mirror of
https://github.com/yattee/yattee.git
synced 2026-02-21 10:19:46 +00:00
Show toolbar buttons and tab picker during channel loading
Display the view options button, channel menu, and content type tabs immediately when the cached header is shown, instead of waiting for the full channel data to load. The spinner now appears only in the content area below the tabs.
This commit is contained in:
@@ -10953,6 +10953,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"settings.icloud.dev.badge" : {
|
"settings.icloud.dev.badge" : {
|
||||||
|
"extractionState" : "stale",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
"stringUnit" : {
|
"stringUnit" : {
|
||||||
@@ -10963,6 +10964,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"settings.icloud.dev.footer" : {
|
"settings.icloud.dev.footer" : {
|
||||||
|
"extractionState" : "stale",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
"stringUnit" : {
|
"stringUnit" : {
|
||||||
@@ -10973,6 +10975,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"settings.icloud.dev.title" : {
|
"settings.icloud.dev.title" : {
|
||||||
|
"extractionState" : "stale",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
"stringUnit" : {
|
"stringUnit" : {
|
||||||
@@ -14649,17 +14652,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sources.field.proxiesVideos" : {
|
|
||||||
"comment" : "Toggle label for video proxy option",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Proxy videos"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"sources.field.password" : {
|
"sources.field.password" : {
|
||||||
"comment" : "Field label for password",
|
"comment" : "Field label for password",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@@ -14704,6 +14696,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"sources.field.proxiesVideos" : {
|
||||||
|
"comment" : "Toggle label for video proxy option",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Proxy videos"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"sources.field.serverVersion" : {
|
"sources.field.serverVersion" : {
|
||||||
"comment" : "Field label for server version in Yattee Server info",
|
"comment" : "Field label for server version in Yattee Server info",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@@ -14792,17 +14795,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sources.footer.proxiesVideos" : {
|
|
||||||
"comment" : "Footer text explaining video proxy option",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "Route video streams through this instance instead of connecting directly. Enable if direct video playback is blocked."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"sources.footer.auth" : {
|
"sources.footer.auth" : {
|
||||||
"comment" : "Footer text for authentication section",
|
"comment" : "Footer text for authentication section",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@@ -14847,6 +14839,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"sources.footer.proxiesVideos" : {
|
||||||
|
"comment" : "Footer text explaining video proxy option",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Route video streams through this instance instead of connecting directly. Enable if direct video playback is blocked."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"sources.footer.remoteServer" : {
|
"sources.footer.remoteServer" : {
|
||||||
"comment" : "Footer text for remote server URL entry",
|
"comment" : "Footer text for remote server URL entry",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
|
|||||||
@@ -381,10 +381,17 @@ struct ChannelView: View {
|
|||||||
header(name: cached.name, thumbnailURL: cached.thumbnailURL, bannerURL: cached.bannerURL)
|
header(name: cached.name, thumbnailURL: cached.thumbnailURL, bannerURL: cached.bannerURL)
|
||||||
.id("channelTop")
|
.id("channelTop")
|
||||||
|
|
||||||
// Centered spinner for content area
|
// Show tab picker during loading (doesn't depend on channel)
|
||||||
|
if supportsChannelTabs {
|
||||||
|
contentTypePicker
|
||||||
|
.padding(.horizontal)
|
||||||
|
.padding(.vertical, 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Centered spinner for content area below tabs
|
||||||
ProgressView()
|
ProgressView()
|
||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
.padding(.top, 60)
|
.padding(.top, 40)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onChange(of: geometry.size.width, initial: true) { _, newWidth in
|
.onChange(of: geometry.size.width, initial: true) { _, newWidth in
|
||||||
@@ -418,11 +425,56 @@ struct ChannelView: View {
|
|||||||
}
|
}
|
||||||
.opacity(collapsedTitleOpacity)
|
.opacity(collapsedTitleOpacity)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ToolbarItem(placement: .primaryAction) {
|
||||||
|
Button {
|
||||||
|
showViewOptions = true
|
||||||
|
} label: {
|
||||||
|
Label(String(localized: "viewOptions.title"), systemImage: "slider.horizontal.3")
|
||||||
|
}
|
||||||
|
.liquidGlassTransitionSource(id: "channelViewOptions", in: sheetTransition)
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !os(tvOS)
|
||||||
|
if #available(iOS 26, macOS 26, *) {
|
||||||
|
ToolbarSpacer(.fixed, placement: .primaryAction)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ToolbarItem(placement: .primaryAction) {
|
||||||
|
channelMenu
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
.sheet(isPresented: $showViewOptions) {
|
||||||
|
ViewOptionsSheet(
|
||||||
|
layout: $layout,
|
||||||
|
rowStyle: $rowStyle,
|
||||||
|
gridColumns: $gridColumns,
|
||||||
|
hideWatched: $hideWatched,
|
||||||
|
maxGridColumns: gridConfig.maxColumns
|
||||||
|
)
|
||||||
|
.liquidGlassSheetContent(sourceID: "channelViewOptions", in: sheetTransition)
|
||||||
|
}
|
||||||
|
#if os(iOS)
|
||||||
|
.toolbarBackground(collapseProgress > 0.8 ? .visible : .hidden, for: .navigationBar)
|
||||||
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
|
#endif
|
||||||
.modifier(ChannelScrollOffsetModifier(
|
.modifier(ChannelScrollOffsetModifier(
|
||||||
scrollOffset: $scrollOffset,
|
scrollOffset: $scrollOffset,
|
||||||
isPlayerExpanded: appEnvironment?.navigationCoordinator.isPlayerExpanded ?? false
|
isPlayerExpanded: appEnvironment?.navigationCoordinator.isPlayerExpanded ?? false
|
||||||
))
|
))
|
||||||
|
.confirmationDialog(
|
||||||
|
String(localized: "channel.unsubscribe.confirmation.title"),
|
||||||
|
isPresented: $showingUnsubscribeConfirmation,
|
||||||
|
titleVisibility: .visible
|
||||||
|
) {
|
||||||
|
Button(String(localized: "channel.unsubscribe.confirmation.action"), role: .destructive) {
|
||||||
|
unsubscribe()
|
||||||
|
}
|
||||||
|
Button(String(localized: "common.cancel"), role: .cancel) {}
|
||||||
|
} message: {
|
||||||
|
Text(String(localized: "channel.unsubscribe.confirmation.message"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Header
|
// MARK: - Header
|
||||||
|
|||||||
Reference in New Issue
Block a user