add LibraryListViewModel

This commit is contained in:
PangMo5 2021-05-28 12:20:49 +09:00
parent ed224da0a4
commit 4dae6bc00e
4 changed files with 178 additions and 137 deletions

View File

@ -45,6 +45,7 @@
6213388E265F777C00A81A2A /* LibraryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6213388D265F777C00A81A2A /* LibraryViewModel.swift */; }; 6213388E265F777C00A81A2A /* LibraryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6213388D265F777C00A81A2A /* LibraryViewModel.swift */; };
62133890265F83A900A81A2A /* LibraryListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6213388F265F83A900A81A2A /* LibraryListView.swift */; }; 62133890265F83A900A81A2A /* LibraryListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6213388F265F83A900A81A2A /* LibraryListView.swift */; };
621338932660107500A81A2A /* String++.swift in Sources */ = {isa = PBXBuildFile; fileRef = 621338922660107500A81A2A /* String++.swift */; }; 621338932660107500A81A2A /* String++.swift in Sources */ = {isa = PBXBuildFile; fileRef = 621338922660107500A81A2A /* String++.swift */; };
62133895266096EF00A81A2A /* LibraryListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62133894266096EF00A81A2A /* LibraryListViewModel.swift */; };
6273DD43265F4195009C1D0B /* Moya in Frameworks */ = {isa = PBXBuildFile; productRef = 6273DD42265F4195009C1D0B /* Moya */; }; 6273DD43265F4195009C1D0B /* Moya in Frameworks */ = {isa = PBXBuildFile; productRef = 6273DD42265F4195009C1D0B /* Moya */; };
6273DD45265F4195009C1D0B /* CombineMoya in Frameworks */ = {isa = PBXBuildFile; productRef = 6273DD44265F4195009C1D0B /* CombineMoya */; }; 6273DD45265F4195009C1D0B /* CombineMoya in Frameworks */ = {isa = PBXBuildFile; productRef = 6273DD44265F4195009C1D0B /* CombineMoya */; };
6273DD48265F41B3009C1D0B /* JellyfinAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6273DD47265F41B3009C1D0B /* JellyfinAPI.swift */; }; 6273DD48265F41B3009C1D0B /* JellyfinAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6273DD47265F41B3009C1D0B /* JellyfinAPI.swift */; };
@ -112,6 +113,7 @@
6213388D265F777C00A81A2A /* LibraryViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryViewModel.swift; sourceTree = "<group>"; }; 6213388D265F777C00A81A2A /* LibraryViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryViewModel.swift; sourceTree = "<group>"; };
6213388F265F83A900A81A2A /* LibraryListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryListView.swift; sourceTree = "<group>"; }; 6213388F265F83A900A81A2A /* LibraryListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryListView.swift; sourceTree = "<group>"; };
621338922660107500A81A2A /* String++.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String++.swift"; sourceTree = "<group>"; }; 621338922660107500A81A2A /* String++.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String++.swift"; sourceTree = "<group>"; };
62133894266096EF00A81A2A /* LibraryListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryListViewModel.swift; sourceTree = "<group>"; };
6273DD47265F41B3009C1D0B /* JellyfinAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JellyfinAPI.swift; sourceTree = "<group>"; }; 6273DD47265F41B3009C1D0B /* JellyfinAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JellyfinAPI.swift; sourceTree = "<group>"; };
6273DD4D265F47B2009C1D0B /* LibrarySearchViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibrarySearchViewModel.swift; sourceTree = "<group>"; }; 6273DD4D265F47B2009C1D0B /* LibrarySearchViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibrarySearchViewModel.swift; sourceTree = "<group>"; };
AE8C3153265D60BF008AA076 /* SettingsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsModel.swift; sourceTree = "<group>"; }; AE8C3153265D60BF008AA076 /* SettingsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsModel.swift; sourceTree = "<group>"; };
@ -224,6 +226,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
6213388D265F777C00A81A2A /* LibraryViewModel.swift */, 6213388D265F777C00A81A2A /* LibraryViewModel.swift */,
62133894266096EF00A81A2A /* LibraryListViewModel.swift */,
); );
path = ViewModels; path = ViewModels;
sourceTree = "<group>"; sourceTree = "<group>";
@ -417,6 +420,7 @@
53E4E649263F725B00F67C6B /* MultiSelector.swift in Sources */, 53E4E649263F725B00F67C6B /* MultiSelector.swift in Sources */,
53E4E647263F6CF100F67C6B /* LibraryFilterView.swift in Sources */, 53E4E647263F6CF100F67C6B /* LibraryFilterView.swift in Sources */,
6213388E265F777C00A81A2A /* LibraryViewModel.swift in Sources */, 6213388E265F777C00A81A2A /* LibraryViewModel.swift in Sources */,
62133895266096EF00A81A2A /* LibraryListViewModel.swift in Sources */,
6273DD48265F41B3009C1D0B /* JellyfinAPI.swift in Sources */, 6273DD48265F41B3009C1D0B /* JellyfinAPI.swift in Sources */,
53892777263CBB000035E14B /* JellyApiTypings.swift in Sources */, 53892777263CBB000035E14B /* JellyApiTypings.swift in Sources */,
5377CBF7263B596A003A4E83 /* ContentView.swift in Sources */, 5377CBF7263B596A003A4E83 /* ContentView.swift in Sources */,

