Fix iOS 15 Poster Buttons (#1172)

This commit is contained in:
Ethan Pippin 2024-08-08 10:01:23 -06:00 committed by GitHub
parent e4fd98c244
commit d85ffb4156
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 120 additions and 27 deletions

View File

@ -90,11 +90,13 @@ extension String {
.replacingOccurrences(of: ".swift", with: "") .replacingOccurrences(of: ".swift", with: "")
} }
// TODO: fix if count > 62
static func random(count: Int) -> String { static func random(count: Int) -> String {
let characters = Self.alphanumeric.randomSample(count: count) let characters = Self.alphanumeric.randomSample(count: count)
return String(characters) return String(characters)
} }
// TODO: fix if upper bound > 62
static func random(count range: Range<Int>) -> String { static func random(count range: Range<Int>) -> String {
let characters = Self.alphanumeric.randomSample(count: Int.random(in: range)) let characters = Self.alphanumeric.randomSample(count: Int.random(in: range))
return String(characters) return String(characters)
@ -114,6 +116,20 @@ extension String {
return s return s
} }
// TODO: remove after iOS 15 support removed
func height(withConstrainedWidth width: CGFloat, font: UIFont) -> CGFloat {
let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude)
let boundingBox = self.boundingRect(
with: constraintRect,
options: .usesLineFragmentOrigin,
attributes: [.font: font],
context: nil
)
return ceil(boundingBox.height)
}
} }
extension CharacterSet { extension CharacterSet {

View File

@ -31,8 +31,16 @@ extension Backport where Content: View {
content content
.lineLimit(limit, reservesSpace: reservesSpace) .lineLimit(limit, reservesSpace: reservesSpace)
} else { } else {
// This may still not be enough and will probably have to
// use String.height in a frame as caller site
//
// The `.font` modifier must come after this modifier in
// order for the layout and content fonts to match
ZStack(alignment: .top) { ZStack(alignment: .top) {
Text(String(repeating: " \n", count: limit)) if reservesSpace {
Text("A" + String(repeating: "A\nA", count: limit - 1))
.hidden()
}
content content
.lineLimit(limit) .lineLimit(limit)

View File

@ -37,7 +37,5 @@ struct EnvironmentModifier<Wrapped: View, Value>: ViewModifier {
func body(content: Content) -> some View { func body(content: Content) -> some View {
wrapped(environmentValue) wrapped(environmentValue)
// wrapped(content)
} }
} }

View File

@ -42,24 +42,27 @@ final class UserSession {
extension Container { extension Container {
var currentUserSession: Factory<UserSession?> { var currentUserSession: Factory<UserSession?> {
self { self {
if let lastUserID = Defaults[.lastSignedInUserID], guard let lastUserID = Defaults[.lastSignedInUserID] else { return nil }
let user = try? SwiftfinStore.dataStack.fetchOne(
From<UserModel>().where(\.$id == lastUserID)
)
{
guard let server = user.server,
let _ = SwiftfinStore.dataStack.fetchExisting(server)
else {
fatalError("No associated server for last user")
}
return .init( guard let user = try? SwiftfinStore.dataStack.fetchOne(
server: server.state, From<UserModel>().where(\.$id == lastUserID)
user: user.state ) else {
) // had last user ID but no saved user
Defaults[.lastSignedInUserID] = nil
return nil
} }
return nil guard let server = user.server,
let _ = SwiftfinStore.dataStack.fetchExisting(server)
else {
fatalError("No associated server for last user")
}
return .init(
server: server.state,
user: user.state
)
}.cached }.cached
} }
} }

View File

@ -824,6 +824,7 @@
E1DABAFA2A270E62008AC34A /* OverviewCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1DABAF92A270E62008AC34A /* OverviewCard.swift */; }; E1DABAFA2A270E62008AC34A /* OverviewCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1DABAF92A270E62008AC34A /* OverviewCard.swift */; };
E1DABAFC2A270EE7008AC34A /* MediaSourcesCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1DABAFB2A270EE7008AC34A /* MediaSourcesCard.swift */; }; E1DABAFC2A270EE7008AC34A /* MediaSourcesCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1DABAFB2A270EE7008AC34A /* MediaSourcesCard.swift */; };
E1DABAFE2A27B982008AC34A /* RatingsCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1DABAFD2A27B982008AC34A /* RatingsCard.swift */; }; E1DABAFE2A27B982008AC34A /* RatingsCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1DABAFD2A27B982008AC34A /* RatingsCard.swift */; };
E1DC7ACA2C63337C00AEE368 /* iOS15View.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1DC7AC92C63337C00AEE368 /* iOS15View.swift */; };
E1DC9814296DC06200982F06 /* PulseLogHandler in Frameworks */ = {isa = PBXBuildFile; productRef = E1DC9813296DC06200982F06 /* PulseLogHandler */; }; E1DC9814296DC06200982F06 /* PulseLogHandler in Frameworks */ = {isa = PBXBuildFile; productRef = E1DC9813296DC06200982F06 /* PulseLogHandler */; };
E1DC981A296DD1CD00982F06 /* CinematicBackgroundView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1DC9818296DD1CD00982F06 /* CinematicBackgroundView.swift */; }; E1DC981A296DD1CD00982F06 /* CinematicBackgroundView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1DC9818296DD1CD00982F06 /* CinematicBackgroundView.swift */; };
E1DC983D296DEB9B00982F06 /* UnwatchedIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1DC983C296DEB9B00982F06 /* UnwatchedIndicator.swift */; }; E1DC983D296DEB9B00982F06 /* UnwatchedIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1DC983C296DEB9B00982F06 /* UnwatchedIndicator.swift */; };
@ -1485,6 +1486,7 @@
E1DABAF92A270E62008AC34A /* OverviewCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverviewCard.swift; sourceTree = "<group>"; }; E1DABAF92A270E62008AC34A /* OverviewCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverviewCard.swift; sourceTree = "<group>"; };
E1DABAFB2A270EE7008AC34A /* MediaSourcesCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaSourcesCard.swift; sourceTree = "<group>"; }; E1DABAFB2A270EE7008AC34A /* MediaSourcesCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaSourcesCard.swift; sourceTree = "<group>"; };
E1DABAFD2A27B982008AC34A /* RatingsCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RatingsCard.swift; sourceTree = "<group>"; }; E1DABAFD2A27B982008AC34A /* RatingsCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RatingsCard.swift; sourceTree = "<group>"; };
E1DC7AC92C63337C00AEE368 /* iOS15View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iOS15View.swift; sourceTree = "<group>"; };
E1DC9818296DD1CD00982F06 /* CinematicBackgroundView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CinematicBackgroundView.swift; sourceTree = "<group>"; }; E1DC9818296DD1CD00982F06 /* CinematicBackgroundView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CinematicBackgroundView.swift; sourceTree = "<group>"; };
E1DC983C296DEB9B00982F06 /* UnwatchedIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnwatchedIndicator.swift; sourceTree = "<group>"; }; E1DC983C296DEB9B00982F06 /* UnwatchedIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnwatchedIndicator.swift; sourceTree = "<group>"; };
E1DC9840296DEBD800982F06 /* WatchedIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchedIndicator.swift; sourceTree = "<group>"; }; E1DC9840296DEBD800982F06 /* WatchedIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchedIndicator.swift; sourceTree = "<group>"; };
@ -2100,6 +2102,7 @@
E1DE2B492B97ECB900F6715F /* ErrorView.swift */, E1DE2B492B97ECB900F6715F /* ErrorView.swift */,
E1921B7528E63306003A5238 /* GestureView.swift */, E1921B7528E63306003A5238 /* GestureView.swift */,
E178B0752BE435D70023651B /* HourMinutePicker.swift */, E178B0752BE435D70023651B /* HourMinutePicker.swift */,
E1DC7AC92C63337C00AEE368 /* iOS15View.swift */,
E1FE69A928C29CC20021BC93 /* LandscapePosterProgressBar.swift */, E1FE69A928C29CC20021BC93 /* LandscapePosterProgressBar.swift */,
4E16FD4E2C0183B500110147 /* LetterPickerBar */, 4E16FD4E2C0183B500110147 /* LetterPickerBar */,
E1A8FDEB2C0574A800D0A51C /* ListRow.swift */, E1A8FDEB2C0574A800D0A51C /* ListRow.swift */,
@ -4571,6 +4574,7 @@
E1BDF2F329524C3B00CC0294 /* ChaptersActionButton.swift in Sources */, E1BDF2F329524C3B00CC0294 /* ChaptersActionButton.swift in Sources */,
E173DA5026D048D600CC4EB7 /* ServerDetailView.swift in Sources */, E173DA5026D048D600CC4EB7 /* ServerDetailView.swift in Sources */,
E1BE1CF02BDB6C97008176A9 /* UserProfileSettingsView.swift in Sources */, E1BE1CF02BDB6C97008176A9 /* UserProfileSettingsView.swift in Sources */,
E1DC7ACA2C63337C00AEE368 /* iOS15View.swift in Sources */,
E1CFE28028FA606800B7D34C /* ChapterTrack.swift in Sources */, E1CFE28028FA606800B7D34C /* ChapterTrack.swift in Sources */,
E1401CA22938122C00E8B599 /* AppIcons.swift in Sources */, E1401CA22938122C00E8B599 /* AppIcons.swift in Sources */,
E1BDF2FB2952502300CC0294 /* SubtitleActionButton.swift in Sources */, E1BDF2FB2952502300CC0294 /* SubtitleActionButton.swift in Sources */,

