Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Navigation and Item Overhaul #492

Merged
merged 34 commits into from
Aug 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
dec16fc
move work over from old branch
LePips Jul 19, 2022
1d636ed
lint
LePips Jul 19, 2022
4d42601
tvOS series and movie items work
LePips Jul 22, 2022
9faed27
fix tvOS series scrolling to about
LePips Jul 22, 2022
bf833f8
some adjustments and rework images
LePips Jul 24, 2022
f383039
wip
LePips Jul 25, 2022
caf7fe0
refactor images
LePips Jul 26, 2022
8fa67c4
tvos imagesource fixes and remove episode views
LePips Jul 27, 2022
ba483fd
Revert "tvos imagesource fixes and remove episode views"
LePips Jul 27, 2022
8b003e6
remove season accessibility
LePips Jul 27, 2022
b450d8b
wip
LePips Jul 28, 2022
f0b78cc
wip
LePips Jul 29, 2022
5d24cf0
implement new item scrollview behavior compact poster
LePips Jul 29, 2022
e07e96b
wip
LePips Aug 1, 2022
ab4aa57
wip
LePips Aug 3, 2022
924a05c
wip
LePips Aug 3, 2022
e9d384d
Merge branch 'main' into navigation-and-item-overhaul
LePips Aug 3, 2022
d33b971
Merge branch 'main' into navigation-and-item-overhaul
LePips Aug 3, 2022
762062c
fix merge conflicts
LePips Aug 3, 2022
35f5c55
wip
LePips Aug 3, 2022
8bf136b
stupid fix ripping my hair out
LePips Aug 3, 2022
20a65f6
remove old cinematic view toggle
LePips Aug 3, 2022
ef580c5
final lint
LePips Aug 3, 2022
d462510
final final lint
LePips Aug 3, 2022
06d6c68
remove my team
LePips Aug 3, 2022
ba7d4b4
some fixes
LePips Aug 3, 2022
71b1664
add slight shadow for most prominent views
LePips Aug 3, 2022
80cce26
lint
LePips Aug 3, 2022
4c19201
fix missing file
LePips Aug 3, 2022
410d157
Update HomeViewModel.swift
LePips Aug 3, 2022
8ec7a2d
Update ItemViewModel.swift
LePips Aug 3, 2022
7ddeaa1
update swiftgen to 6.6.0
LePips Aug 3, 2022
3abb326
Delete .swiftgen.yml.swp
LePips Aug 3, 2022
24fa48f
switch background to after framing
LePips Aug 5, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .swiftformat
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,6 @@
redundantClosure, \
redundantType

--exclude Shared/Generated/Strings.swift
--exclude Shared/Strings/Strings.swift

--header "\nSwiftfin is subject to the terms of the Mozilla Public\nLicense, v2.0. If a copy of the MPL was not distributed with this\nfile, you can obtain one at https://mozilla.org/MPL/2.0/.\n\nCopyright (c) {year} Jellyfin & Jellyfin Contributors\n"
63 changes: 63 additions & 0 deletions Shared/BlurHashKit/BlurHash.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//
// 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) 2022 Jellyfin & Jellyfin Contributors
//

import Foundation

public struct BlurHash {
public let components: [[(Float, Float, Float)]]

public var numberOfHorizontalComponents: Int { components.first!.count }
public var numberOfVerticalComponents: Int { components.count }

public init(components: [[(Float, Float, Float)]]) {
self.components = components
}

public func punch(_ factor: Float) -> BlurHash {
BlurHash(components: components.enumerated().map { j, horizontalComponents -> [(Float, Float, Float)] in
horizontalComponents.enumerated().map { i, component -> (Float, Float, Float) in
if i == 0 && j == 0 {
return component
} else {
return component * factor
}
}
})
}
}

public func + (lhs: BlurHash, rhs: BlurHash) throws -> BlurHash {
BlurHash(components: paddedZip(lhs.components, rhs.components, [], []).map {
paddedZip($0.0, $0.1, (0, 0, 0) as (Float, Float, Float), (0, 0, 0) as (Float, Float, Float))
.map { ($0.0.0 + $0.1.0, $0.0.1 + $0.1.1, $0.0.2 + $0.1.2) }
})
}