View File

@ -8,78 +8,98 @@
import SwiftUI import SwiftUI
import KeychainSwift import KeychainSwift
import SwiftyRequest
import SwiftyJSON
import Sentry
import SDWebImageSwiftUI import SDWebImageSwiftUI
import Sentry
import SwiftyJSON
import SwiftyRequest
struct ContentView: View { struct ContentView: View {
@Environment(\.managedObjectContext) private var viewContext @Environment(\.managedObjectContext)
@EnvironmentObject var orientationInfo: OrientationInfo private var viewContext
@StateObject private var globalData = GlobalData() @EnvironmentObject
@EnvironmentObject var jsi: justSignedIn var orientationInfo: OrientationInfo
@StateObject
private var globalData = GlobalData()
@EnvironmentObject
var jsi: justSignedIn
@FetchRequest(entity: Server.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \Server.name, ascending: true)]) private var servers: FetchedResults<Server> @FetchRequest(entity: Server.entity(),
sortDescriptors: [NSSortDescriptor(keyPath: \Server.name, ascending: true)])
@FetchRequest(entity: SignedInUser.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \SignedInUser.username, ascending: true)]) private var savedUsers: FetchedResults<SignedInUser> private var servers: FetchedResults<Server>
@State private var needsToSelectServer = false; @FetchRequest(entity: SignedInUser.entity(),
@State private var isSignInErrored = false; sortDescriptors: [NSSortDescriptor(keyPath: \SignedInUser.username,
@State private var isNetworkErrored = false; ascending: true)])
@State private var isLoading = false; private var savedUsers: FetchedResults<SignedInUser>
@State private var tabSelection: String = "Home";
@State private var libraries: [String] = []; @State
@State private var library_names: [String: String] = [:]; private var needsToSelectServer = false
@State private var librariesShowRecentlyAdded: [String] = []; @State
@State private var libraryPrefillID: String = ""; private var isSignInErrored = false
@State private var showSettingsPopover: Bool = false; @State
@State private var viewDidLoad: Bool = false; private var isNetworkErrored = false
@State
private var isLoading = false
@State
private var tabSelection: String = "Home"
@State
private var libraries: [String] = []
@State
private var library_names: [String: String] = [:]
@State
private var librariesShowRecentlyAdded: [String] = []
@State
private var libraryPrefillID: String = ""
@State
private var showSettingsPopover: Bool = false
@State
private var viewDidLoad: Bool = false
func startup() { func startup() {
let size = UIScreen.main.bounds.size let size = UIScreen.main.bounds.size
if size.width < size.height { if size.width < size.height {
orientationInfo.orientation = .portrait; orientationInfo.orientation = .portrait
} else { } else {
orientationInfo.orientation = .landscape; orientationInfo.orientation = .landscape
} }
if(_viewDidLoad.wrappedValue) { if _viewDidLoad.wrappedValue {
return return
} }
_viewDidLoad.wrappedValue = true; _viewDidLoad.wrappedValue = true
SentrySDK.start { options in SentrySDK.start { options in
options.dsn = "https://75ac77d6af4d406eb989f3d8ef0f119f@o513670.ingest.sentry.io/5778242" options.dsn = "https://75ac77d6af4d406eb989f3d8ef0f119f@o513670.ingest.sentry.io/5778242"
options.debug = false // Enabled debug when first installing is always helpful options.debug = false // Enabled debug when first installing is always helpful
options.tracesSampleRate = 1.0 options.tracesSampleRate = 1.0
options.releaseName = "ios-" + (Bundle.main.infoDictionary?["CFBundleVersion"] as! String); options.releaseName = "ios-" + (Bundle.main.infoDictionary?["CFBundleVersion"] as! String)
options.enableOutOfMemoryTracking = true options.enableOutOfMemoryTracking = true
} }
let cache = SDImageCache(namespace: "tiny") let cache = SDImageCache(namespace: "tiny")
cache.config.maxMemoryCost = 125 * 1024 * 1024 // 125MB memory cache.config.maxMemoryCost = 125 * 1024 * 1024 // 125MB memory
cache.config.maxDiskSize = 1000 * 1024 * 1024 // 1000MB disk cache.config.maxDiskSize = 1000 * 1024 * 1024 // 1000MB disk
SDImageCachesManager.shared.addCache(cache) SDImageCachesManager.shared.addCache(cache)
SDWebImageManager.defaultImageCache = SDImageCachesManager.shared SDWebImageManager.defaultImageCache = SDImageCachesManager.shared
_libraries.wrappedValue = [] _libraries.wrappedValue = []
_library_names.wrappedValue = [:] _library_names.wrappedValue = [:]
_librariesShowRecentlyAdded.wrappedValue = [] _librariesShowRecentlyAdded.wrappedValue = []
if(servers.isEmpty) { if servers.isEmpty {
_isLoading.wrappedValue = false; _isLoading.wrappedValue = false
_needsToSelectServer.wrappedValue = true; _needsToSelectServer.wrappedValue = true
} else { } else {
_isLoading.wrappedValue = true; _isLoading.wrappedValue = true
let savedUser = savedUsers[0]; let savedUser = savedUsers[0]
let keychain = KeychainSwift(); let keychain = KeychainSwift()
if(keychain.get("AccessToken_\(savedUser.user_id ?? "")") != nil) { if keychain.get("AccessToken_\(savedUser.user_id ?? "")") != nil {
_globalData.wrappedValue.authToken = keychain.get("AccessToken_\(savedUser.user_id ?? "")") ?? "" _globalData.wrappedValue.authToken = keychain.get("AccessToken_\(savedUser.user_id ?? "")") ?? ""
_globalData.wrappedValue.server = servers[0] _globalData.wrappedValue.server = servers[0]
_globalData.wrappedValue.user = savedUser _globalData.wrappedValue.user = savedUser
} }
let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String; let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String
var header = "MediaBrowser " var header = "MediaBrowser "
header.append("Client=\"SwiftFin\",") header.append("Client=\"SwiftFin\",")
header.append("Device=\"\(UIDevice.current.name.removeRegexMatches(pattern: "[^\\w\\s]"))\",") header.append("Device=\"\(UIDevice.current.name.removeRegexMatches(pattern: "[^\\w\\s]"))\",")
@ -87,48 +107,50 @@ struct ContentView: View {
header.append("Version=\"\(appVersion ?? "0.0.1")\",") header.append("Version=\"\(appVersion ?? "0.0.1")\",")
header.append("Token=\"\(globalData.authToken)\"") header.append("Token=\"\(globalData.authToken)\"")
globalData.authHeader = header globalData.authHeader = header
let request = RestRequest(method: .get, url: (globalData.server?.baseURI ?? "") + "/Users/Me") let request = RestRequest(method: .get, url: (globalData.server?.baseURI ?? "") + "/Users/Me")
request.headerParameters["X-Emby-Authorization"] = globalData.authHeader request.headerParameters["X-Emby-Authorization"] = globalData.authHeader
request.contentType = "application/json" request.contentType = "application/json"
request.acceptType = "application/json" request.acceptType = "application/json"
request.responseData() { (result: Result<RestResponse<Data>, RestError>) in request.responseData { (result: Result<RestResponse<Data>, RestError>) in
switch result { switch result {
case .success( let resp): case let .success(resp):
do { do {
let json = try JSON(data: resp.body) let json = try JSON(data: resp.body)
let array2 = json["Configuration"]["LatestItemsExcludes"].arrayObject as? [String] ?? [] let array2 = json["Configuration"]["LatestItemsExcludes"].arrayObject as? [String] ?? []
let request2 = RestRequest(method: .get, url: (globalData.server?.baseURI ?? "") + "/Users/\(globalData.user?.user_id ?? "")/Views") let request2 = RestRequest(method: .get,
url: (globalData.server?.baseURI ?? "") +
"/Users/\(globalData.user?.user_id ?? "")/Views")
request2.headerParameters["X-Emby-Authorization"] = globalData.authHeader request2.headerParameters["X-Emby-Authorization"] = globalData.authHeader
request2.contentType = "application/json" request2.contentType = "application/json"
request2.acceptType = "application/json" request2.acceptType = "application/json"
request2.responseData() { (result2: Result<RestResponse<Data>, RestError>) in request2.responseData { (result2: Result<RestResponse<Data>, RestError>) in
switch result2 { switch result2 {
case .success( let resp): case let .success(resp):
do { do {
let json2 = try JSON(data: resp.body) let json2 = try JSON(data: resp.body)
for (_,item2):(String, JSON) in json2["Items"] { for (_, item2): (String, JSON) in json2["Items"] {
_library_names.wrappedValue[item2["Id"].string ?? ""] = item2["Name"].string ?? "" _library_names.wrappedValue[item2["Id"].string ?? ""] = item2["Name"].string ?? ""
} }
for (_,item2):(String, JSON) in json2["Items"] { for (_, item2): (String, JSON) in json2["Items"] {
if(item2["CollectionType"].string == "tvshows" || item2["CollectionType"].string == "movies") { if item2["CollectionType"].string == "tvshows" || item2["CollectionType"].string == "movies" {
_libraries.wrappedValue.append(item2["Id"].string ?? "") _libraries.wrappedValue.append(item2["Id"].string ?? "")
_librariesShowRecentlyAdded.wrappedValue.append(item2["Id"].string ?? "") _librariesShowRecentlyAdded.wrappedValue.append(item2["Id"].string ?? "")
} }
} }
_librariesShowRecentlyAdded.wrappedValue = _libraries.wrappedValue.filter { element in _librariesShowRecentlyAdded.wrappedValue = _libraries.wrappedValue.filter { element in
return !array2.contains(element) !array2.contains(element)
} }
_libraries.wrappedValue.forEach { library in _libraries.wrappedValue.forEach { library in
if(_library_names.wrappedValue[library] == nil) { if _library_names.wrappedValue[library] == nil {
_libraries.wrappedValue.removeAll { ele in _libraries.wrappedValue.removeAll { ele in
if(library == ele) { if library == ele {
return true return true
} else { } else {
return false return false
@ -136,39 +158,32 @@ struct ContentView: View {
} }
} }
} }
dump(_libraries.wrappedValue) dump(_libraries.wrappedValue)
dump(_librariesShowRecentlyAdded.wrappedValue) dump(_librariesShowRecentlyAdded.wrappedValue)
dump(_library_names.wrappedValue) dump(_library_names.wrappedValue)
} catch { } catch {}
case let .failure(error):
}
break
case .failure(let error):
SentrySDK.capture(error: error) SentrySDK.capture(error: error)
break
} }
let defaults = UserDefaults.standard; let defaults = UserDefaults.standard
if(defaults.integer(forKey: "InNetworkBandwidth") == 0) { if defaults.integer(forKey: "InNetworkBandwidth") == 0 {
defaults.setValue(40000000, forKey: "InNetworkBandwidth") defaults.setValue(40_000_000, forKey: "InNetworkBandwidth")
} }
if(defaults.integer(forKey: "OutOfNetworkBandwidth") == 0) { if defaults.integer(forKey: "OutOfNetworkBandwidth") == 0 {
defaults.setValue(40000000, forKey: "OutOfNetworkBandwidth") defaults.setValue(40_000_000, forKey: "OutOfNetworkBandwidth")
} }
_isLoading.wrappedValue = false; _isLoading.wrappedValue = false
} }
} catch { } catch {}
case let .failure(error):
} if error.response?.status.code == 401 {
break _isLoading.wrappedValue = false
case .failure( let error): _isSignInErrored.wrappedValue = true
if(error.response?.status.code == 401) {
_isLoading.wrappedValue = false;
_isSignInErrored.wrappedValue = true;
} else { } else {
SentrySDK.capture(error: error) SentrySDK.capture(error: error)
_isLoading.wrappedValue = false; _isLoading.wrappedValue = false
_isNetworkErrored.wrappedValue = true; _isNetworkErrored.wrappedValue = true
} }
} }
} }
@ -176,34 +191,37 @@ struct ContentView: View {
} }
var body: some View { var body: some View {
if(needsToSelectServer) { if needsToSelectServer {
NavigationView() { NavigationView {
ConnectToServerView(isActive: $needsToSelectServer) ConnectToServerView(isActive: $needsToSelectServer)
} }
.navigationViewStyle(StackNavigationViewStyle()) .navigationViewStyle(StackNavigationViewStyle())
.environmentObject(globalData) .environmentObject(globalData)
} else if(isSignInErrored) { } else if isSignInErrored {
NavigationView() { NavigationView {
ConnectToServerView(skip_server: true, skip_server_prefill: globalData.server, reauth_deviceId: globalData.user?.device_uuid ?? "", isActive: $isSignInErrored) ConnectToServerView(skip_server: true, skip_server_prefill: globalData.server,
reauth_deviceId: globalData.user?.device_uuid ?? "", isActive: $isSignInErrored)
} }
.navigationViewStyle(StackNavigationViewStyle()) .navigationViewStyle(StackNavigationViewStyle())
.environmentObject(globalData) .environmentObject(globalData)
} else { } else {
if(!jsi.did) { if !jsi.did {
LoadingView(isShowing: $isLoading) { LoadingView(isShowing: $isLoading) {
TabView(selection: $tabSelection) { TabView(selection: $tabSelection) {
NavigationView() { NavigationView {
VStack(alignment: .leading) { VStack(alignment: .leading) {
ScrollView() { ScrollView {
Spacer().frame(height: orientationInfo.orientation == .portrait ? 0 : 15) Spacer().frame(height: orientationInfo.orientation == .portrait ? 0 : 15)
ContinueWatchingView() ContinueWatchingView()
NextUpView().padding(EdgeInsets(top: 4, leading: 0, bottom: 0, trailing: 0)) NextUpView().padding(EdgeInsets(top: 4, leading: 0, bottom: 0, trailing: 0))
ForEach(librariesShowRecentlyAdded, id: \.self) { library_id in ForEach(librariesShowRecentlyAdded, id: \.self) { library_id in
VStack(alignment: .leading) { VStack(alignment: .leading) {
HStack() { HStack {
Text("Latest \(library_names[library_id] ?? "")").font(.title2).fontWeight(.bold).padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 16)) Text("Latest \(library_names[library_id] ?? "")").font(.title2).fontWeight(.bold)
.padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 16))
Spacer() Spacer()
NavigationLink(destination: LibraryView(viewModel: .init(filter: Filter(parentID: library_id)), title: library_names[library_id] ?? "")) { NavigationLink(destination: LibraryView(viewModel: .init(filter: Filter(parentID: library_id)),
title: library_names[library_id] ?? "")) {
Text("See All").font(.subheadline).fontWeight(.bold) Text("See All").font(.subheadline).fontWeight(.bold)
} }
}.padding(EdgeInsets(top: 0, leading: 16, bottom: 0, trailing: 16)) }.padding(EdgeInsets(top: 0, leading: 16, bottom: 0, trailing: 16))
@ -216,28 +234,31 @@ struct ContentView: View {
.toolbar { .toolbar {
ToolbarItemGroup(placement: .navigationBarTrailing) { ToolbarItemGroup(placement: .navigationBarTrailing) {
Button { Button {
showSettingsPopover = true; showSettingsPopover = true
} label: { } label: {
Image(systemName: "gear") Image(systemName: "gear")
} }
} }
}.fullScreenCover( isPresented: $showSettingsPopover) { SettingsView(viewModel: SettingsViewModel(), close: $showSettingsPopover) } }
.fullScreenCover(isPresented: $showSettingsPopover) {
SettingsView(viewModel: SettingsViewModel(), close: $showSettingsPopover)
}
} }
} }
.navigationViewStyle(StackNavigationViewStyle()) .navigationViewStyle(StackNavigationViewStyle())
.tabItem({ .tabItem {
Text("Home") Text("Home")
Image(systemName: "house") Image(systemName: "house")
}) }
.tag("Home") .tag("Home")
NavigationView { NavigationView {
LibraryListView(libraryNames: library_names, libraryIDs: libraries) LibraryListView(viewModel: .init(libraryNames: library_names, libraryIDs: libraries))
} }
.navigationViewStyle(StackNavigationViewStyle()) .navigationViewStyle(StackNavigationViewStyle())
.tabItem({ .tabItem {
Text("All Media") Text("All Media")
Image(systemName: "folder") Image(systemName: "folder")
}) }
.tag("All Media") .tag("All Media")
} }
} }
@ -248,13 +269,13 @@ struct ContentView: View {
} }
} else { } else {
Text("Signing in...") Text("Signing in...")
.onAppear(perform: { .onAppear(perform: {
DispatchQueue.main.async { [self] in DispatchQueue.main.async { [self] in
_viewDidLoad.wrappedValue = false _viewDidLoad.wrappedValue = false
usleep(500000); usleep(500_000)
self.jsi.did = false; self.jsi.did = false
} }
}) })
} }
} }
} }

View File

@ -0,0 +1,38 @@
//
// LibraryListViewModel.swift
// JellyfinPlayer
//
// Created by PangMo5 on 2021/05/28.
//
import Combine
import CombineMoya
import Foundation
import Moya
import SwiftyJSON
final class LibraryListViewModel: ObservableObject {
fileprivate var provider =
MoyaProvider<JellyfinAPI>(plugins: [NetworkLoggerPlugin()])
@Published
var libraryIDs = [String]()
@Published
var libraryNames = [String: String]()
fileprivate var cancellables = Set<AnyCancellable>()
init(libraryNames: [String: String], libraryIDs: [String]) {
self.libraryIDs = libraryIDs
self.libraryNames = libraryNames
refresh()
}
func refresh() {
libraryIDs.append("favorites")
libraryNames["favorites"] = "Favorites"
libraryIDs.append("genres")
libraryNames["genres"] = "Genres - WIP"
}
}

View File

@ -13,48 +13,26 @@ struct LibraryListView: View {
private var viewContext private var viewContext
@EnvironmentObject @EnvironmentObject
var globalData: GlobalData var globalData: GlobalData
@State @ObservedObject
private var libraryIDs: [String] = [] var viewModel: LibraryListViewModel
@State
private var libraryNames: [String: String] = [:]
@State
private var viewDidLoad: Bool = false
@State
private var closeSearch: Bool = false
init(libraryNames: [String: String], libraryIDs: [String]) {
self._libraryNames = State(initialValue: libraryNames)
self._libraryIDs = State(initialValue: libraryIDs)
}
func listOnAppear() {
if viewDidLoad == false {
viewDidLoad = true
libraryIDs.append("favorites")
libraryNames["favorites"] = "Favorites"
libraryIDs.append("genres")
libraryNames["genres"] = "Genres - WIP"
}
}
var body: some View { var body: some View {
List(libraryIDs, id: \.self) { id in List(viewModel.libraryIDs, id: \.self) { id in
switch id { switch id {
case "favorites": case "favorites":
NavigationLink(destination: LibraryView(viewModel: .init(filter: Filter(filterTypes: [.isFavorite])), NavigationLink(destination: LibraryView(viewModel: .init(filter: Filter(filterTypes: [.isFavorite])),
title: libraryNames[id] ?? "")) { title: viewModel.libraryNames[id] ?? "")) {
Text(libraryNames[id] ?? "").foregroundColor(Color.primary) Text(viewModel.libraryNames[id] ?? "").foregroundColor(Color.primary)
} }
case "genres": case "genres":
Text(libraryNames[id] ?? "").foregroundColor(Color.primary) Text(viewModel.libraryNames[id] ?? "").foregroundColor(Color.primary)
default: default:
NavigationLink(destination: LibraryView(viewModel: .init(filter: Filter(parentID: id)), title: libraryNames[id] ?? "")) { NavigationLink(destination: LibraryView(viewModel: .init(filter: Filter(parentID: id)),
Text(libraryNames[id] ?? "").foregroundColor(Color.primary) title: viewModel.libraryNames[id] ?? "")) {
Text(viewModel.libraryNames[id] ?? "").foregroundColor(Color.primary)
} }
} }
} }
.onAppear(perform: listOnAppear)
.navigationTitle("All Media") .navigationTitle("All Media")
.navigationBarItems(trailing: .navigationBarItems(trailing:
NavigationLink(destination: LibrarySearchView(viewModel: .init(filter: .init()))) { NavigationLink(destination: LibrarySearchView(viewModel: .init(filter: .init()))) {