refactor filters system
add LibraryFilterViewModel some func name lowercased
This commit is contained in:
parent
f8a70051ac
commit
39a5b6a2e7
|
@ -131,6 +131,8 @@
|
||||||
62E632EA267D3FF50063E547 /* SeasonItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E632E8267D3FF50063E547 /* SeasonItemViewModel.swift */; };
|
62E632EA267D3FF50063E547 /* SeasonItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E632E8267D3FF50063E547 /* SeasonItemViewModel.swift */; };
|
||||||
62E632EC267D410B0063E547 /* SeriesItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E632EB267D410B0063E547 /* SeriesItemViewModel.swift */; };
|
62E632EC267D410B0063E547 /* SeriesItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E632EB267D410B0063E547 /* SeriesItemViewModel.swift */; };
|
||||||
62E632ED267D410B0063E547 /* SeriesItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E632EB267D410B0063E547 /* SeriesItemViewModel.swift */; };
|
62E632ED267D410B0063E547 /* SeriesItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E632EB267D410B0063E547 /* SeriesItemViewModel.swift */; };
|
||||||
|
62E632EF267D43320063E547 /* LibraryFilterViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E632EE267D43320063E547 /* LibraryFilterViewModel.swift */; };
|
||||||
|
62E632F0267D43320063E547 /* LibraryFilterViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E632EE267D43320063E547 /* LibraryFilterViewModel.swift */; };
|
||||||
62EC3527267665D8000E9F2D /* MobileVLCKit.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53D5E3DC264B47EE00BADDC8 /* MobileVLCKit.xcframework */; };
|
62EC3527267665D8000E9F2D /* MobileVLCKit.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53D5E3DC264B47EE00BADDC8 /* MobileVLCKit.xcframework */; };
|
||||||
62EC3528267665D8000E9F2D /* MobileVLCKit.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 53D5E3DC264B47EE00BADDC8 /* MobileVLCKit.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
62EC3528267665D8000E9F2D /* MobileVLCKit.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 53D5E3DC264B47EE00BADDC8 /* MobileVLCKit.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||||
62EC352C26766675000E9F2D /* ServerEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62EC352B26766675000E9F2D /* ServerEnvironment.swift */; };
|
62EC352C26766675000E9F2D /* ServerEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62EC352B26766675000E9F2D /* ServerEnvironment.swift */; };
|
||||||
|
@ -286,6 +288,7 @@
|
||||||
62E632E5267D3F5B0063E547 /* EpisodeItemViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EpisodeItemViewModel.swift; sourceTree = "<group>"; };
|
62E632E5267D3F5B0063E547 /* EpisodeItemViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EpisodeItemViewModel.swift; sourceTree = "<group>"; };
|
||||||
62E632E8267D3FF50063E547 /* SeasonItemViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeasonItemViewModel.swift; sourceTree = "<group>"; };
|
62E632E8267D3FF50063E547 /* SeasonItemViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeasonItemViewModel.swift; sourceTree = "<group>"; };
|
||||||
62E632EB267D410B0063E547 /* SeriesItemViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SeriesItemViewModel.swift; sourceTree = "<group>"; };
|
62E632EB267D410B0063E547 /* SeriesItemViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SeriesItemViewModel.swift; sourceTree = "<group>"; };
|
||||||
|
62E632EE267D43320063E547 /* LibraryFilterViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryFilterViewModel.swift; sourceTree = "<group>"; };
|
||||||
62EC352B26766675000E9F2D /* ServerEnvironment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerEnvironment.swift; sourceTree = "<group>"; };
|
62EC352B26766675000E9F2D /* ServerEnvironment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerEnvironment.swift; sourceTree = "<group>"; };
|
||||||
62EC352E267666A5000E9F2D /* SessionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionManager.swift; sourceTree = "<group>"; };
|
62EC352E267666A5000E9F2D /* SessionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionManager.swift; sourceTree = "<group>"; };
|
||||||
62EC353326766B03000E9F2D /* DeviceRotationViewModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceRotationViewModifier.swift; sourceTree = "<group>"; };
|
62EC353326766B03000E9F2D /* DeviceRotationViewModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceRotationViewModifier.swift; sourceTree = "<group>"; };
|
||||||
|
@ -354,6 +357,7 @@
|
||||||
62E632E5267D3F5B0063E547 /* EpisodeItemViewModel.swift */,
|
62E632E5267D3F5B0063E547 /* EpisodeItemViewModel.swift */,
|
||||||
62E632E8267D3FF50063E547 /* SeasonItemViewModel.swift */,
|
62E632E8267D3FF50063E547 /* SeasonItemViewModel.swift */,
|
||||||
62E632EB267D410B0063E547 /* SeriesItemViewModel.swift */,
|
62E632EB267D410B0063E547 /* SeriesItemViewModel.swift */,
|
||||||
|
62E632EE267D43320063E547 /* LibraryFilterViewModel.swift */,
|
||||||
);
|
);
|
||||||
path = ViewModels;
|
path = ViewModels;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -730,6 +734,7 @@
|
||||||
62E632E1267D30CA0063E547 /* LibraryViewModel.swift in Sources */,
|
62E632E1267D30CA0063E547 /* LibraryViewModel.swift in Sources */,
|
||||||
535870A82669D8AE00D05A09 /* StringExtensions.swift in Sources */,
|
535870A82669D8AE00D05A09 /* StringExtensions.swift in Sources */,
|
||||||
62E632ED267D410B0063E547 /* SeriesItemViewModel.swift in Sources */,
|
62E632ED267D410B0063E547 /* SeriesItemViewModel.swift in Sources */,
|
||||||
|
62E632F0267D43320063E547 /* LibraryFilterViewModel.swift in Sources */,
|
||||||
53ABFDE6267974EF00886593 /* SettingsViewModel.swift in Sources */,
|
53ABFDE6267974EF00886593 /* SettingsViewModel.swift in Sources */,
|
||||||
6267B3D826710B9800A7371D /* CollectionExtensions.swift in Sources */,
|
6267B3D826710B9800A7371D /* CollectionExtensions.swift in Sources */,
|
||||||
62E632E7267D3F5B0063E547 /* EpisodeItemViewModel.swift in Sources */,
|
62E632E7267D3F5B0063E547 /* EpisodeItemViewModel.swift in Sources */,
|
||||||
|
@ -800,6 +805,7 @@
|
||||||
62E632E0267D30CA0063E547 /* LibraryViewModel.swift in Sources */,
|
62E632E0267D30CA0063E547 /* LibraryViewModel.swift in Sources */,
|
||||||
62EC352F267666A5000E9F2D /* SessionManager.swift in Sources */,
|
62EC352F267666A5000E9F2D /* SessionManager.swift in Sources */,
|
||||||
62E632E3267D3BA60063E547 /* MovieItemViewModel.swift in Sources */,
|
62E632E3267D3BA60063E547 /* MovieItemViewModel.swift in Sources */,
|
||||||
|
62E632EF267D43320063E547 /* LibraryFilterViewModel.swift in Sources */,
|
||||||
535870AD2669D8DD00D05A09 /* Typings.swift in Sources */,
|
535870AD2669D8DD00D05A09 /* Typings.swift in Sources */,
|
||||||
62EC352C26766675000E9F2D /* ServerEnvironment.swift in Sources */,
|
62EC352C26766675000E9F2D /* ServerEnvironment.swift in Sources */,
|
||||||
6267B3DA2671138200A7371D /* ImageExtensions.swift in Sources */,
|
6267B3DA2671138200A7371D /* ImageExtensions.swift in Sources */,
|
||||||
|
|
|
@ -5,75 +5,80 @@
|
||||||
* Copyright 2021 Aiden Vigue & Jellyfin Contributors
|
* Copyright 2021 Aiden Vigue & Jellyfin Contributors
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
import JellyfinAPI
|
import JellyfinAPI
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
struct LibraryFilterView: View {
|
struct LibraryFilterView: View {
|
||||||
@Binding var filter: LibraryFilters
|
@Environment(\.presentationMode)
|
||||||
|
var presentationMode
|
||||||
|
@Binding
|
||||||
|
var filters: LibraryFilters
|
||||||
|
|
||||||
|
@StateObject
|
||||||
|
var viewModel: LibraryFilterViewModel
|
||||||
|
|
||||||
|
init(filters: Binding<LibraryFilters>, enabledFilterType: [FilterType]) {
|
||||||
|
_filters = filters
|
||||||
|
_viewModel = StateObject(wrappedValue: .init(filters: filters.wrappedValue, enabledFilterType: enabledFilterType))
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
EmptyView()
|
|
||||||
/*
|
|
||||||
NavigationView {
|
NavigationView {
|
||||||
LoadingView(isShowing: $isLoading) {
|
ZStack {
|
||||||
Form {
|
Form {
|
||||||
Toggle("Only show unplayed items", isOn: $onlyUnplayed)
|
if viewModel.enabledFilterType.contains(.genre) {
|
||||||
.onChange(of: onlyUnplayed) { value in
|
|
||||||
if value {
|
|
||||||
filter.filterTypes.append(.isUnplayed)
|
|
||||||
} else {
|
|
||||||
filter.filterTypes.removeAll { $0 == .isUnplayed }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MultiSelector(label: "Genres",
|
MultiSelector(label: "Genres",
|
||||||
options: allGenres,
|
options: viewModel.allGenres,
|
||||||
optionToString: { $0.name },
|
optionToString: { $0.name ?? "" },
|
||||||
selected: $selectedGenres)
|
selected: $viewModel.modifyedFilters.withGenres)
|
||||||
.onChange(of: selectedGenres) { genres in
|
|
||||||
filter.genres = genres.map(\.id)
|
|
||||||
}
|
}
|
||||||
MultiSelector(label: "Parental Ratings",
|
if viewModel.enabledFilterType.contains(.filter) {
|
||||||
options: allRatings,
|
MultiSelector(label: "Filters",
|
||||||
optionToString: { $0.name },
|
options: viewModel.allItemFilters,
|
||||||
selected: $selectedRatings)
|
optionToString: { $0.localized },
|
||||||
.onChange(of: selectedRatings) { ratings in
|
selected: $viewModel.modifyedFilters.filters)
|
||||||
filter.officialRatings = ratings.map(\.id)
|
|
||||||
}
|
}
|
||||||
|
if viewModel.enabledFilterType.contains(.tag) {
|
||||||
Section(header: Text("Sort settings")) {
|
MultiSelector(label: "Tags",
|
||||||
Picker("Sort by", selection: $sortBySelection) {
|
options: viewModel.allTags,
|
||||||
Text("Name").tag("SortName")
|
optionToString: { $0 },
|
||||||
Text("Date Added").tag("DateCreated")
|
selected: $viewModel.modifyedFilters.tags)
|
||||||
Text("Date Played").tag("DatePlayed")
|
|
||||||
Text("Date Released").tag("PremiereDate")
|
|
||||||
Text("Runtime").tag("Runtime")
|
|
||||||
}.onChange(of: sortBySelection) { value in
|
|
||||||
guard let sort = SortType(rawValue: value) else { return }
|
|
||||||
filter.sort = sort
|
|
||||||
}
|
}
|
||||||
Picker("Sort order", selection: $sortOrder) {
|
if viewModel.enabledFilterType.contains(.sortBy) {
|
||||||
Text("Ascending").tag("Ascending")
|
MultiSelector(label: "Sort by",
|
||||||
Text("Descending").tag("Descending")
|
options: viewModel.allSortBys,
|
||||||
}.onChange(of: sortOrder) { order in
|
optionToString: { $0.localized },
|
||||||
guard let asc = ASC(rawValue: order) else { return }
|
selected: $viewModel.modifyedFilters.sortBy)
|
||||||
filter.asc = asc
|
}
|
||||||
|
if viewModel.enabledFilterType.contains(.sortOrder) {
|
||||||
|
MultiSelector(label: "Sort Order",
|
||||||
|
options: viewModel.allSortOrders,
|
||||||
|
optionToString: { $0.localized },
|
||||||
|
selected: $viewModel.modifyedFilters.sortOrder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if viewModel.isLoading {
|
||||||
|
ProgressView()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}.onAppear(perform: onAppear)
|
|
||||||
.navigationBarTitle("Filters", displayMode: .inline)
|
.navigationBarTitle("Filters", displayMode: .inline)
|
||||||
.toolbar {
|
.toolbar {
|
||||||
ToolbarItemGroup(placement: .navigationBarLeading) {
|
ToolbarItemGroup(placement: .navigationBarLeading) {
|
||||||
Button {
|
Button {
|
||||||
presentationMode.wrappedValue.dismiss()
|
presentationMode.wrappedValue.dismiss()
|
||||||
} label: {
|
} label: {
|
||||||
HStack {
|
Image(systemName: "xmark")
|
||||||
Text("Back").font(.callout)
|
}
|
||||||
|
}
|
||||||
|
ToolbarItemGroup(placement: .navigationBarTrailing) {
|
||||||
|
Button {
|
||||||
|
self.filters = viewModel.modifyedFilters
|
||||||
|
presentationMode.wrappedValue.dismiss()
|
||||||
|
} label: {
|
||||||
|
Text("Apply")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,8 @@ struct LibraryView: View {
|
||||||
|
|
||||||
@State
|
@State
|
||||||
var isShowingSearchView = false
|
var isShowingSearchView = false
|
||||||
|
@State
|
||||||
|
var isShowingFilterView = false
|
||||||
|
|
||||||
@State
|
@State
|
||||||
private var tracks: [GridItem] = Array(repeating: .init(.flexible()), count: Int(UIScreen.main.bounds.size.width) / 125)
|
private var tracks: [GridItem] = Array(repeating: .init(.flexible()), count: Int(UIScreen.main.bounds.size.width) / 125)
|
||||||
|
@ -109,6 +111,11 @@ struct LibraryView: View {
|
||||||
Image(systemName: "chevron.right")
|
Image(systemName: "chevron.right")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Button(action: {
|
||||||
|
isShowingFilterView = true
|
||||||
|
}) {
|
||||||
|
Image(systemName: "line.horizontal.3.decrease.circle")
|
||||||
|
}
|
||||||
Button(action: {
|
Button(action: {
|
||||||
isShowingSearchView = true
|
isShowingSearchView = true
|
||||||
}) {
|
}) {
|
||||||
|
@ -116,6 +123,9 @@ struct LibraryView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.sheet(isPresented: $isShowingFilterView) {
|
||||||
|
LibraryFilterView(filters: $viewModel.filters, enabledFilterType: viewModel.enabledFilterType)
|
||||||
|
}
|
||||||
.background(
|
.background(
|
||||||
NavigationLink(destination: LibrarySearchView(viewModel: .init(parentID: viewModel.parentID)),
|
NavigationLink(destination: LibrarySearchView(viewModel: .init(parentID: viewModel.parentID)),
|
||||||
isActive: $isShowingSearchView) {
|
isActive: $isShowingSearchView) {
|
||||||
|
|
|
@ -7,44 +7,44 @@
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
private struct MultiSelectionView<Selectable: Identifiable & Hashable>: View {
|
private struct MultiSelectionView<Selectable: Hashable>: View {
|
||||||
let options: [Selectable]
|
let options: [Selectable]
|
||||||
let optionToString: (Selectable) -> String
|
let optionToString: (Selectable) -> String
|
||||||
let label: String
|
let label: String
|
||||||
|
|
||||||
@Binding var selected: Set<Selectable>
|
@Binding var selected: Array<Selectable>
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
List {
|
List {
|
||||||
ForEach(options) { selectable in
|
ForEach(options, id: \.self) { selectable in
|
||||||
Button(action: { toggleSelection(selectable: selectable) }) {
|
Button(action: { toggleSelection(selectable: selectable) }) {
|
||||||
HStack {
|
HStack {
|
||||||
Text(optionToString(selectable)).foregroundColor(Color.primary)
|
Text(optionToString(selectable)).foregroundColor(Color.primary)
|
||||||
Spacer()
|
Spacer()
|
||||||
if selected.contains { $0.id == selectable.id } {
|
if selected.contains { $0 == selectable } {
|
||||||
Image(systemName: "checkmark").foregroundColor(.accentColor)
|
Image(systemName: "checkmark").foregroundColor(.accentColor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.tag(selectable.id)
|
}.tag(selectable)
|
||||||
}
|
}
|
||||||
}.listStyle(GroupedListStyle())
|
}.listStyle(GroupedListStyle())
|
||||||
}
|
}
|
||||||
|
|
||||||
private func toggleSelection(selectable: Selectable) {
|
private func toggleSelection(selectable: Selectable) {
|
||||||
if let existingIndex = selected.firstIndex(where: { $0.id == selectable.id }) {
|
if let existingIndex = selected.firstIndex(where: { $0 == selectable }) {
|
||||||
selected.remove(at: existingIndex)
|
selected.remove(at: existingIndex)
|
||||||
} else {
|
} else {
|
||||||
selected.insert(selectable)
|
selected.append(selectable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MultiSelector<Selectable: Identifiable & Hashable>: View {
|
struct MultiSelector<Selectable: Hashable>: View {
|
||||||
let label: String
|
let label: String
|
||||||
let options: [Selectable]
|
let options: [Selectable]
|
||||||
let optionToString: (Selectable) -> String
|
let optionToString: (Selectable) -> String
|
||||||
|
|
||||||
var selected: Binding<Set<Selectable>>
|
var selected: Binding<Array<Selectable>>
|
||||||
|
|
||||||
private var formattedSelectedListString: String {
|
private var formattedSelectedListString: String {
|
||||||
ListFormatter.localizedString(byJoining: selected.wrappedValue.map { optionToString($0) })
|
ListFormatter.localizedString(byJoining: selected.wrappedValue.map { optionToString($0) })
|
||||||
|
|
|
@ -5,15 +5,16 @@
|
||||||
* Copyright 2021 Aiden Vigue & Jellyfin Contributors
|
* Copyright 2021 Aiden Vigue & Jellyfin Contributors
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import Combine
|
import Combine
|
||||||
|
import Foundation
|
||||||
import JellyfinAPI
|
import JellyfinAPI
|
||||||
|
|
||||||
struct LibraryFilters: Codable, Hashable {
|
struct LibraryFilters: Codable, Hashable {
|
||||||
var filters: [ItemFilter] = []
|
var filters: [ItemFilter] = []
|
||||||
var sortOrder: [APISortOrder] = [.descending]
|
var sortOrder: [APISortOrder] = [.descending]
|
||||||
var withGenres: [NameGuidPair] = []
|
var withGenres: [NameGuidPair] = []
|
||||||
var sortBy: [String] = ["SortName"]
|
var tags: [String] = []
|
||||||
|
var sortBy: [SortBy] = [.name]
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum SortBy: String, Codable, CaseIterable {
|
public enum SortBy: String, Codable, CaseIterable {
|
||||||
|
@ -22,3 +23,54 @@ public enum SortBy: String, Codable, CaseIterable {
|
||||||
case name = "SortName"
|
case name = "SortName"
|
||||||
case dateAdded = "DateCreated"
|
case dateAdded = "DateCreated"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension SortBy {
|
||||||
|
var localized: String {
|
||||||
|
switch self {
|
||||||
|
case .productionYear:
|
||||||
|
return "Production year"
|
||||||
|
case .premiereDate:
|
||||||
|
return "Premiere date"
|
||||||
|
case .name:
|
||||||
|
return "Name"
|
||||||
|
case .dateAdded:
|
||||||
|
return "Date created"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ItemFilter {
|
||||||
|
var localized: String {
|
||||||
|
switch self {
|
||||||
|
case .isFolder:
|
||||||
|
return "Is folder"
|
||||||
|
case .isNotFolder:
|
||||||
|
return "Is not folder"
|
||||||
|
case .isUnplayed:
|
||||||
|
return "Is unplayed"
|
||||||
|
case .isPlayed:
|
||||||
|
return "Is played"
|
||||||
|
case .isFavorite:
|
||||||
|
return "Is favorite"
|
||||||
|
case .isResumable:
|
||||||
|
return "Is resumable"
|
||||||
|
case .likes:
|
||||||
|
return "Likes"
|
||||||
|
case .dislikes:
|
||||||
|
return "Dislikes"
|
||||||
|
case .isFavoriteOrLikes:
|
||||||
|
return "Is favorite or likes"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension APISortOrder {
|
||||||
|
var localized: String {
|
||||||
|
switch self {
|
||||||
|
case .ascending:
|
||||||
|
return "Ascending"
|
||||||
|
case .descending:
|
||||||
|
return "Descending"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ final class ConnectToServerViewModel: ViewModel {
|
||||||
if ServerEnvironment.current.server != nil {
|
if ServerEnvironment.current.server != nil {
|
||||||
UserAPI.getPublicUsers()
|
UserAPI.getPublicUsers()
|
||||||
.sink(receiveCompletion: { completion in
|
.sink(receiveCompletion: { completion in
|
||||||
self.HandleAPIRequestCompletion(completion: completion)
|
self.handleAPIRequestCompletion(completion: completion)
|
||||||
}, receiveValue: { response in
|
}, receiveValue: { response in
|
||||||
self.publicUsers = response
|
self.publicUsers = response
|
||||||
self.isConnectedServer = true
|
self.isConnectedServer = true
|
||||||
|
@ -74,7 +74,7 @@ final class ConnectToServerViewModel: ViewModel {
|
||||||
func login() {
|
func login() {
|
||||||
SessionManager.current.login(username: username, password: password)
|
SessionManager.current.login(username: username, password: password)
|
||||||
.sink(receiveCompletion: { completion in
|
.sink(receiveCompletion: { completion in
|
||||||
self.HandleAPIRequestCompletion(completion: completion)
|
self.handleAPIRequestCompletion(completion: completion)
|
||||||
}, receiveValue: { _ in
|
}, receiveValue: { _ in
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
|
@ -33,7 +33,7 @@ final class EpisodeItemViewModel: ViewModel {
|
||||||
PlaystateAPI.markUnplayedItem(userId: SessionManager.current.user.user_id!, itemId: id)
|
PlaystateAPI.markUnplayedItem(userId: SessionManager.current.user.user_id!, itemId: id)
|
||||||
.trackActivity(loading)
|
.trackActivity(loading)
|
||||||
.sink(receiveCompletion: { [weak self] completion in
|
.sink(receiveCompletion: { [weak self] completion in
|
||||||
self?.HandleAPIRequestCompletion(completion: completion)
|
self?.handleAPIRequestCompletion(completion: completion)
|
||||||
}, receiveValue: { [weak self] _ in
|
}, receiveValue: { [weak self] _ in
|
||||||
self?.isWatched = false
|
self?.isWatched = false
|
||||||
})
|
})
|
||||||
|
@ -42,7 +42,7 @@ final class EpisodeItemViewModel: ViewModel {
|
||||||
PlaystateAPI.markPlayedItem(userId: SessionManager.current.user.user_id!, itemId: id)
|
PlaystateAPI.markPlayedItem(userId: SessionManager.current.user.user_id!, itemId: id)
|
||||||
.trackActivity(loading)
|
.trackActivity(loading)
|
||||||
.sink(receiveCompletion: { [weak self] completion in
|
.sink(receiveCompletion: { [weak self] completion in
|
||||||
self?.HandleAPIRequestCompletion(completion: completion)
|
self?.handleAPIRequestCompletion(completion: completion)
|
||||||
}, receiveValue: { [weak self] _ in
|
}, receiveValue: { [weak self] _ in
|
||||||
self?.isWatched = true
|
self?.isWatched = true
|
||||||
})
|
})
|
||||||
|
@ -56,7 +56,7 @@ final class EpisodeItemViewModel: ViewModel {
|
||||||
UserLibraryAPI.unmarkFavoriteItem(userId: SessionManager.current.user.user_id!, itemId: id)
|
UserLibraryAPI.unmarkFavoriteItem(userId: SessionManager.current.user.user_id!, itemId: id)
|
||||||
.trackActivity(loading)
|
.trackActivity(loading)
|
||||||
.sink(receiveCompletion: { [weak self] completion in
|
.sink(receiveCompletion: { [weak self] completion in
|
||||||
self?.HandleAPIRequestCompletion(completion: completion)
|
self?.handleAPIRequestCompletion(completion: completion)
|
||||||
}, receiveValue: { [weak self] _ in
|
}, receiveValue: { [weak self] _ in
|
||||||
self?.isFavorited = false
|
self?.isFavorited = false
|
||||||
})
|
})
|
||||||
|
@ -65,7 +65,7 @@ final class EpisodeItemViewModel: ViewModel {
|
||||||
UserLibraryAPI.markFavoriteItem(userId: SessionManager.current.user.user_id!, itemId: id)
|
UserLibraryAPI.markFavoriteItem(userId: SessionManager.current.user.user_id!, itemId: id)
|
||||||
.trackActivity(loading)
|
.trackActivity(loading)
|
||||||
.sink(receiveCompletion: { [weak self] completion in
|
.sink(receiveCompletion: { [weak self] completion in
|
||||||
self?.HandleAPIRequestCompletion(completion: completion)
|
self?.handleAPIRequestCompletion(completion: completion)
|
||||||
}, receiveValue: { [weak self] _ in
|
}, receiveValue: { [weak self] _ in
|
||||||
self?.isFavorited = true
|
self?.isFavorited = true
|
||||||
})
|
})
|
||||||
|
|
|
@ -24,7 +24,7 @@ final class HomeViewModel: ViewModel {
|
||||||
var nextUpItems = [BaseItemDto]()
|
var nextUpItems = [BaseItemDto]()
|
||||||
|
|
||||||
// temp
|
// temp
|
||||||
var recentFilterSet: LibraryFilters = LibraryFilters(filters: [], sortOrder: [.descending], sortBy: ["DateCreated"])
|
var recentFilterSet: LibraryFilters = LibraryFilters(filters: [], sortOrder: [.descending], sortBy: [.dateAdded])
|
||||||
|
|
||||||
override init() {
|
override init() {
|
||||||
super.init()
|
super.init()
|
||||||
|
@ -36,7 +36,7 @@ final class HomeViewModel: ViewModel {
|
||||||
UserViewsAPI.getUserViews(userId: SessionManager.current.user.user_id!)
|
UserViewsAPI.getUserViews(userId: SessionManager.current.user.user_id!)
|
||||||
.trackActivity(loading)
|
.trackActivity(loading)
|
||||||
.sink(receiveCompletion: { completion in
|
.sink(receiveCompletion: { completion in
|
||||||
self.HandleAPIRequestCompletion(completion: completion)
|
self.handleAPIRequestCompletion(completion: completion)
|
||||||
}, receiveValue: { response in
|
}, receiveValue: { response in
|
||||||
response.items!.forEach { item in
|
response.items!.forEach { item in
|
||||||
if item.collectionType == "movies" || item.collectionType == "tvshows" {
|
if item.collectionType == "movies" || item.collectionType == "tvshows" {
|
||||||
|
@ -47,7 +47,7 @@ final class HomeViewModel: ViewModel {
|
||||||
UserAPI.getCurrentUser()
|
UserAPI.getCurrentUser()
|
||||||
.trackActivity(self.loading)
|
.trackActivity(self.loading)
|
||||||
.sink(receiveCompletion: { completion in
|
.sink(receiveCompletion: { completion in
|
||||||
self.HandleAPIRequestCompletion(completion: completion)
|
self.handleAPIRequestCompletion(completion: completion)
|
||||||
}, receiveValue: { response in
|
}, receiveValue: { response in
|
||||||
self.libraries.forEach { library in
|
self.libraries.forEach { library in
|
||||||
if !(response.configuration?.latestItemsExcludes?.contains(library.id!))! {
|
if !(response.configuration?.latestItemsExcludes?.contains(library.id!))! {
|
||||||
|
@ -64,7 +64,7 @@ final class HomeViewModel: ViewModel {
|
||||||
mediaTypes: ["Video"], imageTypeLimit: 1, enableImageTypes: [.primary, .backdrop, .thumb])
|
mediaTypes: ["Video"], imageTypeLimit: 1, enableImageTypes: [.primary, .backdrop, .thumb])
|
||||||
.trackActivity(loading)
|
.trackActivity(loading)
|
||||||
.sink(receiveCompletion: { completion in
|
.sink(receiveCompletion: { completion in
|
||||||
self.HandleAPIRequestCompletion(completion: completion)
|
self.handleAPIRequestCompletion(completion: completion)
|
||||||
}, receiveValue: { response in
|
}, receiveValue: { response in
|
||||||
self.resumeItems = response.items ?? []
|
self.resumeItems = response.items ?? []
|
||||||
})
|
})
|
||||||
|
@ -74,7 +74,7 @@ final class HomeViewModel: ViewModel {
|
||||||
fields: [.primaryImageAspectRatio, .seriesPrimaryImage, .seasonUserData, .overview, .genres, .people])
|
fields: [.primaryImageAspectRatio, .seriesPrimaryImage, .seasonUserData, .overview, .genres, .people])
|
||||||
.trackActivity(loading)
|
.trackActivity(loading)
|
||||||
.sink(receiveCompletion: { completion in
|
.sink(receiveCompletion: { completion in
|
||||||
self.HandleAPIRequestCompletion(completion: completion)
|
self.handleAPIRequestCompletion(completion: completion)
|
||||||
}, receiveValue: { response in
|
}, receiveValue: { response in
|
||||||
self.nextUpItems = response.items ?? []
|
self.nextUpItems = response.items ?? []
|
||||||
})
|
})
|
||||||
|
|
|
@ -37,7 +37,7 @@ final class LatestMediaViewModel: ViewModel {
|
||||||
enableUserData: true, limit: 12)
|
enableUserData: true, limit: 12)
|
||||||
.trackActivity(loading)
|
.trackActivity(loading)
|
||||||
.sink(receiveCompletion: { [weak self] completion in
|
.sink(receiveCompletion: { [weak self] completion in
|
||||||
self?.HandleAPIRequestCompletion(completion: completion)
|
self?.handleAPIRequestCompletion(completion: completion)
|
||||||
}, receiveValue: { [weak self] response in
|
}, receiveValue: { [weak self] response in
|
||||||
self?.items = response
|
self?.items = response
|
||||||
})
|
})
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* 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 2021 Aiden Vigue & Jellyfin Contributors
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Combine
|
||||||
|
import Foundation
|
||||||
|
import JellyfinAPI
|
||||||
|
|
||||||
|
enum FilterType {
|
||||||
|
case tag
|
||||||
|
case genre
|
||||||
|
case sortOrder
|
||||||
|
case sortBy
|
||||||
|
case filter
|
||||||
|
}
|
||||||
|
|
||||||
|
final class LibraryFilterViewModel: ViewModel {
|
||||||
|
@Published
|
||||||
|
var modifyedFilters = LibraryFilters()
|
||||||
|
|
||||||
|
@Published
|
||||||
|
var allGenres = [NameGuidPair]()
|
||||||
|
@Published
|
||||||
|
var allTags = [String]()
|
||||||
|
@Published
|
||||||
|
var allSortOrders = APISortOrder.allCases
|
||||||
|
@Published
|
||||||
|
var allSortBys = SortBy.allCases
|
||||||
|
@Published
|
||||||
|
var allItemFilters = ItemFilter.allCases
|
||||||
|
@Published
|
||||||
|
var enabledFilterType: [FilterType]
|
||||||
|
|
||||||
|
init(filters: LibraryFilters? = nil,
|
||||||
|
enabledFilterType: [FilterType] = [.tag, .genre, .sortBy, .sortOrder, .filter]) {
|
||||||
|
self.enabledFilterType = enabledFilterType
|
||||||
|
super.init()
|
||||||
|
if let filters = filters {
|
||||||
|
self.modifyedFilters = filters
|
||||||
|
}
|
||||||
|
refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
func refresh() {
|
||||||
|
FilterAPI.getQueryFilters(userId: SessionManager.current.user.user_id!)
|
||||||
|
.trackActivity(loading)
|
||||||
|
.sink(receiveCompletion: { [weak self] completion in
|
||||||
|
self?.handleAPIRequestCompletion(completion: completion)
|
||||||
|
}, receiveValue: { [weak self] quertFilters in
|
||||||
|
guard let self = self else { return }
|
||||||
|
self.allGenres = quertFilters.genres ?? []
|
||||||
|
self.allTags = quertFilters.tags ?? []
|
||||||
|
})
|
||||||
|
.store(in: &cancellables)
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,7 +29,7 @@ final class LibraryListViewModel: ViewModel {
|
||||||
UserViewsAPI.getUserViews(userId: SessionManager.current.user.user_id!)
|
UserViewsAPI.getUserViews(userId: SessionManager.current.user.user_id!)
|
||||||
.trackActivity(loading)
|
.trackActivity(loading)
|
||||||
.sink(receiveCompletion: { completion in
|
.sink(receiveCompletion: { completion in
|
||||||
self.HandleAPIRequestCompletion(completion: completion)
|
self.handleAPIRequestCompletion(completion: completion)
|
||||||
}, receiveValue: { response in
|
}, receiveValue: { response in
|
||||||
self.libraries.append(contentsOf: response.items ?? [])
|
self.libraries.append(contentsOf: response.items ?? [])
|
||||||
})
|
})
|
||||||
|
|
|
@ -36,7 +36,7 @@ final class LibrarySearchViewModel: ViewModel {
|
||||||
includeItemTypes: ["Movie", "Series"], sortBy: ["SortName"], enableUserData: true, enableImages: true)
|
includeItemTypes: ["Movie", "Series"], sortBy: ["SortName"], enableUserData: true, enableImages: true)
|
||||||
.trackActivity(loading)
|
.trackActivity(loading)
|
||||||
.sink(receiveCompletion: { [weak self] completion in
|
.sink(receiveCompletion: { [weak self] completion in
|
||||||
self?.HandleAPIRequestCompletion(completion: completion)
|
self?.handleAPIRequestCompletion(completion: completion)
|
||||||
}, receiveValue: { [weak self] response in
|
}, receiveValue: { [weak self] response in
|
||||||
self?.items = response.items ?? []
|
self?.items = response.items ?? []
|
||||||
})
|
})
|
||||||
|
|
|
@ -30,13 +30,22 @@ final class LibraryViewModel: ViewModel {
|
||||||
var isCanPreviousPaging = false
|
var isCanPreviousPaging = false
|
||||||
|
|
||||||
// temp
|
// temp
|
||||||
|
@Published
|
||||||
var filters: LibraryFilters
|
var filters: LibraryFilters
|
||||||
|
|
||||||
|
var enabledFilterType: [FilterType] {
|
||||||
|
if genre == nil {
|
||||||
|
return [.tag, .genre, .sortBy, .sortOrder, .filter]
|
||||||
|
} else {
|
||||||
|
return [.tag, .sortBy, .sortOrder, .filter]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
init(parentID: String? = nil,
|
init(parentID: String? = nil,
|
||||||
person: BaseItemPerson? = nil,
|
person: BaseItemPerson? = nil,
|
||||||
genre: NameGuidPair? = nil,
|
genre: NameGuidPair? = nil,
|
||||||
studio: NameGuidPair? = nil,
|
studio: NameGuidPair? = nil,
|
||||||
filters: LibraryFilters = LibraryFilters(filters: [], sortOrder: [.ascending], withGenres: [], sortBy: ["SortName"]))
|
filters: LibraryFilters = LibraryFilters(filters: [], sortOrder: [.ascending], withGenres: [], sortBy: [.name]))
|
||||||
{
|
{
|
||||||
self.parentID = parentID
|
self.parentID = parentID
|
||||||
self.person = person
|
self.person = person
|
||||||
|
@ -45,18 +54,30 @@ final class LibraryViewModel: ViewModel {
|
||||||
self.filters = filters
|
self.filters = filters
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
refresh()
|
$filters
|
||||||
|
.sink(receiveValue: refresh(with:))
|
||||||
|
.store(in: &cancellables)
|
||||||
}
|
}
|
||||||
|
|
||||||
func refresh() {
|
func refresh(with filters: LibraryFilters) {
|
||||||
let personIDs: [String] = [person].compactMap(\.?.id)
|
let personIDs: [String] = [person].compactMap(\.?.id)
|
||||||
let studioIDs: [String] = [studio].compactMap(\.?.id)
|
let studioIDs: [String] = [studio].compactMap(\.?.id)
|
||||||
let genreIDs: [String] = [genre].compactMap(\.?.id)
|
let genreIDs: [String]
|
||||||
|
if filters.withGenres.isEmpty {
|
||||||
|
genreIDs = [genre].compactMap(\.?.id)
|
||||||
|
} else {
|
||||||
|
genreIDs = filters.withGenres.compactMap(\.id)
|
||||||
|
}
|
||||||
|
let sortBy = filters.sortBy.map(\.rawValue)
|
||||||
|
|
||||||
ItemsAPI.getItemsByUserId(userId: SessionManager.current.user.user_id!, startIndex: currentPage * 100, limit: 100, recursive: true, searchTerm: nil, sortOrder: filters.sortOrder, parentId: parentID, fields: [.primaryImageAspectRatio, .seriesPrimaryImage, .seasonUserData, .overview, .genres, .people], includeItemTypes: ["Movie", "Series"], filters: filters.filters, sortBy: filters.sortBy, enableUserData: true, personIds: personIDs, studioIds: studioIDs, genreIds: genreIDs, enableImages: true)
|
ItemsAPI.getItemsByUserId(userId: SessionManager.current.user.user_id!, startIndex: currentPage * 100, limit: 100, recursive: true,
|
||||||
|
searchTerm: nil, sortOrder: filters.sortOrder, parentId: parentID,
|
||||||
|
fields: [.primaryImageAspectRatio, .seriesPrimaryImage, .seasonUserData, .overview, .genres, .people],
|
||||||
|
includeItemTypes: ["Movie", "Series"], filters: filters.filters, sortBy: sortBy, tags: filters.tags,
|
||||||
|
enableUserData: true, personIds: personIDs, studioIds: studioIDs, genreIds: genreIDs, enableImages: true)
|
||||||
.trackActivity(loading)
|
.trackActivity(loading)
|
||||||
.sink(receiveCompletion: { [weak self] completion in
|
.sink(receiveCompletion: { [weak self] completion in
|
||||||
self?.HandleAPIRequestCompletion(completion: completion)
|
self?.handleAPIRequestCompletion(completion: completion)
|
||||||
}, receiveValue: { [weak self] response in
|
}, receiveValue: { [weak self] response in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
let totalPages = ceil(Double(response.totalRecordCount ?? 0) / 100.0)
|
let totalPages = ceil(Double(response.totalRecordCount ?? 0) / 100.0)
|
||||||
|
@ -70,11 +91,11 @@ final class LibraryViewModel: ViewModel {
|
||||||
|
|
||||||
func requestNextPage() {
|
func requestNextPage() {
|
||||||
currentPage += 1
|
currentPage += 1
|
||||||
refresh()
|
refresh(with: filters)
|
||||||
}
|
}
|
||||||
|
|
||||||
func requestPreviousPage() {
|
func requestPreviousPage() {
|
||||||
currentPage -= 1
|
currentPage -= 1
|
||||||
refresh()
|
refresh(with: filters)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ final class MovieItemViewModel: ViewModel {
|
||||||
PlaystateAPI.markUnplayedItem(userId: SessionManager.current.user.user_id!, itemId: id)
|
PlaystateAPI.markUnplayedItem(userId: SessionManager.current.user.user_id!, itemId: id)
|
||||||
.trackActivity(loading)
|
.trackActivity(loading)
|
||||||
.sink(receiveCompletion: { [weak self] completion in
|
.sink(receiveCompletion: { [weak self] completion in
|
||||||
self?.HandleAPIRequestCompletion(completion: completion)
|
self?.handleAPIRequestCompletion(completion: completion)
|
||||||
}, receiveValue: { [weak self] _ in
|
}, receiveValue: { [weak self] _ in
|
||||||
self?.isWatched = false
|
self?.isWatched = false
|
||||||
})
|
})
|
||||||
|
@ -42,7 +42,7 @@ final class MovieItemViewModel: ViewModel {
|
||||||
PlaystateAPI.markPlayedItem(userId: SessionManager.current.user.user_id!, itemId: id)
|
PlaystateAPI.markPlayedItem(userId: SessionManager.current.user.user_id!, itemId: id)
|
||||||
.trackActivity(loading)
|
.trackActivity(loading)
|
||||||
.sink(receiveCompletion: { [weak self] completion in
|
.sink(receiveCompletion: { [weak self] completion in
|
||||||
self?.HandleAPIRequestCompletion(completion: completion)
|
self?.handleAPIRequestCompletion(completion: completion)
|
||||||
}, receiveValue: { [weak self] _ in
|
}, receiveValue: { [weak self] _ in
|
||||||
self?.isWatched = true
|
self?.isWatched = true
|
||||||
})
|
})
|
||||||
|
@ -56,7 +56,7 @@ final class MovieItemViewModel: ViewModel {
|
||||||
UserLibraryAPI.unmarkFavoriteItem(userId: SessionManager.current.user.user_id!, itemId: id)
|
UserLibraryAPI.unmarkFavoriteItem(userId: SessionManager.current.user.user_id!, itemId: id)
|
||||||
.trackActivity(loading)
|
.trackActivity(loading)
|
||||||
.sink(receiveCompletion: { [weak self] completion in
|
.sink(receiveCompletion: { [weak self] completion in
|
||||||
self?.HandleAPIRequestCompletion(completion: completion)
|
self?.handleAPIRequestCompletion(completion: completion)
|
||||||
}, receiveValue: { [weak self] _ in
|
}, receiveValue: { [weak self] _ in
|
||||||
self?.isFavorited = false
|
self?.isFavorited = false
|
||||||
})
|
})
|
||||||
|
@ -65,7 +65,7 @@ final class MovieItemViewModel: ViewModel {
|
||||||
UserLibraryAPI.markFavoriteItem(userId: SessionManager.current.user.user_id!, itemId: id)
|
UserLibraryAPI.markFavoriteItem(userId: SessionManager.current.user.user_id!, itemId: id)
|
||||||
.trackActivity(loading)
|
.trackActivity(loading)
|
||||||
.sink(receiveCompletion: { [weak self] completion in
|
.sink(receiveCompletion: { [weak self] completion in
|
||||||
self?.HandleAPIRequestCompletion(completion: completion)
|
self?.handleAPIRequestCompletion(completion: completion)
|
||||||
}, receiveValue: { [weak self] _ in
|
}, receiveValue: { [weak self] _ in
|
||||||
self?.isFavorited = true
|
self?.isFavorited = true
|
||||||
})
|
})
|
||||||
|
|
|
@ -31,7 +31,7 @@ final class SeasonItemViewModel: ViewModel {
|
||||||
seasonId: item.id ?? "")
|
seasonId: item.id ?? "")
|
||||||
.trackActivity(loading)
|
.trackActivity(loading)
|
||||||
.sink(receiveCompletion: { [weak self] completion in
|
.sink(receiveCompletion: { [weak self] completion in
|
||||||
self?.HandleAPIRequestCompletion(completion: completion)
|
self?.handleAPIRequestCompletion(completion: completion)
|
||||||
}, receiveValue: { [weak self] response in
|
}, receiveValue: { [weak self] response in
|
||||||
self?.episodes = response.items ?? []
|
self?.episodes = response.items ?? []
|
||||||
})
|
})
|
||||||
|
|
|
@ -29,7 +29,7 @@ final class SeriesItemViewModel: ViewModel {
|
||||||
TvShowsAPI.getSeasons(seriesId: item.id ?? "", fields: [.primaryImageAspectRatio, .seriesPrimaryImage, .seasonUserData, .overview, .genres, .people])
|
TvShowsAPI.getSeasons(seriesId: item.id ?? "", fields: [.primaryImageAspectRatio, .seriesPrimaryImage, .seasonUserData, .overview, .genres, .people])
|
||||||
.trackActivity(loading)
|
.trackActivity(loading)
|
||||||
.sink(receiveCompletion: { [weak self] completion in
|
.sink(receiveCompletion: { [weak self] completion in
|
||||||
self?.HandleAPIRequestCompletion(completion: completion)
|
self?.handleAPIRequestCompletion(completion: completion)
|
||||||
}, receiveValue: { [weak self] response in
|
}, receiveValue: { [weak self] response in
|
||||||
self?.seasons = response.items ?? []
|
self?.seasons = response.items ?? []
|
||||||
})
|
})
|
||||||
|
|
|
@ -32,7 +32,7 @@ class ViewModel: ObservableObject {
|
||||||
loading.loading.assign(to: \.isLoading, on: self).store(in: &cancellables)
|
loading.loading.assign(to: \.isLoading, on: self).store(in: &cancellables)
|
||||||
}
|
}
|
||||||
|
|
||||||
func HandleAPIRequestCompletion(completion: Subscribers.Completion<Error>) {
|
func handleAPIRequestCompletion(completion: Subscribers.Completion<Error>) {
|
||||||
switch completion {
|
switch completion {
|
||||||
case .finished:
|
case .finished:
|
||||||
break
|
break
|
||||||
|
|
Loading…
Reference in New Issue