View File

@ -66,7 +66,7 @@ struct SwiftfinApp: App {
// Swiftfin // Swiftfin
// don't keep last user id // don't keep last user id
if Defaults[.signOutOnClose] { if Defaults[.signOutOnClose] || Container.shared.currentUserSession() == nil {
Defaults[.lastSignedInUserID] = nil Defaults[.lastSignedInUserID] = nil
} }
} }

View File

@ -140,16 +140,36 @@ extension PosterButton {
let item: Item let item: Item
var body: some View { var body: some View {
VStack(alignment: .leading) { iOS15View {
if item.showTitle { VStack(alignment: .leading, spacing: 0) {
TitleContentView(item: item) if item.showTitle {
TitleContentView(item: item)
.backport
.lineLimit(1, reservesSpace: true)
.iOS15 { v in
v.font(.footnote.weight(.regular))
}
}
SubtitleContentView(item: item)
.backport
.lineLimit(1, reservesSpace: true)
.iOS15 { v in
v.font(.caption.weight(.medium))
}
}
} content: {
VStack(alignment: .leading) {
if item.showTitle {
TitleContentView(item: item)
.backport
.lineLimit(1, reservesSpace: true)
}
SubtitleContentView(item: item)
.backport .backport
.lineLimit(1, reservesSpace: true) .lineLimit(1, reservesSpace: true)
} }
SubtitleContentView(item: item)
.backport
.lineLimit(1, reservesSpace: true)
} }
} }
} }

