mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2025-09-04 00:43:48 +00:00
Add avatar position setting (#14)
Co-authored-by: Jérôme Danthinne <jerome.danthinne@smile.eu>
This commit is contained in:
parent
315a57b447
commit
810e9fbe6b
6 changed files with 66 additions and 17 deletions
|
@ -71,11 +71,17 @@ struct SettingsTabs: View {
|
||||||
ColorPicker("Tint color", selection: $theme.tintColor)
|
ColorPicker("Tint color", selection: $theme.tintColor)
|
||||||
ColorPicker("Background color", selection: $theme.primaryBackgroundColor)
|
ColorPicker("Background color", selection: $theme.primaryBackgroundColor)
|
||||||
ColorPicker("Secondary Background color", selection: $theme.secondaryBackgroundColor)
|
ColorPicker("Secondary Background color", selection: $theme.secondaryBackgroundColor)
|
||||||
|
Picker("Avatar position", selection: $theme.avatarPosition) {
|
||||||
|
ForEach(Theme.AvatarPosition.allCases, id: \.rawValue) { position in
|
||||||
|
Text(position.description).tag(position)
|
||||||
|
}
|
||||||
|
}
|
||||||
Button {
|
Button {
|
||||||
theme.colorScheme = "dark"
|
theme.colorScheme = "dark"
|
||||||
theme.tintColor = .brand
|
theme.tintColor = .brand
|
||||||
theme.primaryBackgroundColor = .primaryBackground
|
theme.primaryBackgroundColor = .primaryBackground
|
||||||
theme.secondaryBackgroundColor = .secondaryBackground
|
theme.secondaryBackgroundColor = .secondaryBackground
|
||||||
|
theme.avatarPosition = .top
|
||||||
} label: {
|
} label: {
|
||||||
Text("Restore default")
|
Text("Restore default")
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,5 +4,6 @@ public struct DS {
|
||||||
public enum Constants {
|
public enum Constants {
|
||||||
public static let layoutPadding: CGFloat = 20
|
public static let layoutPadding: CGFloat = 20
|
||||||
public static let dividerPadding: CGFloat = 4
|
public static let dividerPadding: CGFloat = 4
|
||||||
|
public static let statusColumnsSpacing: CGFloat = 8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,23 @@
|
||||||
|
import Combine
|
||||||
import SwiftUI
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum AvatarPosition: String, CaseIterable {
|
||||||
|
case leading, top
|
||||||
|
|
||||||
|
public var description: LocalizedStringKey {
|
||||||
|
switch self {
|
||||||
|
case .leading:
|
||||||
|
return "Leading"
|
||||||
|
case .top:
|
||||||
|
return "Top"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@AppStorage("is_previously_set") var isSet: Bool = false
|
@AppStorage("is_previously_set") var isSet: Bool = false
|
||||||
|
@ -19,12 +34,27 @@ public class Theme: ObservableObject {
|
||||||
@AppStorage(ThemeKey.primaryBackground.rawValue) public var primaryBackgroundColor: Color = .white
|
@AppStorage(ThemeKey.primaryBackground.rawValue) public var primaryBackgroundColor: Color = .white
|
||||||
@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
|
||||||
|
|
||||||
|
@Published public var avatarPosition: AvatarPosition = .top
|
||||||
|
|
||||||
|
private var cancellables = Set<AnyCancellable>()
|
||||||
|
|
||||||
public init() {
|
public init() {
|
||||||
if !isSet {
|
if !isSet {
|
||||||
setColor(set: DarkSet())
|
setColor(set: DarkSet())
|
||||||
isSet.toggle()
|
isSet.toggle()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
avatarPosition = AvatarPosition(rawValue: rawAvatarPosition) ?? .top
|
||||||
|
|
||||||
|
$avatarPosition
|
||||||
|
.dropFirst()
|
||||||
|
.map(\.rawValue)
|
||||||
|
.sink { [weak self] position in
|
||||||
|
self?.rawAvatarPosition = position
|
||||||
|
}
|
||||||
|
.store(in: &cancellables)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func setColor(set: ColorSet) {
|
public func setColor(set: ColorSet) {
|
||||||
|
|
|
@ -6,7 +6,7 @@ public struct AvatarView: View {
|
||||||
public enum Size {
|
public enum Size {
|
||||||
case account, status, embed, badge, boost
|
case account, status, embed, badge, boost
|
||||||
|
|
||||||
var size: CGSize {
|
public var size: CGSize {
|
||||||
switch self {
|
switch self {
|
||||||
case .account:
|
case .account:
|
||||||
return .init(width: 80, height: 80)
|
return .init(width: 80, height: 80)
|
||||||
|
|
|
@ -7,6 +7,7 @@ import DesignSystem
|
||||||
|
|
||||||
public struct StatusMediaPreviewView: View {
|
public struct StatusMediaPreviewView: View {
|
||||||
@EnvironmentObject private var quickLook: QuickLook
|
@EnvironmentObject private var quickLook: QuickLook
|
||||||
|
@EnvironmentObject private var theme: Theme
|
||||||
|
|
||||||
public let attachements: [MediaAttachement]
|
public let attachements: [MediaAttachement]
|
||||||
public let isCompact: Bool
|
public let isCompact: Bool
|
||||||
|
@ -95,8 +96,10 @@ public struct StatusMediaPreviewView: View {
|
||||||
switch attachement.supportedType {
|
switch attachement.supportedType {
|
||||||
case .image:
|
case .image:
|
||||||
if let size = size(for: attachement) {
|
if let size = size(for: attachement) {
|
||||||
|
let avatarColumnWidth = theme.avatarPosition == .leading ? AvatarView.Size.status.size.width + DS.Constants.statusColumnsSpacing : 0
|
||||||
|
let availableWidth = UIScreen.main.bounds.width - (DS.Constants.layoutPadding * 2) - avatarColumnWidth
|
||||||
let newSize = imageSize(from: size,
|
let newSize = imageSize(from: size,
|
||||||
newWidth: UIScreen.main.bounds.width - (DS.Constants.layoutPadding * 2))
|
newWidth: availableWidth)
|
||||||
LazyImage(url: attachement.url) { state in
|
LazyImage(url: attachement.url) { state in
|
||||||
if let image = state.image {
|
if let image = state.image {
|
||||||
image
|
image
|
||||||
|
|
|
@ -18,20 +18,27 @@ public struct StatusRowView: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
public var body: some View {
|
public var body: some View {
|
||||||
VStack(alignment: .leading) {
|
HStack(alignment: .top, spacing: DS.Constants.statusColumnsSpacing) {
|
||||||
if !viewModel.isCompact {
|
if !viewModel.isCompact,
|
||||||
reblogView
|
theme.avatarPosition == .leading,
|
||||||
replyView
|
let status: AnyStatus = viewModel.status.reblog ?? viewModel.status {
|
||||||
|
AvatarView(url: status.account.avatar, size: .status)
|
||||||
}
|
}
|
||||||
statusView
|
VStack(alignment: .leading) {
|
||||||
if !viewModel.isCompact {
|
if !viewModel.isCompact {
|
||||||
StatusActionsView(viewModel: viewModel)
|
reblogView
|
||||||
.padding(.vertical, 8)
|
replyView
|
||||||
.tint(viewModel.isFocused ? theme.tintColor : .gray)
|
}
|
||||||
.contentShape(Rectangle())
|
statusView
|
||||||
.onTapGesture {
|
if !viewModel.isCompact {
|
||||||
routeurPath.navigate(to: .statusDetail(id: viewModel.status.reblog?.id ?? viewModel.status.id))
|
StatusActionsView(viewModel: viewModel)
|
||||||
}
|
.padding(.vertical, 8)
|
||||||
|
.tint(viewModel.isFocused ? theme.tintColor : .gray)
|
||||||
|
.contentShape(Rectangle())
|
||||||
|
.onTapGesture {
|
||||||
|
routeurPath.navigate(to: .statusDetail(id: viewModel.status.reblog?.id ?? viewModel.status.id))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
|
@ -155,7 +162,9 @@ public struct StatusRowView: View {
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
private func accountView(status: AnyStatus) -> some View {
|
private func accountView(status: AnyStatus) -> some View {
|
||||||
HStack(alignment: .center) {
|
HStack(alignment: .center) {
|
||||||
AvatarView(url: status.account.avatar, size: .status)
|
if theme.avatarPosition == .top {
|
||||||
|
AvatarView(url: status.account.avatar, size: .status)
|
||||||
|
}
|
||||||
VStack(alignment: .leading, spacing: 0) {
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
status.account.displayNameWithEmojis
|
status.account.displayNameWithEmojis
|
||||||
.font(.headline)
|
.font(.headline)
|
||||||
|
|
Loading…
Reference in a new issue