jellyflood/Swiftfin/Views/AdminDashboardView/ActiveSessions/ActiveSessionsView/Components/ActiveSessionRow.swift
Joe Kribs 0025422634
[iOS & tvOS] Upgrade SDK to 10.10 (#1463)
* Buildable!

* Update file names.

* Default sort to sort name NOT name.

* SessionInfoDto vs SessionInfo

* Targetting

* Fix many invalid `ItemSortBy` existing. Will need to revisit later to see which can still be used!

* ExtraTypes Patch.

* Move from Binding to OnChange. Tested and Working.

* Update README.md

Update README to use 10.10.6. Bumped up from 10.8.13

* Update to Main on https://github.com/jellyfin/jellyfin-sdk-swift.git

* Now using https://github.com/jellyfin/jellyfin-sdk-swift.git again!

* Paths.getUserViews() userId moved to parameters

* Fix ViewModels where -Dto suffixes were removed by https://github.com/jellyfin/Swiftfin/pull/1465 auto-merge.

* SupportedCaseIterable

* tvOS supportedCases fixes for build issue.

* cleanup

* update API to 0.5.1 and correct VideoRangeTypes.

* Remove deviceProfile.responseProfiles = videoPlayer.responseProfiles

* Second to last adjustment:
Resolved: // TODO: 10.10 - Filter to only valid SortBy's for each BaseItemKind.
Last outstanding item: // TODO: 10.10 - What should authenticationProviderID & passwordResetProviderID be?

* Trailers itemID must precede userID

* Force User Policy to exist.

---------

Co-authored-by: Ethan Pippin <ethanpippin2343@gmail.com>
2025-04-06 23:42:47 -04:00

138 lines
4.5 KiB
Swift

//
// 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) 2025 Jellyfin & Jellyfin Contributors
//
import Defaults
import JellyfinAPI
import SwiftUI
extension ActiveSessionsView {
struct ActiveSessionRow: View {
@CurrentDate
private var currentDate: Date
@ObservedObject
private var box: BindingBox<SessionInfoDto?>
private let onSelect: () -> Void
private var session: SessionInfoDto {
box.value ?? .init()
}
init(box: BindingBox<SessionInfoDto?>, onSelect action: @escaping () -> Void) {
self.box = box
self.onSelect = action
}
@ViewBuilder
private var rowLeading: some View {
// TODO: better handling for different poster types
Group {
if let nowPlayingItem = session.nowPlayingItem {
if nowPlayingItem.type == .audio {
ZStack {
Color.clear
ImageView(nowPlayingItem.squareImageSources(maxWidth: 60))
.failure {
SystemImageContentView(systemName: nowPlayingItem.systemImage)
}
}
.squarePosterStyle()
.frame(width: 60, height: 60)
} else {
ZStack {
Color.clear
ImageView(nowPlayingItem.portraitImageSources(maxWidth: 60))
.failure {
SystemImageContentView(systemName: nowPlayingItem.systemImage)
}
}
.posterStyle(.portrait)
.frame(width: 60, height: 90)
}
} else {
ZStack {
session.device.clientColor
Image(session.device.image)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 40)
}
.squarePosterStyle()
.frame(width: 60, height: 60)
}
}
.frame(width: 60, height: 90)
.posterShadow()
.padding(.vertical, 8)
}
@ViewBuilder
private func activeSessionDetails(_ nowPlayingItem: BaseItemDto, playState: PlayerStateInfo) -> some View {
VStack(alignment: .leading) {
Text(session.userName ?? L10n.unknown)
.font(.headline)
Text(nowPlayingItem.name ?? L10n.unknown)
ProgressSection(
item: nowPlayingItem,
playState: playState,
transcodingInfo: session.transcodingInfo
)
}
.font(.subheadline)
}
@ViewBuilder
private var idleSessionDetails: some View {
VStack(alignment: .leading) {
Text(session.userName ?? L10n.unknown)
.font(.headline)
if let client = session.client {
TextPairView(leading: L10n.client, trailing: client)
}
if let device = session.deviceName {
TextPairView(leading: L10n.device, trailing: device)
}
if let lastActivityDate = session.lastActivityDate {
TextPairView(
L10n.lastSeen,
value: Text(lastActivityDate, format: .lastSeen)
)
.id(currentDate)
.monospacedDigit()
}
}
.font(.subheadline)
}
var body: some View {
ListRow(insets: .init(vertical: 8, horizontal: EdgeInsets.edgePadding)) {
rowLeading
} content: {
if let nowPlayingItem = session.nowPlayingItem, let playState = session.playState {
activeSessionDetails(nowPlayingItem, playState: playState)
} else {
idleSessionDetails
}
}
.onSelect(perform: onSelect)
}
}
}