Fix editor progress bar

This commit is contained in:
Thomas Ricouard 2024-05-04 11:27:52 +02:00
parent e857439a02
commit 66754ecc7c

View file

@ -16,133 +16,135 @@ public extension StatusEditor {
@Environment(AppAccountsManager.self) private var appAccounts @Environment(AppAccountsManager.self) private var appAccounts
@Environment(CurrentAccount.self) private var currentAccount @Environment(CurrentAccount.self) private var currentAccount
@Environment(Theme.self) private var theme @Environment(Theme.self) private var theme
@State private var presentationDetent: PresentationDetent = .large @State private var presentationDetent: PresentationDetent = .large
@State private var mainSEVM: ViewModel @State private var mainSEVM: ViewModel
@State private var followUpSEVMs: [ViewModel] = [] @State private var followUpSEVMs: [ViewModel] = []
@State private var editingMediaContainer: MediaContainer? @State private var editingMediaContainer: MediaContainer?
@State private var scrollID: UUID? @State private var scrollID: UUID?
@FocusState private var editorFocusState: EditorFocusState? @FocusState private var editorFocusState: EditorFocusState?
private var focusedSEVM: ViewModel { private var focusedSEVM: ViewModel {
if case let .followUp(id) = editorFocusState, if case let .followUp(id) = editorFocusState,
let sevm = followUpSEVMs.first(where: { $0.id == id }) let sevm = followUpSEVMs.first(where: { $0.id == id })
{ return sevm } { return sevm }
return mainSEVM return mainSEVM
} }
public init(mode: ViewModel.Mode) { public init(mode: ViewModel.Mode) {
_mainSEVM = State(initialValue: ViewModel(mode: mode)) _mainSEVM = State(initialValue: ViewModel(mode: mode))
} }
public var body: some View { public var body: some View {
@Bindable var focusedSEVM = focusedSEVM @Bindable var focusedSEVM = focusedSEVM
NavigationStack { NavigationStack {
ScrollView { ZStack(alignment: .top) {
VStackLayout(spacing: 0) { ScrollView {
if mainSEVM.isPosting { VStackLayout(spacing: 0) {
ProgressView(value: mainSEVM.postingProgress, total: 100.0)
}
EditorView(
viewModel: mainSEVM,
followUpSEVMs: $followUpSEVMs,
editingMediaContainer: $editingMediaContainer,
editorFocusState: $editorFocusState,
assignedFocusState: .main,
isMain: true
)
.id(mainSEVM.id)
ForEach(followUpSEVMs) { sevm in
@Bindable var sevm: ViewModel = sevm
EditorView( EditorView(
viewModel: sevm, viewModel: mainSEVM,
followUpSEVMs: $followUpSEVMs, followUpSEVMs: $followUpSEVMs,
editingMediaContainer: $editingMediaContainer, editingMediaContainer: $editingMediaContainer,
editorFocusState: $editorFocusState, editorFocusState: $editorFocusState,
assignedFocusState: .followUp(index: sevm.id), assignedFocusState: .main,
isMain: false isMain: true
) )
.id(sevm.id) .id(mainSEVM.id)
ForEach(followUpSEVMs) { sevm in
@Bindable var sevm: ViewModel = sevm
EditorView(
viewModel: sevm,
followUpSEVMs: $followUpSEVMs,
editingMediaContainer: $editingMediaContainer,
editorFocusState: $editorFocusState,
assignedFocusState: .followUp(index: sevm.id),
isMain: false
)
.id(sevm.id)
}
} }
.scrollTargetLayout()
} }
.scrollTargetLayout() .scrollPosition(id: $scrollID, anchor: .top)
} .animation(.bouncy(duration: 0.3), value: editorFocusState)
.scrollPosition(id: $scrollID, anchor: .top) .animation(.bouncy(duration: 0.3), value: followUpSEVMs)
.animation(.bouncy(duration: 0.3), value: editorFocusState) #if !os(visionOS)
.animation(.bouncy(duration: 0.3), value: followUpSEVMs)
#if !os(visionOS)
.background(theme.primaryBackgroundColor) .background(theme.primaryBackgroundColor)
#endif #endif
.safeAreaInset(edge: .bottom) { .safeAreaInset(edge: .bottom) {
AutoCompleteView(viewModel: focusedSEVM) AutoCompleteView(viewModel: focusedSEVM)
} }
#if os(visionOS) #if os(visionOS)
.ornament(attachmentAnchor: .scene(.leading)) { .ornament(attachmentAnchor: .scene(.leading)) {
AccessoryView(focusedSEVM: focusedSEVM, AccessoryView(focusedSEVM: focusedSEVM,
followUpSEVMs: $followUpSEVMs) followUpSEVMs: $followUpSEVMs)
} }
#else #else
.safeAreaInset(edge: .bottom) { .safeAreaInset(edge: .bottom) {
if presentationDetent == .large || presentationDetent == .medium { if presentationDetent == .large || presentationDetent == .medium {
AccessoryView(focusedSEVM: focusedSEVM, AccessoryView(focusedSEVM: focusedSEVM,
followUpSEVMs: $followUpSEVMs) followUpSEVMs: $followUpSEVMs)
}
}
#endif
.accessibilitySortPriority(1) // Ensure that all elements inside the `ScrollView` occur earlier than the accessory views
.navigationTitle(focusedSEVM.mode.title)
.navigationBarTitleDisplayMode(.inline)
.toolbar { ToolbarItems(mainSEVM: mainSEVM,
focusedSEVM: focusedSEVM,
followUpSEVMs: followUpSEVMs) }
.toolbarBackground(.visible, for: .navigationBar)
.alert(
"status.error.posting.title",
isPresented: $focusedSEVM.showPostingErrorAlert,
actions: {
Button("OK") {}
}, message: {
Text(mainSEVM.postingError ?? "")
}
)
.interactiveDismissDisabled(mainSEVM.shouldDisplayDismissWarning)
.onChange(of: appAccounts.currentClient) { _, newValue in
if mainSEVM.mode.isInShareExtension {
currentAccount.setClient(client: newValue)
mainSEVM.client = newValue
for post in followUpSEVMs {
post.client = newValue
} }
} }
#endif }
.accessibilitySortPriority(1) // Ensure that all elements inside the `ScrollView` occur earlier than the accessory views .onDrop(of: [.image, .video, .gif, .mpeg4Movie, .quickTimeMovie, .movie],
.navigationTitle(focusedSEVM.mode.title) delegate: focusedSEVM)
.navigationBarTitleDisplayMode(.inline) .onChange(of: currentAccount.account?.id) {
.toolbar { ToolbarItems(mainSEVM: mainSEVM, mainSEVM.currentAccount = currentAccount.account
focusedSEVM: focusedSEVM, for p in followUpSEVMs {
followUpSEVMs: followUpSEVMs) } p.currentAccount = mainSEVM.currentAccount
.toolbarBackground(.visible, for: .navigationBar) }
.alert( }
"status.error.posting.title", .onChange(of: mainSEVM.visibility) {
isPresented: $focusedSEVM.showPostingErrorAlert, for p in followUpSEVMs {
actions: { p.visibility = mainSEVM.visibility
Button("OK") {} }
}, message: { }
Text(mainSEVM.postingError ?? "") .onChange(of: followUpSEVMs.count) { oldValue, newValue in
} if oldValue < newValue {
) Task {
.interactiveDismissDisabled(mainSEVM.shouldDisplayDismissWarning) try? await Task.sleep(for: .seconds(0.1))
.onChange(of: appAccounts.currentClient) { _, newValue in withAnimation(.bouncy(duration: 0.5)) {
if mainSEVM.mode.isInShareExtension { scrollID = followUpSEVMs.last?.id
currentAccount.setClient(client: newValue)
mainSEVM.client = newValue
for post in followUpSEVMs {
post.client = newValue
}
}
}
.onDrop(of: [.image, .video, .gif, .mpeg4Movie, .quickTimeMovie, .movie],
delegate: focusedSEVM)
.onChange(of: currentAccount.account?.id) {
mainSEVM.currentAccount = currentAccount.account
for p in followUpSEVMs {
p.currentAccount = mainSEVM.currentAccount
}
}
.onChange(of: mainSEVM.visibility) {
for p in followUpSEVMs {
p.visibility = mainSEVM.visibility
}
}
.onChange(of: followUpSEVMs.count) { oldValue, newValue in
if oldValue < newValue {
Task {
try? await Task.sleep(for: .seconds(0.1))
withAnimation(.bouncy(duration: 0.5)) {
scrollID = followUpSEVMs.last?.id
}
} }
} }
} }
}
if mainSEVM.isPosting {
ProgressView(value: mainSEVM.postingProgress, total: 100.0)
}
}
} }
.sheet(item: $editingMediaContainer) { container in .sheet(item: $editingMediaContainer) { container in
StatusEditor.MediaEditView(viewModel: focusedSEVM, container: container) StatusEditor.MediaEditView(viewModel: focusedSEVM, container: container)