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

[iOS] Media Item Menu - Edit Item Images #1345

Open
wants to merge 62 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
305a9b5
Good start but some missing items:
JPKribs Dec 8, 2024
8b813ba
Upload still failing but now update and set are 2 different processes…
JPKribs Dec 8, 2024
0699c80
~70% Complete
JPKribs Dec 8, 2024
0313790
Merge branch 'jellyfin:main' into editItemImages
JPKribs Dec 8, 2024
480b94d
Merge with Main
JPKribs Dec 8, 2024
babc444
Merge branch 'main' into editItemImages
JPKribs Dec 11, 2024
2d9cf7c
Merge branch 'main' into editItemImages
JPKribs Dec 14, 2024
c246de7
Merge branch 'jellyfin:main' into editItemImages
JPKribs Dec 20, 2024
f21bb99
URL Changes
JPKribs Dec 20, 2024
fa29173
Updating logic and confirmation screen
JPKribs Dec 20, 2024
57cf69c
Merge branch 'jellyfin:main' into editItemImages
JPKribs Dec 20, 2024
da3a8ed
Lots of changes:
JPKribs Dec 21, 2024
731a386
Merge remote-tracking branch 'refs/remotes/origin/editItemImages'
JPKribs Dec 21, 2024
daca500
Merge branch 'jellyfin:main' into editItemImages
JPKribs Dec 21, 2024
33f38bd
Breaking this even more with the hopes of a better tomorrow.
JPKribs Dec 22, 2024
51d0148
Merge remote-tracking branch 'refs/remotes/origin/editItemImages'
JPKribs Dec 22, 2024
08a8107
Getting better?
JPKribs Dec 22, 2024
938cc2b
Refreshing is working but I might need to make this work mroe effient…
JPKribs Dec 22, 2024
26677c7
90% There!
JPKribs Dec 23, 2024
bccfcef
Ability to cancel the update
JPKribs Dec 23, 2024
9949b72
Still no luck uploading images?
JPKribs Dec 23, 2024
206fbff
Merge branch 'jellyfin:main' into editItemImages
JPKribs Dec 28, 2024
1dac7cd
Stop reordering on deletion/addition
JPKribs Dec 29, 2024
2c3cfed
Merge remote-tracking branch 'refs/remotes/origin/editItemImages'
JPKribs Dec 29, 2024
d3b20b9
Merge branch 'jellyfin:main' into editItemImages
JPKribs Dec 29, 2024
483db8c
Merge branch 'main' into editItemImages
JPKribs Dec 31, 2024
6ee6b12
2025 disclaimers
JPKribs Jan 3, 2025
08e967d
Merge branch 'main' into editItemImages
JPKribs Jan 3, 2025
ad180b5
Merge branch 'editItemImages' of https://github.com/JPKribs/Swiftfin …
JPKribs Jan 3, 2025
7baead4
Uploading finally works!
JPKribs Jan 4, 2025
c03f2c1
Functional but messy.
JPKribs Jan 4, 2025
605eee6
Now conforms to PagingLIbraryViewModel but everything else is a mess
JPKribs Jan 4, 2025
f3a5343
Close!
JPKribs Jan 5, 2025
22fb028
First no all appears
JPKribs Jan 5, 2025
ada6e01
Fix double pop/routerdismiss
JPKribs Jan 5, 2025
fd9734e
Uploading from Photos is (Finally) Ready!
JPKribs Jan 6, 2025
62bce8d
wip
LePips Jan 6, 2025
751b977
Reuse PhotoPicker and Crop code.
JPKribs Jan 6, 2025
db368e7
Merge remote-tracking branch 'refs/remotes/origin/editItemImages'
JPKribs Jan 6, 2025
8cc8d64
4/6 of the codefactor changes
JPKribs Jan 6, 2025
eb1570f
Pass around the URL NOT the UIImage
JPKribs Jan 6, 2025
d004bcf
Clean up ItemImageDetails types.
JPKribs Jan 7, 2025
43364b7
Make sure the ImageView mirrors the real shape of the image. Posters …
JPKribs Jan 7, 2025
31b4da6
Rating Type label.
JPKribs Jan 7, 2025
d17d416
Delete confirmation dialog.
JPKribs Jan 7, 2025
a94fc64
Remove double sizing. Remove Unused ViewModel. Change PhotoPicker to …
JPKribs Jan 7, 2025
0832c7a
Get the image URL as needed. No more Truples. Localize ImageTypes.
JPKribs Jan 7, 2025
6dfecf7
Remove attempt at ImageInfo Poster Comformance.
JPKribs Jan 7, 2025
57fc825
Even more cleanup
JPKribs Jan 7, 2025
710e9a6
Delete vs Save flip
JPKribs Jan 7, 2025
7a7c875
Hide delete button
JPKribs Jan 7, 2025
57eab13
Even more cleanup
JPKribs Jan 7, 2025
938ad7a
Fix tvOS build issues.
JPKribs Jan 7, 2025
4ab8131
Reduce delay & remove unused comment. Should finally be ready again.
JPKribs Jan 7, 2025
87a5d00
wip
LePips Jan 7, 2025
a1d75df
Update ItemImagesView.swift
LePips Jan 7, 2025
8249bd9
Event Only on upload failures.
JPKribs Jan 8, 2025
2fd52eb
Remove unnecessary ViewModel's from tvOS.
JPKribs Jan 8, 2025
96eedc4
Add dismiss action to RemoteSearchResultView. While I am doing this h…
JPKribs Jan 8, 2025
8ce80aa
Move From Coordinator -> .Sheet. This fixes the popping issue / delay…
JPKribs Jan 8, 2025
6271497
Merge branch 'jellyfin:main' into editItemImages
JPKribs Jan 10, 2025
eb4e2fc
Merge branch 'jellyfin:main' into editItemImages
JPKribs Jan 17, 2025
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
11 changes: 11 additions & 0 deletions Shared/Coordinators/ItemEditorCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ final class ItemEditorCoordinator: ObservableObject, NavigationCoordinatable {
@Route(.modal)
var editMetadata = makeEditMetadata

// MARK: - Route to Images

@Route(.modal)
var imageEditor = makeImageEditor

// MARK: - Route to Genres

@Route(.push)
Expand Down Expand Up @@ -73,6 +78,12 @@ final class ItemEditorCoordinator: ObservableObject, NavigationCoordinatable {
}
}