public func - (lhs: BlurHash, rhs: BlurHash) throws -> BlurHash {
BlurHash(components: paddedZip(lhs.components, rhs.components, [], []).map {
paddedZip($0.0, $0.1, (0, 0, 0) as (Float, Float, Float), (0, 0, 0) as (Float, Float, Float))
.map { ($0.0.0 - $0.1.0, $0.0.1 - $0.1.1, $0.0.2 - $0.1.2) }
})
}

private func paddedZip<Collection1, Collection2>(
_ collection1: Collection1,
_ collection2: Collection2,
_ padding1: Collection1.Element,
_ padding2: Collection2.Element
) -> Zip2Sequence<[Collection1.Element], [Collection2.Element]> where Collection1: Collection, Collection2: Collection {
if collection1.count < collection2.count {
let padded = collection1 + Array(repeating: padding1, count: collection2.count - collection1.count)
return zip(padded, Array(collection2))
} else if collection2.count < collection1.count {
let padded = collection2 + Array(repeating: padding2, count: collection1.count - collection2.count)
return zip(Array(collection1), padded)
} else {
return zip(Array(collection1), Array(collection2))
}
}
102 changes: 102 additions & 0 deletions Shared/BlurHashKit/ColourProbes.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
//
// 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) 2022 Jellyfin & Jellyfin Contributors
//

import Foundation

public extension BlurHash {
func linearRGB(atX x: Float) -> (Float, Float, Float) {
return components[0].enumerated().reduce((0, 0, 0)) { sum, horizontalEnumerated -> (Float, Float, Float) in
let (i, component) = horizontalEnumerated
return sum + component * cos(Float.pi * Float(i) * x)
}
}

func linearRGB(atY y: Float) -> (Float, Float, Float) {
return components.enumerated().reduce((0, 0, 0)) { sum, verticalEnumerated in
let (j, horizontalComponents) = verticalEnumerated
return sum + horizontalComponents[0] * cos(Float.pi * Float(j) * y)
}
}

func linearRGB(at position: (Float, Float)) -> (Float, Float, Float) {
return components.enumerated().reduce((0, 0, 0)) { sum, verticalEnumerated in
let (j, horizontalComponents) = verticalEnumerated
return horizontalComponents.enumerated().reduce(sum) { sum, horizontalEnumerated in
let (i, component) = horizontalEnumerated
return sum + component * cos(Float.pi * Float(i) * position.0) * cos(Float.pi * Float(j) * position.1)
}
}
}

func linearRGB(from upperLeft: (Float, Float), to lowerRight: (Float, Float)) -> (Float, Float, Float) {
return components.enumerated().reduce((0, 0, 0)) { sum, verticalEnumerated in
let (j, horizontalComponents) = verticalEnumerated
return horizontalComponents.enumerated().reduce(sum) { sum, horizontalEnumerated in
let (i, component) = horizontalEnumerated
let horizontalAverage: Float = i == 0 ? 1 :
(sin(Float.pi * Float(i) * lowerRight.0) - sin(Float.pi * Float(i) * upperLeft.0)) /
(Float(i) * Float.pi * (lowerRight.0 - upperLeft.0))
let veritcalAverage: Float = j == 0 ? 1 :
(sin(Float.pi * Float(j) * lowerRight.1) - sin(Float.pi * Float(j) * upperLeft.1)) /
(Float(j) * Float.pi * (lowerRight.1 - upperLeft.1))
return sum + component * horizontalAverage * veritcalAverage
}
}
}

func linearRGB(at upperLeft: (Float, Float), size: (Float, Float)) -> (Float, Float, Float) {
return linearRGB(from: upperLeft, to: (upperLeft.0 + size.0, upperLeft.1 + size.1))
}

var averageLinearRGB: (Float, Float, Float) {
return components[0][0]
}

var leftEdgeLinearRGB: (Float, Float, Float) { return linearRGB(atX: 0) }
var rightEdgeLinearRGB: (Float, Float, Float) { return linearRGB(atX: 1) }
var topEdgeLinearRGB: (Float, Float, Float) { return linearRGB(atY: 0) }
var bottomEdgeLinearRGB: (Float, Float, Float) { return linearRGB(atY: 1) }
var topLeftCornerLinearRGB: (Float, Float, Float) { return linearRGB(at: (0, 0)) }
var topRightCornerLinearRGB: (Float, Float, Float) { return linearRGB(at: (1, 0)) }
var bottomLeftCornerLinearRGB: (Float, Float, Float) { return linearRGB(at: (0, 1)) }
var bottomRightCornerLinearRGB: (Float, Float, Float) { return linearRGB(at: (1, 1)) }
}

