Skip to content

Commit

Permalink
[iOS] Admin Dashboard - Device Management (jellyfin#1277)
Browse files Browse the repository at this point in the history
* Split out Devices Logic - Ready to go!

* Review Items + Reworking the deleteDevices logic to all use the same deleteDevice core + deleteDevices. Delete All Devices now just uses the more generic deleteDevices

* Allow Filtering on UserID for later usage on UserDetailView.

* Fully remove DeleteAll action in favor of Delete Devices. Change view to pass in the viewModel.devices as a 'Delete All' function

* DeviceDetailsView

* Section Split out, Localization, and cleanup.

* I guess I missed there on first upload.

* Initial Select All / Delete Devices logic. Checkbox options on the list. Hopefully this is good.

* Initial Review Item!

* Custom Device Name is now a field. Change DevicesViewModel to Eventful to capture updates

* Revised Device Interaction Buttons

* Remove unused Label.

* Make DeviceRow mirror UserRow. UpdateDevicesView to have DeleteButton when in EditMode. Also, it's EDITMODE not SELECTMODE... Finally, make sure the SelectedDevice and SelectedDevices are both empty if the user tries to delete themselves and fails. Change how the single device delete works to confirm deleting from an array still works as needed.

* wip

* Review Changes: https://github.com/jellyfin/Swiftfin/pull/1277/files/61b37162397bd27797b084c90a08ffa25fd2447c

* Merge issues + testing again to make sure. Checks out.

* wip

---------

Co-authored-by: Ethan Pippin <[email protected]>
  • Loading branch information
JPKribs and LePips authored Oct 21, 2024
1 parent 11d6907 commit a04f97e
Show file tree
Hide file tree
Showing 22 changed files with 1,317 additions and 61 deletions.
4 changes: 2 additions & 2 deletions Shared/Components/TextPairView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ struct TextPairView: View {
var body: some View {
HStack {
leading
.foregroundColor(.primary)
.foregroundStyle(.primary)

Spacer()

trailing
.foregroundColor(.secondary)
.foregroundStyle(.secondary)
}
}
}
Expand Down
14 changes: 14 additions & 0 deletions Shared/Coordinators/SettingsCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ final class SettingsCoordinator: NavigationCoordinatable {
@Route(.push)
var tasks = makeTasks
@Route(.push)
var devices = makeDevices
@Route(.push)
var deviceDetails = makeDeviceDetails
@Route(.push)
var editScheduledTask = makeEditScheduledTask
@Route(.push)
var serverLogs = makeServerLogs
Expand Down Expand Up @@ -186,6 +190,16 @@ final class SettingsCoordinator: NavigationCoordinatable {
ScheduledTasksView()
}

@ViewBuilder
func makeDevices() -> some View {
DevicesView()
}

@ViewBuilder
func makeDeviceDetails(device: DeviceInfo) -> some View {
DeviceDetailsView(device: device)
}

@ViewBuilder
func makeEditScheduledTask(observer: ServerTaskObserver) -> some View {
EditScheduledTaskView(observer: observer)
Expand Down
20 changes: 20 additions & 0 deletions Shared/Extensions/JellyfinAPI/DeviceInfo.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// 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 DeviceInfo {

var device: DeviceType {
DeviceType(
client: appName,
deviceName: name
)
}
}
4 changes: 4 additions & 0 deletions Shared/Extensions/URL.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ extension URL {

static let swiftfinGithubIssues: URL = URL(string: "https://github.com/jellyfin/Swiftfin/issues")!

static let jellyfinDocsDevices: URL = URL(string: "https://jellyfin.org/docs/general/server/devices")!

static let jellyfinDocsTasks: URL = URL(string: "https://jellyfin.org/docs/general/server/tasks")!

func isDirectoryAndReachable() throws -> Bool {
guard try resourceValues(forKeys: [.isDirectoryKey]).isDirectory == true else {
return false
Expand Down
46 changes: 46 additions & 0 deletions Shared/Strings/Strings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ internal enum L10n {
internal static func airWithDate(_ p1: UnsafePointer<CChar>) -> String {
return L10n.tr("Localizable", "airWithDate", p1, fallback: "Airs %s")
}
/// View all past and present devices that have connected.
internal static let allDevicesDescription = L10n.tr("Localizable", "allDevicesDescription", fallback: "View all past and present devices that have connected.")
/// All Genres
internal static let allGenres = L10n.tr("Localizable", "allGenres", fallback: "All Genres")
/// All Media
Expand Down Expand Up @@ -138,6 +140,8 @@ internal enum L10n {
internal static let cancelling = L10n.tr("Localizable", "cancelling", fallback: "Cancelling...")
/// Cannot connect to host
internal static let cannotConnectToHost = L10n.tr("Localizable", "cannotConnectToHost", fallback: "Cannot connect to host")
/// Capabilities
internal static let capabilities = L10n.tr("Localizable", "capabilities", fallback: "Capabilities")
/// CAST
internal static let cast = L10n.tr("Localizable", "cast", fallback: "CAST")
/// Cast & Crew
Expand Down Expand Up @@ -214,6 +218,12 @@ internal enum L10n {
internal static let currentPosition = L10n.tr("Localizable", "currentPosition", fallback: "Current Position")
/// PlaybackCompatibility Custom Category
internal static let custom = L10n.tr("Localizable", "custom", fallback: "Custom")
/// Custom Device Name
internal static let customDeviceName = L10n.tr("Localizable", "customDeviceName", fallback: "Custom Device Name")
/// Your custom device name '%1$@' has been saved.
internal static func customDeviceNameSaved(_ p1: Any) -> String {
return L10n.tr("Localizable", "customDeviceNameSaved", String(describing: p1), fallback: "Your custom device name '%1$@' has been saved.")
}
/// Custom profile is Added to the Existing Profiles
internal static let customDeviceProfileAdd = L10n.tr("Localizable", "customDeviceProfileAdd", fallback: "The custom device profiles will be added to the default Swiftfin device profiles")
/// Device Profile Section Description
Expand All @@ -236,6 +246,20 @@ internal enum L10n {
internal static let defaultScheme = L10n.tr("Localizable", "defaultScheme", fallback: "Default Scheme")
/// Server Detail View - Delete
internal static let delete = L10n.tr("Localizable", "delete", fallback: "Delete")
/// Delete Device
internal static let deleteDevice = L10n.tr("Localizable", "deleteDevice", fallback: "Delete Device")
/// Failed to Delete Device
internal static let deleteDeviceFailed = L10n.tr("Localizable", "deleteDeviceFailed", fallback: "Failed to Delete Device")
/// Cannot delete a session from the same device (%1$@).
internal static func deleteDeviceSelfDeletion(_ p1: Any) -> String {
return L10n.tr("Localizable", "deleteDeviceSelfDeletion", String(describing: p1), fallback: "Cannot delete a session from the same device (%1$@).")
}
/// Are you sure you wish to delete this device? This session will be logged out.
internal static let deleteDeviceWarning = L10n.tr("Localizable", "deleteDeviceWarning", fallback: "Are you sure you wish to delete this device? This session will be logged out.")
/// Delete Selected Devices
internal static let deleteSelectedDevices = L10n.tr("Localizable", "deleteSelectedDevices", fallback: "Delete Selected Devices")
/// Are you sure you wish to delete all selected devices? All selected sessions will be logged out.
internal static let deleteSelectionDevicesWarning = L10n.tr("Localizable", "deleteSelectionDevicesWarning", fallback: "Are you sure you wish to delete all selected devices? All selected sessions will be logged out.")
/// Server Detail View - Delete Server
internal static let deleteServer = L10n.tr("Localizable", "deleteServer", fallback: "Delete Server")
/// Delivery
Expand All @@ -244,6 +268,8 @@ internal enum L10n {
internal static let device = L10n.tr("Localizable", "device", fallback: "Device")
/// Section Header for Device Profiles
internal static let deviceProfile = L10n.tr("Localizable", "deviceProfile", fallback: "Device Profile")
/// Devices
internal static let devices = L10n.tr("Localizable", "devices", fallback: "Devices")
/// PlaybackCompatibility DirectPlay Category
internal static let direct = L10n.tr("Localizable", "direct", fallback: "Direct Play")
/// DIRECTOR
Expand Down Expand Up @@ -424,6 +450,8 @@ internal enum L10n {
internal static let networking = L10n.tr("Localizable", "networking", fallback: "Networking")
/// Network timed out
internal static let networkTimedOut = L10n.tr("Localizable", "networkTimedOut", fallback: "Network timed out")
/// Never
internal static let never = L10n.tr("Localizable", "never", fallback: "Never")
/// Message shown when a task has never run
internal static let neverRun = L10n.tr("Localizable", "neverRun", fallback: "Never run")
/// News
Expand All @@ -440,6 +468,8 @@ internal enum L10n {
internal static let nextUpDaysDescription = L10n.tr("Localizable", "nextUpDaysDescription", fallback: "Set the maximum amount of days a show should stay in the 'Next Up' list without watching it.")
/// Settings Description for enabling rewatching in Next Up
internal static let nextUpRewatch = L10n.tr("Localizable", "nextUpRewatch", fallback: "Rewatching in Next Up")
/// No
internal static let no = L10n.tr("Localizable", "no", fallback: "No")
/// No Cast devices found..
internal static let noCastdevicesfound = L10n.tr("Localizable", "noCastdevicesfound", fallback: "No Cast devices found..")
/// No Codec
Expand Down Expand Up @@ -596,6 +626,8 @@ internal enum L10n {
internal static let remainingTime = L10n.tr("Localizable", "remainingTime", fallback: "Remaining Time")
/// Remove
internal static let remove = L10n.tr("Localizable", "remove", fallback: "Remove")
/// Remove All
internal static let removeAll = L10n.tr("Localizable", "removeAll", fallback: "Remove All")
/// Remove All Servers
internal static let removeAllServers = L10n.tr("Localizable", "removeAllServers", fallback: "Remove All Servers")
/// Remove All Users
Expand Down Expand Up @@ -672,6 +704,8 @@ internal enum L10n {
internal static let seekSlideGestureEnabled = L10n.tr("Localizable", "seekSlideGestureEnabled", fallback: "Seek Slide Gesture Enabled")
/// See More
internal static let seeMore = L10n.tr("Localizable", "seeMore", fallback: "See More")
/// Select All
internal static let selectAll = L10n.tr("Localizable", "selectAll", fallback: "Select All")
/// Select Cast Destination
internal static let selectCastDestination = L10n.tr("Localizable", "selectCastDestination", fallback: "Select Cast Destination")
/// Series
Expand Down Expand Up @@ -786,8 +820,18 @@ internal enum L10n {
internal static let subtitlesDisclaimer = L10n.tr("Localizable", "subtitlesDisclaimer", fallback: "Settings only affect some subtitle types")
/// Subtitle Size
internal static let subtitleSize = L10n.tr("Localizable", "subtitleSize", fallback: "Subtitle Size")
/// Success
internal static let success = L10n.tr("Localizable", "success", fallback: "Success")
/// Suggestions
internal static let suggestions = L10n.tr("Localizable", "suggestions", fallback: "Suggestions")
/// Content Uploading
internal static let supportsContentUploading = L10n.tr("Localizable", "supportsContentUploading", fallback: "Content Uploading")
/// Media Control
internal static let supportsMediaControl = L10n.tr("Localizable", "supportsMediaControl", fallback: "Media Control")
/// Persistent Identifier
internal static let supportsPersistentIdentifier = L10n.tr("Localizable", "supportsPersistentIdentifier", fallback: "Persistent Identifier")
/// Sync
internal static let supportsSync = L10n.tr("Localizable", "supportsSync", fallback: "Sync")
/// Switch User
internal static let switchUser = L10n.tr("Localizable", "switchUser", fallback: "Switch User")
/// Represents the system theme setting
Expand Down Expand Up @@ -896,6 +940,8 @@ internal enum L10n {
internal static let wip = L10n.tr("Localizable", "wip", fallback: "WIP")
/// Yellow
internal static let yellow = L10n.tr("Localizable", "yellow", fallback: "Yellow")
/// Yes
internal static let yes = L10n.tr("Localizable", "yes", fallback: "Yes")
/// Your Favorites
internal static let yourFavorites = L10n.tr("Localizable", "yourFavorites", fallback: "Your Favorites")
}
Expand Down
Loading

0 comments on commit a04f97e

Please sign in to comment.