// MARK: - Item Images

func makeImageEditor(viewModel: ItemImagesViewModel) -> NavigationViewCoordinator<ItemImagesCoordinator> {
NavigationViewCoordinator(ItemImagesCoordinator(viewModel: viewModel))
}

// MARK: - Item Genres

@ViewBuilder
Expand Down
69 changes: 69 additions & 0 deletions Shared/Coordinators/ItemImagesCoordinator.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//
// 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 JellyfinAPI
import Stinsen
import SwiftUI

final class ItemImagesCoordinator: ObservableObject, NavigationCoordinatable {

let stack = NavigationStack(initial: \ItemImagesCoordinator.start)

@Root
var start = makeStart

@ObservedObject
private var viewModel: ItemImagesViewModel

// MARK: - Route to Views

@Route(.push)
var addImage = makeAddImage
@Route(.modal)
var deleteImage = makeDeleteImage
@Route(.modal)
var selectImage = makeSelectImage
@Route(.modal)
var photoPicker = makePhotoPicker

// MARK: - Initializer

init(viewModel: ItemImagesViewModel) {
self._viewModel = ObservedObject(wrappedValue: viewModel)
}

// MARK: - Item Images

@ViewBuilder
func makeAddImage(imageType: ImageType) -> some View {
AddItemImageView(viewModel: viewModel, imageType: imageType)
}

func makeDeleteImage(imageInfo: (key: ImageInfo, value: UIImage)) -> NavigationViewCoordinator<BasicNavigationViewCoordinator> {
NavigationViewCoordinator {
ItemImageDetailsView(viewModel: self.viewModel, localImageInfo: imageInfo)
}
}

func makeSelectImage(remoteImageInfo: RemoteImageInfo) -> NavigationViewCoordinator<BasicNavigationViewCoordinator> {
NavigationViewCoordinator {
ItemImageDetailsView(viewModel: self.viewModel, remoteImageInfo: remoteImageInfo)
}
}

func makePhotoPicker(type: ImageType) -> NavigationViewCoordinator<ItemPhotoCoordinator> {
NavigationViewCoordinator(ItemPhotoCoordinator(viewModel: self.viewModel, type: type))
}

// MARK: - Start

@ViewBuilder
func makeStart() -> some View {
ItemImagesView(viewModel: self.viewModel)
}
}
59 changes: 59 additions & 0 deletions Shared/Coordinators/ItemPhotoCoordinator.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
//
// 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 JellyfinAPI
import Stinsen
import SwiftUI