public extension BlurHash {
func isDark(linearRGB rgb: (Float, Float, Float), threshold: Float = 0.3) -> Bool {
rgb.0 * 0.299 + rgb.1 * 0.587 + rgb.2 * 0.114 < threshold
}

func isDark(threshold: Float = 0.3) -> Bool { isDark(linearRGB: averageLinearRGB, threshold: threshold) }

func isDark(atX x: Float, threshold: Float = 0.3) -> Bool { isDark(linearRGB: linearRGB(atX: x), threshold: threshold) }
func isDark(atY y: Float, threshold: Float = 0.3) -> Bool { isDark(linearRGB: linearRGB(atY: y), threshold: threshold) }
func isDark(
at position: (Float, Float),
threshold: Float = 0.3
) -> Bool { isDark(linearRGB: linearRGB(at: position), threshold: threshold) }
func isDark(
from upperLeft: (Float, Float),
to lowerRight: (Float, Float),
threshold: Float = 0.3
) -> Bool { isDark(linearRGB: linearRGB(from: upperLeft, to: lowerRight), threshold: threshold) }
func isDark(
at upperLeft: (Float, Float),
size: (Float, Float),
threshold: Float = 0.3
) -> Bool { isDark(linearRGB: linearRGB(at: upperLeft, size: size), threshold: threshold) }

var isLeftEdgeDark: Bool { isDark(atX: 0) }
var isRightEdgeDark: Bool { isDark(atX: 1) }
var isTopEdgeDark: Bool { isDark(atY: 0) }
var isBottomEdgeDark: Bool { isDark(atY: 1) }
var isTopLeftCornerDark: Bool { isDark(at: (0, 0)) }
var isTopRightCornerDark: Bool { isDark(at: (1, 0)) }
var isBottomLeftCornerDark: Bool { isDark(at: (0, 1)) }
var isBottomRightCornerDark: Bool { isDark(at: (1, 1)) }
}
25 changes: 25 additions & 0 deletions Shared/BlurHashKit/ColourSpace.swift
Original file line number Diff line number Diff line change
@@ -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) 2022 Jellyfin & Jellyfin Contributors
//

import Foundation

func signPow(_ value: Float, _ exp: Float) -> Float {
copysign(pow(abs(value), exp), value)
}

func linearTosRGB(_ value: Float) -> Int {
let v = max(0, min(1, value))
if v <= 0.0031308 { return Int(v * 12.92 * 255 + 0.5) }
else { return Int((1.055 * pow(v, 1 / 2.4) - 0.055) * 255 + 0.5) }
}

func sRGBToLinear<Type: BinaryInteger>(_ value: Type) -> Float {
let v = Float(Int64(value)) / 255
if v <= 0.04045 { return v / 12.92 }
else { return pow((v + 0.055) / 1.055, 2.4) }
}
43 changes: 43 additions & 0 deletions Shared/BlurHashKit/EscapeSequences.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//
// 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) 2022 Jellyfin & Jellyfin Contributors
//

import Foundation