View File

@ -0,0 +1,24 @@
//
// 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: remove when iOS 15 support removed
struct iOS15View<iOS15Content: View, Content: View>: View {
let iOS15: () -> iOS15Content
let content: () -> Content
var body: some View {
if #available(iOS 16, *) {
content()
} else {
iOS15()
}
}
}

View File

@ -11,6 +11,17 @@ import SwiftUI
extension View { extension View {
// TODO: remove after removing support for iOS 15
@ViewBuilder
func iOS15<Content: View>(@ViewBuilder _ content: (Self) -> Content) -> some View {
if #available(iOS 16, *) {
self
} else {
content(self)
}
}
func detectOrientation(_ orientation: Binding<UIDeviceOrientation>) -> some View { func detectOrientation(_ orientation: Binding<UIDeviceOrientation>) -> some View {
modifier(DetectOrientation(orientation: orientation)) modifier(DetectOrientation(orientation: orientation))
} }

View File

@ -52,6 +52,7 @@ extension ChannelLibraryView {
.foregroundColor(.primary) .foregroundColor(.primary)
.backport .backport
.lineLimit(1, reservesSpace: true) .lineLimit(1, reservesSpace: true)
.font(.footnote.weight(.regular))
} }
} }
.buttonStyle(.plain) .buttonStyle(.plain)

View File

@ -49,6 +49,7 @@ extension SeriesEpisodeSelector {
.multilineTextAlignment(.leading) .multilineTextAlignment(.leading)
.backport .backport
.lineLimit(3, reservesSpace: true) .lineLimit(3, reservesSpace: true)
.font(.caption.weight(.light))
} }
var body: some View { var body: some View {
@ -61,6 +62,14 @@ extension SeriesEpisodeSelector {
headerView headerView
contentView contentView
.iOS15 { v in
v.frame(
height: "A\nA\nA".height(
withConstrainedWidth: 10,
font: Font.caption.uiFont
)
)
}
L10n.seeMore.text L10n.seeMore.text
.font(.caption.weight(.light)) .font(.caption.weight(.light))

View File

@ -43,7 +43,6 @@ struct SeriesEpisodeSelector: View {
) )
.labelStyle(.episodeSelector) .labelStyle(.episodeSelector)
} }
.fixedSize()
} }
var body: some View { var body: some View {