Cleanup (#1075)
This commit is contained in:
parent
b987d6d7ae
commit
fd4052ed53
|
@ -22,4 +22,22 @@ enum LetterPickerOrientation: String, CaseIterable, Defaults.Serializable, Displ
|
||||||
return L10n.right
|
return L10n.right
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var alignment: Alignment {
|
||||||
|
switch self {
|
||||||
|
case .leading:
|
||||||
|
.leading
|
||||||
|
case .trailing:
|
||||||
|
.trailing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var edge: Edge.Set {
|
||||||
|
switch self {
|
||||||
|
case .leading:
|
||||||
|
.leading
|
||||||
|
case .trailing:
|
||||||
|
.trailing
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
//
|
||||||
|
// 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 Foundation
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
extension Backport {
|
||||||
|
|
||||||
|
enum ScrollIndicatorVisibility {
|
||||||
|
|
||||||
|
case automatic
|
||||||
|
case visible
|
||||||
|
case hidden
|
||||||
|
case never
|
||||||
|
|
||||||
|
@available(iOS 16, tvOS 16, *)
|
||||||
|
var supportedValue: SwiftUI.ScrollIndicatorVisibility {
|
||||||
|
switch self {
|
||||||
|
case .automatic: .automatic
|
||||||
|
case .visible: .visible
|
||||||
|
case .hidden: .hidden
|
||||||
|
case .never: .never
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -51,6 +51,18 @@ extension Backport where Content: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
func scrollIndicators(_ visibility: Backport.ScrollIndicatorVisibility) -> some View {
|
||||||
|
if #available(iOS 16, tvOS 16, *) {
|
||||||
|
content.scrollIndicators(visibility.supportedValue)
|
||||||
|
} else {
|
||||||
|
content.introspect(.scrollView, on: .iOS(.v15), .tvOS(.v15)) { scrollView in
|
||||||
|
scrollView.showsHorizontalScrollIndicator = visibility == .visible
|
||||||
|
scrollView.showsVerticalScrollIndicator = visibility == .visible
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
|
|
||||||
// TODO: - remove comment when migrated away from Stinsen
|
// TODO: - remove comment when migrated away from Stinsen
|
|
@ -0,0 +1,38 @@
|
||||||
|
//
|
||||||
|
// 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: both axes
|
||||||
|
|
||||||
|
struct ScrollIfLargerThanContainerModifier: ViewModifier {
|
||||||
|
|
||||||
|
@State
|
||||||
|
private var contentSize: CGSize = .zero
|
||||||
|
@State
|
||||||
|
private var layoutSize: CGSize = .zero
|
||||||
|
|
||||||
|
let padding: CGFloat
|
||||||
|
|
||||||
|
func body(content: Content) -> some View {
|
||||||
|
AlternateLayoutView {
|
||||||
|
Color.clear
|
||||||
|
.trackingSize($layoutSize)
|
||||||
|
} content: {
|
||||||
|
ScrollView {
|
||||||
|
content
|
||||||
|
.trackingSize($contentSize)
|
||||||
|
}
|
||||||
|
.frame(maxHeight: contentSize.height >= layoutSize.height ? .infinity : contentSize.height)
|
||||||
|
.backport
|
||||||
|
.scrollDisabled(contentSize.height < layoutSize.height)
|
||||||
|
.backport
|
||||||
|
.scrollIndicators(.never)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,27 +0,0 @@
|
||||||
//
|
|
||||||
// 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
|
|
||||||
|
|
||||||
struct ScrollIfLargerThanModifier: ViewModifier {
|
|
||||||
|
|
||||||
@State
|
|
||||||
private var contentSize: CGSize = .zero
|
|
||||||
|
|
||||||
let height: CGFloat
|
|
||||||
|
|
||||||
func body(content: Content) -> some View {
|
|
||||||
ScrollView {
|
|
||||||
content
|
|
||||||
.trackingSize($contentSize)
|
|
||||||
}
|
|
||||||
.backport
|
|
||||||
.scrollDisabled(contentSize.height < height)
|
|
||||||
.frame(maxHeight: contentSize.height >= height ? .infinity : contentSize.height)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -328,13 +328,13 @@ extension View {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func scroll(ifLargerThan height: CGFloat) -> some View {
|
func scrollIfLargerThanContainer(padding: CGFloat = 0) -> some View {
|
||||||
modifier(ScrollIfLargerThanModifier(height: height))
|
modifier(ScrollIfLargerThanContainerModifier(padding: padding))
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: debug
|
// MARK: debug
|
||||||
|
|
||||||
// Useful modifiers during development for layout
|
// Useful modifiers during development for layout without RocketSim
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
func debugBackground<S: ShapeStyle>(_ fill: S = .red.opacity(0.5)) -> some View {
|
func debugBackground<S: ShapeStyle>(_ fill: S = .red.opacity(0.5)) -> some View {
|
||||||
|
|
|
@ -190,7 +190,7 @@ struct SelectUserView: View {
|
||||||
|
|
||||||
gridContentView
|
gridContentView
|
||||||
}
|
}
|
||||||
.scroll(ifLargerThan: contentSize.height - 100)
|
.scrollIfLargerThanContainer(padding: 100)
|
||||||
.scrollViewOffset($scrollViewOffset)
|
.scrollViewOffset($scrollViewOffset)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
4E5E48E52AB59806003F1B48 /* CustomizeViewsSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E5E48E42AB59806003F1B48 /* CustomizeViewsSettings.swift */; };
|
4E5E48E52AB59806003F1B48 /* CustomizeViewsSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E5E48E42AB59806003F1B48 /* CustomizeViewsSettings.swift */; };
|
||||||
4E8B34EA2AB91B6E0018F305 /* ItemFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E8B34E92AB91B6E0018F305 /* ItemFilter.swift */; };
|
4E8B34EA2AB91B6E0018F305 /* ItemFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E8B34E92AB91B6E0018F305 /* ItemFilter.swift */; };
|
||||||
4E8B34EB2AB91B6E0018F305 /* ItemFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E8B34E92AB91B6E0018F305 /* ItemFilter.swift */; };
|
4E8B34EB2AB91B6E0018F305 /* ItemFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E8B34E92AB91B6E0018F305 /* ItemFilter.swift */; };
|
||||||
4EF7A3E22C031FEB00CC58A2 /* LetterPickerOverflow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EF7A3E12C031FEB00CC58A2 /* LetterPickerOverflow.swift */; };
|
|
||||||
531690E7267ABD79005D8AB9 /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 531690E6267ABD79005D8AB9 /* HomeView.swift */; };
|
531690E7267ABD79005D8AB9 /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 531690E6267ABD79005D8AB9 /* HomeView.swift */; };
|
||||||
531AC8BF26750DE20091C7EB /* ImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 531AC8BE26750DE20091C7EB /* ImageView.swift */; };
|
531AC8BF26750DE20091C7EB /* ImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 531AC8BE26750DE20091C7EB /* ImageView.swift */; };
|
||||||
5321753B2671BCFC005491E6 /* SettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5321753A2671BCFC005491E6 /* SettingsViewModel.swift */; };
|
5321753B2671BCFC005491E6 /* SettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5321753A2671BCFC005491E6 /* SettingsViewModel.swift */; };
|
||||||
|
@ -378,7 +377,7 @@
|
||||||
E145EB422BE0A6EE003BF6F3 /* ServerSelectionMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = E145EB412BE0A6EE003BF6F3 /* ServerSelectionMenu.swift */; };
|
E145EB422BE0A6EE003BF6F3 /* ServerSelectionMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = E145EB412BE0A6EE003BF6F3 /* ServerSelectionMenu.swift */; };
|
||||||
E145EB452BE0AD4E003BF6F3 /* Set.swift in Sources */ = {isa = PBXBuildFile; fileRef = E145EB442BE0AD4E003BF6F3 /* Set.swift */; };
|
E145EB452BE0AD4E003BF6F3 /* Set.swift in Sources */ = {isa = PBXBuildFile; fileRef = E145EB442BE0AD4E003BF6F3 /* Set.swift */; };
|
||||||
E145EB462BE0AD4E003BF6F3 /* Set.swift in Sources */ = {isa = PBXBuildFile; fileRef = E145EB442BE0AD4E003BF6F3 /* Set.swift */; };
|
E145EB462BE0AD4E003BF6F3 /* Set.swift in Sources */ = {isa = PBXBuildFile; fileRef = E145EB442BE0AD4E003BF6F3 /* Set.swift */; };
|
||||||
E145EB482BE0C136003BF6F3 /* ScrollIfLargerThanModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = E145EB472BE0C136003BF6F3 /* ScrollIfLargerThanModifier.swift */; };
|
E145EB482BE0C136003BF6F3 /* ScrollIfLargerThanContainerModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = E145EB472BE0C136003BF6F3 /* ScrollIfLargerThanContainerModifier.swift */; };
|
||||||
E145EB4B2BE16849003BF6F3 /* KeychainSwift in Frameworks */ = {isa = PBXBuildFile; productRef = E145EB4A2BE16849003BF6F3 /* KeychainSwift */; };
|
E145EB4B2BE16849003BF6F3 /* KeychainSwift in Frameworks */ = {isa = PBXBuildFile; productRef = E145EB4A2BE16849003BF6F3 /* KeychainSwift */; };
|
||||||
E145EB4D2BE1688E003BF6F3 /* SwiftinStore+UserState.swift in Sources */ = {isa = PBXBuildFile; fileRef = E145EB4C2BE1688E003BF6F3 /* SwiftinStore+UserState.swift */; };
|
E145EB4D2BE1688E003BF6F3 /* SwiftinStore+UserState.swift in Sources */ = {isa = PBXBuildFile; fileRef = E145EB4C2BE1688E003BF6F3 /* SwiftinStore+UserState.swift */; };
|
||||||
E145EB4F2BE168AC003BF6F3 /* SwiftfinStore+ServerState.swift in Sources */ = {isa = PBXBuildFile; fileRef = E145EB4E2BE168AC003BF6F3 /* SwiftfinStore+ServerState.swift */; };
|
E145EB4F2BE168AC003BF6F3 /* SwiftfinStore+ServerState.swift in Sources */ = {isa = PBXBuildFile; fileRef = E145EB4E2BE168AC003BF6F3 /* SwiftfinStore+ServerState.swift */; };
|
||||||
|
@ -545,7 +544,7 @@
|
||||||
E174121029AE9D94003EF3B5 /* NavigationCoordinatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E174120E29AE9D94003EF3B5 /* NavigationCoordinatable.swift */; };
|
E174121029AE9D94003EF3B5 /* NavigationCoordinatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E174120E29AE9D94003EF3B5 /* NavigationCoordinatable.swift */; };
|
||||||
E175AFF3299AC117004DCF52 /* DebugSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E175AFF2299AC117004DCF52 /* DebugSettingsView.swift */; };
|
E175AFF3299AC117004DCF52 /* DebugSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E175AFF2299AC117004DCF52 /* DebugSettingsView.swift */; };
|
||||||
E17639F82BF2E25B004DF6AB /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19D41A92BF077130082B8B2 /* Keychain.swift */; };
|
E17639F82BF2E25B004DF6AB /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19D41A92BF077130082B8B2 /* Keychain.swift */; };
|
||||||
E1763A252BF2F77B004DF6AB /* ScrollIfLargerThanModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = E145EB472BE0C136003BF6F3 /* ScrollIfLargerThanModifier.swift */; };
|
E1763A252BF2F77B004DF6AB /* ScrollIfLargerThanContainerModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = E145EB472BE0C136003BF6F3 /* ScrollIfLargerThanContainerModifier.swift */; };
|
||||||
E1763A272BF303C9004DF6AB /* ServerSelectionMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1763A262BF303C9004DF6AB /* ServerSelectionMenu.swift */; };
|
E1763A272BF303C9004DF6AB /* ServerSelectionMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1763A262BF303C9004DF6AB /* ServerSelectionMenu.swift */; };
|
||||||
E1763A292BF3046A004DF6AB /* AddUserButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1763A282BF3046A004DF6AB /* AddUserButton.swift */; };
|
E1763A292BF3046A004DF6AB /* AddUserButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1763A282BF3046A004DF6AB /* AddUserButton.swift */; };
|
||||||
E1763A2B2BF3046E004DF6AB /* UserGridButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1763A2A2BF3046E004DF6AB /* UserGridButton.swift */; };
|
E1763A2B2BF3046E004DF6AB /* UserGridButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1763A2A2BF3046E004DF6AB /* UserGridButton.swift */; };
|
||||||
|
@ -806,6 +805,8 @@
|
||||||
E1D842912933F87500D1041A /* ItemFields.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D842902933F87500D1041A /* ItemFields.swift */; };
|
E1D842912933F87500D1041A /* ItemFields.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D842902933F87500D1041A /* ItemFields.swift */; };
|
||||||
E1D8429329340B8300D1041A /* Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D8429229340B8300D1041A /* Utilities.swift */; };
|
E1D8429329340B8300D1041A /* Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D8429229340B8300D1041A /* Utilities.swift */; };
|
||||||
E1D8429529346C6400D1041A /* BasicStepper.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D8429429346C6400D1041A /* BasicStepper.swift */; };
|
E1D8429529346C6400D1041A /* BasicStepper.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D8429429346C6400D1041A /* BasicStepper.swift */; };
|
||||||
|
E1D90D762C051D44000EA787 /* BackPort+ScrollIndicatorVisibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D90D752C051D44000EA787 /* BackPort+ScrollIndicatorVisibility.swift */; };
|
||||||
|
E1D90D772C051D44000EA787 /* BackPort+ScrollIndicatorVisibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D90D752C051D44000EA787 /* BackPort+ScrollIndicatorVisibility.swift */; };
|
||||||
E1D9F475296E86D400129AF3 /* NativeVideoPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D9F474296E86D400129AF3 /* NativeVideoPlayer.swift */; };
|
E1D9F475296E86D400129AF3 /* NativeVideoPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D9F474296E86D400129AF3 /* NativeVideoPlayer.swift */; };
|
||||||
E1DA654C28E69B0500592A73 /* SpecialFeatureType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1DA654B28E69B0500592A73 /* SpecialFeatureType.swift */; };
|
E1DA654C28E69B0500592A73 /* SpecialFeatureType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1DA654B28E69B0500592A73 /* SpecialFeatureType.swift */; };
|
||||||
E1DA656F28E78C9900592A73 /* EpisodeSelector.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1DA656E28E78C9900592A73 /* EpisodeSelector.swift */; };
|
E1DA656F28E78C9900592A73 /* EpisodeSelector.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1DA656E28E78C9900592A73 /* EpisodeSelector.swift */; };
|
||||||
|
@ -927,7 +928,6 @@
|
||||||
4E16FD562C01A32700110147 /* LetterPickerOrientation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LetterPickerOrientation.swift; sourceTree = "<group>"; };
|
4E16FD562C01A32700110147 /* LetterPickerOrientation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LetterPickerOrientation.swift; sourceTree = "<group>"; };
|
||||||
4E5E48E42AB59806003F1B48 /* CustomizeViewsSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomizeViewsSettings.swift; sourceTree = "<group>"; };
|
4E5E48E42AB59806003F1B48 /* CustomizeViewsSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomizeViewsSettings.swift; sourceTree = "<group>"; };
|
||||||
4E8B34E92AB91B6E0018F305 /* ItemFilter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemFilter.swift; sourceTree = "<group>"; };
|
4E8B34E92AB91B6E0018F305 /* ItemFilter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemFilter.swift; sourceTree = "<group>"; };
|
||||||
4EF7A3E12C031FEB00CC58A2 /* LetterPickerOverflow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LetterPickerOverflow.swift; sourceTree = "<group>"; };
|
|
||||||
531690E6267ABD79005D8AB9 /* HomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeView.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>"; };
|
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>"; };
|
5321753A2671BCFC005491E6 /* SettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewModel.swift; sourceTree = "<group>"; };
|
||||||
|
@ -1198,7 +1198,7 @@
|
||||||
E145EB242BE055AD003BF6F3 /* ServerResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerResponse.swift; sourceTree = "<group>"; };
|
E145EB242BE055AD003BF6F3 /* ServerResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerResponse.swift; sourceTree = "<group>"; };
|
||||||
E145EB412BE0A6EE003BF6F3 /* ServerSelectionMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionMenu.swift; sourceTree = "<group>"; };
|
E145EB412BE0A6EE003BF6F3 /* ServerSelectionMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionMenu.swift; sourceTree = "<group>"; };
|
||||||
E145EB442BE0AD4E003BF6F3 /* Set.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Set.swift; sourceTree = "<group>"; };
|
E145EB442BE0AD4E003BF6F3 /* Set.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Set.swift; sourceTree = "<group>"; };
|
||||||
E145EB472BE0C136003BF6F3 /* ScrollIfLargerThanModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollIfLargerThanModifier.swift; sourceTree = "<group>"; };
|
E145EB472BE0C136003BF6F3 /* ScrollIfLargerThanContainerModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollIfLargerThanContainerModifier.swift; sourceTree = "<group>"; };
|
||||||
E145EB4C2BE1688E003BF6F3 /* SwiftinStore+UserState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SwiftinStore+UserState.swift"; sourceTree = "<group>"; };
|
E145EB4C2BE1688E003BF6F3 /* SwiftinStore+UserState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SwiftinStore+UserState.swift"; sourceTree = "<group>"; };
|
||||||
E145EB4E2BE168AC003BF6F3 /* SwiftfinStore+ServerState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SwiftfinStore+ServerState.swift"; sourceTree = "<group>"; };
|
E145EB4E2BE168AC003BF6F3 /* SwiftfinStore+ServerState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SwiftfinStore+ServerState.swift"; sourceTree = "<group>"; };
|
||||||
E146A9D72BE6E9830034DA1E /* StoredValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoredValue.swift; sourceTree = "<group>"; };
|
E146A9D72BE6E9830034DA1E /* StoredValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoredValue.swift; sourceTree = "<group>"; };
|
||||||
|
@ -1458,6 +1458,7 @@
|
||||||
E1D842902933F87500D1041A /* ItemFields.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemFields.swift; sourceTree = "<group>"; };
|
E1D842902933F87500D1041A /* ItemFields.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemFields.swift; sourceTree = "<group>"; };
|
||||||
E1D8429229340B8300D1041A /* Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utilities.swift; sourceTree = "<group>"; };
|
E1D8429229340B8300D1041A /* Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utilities.swift; sourceTree = "<group>"; };
|
||||||
E1D8429429346C6400D1041A /* BasicStepper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BasicStepper.swift; sourceTree = "<group>"; };
|
E1D8429429346C6400D1041A /* BasicStepper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BasicStepper.swift; sourceTree = "<group>"; };
|
||||||
|
E1D90D752C051D44000EA787 /* BackPort+ScrollIndicatorVisibility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BackPort+ScrollIndicatorVisibility.swift"; sourceTree = "<group>"; };
|
||||||
E1D9F474296E86D400129AF3 /* NativeVideoPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeVideoPlayer.swift; sourceTree = "<group>"; };
|
E1D9F474296E86D400129AF3 /* NativeVideoPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeVideoPlayer.swift; sourceTree = "<group>"; };
|
||||||
E1DA654B28E69B0500592A73 /* SpecialFeatureType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpecialFeatureType.swift; sourceTree = "<group>"; };
|
E1DA654B28E69B0500592A73 /* SpecialFeatureType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpecialFeatureType.swift; sourceTree = "<group>"; };
|
||||||
E1DA656E28E78C9900592A73 /* EpisodeSelector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EpisodeSelector.swift; sourceTree = "<group>"; };
|
E1DA656E28E78C9900592A73 /* EpisodeSelector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EpisodeSelector.swift; sourceTree = "<group>"; };
|
||||||
|
@ -1656,7 +1657,6 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
4E16FD502C0183DB00110147 /* LetterPickerButton.swift */,
|
4E16FD502C0183DB00110147 /* LetterPickerButton.swift */,
|
||||||
4EF7A3E12C031FEB00CC58A2 /* LetterPickerOverflow.swift */,
|
|
||||||
);
|
);
|
||||||
path = Components;
|
path = Components;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -2499,7 +2499,7 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
E170D101294CE4C10017224C /* Modifiers */,
|
E170D101294CE4C10017224C /* Modifiers */,
|
||||||
E15D4F062B1B12C300442DB8 /* Backport.swift */,
|
E1D90D742C051D3B000EA787 /* Backport */,
|
||||||
E1E1E24C28DF8A2E000DF5FD /* PreferenceKeys.swift */,
|
E1E1E24C28DF8A2E000DF5FD /* PreferenceKeys.swift */,
|
||||||
6220D0AC26D5EABB00B8E046 /* ViewExtensions.swift */,
|
6220D0AC26D5EABB00B8E046 /* ViewExtensions.swift */,
|
||||||
);
|
);
|
||||||
|
@ -2839,7 +2839,7 @@
|
||||||
E129428428F080B500796AC6 /* OnReceiveNotificationModifier.swift */,
|
E129428428F080B500796AC6 /* OnReceiveNotificationModifier.swift */,
|
||||||
E43918652AD5C8310045A18C /* OnScenePhaseChangedModifier.swift */,
|
E43918652AD5C8310045A18C /* OnScenePhaseChangedModifier.swift */,
|
||||||
E13316FD2ADE42B6009BF865 /* OnSizeChangedModifier.swift */,
|
E13316FD2ADE42B6009BF865 /* OnSizeChangedModifier.swift */,
|
||||||
E145EB472BE0C136003BF6F3 /* ScrollIfLargerThanModifier.swift */,
|
E145EB472BE0C136003BF6F3 /* ScrollIfLargerThanContainerModifier.swift */,
|
||||||
E11895A8289383BC0042947B /* ScrollViewOffsetModifier.swift */,
|
E11895A8289383BC0042947B /* ScrollViewOffsetModifier.swift */,
|
||||||
E1E2F8442B757E3400B75998 /* SinceLastDisappearModifier.swift */,
|
E1E2F8442B757E3400B75998 /* SinceLastDisappearModifier.swift */,
|
||||||
);
|
);
|
||||||
|
@ -3367,6 +3367,15 @@
|
||||||
path = Slider;
|
path = Slider;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
E1D90D742C051D3B000EA787 /* Backport */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
E15D4F062B1B12C300442DB8 /* Backport.swift */,
|
||||||
|
E1D90D752C051D44000EA787 /* BackPort+ScrollIndicatorVisibility.swift */,
|
||||||
|
);
|
||||||
|
path = Backport;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
E1DABAD62A26E28E008AC34A /* Resources */ = {
|
E1DABAD62A26E28E008AC34A /* Resources */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
@ -4102,7 +4111,7 @@
|
||||||
E1575E5D293E77B5001665B1 /* ItemViewType.swift in Sources */,
|
E1575E5D293E77B5001665B1 /* ItemViewType.swift in Sources */,
|
||||||
E12CC1AF28D0FAEA00678D5D /* NextUpLibraryViewModel.swift in Sources */,
|
E12CC1AF28D0FAEA00678D5D /* NextUpLibraryViewModel.swift in Sources */,
|
||||||
E1575E7A293E77B5001665B1 /* TimeStampType.swift in Sources */,
|
E1575E7A293E77B5001665B1 /* TimeStampType.swift in Sources */,
|
||||||
E1763A252BF2F77B004DF6AB /* ScrollIfLargerThanModifier.swift in Sources */,
|
E1763A252BF2F77B004DF6AB /* ScrollIfLargerThanContainerModifier.swift in Sources */,
|
||||||
E11E374E293E7F08009EF240 /* MediaSourceInfo.swift in Sources */,
|
E11E374E293E7F08009EF240 /* MediaSourceInfo.swift in Sources */,
|
||||||
E1E1643A28BAC2EF00323B0A /* SearchView.swift in Sources */,
|
E1E1643A28BAC2EF00323B0A /* SearchView.swift in Sources */,
|
||||||
E1763A642BF3C9AA004DF6AB /* ListRowButton.swift in Sources */,
|
E1763A642BF3C9AA004DF6AB /* ListRowButton.swift in Sources */,
|
||||||
|
@ -4152,6 +4161,7 @@
|
||||||
E10B1ECB2BD9AF8200A92EAF /* SwiftfinStore+V1.swift in Sources */,
|
E10B1ECB2BD9AF8200A92EAF /* SwiftfinStore+V1.swift in Sources */,
|
||||||
E154966B296CA2EF00C4EF88 /* DownloadManager.swift in Sources */,
|
E154966B296CA2EF00C4EF88 /* DownloadManager.swift in Sources */,
|
||||||
535870632669D21600D05A09 /* SwiftfinApp.swift in Sources */,
|
535870632669D21600D05A09 /* SwiftfinApp.swift in Sources */,
|
||||||
|
E1D90D772C051D44000EA787 /* BackPort+ScrollIndicatorVisibility.swift in Sources */,
|
||||||
E10231582BCF8AF8009D71FC /* WideChannelGridItem.swift in Sources */,
|
E10231582BCF8AF8009D71FC /* WideChannelGridItem.swift in Sources */,
|
||||||
E15D4F082B1B12C300442DB8 /* Backport.swift in Sources */,
|
E15D4F082B1B12C300442DB8 /* Backport.swift in Sources */,
|
||||||
E1D4BF8F271A079A00A11E64 /* BasicAppSettingsView.swift in Sources */,
|
E1D4BF8F271A079A00A11E64 /* BasicAppSettingsView.swift in Sources */,
|
||||||
|
@ -4253,7 +4263,6 @@
|
||||||
E18CE0AF28A222240092E7F1 /* PublicUserRow.swift in Sources */,
|
E18CE0AF28A222240092E7F1 /* PublicUserRow.swift in Sources */,
|
||||||
E129429828F4785200796AC6 /* CaseIterablePicker.swift in Sources */,
|
E129429828F4785200796AC6 /* CaseIterablePicker.swift in Sources */,
|
||||||
E18E01E5288747230022598C /* CinematicScrollView.swift in Sources */,
|
E18E01E5288747230022598C /* CinematicScrollView.swift in Sources */,
|
||||||
4EF7A3E22C031FEB00CC58A2 /* LetterPickerOverflow.swift in Sources */,
|
|
||||||
E154965E296CA2EF00C4EF88 /* DownloadTask.swift in Sources */,
|
E154965E296CA2EF00C4EF88 /* DownloadTask.swift in Sources */,
|
||||||
535BAE9F2649E569005FA86D /* ItemView.swift in Sources */,
|
535BAE9F2649E569005FA86D /* ItemView.swift in Sources */,
|
||||||
E1E2F8422B757E0900B75998 /* OnFirstAppearModifier.swift in Sources */,
|
E1E2F8422B757E0900B75998 /* OnFirstAppearModifier.swift in Sources */,
|
||||||
|
@ -4343,6 +4352,7 @@
|
||||||
E1B5784128F8AFCB00D42911 /* WrappedView.swift in Sources */,
|
E1B5784128F8AFCB00D42911 /* WrappedView.swift in Sources */,
|
||||||
E1921B7428E61914003A5238 /* SpecialFeatureHStack.swift in Sources */,
|
E1921B7428E61914003A5238 /* SpecialFeatureHStack.swift in Sources */,
|
||||||
E118959D289312020042947B /* BaseItemPerson+Poster.swift in Sources */,
|
E118959D289312020042947B /* BaseItemPerson+Poster.swift in Sources */,
|
||||||
|
E1D90D762C051D44000EA787 /* BackPort+ScrollIndicatorVisibility.swift in Sources */,
|
||||||
6264E88C273850380081A12A /* Strings.swift in Sources */,
|
6264E88C273850380081A12A /* Strings.swift in Sources */,
|
||||||
E145EB252BE055AD003BF6F3 /* ServerResponse.swift in Sources */,
|
E145EB252BE055AD003BF6F3 /* ServerResponse.swift in Sources */,
|
||||||
E1BDF31729525F0400CC0294 /* AdvancedActionButton.swift in Sources */,
|
E1BDF31729525F0400CC0294 /* AdvancedActionButton.swift in Sources */,
|
||||||
|
@ -4392,7 +4402,7 @@
|
||||||
E170D107294D23BA0017224C /* MediaSourceInfoCoordinator.swift in Sources */,
|
E170D107294D23BA0017224C /* MediaSourceInfoCoordinator.swift in Sources */,
|
||||||
E102313B2BCF8A3C009D71FC /* ProgramProgressOverlay.swift in Sources */,
|
E102313B2BCF8A3C009D71FC /* ProgramProgressOverlay.swift in Sources */,
|
||||||
E1937A61288F32DB00CB80AA /* Poster.swift in Sources */,
|
E1937A61288F32DB00CB80AA /* Poster.swift in Sources */,
|
||||||
E145EB482BE0C136003BF6F3 /* ScrollIfLargerThanModifier.swift in Sources */,
|
E145EB482BE0C136003BF6F3 /* ScrollIfLargerThanContainerModifier.swift in Sources */,
|
||||||
E1CAF65F2BA345830087D991 /* MediaViewModel.swift in Sources */,
|
E1CAF65F2BA345830087D991 /* MediaViewModel.swift in Sources */,
|
||||||
E1EA9F6A28F8A79E00BEC442 /* VideoPlayerManager.swift in Sources */,
|
E1EA9F6A28F8A79E00BEC442 /* VideoPlayerManager.swift in Sources */,
|
||||||
E133328D2953AE4B00EE76AB /* CircularProgressView.swift in Sources */,
|
E133328D2953AE4B00EE76AB /* CircularProgressView.swift in Sources */,
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
"location" : "https://github.com/LePips/CollectionVGrid",
|
"location" : "https://github.com/LePips/CollectionVGrid",
|
||||||
"state" : {
|
"state" : {
|
||||||
"branch" : "main",
|
"branch" : "main",
|
||||||
"revision" : "b50b5241df5fc1d71e5a09f6a87731c67c2a79e5"
|
"revision" : "91ba930a502761924204ae74a59ded05f3b7ef89"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,36 +19,31 @@ extension LetterPickerBar {
|
||||||
@Environment(\.isSelected)
|
@Environment(\.isSelected)
|
||||||
private var isSelected
|
private var isSelected
|
||||||
|
|
||||||
private let filterLetter: ItemLetter
|
private let letter: ItemLetter
|
||||||
private let viewModel: FilterViewModel
|
private let viewModel: FilterViewModel
|
||||||
|
|
||||||
init(filterLetter: ItemLetter, viewModel: FilterViewModel) {
|
init(letter: ItemLetter, viewModel: FilterViewModel) {
|
||||||
self.filterLetter = filterLetter
|
self.letter = letter
|
||||||
self.viewModel = viewModel
|
self.viewModel = viewModel
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Button {
|
Button {
|
||||||
if !viewModel.currentFilters.letter.contains(filterLetter) {
|
if !viewModel.currentFilters.letter.contains(letter) {
|
||||||
viewModel.currentFilters.letter = [ItemLetter(stringLiteral: filterLetter.value)]
|
viewModel.currentFilters.letter = [ItemLetter(stringLiteral: letter.value)]
|
||||||
} else {
|
} else {
|
||||||
viewModel.currentFilters.letter = []
|
viewModel.currentFilters.letter = []
|
||||||
}
|
}
|
||||||
} label: {
|
} label: {
|
||||||
Text(
|
ZStack {
|
||||||
filterLetter.value
|
|
||||||
)
|
|
||||||
.environment(\.isSelected, viewModel.currentFilters.letter.contains(filterLetter))
|
|
||||||
.font(.headline)
|
|
||||||
.frame(width: 15, height: 15)
|
|
||||||
.foregroundStyle(isSelected ? accentColor.overlayColor : accentColor)
|
|
||||||
.padding(.vertical, 2)
|
|
||||||
.fixedSize(horizontal: false, vertical: true)
|
|
||||||
.background {
|
|
||||||
RoundedRectangle(cornerRadius: 5)
|
RoundedRectangle(cornerRadius: 5)
|
||||||
.frame(width: 20, height: 20)
|
.foregroundStyle(isSelected ? accentColor : Color.clear)
|
||||||
.foregroundStyle(isSelected ? accentColor.opacity(0.5) : Color.clear)
|
|
||||||
|
Text(letter.value)
|
||||||
|
.font(.headline)
|
||||||
|
.foregroundStyle(isSelected ? accentColor.overlayColor : accentColor)
|
||||||
}
|
}
|
||||||
|
.frame(width: 20, height: 20)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
//
|
|
||||||
// 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 Foundation
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct LetterPickerOverflow: ViewModifier {
|
|
||||||
@State
|
|
||||||
private var contentOverflow: Bool = false
|
|
||||||
|
|
||||||
func body(content: Content) -> some View {
|
|
||||||
GeometryReader { geometry in
|
|
||||||
content
|
|
||||||
.background(
|
|
||||||
GeometryReader { contentGeometry in
|
|
||||||
Color.clear.onAppear {
|
|
||||||
contentOverflow = contentGeometry.size.height > geometry.size.height
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.wrappedInScrollView(when: contentOverflow)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension View {
|
|
||||||
@ViewBuilder
|
|
||||||
func wrappedInScrollView(when condition: Bool) -> some View {
|
|
||||||
if condition {
|
|
||||||
ScrollView(showsIndicators: false) {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
.frame(maxWidth: .infinity, alignment: .center)
|
|
||||||
} else {
|
|
||||||
self
|
|
||||||
.frame(width: 30, alignment: .center)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension View {
|
|
||||||
func scrollOnOverflow() -> some View {
|
|
||||||
modifier(LetterPickerOverflow())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -10,28 +10,26 @@ import Defaults
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct LetterPickerBar: View {
|
struct LetterPickerBar: View {
|
||||||
@ObservedObject
|
|
||||||
private var viewModel: FilterViewModel
|
|
||||||
|
|
||||||
init(viewModel: FilterViewModel) {
|
@ObservedObject
|
||||||
self.viewModel = viewModel
|
var viewModel: FilterViewModel
|
||||||
}
|
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
ForEach(ItemLetter.allCases, id: \.hashValue) { filterLetter in
|
ForEach(ItemLetter.allCases, id: \.hashValue) { filterLetter in
|
||||||
LetterPickerButton(
|
LetterPickerButton(
|
||||||
filterLetter: filterLetter,
|
letter: filterLetter,
|
||||||
viewModel: viewModel
|
viewModel: viewModel
|
||||||
)
|
)
|
||||||
.environment(\.isSelected, viewModel.currentFilters.letter.contains(filterLetter))
|
.environment(\.isSelected, viewModel.currentFilters.letter.contains(filterLetter))
|
||||||
.frame(maxWidth: .infinity)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
.scrollOnOverflow()
|
.scrollIfLargerThanContainer()
|
||||||
.frame(width: 30, alignment: .center)
|
.frame(width: 30, alignment: .center)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -180,6 +180,7 @@ struct PagingLibraryView<Element: Poster>: View {
|
||||||
// Note: if parent is a folders then other items will have labels,
|
// Note: if parent is a folders then other items will have labels,
|
||||||
// so an empty content view is necessary
|
// so an empty content view is necessary
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
private func landscapeGridItemView(item: Element) -> some View {
|
private func landscapeGridItemView(item: Element) -> some View {
|
||||||
PosterButton(item: item, type: .landscape)
|
PosterButton(item: item, type: .landscape)
|
||||||
.content {
|
.content {
|
||||||
|
@ -199,6 +200,7 @@ struct PagingLibraryView<Element: Poster>: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
private func portraitGridItemView(item: Element) -> some View {
|
private func portraitGridItemView(item: Element) -> some View {
|
||||||
PosterButton(item: item, type: .portrait)
|
PosterButton(item: item, type: .portrait)
|
||||||
.content {
|
.content {
|
||||||
|
@ -218,6 +220,7 @@ struct PagingLibraryView<Element: Poster>: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
private func listItemView(item: Element, posterType: PosterDisplayType) -> some View {
|
private func listItemView(item: Element, posterType: PosterDisplayType) -> some View {
|
||||||
LibraryRow(item: item, posterType: posterType)
|
LibraryRow(item: item, posterType: posterType)
|
||||||
.onSelect {
|
.onSelect {
|
||||||
|
@ -233,7 +236,8 @@ struct PagingLibraryView<Element: Poster>: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var contentView: some View {
|
@ViewBuilder
|
||||||
|
private var gridView: some View {
|
||||||
CollectionVGrid(
|
CollectionVGrid(
|
||||||
$viewModel.elements,
|
$viewModel.elements,
|
||||||
layout: $layout
|
layout: $layout
|
||||||
|
@ -256,33 +260,40 @@ struct PagingLibraryView<Element: Poster>: View {
|
||||||
viewModel.send(.getNextPage)
|
viewModel.send(.getNextPage)
|
||||||
}
|
}
|
||||||
.proxy(collectionVGridProxy)
|
.proxy(collectionVGridProxy)
|
||||||
|
.scrollIndicatorsVisible(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
private func contentLetterBarView(content: some View) -> some View {
|
private var innerContent: some View {
|
||||||
|
switch viewModel.state {
|
||||||
|
case .content:
|
||||||
|
if viewModel.elements.isEmpty {
|
||||||
|
L10n.noResults.text
|
||||||
|
} else {
|
||||||
|
gridView
|
||||||
|
}
|
||||||
|
case .initial, .refreshing:
|
||||||
|
DelayedProgressView()
|
||||||
|
default:
|
||||||
|
AssertionFailureView("Expected view for unexpected state")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private var contentView: some View {
|
||||||
if letterPickerEnabled, let filterViewModel = viewModel.filterViewModel {
|
if letterPickerEnabled, let filterViewModel = viewModel.filterViewModel {
|
||||||
switch letterPickerOrientation {
|
ZStack(alignment: letterPickerOrientation.alignment) {
|
||||||
case .trailing:
|
innerContent
|
||||||
HStack(spacing: 0) {
|
.padding(letterPickerOrientation.edge, 35)
|
||||||
content
|
.frame(maxWidth: .infinity)
|
||||||
.frame(maxWidth: .infinity)
|
|
||||||
|
|
||||||
LetterPickerBar(viewModel: filterViewModel)
|
LetterPickerBar(viewModel: filterViewModel)
|
||||||
.padding(.top, safeArea.top)
|
.padding(.top, safeArea.top)
|
||||||
.padding(.bottom, safeArea.bottom)
|
.padding(.bottom, safeArea.bottom)
|
||||||
}
|
.padding(letterPickerOrientation.edge, 10)
|
||||||
case .leading:
|
|
||||||
HStack(spacing: 0) {
|
|
||||||
LetterPickerBar(viewModel: filterViewModel)
|
|
||||||
.padding(.top, safeArea.top)
|
|
||||||
.padding(.bottom, safeArea.bottom)
|
|
||||||
|
|
||||||
content
|
|
||||||
.frame(maxWidth: .infinity)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
content
|
innerContent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,17 +303,13 @@ struct PagingLibraryView<Element: Poster>: View {
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
|
Color.clear
|
||||||
|
|
||||||
switch viewModel.state {
|
switch viewModel.state {
|
||||||
case .content:
|
case .content, .initial, .refreshing:
|
||||||
if viewModel.elements.isEmpty {
|
contentView
|
||||||
contentLetterBarView(content: L10n.noResults.text)
|
|
||||||
} else {
|
|
||||||
contentLetterBarView(content: contentView)
|
|
||||||
}
|
|
||||||
case let .error(error):
|
case let .error(error):
|
||||||
errorView(with: error)
|
errorView(with: error)
|
||||||
case .initial, .refreshing:
|
|
||||||
contentLetterBarView(content: DelayedProgressView())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.animation(.linear(duration: 0.1), value: viewModel.state)
|
.animation(.linear(duration: 0.1), value: viewModel.state)
|
||||||
|
|
|
@ -20,8 +20,6 @@ import SwiftUI
|
||||||
// TODO: user ordering
|
// TODO: user ordering
|
||||||
// - name
|
// - name
|
||||||
// - last signed in date
|
// - last signed in date
|
||||||
// TODO: for random splash screen, instead have a random sorted array
|
|
||||||
// for failure cases
|
|
||||||
|
|
||||||
struct SelectUserView: View {
|
struct SelectUserView: View {
|
||||||
|
|
||||||
|
@ -45,8 +43,6 @@ struct SelectUserView: View {
|
||||||
@EnvironmentObject
|
@EnvironmentObject
|
||||||
private var router: SelectUserCoordinator.Router
|
private var router: SelectUserCoordinator.Router
|
||||||
|
|
||||||
@State
|
|
||||||
private var contentSafeAreaInsets: EdgeInsets = .zero
|
|
||||||
@State
|
@State
|
||||||
private var contentSize: CGSize = .zero
|
private var contentSize: CGSize = .zero
|
||||||
@State
|
@State
|
||||||
|
@ -70,7 +66,7 @@ struct SelectUserView: View {
|
||||||
@State
|
@State
|
||||||
private var selectedUsers: Set<UserState> = []
|
private var selectedUsers: Set<UserState> = []
|
||||||
@State
|
@State
|
||||||
private var splashScreenImageSource: ImageSource? = nil
|
private var splashScreenImageSources: [ImageSource] = []
|
||||||
|
|
||||||
@StateObject
|
@StateObject
|
||||||
private var viewModel = SelectUserViewModel()
|
private var viewModel = SelectUserViewModel()
|
||||||
|
@ -115,25 +111,27 @@ struct SelectUserView: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
// For all server selection, .all is random
|
// For all server selection, .all is random
|
||||||
private func makeSplashScreenImageSource(
|
private func makeSplashScreenImageSources(
|
||||||
serverSelection: SelectUserServerSelection,
|
serverSelection: SelectUserServerSelection,
|
||||||
allServersSelection: SelectUserServerSelection
|
allServersSelection: SelectUserServerSelection
|
||||||
) -> ImageSource? {
|
) -> [ImageSource] {
|
||||||
switch (serverSelection, allServersSelection) {
|
switch (serverSelection, allServersSelection) {
|
||||||
case (.all, .all):
|
case (.all, .all):
|
||||||
return viewModel
|
return viewModel
|
||||||
.servers
|
.servers
|
||||||
.keys
|
.keys
|
||||||
.randomElement()?
|
.shuffled()
|
||||||
.splashScreenImageSource()
|
.map { $0.splashScreenImageSource() }
|
||||||
|
|
||||||
// need to evaluate server with id selection first
|
// need to evaluate server with id selection first
|
||||||
case let (.server(id), _), let (.all, .server(id)):
|
case let (.server(id), _), let (.all, .server(id)):
|
||||||
return viewModel
|
return [
|
||||||
.servers
|
viewModel
|
||||||
.keys
|
.servers
|
||||||
.first { $0.id == id }?
|
.keys
|
||||||
.splashScreenImageSource()
|
.first { $0.id == id }?
|
||||||
|
.splashScreenImageSource() ?? .init(),
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,7 +250,7 @@ struct SelectUserView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.edgePadding()
|
.edgePadding()
|
||||||
.scroll(ifLargerThan: contentSize.height - 100)
|
.scrollIfLargerThanContainer(padding: 100)
|
||||||
.onChange(of: gridItemSize) { newValue in
|
.onChange(of: gridItemSize) { newValue in
|
||||||
let columns = Int(contentSize.width / (newValue.width + EdgeInsets.edgePadding))
|
let columns = Int(contentSize.width / (newValue.width + EdgeInsets.edgePadding))
|
||||||
|
|
||||||
|
@ -274,7 +272,7 @@ struct SelectUserView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.edgePadding()
|
.edgePadding()
|
||||||
.scroll(ifLargerThan: contentSize.height - 100)
|
.scrollIfLargerThanContainer(padding: 100)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
|
@ -386,9 +384,8 @@ struct SelectUserView: View {
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
ZStack {
|
ZStack {
|
||||||
Color.clear
|
Color.clear
|
||||||
.onSizeChanged { size, safeAreaInsets in
|
.onSizeChanged { size, _ in
|
||||||
contentSize = size
|
contentSize = size
|
||||||
contentSafeAreaInsets = safeAreaInsets
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch userListDisplayType {
|
switch userListDisplayType {
|
||||||
|
@ -433,16 +430,16 @@ struct SelectUserView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.background {
|
.background {
|
||||||
if selectUserUseSplashscreen, let splashScreenImageSource {
|
if selectUserUseSplashscreen, splashScreenImageSources.isNotEmpty {
|
||||||
ZStack {
|
ZStack {
|
||||||
Color.clear
|
Color.clear
|
||||||
|
|
||||||
ImageView(splashScreenImageSource)
|
ImageView(splashScreenImageSources)
|
||||||
.pipeline(.Swiftfin.branding)
|
.pipeline(.Swiftfin.branding)
|
||||||
.aspectRatio(contentMode: .fill)
|
.aspectRatio(contentMode: .fill)
|
||||||
.id(splashScreenImageSource)
|
.id(splashScreenImageSources)
|
||||||
.transition(.opacity)
|
.transition(.opacity)
|
||||||
.animation(.linear, value: splashScreenImageSource)
|
.animation(.linear, value: splashScreenImageSources)
|
||||||
|
|
||||||
Color.black
|
Color.black
|
||||||
.opacity(0.9)
|
.opacity(0.9)
|
||||||
|
@ -515,7 +512,7 @@ struct SelectUserView: View {
|
||||||
.onAppear {
|
.onAppear {
|
||||||
viewModel.send(.getServers)
|
viewModel.send(.getServers)
|
||||||
|
|
||||||
splashScreenImageSource = makeSplashScreenImageSource(
|
splashScreenImageSources = makeSplashScreenImageSources(
|
||||||
serverSelection: serverSelection,
|
serverSelection: serverSelection,
|
||||||
allServersSelection: selectUserAllServersSplashscreen
|
allServersSelection: selectUserAllServersSplashscreen
|
||||||
)
|
)
|
||||||
|
@ -537,7 +534,7 @@ struct SelectUserView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onChange(of: selectUserAllServersSplashscreen) { newValue in
|
.onChange(of: selectUserAllServersSplashscreen) { newValue in
|
||||||
splashScreenImageSource = makeSplashScreenImageSource(
|
splashScreenImageSources = makeSplashScreenImageSources(
|
||||||
serverSelection: serverSelection,
|
serverSelection: serverSelection,
|
||||||
allServersSelection: newValue
|
allServersSelection: newValue
|
||||||
)
|
)
|
||||||
|
@ -545,7 +542,7 @@ struct SelectUserView: View {
|
||||||
.onChange(of: serverSelection) { newValue in
|
.onChange(of: serverSelection) { newValue in
|
||||||
gridItems = makeGridItems(for: newValue)
|
gridItems = makeGridItems(for: newValue)
|
||||||
|
|
||||||
splashScreenImageSource = makeSplashScreenImageSource(
|
splashScreenImageSources = makeSplashScreenImageSources(
|
||||||
serverSelection: newValue,
|
serverSelection: newValue,
|
||||||
allServersSelection: selectUserAllServersSplashscreen
|
allServersSelection: selectUserAllServersSplashscreen
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue