jellyflood/Swiftfin/Views/SettingsView/UserDashboardView/ServerTasksView/Components/ServerTaskRow.swift

127 lines
4.0 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) 2024 Jellyfin & Jellyfin Contributors
//
import JellyfinAPI
import Stinsen
import SwiftUI
extension ServerTasksView {
struct ServerTaskRow: View {
@CurrentDate
private var currentDate: Date
@EnvironmentObject
private var router: SettingsCoordinator.Router
@ObservedObject
var observer: ServerTaskObserver
@State
private var isPresentingConfirmation = false
// MARK: - Task Details Section
@ViewBuilder
private var taskView: some View {
VStack(alignment: .leading, spacing: 4) {
Text(observer.task.name ?? L10n.unknown)
.fontWeight(.semibold)
taskResultView
.font(.subheadline)
.foregroundStyle(.secondary)
}
}
// MARK: - Task Status View
@ViewBuilder
private var taskResultView: some View {
if observer.state == .running {
Text(L10n.running)
} else if observer.task.state == .cancelling {
Text(L10n.cancelling)
} else {
if let taskEndTime = observer.task.lastExecutionResult?.endTimeUtc {
Text(L10n.lastRunTime(Date.RelativeFormatStyle(presentation: .numeric, unitsStyle: .narrow).format(taskEndTime)))
.id(currentDate)
.monospacedDigit()
} else {
Text(L10n.neverRun)
}
if let status = observer.task.lastExecutionResult?.status, status != .completed {
Label(
status.displayTitle,
systemImage: "exclamationmark.circle.fill"
)
.labelStyle(.sectionFooterWithImage(imageStyle: .orange))
.foregroundStyle(.orange)
.backport
.fontWeight(.semibold)
}
}
}
@ViewBuilder
var body: some View {
Button {
isPresentingConfirmation = true
} label: {
HStack {
taskView
Spacer()
if observer.state == .running {
ProgressView(value: (observer.task.currentProgressPercentage ?? 0) / 100)
.progressViewStyle(.gauge)
.transition(.opacity.combined(with: .scale).animation(.bouncy))
.frame(width: 25, height: 25)
}
Image(systemName: "chevron.right")
.font(.body.weight(.regular))
.foregroundStyle(.secondary)
}
}
.animation(.linear(duration: 0.1), value: observer.state)
.foregroundStyle(.primary, .secondary)
.confirmationDialog(
observer.task.name ?? .emptyDash,
isPresented: $isPresentingConfirmation,
titleVisibility: .visible
) {
Group {
if observer.state == .running {
Button(L10n.stop) {
observer.send(.stop)
}
} else {
Button(L10n.run) {
observer.send(.start)
}
}
}
.disabled(observer.task.state == .cancelling)
Button(L10n.edit) {
router.route(to: \.editServerTask, observer)
}
} message: {
if let description = observer.task.description {
Text(description)
}
}
}
}
}