Fix compose reply view not working after ContentTextView refactor, use named CoordinateSpace for calculating scroll offset in reply avatar view
This commit is contained in:
parent
e9962997a6
commit
c6c8f63e39
|
@ -23,6 +23,7 @@ struct ComposeReplyContentView: UIViewRepresentable {
|
|||
view.setTextFrom(status: status)
|
||||
view.isUserInteractionEnabled = false
|
||||
view.backgroundColor = .clear
|
||||
view.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
||||
|
||||
return view
|
||||
}
|
||||
|
|
|
@ -11,8 +11,8 @@ import SwiftUI
|
|||
struct ComposeReplyView: View {
|
||||
let status: StatusMO
|
||||
let stackPadding: CGFloat
|
||||
let outerMinY: CGFloat
|
||||
|
||||
@State private var displayNameHeight: CGFloat?
|
||||
@State private var contentHeight: CGFloat?
|
||||
|
||||
@ObservedObject private var preferences = Preferences.shared
|
||||
|
@ -37,23 +37,25 @@ struct ComposeReplyView: View {
|
|||
|
||||
Spacer()
|
||||
}
|
||||
|
||||
ComposeReplyContentView(status: status) { (newHeight) in
|
||||
self.contentHeight = newHeight
|
||||
.background(GeometryReader { proxy in
|
||||
Color.clear
|
||||
.preference(key: DisplayNameHeightPrefKey.self, value: proxy.size.height)
|
||||
.onPreferenceChange(DisplayNameHeightPrefKey.self) { newValue in
|
||||
displayNameHeight = newValue
|
||||
}
|
||||
})
|
||||
|
||||
ComposeReplyContentView(status: status) { newHeight in
|
||||
contentHeight = newHeight
|
||||
}
|
||||
.offset(x: -4, y: -8)
|
||||
.padding(.bottom, -8)
|
||||
.frame(height: contentHeight ?? 0)
|
||||
}
|
||||
.frame(height: max(50, contentHeight ?? 0) + 8)
|
||||
}
|
||||
.padding(.bottom, -8)
|
||||
}
|
||||
|
||||
private func replyAvatarImage(geometry: GeometryProxy) -> some View {
|
||||
// using named coordinate spaces produces an incorrect scroll offset on iOS 13,
|
||||
// so simply compare the geometry inside and outside the scroll view in the global coordinate space
|
||||
let scrollOffset = outerMinY - geometry.frame(in: .global).minY
|
||||
|
||||
let scrollOffset = -geometry.frame(in: .named(ComposeView.coordinateSpaceOutsideOfScrollView)).minY
|
||||
|
||||
// add stackPadding so that the image is always at least stackPadding away from the top
|
||||
var offset = scrollOffset + stackPadding
|
||||
|
||||
|
@ -61,7 +63,7 @@ struct ComposeReplyView: View {
|
|||
offset = max(offset, 0)
|
||||
|
||||
// subtract 50, because we care about where the bottom of the view is but the offset is relative to the top of the view
|
||||
let maxOffset = (contentHeight ?? 0) - 50
|
||||
let maxOffset = (contentHeight ?? 0) + (displayNameHeight ?? 0) - 50
|
||||
|
||||
// once you scroll past the in-reply-to-content, the bottom of the avatar should be pinned to the bottom of the content
|
||||
offset = min(offset, maxOffset)
|
||||
|
@ -74,6 +76,13 @@ struct ComposeReplyView: View {
|
|||
|
||||
}
|
||||
|
||||
private struct DisplayNameHeightPrefKey: PreferenceKey {
|
||||
static var defaultValue: CGFloat = 0
|
||||
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
|
||||
value = nextValue()
|
||||
}
|
||||
}
|
||||
|
||||
//struct ComposeReplyView_Previews: PreviewProvider {
|
||||
// static var previews: some View {
|
||||
// ComposeReplyView()
|
||||
|
|
|
@ -42,6 +42,8 @@ import Combine
|
|||
}
|
||||
|
||||
struct ComposeView: View {
|
||||
static let coordinateSpaceOutsideOfScrollView = "coordinateSpaceOutsideOfScrollView"
|
||||
|
||||
@ObservedObject var draft: Draft
|
||||
@EnvironmentObject var mastodonController: MastodonController
|
||||
@EnvironmentObject var uiState: ComposeUIState
|
||||
|
@ -77,20 +79,12 @@ struct ComposeView: View {
|
|||
}
|
||||
|
||||
var body: some View {
|
||||
mostOfTheBody.toolbar {
|
||||
ToolbarItem(placement: .cancellationAction) { cancelButton }
|
||||
ToolbarItem(placement: .confirmationAction) { postButton }
|
||||
}
|
||||
}
|
||||
|
||||
var mostOfTheBody: some View {
|
||||
ZStack(alignment: .top) {
|
||||
GeometryReader { (outer) in
|
||||
ScrollView(.vertical) {
|
||||
mainStack(outerMinY: outer.frame(in: .global).minY)
|
||||
}
|
||||
.scrollDismissesKeyboardInteractivelyIfAvailable()
|
||||
ScrollView(.vertical) {
|
||||
mainStack
|
||||
}
|
||||
.coordinateSpace(name: ComposeView.coordinateSpaceOutsideOfScrollView)
|
||||
.scrollDismissesKeyboardInteractivelyIfAvailable()
|
||||
|
||||
if let poster = poster {
|
||||
// can't use SwiftUI.ProgressView because there's no UIProgressView.Style.bar equivalent, see FB8587149
|
||||
|
@ -108,6 +102,10 @@ struct ComposeView: View {
|
|||
dismissButton: .default(Text("OK"))
|
||||
)
|
||||
}
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .cancellationAction) { cancelButton }
|
||||
ToolbarItem(placement: .confirmationAction) { postButton }
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
|
@ -122,14 +120,13 @@ struct ComposeView: View {
|
|||
.animation(.default, value: uiState.autocompleteState)
|
||||
}
|
||||
|
||||
func mainStack(outerMinY: CGFloat) -> some View {
|
||||
var mainStack: some View {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
if let id = draft.inReplyToID,
|
||||
let status = mastodonController.persistentContainer.status(for: id) {
|
||||
ComposeReplyView(
|
||||
status: status,
|
||||
stackPadding: stackPadding,
|
||||
outerMinY: outerMinY
|
||||
stackPadding: stackPadding
|
||||
)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue