From ca61e0dd4c7978fee7a1f85a9ff244e7e77d54c6 Mon Sep 17 00:00:00 2001 From: Aiden Vigue Date: Sat, 22 May 2021 11:14:07 -0400 Subject: [PATCH] Build 8 (1.0.0) --- JellyfinPlayer/ContentView.swift | 172 +++++++++++++--------- JellyfinPlayer/ContinueWatchingView.swift | 48 +++++- JellyfinPlayer/EpisodeItemView.swift | 9 +- JellyfinPlayer/Info.plist | 19 +-- JellyfinPlayer/LatestMediaView.swift | 15 +- JellyfinPlayer/LibraryFilterView.swift | 9 +- JellyfinPlayer/LibrarySearchView.swift | 17 ++- JellyfinPlayer/LibraryView.swift | 17 ++- JellyfinPlayer/MovieItemView.swift | 11 +- JellyfinPlayer/SeasonItemView.swift | 18 ++- JellyfinPlayer/SeriesItemView.swift | 20 ++- Release Notes.rtf | 31 ++++ 12 files changed, 258 insertions(+), 128 deletions(-) create mode 100644 Release Notes.rtf diff --git a/JellyfinPlayer/ContentView.swift b/JellyfinPlayer/ContentView.swift index c793ab18..f77b2ade 100644 --- a/JellyfinPlayer/ContentView.swift +++ b/JellyfinPlayer/ContentView.swift @@ -188,6 +188,7 @@ struct ContentView: View { @State private var librariesShowRecentlyAdded: [String] = []; @State private var libraryPrefillID: String = ""; @State private var showSettingsPopover: Bool = false; + @State private var viewDidLoad: Bool = false; @Environment(\.verticalSizeClass) var verticalSizeClass: UserInterfaceSizeClass? @Environment(\.horizontalSizeClass) var horizontalSizeClass: UserInterfaceSizeClass? @@ -198,6 +199,10 @@ struct ContentView: View { } func startup() { + if(_viewDidLoad.wrappedValue) { + return + } + _viewDidLoad.wrappedValue = true; SentrySDK.start { options in options.dsn = "https://75ac77d6af4d406eb989f3d8ef0f119f@o513670.ingest.sentry.io/5778242" options.debug = false // Enabled debug when first installing is always helpful @@ -274,6 +279,18 @@ struct ContentView: View { _librariesShowRecentlyAdded.wrappedValue = _libraries.wrappedValue.filter { element in return !array2.contains(element) } + + _libraries.wrappedValue.forEach { library in + if(_library_names.wrappedValue[library] == nil) { + _libraries.wrappedValue.removeAll { ele in + if(library == ele) { + return true + } else { + return false + } + } + } + } } catch { } @@ -301,84 +318,95 @@ struct ContentView: View { } var body: some View { - if(!jsi.did) { - LoadingView(isShowing: $isLoading) { - TabView(selection: $tabSelection) { - NavigationView() { - VStack { - NavigationLink(destination: ConnectToServerView(isActive: $needsToSelectServer), isActive: $needsToSelectServer) { - EmptyView() - }.isDetailLink(false) - NavigationLink(destination: ConnectToServerView(skip_server: true, skip_server_prefill: globalData.server, reauth_deviceId: globalData.user?.device_uuid ?? "", isActive: $isSignInErrored), isActive: $isSignInErrored) { - EmptyView() - }.isDetailLink(false) - if(!needsToSelectServer && !isSignInErrored) { - VStack(alignment: .leading) { - ScrollView() { - Spacer().frame(height: self.isPortrait ? 0 : 15) - ContinueWatchingView() - NextUpView().padding(EdgeInsets(top: 4, leading: 0, bottom: 0, trailing: 0)) - ForEach(librariesShowRecentlyAdded, id: \.self) { library_id in - VStack(alignment: .leading) { - HStack() { - Text("Latest \(library_names[library_id] ?? "")").font(.title2).fontWeight(.bold).padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 16)) - Spacer() - NavigationLink(destination: LibraryView(prefill: library_id, names: library_names, libraries: libraries, filter: "&SortBy=DateCreated&SortOrder=Descending")) { - Text("See All").font(.subheadline).fontWeight(.bold) - } - }.padding(EdgeInsets(top: 0, leading: 16, bottom: 0, trailing: 16)) - LatestMediaView(library: library_id) - }.padding(EdgeInsets(top: 4, leading: 0, bottom: 0, trailing: 0)) + if(needsToSelectServer) { + NavigationView() { + ConnectToServerView(isActive: $needsToSelectServer) + } + } else if(isSignInErrored) { + NavigationView() { + ConnectToServerView(skip_server: true, skip_server_prefill: globalData.server, reauth_deviceId: globalData.user?.device_uuid ?? "", isActive: $isSignInErrored) + } + } else { + if(!jsi.did) { + LoadingView(isShowing: $isLoading) { + TabView(selection: $tabSelection) { + NavigationView() { + VStack { + NavigationLink(destination: ConnectToServerView(isActive: $needsToSelectServer), isActive: $needsToSelectServer) { + EmptyView() + }.isDetailLink(false) + NavigationLink(destination: ConnectToServerView(skip_server: true, skip_server_prefill: globalData.server, reauth_deviceId: globalData.user?.device_uuid ?? "", isActive: $isSignInErrored), isActive: $isSignInErrored) { + EmptyView() + }.isDetailLink(false) + if(!needsToSelectServer && !isSignInErrored) { + VStack(alignment: .leading) { + ScrollView() { + Spacer().frame(height: self.isPortrait ? 0 : 15) + ContinueWatchingView() + NextUpView().padding(EdgeInsets(top: 4, leading: 0, bottom: 0, trailing: 0)) + ForEach(librariesShowRecentlyAdded, id: \.self) { library_id in + VStack(alignment: .leading) { + HStack() { + Text("Latest \(library_names[library_id] ?? "")").font(.title2).fontWeight(.bold).padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 16)) + Spacer() + NavigationLink(destination: LibraryView(prefill: library_id, names: library_names, libraries: libraries, filter: "&SortBy=DateCreated&SortOrder=Descending")) { + Text("See All").font(.subheadline).fontWeight(.bold) + } + }.padding(EdgeInsets(top: 0, leading: 16, bottom: 0, trailing: 16)) + LatestMediaView(library: library_id) + }.padding(EdgeInsets(top: 4, leading: 0, bottom: 0, trailing: 0)) + } + Spacer().frame(height: 7) } - Spacer().frame(height: 7) } } } - } - .navigationTitle("Home") - .toolbar { - ToolbarItemGroup(placement: .navigationBarTrailing) { - Button { - showSettingsPopover = true; - } label: { - Image(systemName: "gear") + .navigationTitle("Home") + .toolbar { + ToolbarItemGroup(placement: .navigationBarTrailing) { + Button { + showSettingsPopover = true; + } label: { + Image(systemName: "gear") + } } - } - }.popover( isPresented: self.$showSettingsPopover, arrowEdge: .bottom) { SettingsView(close: $showSettingsPopover).environmentObject(self.globalData) } - } - .tabItem({ - Text("Home") - Image(systemName: "house") - }) - .tag("Home") - NavigationView() { - LibraryView(prefill: "", names: library_names, libraries: libraries) - .navigationTitle("Library") - } - .tabItem({ - Text("All Media") - Image(systemName: "folder") - }) - .tag("All Media") - - }.edgesIgnoringSafeArea(isPortrait ? [] : [.leading,.trailing]) - }.environmentObject(globalData) - .edgesIgnoringSafeArea(isPortrait ? [] : [.leading,.trailing]) - .onAppear(perform: startup) - .navigationViewStyle(StackNavigationViewStyle()) - .alert(isPresented: $isNetworkErrored) { - Alert(title: Text("Network Error"), message: Text("Couldn't connect to Jellyfin"), dismissButton: .default(Text("Ok"))) - }.introspectTabBarController { (UITabBarController) in - UITabBarController.tabBar.isHidden = false - } - } else { - Text("Signing in...") - .onAppear(perform: { - DispatchQueue.main.async { [self] in - usleep(500000); - self.jsi.did = false; + }.popover( isPresented: self.$showSettingsPopover, arrowEdge: .bottom) { SettingsView(close: $showSettingsPopover).environmentObject(self.globalData) } + } + .tabItem({ + Text("Home") + Image(systemName: "house") + }) + .tag("Home") + NavigationView() { + LibraryView(prefill: "", names: library_names, libraries: libraries) + .navigationTitle("Library") + } + .tabItem({ + Text("All Media") + Image(systemName: "folder") + }) + .tag("All Media") + + }.edgesIgnoringSafeArea(isPortrait ? [] : [.leading,.trailing]) + }.environmentObject(globalData) + .edgesIgnoringSafeArea(isPortrait ? [] : [.leading,.trailing]) + .onAppear(perform: startup) + .navigationViewStyle(StackNavigationViewStyle()) + .alert(isPresented: $isNetworkErrored) { + Alert(title: Text("Network Error"), message: Text("Couldn't connect to Jellyfin"), dismissButton: .default(Text("Ok"))) + }.introspectTabBarController { (UITabBarController) in + UITabBarController.tabBar.isHidden = false } - }) + } else { + Text("Signing in...") + .onAppear(perform: { + DispatchQueue.main.async { [self] in + _viewDidLoad.wrappedValue = false + usleep(500000); + self.jsi.did = false; + } + }) + } } } } diff --git a/JellyfinPlayer/ContinueWatchingView.swift b/JellyfinPlayer/ContinueWatchingView.swift index cdecc48b..9dac7dcf 100644 --- a/JellyfinPlayer/ContinueWatchingView.swift +++ b/JellyfinPlayer/ContinueWatchingView.swift @@ -10,6 +10,30 @@ import SwiftyRequest import SwiftyJSON import SDWebImageSwiftUI +struct CustomShape: Shape { + let radius: CGFloat + + func path(in rect: CGRect) -> Path { + var path = Path() + + let tl = CGPoint(x: rect.minX, y: rect.minY) + let tr = CGPoint(x: rect.maxX, y: rect.minY) + let br = CGPoint(x: rect.maxX, y: rect.maxY) + let bls = CGPoint(x: rect.minX + radius, y: rect.maxY) + let blc = CGPoint(x: rect.minX + radius, y: rect.maxY - radius) + + path.move(to: tl) + path.addLine(to: tr) + path.addLine(to: br) + path.addLine(to: bls) + path.addRelativeArc(center: blc, radius: radius, + startAngle: Angle.degrees(90), delta: Angle.degrees(90)) + + return path + } +} + + struct ContinueWatchingView: View { @Environment(\.managedObjectContext) private var viewContext @EnvironmentObject var globalData: GlobalData @@ -44,12 +68,18 @@ struct ContinueWatchingView: View { //portrait; use backdrop instead itemObj.Image = item["BackdropImageTags"][0].string ?? "" itemObj.ImageType = "Backdrop" + + if(itemObj.Image == "") { + itemObj.Image = item["ParentBackdropImageTags"][0].string ?? "" + } + itemObj.BlurHash = item["ImageBlurHashes"]["Backdrop"][itemObj.Image].string ?? "" } else { itemObj.Image = item["ImageTags"]["Primary"].string ?? "" itemObj.ImageType = "Primary" itemObj.BlurHash = item["ImageBlurHashes"]["Primary"][itemObj.Image].string ?? "" } + itemObj.Name = item["Name"].string ?? "" itemObj.Type = item["Type"].string ?? "" itemObj.IndexNumber = item["IndexNumber"].int ?? nil @@ -108,10 +138,11 @@ struct ContinueWatchingView: View { .padding(6), alignment: .topTrailing ) .overlay( - RoundedRectangle(cornerRadius: 10, style: .circular) - .fill(Color(red: 172/255, green: 92/255, blue: 195/255).opacity(0.4)) - .frame(width: CGFloat((item.ItemProgress/100)*320), height: 180) - .padding(0), alignment: .bottomLeading + Rectangle() + .fill(Color(red: 172/255, green: 92/255, blue: 195/255)) + .mask(CustomShape(radius: 10)) + .frame(width: CGFloat((item.ItemProgress/100)*320), height: 7) + .padding(0), alignment: .bottomLeading ) .shadow(radius: 5) } else { @@ -126,9 +157,10 @@ struct ContinueWatchingView: View { .frame(width: 320, height: 180) .cornerRadius(10) .overlay( - RoundedRectangle(cornerRadius: 10, style: .circular) - .fill(Color(red: 172/255, green: 92/255, blue: 195/255).opacity(0.4)) - .frame(width: CGFloat((item.ItemProgress/100)*320), height: 180) + Rectangle() + .fill(Color(red: 172/255, green: 92/255, blue: 195/255)) + .mask(CustomShape(radius: 10)) + .frame(width: CGFloat((item.ItemProgress/100)*320), height: 7) .padding(0), alignment: .bottomLeading ) .shadow(radius: 5) @@ -137,6 +169,8 @@ struct ContinueWatchingView: View { .font(.callout) .fontWeight(.semibold) .foregroundColor(.primary) + .lineLimit(1) + .frame(width: 320, alignment: .leading) Spacer().frame(height: 5) }.padding(.trailing, 5) } diff --git a/JellyfinPlayer/EpisodeItemView.swift b/JellyfinPlayer/EpisodeItemView.swift index 9edcd7ac..ba501beb 100644 --- a/JellyfinPlayer/EpisodeItemView.swift +++ b/JellyfinPlayer/EpisodeItemView.swift @@ -265,7 +265,7 @@ struct EpisodeItemView: View { .stroke(Color.secondary, lineWidth: 1) ) } - if(fullItem.CommunityRating != "") { + if(fullItem.CommunityRating != "0") { HStack() { Image(systemName: "star").foregroundColor(.secondary) Text(fullItem.CommunityRating).font(.subheadline) @@ -275,9 +275,8 @@ struct EpisodeItemView: View { .offset(x: -7, y: 0.7) } } - } - - }.offset(x: 0, y: -46).padding(.trailing, 16) + }.frame(maxWidth: .infinity, alignment: .leading) + }.frame(maxWidth: .infinity, alignment: .leading).offset(x: 0, y: -46).padding(.trailing, 16) }.offset(x: 16, y: 40) , alignment: .bottomLeading) VStack(alignment: .leading) { @@ -466,7 +465,7 @@ struct EpisodeItemView: View { .stroke(Color.secondary, lineWidth: 1) ) } - if(fullItem.CommunityRating != "") { + if(fullItem.CommunityRating != "0") { HStack() { Image(systemName: "star").foregroundColor(.secondary) Text(fullItem.CommunityRating).font(.subheadline) diff --git a/JellyfinPlayer/Info.plist b/JellyfinPlayer/Info.plist index b84f7c33..cc9ab1e3 100644 --- a/JellyfinPlayer/Info.plist +++ b/JellyfinPlayer/Info.plist @@ -20,6 +20,14 @@ $(MARKETING_VERSION) CFBundleVersion 7 + DTXApplicationID + 8c1f6941-ec78-480c-b589-b41aca29a52e + DTXBeaconURL + https://bf64941kgh.bf.dynatrace.com/mbeacon + DTXStartupLoadBalancing + + DTXUserOptIn + ITSAppUsesNonExemptEncryption LSRequiresIPhoneOS @@ -42,6 +50,8 @@ armv7 + UIRequiresFullScreen + UIStatusBarHidden UISupportedInterfaceOrientations @@ -53,17 +63,8 @@ UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - DTXApplicationID - 8c1f6941-ec78-480c-b589-b41aca29a52e - DTXBeaconURL - https://bf64941kgh.bf.dynatrace.com/mbeacon - DTXUserOptIn - - DTXStartupLoadBalancing - diff --git a/JellyfinPlayer/LatestMediaView.swift b/JellyfinPlayer/LatestMediaView.swift index 394aabe5..13584ed8 100644 --- a/JellyfinPlayer/LatestMediaView.swift +++ b/JellyfinPlayer/LatestMediaView.swift @@ -103,10 +103,17 @@ struct LatestMediaView: View { .cornerRadius(10) .overlay( ZStack { - Text("\(String(item.ItemBadge ?? 0))") - .font(.caption) - .padding(3) - .foregroundColor(.white) + if(item.ItemBadge == 0) { + Image(systemName: "checkmark") + .font(.caption) + .padding(3) + .foregroundColor(.white) + } else { + Text("\(String(item.ItemBadge ?? 0))") + .font(.caption) + .padding(3) + .foregroundColor(.white) + } }.background(Color.black) .opacity(0.8) .cornerRadius(10.0) diff --git a/JellyfinPlayer/LibraryFilterView.swift b/JellyfinPlayer/LibraryFilterView.swift index b7ae8a15..a16c4a5b 100644 --- a/JellyfinPlayer/LibraryFilterView.swift +++ b/JellyfinPlayer/LibraryFilterView.swift @@ -34,6 +34,10 @@ struct LibraryFilterView: View { @Binding var close: Bool; func onAppear() { + if(_viewDidLoad.wrappedValue == true) { + return + } + _viewDidLoad.wrappedValue = true; if(_output.wrappedValue.contains("&Filters=IsUnplayed")) { _onlyUnplayed.wrappedValue = true; } @@ -55,10 +59,6 @@ struct LibraryFilterView: View { _sortOrder.wrappedValue = sortOrder; recalculateFilters() - if(_viewDidLoad.wrappedValue == true) { - return - } - _viewDidLoad.wrappedValue = true; _allGenres.wrappedValue = [] let url = "/Items/Filters?UserId=\(globalData.user?.user_id ?? "")&ParentId=\(library)" let request = RestRequest(method: .get, url: (globalData.server?.baseURI ?? "") + url) @@ -98,6 +98,7 @@ struct LibraryFilterView: View { } func recalculateFilters() { + print("recalcFilters running"); output = ""; if(_onlyUnplayed.wrappedValue) { output = "&Filters=IsUnPlayed"; diff --git a/JellyfinPlayer/LibrarySearchView.swift b/JellyfinPlayer/LibrarySearchView.swift index 2dd62278..8287500b 100644 --- a/JellyfinPlayer/LibrarySearchView.swift +++ b/JellyfinPlayer/LibrarySearchView.swift @@ -32,7 +32,7 @@ struct LibrarySearchView: View { func onAppear() { _isLoading.wrappedValue = true; _items.wrappedValue = []; - let request = RestRequest(method: .get, url: (globalData.server?.baseURI ?? "") + _url.wrappedValue + "&searchTerm=" + searchQuery.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!) + let request = RestRequest(method: .get, url: (globalData.server?.baseURI ?? "") + _url.wrappedValue + "&searchTerm=" + searchQuery.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)! + (_url.wrappedValue.contains("SortBy") ? "" : "&SortBy=Name&SortOrder=Descending")) request.headerParameters["X-Emby-Authorization"] = globalData.authHeader request.contentType = "application/json" request.acceptType = "application/json" @@ -151,10 +151,17 @@ struct LibrarySearchView: View { .frame(width:100, height: 150) .cornerRadius(10).overlay( ZStack { - Text("\(String(item.ItemBadge ?? 0))") - .font(.caption) - .padding(3) - .foregroundColor(.white) + if(item.ItemBadge == 0) { + Image(systemName: "checkmark") + .font(.caption) + .padding(3) + .foregroundColor(.white) + } else { + Text("\(String(item.ItemBadge ?? 0))") + .font(.caption) + .padding(3) + .foregroundColor(.white) + } }.background(Color.black) .opacity(0.8) .cornerRadius(10.0) diff --git a/JellyfinPlayer/LibraryView.swift b/JellyfinPlayer/LibraryView.swift index de9d8ced..cb98276a 100644 --- a/JellyfinPlayer/LibraryView.swift +++ b/JellyfinPlayer/LibraryView.swift @@ -71,7 +71,7 @@ struct LibraryView: View { _library_names.wrappedValue["favorites"] = "Favorites" _library_ids.wrappedValue.append("genres") - _library_names.wrappedValue["genres"] = "Genres" + _library_names.wrappedValue["genres"] = "Genres - WIP" } } @@ -196,10 +196,17 @@ struct LibraryView: View { .frame(width:100, height: 150) .cornerRadius(10).overlay( ZStack { - Text("\(String(item.ItemBadge ?? 0))") - .font(.caption) - .padding(3) - .foregroundColor(.white) + if(item.ItemBadge == 0) { + Image(systemName: "checkmark") + .font(.caption) + .padding(3) + .foregroundColor(.white) + } else { + Text("\(String(item.ItemBadge ?? 0))") + .font(.caption) + .padding(3) + .foregroundColor(.white) + } }.background(Color.black) .opacity(0.8) .cornerRadius(10.0) diff --git a/JellyfinPlayer/MovieItemView.swift b/JellyfinPlayer/MovieItemView.swift index dc607020..cd897181 100644 --- a/JellyfinPlayer/MovieItemView.swift +++ b/JellyfinPlayer/MovieItemView.swift @@ -312,7 +312,7 @@ struct MovieItemView: View { .stroke(Color.secondary, lineWidth: 1) ) } - if(fullItem.CommunityRating != "") { + if(fullItem.CommunityRating != "0") { HStack() { Image(systemName: "star").foregroundColor(.secondary) Text(fullItem.CommunityRating).font(.subheadline) @@ -322,8 +322,7 @@ struct MovieItemView: View { .offset(x: -7, y: 0.7) } } - } - + }.frame(maxWidth: .infinity, alignment: .leading) }.offset(x: 0, y: -46).padding(.trailing, 16) }.offset(x: 16, y: 40) , alignment: .bottomLeading) @@ -512,7 +511,7 @@ struct MovieItemView: View { .stroke(Color.secondary, lineWidth: 1) ) } - if(fullItem.CommunityRating != "") { + if(fullItem.CommunityRating != "0") { HStack() { Image(systemName: "star").foregroundColor(.secondary) Text(fullItem.CommunityRating).font(.subheadline) @@ -523,9 +522,9 @@ struct MovieItemView: View { } } Spacer() - }.frame(maxWidth: .infinity) + }.frame(maxWidth: .infinity, alignment: .leading) .offset(x: 14) - }.frame(maxWidth: .infinity) + }.frame(maxWidth: .infinity, alignment: .leading) Spacer() HStack() { Button() { diff --git a/JellyfinPlayer/SeasonItemView.swift b/JellyfinPlayer/SeasonItemView.swift index 8daa4c03..10cbcdfb 100644 --- a/JellyfinPlayer/SeasonItemView.swift +++ b/JellyfinPlayer/SeasonItemView.swift @@ -218,10 +218,12 @@ struct SeasonItemView: View { .foregroundColor(.primary) .fixedSize(horizontal: false, vertical: true) .offset(y: -4) - Text(String(fullItem.ProductionYear)).font(.subheadline) - .fontWeight(.medium) - .foregroundColor(.secondary) - .lineLimit(1) + if(fullItem.ProductionYear != 0) { + Text(String(fullItem.ProductionYear)).font(.subheadline) + .fontWeight(.medium) + .foregroundColor(.secondary) + .lineLimit(1) + } }.offset(x: 0, y: 45) }.offset(x: 16, y: 22) , alignment: .bottomLeading) @@ -324,9 +326,11 @@ struct SeasonItemView: View { .frame(width: 120, height: 180) .cornerRadius(10) Spacer().frame(height: 4) - Text(String(fullItem.ProductionYear)).font(.subheadline) - .fontWeight(.medium) - .foregroundColor(.secondary) + if(fullItem.ProductionYear != 0) { + Text(String(fullItem.ProductionYear)).font(.subheadline) + .fontWeight(.medium) + .foregroundColor(.secondary) + } Spacer() } ScrollView() { diff --git a/JellyfinPlayer/SeriesItemView.swift b/JellyfinPlayer/SeriesItemView.swift index ee19b341..7934d57d 100644 --- a/JellyfinPlayer/SeriesItemView.swift +++ b/JellyfinPlayer/SeriesItemView.swift @@ -43,6 +43,11 @@ struct SeriesItemView: View { itemObj.ProductionYear = item["ProductionYear"].int ?? 0 itemObj.ItemBadge = item["UserData"]["UnplayedItemCount"].int ?? 0 itemObj.Image = item["ImageTags"]["Primary"].string ?? "" + + if(itemObj.Image == "") { + itemObj.Image = item["ParentBackdropImageTags"][0].string ?? "" + } + itemObj.ImageType = "Primary" itemObj.SeasonImage = item["ParentBackdropImageTags"][0].string ?? "" itemObj.SeasonImageType = "Backdrop" @@ -93,10 +98,17 @@ struct SeriesItemView: View { .cornerRadius(10) }.overlay( ZStack { - Text("\(String(item.ItemBadge ?? 0))") - .font(.caption) - .padding(3) - .foregroundColor(.white) + if(item.ItemBadge == 0) { + Image(systemName: "checkmark") + .font(.caption) + .padding(3) + .foregroundColor(.white) + } else { + Text("\(String(item.ItemBadge ?? 0))") + .font(.caption) + .padding(3) + .foregroundColor(.white) + } }.background(Color.black) .opacity(0.8) .cornerRadius(10.0) diff --git a/Release Notes.rtf b/Release Notes.rtf new file mode 100644 index 00000000..0db3bb8e --- /dev/null +++ b/Release Notes.rtf @@ -0,0 +1,31 @@ +{\rtf1\ansi\ansicpg1252\cocoartf2580 +\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica-Bold;\f1\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +{\*\expandedcolortbl;;} +{\*\listtable{\list\listtemplateid1\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid1\'01\uc0\u8226 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listname ;}\listid1} +{\list\listtemplateid2\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{hyphen\}}{\leveltext\leveltemplateid101\'01\uc0\u8259 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listname ;}\listid2}} +{\*\listoverridetable{\listoverride\listid1\listoverridecount0\ls1}{\listoverride\listid2\listoverridecount0\ls2}} +\margl1440\margr1440\vieww11520\viewh8400\viewkind0 +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0 + +\f0\b\fs26 \cf0 1.0.0 (Build: 8) +\f1\b0\fs24 \ +\ +\pard\tx220\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\li720\fi-720\pardirnatural\partightenfactor0 +\ls1\ilvl0\cf0 {\listtext \uc0\u8226 }Fix progress bar on ContinueWatchingView\ +{\listtext \uc0\u8226 }Sort search if no sorting active\ +{\listtext \uc0\u8226 }Limit text length on ContinueWatchingView\ +{\listtext \uc0\u8226 }Fix \'930\'94 for some production years on SeasonItemView\ +{\listtext \uc0\u8226 }Fix \'930\'94 for some CommunityRatings on EpisodeItemView & MovieItemView\ +{\listtext \uc0\u8226 }Fix placeholder image for some episodes on ContinueWatchingView\ +{\listtext \uc0\u8226 }Fix placeholder image for some seasons w/o their own images in SeriesItemView\ +{\listtext \uc0\u8226 }Show checkmarks instead of \'930\'94 on ItemBadges\ +{\listtext \uc0\u8226 }Fix having to click twice on selections in LibraryFilterView\ +{\listtext \uc0\u8226 }Fix bug where sign in page would disappear on orientation change or app relaunch\ +{\listtext \uc0\u8226 }Fix bug where some users would have access to libraries they were not supposed to see.\ +{\listtext \uc0\u8226 }Adds Dynatrace session tracking to try and find the cause for random crashes (app is FOOMing)\ +{\listtext \uc0\u8226 }Fix memory leak when viewing the main page multiple times\ +\pard\tx220\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\li720\fi-720\pardirnatural\partightenfactor0 +\ls2\ilvl0\cf0 {\listtext \uc0\u8259 }Squashed some commits in the repo as sensitive tokens were exposed for Sentry & Dynatrace\ +{\listtext \uc0\u8259 }Also adds Fastlane\ +} \ No newline at end of file