mirror of
https://github.com/yattee/yattee.git
synced 2026-10-28 15:37:17 +00:00
Send a creation where the button said it would go
Creating a playlist while an Invidious account was the selected context wrote it to the device. No request left the app, the row never appeared in the account's list, and the form had come up without its visibility picker — the two symptoms of the same thing: the sheet took the local branch. The destination was decided correctly and then read wrongly. The button resolved the account and put it in a companion `@State`, and the sheet's content closure — created by an earlier body evaluation — read that property as it stood *then*, which was nil. Measured on device: the create resolved the account and validity fine, and one millisecond later the sheet rendered the local form while every live value around it still named the account. Whether the stale read is corrected depends on whether anything re-renders the view before the form is saved, which is why the same steps against Piped had landed on the server. The destination now travels with the presentation as `PlaylistCreationTarget`, so the sheet is handed the account rather than looking one up. One resolver answers for both the create affordances and the row menus, and it is where the rule lives: a context reading an account's data creates on that account or creates nothing at all — a toolbar item can outlive the condition that put it there, and a write with nowhere to go is not a write to somewhere else. A context that fell back to local reads is the one case that does create locally, and it is honest: those are the rows on screen, with the banner above them saying why. Two more from the same pass: - Subscriptions stopped giving two answers at once. Under a fallback the local feed asks for a Yattee Server nobody has configured, so "Add a subscriptions account in Settings" was stacking under a banner saying this account needs signing in again. The banner names the cause, so the feed error stands down while it is up. - The playlists banner no longer lands on the search field. A navigation bar carrying a search field keeps its full height over content that cannot scroll, and the empty, loading and error states could not — they scroll now, which also gives pull to refresh somewhere to live.
This commit is contained in:
@@ -165,11 +165,24 @@ struct SubscriptionsView: View {
|
||||
}
|
||||
#endif
|
||||
|
||||
/// The feed error worth showing, if any.
|
||||
///
|
||||
/// Nothing while the context banner is up: a selected account that cannot be
|
||||
/// used reads local data, and the local feed then reports the Yattee Server
|
||||
/// it has no reason to have — "add a subscriptions account in Settings"
|
||||
/// under a banner saying *this* account needs signing in again is two
|
||||
/// answers to one question. The banner names the cause, so it is the one
|
||||
/// that stays.
|
||||
private var displayedFeedError: FeedLoadState.FeedLoadError? {
|
||||
guard contextUnavailability == nil,
|
||||
case let .error(error) = feedCache.feedLoadState
|
||||
else { return nil }
|
||||
|
||||
return error
|
||||
}
|
||||
|
||||
private var isShowingFullScreenError: Bool {
|
||||
if case .error = feedCache.feedLoadState, feedCache.videos.isEmpty {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
displayedFeedError != nil && feedCache.videos.isEmpty
|
||||
}
|
||||
|
||||
private var dataManager: DataManager? { appEnvironment?.dataManager }
|
||||
@@ -249,19 +262,21 @@ struct SubscriptionsView: View {
|
||||
.background(Color.black.opacity(0.3))
|
||||
#endif
|
||||
|
||||
case .error(let error):
|
||||
HStack(spacing: 8) {
|
||||
Image(systemName: "exclamationmark.triangle")
|
||||
Text(errorMessage(for: error))
|
||||
.font(.caption)
|
||||
case .error:
|
||||
if let error = displayedFeedError {
|
||||
HStack(spacing: 8) {
|
||||
Image(systemName: "exclamationmark.triangle")
|
||||
Text(errorMessage(for: error))
|
||||
.font(.caption)
|
||||
}
|
||||
.foregroundStyle(.red)
|
||||
.padding(.horizontal)
|
||||
.padding(.vertical, 8)
|
||||
.frame(maxWidth: .infinity)
|
||||
#if os(tvOS)
|
||||
.background(Color.black.opacity(0.3))
|
||||
#endif
|
||||
}
|
||||
.foregroundStyle(.red)
|
||||
.padding(.horizontal)
|
||||
.padding(.vertical, 8)
|
||||
.frame(maxWidth: .infinity)
|
||||
#if os(tvOS)
|
||||
.background(Color.black.opacity(0.3))
|
||||
#endif
|
||||
|
||||
case .loadingMore:
|
||||
HStack(spacing: 8) {
|
||||
@@ -640,7 +655,7 @@ struct SubscriptionsView: View {
|
||||
/// Feed content rows or empty/loading states.
|
||||
@ViewBuilder
|
||||
private var feedContentRows: some View {
|
||||
if case .error(let feedError) = feedCache.feedLoadState, feedCache.videos.isEmpty {
|
||||
if let feedError = displayedFeedError, feedCache.videos.isEmpty {
|
||||
// Show specific error states
|
||||
switch feedError {
|
||||
case .yatteeServerRequired:
|
||||
@@ -730,7 +745,7 @@ struct SubscriptionsView: View {
|
||||
#endif
|
||||
|
||||
// Content
|
||||
if case .error(let feedError) = feedCache.feedLoadState, feedCache.videos.isEmpty {
|
||||
if let feedError = displayedFeedError, feedCache.videos.isEmpty {
|
||||
// Show specific error states
|
||||
switch feedError {
|
||||
case .yatteeServerRequired:
|
||||
|
||||
Reference in New Issue
Block a user