Skip to content

Commit

Permalink
[iOS] Admin Dashboard - Add/Delete Task Triggers (jellyfin#1276)
Browse files Browse the repository at this point in the history
* All Working. TODO: Figure out why TimeInterval crashes Swiftfin if I select 'Cancel'

* Cleanup. Kind of a typeAlias but not really? Fixed the minute crash, I was make a recursive calc. All good now. Make sure temp values default to existing value at startup

* Manual Run action from Edit View

* Issues resolved.

* Labels / soft merge with Main

* Utilize events to print a success/failure message for when there is an attempted change with a TaskTrigger.

* Fix label wrong value & remove TODO for completed item.

* Fix all the merge issues.

* wip

* wip

* localize

---------

Co-authored-by: Ethan Pippin <[email protected]>
  • Loading branch information
JPKribs and LePips authored Oct 23, 2024
1 parent a04f97e commit c46ee13
Show file tree
Hide file tree
Showing 30 changed files with 1,612 additions and 205 deletions.
63 changes: 38 additions & 25 deletions Shared/Coordinators/SettingsCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,30 +49,34 @@ final class SettingsCoordinator: NavigationCoordinatable {
var videoPlayerSettings = makeVideoPlayerSettings
@Route(.push)
var customDeviceProfileSettings = makeCustomDeviceProfileSettings
@Route(.modal)
var itemOverviewView = makeItemOverviewView

@Route(.modal)
var editCustomDeviceProfile = makeEditCustomDeviceProfile
@Route(.modal)
var createCustomDeviceProfile = makeCreateCustomDeviceProfile

// TODO: Move AdminDashboard items to its own coordinator ->
@Route(.push)
var userDashboard = makeUserDashboard
@Route(.push)
var activeSessions = makeActiveSessions
@Route(.push)
var activeDeviceDetails = makeActiveDeviceDetails
@Route(.modal)
var itemOverviewView = makeItemOverviewView
@Route(.push)
var tasks = makeTasks
@Route(.push)
var devices = makeDevices
@Route(.push)
var deviceDetails = makeDeviceDetails
@Route(.push)
var editScheduledTask = makeEditScheduledTask
var editServerTask = makeEditServerTask
@Route(.modal)
var addServerTaskTrigger = makeAddServerTaskTrigger
@Route(.push)
var serverLogs = makeServerLogs

@Route(.modal)
var editCustomDeviceProfile = makeEditCustomDeviceProfile
@Route(.modal)
var createCustomDeviceProfile = makeCreateCustomDeviceProfile
// <- End of AdminDashboard Items

#if DEBUG
@Route(.push)
Expand Down Expand Up @@ -164,6 +168,22 @@ final class SettingsCoordinator: NavigationCoordinatable {
EditServerView(server: server)
}

func makeItemOverviewView(item: BaseItemDto) -> NavigationViewCoordinator<BasicNavigationViewCoordinator> {
NavigationViewCoordinator {
ItemOverviewView(item: item)
}
}

func makeItemFilterDrawerSelector(selection: Binding<[ItemFilterType]>) -> some View {
OrderedSectionSelectorView(selection: selection, sources: ItemFilterType.allCases)
.navigationTitle(L10n.filters)
}

func makeVideoPlayerSettings() -> VideoPlayerSettingsCoordinator {
VideoPlayerSettingsCoordinator()
}

// TODO: Move AdminDashboard items to its own coordinator ->
@ViewBuilder
func makeUserDashboard() -> some View {
UserDashboardView()
Expand All @@ -179,15 +199,9 @@ final class SettingsCoordinator: NavigationCoordinatable {
ActiveSessionDetailView(box: box)
}

func makeItemOverviewView(item: BaseItemDto) -> NavigationViewCoordinator<BasicNavigationViewCoordinator> {
NavigationViewCoordinator {
ItemOverviewView(item: item)
}
}

@ViewBuilder
func makeTasks() -> some View {
ScheduledTasksView()
ServerTasksView()
}

@ViewBuilder
Expand All @@ -201,23 +215,22 @@ final class SettingsCoordinator: NavigationCoordinatable {
}

@ViewBuilder
func makeEditScheduledTask(observer: ServerTaskObserver) -> some View {
EditScheduledTaskView(observer: observer)
func makeEditServerTask(observer: ServerTaskObserver) -> some View {
EditServerTaskView(observer: observer)
}

func makeAddServerTaskTrigger(observer: ServerTaskObserver) -> NavigationViewCoordinator<BasicNavigationViewCoordinator> {
NavigationViewCoordinator {
AddTaskTriggerView(observer: observer)
}
}

@ViewBuilder
func makeServerLogs() -> some View {
ServerLogsView()
}

func makeItemFilterDrawerSelector(selection: Binding<[ItemFilterType]>) -> some View {
OrderedSectionSelectorView(selection: selection, sources: ItemFilterType.allCases)
.navigationTitle(L10n.filters)
}

func makeVideoPlayerSettings() -> VideoPlayerSettingsCoordinator {
VideoPlayerSettingsCoordinator()
}
// <- End of AdminDashboard Items

#if DEBUG
@ViewBuilder
Expand Down
25 changes: 25 additions & 0 deletions Shared/Extensions/JellyfinAPI/DayOfWeek.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) 2024 Jellyfin & Jellyfin Contributors
//

import Foundation
import JellyfinAPI

extension DayOfWeek {

var displayTitle: String? {
let newLineRemoved = rawValue.replacingOccurrences(of: "\n", with: "")

guard let index = DateFormatter().weekdaySymbols.firstIndex(of: newLineRemoved) else {
return nil
}

return Calendar.current
.weekdaySymbols[index]
.localizedCapitalized
}
}
87 changes: 87 additions & 0 deletions Shared/Extensions/JellyfinAPI/ServerTicks.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
//
// 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

// TODO: remove and have sdk use strong types instead

typealias ServerTicks = Int

extension ServerTicks {

// MARK: - Conversion Constants

private static let ticksPerSecond = 10_000_000
private static let ticksPerMinute = 600_000_000
private static let ticksPerHour = 36_000_000_000
private static let ticksPerDay = 864_000_000_000

// MARK: - Initializers

init(_ ticks: Int? = nil) {
self = ticks ?? 0
}

init(seconds: Int? = nil) {
self = (seconds ?? 0) * ServerTicks.ticksPerSecond
}

init(minutes: Int? = nil) {
self = (minutes ?? 0) * ServerTicks.ticksPerMinute
}

init(hours: Int? = nil) {
self = (hours ?? 0) * ServerTicks.ticksPerHour
}

init(days: Int? = nil) {
self = (days ?? 0) * ServerTicks.ticksPerDay
}

init(timeInterval: TimeInterval? = nil) {
self = Int((timeInterval ?? 0) * Double(ServerTicks.ticksPerSecond))
}

init(date: Date) {
let components = Calendar.current.dateComponents([.hour, .minute], from: date)
let totalSeconds = TimeInterval((components.hour ?? 0) * 3600 + (components.minute ?? 0) * 60)
self = Int(totalSeconds * 10_000_000)
}

// MARK: - Computed Properties

var ticks: Int {
self
}

var seconds: TimeInterval {
TimeInterval(self) / Double(ServerTicks.ticksPerSecond)
}

var minutes: TimeInterval {
TimeInterval(self) / Double(ServerTicks.ticksPerMinute)
}

var hours: TimeInterval {
TimeInterval(self) / Double(ServerTicks.ticksPerHour)
}

var days: TimeInterval {
TimeInterval(self) / Double(ServerTicks.ticksPerDay)
}

var date: Date {
let totalSeconds = TimeInterval(self) / 10_000_000
let hours = Int(totalSeconds) / 3600
let minutes = (Int(totalSeconds) % 3600) / 60
var components = DateComponents()
components.hour = hours
components.minute = minutes
return Calendar.current.date(from: components) ?? Date()
}
}
24 changes: 24 additions & 0 deletions Shared/Extensions/JellyfinAPI/TaskState.swift
Original file line number Diff line number Diff line change
@@ -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 Foundation
import JellyfinAPI

extension TaskState: Displayable {

var displayTitle: String {
switch self {
case .cancelling:
return L10n.cancelling
case .idle:
return L10n.idle
case .running:
return L10n.running
}
}
}
45 changes: 45 additions & 0 deletions Shared/Extensions/JellyfinAPI/TaskTriggerType.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//
// 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

// TODO: move to SDK as patch file

enum TaskTriggerType: String, Codable, CaseIterable, Displayable, SystemImageable {

case daily = "DailyTrigger"
case weekly = "WeeklyTrigger"
case interval = "IntervalTrigger"
case startup = "StartupTrigger"

var displayTitle: String {
switch self {
case .daily:
return L10n.daily
case .weekly:
return L10n.weekly
case .interval:
return L10n.interval
case .startup:
return L10n.onApplicationStartup
}
}

var systemImage: String {
switch self {
case .daily:
return "clock"
case .weekly:
return "calendar"
case .interval:
return "timer"
case .startup:
return "power"
}
}
}
Loading

0 comments on commit c46ee13

Please sign in to comment.