extension BlurHash {
var twoByThreeEscapeSequence: String {
let areas: [(from: (Float, Float), to: (Float, Float))] = [
(from: (0, 0), to: (0.333, 0.5)),
(from: (0, 0.5), to: (0.333, 1.0)),
(from: (0.333, 0), to: (0.666, 0.5)),
(from: (0.333, 0.5), to: (0.666, 1.0)),
(from: (0.666, 0), to: (1.0, 0.5)),
(from: (0.666, 0.5), to: (1.0, 1.0)),
]

let rgb: [(Float, Float, Float)] = areas.map { area in
linearRGB(from: area.from, to: area.to)
}

let maxRgb: (Float, Float, Float) = rgb.reduce((-Float.infinity, -Float.infinity, -Float.infinity), max)
let minRgb: (Float, Float, Float) = rgb.reduce((Float.infinity, Float.infinity, Float.infinity), min)

let positiveScale: (Float, Float, Float) = ((1, 1, 1) - averageLinearRGB) / (maxRgb - averageLinearRGB)
let negativeScale: (Float, Float, Float) = averageLinearRGB / (averageLinearRGB - minRgb)
let scale: (Float, Float, Float) = min(positiveScale, negativeScale)

let scaledRgb: [(Float, Float, Float)] = rgb.map { rgb in
(rgb - averageLinearRGB) * scale + averageLinearRGB
}

let c = scaledRgb.map { rgb in
(linearTosRGB(rgb.0) / 51) * 36 + (linearTosRGB(rgb.1) / 51) * 6 + (linearTosRGB(rgb.2) / 51) + 16
}

return "\u{1b}[38;5;\(c[1]);48;5;\(c[0])m▄\u{1b}[38;5;\(c[3]);48;5;\(c[2])m▄\u{1b}[38;5;\(c[5]);48;5;\(c[4])m▄\u{1b}[m"
}
}
76 changes: 76 additions & 0 deletions Shared/BlurHashKit/FromString.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
//
// 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) 2022 Jellyfin & Jellyfin Contributors
//

import Foundation

public extension BlurHash {
init?(string: String) {
guard string.count >= 6 else { return nil }

let sizeFlag = String(string[0]).decode83()
let numberOfHorizontalComponents = (sizeFlag % 9) + 1
let numberOfVerticalComponents = (sizeFlag / 9) + 1

let quantisedMaximumValue = String(string[1]).decode83()
let maximumValue = Float(quantisedMaximumValue + 1) / 166

guard string.count == 4 + 2 * numberOfHorizontalComponents * numberOfVerticalComponents else { return nil }

self.components = (0 ..< numberOfVerticalComponents).map { j in
(0 ..< numberOfHorizontalComponents).map { i in
if i == 0 && j == 0 {
let value = String(string[2 ..< 6]).decode83()
return BlurHash.decodeDC(value)
} else {
let index = i + j * numberOfHorizontalComponents
let value = String(string[4 + index * 2 ..< 4 + index * 2 + 2]).decode83()
return BlurHash.decodeAC(value, maximumValue: maximumValue)
}
}
}
}

private static func decodeDC(_ value: Int) -> (Float, Float, Float) {
let intR = value >> 16
let intG = (value >> 8) & 255
let intB = value & 255
return (sRGBToLinear(intR), sRGBToLinear(intG), sRGBToLinear(intB))
}

private static func decodeAC(_ value: Int, maximumValue: Float) -> (Float, Float, Float) {
let quantR = value / (19 * 19)
let quantG = (value / 19) % 19
let quantB = value % 19

let rgb = (
signPow((Float(quantR) - 9) / 9, 2) * maximumValue,
signPow((Float(quantG) - 9) / 9, 2) * maximumValue,
signPow((Float(quantB) - 9) / 9, 2) * maximumValue
)

return rgb
}
}

private extension String {
subscript(offset: Int) -> Character {
self[index(startIndex, offsetBy: offset)]
}

subscript(bounds: CountableClosedRange<Int>) -> Substring {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(startIndex, offsetBy: bounds.upperBound)
return self[start ... end]
}

subscript(bounds: CountableRange<Int>) -> Substring {
let start = index(startIndex, offsetBy: bounds.lowerBound)
let end = index(startIndex, offsetBy: bounds.upperBound)
return self[start ..< end]
}
}
Loading