WIP poll editing
This commit is contained in:
parent
fbbcb0d07d
commit
ac78fe2807
@ -90,10 +90,6 @@ class ToolbarController: ViewController {
|
|||||||
cwButton
|
cwButton
|
||||||
|
|
||||||
MenuPicker(selection: visibilityBinding, options: visibilityOptions, buttonStyle: .iconOnly)
|
MenuPicker(selection: visibilityBinding, options: visibilityOptions, buttonStyle: .iconOnly)
|
||||||
#if !targetEnvironment(macCatalyst) && !os(visionOS)
|
|
||||||
// the button has a bunch of extra space by default, but combined with what we add it's too much
|
|
||||||
.padding(.horizontal, -8)
|
|
||||||
#endif
|
|
||||||
.disabled(draft.editedStatusID != nil)
|
.disabled(draft.editedStatusID != nil)
|
||||||
.disabled(composeController.mastodonController.instanceFeatures.localOnlyPostsVisibility && draft.localOnly)
|
.disabled(composeController.mastodonController.instanceFeatures.localOnlyPostsVisibility && draft.localOnly)
|
||||||
|
|
||||||
@ -101,8 +97,6 @@ class ToolbarController: ViewController {
|
|||||||
localOnlyPicker
|
localOnlyPicker
|
||||||
#if targetEnvironment(macCatalyst)
|
#if targetEnvironment(macCatalyst)
|
||||||
.padding(.leading, 4)
|
.padding(.leading, 4)
|
||||||
#elseif !os(visionOS)
|
|
||||||
.padding(.horizontal, -8)
|
|
||||||
#endif
|
#endif
|
||||||
.disabled(draft.editedStatusID != nil)
|
.disabled(draft.editedStatusID != nil)
|
||||||
}
|
}
|
||||||
|
@ -197,9 +197,9 @@ private class WrappedCollectionViewController: UIViewController {
|
|||||||
cell.containingViewController = self
|
cell.containingViewController = self
|
||||||
cell.setView(AttachmentCollectionViewCellView(attachment: attachment))
|
cell.setView(AttachmentCollectionViewCellView(attachment: attachment))
|
||||||
}
|
}
|
||||||
let addButtonCell = UICollectionView.CellRegistration<HostingCollectionViewCell, Bool> { [unowned self] cell, indexPath, item in
|
let addButtonCell = UICollectionView.CellRegistration<HostingCollectionViewCell, Void> { [unowned self] cell, indexPath, item in
|
||||||
cell.containingViewController = self
|
cell.containingViewController = self
|
||||||
cell.setView(AddAttachmentButton(viewController: self, enabled: item))
|
cell.setView(AddAttachmentButton(viewController: self))
|
||||||
}
|
}
|
||||||
let collectionView = IntrinsicContentSizeCollectionView(frame: .zero, collectionViewLayout: layout)
|
let collectionView = IntrinsicContentSizeCollectionView(frame: .zero, collectionViewLayout: layout)
|
||||||
self.view = collectionView
|
self.view = collectionView
|
||||||
@ -208,7 +208,7 @@ private class WrappedCollectionViewController: UIViewController {
|
|||||||
case .attachment(let attachment):
|
case .attachment(let attachment):
|
||||||
return collectionView.dequeueConfiguredReusableCell(using: attachmentCell, for: indexPath, item: attachment)
|
return collectionView.dequeueConfiguredReusableCell(using: attachmentCell, for: indexPath, item: attachment)
|
||||||
case .addButton:
|
case .addButton:
|
||||||
return collectionView.dequeueConfiguredReusableCell(using: addButtonCell, for: indexPath, item: true)
|
return collectionView.dequeueConfiguredReusableCell(using: addButtonCell, for: indexPath, item: ())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dataSource.reorderingHandlers.canReorderItem = { item in
|
dataSource.reorderingHandlers.canReorderItem = { item in
|
||||||
@ -423,7 +423,7 @@ private class HostingCollectionViewCell: UICollectionViewCell {
|
|||||||
|
|
||||||
private struct AddAttachmentButton: View {
|
private struct AddAttachmentButton: View {
|
||||||
unowned let viewController: WrappedCollectionViewController
|
unowned let viewController: WrappedCollectionViewController
|
||||||
let enabled: Bool
|
@Environment(\.canAddAttachment) private var enabled
|
||||||
@Environment(\.composeUIConfig.presentAssetPicker) private var presentAssetPicker
|
@Environment(\.composeUIConfig.presentAssetPicker) private var presentAssetPicker
|
||||||
@Environment(\.composeUIConfig.presentDrawing) private var presentDrawing
|
@Environment(\.composeUIConfig.presentDrawing) private var presentDrawing
|
||||||
|
|
||||||
@ -462,6 +462,7 @@ private struct AddAttachmentButton: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.disabled(!enabled)
|
.disabled(!enabled)
|
||||||
|
.animation(.linear(duration: 0.2), value: enabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var iconName: String {
|
private var iconName: String {
|
||||||
|
@ -13,18 +13,11 @@ struct ComposeDraftView: View {
|
|||||||
@ObservedObject var draft: Draft
|
@ObservedObject var draft: Draft
|
||||||
@FocusState.Binding var focusedField: FocusableField?
|
@FocusState.Binding var focusedField: FocusableField?
|
||||||
@Environment(\.currentAccount) private var currentAccount
|
@Environment(\.currentAccount) private var currentAccount
|
||||||
@EnvironmentObject private var controller: ComposeController
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack(alignment: .top, spacing: 8) {
|
HStack(alignment: .top, spacing: 8) {
|
||||||
// TODO: scroll effect?
|
// TODO: scroll effect?
|
||||||
AvatarImageView(
|
AvatarView(account: currentAccount)
|
||||||
url: currentAccount?.avatar,
|
|
||||||
size: 50,
|
|
||||||
style: controller.config.avatarStyle,
|
|
||||||
fetchAvatar: controller.fetchAvatar
|
|
||||||
)
|
|
||||||
.accessibilityHidden(true)
|
|
||||||
|
|
||||||
VStack(alignment: .leading, spacing: 4) {
|
VStack(alignment: .leading, spacing: 4) {
|
||||||
if let currentAccount {
|
if let currentAccount {
|
||||||
@ -35,10 +28,38 @@ struct ComposeDraftView: View {
|
|||||||
|
|
||||||
DraftContentEditor(draft: draft, focusedField: $focusedField)
|
DraftContentEditor(draft: draft, focusedField: $focusedField)
|
||||||
|
|
||||||
|
if let poll = draft.poll {
|
||||||
|
PollEditor(poll: poll)
|
||||||
|
.padding(.bottom, 4)
|
||||||
|
// So that during the appearance transition, it's behind the text view.
|
||||||
|
.zIndex(-1)
|
||||||
|
.transition(.move(edge: .top).combined(with: .opacity))
|
||||||
|
}
|
||||||
|
|
||||||
AttachmentsSection(draft: draft)
|
AttachmentsSection(draft: draft)
|
||||||
|
// We want the padding between the poll/attachments to be part of the poll, so it animates in/out with the transition.
|
||||||
|
// Otherwise, when the poll is added, its bottom edge is aligned with the top edge of the attachments
|
||||||
|
.padding(.top, draft.poll == nil ? 0 : -4)
|
||||||
|
}
|
||||||
|
.animation(.snappy, value: draft.poll == nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private struct AvatarView: View {
|
||||||
|
let account: (any AccountProtocol)?
|
||||||
|
@Environment(\.composeUIConfig.avatarStyle) private var avatarStyle
|
||||||
|
@EnvironmentObject private var controller: ComposeController
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
AvatarImageView(
|
||||||
|
url: account?.avatar,
|
||||||
|
size: 50,
|
||||||
|
style: avatarStyle,
|
||||||
|
fetchAvatar: controller.fetchAvatar
|
||||||
|
)
|
||||||
|
.accessibilityHidden(true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct AccountNameView: View {
|
private struct AccountNameView: View {
|
||||||
|
@ -142,10 +142,6 @@ private struct VisibilityButton: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
MenuPicker(selection: visibilityBinding, options: visibilityOptions, buttonStyle: .iconOnly)
|
MenuPicker(selection: visibilityBinding, options: visibilityOptions, buttonStyle: .iconOnly)
|
||||||
#if !targetEnvironment(macCatalyst) && !os(visionOS)
|
|
||||||
// the button has a bunch of extra space by default, but combined with what we add it's too much
|
|
||||||
.padding(.horizontal, -8)
|
|
||||||
#endif
|
|
||||||
.disabled(draft.editedStatusID != nil)
|
.disabled(draft.editedStatusID != nil)
|
||||||
.disabled(instanceFeatures.localOnlyPostsVisibility && draft.localOnly)
|
.disabled(instanceFeatures.localOnlyPostsVisibility && draft.localOnly)
|
||||||
}
|
}
|
||||||
|
@ -20,16 +20,13 @@ struct DraftContentEditor: View {
|
|||||||
|
|
||||||
HStack(alignment: .firstTextBaseline) {
|
HStack(alignment: .firstTextBaseline) {
|
||||||
LanguageButton(draft: draft)
|
LanguageButton(draft: draft)
|
||||||
|
TogglePollButton(draft: draft)
|
||||||
Spacer()
|
Spacer()
|
||||||
CharactersRemaining(draft: draft)
|
CharactersRemaining(draft: draft)
|
||||||
.padding(.trailing, 4)
|
.padding(.trailing, 6)
|
||||||
}
|
}
|
||||||
.padding(.all.subtracting(.top), 2)
|
|
||||||
}
|
|
||||||
.background {
|
|
||||||
RoundedRectangle(cornerRadius: 5)
|
|
||||||
.fill(colorScheme == .dark ? fillColor : Color(uiColor: .secondarySystemBackground))
|
|
||||||
}
|
}
|
||||||
|
.composePlatterBackground()
|
||||||
}
|
}
|
||||||
|
|
||||||
private func addAttachments(_ providers: [NSItemProvider]) {
|
private func addAttachments(_ providers: [NSItemProvider]) {
|
||||||
@ -50,7 +47,7 @@ private struct CharactersRemaining: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
Text(verbatim: charsRemaining.description)
|
Text(verbatim: charsRemaining.description)
|
||||||
.foregroundStyle(charsRemaining < 0 ? .red : .secondary)
|
.foregroundStyle(charsRemaining < 0 ? .red : .secondary)
|
||||||
.font(.callout.monospacedDigit())
|
.font(.body.monospacedDigit())
|
||||||
.accessibility(label: Text(charsRemaining < 0 ? "\(-charsRemaining) characters too many" : "\(charsRemaining) characters remaining"))
|
.accessibility(label: Text(charsRemaining < 0 ? "\(-charsRemaining) characters too many" : "\(charsRemaining) characters remaining"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -85,11 +82,36 @@ private struct LanguageButton: View {
|
|||||||
private struct LanguageButtonStyle: ButtonStyle {
|
private struct LanguageButtonStyle: ButtonStyle {
|
||||||
func makeBody(configuration: Configuration) -> some View {
|
func makeBody(configuration: Configuration) -> some View {
|
||||||
configuration.label
|
configuration.label
|
||||||
.font(.callout)
|
|
||||||
.foregroundStyle(.tint.opacity(configuration.isPressed ? 0.8 : 1))
|
.foregroundStyle(.tint.opacity(configuration.isPressed ? 0.8 : 1))
|
||||||
.padding(.vertical, 2)
|
.padding(.vertical, 2)
|
||||||
.padding(.horizontal, 4)
|
.padding(.horizontal, 4)
|
||||||
.background(.tint.opacity(configuration.isPressed ? 0.15 : 0.2), in: RoundedRectangle(cornerRadius: 3))
|
.background(.tint.opacity(configuration.isPressed ? 0.15 : 0.2), in: RoundedRectangle(cornerRadius: 3))
|
||||||
.animation(.linear(duration: 0.1), value: configuration.isPressed)
|
.animation(.linear(duration: 0.1), value: configuration.isPressed)
|
||||||
|
.padding(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct TogglePollButton: View {
|
||||||
|
@ObservedObject var draft: Draft
|
||||||
|
@EnvironmentObject private var instanceFeatures: InstanceFeatures
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Button {
|
||||||
|
if draft.poll == nil {
|
||||||
|
draft.poll = Poll(context: DraftsPersistentContainer.shared.viewContext)
|
||||||
|
} else {
|
||||||
|
draft.poll = nil
|
||||||
|
}
|
||||||
|
} label: {
|
||||||
|
Image(systemName: draft.poll == nil ? "chart.bar.doc.horizontal" : "chart.bar.horizontal.page.fill")
|
||||||
|
}
|
||||||
|
.buttonStyle(LanguageButtonStyle())
|
||||||
|
.disabled(disabled)
|
||||||
|
.animation(.linear(duration: 0.2), value: disabled)
|
||||||
|
.animation(.linear(duration: 0.2), value: draft.poll == nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var disabled: Bool {
|
||||||
|
instanceFeatures.mastodonAttachmentRestrictions && draft.attachments.count > 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,29 @@
|
|||||||
|
//
|
||||||
|
// BackgroundPlatterView.swift
|
||||||
|
// ComposeUI
|
||||||
|
//
|
||||||
|
// Created by Shadowfacts on 1/29/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
extension View {
|
||||||
|
func composePlatterBackground() -> some View {
|
||||||
|
self.background {
|
||||||
|
PlatterBackgroundView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct PlatterBackgroundView: View {
|
||||||
|
@Environment(\.colorScheme) private var colorScheme
|
||||||
|
@Environment(\.composeUIConfig.fillColor) private var fillColor
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
RoundedRectangle(cornerRadius: 5)
|
||||||
|
// TODO: fillColor is semi-transparent in pure-black dark mode, but it needs to be fully opaque for the poll transition to look right
|
||||||
|
// .fill(colorScheme == .dark ? fillColor : Color(uiColor: .secondarySystemBackground))
|
||||||
|
.fill(Color(uiColor: .secondarySystemBackground))
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
189
Packages/ComposeUI/Sources/ComposeUI/Views/PollEditor.swift
Normal file
189
Packages/ComposeUI/Sources/ComposeUI/Views/PollEditor.swift
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
//
|
||||||
|
// PollEditor.swift
|
||||||
|
// ComposeUI
|
||||||
|
//
|
||||||
|
// Created by Shadowfacts on 1/29/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
import InstanceFeatures
|
||||||
|
import TuskerComponents
|
||||||
|
|
||||||
|
struct PollEditor: View {
|
||||||
|
@ObservedObject var poll: Poll
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack(alignment: .leading, spacing: 8) {
|
||||||
|
Text("Poll")
|
||||||
|
.font(.headline)
|
||||||
|
|
||||||
|
ForEach(poll.pollOptions) { option in
|
||||||
|
PollOptionEditor(option: option, index: poll.options.index(of: option)) {
|
||||||
|
self.removeOption(option)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AddOptionButton(poll: poll)
|
||||||
|
|
||||||
|
Toggle("Multiple choice", isOn: $poll.multiple)
|
||||||
|
.padding(.bottom, -8)
|
||||||
|
|
||||||
|
HStack {
|
||||||
|
Text("Duration")
|
||||||
|
Spacer()
|
||||||
|
PollDurationPicker(poll: poll)
|
||||||
|
.frame(minHeight: 32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(.all.subtracting(.bottom), 8)
|
||||||
|
.padding(.bottom, 4)
|
||||||
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
|
.composePlatterBackground()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func removeOption(_ option: PollOption) {
|
||||||
|
let index = poll.options.index(of: option)
|
||||||
|
if index != NSNotFound {
|
||||||
|
var array = poll.options.array
|
||||||
|
array.remove(at: index)
|
||||||
|
poll.options = NSMutableOrderedSet(array: array)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct AddOptionButton: View {
|
||||||
|
@ObservedObject var poll: Poll
|
||||||
|
@EnvironmentObject private var instanceFeatures: InstanceFeatures
|
||||||
|
|
||||||
|
private var canAddOption: Bool {
|
||||||
|
if let max = instanceFeatures.maxPollOptionsCount {
|
||||||
|
poll.options.count < max
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Button(action: addOption) {
|
||||||
|
Label("Add Option", systemImage: "plus")
|
||||||
|
}
|
||||||
|
.buttonStyle(.borderless)
|
||||||
|
.disabled(!canAddOption)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func addOption() {
|
||||||
|
let option = PollOption(context: DraftsPersistentContainer.shared.viewContext)
|
||||||
|
option.poll = poll
|
||||||
|
poll.options.add(option)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct PollDurationPicker: View {
|
||||||
|
@ObservedObject var poll: Poll
|
||||||
|
@State var duration: PollDuration
|
||||||
|
|
||||||
|
init(poll: Poll) {
|
||||||
|
self.poll = poll
|
||||||
|
self._duration = State(wrappedValue: .fromTimeInterval(poll.duration) ?? .oneDay)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var options: [MenuPicker<PollDuration>.Option] {
|
||||||
|
PollDuration.allCases.map {
|
||||||
|
.init(value: $0, title: PollDuration.formatter.string(from: $0.timeInterval)!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
MenuPicker(selection: $duration, options: options)
|
||||||
|
#if os(visionOS)
|
||||||
|
.onChange(of: duration) {
|
||||||
|
poll.duration = duration.timeInterval
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
.onChange(of: duration) { newValue in
|
||||||
|
poll.duration = newValue.timeInterval
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum PollDuration: Hashable, Equatable, CaseIterable {
|
||||||
|
case fiveMinutes, thirtyMinutes, oneHour, sixHours, oneDay, threeDays, sevenDays
|
||||||
|
|
||||||
|
static let formatter: DateComponentsFormatter = {
|
||||||
|
let f = DateComponentsFormatter()
|
||||||
|
f.maximumUnitCount = 1
|
||||||
|
f.unitsStyle = .full
|
||||||
|
f.allowedUnits = [.weekOfMonth, .day, .hour, .minute]
|
||||||
|
return f
|
||||||
|
}()
|
||||||
|
|
||||||
|
static func fromTimeInterval(_ ti: TimeInterval) -> PollDuration? {
|
||||||
|
for it in allCases where it.timeInterval == ti {
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var timeInterval: TimeInterval {
|
||||||
|
switch self {
|
||||||
|
case .fiveMinutes:
|
||||||
|
return 5 * 60
|
||||||
|
case .thirtyMinutes:
|
||||||
|
return 30 * 60
|
||||||
|
case .oneHour:
|
||||||
|
return 60 * 60
|
||||||
|
case .sixHours:
|
||||||
|
return 6 * 60 * 60
|
||||||
|
case .oneDay:
|
||||||
|
return 24 * 60 * 60
|
||||||
|
case .threeDays:
|
||||||
|
return 3 * 24 * 60 * 60
|
||||||
|
case .sevenDays:
|
||||||
|
return 7 * 24 * 60 * 60
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct PollOptionEditor: View {
|
||||||
|
@ObservedObject var option: PollOption
|
||||||
|
let index: Int
|
||||||
|
let removeOption: () -> Void
|
||||||
|
@EnvironmentObject private var instanceFeatures: InstanceFeatures
|
||||||
|
|
||||||
|
var placeholder: String {
|
||||||
|
if index != NSNotFound {
|
||||||
|
"Option \(index + 1)"
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
HStack(spacing: 4) {
|
||||||
|
Button(role: .destructive, action: removeOption) {
|
||||||
|
Label("Remove option", systemImage: "minus")
|
||||||
|
}
|
||||||
|
.labelStyle(.iconOnly)
|
||||||
|
.buttonStyle(PollOptionButtonStyle())
|
||||||
|
.accessibilityLabel("Remove option")
|
||||||
|
EmojiTextField(text: $option.text, placeholder: placeholder, maxLength: instanceFeatures.maxPollOptionChars)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct PollOptionButtonStyle: ButtonStyle {
|
||||||
|
func makeBody(configuration: Configuration) -> some View {
|
||||||
|
configuration.label
|
||||||
|
.foregroundStyle(.white)
|
||||||
|
.font(.body.bold())
|
||||||
|
.padding(4)
|
||||||
|
.frame(width: 20, height: 20)
|
||||||
|
.background {
|
||||||
|
let color = configuration.role == .destructive ? Color.red : .green
|
||||||
|
let opacity = configuration.isPressed ? 0.8 : 1
|
||||||
|
Circle()
|
||||||
|
.fill(color.opacity(opacity))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -59,6 +59,7 @@ public struct MenuPicker<Value: Hashable>: UIViewRepresentable {
|
|||||||
#if targetEnvironment(macCatalyst)
|
#if targetEnvironment(macCatalyst)
|
||||||
config.macIdiomStyle = .bordered
|
config.macIdiomStyle = .bordered
|
||||||
#endif
|
#endif
|
||||||
|
config.contentInsets = .zero
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,8 +181,8 @@ class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollecti
|
|||||||
private(set) lazy var contentContainer = StatusContentContainer(arrangedSubviews: [
|
private(set) lazy var contentContainer = StatusContentContainer(arrangedSubviews: [
|
||||||
contentTextView,
|
contentTextView,
|
||||||
cardView,
|
cardView,
|
||||||
attachmentsView,
|
|
||||||
pollView,
|
pollView,
|
||||||
|
attachmentsView,
|
||||||
] as! [any StatusContentView], useTopSpacer: false).configure {
|
] as! [any StatusContentView], useTopSpacer: false).configure {
|
||||||
$0.setContentHuggingPriority(.defaultLow, for: .vertical)
|
$0.setContentHuggingPriority(.defaultLow, for: .vertical)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user