final class ItemPhotoCoordinator: NavigationCoordinatable {

// MARK: - Navigation Components

let stack = Stinsen.NavigationStack(initial: \ItemPhotoCoordinator.start)

@Root
var start = makeStart

// MARK: - Routes

@Route(.push)
var cropImage = makeCropImage

// MARK: - Observed Object

@ObservedObject
var viewModel: ItemImagesViewModel

let type: ImageType

// MARK: - Initializer

init(viewModel: ItemImagesViewModel, type: ImageType) {
self.viewModel = viewModel
self.type = type
}

// MARK: - Views

func makeCropImage(image: UIImage) -> some View {
#if os(iOS)
ItemImagePicker.ImageCropView(viewModel: viewModel, image: image, type: type)
#else
AssertionFailureView("not implemented")
#endif
}

@ViewBuilder
func makeStart() -> some View {
#if os(iOS)
ItemImagePicker()
#else
AssertionFailureView("not implemented")
#endif
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@
//

import Foundation
import JellyfinAPI

extension Hashable {
extension ImageInfo: @retroactive Identifiable {

var hashString: String {
"\(hashValue)"
public var id: Int {
hashValue
}
}
34 changes: 34 additions & 0 deletions Shared/Extensions/JellyfinAPI/RemoteImageInfo.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// 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 Foundation
import JellyfinAPI
import SwiftUI

extension RemoteImageInfo: @retroactive Identifiable, Poster {

var displayTitle: String {
self.providerName ?? L10n.unknown
}

var unwrappedIDHashOrZero: Int {
self.id
}

var subtitle: String? {
self.language
}

var systemImage: String {
"circle"
}

public var id: Int {
self.hashValue
}
}
66 changes: 66 additions & 0 deletions Shared/Extensions/JellyfinAPI/Request.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//
// 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 Foundation
import Get

public extension Request {
/// Size of the request HTTP method in bytes
var methodSize: Int {
method.rawValue.count
}

/// Size of the request URL in bytes
var urlSize: Int {
url?.absoluteString.count ?? 0
}

/// Size of the request query parameters in bytes
var querySize: Int {
guard let query = query else { return 0 }
return query.reduce(0) { $0 + $1.0.count + ($1.1?.count ?? 0) + 2 }
}

/// Size of the request headers in bytes
var headersSize: Int {
guard let headers = headers else { return 0 }
return headers.reduce(0) { $0 + $1.key.count + $1.value.count + 4 }
}

/// Size of the request body in bytes
var bodySize: Int {
var size = 0
if let body = body {
do {
let bodyData = try JSONEncoder().encode(AnyEncodable(body))
size += bodyData.count
} catch {
size += 0
}
}
return size
}

/// Total size of the total request in bytes
var requestSize: Int {
methodSize + urlSize + querySize + headersSize + bodySize
}
}

/// A type-erased `Encodable` to encode any value conforming to `Encodable`
private struct AnyEncodable: Encodable {
private let _encode: (Encoder) throws -> Void

init<T: Encodable>(_ value: T) {
_encode = value.encode
}

func encode(to encoder: Encoder) throws {
try _encode(encoder)
}
}
8 changes: 8 additions & 0 deletions Shared/Strings/Strings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,8 @@ internal enum L10n {
}
/// 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 image
internal static let deleteImage = L10n.tr("Localizable", "deleteImage", fallback: "Delete image")
/// Are you sure you want to delete this item?
internal static let deleteItemConfirmation = L10n.tr("Localizable", "deleteItemConfirmation", fallback: "Are you sure you want to delete this item?")
/// Are you sure you want to delete this item? This action cannot be undone.
Expand Down Expand Up @@ -624,6 +626,8 @@ internal enum L10n {
internal static let idle = L10n.tr("Localizable", "idle", fallback: "Idle")
/// Illustrator
internal static let illustrator = L10n.tr("Localizable", "illustrator", fallback: "Illustrator")
/// Images
internal static let images = L10n.tr("Localizable", "images", fallback: "Images")
/// Indicators
internal static let indicators = L10n.tr("Localizable", "indicators", fallback: "Indicators")
/// Inker
Expand Down Expand Up @@ -1320,6 +1324,10 @@ internal enum L10n {
internal static let unreleased = L10n.tr("Localizable", "unreleased", fallback: "Unreleased")
/// You have unsaved changes. Are you sure you want to discard them?
internal static let unsavedChangesMessage = L10n.tr("Localizable", "unsavedChangesMessage", fallback: "You have unsaved changes. Are you sure you want to discard them?")
/// Upload file
internal static let uploadFile = L10n.tr("Localizable", "uploadFile", fallback: "Upload file")
/// Upload photo
internal static let uploadPhoto = L10n.tr("Localizable", "uploadPhoto", fallback: "Upload photo")
/// URL
internal static let url = L10n.tr("Localizable", "url", fallback: "URL")
/// Use as Transcoding Profile
Expand Down
Loading