mirror of
https://github.com/yattee/yattee.git
synced 2025-11-16 06:58:43 +00:00
Added height reservation to FavoriteItemView to prevent layout shifts during content loading. Changed HomeView to use LazyVStack for better performance. Converted QueueView from LazyVStack to VStack. Disabled animations on content count changes across multiple views to prevent jarring layout transitions. Added width constraint to stream button in PlaybackSettings.
247 lines
8.6 KiB
Swift
247 lines
8.6 KiB
Swift
import Defaults
|
|
import Siesta
|
|
import SwiftUI
|
|
import UniformTypeIdentifiers
|
|
|
|
struct HomeView: View {
|
|
@ObservedObject private var accounts = AccountsModel.shared
|
|
@ObservedObject private var player = PlayerModel.shared
|
|
|
|
@State private var presentingHomeSettings = false
|
|
@State private var favoritesChanged = false
|
|
@State private var updateTask: Task<Void, Never>?
|
|
|
|
@FetchRequest(sortDescriptors: [.init(key: "watchedAt", ascending: false)])
|
|
var watches: FetchedResults<Watch>
|
|
@State private var historyID = UUID()
|
|
#if os(iOS)
|
|
@State private var recentDocumentsID = UUID()
|
|
#endif
|
|
|
|
#if !os(tvOS)
|
|
@Default(.favorites) private var favorites
|
|
@Default(.widgetsSettings) private var widgetsSettings
|
|
#endif
|
|
@Default(.showFavoritesInHome) private var showFavoritesInHome
|
|
@Default(.showOpenActionsInHome) private var showOpenActionsInHome
|
|
@Default(.showQueueInHome) private var showQueueInHome
|
|
|
|
private var navigation: NavigationModel { .shared }
|
|
|
|
var body: some View {
|
|
ScrollView(.vertical, showsIndicators: false) {
|
|
LazyVStack(spacing: 0, pinnedViews: []) {
|
|
VStack {
|
|
#if !os(tvOS)
|
|
HStack {
|
|
if showOpenActionsInHome {
|
|
AccentButton(text: "Files", imageSystemName: "folder") {
|
|
NavigationModel.shared.presentingFileImporter = true
|
|
}
|
|
AccentButton(text: "Paste", imageSystemName: "doc.on.clipboard.fill") {
|
|
OpenVideosModel.shared.openURLsFromClipboard(playbackMode: .playNow)
|
|
}
|
|
AccentButton(imageSystemName: "ellipsis") {
|
|
NavigationModel.shared.presentingOpenVideos = true
|
|
}
|
|
.frame(maxWidth: 40)
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if os(tvOS)
|
|
HStack {
|
|
if showOpenActionsInHome {
|
|
Button {
|
|
NavigationModel.shared.presentingOpenVideos = true
|
|
} label: {
|
|
Label("Open Video", systemImage: "globe")
|
|
}
|
|
}
|
|
Button {
|
|
NavigationModel.shared.presentingAccounts = true
|
|
} label: {
|
|
Label("Locations", systemImage: "globe")
|
|
}
|
|
Spacer()
|
|
HideWatchedButtons()
|
|
HideShortsButtons()
|
|
Button {
|
|
NavigationModel.shared.presentingSettings = true
|
|
} label: {
|
|
Label("Settings", systemImage: "gear")
|
|
}
|
|
}
|
|
.font(.caption)
|
|
.imageScale(.small)
|
|
.foregroundColor(.primary)
|
|
#endif
|
|
}
|
|
.padding(.top, 15)
|
|
.padding(.bottom, 15)
|
|
#if os(tvOS)
|
|
.padding(.horizontal, 40)
|
|
#else
|
|
.padding(.horizontal, 15)
|
|
#endif
|
|
|
|
if showQueueInHome {
|
|
QueueView()
|
|
#if os(tvOS)
|
|
.padding(.horizontal, 40)
|
|
#else
|
|
.padding(.horizontal, 15)
|
|
#endif
|
|
}
|
|
|
|
if !accounts.current.isNil, showFavoritesInHome {
|
|
#if os(tvOS)
|
|
ForEach(Defaults[.favorites]) { item in
|
|
FavoriteItemView(item: item, favoritesChanged: $favoritesChanged)
|
|
.animation(nil, value: favoritesChanged)
|
|
}
|
|
#else
|
|
ForEach(favorites) { item in
|
|
FavoriteItemView(item: item, favoritesChanged: $favoritesChanged)
|
|
.animation(nil, value: favoritesChanged)
|
|
#if os(macOS)
|
|
.workaroundForVerticalScrollingBug()
|
|
#endif
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if !os(tvOS)
|
|
Color.clear.padding(.bottom, 60)
|
|
#endif
|
|
}
|
|
}
|
|
.animation(nil, value: favoritesChanged)
|
|
.onAppear {
|
|
updateTask = Task {
|
|
async let favoritesUpdates: Void = {
|
|
for await _ in Defaults.updates(.favorites) {
|
|
favoritesChanged.toggle()
|
|
}
|
|
}()
|
|
async let widgetsUpdates: Void = {
|
|
for await _ in Defaults.updates(.widgetsSettings) {
|
|
favoritesChanged.toggle()
|
|
}
|
|
}()
|
|
_ = await (favoritesUpdates, widgetsUpdates)
|
|
}
|
|
}
|
|
.onDisappear {
|
|
updateTask?.cancel()
|
|
}
|
|
|
|
.onChange(of: player.presentingPlayer) { presenting in
|
|
if presenting {
|
|
updateTask?.cancel()
|
|
} else {
|
|
updateTask = Task {
|
|
async let favoritesUpdates: Void = {
|
|
for await _ in Defaults.updates(.favorites) {
|
|
favoritesChanged.toggle()
|
|
}
|
|
}()
|
|
async let widgetsUpdates: Void = {
|
|
for await _ in Defaults.updates(.widgetsSettings) {
|
|
favoritesChanged.toggle()
|
|
}
|
|
}()
|
|
_ = await (favoritesUpdates, widgetsUpdates)
|
|
}
|
|
}
|
|
}
|
|
|
|
.redrawOn(change: favoritesChanged)
|
|
|
|
#if os(tvOS)
|
|
.edgesIgnoringSafeArea(.horizontal)
|
|
#else
|
|
.navigationTitle("Home")
|
|
#endif
|
|
#if os(macOS)
|
|
.background(Color.secondaryBackground)
|
|
.frame(minWidth: Constants.contentViewMinWidth)
|
|
.toolbar {
|
|
ToolbarItemGroup(placement: .automatic) {
|
|
HideWatchedButtons()
|
|
HideShortsButtons()
|
|
HomeSettingsButton()
|
|
}
|
|
}
|
|
#endif
|
|
#if os(iOS)
|
|
.navigationBarTitleDisplayMode(.inline)
|
|
.toolbar {
|
|
ToolbarItem(placement: .principal) {
|
|
homeMenu
|
|
}
|
|
}
|
|
#endif
|
|
#if !os(macOS)
|
|
.onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in
|
|
favoritesChanged.toggle()
|
|
}
|
|
#endif
|
|
}
|
|
|
|
func sectionLabel(_ label: String) -> some View {
|
|
Text(label.localized())
|
|
#if os(tvOS)
|
|
.padding(.horizontal, 40)
|
|
#else
|
|
.padding(.horizontal, 15)
|
|
#endif
|
|
.font(.title3.bold())
|
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
.foregroundColor(.secondary)
|
|
}
|
|
|
|
#if os(iOS)
|
|
var homeMenu: some View {
|
|
Menu {
|
|
Section {
|
|
HideWatchedButtons()
|
|
HideShortsButtons()
|
|
}
|
|
Section {
|
|
Button {
|
|
navigation.presentingHomeSettings = true
|
|
} label: {
|
|
Label("Home Settings", systemImage: "gear")
|
|
}
|
|
}
|
|
} label: {
|
|
HStack(spacing: 12) {
|
|
Text("Home")
|
|
.foregroundColor(.primary)
|
|
.font(.headline)
|
|
|
|
Image(systemName: "chevron.down.circle.fill")
|
|
.foregroundColor(.accentColor)
|
|
.imageScale(.small)
|
|
}
|
|
.transaction { t in t.animation = nil }
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
struct Home_Previews: PreviewProvider {
|
|
static var previews: some View {
|
|
TabView {
|
|
NavigationView {
|
|
HomeView()
|
|
.injectFixtureEnvironmentObjects()
|
|
.tabItem {
|
|
Label("Home", systemImage: "house")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|