Fix login bug, remove empty homescreen, add landscape MovieItemView
This commit is contained in:
parent
ee0f46576e
commit
63f7264902
|
@ -11,6 +11,7 @@ import SwiftyRequest
|
||||||
import SwiftyJSON
|
import SwiftyJSON
|
||||||
import CoreData
|
import CoreData
|
||||||
import KeychainSwift
|
import KeychainSwift
|
||||||
|
import Introspect
|
||||||
|
|
||||||
struct ConnectToServerView: View {
|
struct ConnectToServerView: View {
|
||||||
@Environment(\.managedObjectContext) private var viewContext
|
@Environment(\.managedObjectContext) private var viewContext
|
||||||
|
@ -193,5 +194,8 @@ struct ConnectToServerView: View {
|
||||||
}
|
}
|
||||||
.onAppear(perform: start)
|
.onAppear(perform: start)
|
||||||
.transition(.move(edge:.bottom))
|
.transition(.move(edge:.bottom))
|
||||||
|
.introspectTabBarController { (UITabBarController) in
|
||||||
|
UITabBarController.tabBar.isHidden = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import SwiftUI
|
||||||
import KeychainSwift
|
import KeychainSwift
|
||||||
import SwiftyRequest
|
import SwiftyRequest
|
||||||
import SwiftyJSON
|
import SwiftyJSON
|
||||||
|
import Introspect
|
||||||
|
|
||||||
class GlobalData: ObservableObject {
|
class GlobalData: ObservableObject {
|
||||||
@Published var user: SignedInUser?
|
@Published var user: SignedInUser?
|
||||||
|
@ -134,9 +135,6 @@ class PreferenceUIHostingController: UIHostingController<AnyView> {
|
||||||
if(_orientations == .landscapeRight) {
|
if(_orientations == .landscapeRight) {
|
||||||
let value = UIInterfaceOrientation.landscapeRight.rawValue;
|
let value = UIInterfaceOrientation.landscapeRight.rawValue;
|
||||||
UIDevice.current.setValue(value, forKey: "orientation")
|
UIDevice.current.setValue(value, forKey: "orientation")
|
||||||
} else {
|
|
||||||
let value = UIInterfaceOrientation.portrait.rawValue;
|
|
||||||
UIDevice.current.setValue(value, forKey: "orientation")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -186,6 +184,7 @@ struct ContentView: View {
|
||||||
@State private var library_names: [String: String] = [:];
|
@State private var library_names: [String: String] = [:];
|
||||||
@State private var librariesShowRecentlyAdded: [String] = [];
|
@State private var librariesShowRecentlyAdded: [String] = [];
|
||||||
@State private var libraryPrefillID: String = "";
|
@State private var libraryPrefillID: String = "";
|
||||||
|
@State private var showSettingsPopover: Bool = false;
|
||||||
|
|
||||||
@Environment(\.verticalSizeClass) var verticalSizeClass: UserInterfaceSizeClass?
|
@Environment(\.verticalSizeClass) var verticalSizeClass: UserInterfaceSizeClass?
|
||||||
@Environment(\.horizontalSizeClass) var horizontalSizeClass: UserInterfaceSizeClass?
|
@Environment(\.horizontalSizeClass) var horizontalSizeClass: UserInterfaceSizeClass?
|
||||||
|
@ -309,12 +308,12 @@ struct ContentView: View {
|
||||||
.toolbar {
|
.toolbar {
|
||||||
ToolbarItemGroup(placement: .navigationBarTrailing) {
|
ToolbarItemGroup(placement: .navigationBarTrailing) {
|
||||||
Button {
|
Button {
|
||||||
print("Settings tapped!")
|
showSettingsPopover = true;
|
||||||
} label: {
|
} label: {
|
||||||
Image(systemName: "gear")
|
Image(systemName: "gear")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}.popover( isPresented: self.$showSettingsPopover, arrowEdge: .bottom) { SettingsView(close: $showSettingsPopover).environmentObject(self.globalData) }
|
||||||
}
|
}
|
||||||
.tabItem({
|
.tabItem({
|
||||||
Text("Home")
|
Text("Home")
|
||||||
|
@ -337,14 +336,15 @@ struct ContentView: View {
|
||||||
.navigationViewStyle(StackNavigationViewStyle())
|
.navigationViewStyle(StackNavigationViewStyle())
|
||||||
.alert(isPresented: $isNetworkErrored) {
|
.alert(isPresented: $isNetworkErrored) {
|
||||||
Alert(title: Text("Network Error"), message: Text("Couldn't connect to Jellyfin"), dismissButton: .default(Text("Ok")))
|
Alert(title: Text("Network Error"), message: Text("Couldn't connect to Jellyfin"), dismissButton: .default(Text("Ok")))
|
||||||
|
}.introspectTabBarController { (UITabBarController) in
|
||||||
|
UITabBarController.tabBar.isHidden = false
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Text("Signing in...")
|
Text("Signing in...")
|
||||||
.onAppear(perform: {
|
.onAppear(perform: {
|
||||||
DispatchQueue.global(qos: .userInitiated).async { [self] in
|
DispatchQueue.global(qos: .userInitiated).async { [self] in
|
||||||
print("Signing in")
|
usleep(500000);
|
||||||
sleep(3)
|
self.jsi.did = false;
|
||||||
jsi.did = false
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,78 +75,84 @@ struct ContinueWatchingView: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .leading) {
|
if(resumeItems.count != 0) {
|
||||||
ScrollView(.horizontal, showsIndicators: false) {
|
VStack(alignment: .leading) {
|
||||||
HStack() {
|
ScrollView(.horizontal, showsIndicators: false) {
|
||||||
if(isLoading == false) {
|
HStack() {
|
||||||
Spacer().frame(width:16)
|
if(isLoading == false) {
|
||||||
ForEach(resumeItems, id: \.Id) { item in
|
Spacer().frame(width:16)
|
||||||
NavigationLink(destination: ItemView(item: item)) {
|
ForEach(resumeItems, id: \.Id) { item in
|
||||||
VStack(alignment: .leading) {
|
NavigationLink(destination: ItemView(item: item)) {
|
||||||
Spacer().frame(height: 10)
|
VStack(alignment: .leading) {
|
||||||
if(item.Type == "Episode") {
|
Spacer().frame(height: 10)
|
||||||
WebImage(url: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.Id)/Images/\(item.ImageType)?fillWidth=560&fillHeight=315&quality=90&tag=\(item.Image)")!)
|
if(item.Type == "Episode") {
|
||||||
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
WebImage(url: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.Id)/Images/\(item.ImageType)?fillWidth=560&fillHeight=315&quality=90&tag=\(item.Image)")!)
|
||||||
.placeholder {
|
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
||||||
Image(uiImage: UIImage(blurHash: (item.BlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item.BlurHash), size: CGSize(width: 32, height: 32))!)
|
.placeholder {
|
||||||
.resizable()
|
Image(uiImage: UIImage(blurHash: (item.BlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item.BlurHash), size: CGSize(width: 32, height: 32))!)
|
||||||
.scaledToFit()
|
.resizable()
|
||||||
.cornerRadius(10)
|
.scaledToFit()
|
||||||
}
|
.cornerRadius(10)
|
||||||
.frame(width: 320, height: 180)
|
}
|
||||||
.cornerRadius(10)
|
.frame(width: 320, height: 180)
|
||||||
.overlay(
|
.cornerRadius(10)
|
||||||
ZStack {
|
.overlay(
|
||||||
Text("S\(String(item.ParentIndexNumber ?? 0)):E\(String(item.IndexNumber ?? 0)) - \(item.Name)")
|
ZStack {
|
||||||
.font(.caption)
|
Text("S\(String(item.ParentIndexNumber ?? 0)):E\(String(item.IndexNumber ?? 0)) - \(item.Name)")
|
||||||
.padding(6)
|
.font(.caption)
|
||||||
.foregroundColor(.white)
|
.padding(6)
|
||||||
}.background(Color.black)
|
.foregroundColor(.white)
|
||||||
.opacity(0.8)
|
}.background(Color.black)
|
||||||
.cornerRadius(10.0)
|
.opacity(0.8)
|
||||||
.padding(6), alignment: .topTrailing
|
.cornerRadius(10.0)
|
||||||
)
|
.padding(6), alignment: .topTrailing
|
||||||
.overlay(
|
)
|
||||||
RoundedRectangle(cornerRadius: 10, style: .circular)
|
.overlay(
|
||||||
.fill(Color(red: 172/255, green: 92/255, blue: 195/255).opacity(0.4))
|
RoundedRectangle(cornerRadius: 10, style: .circular)
|
||||||
.frame(width: CGFloat((item.ItemProgress/100)*320), height: 180)
|
.fill(Color(red: 172/255, green: 92/255, blue: 195/255).opacity(0.4))
|
||||||
.padding(0), alignment: .bottomLeading
|
.frame(width: CGFloat((item.ItemProgress/100)*320), height: 180)
|
||||||
)
|
.padding(0), alignment: .bottomLeading
|
||||||
.shadow(radius: 5)
|
)
|
||||||
} else {
|
.shadow(radius: 5)
|
||||||
WebImage(url: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.Id)/Images/\(item.ImageType)?fillWidth=560&fillHeight=315&quality=90&tag=\(item.Image)")!)
|
} else {
|
||||||
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
WebImage(url: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.Id)/Images/\(item.ImageType)?fillWidth=560&fillHeight=315&quality=90&tag=\(item.Image)")!)
|
||||||
.placeholder {
|
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
||||||
Image(uiImage: UIImage(blurHash: (item.BlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item.BlurHash), size: CGSize(width: 32, height: 32))!)
|
.placeholder {
|
||||||
.resizable()
|
Image(uiImage: UIImage(blurHash: (item.BlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item.BlurHash), size: CGSize(width: 32, height: 32))!)
|
||||||
.scaledToFit()
|
.resizable()
|
||||||
.cornerRadius(10)
|
.scaledToFit()
|
||||||
}
|
.cornerRadius(10)
|
||||||
.frame(width: 320, height: 180)
|
}
|
||||||
.cornerRadius(10)
|
.frame(width: 320, height: 180)
|
||||||
.overlay(
|
.cornerRadius(10)
|
||||||
RoundedRectangle(cornerRadius: 10, style: .circular)
|
.overlay(
|
||||||
.fill(Color(red: 172/255, green: 92/255, blue: 195/255).opacity(0.4))
|
RoundedRectangle(cornerRadius: 10, style: .circular)
|
||||||
.frame(width: CGFloat((item.ItemProgress/100)*320), height: 180)
|
.fill(Color(red: 172/255, green: 92/255, blue: 195/255).opacity(0.4))
|
||||||
.padding(0), alignment: .bottomLeading
|
.frame(width: CGFloat((item.ItemProgress/100)*320), height: 180)
|
||||||
)
|
.padding(0), alignment: .bottomLeading
|
||||||
.shadow(radius: 5)
|
)
|
||||||
}
|
.shadow(radius: 5)
|
||||||
Text("\(item.Type == "Episode" ? item.SeriesName ?? "" : item.Name)")
|
}
|
||||||
.font(.callout)
|
Text("\(item.Type == "Episode" ? item.SeriesName ?? "" : item.Name)")
|
||||||
.fontWeight(.semibold)
|
.font(.callout)
|
||||||
.foregroundColor(.primary)
|
.fontWeight(.semibold)
|
||||||
Spacer().frame(height: 5)
|
.foregroundColor(.primary)
|
||||||
}.padding(.trailing, 5)
|
Spacer().frame(height: 5)
|
||||||
}
|
}.padding(.trailing, 5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spacer().frame(width:14)
|
||||||
}
|
}
|
||||||
Spacer().frame(width:14)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.frame(height: 200)
|
||||||
|
.padding(.bottom, 10)
|
||||||
}
|
}
|
||||||
.frame(height: 200)
|
} else {
|
||||||
.padding(.bottom, 10)
|
VStack() {
|
||||||
}.onAppear(perform: onAppear)
|
EmptyView()
|
||||||
|
}.onAppear(perform: onAppear)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -240,6 +240,14 @@ struct MovieItemView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Environment(\.verticalSizeClass) var verticalSizeClass: UserInterfaceSizeClass?
|
||||||
|
@Environment(\.horizontalSizeClass) var horizontalSizeClass: UserInterfaceSizeClass?
|
||||||
|
|
||||||
|
var isPortrait: Bool {
|
||||||
|
let result = verticalSizeClass == .regular && horizontalSizeClass == .compact
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
if(playing) {
|
if(playing) {
|
||||||
PlayerDemo(item: fullItem, playing: $playing).onAppear(perform: lockOrientations)
|
PlayerDemo(item: fullItem, playing: $playing).onAppear(perform: lockOrientations)
|
||||||
|
@ -247,191 +255,375 @@ struct MovieItemView: View {
|
||||||
LoadingView(isShowing: $isLoading) {
|
LoadingView(isShowing: $isLoading) {
|
||||||
VStack(alignment:.leading) {
|
VStack(alignment:.leading) {
|
||||||
if(!isLoading) {
|
if(!isLoading) {
|
||||||
GeometryReader { geometry in
|
if(isPortrait) {
|
||||||
VStack() {
|
GeometryReader { geometry in
|
||||||
WebImage(url: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.Id)/Images/Backdrop?maxWidth=3840&quality=90&tag=\(fullItem.Backdrop)")!)
|
VStack() {
|
||||||
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
WebImage(url: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.Id)/Images/Backdrop?maxWidth=3840&quality=90&tag=\(fullItem.Backdrop)")!)
|
||||||
.placeholder {
|
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
||||||
Image(uiImage: UIImage(blurHash: (fullItem.BackdropBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : fullItem.BackdropBlurHash), size: CGSize(width: 32, height: 32))!)
|
.placeholder {
|
||||||
.resizable()
|
Image(uiImage: UIImage(blurHash: (fullItem.BackdropBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : fullItem.BackdropBlurHash), size: CGSize(width: 32, height: 32))!)
|
||||||
.frame(width: geometry.size.width + geometry.safeAreaInsets.leading + geometry.safeAreaInsets.trailing, height: (geometry.size.width + geometry.safeAreaInsets.leading + geometry.safeAreaInsets.trailing) * 0.5625)
|
.resizable()
|
||||||
}
|
.frame(width: geometry.size.width + geometry.safeAreaInsets.leading + geometry.safeAreaInsets.trailing, height: (geometry.size.width + geometry.safeAreaInsets.leading + geometry.safeAreaInsets.trailing) * 0.5625)
|
||||||
|
}
|
||||||
.opacity(0.4)
|
|
||||||
.frame(width: geometry.size.width + geometry.safeAreaInsets.leading + geometry.safeAreaInsets.trailing, height: (geometry.size.width + geometry.safeAreaInsets.leading + geometry.safeAreaInsets.trailing) * 0.5625)
|
.opacity(0.4)
|
||||||
.aspectRatio(contentMode: .fill)
|
.aspectRatio(contentMode: .fill)
|
||||||
.shadow(radius: 5)
|
.frame(width: geometry.size.width + geometry.safeAreaInsets.leading + geometry.safeAreaInsets.trailing, height: (geometry.size.width + geometry.safeAreaInsets.leading + geometry.safeAreaInsets.trailing) * 0.5625)
|
||||||
.overlay(
|
.shadow(radius: 5)
|
||||||
|
.overlay(
|
||||||
|
HStack() {
|
||||||
|
WebImage(url: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.Id)/Images/Primary?fillWidth=300&fillHeight=450&quality=90&tag=\(fullItem.Poster)")!)
|
||||||
|
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
||||||
|
.placeholder {
|
||||||
|
Image(uiImage: UIImage(blurHash: (fullItem.PosterBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : fullItem.PosterBlurHash), size: CGSize(width: 32, height: 32))!)
|
||||||
|
.resizable()
|
||||||
|
.frame(width: 120, height: 180)
|
||||||
|
.cornerRadius(10)
|
||||||
|
}.aspectRatio(contentMode: .fill)
|
||||||
|
.frame(width: 120, height: 180)
|
||||||
|
.cornerRadius(10)
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
Spacer()
|
||||||
|
Text(fullItem.Name).font(.headline)
|
||||||
|
.fontWeight(.semibold)
|
||||||
|
.foregroundColor(.primary)
|
||||||
|
.fixedSize(horizontal: false, vertical: true)
|
||||||
|
.offset(y: -4)
|
||||||
|
HStack() {
|
||||||
|
Text(String(fullItem.ProductionYear)).font(.subheadline)
|
||||||
|
.fontWeight(.medium)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
.lineLimit(1)
|
||||||
|
Text(fullItem.Runtime).font(.subheadline)
|
||||||
|
.fontWeight(.medium)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
.lineLimit(1)
|
||||||
|
if(fullItem.OfficialRating != "") {
|
||||||
|
Text(fullItem.OfficialRating).font(.subheadline)
|
||||||
|
.fontWeight(.semibold)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
.lineLimit(1)
|
||||||
|
.padding(EdgeInsets(top: 1, leading: 4, bottom: 1, trailing: 4))
|
||||||
|
.overlay(
|
||||||
|
RoundedRectangle(cornerRadius: 2)
|
||||||
|
.stroke(Color.secondary, lineWidth: 1)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if(fullItem.CommunityRating != "") {
|
||||||
|
HStack() {
|
||||||
|
Image(systemName: "star").foregroundColor(.secondary)
|
||||||
|
Text(fullItem.CommunityRating).font(.subheadline)
|
||||||
|
.fontWeight(.semibold)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
.lineLimit(1)
|
||||||
|
.offset(x: -7, y: 0.7)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}.offset(x: 0, y: -46)
|
||||||
|
}.offset(x: 16, y: 40)
|
||||||
|
, alignment: .bottomLeading)
|
||||||
|
VStack(alignment: .leading) {
|
||||||
HStack() {
|
HStack() {
|
||||||
WebImage(url: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.Id)/Images/Primary?fillWidth=300&fillHeight=450&quality=90&tag=\(fullItem.Poster)")!)
|
//Play button
|
||||||
|
Button() {
|
||||||
|
playing = true;
|
||||||
|
} label: {
|
||||||
|
HStack() {
|
||||||
|
Text(fullItem.Progress == 0 ? "Play" : "\(progressString) left").foregroundColor(Color.white).font(.callout).fontWeight(.semibold)
|
||||||
|
Image(systemName: "play.fill").foregroundColor(Color.white).font(.system(size: 20))
|
||||||
|
}
|
||||||
|
.frame(width: 120, height: 35)
|
||||||
|
.background(Color(UIColor.systemBlue))
|
||||||
|
.cornerRadius(10)
|
||||||
|
}.buttonStyle(PlainButtonStyle())
|
||||||
|
.frame(width: 120, height: 25)
|
||||||
|
Spacer()
|
||||||
|
HStack() {
|
||||||
|
Button() {
|
||||||
|
favorite.toggle()
|
||||||
|
} label: {
|
||||||
|
if(!favorite) {
|
||||||
|
Image(systemName: "heart").foregroundColor(Color.primary).font(.system(size: 20))
|
||||||
|
} else {
|
||||||
|
Image(systemName: "heart.fill").foregroundColor(Color(UIColor.systemRed)).font(.system(size: 20))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Button() {
|
||||||
|
watched.toggle()
|
||||||
|
} label: {
|
||||||
|
if(watched) {
|
||||||
|
Image(systemName: "checkmark.rectangle.fill").foregroundColor(Color.primary).font(.system(size: 20))
|
||||||
|
} else {
|
||||||
|
Image(systemName: "xmark.rectangle").foregroundColor(Color.primary).font(.system(size: 20))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.padding(.leading, 16).padding(.trailing,16)
|
||||||
|
ScrollView() {
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
if(fullItem.Tagline != "") {
|
||||||
|
Text(fullItem.Tagline).font(.body).italic().padding(.top, 7).fixedSize(horizontal: false, vertical: true).padding(.leading, 16).padding(.trailing,16)
|
||||||
|
}
|
||||||
|
Text(fullItem.Overview).font(.footnote).padding(.top, 3).fixedSize(horizontal: false, vertical: true).padding(.bottom, 3).padding(.leading, 16).padding(.trailing,16)
|
||||||
|
if(fullItem.Genres.count != 0) {
|
||||||
|
ScrollView(.horizontal, showsIndicators: false) {
|
||||||
|
HStack() {
|
||||||
|
Text("Genres:").font(.callout).fontWeight(.semibold)
|
||||||
|
ForEach(fullItem.Genres, id: \.Id) {genre in
|
||||||
|
NavigationLink(destination: LibraryView(extraParams: "&Genres=\(genre.Name.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "")", title: genre.Name)) {
|
||||||
|
Text(genre.Name).font(.footnote)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.padding(.leading, 16).padding(.trailing,16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(fullItem.Cast.count != 0) {
|
||||||
|
ScrollView(.horizontal, showsIndicators: false) {
|
||||||
|
VStack() {
|
||||||
|
Spacer().frame(height: 8);
|
||||||
|
HStack() {
|
||||||
|
Spacer().frame(width: 16)
|
||||||
|
ForEach(fullItem.Cast, id: \.Id) { cast in
|
||||||
|
NavigationLink(destination: LibraryView(extraParams: "&PersonIds=\(cast.Id)", title: cast.Name)) {
|
||||||
|
VStack() {
|
||||||
|
WebImage(url: cast.Image)
|
||||||
|
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
||||||
|
.placeholder {
|
||||||
|
Image(uiImage: UIImage(blurHash: (cast.ImageBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : cast.ImageBlurHash), size: CGSize(width: 32, height: 32))!)
|
||||||
|
.resizable()
|
||||||
|
.aspectRatio(contentMode: .fill)
|
||||||
|
.frame(width: 100, height: 100)
|
||||||
|
.cornerRadius(10)
|
||||||
|
}
|
||||||
|
.aspectRatio(contentMode: .fill)
|
||||||
|
.frame(width: 100, height: 100)
|
||||||
|
.cornerRadius(10).shadow(radius: 6)
|
||||||
|
Text(cast.Name).font(.footnote).fontWeight(.regular).lineLimit(1).frame(width: 100).foregroundColor(Color.primary)
|
||||||
|
if(cast.Role != "") {
|
||||||
|
Text(cast.Role).font(.caption).fontWeight(.medium).lineLimit(1).foregroundColor(Color.secondary).frame(width: 100)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spacer().frame(width: 10)
|
||||||
|
}
|
||||||
|
Spacer().frame(width: 16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.padding(.top, -3)
|
||||||
|
}
|
||||||
|
if(fullItem.Directors.count != 0) {
|
||||||
|
HStack() {
|
||||||
|
Text("Directors:").font(.callout).fontWeight(.semibold)
|
||||||
|
Text(fullItem.Directors.joined(separator: ", ")).font(.footnote).lineLimit(1).foregroundColor(Color.secondary)
|
||||||
|
}.padding(.leading, 16).padding(.trailing,16)
|
||||||
|
}
|
||||||
|
if(fullItem.Writers.count != 0) {
|
||||||
|
HStack() {
|
||||||
|
Text("Writers:").font(.callout).fontWeight(.semibold)
|
||||||
|
Text(fullItem.Writers.joined(separator: ", ")).font(.footnote).lineLimit(1).foregroundColor(Color.secondary)
|
||||||
|
}.padding(.leading, 16).padding(.trailing,16)
|
||||||
|
}
|
||||||
|
if(fullItem.Studios.count != 0) {
|
||||||
|
HStack() {
|
||||||
|
Text("Studios:").font(.callout).fontWeight(.semibold)
|
||||||
|
Text(fullItem.Studios.joined(separator: ", ")).font(.footnote).lineLimit(1).foregroundColor(Color.secondary)
|
||||||
|
}.padding(.leading, 16).padding(.trailing,16)
|
||||||
|
}
|
||||||
|
Spacer().frame(height: 3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.padding(EdgeInsets(top: 24, leading: 0, bottom: 0, trailing: 0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
GeometryReader { geometry in
|
||||||
|
ZStack() {
|
||||||
|
WebImage(url: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.Id)/Images/Backdrop?maxWidth=3840&quality=90&tag=\(fullItem.Backdrop)")!)
|
||||||
|
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
||||||
|
.placeholder {
|
||||||
|
Image(uiImage: UIImage(blurHash: (fullItem.BackdropBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : fullItem.BackdropBlurHash), size: CGSize(width: 32, height: 32))!)
|
||||||
|
.resizable()
|
||||||
|
.frame(width: geometry.size.width + geometry.safeAreaInsets.leading + geometry.safeAreaInsets.trailing, height: (geometry.size.width + geometry.safeAreaInsets.leading + geometry.safeAreaInsets.trailing) * 0.5625)
|
||||||
|
}
|
||||||
|
|
||||||
|
.opacity(0.4)
|
||||||
|
.aspectRatio(contentMode: .fill)
|
||||||
|
.frame(width: geometry.size.width + geometry.safeAreaInsets.leading + geometry.safeAreaInsets.trailing, height: (geometry.size.width + geometry.safeAreaInsets.leading + geometry.safeAreaInsets.trailing) * 0.5625)
|
||||||
|
.edgesIgnoringSafeArea(.all)
|
||||||
|
HStack() {
|
||||||
|
VStack() {
|
||||||
|
WebImage(url: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(fullItem.Id)/Images/Primary?maxWidth=300&quality=90&tag=\(fullItem.Poster)")!)
|
||||||
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
||||||
.placeholder {
|
.placeholder {
|
||||||
Image(uiImage: UIImage(blurHash: (fullItem.PosterBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : fullItem.PosterBlurHash), size: CGSize(width: 32, height: 32))!)
|
Image(uiImage: UIImage(blurHash: (fullItem.PosterBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : fullItem.PosterBlurHash), size: CGSize(width: 32, height: 32))!)
|
||||||
.resizable()
|
.resizable()
|
||||||
.frame(width: 120, height: 180)
|
.frame(width: 120, height: 180)
|
||||||
.cornerRadius(10)
|
}
|
||||||
}.aspectRatio(contentMode: .fill)
|
|
||||||
.frame(width: 120, height: 180)
|
.frame(width: 120, height: 180)
|
||||||
.cornerRadius(10)
|
.cornerRadius(10)
|
||||||
VStack(alignment: .leading) {
|
.shadow(radius: 5)
|
||||||
Spacer()
|
Spacer().frame(height: 15)
|
||||||
Text(fullItem.Name).font(.headline)
|
Button() {
|
||||||
.fontWeight(.semibold)
|
playing = true;
|
||||||
.foregroundColor(.primary)
|
} label: {
|
||||||
.fixedSize(horizontal: false, vertical: true)
|
|
||||||
.offset(y: -4)
|
|
||||||
HStack() {
|
HStack() {
|
||||||
Text(String(fullItem.ProductionYear)).font(.subheadline)
|
Text(fullItem.Progress == 0 ? "Play" : "\(progressString) left").foregroundColor(Color.white).font(.callout).fontWeight(.semibold)
|
||||||
.fontWeight(.medium)
|
Image(systemName: "play.fill").foregroundColor(Color.white).font(.system(size: 20))
|
||||||
.foregroundColor(.secondary)
|
}
|
||||||
.lineLimit(1)
|
.frame(width: 120, height: 35)
|
||||||
Text(fullItem.Runtime).font(.subheadline)
|
.background(Color(UIColor.systemBlue))
|
||||||
.fontWeight(.medium)
|
.cornerRadius(10)
|
||||||
.foregroundColor(.secondary)
|
}.buttonStyle(PlainButtonStyle())
|
||||||
.lineLimit(1)
|
.frame(width: 120, height: 25)
|
||||||
if(fullItem.OfficialRating != "") {
|
Spacer()
|
||||||
Text(fullItem.OfficialRating).font(.subheadline)
|
}
|
||||||
|
ScrollView() {
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
HStack() {
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
Text(fullItem.Name).font(.headline)
|
||||||
.fontWeight(.semibold)
|
.fontWeight(.semibold)
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.primary)
|
||||||
.lineLimit(1)
|
.fixedSize(horizontal: false, vertical: true)
|
||||||
.padding(EdgeInsets(top: 1, leading: 4, bottom: 1, trailing: 4))
|
.offset(x: 11, y: 0)
|
||||||
.overlay(
|
Spacer().frame(height: 1)
|
||||||
RoundedRectangle(cornerRadius: 2)
|
|
||||||
.stroke(Color.secondary, lineWidth: 1)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if(fullItem.CommunityRating != "") {
|
|
||||||
HStack() {
|
HStack() {
|
||||||
Image(systemName: "star").foregroundColor(.secondary)
|
Text(String(fullItem.ProductionYear)).font(.subheadline)
|
||||||
Text(fullItem.CommunityRating).font(.subheadline)
|
.fontWeight(.medium)
|
||||||
.fontWeight(.semibold)
|
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
.lineLimit(1)
|
.lineLimit(1)
|
||||||
.offset(x: -7, y: 0.7)
|
Text(fullItem.Runtime).font(.subheadline)
|
||||||
|
.fontWeight(.medium)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
.lineLimit(1)
|
||||||
|
if(fullItem.OfficialRating != "") {
|
||||||
|
Text(fullItem.OfficialRating).font(.subheadline)
|
||||||
|
.fontWeight(.semibold)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
.lineLimit(1)
|
||||||
|
.padding(EdgeInsets(top: 1, leading: 4, bottom: 1, trailing: 4))
|
||||||
|
.overlay(
|
||||||
|
RoundedRectangle(cornerRadius: 2)
|
||||||
|
.stroke(Color.secondary, lineWidth: 1)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if(fullItem.CommunityRating != "") {
|
||||||
|
HStack() {
|
||||||
|
Image(systemName: "star").foregroundColor(.secondary)
|
||||||
|
Text(fullItem.CommunityRating).font(.subheadline)
|
||||||
|
.fontWeight(.semibold)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
.lineLimit(1)
|
||||||
|
.offset(x: -7, y: 0.7)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spacer()
|
||||||
|
}.frame(maxWidth: .infinity)
|
||||||
|
.offset(x: 11)
|
||||||
|
}.frame(maxWidth: .infinity)
|
||||||
|
Spacer()
|
||||||
|
HStack() {
|
||||||
|
Button() {
|
||||||
|
favorite.toggle()
|
||||||
|
} label: {
|
||||||
|
if(!favorite) {
|
||||||
|
Image(systemName: "heart").foregroundColor(Color.primary).font(.system(size: 20))
|
||||||
|
} else {
|
||||||
|
Image(systemName: "heart.fill").foregroundColor(Color(UIColor.systemRed)).font(.system(size: 20))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Button() {
|
||||||
|
watched.toggle()
|
||||||
|
} label: {
|
||||||
|
if(watched) {
|
||||||
|
Image(systemName: "checkmark.rectangle.fill").foregroundColor(Color.primary).font(.system(size: 20))
|
||||||
|
} else {
|
||||||
|
Image(systemName: "xmark.rectangle").foregroundColor(Color.primary).font(.system(size: 20))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(fullItem.Tagline != "") {
|
||||||
}.offset(x: 0, y: -46)
|
Text(fullItem.Tagline).font(.body).italic().padding(.top, 3).fixedSize(horizontal: false, vertical: true).padding(.leading, 16).padding(.trailing,16)
|
||||||
}.offset(x: 16, y: 40)
|
|
||||||
, alignment: .bottomLeading)
|
|
||||||
VStack(alignment: .leading) {
|
|
||||||
HStack() {
|
|
||||||
//Play button
|
|
||||||
Button() {
|
|
||||||
playing = true;
|
|
||||||
} label: {
|
|
||||||
HStack() {
|
|
||||||
Text(fullItem.Progress == 0 ? "Play" : "\(progressString) left").foregroundColor(Color.white).font(.callout).fontWeight(.semibold)
|
|
||||||
Image(systemName: "play.fill").foregroundColor(Color.white).font(.system(size: 20))
|
|
||||||
}
|
|
||||||
.frame(width: 120, height: 35)
|
|
||||||
.background(Color(UIColor.systemBlue))
|
|
||||||
.cornerRadius(10)
|
|
||||||
}.buttonStyle(PlainButtonStyle())
|
|
||||||
.frame(width: 120, height: 25)
|
|
||||||
Spacer()
|
|
||||||
HStack() {
|
|
||||||
Button() {
|
|
||||||
favorite.toggle()
|
|
||||||
} label: {
|
|
||||||
if(!favorite) {
|
|
||||||
Image(systemName: "heart").foregroundColor(Color.primary).font(.system(size: 20))
|
|
||||||
} else {
|
|
||||||
Image(systemName: "heart.fill").foregroundColor(Color(UIColor.systemRed)).font(.system(size: 20))
|
|
||||||
}
|
}
|
||||||
}
|
Text(fullItem.Overview).font(.footnote).padding(.top, 3).fixedSize(horizontal: false, vertical: true).padding(.bottom, 3).padding(.leading, 16).padding(.trailing,16)
|
||||||
Button() {
|
if(fullItem.Genres.count != 0) {
|
||||||
watched.toggle()
|
ScrollView(.horizontal, showsIndicators: false) {
|
||||||
} label: {
|
|
||||||
if(watched) {
|
|
||||||
Image(systemName: "checkmark.rectangle.fill").foregroundColor(Color.primary).font(.system(size: 20))
|
|
||||||
} else {
|
|
||||||
Image(systemName: "xmark.rectangle").foregroundColor(Color.primary).font(.system(size: 20))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.padding(.leading, 16).padding(.trailing,16)
|
|
||||||
ScrollView() {
|
|
||||||
VStack(alignment: .leading) {
|
|
||||||
if(fullItem.Tagline != "") {
|
|
||||||
Text(fullItem.Tagline).font(.body).italic().padding(.top, 7).fixedSize(horizontal: false, vertical: true).padding(.leading, 16).padding(.trailing,16)
|
|
||||||
}
|
|
||||||
Text(fullItem.Overview).font(.footnote).padding(.top, 3).fixedSize(horizontal: false, vertical: true).padding(.bottom, 3).padding(.leading, 16).padding(.trailing,16)
|
|
||||||
if(fullItem.Genres.count != 0) {
|
|
||||||
ScrollView(.horizontal, showsIndicators: false) {
|
|
||||||
HStack() {
|
|
||||||
Text("Genres:").font(.callout).fontWeight(.semibold)
|
|
||||||
ForEach(fullItem.Genres, id: \.Id) {genre in
|
|
||||||
NavigationLink(destination: LibraryView(extraParams: "&Genres=\(genre.Name.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "")", title: genre.Name)) {
|
|
||||||
Text(genre.Name).font(.footnote)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.padding(.leading, 16).padding(.trailing,16)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(fullItem.Cast.count != 0) {
|
|
||||||
ScrollView(.horizontal, showsIndicators: false) {
|
|
||||||
VStack() {
|
|
||||||
Spacer().frame(height: 8);
|
|
||||||
HStack() {
|
HStack() {
|
||||||
Spacer().frame(width: 16)
|
Text("Genres:").font(.callout).fontWeight(.semibold)
|
||||||
ForEach(fullItem.Cast, id: \.Id) { cast in
|
ForEach(fullItem.Genres, id: \.Id) {genre in
|
||||||
NavigationLink(destination: LibraryView(extraParams: "&PersonIds=\(cast.Id)", title: cast.Name)) {
|
NavigationLink(destination: LibraryView(extraParams: "&Genres=\(genre.Name.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "")", title: genre.Name)) {
|
||||||
VStack() {
|
Text(genre.Name).font(.footnote)
|
||||||
WebImage(url: cast.Image)
|
}
|
||||||
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
}
|
||||||
.placeholder {
|
}.padding(.leading, 16).padding(.trailing,16)
|
||||||
Image(uiImage: UIImage(blurHash: (cast.ImageBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : cast.ImageBlurHash), size: CGSize(width: 32, height: 32))!)
|
}
|
||||||
.resizable()
|
}
|
||||||
.aspectRatio(contentMode: .fill)
|
if(fullItem.Cast.count != 0) {
|
||||||
.frame(width: 100, height: 100)
|
ScrollView(.horizontal, showsIndicators: false) {
|
||||||
.cornerRadius(10)
|
VStack() {
|
||||||
|
Spacer().frame(height: 8);
|
||||||
|
HStack() {
|
||||||
|
Spacer().frame(width: 16)
|
||||||
|
ForEach(fullItem.Cast, id: \.Id) { cast in
|
||||||
|
NavigationLink(destination: LibraryView(extraParams: "&PersonIds=\(cast.Id)", title: cast.Name)) {
|
||||||
|
VStack() {
|
||||||
|
WebImage(url: cast.Image)
|
||||||
|
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
||||||
|
.placeholder {
|
||||||
|
Image(uiImage: UIImage(blurHash: (cast.ImageBlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : cast.ImageBlurHash), size: CGSize(width: 32, height: 32))!)
|
||||||
|
.resizable()
|
||||||
|
.aspectRatio(contentMode: .fill)
|
||||||
|
.frame(width: 100, height: 100)
|
||||||
|
.cornerRadius(10)
|
||||||
|
}
|
||||||
|
.aspectRatio(contentMode: .fill)
|
||||||
|
.frame(width: 100, height: 100)
|
||||||
|
.cornerRadius(10).shadow(radius: 6)
|
||||||
|
Text(cast.Name).font(.footnote).fontWeight(.regular).lineLimit(1).frame(width: 100).foregroundColor(Color.primary)
|
||||||
|
if(cast.Role != "") {
|
||||||
|
Text(cast.Role).font(.caption).fontWeight(.medium).lineLimit(1).foregroundColor(Color.secondary).frame(width: 100)
|
||||||
}
|
}
|
||||||
.aspectRatio(contentMode: .fill)
|
|
||||||
.frame(width: 100, height: 100)
|
|
||||||
.cornerRadius(10).shadow(radius: 6)
|
|
||||||
Text(cast.Name).font(.footnote).fontWeight(.regular).lineLimit(1).frame(width: 100).foregroundColor(Color.primary)
|
|
||||||
if(cast.Role != "") {
|
|
||||||
Text(cast.Role).font(.caption).fontWeight(.medium).lineLimit(1).foregroundColor(Color.secondary).frame(width: 100)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Spacer().frame(width: 10)
|
||||||
}
|
}
|
||||||
Spacer().frame(width: 10)
|
Spacer().frame(width: 16)
|
||||||
}
|
}
|
||||||
Spacer().frame(width: 16)
|
|
||||||
}
|
}
|
||||||
}
|
}.padding(.top, -3)
|
||||||
}.padding(.top, -3)
|
}
|
||||||
}
|
if(fullItem.Directors.count != 0) {
|
||||||
if(fullItem.Directors.count != 0) {
|
HStack() {
|
||||||
HStack() {
|
Text("Directors:").font(.callout).fontWeight(.semibold)
|
||||||
Text("Directors:").font(.callout).fontWeight(.semibold)
|
Text(fullItem.Directors.joined(separator: ", ")).font(.footnote).lineLimit(1).foregroundColor(Color.secondary)
|
||||||
Text(fullItem.Directors.joined(separator: ", ")).font(.footnote).lineLimit(1).foregroundColor(Color.secondary)
|
}.padding(.leading, 16).padding(.trailing,16)
|
||||||
}.padding(.leading, 16).padding(.trailing,16)
|
}
|
||||||
}
|
if(fullItem.Writers.count != 0) {
|
||||||
if(fullItem.Writers.count != 0) {
|
HStack() {
|
||||||
HStack() {
|
Text("Writers:").font(.callout).fontWeight(.semibold)
|
||||||
Text("Writers:").font(.callout).fontWeight(.semibold)
|
Text(fullItem.Writers.joined(separator: ", ")).font(.footnote).lineLimit(1).foregroundColor(Color.secondary)
|
||||||
Text(fullItem.Writers.joined(separator: ", ")).font(.footnote).lineLimit(1).foregroundColor(Color.secondary)
|
}.padding(.leading, 16).padding(.trailing,16)
|
||||||
}.padding(.leading, 16).padding(.trailing,16)
|
}
|
||||||
}
|
if(fullItem.Studios.count != 0) {
|
||||||
if(fullItem.Studios.count != 0) {
|
HStack() {
|
||||||
HStack() {
|
Text("Studios:").font(.callout).fontWeight(.semibold)
|
||||||
Text("Studios:").font(.callout).fontWeight(.semibold)
|
Text(fullItem.Studios.joined(separator: ", ")).font(.footnote).lineLimit(1).foregroundColor(Color.secondary)
|
||||||
Text(fullItem.Studios.joined(separator: ", ")).font(.footnote).lineLimit(1).foregroundColor(Color.secondary)
|
}.padding(.leading, 16).padding(.trailing,16)
|
||||||
}.padding(.leading, 16).padding(.trailing,16)
|
}
|
||||||
}
|
Spacer().frame(height: 195);
|
||||||
Spacer().frame(height: 3)
|
}.frame(maxHeight: .infinity)
|
||||||
}
|
}.padding(.trailing, 55)
|
||||||
}
|
}.padding(.top, 12)
|
||||||
}.padding(EdgeInsets(top: 24, leading: 0, bottom: 0, trailing: 0))
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
.navigationTitle("Movie Details")
|
.navigationTitle(fullItem.Name)
|
||||||
.supportedOrientations(.allButUpsideDown)
|
.supportedOrientations(.allButUpsideDown)
|
||||||
.prefersHomeIndicatorAutoHidden(false)
|
.prefersHomeIndicatorAutoHidden(false)
|
||||||
.withHostingWindow() { window in
|
.withHostingWindow() { window in
|
||||||
|
|
|
@ -69,46 +69,48 @@ struct NextUpView: View {
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
Text("Next Up").font(.title2).fontWeight(.bold).padding(EdgeInsets(top: 0, leading: 16, bottom: 0, trailing: 16))
|
if(resumeItems.count != 0) {
|
||||||
ScrollView(.horizontal, showsIndicators: false) {
|
Text("Next Up").font(.title2).fontWeight(.bold).padding(EdgeInsets(top: 0, leading: 16, bottom: 0, trailing: 16))
|
||||||
HStack() {
|
ScrollView(.horizontal, showsIndicators: false) {
|
||||||
if(isLoading == false) {
|
HStack() {
|
||||||
Spacer().frame(width:18)
|
if(isLoading == false) {
|
||||||
ForEach(resumeItems, id: \.Id) { item in
|
Spacer().frame(width:18)
|
||||||
NavigationLink(destination: ItemView(item: item)) {
|
ForEach(resumeItems, id: \.Id) { item in
|
||||||
VStack(alignment: .leading) {
|
NavigationLink(destination: ItemView(item: item)) {
|
||||||
Spacer().frame(height:10)
|
VStack(alignment: .leading) {
|
||||||
WebImage(url: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.SeriesId ?? "")/Images/\(item.ImageType)?fillWidth=300&fillHeight=450&quality=90&tag=\(item.Image)")!)
|
Spacer().frame(height:10)
|
||||||
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
WebImage(url: URL(string: "\(globalData.server?.baseURI ?? "")/Items/\(item.SeriesId ?? "")/Images/\(item.ImageType)?fillWidth=300&fillHeight=450&quality=90&tag=\(item.Image)")!)
|
||||||
.placeholder {
|
.resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
|
||||||
Image(uiImage: UIImage(blurHash: (item.BlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item.BlurHash), size: CGSize(width: 32, height: 32))!)
|
.placeholder {
|
||||||
.resizable()
|
Image(uiImage: UIImage(blurHash: (item.BlurHash == "" ? "W$H.4}D%bdo#a#xbtpxVW?W?jXWsXVt7Rjf5axWqxbWXnhada{s-" : item.BlurHash), size: CGSize(width: 32, height: 32))!)
|
||||||
.scaledToFit()
|
.resizable()
|
||||||
.cornerRadius(10)
|
.scaledToFit()
|
||||||
}
|
.cornerRadius(10)
|
||||||
.frame(width: 100, height: 150)
|
}
|
||||||
.cornerRadius(10)
|
.frame(width: 100, height: 150)
|
||||||
.shadow(radius: 6)
|
.cornerRadius(10)
|
||||||
Text(item.SeriesName ?? "")
|
.shadow(radius: 6)
|
||||||
.font(.caption)
|
Text(item.SeriesName ?? "")
|
||||||
.fontWeight(.semibold)
|
.font(.caption)
|
||||||
.foregroundColor(.primary)
|
.fontWeight(.semibold)
|
||||||
.lineLimit(1)
|
.foregroundColor(.primary)
|
||||||
Text("S\(String(item.ParentIndexNumber ?? 0)):E\(String(item.IndexNumber ?? 0))")
|
.lineLimit(1)
|
||||||
.font(.caption)
|
Text("S\(String(item.ParentIndexNumber ?? 0)):E\(String(item.IndexNumber ?? 0))")
|
||||||
.fontWeight(.semibold)
|
.font(.caption)
|
||||||
.foregroundColor(.secondary)
|
.fontWeight(.semibold)
|
||||||
.lineLimit(1)
|
.foregroundColor(.secondary)
|
||||||
Spacer().frame(height:5)
|
.lineLimit(1)
|
||||||
|
Spacer().frame(height:5)
|
||||||
|
}
|
||||||
|
.frame(width: 100)
|
||||||
|
Spacer().frame(width:12)
|
||||||
}
|
}
|
||||||
.frame(width: 100)
|
|
||||||
Spacer().frame(width:12)
|
|
||||||
}
|
}
|
||||||
|
Spacer().frame(width:18)
|
||||||
}
|
}
|
||||||
Spacer().frame(width:18)
|
|
||||||
}
|
}
|
||||||
}
|
}.padding(EdgeInsets(top: -2, leading: 0, bottom: 0, trailing: 0))
|
||||||
}.padding(EdgeInsets(top: -2, leading: 0, bottom: 0, trailing: 0))
|
}
|
||||||
}.onAppear(perform: onAppear).padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
|
}.onAppear(perform: onAppear).padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,13 +8,22 @@
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct SettingsView: View {
|
struct SettingsView: View {
|
||||||
|
@Binding var close: Bool;
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
|
NavigationView() {
|
||||||
}
|
Text("SettingsView not implemented.")
|
||||||
}
|
.navigationBarTitle("Settings", displayMode: .inline)
|
||||||
|
.toolbar {
|
||||||
struct SettingsView_Previews: PreviewProvider {
|
ToolbarItemGroup(placement: .navigationBarLeading) {
|
||||||
static var previews: some View {
|
Button {
|
||||||
SettingsView()
|
close = false
|
||||||
|
} label: {
|
||||||
|
HStack() {
|
||||||
|
Text("Back").font(.callout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue