[tvOS] ListView + Grid Landscape Poster Padding (#1213)
This commit is contained in:
parent
46f90bcb33
commit
498842bb84
|
@ -10,6 +10,7 @@ import Stinsen
|
|||
import SwiftUI
|
||||
|
||||
final class CustomizeSettingsCoordinator: NavigationCoordinatable {
|
||||
|
||||
let stack = NavigationStack(initial: \CustomizeSettingsCoordinator.start)
|
||||
|
||||
@Root
|
||||
|
@ -17,6 +18,8 @@ final class CustomizeSettingsCoordinator: NavigationCoordinatable {
|
|||
|
||||
@Route(.modal)
|
||||
var indicatorSettings = makeIndicatorSettings
|
||||
@Route(.modal)
|
||||
var listColumnSettings = makeListColumnSettings
|
||||
|
||||
func makeIndicatorSettings() -> NavigationViewCoordinator<BasicNavigationViewCoordinator> {
|
||||
NavigationViewCoordinator {
|
||||
|
@ -24,6 +27,10 @@ final class CustomizeSettingsCoordinator: NavigationCoordinatable {
|
|||
}
|
||||
}
|
||||
|
||||
func makeListColumnSettings(selection: Binding<Int>) -> some View {
|
||||
ListColumnsPickerView(selection: selection)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func makeStart() -> some View {
|
||||
CustomizeViewsSettings()
|
||||
|
|
|
@ -82,8 +82,6 @@ final class SettingsCoordinator: NavigationCoordinatable {
|
|||
@Route(.modal)
|
||||
var experimentalSettings = makeExperimentalSettings
|
||||
@Route(.modal)
|
||||
var indicatorSettings = makeIndicatorSettings
|
||||
@Route(.modal)
|
||||
var log = makeLog
|
||||
@Route(.modal)
|
||||
var serverDetail = makeServerDetail
|
||||
|
|
|
@ -168,6 +168,8 @@ internal enum L10n {
|
|||
internal static let collections = L10n.tr("Localizable", "collections", fallback: "Collections")
|
||||
/// Color
|
||||
internal static let color = L10n.tr("Localizable", "color", fallback: "Color")
|
||||
/// Columns
|
||||
internal static let columns = L10n.tr("Localizable", "columns", fallback: "Columns")
|
||||
/// Coming soon
|
||||
internal static let comingSoon = L10n.tr("Localizable", "comingSoon", fallback: "Coming soon")
|
||||
/// Compact
|
||||
|
|
|
@ -13,6 +13,11 @@ struct StepperView<Value: CustomStringConvertible & Strideable>: View {
|
|||
@Binding
|
||||
private var value: Value
|
||||
|
||||
@State
|
||||
private var updatedValue: Value
|
||||
@Environment(\.presentationMode)
|
||||
private var presentationMode
|
||||
|
||||
private var title: String
|
||||
private var description: String?
|
||||
private var range: ClosedRange<Value>
|
||||
|
@ -36,7 +41,7 @@ struct StepperView<Value: CustomStringConvertible & Strideable>: View {
|
|||
}
|
||||
.frame(maxHeight: .infinity)
|
||||
|
||||
formatter(value).text
|
||||
formatter(updatedValue).text
|
||||
.font(.title)
|
||||
.frame(height: 250)
|
||||
|
||||
|
@ -44,8 +49,10 @@ struct StepperView<Value: CustomStringConvertible & Strideable>: View {
|
|||
|
||||
HStack {
|
||||
Button {
|
||||
guard value >= range.lowerBound else { return }
|
||||
value = value.advanced(by: -step)
|
||||
if updatedValue > range.lowerBound {
|
||||
updatedValue = max(updatedValue.advanced(by: -step), range.lowerBound)
|
||||
value = updatedValue
|
||||
}
|
||||
} label: {
|
||||
Image(systemName: "minus")
|
||||
.font(.title2.weight(.bold))
|
||||
|
@ -54,8 +61,10 @@ struct StepperView<Value: CustomStringConvertible & Strideable>: View {
|
|||
.buttonStyle(.card)
|
||||
|
||||
Button {
|
||||
guard value <= range.upperBound else { return }
|
||||
value = value.advanced(by: step)
|
||||
if updatedValue < range.upperBound {
|
||||
updatedValue = min(updatedValue.advanced(by: step), range.upperBound)
|
||||
value = updatedValue
|
||||
}
|
||||
} label: {
|
||||
Image(systemName: "plus")
|
||||
.font(.title2.weight(.bold))
|
||||
|
@ -64,10 +73,9 @@ struct StepperView<Value: CustomStringConvertible & Strideable>: View {
|
|||
.buttonStyle(.card)
|
||||
}
|
||||
|
||||
Button {
|
||||
Button(L10n.close) {
|
||||
onCloseSelected()
|
||||
} label: {
|
||||
Text("Close")
|
||||
presentationMode.wrappedValue.dismiss()
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
@ -86,15 +94,14 @@ extension StepperView {
|
|||
range: ClosedRange<Value>,
|
||||
step: Value.Stride
|
||||
) {
|
||||
self.init(
|
||||
value: value,
|
||||
title: title,
|
||||
description: description,
|
||||
range: range,
|
||||
step: step,
|
||||
formatter: { $0.description },
|
||||
onCloseSelected: {}
|
||||
)
|
||||
self._value = value
|
||||
self._updatedValue = State(initialValue: value.wrappedValue)
|
||||
self.title = title
|
||||
self.description = description
|
||||
self.range = range
|
||||
self.step = step
|
||||
self.formatter = { $0.description }
|
||||
self.onCloseSelected = {}
|
||||
}
|
||||
|
||||
func valueFormatter(_ formatter: @escaping (Value) -> String) -> Self {
|
||||
|
|
|
@ -0,0 +1,165 @@
|
|||
//
|
||||
// Swiftfin is subject to the terms of the Mozilla Public
|
||||
// License, v2.0. If a copy of the MPL was not distributed with this
|
||||
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
//
|
||||
// Copyright (c) 2024 Jellyfin & Jellyfin Contributors
|
||||
//
|
||||
|
||||
import Defaults
|
||||
import JellyfinAPI
|
||||
import SwiftUI
|
||||
|
||||
extension PagingLibraryView {
|
||||
|
||||
struct LibraryRow: View {
|
||||
|
||||
@State
|
||||
private var contentWidth: CGFloat = 0
|
||||
@State
|
||||
private var focusedItem: Element?
|
||||
|
||||
@FocusState
|
||||
private var isFocused: Bool
|
||||
|
||||
private let item: Element
|
||||
private var action: () -> Void
|
||||
private var contextMenu: () -> any View
|
||||
private let posterType: PosterDisplayType
|
||||
|
||||
private var onFocusChanged: ((Bool) -> Void)?
|
||||
|
||||
private func imageView(from element: Element) -> ImageView {
|
||||
switch posterType {
|
||||
case .landscape:
|
||||
ImageView(element.landscapeImageSources(maxWidth: 110))
|
||||
case .portrait:
|
||||
ImageView(element.portraitImageSources(maxWidth: 60))
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func itemAccessoryView(item: BaseItemDto) -> some View {
|
||||
DotHStack {
|
||||
if item.type == .episode, let seasonEpisodeLocator = item.seasonEpisodeLabel {
|
||||
Text(seasonEpisodeLocator)
|
||||
} else if let premiereYear = item.premiereDateYear {
|
||||
Text(premiereYear)
|
||||
}
|
||||
|
||||
if let runtime = item.runTimeLabel {
|
||||
Text(runtime)
|
||||
}
|
||||
|
||||
if let officialRating = item.officialRating {
|
||||
Text(officialRating)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func personAccessoryView(person: BaseItemPerson) -> some View {
|
||||
if let subtitle = person.subtitle {
|
||||
Text(subtitle)
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var accessoryView: some View {
|
||||
switch item {
|
||||
case let element as BaseItemDto:
|
||||
itemAccessoryView(item: element)
|
||||
case let element as BaseItemPerson:
|
||||
personAccessoryView(person: element)
|
||||
default:
|
||||
AssertionFailureView("Used an unexpected type within a `PagingLibaryView`?")
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var rowContent: some View {
|
||||
HStack {
|
||||
VStack(alignment: .leading, spacing: 5) {
|
||||
Text(item.displayTitle)
|
||||
.font(posterType == .landscape ? .subheadline : .callout)
|
||||
.fontWeight(.semibold)
|
||||
.foregroundColor(.primary)
|
||||
.lineLimit(2)
|
||||
.multilineTextAlignment(.leading)
|
||||
|
||||
accessoryView
|
||||
.font(.caption)
|
||||
.foregroundColor(Color(UIColor.lightGray))
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var rowLeading: some View {
|
||||
ZStack {
|
||||
Color.clear
|
||||
|
||||
imageView(from: item)
|
||||
.failure {
|
||||
SystemImageContentView(systemName: item.systemImage)
|
||||
}
|
||||
}
|
||||
.posterStyle(posterType)
|
||||
.frame(width: posterType == .landscape ? 110 : 60)
|
||||
.posterShadow()
|
||||
.padding(.vertical, 8)
|
||||
}
|
||||
|
||||
// MARK: body
|
||||
|
||||
var body: some View {
|
||||
ListRow(insets: .init(horizontal: EdgeInsets.edgePadding)) {
|
||||
rowLeading
|
||||
} content: {
|
||||
rowContent
|
||||
}
|
||||
.onSelect(perform: action)
|
||||
.contextMenu(menuItems: {
|
||||
contextMenu()
|
||||
.eraseToAnyView()
|
||||
})
|
||||
.posterShadow()
|
||||
.ifLet(onFocusChanged) { view, onFocusChanged in
|
||||
view
|
||||
.focused($isFocused)
|
||||
.onChange(of: isFocused) { _, newValue in
|
||||
onFocusChanged(newValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension PagingLibraryView.LibraryRow {
|
||||
|
||||
init(item: Element, posterType: PosterDisplayType) {
|
||||
self.init(
|
||||
item: item,
|
||||
action: {},
|
||||
contextMenu: { EmptyView() },
|
||||
posterType: posterType,
|
||||
onFocusChanged: nil
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
extension PagingLibraryView.LibraryRow {
|
||||
|
||||
func onSelect(perform action: @escaping () -> Void) -> Self {
|
||||
copy(modifying: \.action, with: action)
|
||||
}
|
||||
|
||||
func contextMenu(@ViewBuilder perform content: @escaping () -> any View) -> Self {
|
||||
copy(modifying: \.contextMenu, with: content)
|
||||
}
|
||||
|
||||
func onFocusChanged(perform action: @escaping (Bool) -> Void) -> Self {
|
||||
copy(modifying: \.onFocusChanged, with: action)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
//
|
||||
// Swiftfin is subject to the terms of the Mozilla Public
|
||||
// License, v2.0. If a copy of the MPL was not distributed with this
|
||||
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
//
|
||||
// Copyright (c) 2024 Jellyfin & Jellyfin Contributors
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
// TODO: come up with better name along with `ListRowButton`
|
||||
|
||||
// Meant to be used when making a custom list without `List` or `Form`
|
||||
struct ListRow<Leading: View, Content: View>: View {
|
||||
|
||||
@State
|
||||
private var contentSize: CGSize = .zero
|
||||
|
||||
private let leading: () -> Leading
|
||||
private let content: () -> Content
|
||||
private var action: () -> Void
|
||||
private var insets: EdgeInsets
|
||||
private var isSeparatorVisible: Bool
|
||||
|
||||
var body: some View {
|
||||
ZStack(alignment: .bottomTrailing) {
|
||||
|
||||
Button {
|
||||
action()
|
||||
} label: {
|
||||
HStack(alignment: .center, spacing: EdgeInsets.edgePadding) {
|
||||
|
||||
leading()
|
||||
|
||||
content()
|
||||
.frame(maxHeight: .infinity)
|
||||
.trackingSize($contentSize)
|
||||
}
|
||||
.padding(.top, insets.top)
|
||||
.padding(.bottom, insets.bottom)
|
||||
.padding(.leading, insets.leading)
|
||||
.padding(.trailing, insets.trailing)
|
||||
}
|
||||
.foregroundStyle(.primary, .secondary)
|
||||
.buttonStyle(.plain)
|
||||
|
||||
Color.secondarySystemFill
|
||||
.frame(width: contentSize.width, height: 1)
|
||||
.padding(.trailing, insets.trailing)
|
||||
.visible(isSeparatorVisible)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension ListRow {
|
||||
|
||||
init(
|
||||
insets: EdgeInsets = .zero,
|
||||
@ViewBuilder leading: @escaping () -> Leading,
|
||||
@ViewBuilder content: @escaping () -> Content
|
||||
) {
|
||||
self.init(
|
||||
leading: leading,
|
||||
content: content,
|
||||
action: {},
|
||||
insets: insets,
|
||||
isSeparatorVisible: true
|
||||
)
|
||||
}
|
||||
|
||||
func isSeparatorVisible(_ isVisible: Bool) -> Self {
|
||||
copy(modifying: \.isSeparatorVisible, with: isVisible)
|
||||
}
|
||||
|
||||
func onSelect(perform action: @escaping () -> Void) -> Self {
|
||||
copy(modifying: \.action, with: action)
|
||||
}
|
||||
}
|
|
@ -49,11 +49,13 @@ struct PagingLibraryView<Element: Poster>: View {
|
|||
|
||||
let initialPosterType = Defaults[.Customization.Library.posterType]
|
||||
let initialViewType = Defaults[.Customization.Library.displayType]
|
||||
let listColumnCount = Defaults[.Customization.Library.listColumnCount]
|
||||
|
||||
self._layout = State(
|
||||
initialValue: Self.makeLayout(
|
||||
posterType: initialPosterType,
|
||||
viewType: initialViewType
|
||||
displayType: initialViewType,
|
||||
listColumnCount: listColumnCount
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -90,15 +92,16 @@ struct PagingLibraryView<Element: Poster>: View {
|
|||
|
||||
private static func makeLayout(
|
||||
posterType: PosterDisplayType,
|
||||
viewType: LibraryDisplayType
|
||||
displayType: LibraryDisplayType,
|
||||
listColumnCount: Int
|
||||
) -> CollectionVGridLayout {
|
||||
switch (posterType, viewType) {
|
||||
switch (posterType, displayType) {
|
||||
case (.landscape, .grid):
|
||||
.columns(5)
|
||||
return .columns(5, insets: .init(50), itemSpacing: 50, lineSpacing: 50)
|
||||
case (.portrait, .grid):
|
||||
.columns(7, insets: .init(50), itemSpacing: 50, lineSpacing: 50)
|
||||
return .columns(7, insets: .init(50), itemSpacing: 50, lineSpacing: 50)
|
||||
case (_, .list):
|
||||
.columns(1)
|
||||
return .columns(listColumnCount, insets: .init(50), itemSpacing: 50, lineSpacing: 50)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -140,8 +143,17 @@ struct PagingLibraryView<Element: Poster>: View {
|
|||
}
|
||||
}
|
||||
|
||||
private func listItemView(item: Element) -> some View {
|
||||
Button(item.displayTitle)
|
||||
@ViewBuilder
|
||||
private func listItemView(item: Element, posterType: PosterDisplayType) -> some View {
|
||||
LibraryRow(item: item, posterType: posterType)
|
||||
.onFocusChanged { newValue in
|
||||
if newValue {
|
||||
focusedItem = item
|
||||
}
|
||||
}
|
||||
.onSelect {
|
||||
onSelect(item)
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
|
@ -156,7 +168,7 @@ struct PagingLibraryView<Element: Poster>: View {
|
|||
case (.portrait, .grid):
|
||||
portraitGridItemView(item: item)
|
||||
case (_, .list):
|
||||
listItemView(item: item)
|
||||
listItemView(item: item, posterType: posterType)
|
||||
}
|
||||
}
|
||||
.onReachedBottomEdge(offset: .rows(3)) {
|
|
@ -0,0 +1,25 @@
|
|||
//
|
||||
// Swiftfin is subject to the terms of the Mozilla Public
|
||||
// License, v2.0. If a copy of the MPL was not distributed with this
|
||||
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
//
|
||||
// Copyright (c) 2024 Jellyfin & Jellyfin Contributors
|
||||
//
|
||||
|
||||
import Defaults
|
||||
import SwiftUI
|
||||
|
||||
struct ListColumnsPickerView: View {
|
||||
|
||||
@Binding
|
||||
var selection: Int
|
||||
|
||||
var body: some View {
|
||||
StepperView(
|
||||
title: "Columns",
|
||||
value: $selection,
|
||||
range: 1 ... 3,
|
||||
step: 1
|
||||
)
|
||||
}
|
||||
}
|
|
@ -37,6 +37,12 @@ struct CustomizeViewsSettings: View {
|
|||
private var libraryRandomImage
|
||||
@Default(.Customization.Library.showFavorites)
|
||||
private var showFavorites
|
||||
@Default(.Customization.Library.displayType)
|
||||
private var libraryDisplayType
|
||||
@Default(.Customization.Library.posterType)
|
||||
private var libraryPosterType
|
||||
@Default(.Customization.Library.listColumnCount)
|
||||
private var listColumnCount
|
||||
|
||||
@EnvironmentObject
|
||||
private var router: CustomizeSettingsCoordinator.Router
|
||||
|
@ -76,8 +82,6 @@ struct CustomizeViewsSettings: View {
|
|||
InlineEnumToggle(title: L10n.recommended, selection: $similarPosterType)
|
||||
|
||||
InlineEnumToggle(title: L10n.search, selection: $searchPosterType)
|
||||
|
||||
InlineEnumToggle(title: L10n.library, selection: $libraryViewType)
|
||||
}
|
||||
|
||||
Section(L10n.library) {
|
||||
|
@ -87,6 +91,18 @@ struct CustomizeViewsSettings: View {
|
|||
Toggle(L10n.randomImage, isOn: $libraryRandomImage)
|
||||
|
||||
Toggle(L10n.showFavorites, isOn: $showFavorites)
|
||||
|
||||
InlineEnumToggle(title: L10n.posters, selection: $libraryPosterType)
|
||||
InlineEnumToggle(title: L10n.library, selection: $libraryDisplayType)
|
||||
if libraryDisplayType == .list {
|
||||
ChevronButton(
|
||||
L10n.columns,
|
||||
subtitle: listColumnCount.description
|
||||
)
|
||||
.onSelect {
|
||||
router.route(to: \.listColumnSettings, $listColumnCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HomeSection()
|
||||
|
|
|
@ -73,6 +73,9 @@
|
|||
4ECDAA9E2C920A8E0030F2F5 /* TranscodeReason.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4ECDAA9D2C920A8E0030F2F5 /* TranscodeReason.swift */; };
|
||||
4ECDAA9F2C920A8E0030F2F5 /* TranscodeReason.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4ECDAA9D2C920A8E0030F2F5 /* TranscodeReason.swift */; };
|
||||
4EE141692C8BABDF0045B661 /* ProgressSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EE141682C8BABDF0045B661 /* ProgressSection.swift */; };
|
||||
4EF18B262CB9934C00343666 /* LibraryRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EF18B252CB9934700343666 /* LibraryRow.swift */; };
|
||||
4EF18B282CB9936D00343666 /* ListColumnsPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EF18B272CB9936400343666 /* ListColumnsPickerView.swift */; };
|
||||
4EF18B2A2CB993BD00343666 /* ListRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EF18B292CB993AD00343666 /* ListRow.swift */; };
|
||||
531690E7267ABD79005D8AB9 /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 531690E6267ABD79005D8AB9 /* HomeView.swift */; };
|
||||
531AC8BF26750DE20091C7EB /* ImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 531AC8BE26750DE20091C7EB /* ImageView.swift */; };
|
||||
5321753B2671BCFC005491E6 /* SettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5321753A2671BCFC005491E6 /* SettingsViewModel.swift */; };
|
||||
|
@ -1061,6 +1064,9 @@
|
|||
4EC6C16A2C92999800FC904B /* TranscodeSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranscodeSection.swift; sourceTree = "<group>"; };
|
||||
4ECDAA9D2C920A8E0030F2F5 /* TranscodeReason.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranscodeReason.swift; sourceTree = "<group>"; };
|
||||
4EE141682C8BABDF0045B661 /* ProgressSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressSection.swift; sourceTree = "<group>"; };
|
||||
4EF18B252CB9934700343666 /* LibraryRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryRow.swift; sourceTree = "<group>"; };
|
||||
4EF18B272CB9936400343666 /* ListColumnsPickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListColumnsPickerView.swift; sourceTree = "<group>"; };
|
||||
4EF18B292CB993AD00343666 /* ListRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRow.swift; sourceTree = "<group>"; };
|
||||
531690E6267ABD79005D8AB9 /* HomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeView.swift; sourceTree = "<group>"; };
|
||||
531AC8BE26750DE20091C7EB /* ImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageView.swift; sourceTree = "<group>"; };
|
||||
5321753A2671BCFC005491E6 /* SettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewModel.swift; sourceTree = "<group>"; };
|
||||
|
@ -1905,6 +1911,7 @@
|
|||
4E699BBD2CB34746007CBD5D /* Components */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4EF18B272CB9936400343666 /* ListColumnsPickerView.swift */,
|
||||
4E699BBE2CB3474C007CBD5D /* Sections */,
|
||||
);
|
||||
path = Components;
|
||||
|
@ -1990,6 +1997,24 @@
|
|||
path = Components;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4EF18B232CB9932F00343666 /* PagingLibraryView */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4EF18B242CB9933700343666 /* Components */,
|
||||
E111D8F928D0400900400001 /* PagingLibraryView.swift */,
|
||||
);
|
||||
path = PagingLibraryView;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4EF18B242CB9933700343666 /* Components */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4EF18B252CB9934700343666 /* LibraryRow.swift */,
|
||||
4EF18B292CB993AD00343666 /* ListRow.swift */,
|
||||
);
|
||||
path = Components;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5310694F2684E7EE00CFFDBA /* VideoPlayer */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -2181,7 +2206,6 @@
|
|||
E1763A632BF3C9AA004DF6AB /* ListRowButton.swift */,
|
||||
E10E842B29A589860064EA49 /* NonePosterButton.swift */,
|
||||
4E2AC4D32C6C4C1200DD600D /* OrderedSectionSelectorView.swift */,
|
||||
E111D8F928D0400900400001 /* PagingLibraryView.swift */,
|
||||
E1C92617288756BD002A7A66 /* PosterButton.swift */,
|
||||
E1C92619288756BD002A7A66 /* PosterHStack.swift */,
|
||||
E12CC1C428D12D9B00678D5D /* SeeAllPosterButton.swift */,
|
||||
|
@ -2923,6 +2947,7 @@
|
|||
E10231572BCF8AF8009D71FC /* ProgramsView */,
|
||||
E10B1E8C2BD7708900A92EAF /* QuickConnectView.swift */,
|
||||
E1E1643928BAC2EF00323B0A /* SearchView.swift */,
|
||||
4EF18B232CB9932F00343666 /* PagingLibraryView */,
|
||||
E193D54A271941D300900D82 /* SelectServerView.swift */,
|
||||
E164A8122BE4995200A54B18 /* SelectUserView */,
|
||||
E193D54F2719430400900D82 /* ServerDetailView.swift */,
|
||||
|
@ -4266,6 +4291,7 @@
|
|||
E190704C2C858CEB0004600E /* VideoPlayerType+Shared.swift in Sources */,
|
||||
E152107D2947ACA000375CC2 /* InvertedLightAppIcon.swift in Sources */,
|
||||
E1549663296CA2EF00C4EF88 /* UserSession.swift in Sources */,
|
||||
4EF18B2A2CB993BD00343666 /* ListRow.swift in Sources */,
|
||||
531690E7267ABD79005D8AB9 /* HomeView.swift in Sources */,
|
||||
E145EB232BDCCA43003BF6F3 /* BulletedList.swift in Sources */,
|
||||
E104DC972B9E7E29008F506D /* AssertionFailureView.swift in Sources */,
|
||||
|
@ -4476,6 +4502,7 @@
|
|||
E1575E66293E77B5001665B1 /* Poster.swift in Sources */,
|
||||
E18E021F2887492B0022598C /* SystemImageContentView.swift in Sources */,
|
||||
E19D41B42BF2C0020082B8B2 /* StoredValues+Temp.swift in Sources */,
|
||||
4EF18B282CB9936D00343666 /* ListColumnsPickerView.swift in Sources */,
|
||||
E11BDF7B2B85529D0045C54A /* SupportedCaseIterable.swift in Sources */,
|
||||
4E204E592C574FD9004D22A2 /* CustomizeSettingsCoordinator.swift in Sources */,
|
||||
E1575E8C293E7B1E001665B1 /* UIScreen.swift in Sources */,
|
||||
|
@ -4488,6 +4515,7 @@
|
|||
E1DABAFA2A270E62008AC34A /* OverviewCard.swift in Sources */,
|
||||
E11CEB8928998549003E74C7 /* BottomEdgeGradientModifier.swift in Sources */,
|
||||
4E2AC4CC2C6C494E00DD600D /* VideoCodec.swift in Sources */,
|
||||
4EF18B262CB9934C00343666 /* LibraryRow.swift in Sources */,
|
||||
E129428628F080B500796AC6 /* OnReceiveNotificationModifier.swift in Sources */,
|
||||
53ABFDE7267974EF00886593 /* ConnectToServerViewModel.swift in Sources */,
|
||||
62E632E4267D3BA60063E547 /* MovieItemViewModel.swift in Sources */,
|
||||
|
|
Binary file not shown.
Loading…
Reference in New Issue