diff --git a/Sora/ContentView.swift b/Sora/ContentView.swift index 01fca9c..afbd4ea 100644 --- a/Sora/ContentView.swift +++ b/Sora/ContentView.swift @@ -11,10 +11,6 @@ import Kingfisher struct ContentView: View { var body: some View { TabView { - HomeView() - .tabItem { - Label("Home", systemImage: "house") - } LibraryView() .tabItem { Label("Library", systemImage: "books.vertical") diff --git a/Sora/Views/HomeView.swift b/Sora/Views/HomeView.swift deleted file mode 100644 index 56e51d4..0000000 --- a/Sora/Views/HomeView.swift +++ /dev/null @@ -1,353 +0,0 @@ -// -// HomeView.swift -// Sora -// -// Created by Francesco on 05/01/25. -// - -import SwiftUI -import Kingfisher - -struct HomeView: View { - @AppStorage("trackingService") private var tracingService: String = "AniList" - @State private var aniListItems: [AniListItem] = [] - @State private var trendingItems: [AniListItem] = [] - @State private var continueWatchingItems: [ContinueWatchingItem] = [] - @State private var isLoading: Bool = true - - private var currentDeviceSeasonAndYear: (season: String, year: Int) { - let currentDate = Date() - let calendar = Calendar.current - let year = calendar.component(.year, from: currentDate) - let month = calendar.component(.month, from: currentDate) - - let season: String - switch month { - case 1...3: - season = "Winter" - case 4...6: - season = "Spring" - case 7...9: - season = "Summer" - default: - season = "Fall" - } - return (season, year) - } - - private var trendingDateString: String { - let formatter = DateFormatter() - formatter.dateFormat = "EEEE, dd MMMM yyyy" - return formatter.string(from: Date()) - } - - var body: some View { - NavigationView { - ScrollView { - VStack(alignment: .leading) { - if !continueWatchingItems.isEmpty { - ContinueWatchingSection(items: $continueWatchingItems) { item in - markContinueWatchingItemAsWatched(item: item) - } removeItem: { item in - removeContinueWatchingItem(item: item) - } - } - - SeasonalSection( - title: "Seasonal of \(currentDeviceSeasonAndYear.season) \(String(format: "%d", currentDeviceSeasonAndYear.year))", - items: aniListItems, - isLoading: isLoading - ) - - TrendingSection( - title: "Trending on \(trendingDateString)", - items: trendingItems, - isLoading: isLoading - ) - } - .padding(.bottom, 16) - } - .navigationTitle("Home") - .onAppear { - fetchData() - } - .refreshable { - fetchData() - } - } - .navigationViewStyle(StackNavigationViewStyle()) - } - - private func fetchData() { - isLoading = true - continueWatchingItems = ContinueWatchingManager.shared.fetchItems() - - let fetchSeasonal: (@escaping ([AniListItem]?) -> Void) -> Void - let fetchTrending: (@escaping ([AniListItem]?) -> Void) -> Void - - if tracingService == "TMDB" { - fetchSeasonal = TMDBSeasonal.fetchTMDBSeasonal - fetchTrending = TMBDTrending.fetchTMDBTrending - } else { - fetchSeasonal = AnilistServiceSeasonalAnime().fetchSeasonalAnime - fetchTrending = AnilistServiceTrendingAnime().fetchTrendingAnime - } - - fetchSeasonal { items in - aniListItems = items ?? [] - checkLoadingState() - } - - fetchTrending { items in - trendingItems = items ?? [] - checkLoadingState() - } - } - - private func checkLoadingState() { - if !aniListItems.isEmpty && !trendingItems.isEmpty { - isLoading = false - } - } - - private func markContinueWatchingItemAsWatched(item: ContinueWatchingItem) { - let key = "lastPlayedTime_\(item.fullUrl)" - let totalKey = "totalTime_\(item.fullUrl)" - UserDefaults.standard.set(99999999.0, forKey: key) - UserDefaults.standard.set(99999999.0, forKey: totalKey) - ContinueWatchingManager.shared.remove(item: item) - - continueWatchingItems.removeAll { $0.id == item.id } - } - - private func removeContinueWatchingItem(item: ContinueWatchingItem) { - ContinueWatchingManager.shared.remove(item: item) - continueWatchingItems.removeAll { $0.id == item.id } - } -} - -struct ContinueWatchingSection: View { - @Binding var items: [ContinueWatchingItem] - var markAsWatched: (ContinueWatchingItem) -> Void - var removeItem: (ContinueWatchingItem) -> Void - - var body: some View { - LazyVStack(alignment: .leading) { - SectionHeader(title: "Continue Watching") - ScrollView(.horizontal, showsIndicators: false) { - HStack(spacing: 8) { - ForEach(Array(items.reversed())) { item in - ContinueWatchingCell(item: item) { - markAsWatched(item) - } removeItem: { - removeItem(item) - } - } - } - .padding(.horizontal, 20) - } - .frame(height: 190) - } - } -} - -struct ContinueWatchingCell: View { - let item: ContinueWatchingItem - var markAsWatched: () -> Void - var removeItem: () -> Void - - var body: some View { - Button(action: { - if UserDefaults.standard.string(forKey: "externalPlayer") == "Sora" { - let customMediaPlayer = CustomMediaPlayerViewController( - module: item.module, - urlString: item.streamUrl, - fullUrl: item.fullUrl, - title: item.mediaTitle, - episodeNumber: item.episodeNumber, - onWatchNext: { }, - subtitlesURL: item.subtitles, - episodeImageUrl: item.imageUrl - ) - customMediaPlayer.modalPresentationStyle = .fullScreen - - if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, - let rootVC = windowScene.windows.first?.rootViewController { - findTopViewController.findViewController(rootVC).present(customMediaPlayer, animated: true, completion: nil) - } - } else { - let videoPlayerViewController = VideoPlayerViewController(module: item.module) - videoPlayerViewController.streamUrl = item.streamUrl - videoPlayerViewController.fullUrl = item.fullUrl - videoPlayerViewController.episodeImageUrl = item.imageUrl - videoPlayerViewController.episodeNumber = item.episodeNumber - videoPlayerViewController.mediaTitle = item.mediaTitle - videoPlayerViewController.subtitles = item.subtitles ?? "" - videoPlayerViewController.modalPresentationStyle = .fullScreen - - if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, - let rootVC = windowScene.windows.first?.rootViewController { - findTopViewController.findViewController(rootVC).present(videoPlayerViewController, animated: true, completion: nil) - } - } - }) { - VStack(alignment: .leading) { - ZStack { - KFImage(URL(string: item.imageUrl.isEmpty ? "https://raw.githubusercontent.com/cranci1/Sora/refs/heads/main/assets/banner2.png" : item.imageUrl)) - .placeholder { - RoundedRectangle(cornerRadius: 10) - .fill(Color.gray.opacity(0.3)) - .frame(width: 240, height: 135) - .shimmering() - } - .setProcessor(RoundCornerImageProcessor(cornerRadius: 10)) - .resizable() - .aspectRatio(16/9, contentMode: .fill) - .frame(width: 240, height: 135) - .cornerRadius(10) - .clipped() - .overlay( - KFImage(URL(string: item.module.metadata.iconUrl)) - .resizable() - .frame(width: 24, height: 24) - .cornerRadius(4) - .padding(4), - alignment: .topLeading - ) - } - .overlay( - ZStack { - Rectangle() - .fill(Color.black.opacity(0.3)) - .blur(radius: 3) - .frame(height: 30) - - ProgressView(value: item.progress) - .progressViewStyle(LinearProgressViewStyle(tint: .white)) - .padding(.horizontal, 8) - .scaleEffect(x: 1, y: 1.5, anchor: .center) - }, - alignment: .bottom - ) - - VStack(alignment: .leading) { - Text("Episode \(item.episodeNumber)") - .font(.caption) - .lineLimit(1) - .foregroundColor(.secondary) - - Text(item.mediaTitle) - .font(.caption) - .lineLimit(2) - .foregroundColor(.primary) - .multilineTextAlignment(.leading) - } - } - .frame(width: 240, height: 170) - } - .contextMenu { - Button(action: { markAsWatched() }) { - Label("Mark as Watched", systemImage: "checkmark.circle") - } - Button(role: .destructive, action: { removeItem() }) { - Label("Remove Item", systemImage: "trash") - } - } - } -} - -struct SeasonalSection: View { - let title: String - let items: [AniListItem] - let isLoading: Bool - - var body: some View { - VStack(alignment: .leading) { - SectionHeader(title: title) - ScrollView(.horizontal, showsIndicators: false) { - HStack(spacing: 8) { - if isLoading { - ForEach(0..<5, id: \.self) { _ in - HomeSkeletonCell() - } - } else { - ForEach(items, id: \.id) { item in - NavigationLink(destination: AniListDetailsView(animeID: item.id)) { - AnimeItemCell(item: item) - } - } - } - } - .padding(.horizontal, 20) - } - } - } -} - -struct TrendingSection: View { - let title: String - let items: [AniListItem] - let isLoading: Bool - - var body: some View { - VStack(alignment: .leading) { - SectionHeader(title: title) - ScrollView(.horizontal, showsIndicators: false) { - HStack(spacing: 8) { - if isLoading { - ForEach(0..<5, id: \.self) { _ in - HomeSkeletonCell() - } - } else { - ForEach(items, id: \.id) { item in - NavigationLink(destination: AniListDetailsView(animeID: item.id)) { - AnimeItemCell(item: item) - } - } - } - } - .padding(.horizontal, 20) - } - } - } -} - -struct SectionHeader: View { - let title: String - - var body: some View { - Text(title) - .font(.headline) - .padding(.horizontal, 20) - .padding(.top, 8) - } -} - -struct AnimeItemCell: View { - let item: AniListItem - - var body: some View { - VStack { - KFImage(URL(string: item.coverImage.large)) - .placeholder { - RoundedRectangle(cornerRadius: 10) - .fill(Color.gray.opacity(0.3)) - .frame(width: 130, height: 195) - .shimmering() - } - .setProcessor(RoundCornerImageProcessor(cornerRadius: 10)) - .resizable() - .scaledToFill() - .frame(width: 130, height: 195) - .cornerRadius(10) - .clipped() - - Text(item.title.romaji) - .font(.caption) - .frame(width: 130) - .lineLimit(1) - .multilineTextAlignment(.center) - .foregroundColor(.primary) - } - } -} diff --git a/Sora/Views/LibraryView/LibraryManager.swift b/Sora/Views/LibraryView/LibraryManager.swift index f6474d9..19712fb 100644 --- a/Sora/Views/LibraryView/LibraryManager.swift +++ b/Sora/Views/LibraryView/LibraryManager.swift @@ -13,14 +13,16 @@ struct LibraryItem: Codable, Identifiable { let imageUrl: String let href: String let moduleId: String + let moduleName: String let dateAdded: Date - init(title: String, imageUrl: String, href: String, moduleId: String) { + init(title: String, imageUrl: String, href: String, moduleId: String, moduleName: String) { self.id = UUID() self.title = title self.imageUrl = imageUrl self.href = href self.moduleId = moduleId + self.moduleName = moduleName self.dateAdded = Date() } } @@ -55,15 +57,15 @@ class LibraryManager: ObservableObject { } } - func isBookmarked(href: String) -> Bool { + func isBookmarked(href: String, moduleName: String) -> Bool { bookmarks.contains { $0.href == href } } - func toggleBookmark(title: String, imageUrl: String, href: String, moduleId: String) { + func toggleBookmark(title: String, imageUrl: String, href: String, moduleId: String, moduleName: String) { if let index = bookmarks.firstIndex(where: { $0.href == href }) { bookmarks.remove(at: index) } else { - let bookmark = LibraryItem(title: title, imageUrl: imageUrl, href: href, moduleId: moduleId) + let bookmark = LibraryItem(title: title, imageUrl: imageUrl, href: href, moduleId: moduleId, moduleName: moduleName) bookmarks.insert(bookmark, at: 0) } saveBookmarks() diff --git a/Sora/Views/LibraryView/LibraryView.swift b/Sora/Views/LibraryView/LibraryView.swift index 108cde5..0b6480f 100644 --- a/Sora/Views/LibraryView/LibraryView.swift +++ b/Sora/Views/LibraryView/LibraryView.swift @@ -12,6 +12,8 @@ struct LibraryView: View { @EnvironmentObject private var libraryManager: LibraryManager @EnvironmentObject private var moduleManager: ModuleManager + @State private var continueWatchingItems: [ContinueWatchingItem] = [] + private let columns = [ GridItem(.adaptive(minimum: 150), spacing: 16) ] @@ -19,68 +21,252 @@ struct LibraryView: View { var body: some View { NavigationView { ScrollView { - if libraryManager.bookmarks.isEmpty { - VStack(spacing: 8) { - Image(systemName: "magazine") - .font(.largeTitle) - .foregroundColor(.secondary) - Text("No Items saved") - .font(.headline) - Text("You can bookmark items to find them easily here") - .font(.caption) - .foregroundColor(.secondary) + VStack(alignment: .leading, spacing: 32) { + Group { + Text("Continue Watching") + .font(.title2) + .bold() + .padding(.horizontal, 20) + + if continueWatchingItems.isEmpty { + Text("No items to continue watching") + .foregroundColor(.secondary) + .padding(.horizontal, 20) + } else { + ContinueWatchingSection(items: $continueWatchingItems, + markAsWatched: { item in + markContinueWatchingItemAsWatched(item: item) + }, + removeItem: { item in + removeContinueWatchingItem(item: item) + }) + } } - .padding() - .frame(maxWidth: .infinity) - } else { - LazyVGrid(columns: columns, spacing: 16) { - ForEach(libraryManager.bookmarks) { item in - if let module = moduleManager.modules.first(where: { $0.id.uuidString == item.moduleId }) { - NavigationLink(destination: MediaInfoView(title: item.title, imageUrl: item.imageUrl, href: item.href, module: module)) { - VStack { - ZStack(alignment: .bottomTrailing) { - KFImage(URL(string: item.imageUrl)) - .placeholder { - RoundedRectangle(cornerRadius: 10) - .fill(Color.gray.opacity(0.3)) + + Group { + Text("Bookmarks") + .font(.title2) + .bold() + .padding(.horizontal, 20) + + if libraryManager.bookmarks.isEmpty { + VStack(spacing: 8) { + Image(systemName: "magazine") + .font(.largeTitle) + .foregroundColor(.secondary) + Text("No Items saved") + .font(.headline) + Text("Bookmark items for easy access later") + .font(.caption) + .foregroundColor(.secondary) + } + .padding() + .frame(maxWidth: .infinity) + } else { + LazyVGrid(columns: columns, spacing: 16) { + ForEach(libraryManager.bookmarks) { item in + if let module = moduleManager.modules.first(where: { $0.id.uuidString == item.moduleId }) { + NavigationLink(destination: MediaInfoView(title: item.title, imageUrl: item.imageUrl, href: item.href, module: module)) { + VStack { + ZStack(alignment: .bottomTrailing) { + KFImage(URL(string: item.imageUrl)) + .placeholder { + RoundedRectangle(cornerRadius: 10) + .fill(Color.gray.opacity(0.3)) + .frame(width: 150, height: 225) + .shimmering() + } + .resizable() + .aspectRatio(2/3, contentMode: .fill) + .cornerRadius(10) .frame(width: 150, height: 225) - .shimmering() - } - .resizable() - .aspectRatio(2/3, contentMode: .fill) - .cornerRadius(10) - .frame(width: 150, height: 225) - - KFImage(URL(string: module.metadata.iconUrl)) - .placeholder { - Circle() - .fill(Color.gray.opacity(0.3)) + + KFImage(URL(string: module.metadata.iconUrl)) + .placeholder { + Circle() + .fill(Color.gray.opacity(0.3)) + .frame(width: 35, height: 35) + .shimmering() + } + .resizable() + .aspectRatio(contentMode: .fit) .frame(width: 35, height: 35) - .shimmering() + .clipShape(Circle()) + .padding(5) } - .resizable() - .aspectRatio(contentMode: .fit) - .frame(width: 35, height: 35) - .clipShape(Circle()) - .padding(5) + + Text(item.title) + .font(.subheadline) + .foregroundColor(.primary) + .lineLimit(2) + .multilineTextAlignment(.leading) + .padding(.horizontal, 8) + } } - - Text(item.title) - .font(.subheadline) - .foregroundColor(.primary) - .lineLimit(2) - .multilineTextAlignment(.leading) - .padding(.horizontal, 8) } } } + .padding(.horizontal, 20) } } - .padding() } + .padding(.vertical, 20) } .navigationTitle("Library") + .onAppear { + fetchContinueWatching() + } } .navigationViewStyle(StackNavigationViewStyle()) } + + private func fetchContinueWatching() { + continueWatchingItems = ContinueWatchingManager.shared.fetchItems() + } + + private func markContinueWatchingItemAsWatched(item: ContinueWatchingItem) { + let key = "lastPlayedTime_\(item.fullUrl)" + let totalKey = "totalTime_\(item.fullUrl)" + UserDefaults.standard.set(99999999.0, forKey: key) + UserDefaults.standard.set(99999999.0, forKey: totalKey) + ContinueWatchingManager.shared.remove(item: item) + continueWatchingItems.removeAll { $0.id == item.id } + } + + private func removeContinueWatchingItem(item: ContinueWatchingItem) { + ContinueWatchingManager.shared.remove(item: item) + continueWatchingItems.removeAll { $0.id == item.id } + } +} + +// ContinueWatchingSection and ContinueWatchingCell remain unchanged +struct ContinueWatchingSection: View { + @Binding var items: [ContinueWatchingItem] + var markAsWatched: (ContinueWatchingItem) -> Void + var removeItem: (ContinueWatchingItem) -> Void + + var body: some View { + VStack(alignment: .leading) { + ScrollView(.horizontal, showsIndicators: false) { + HStack(spacing: 8) { + ForEach(Array(items.reversed())) { item in + ContinueWatchingCell(item: item, + markAsWatched: { + markAsWatched(item) + }, + removeItem: { + removeItem(item) + }) + } + } + .padding(.horizontal, 20) + } + .frame(height: 190) + } + } +} + +struct ContinueWatchingCell: View { + let item: ContinueWatchingItem + var markAsWatched: () -> Void + var removeItem: () -> Void + + var body: some View { + Button(action: { + if UserDefaults.standard.string(forKey: "externalPlayer") == "Sora" { + let customMediaPlayer = CustomMediaPlayerViewController( + module: item.module, + urlString: item.streamUrl, + fullUrl: item.fullUrl, + title: item.mediaTitle, + episodeNumber: item.episodeNumber, + onWatchNext: { }, + subtitlesURL: item.subtitles, + episodeImageUrl: item.imageUrl + ) + customMediaPlayer.modalPresentationStyle = .fullScreen + + if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, + let rootVC = windowScene.windows.first?.rootViewController { + findTopViewController.findViewController(rootVC).present(customMediaPlayer, animated: true, completion: nil) + } + } else { + let videoPlayerViewController = VideoPlayerViewController(module: item.module) + videoPlayerViewController.streamUrl = item.streamUrl + videoPlayerViewController.fullUrl = item.fullUrl + videoPlayerViewController.episodeImageUrl = item.imageUrl + videoPlayerViewController.episodeNumber = item.episodeNumber + videoPlayerViewController.mediaTitle = item.mediaTitle + videoPlayerViewController.subtitles = item.subtitles ?? "" + videoPlayerViewController.modalPresentationStyle = .fullScreen + + if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, + let rootVC = windowScene.windows.first?.rootViewController { + findTopViewController.findViewController(rootVC).present(videoPlayerViewController, animated: true, completion: nil) + } + } + }) { + VStack(alignment: .leading) { + ZStack { + KFImage(URL(string: item.imageUrl.isEmpty ? "https://raw.githubusercontent.com/cranci1/Sora/refs/heads/main/assets/banner2.png" : item.imageUrl)) + .placeholder { + RoundedRectangle(cornerRadius: 10) + .fill(Color.gray.opacity(0.3)) + .frame(width: 240, height: 135) + .shimmering() + } + .setProcessor(RoundCornerImageProcessor(cornerRadius: 10)) + .resizable() + .aspectRatio(16/9, contentMode: .fill) + .frame(width: 240, height: 135) + .cornerRadius(10) + .clipped() + .overlay( + KFImage(URL(string: item.module.metadata.iconUrl)) + .resizable() + .frame(width: 24, height: 24) + .cornerRadius(4) + .padding(4), + alignment: .topLeading + ) + } + .overlay( + ZStack { + Rectangle() + .fill(Color.black.opacity(0.3)) + .blur(radius: 3) + .frame(height: 30) + + ProgressView(value: item.progress) + .progressViewStyle(LinearProgressViewStyle(tint: .white)) + .padding(.horizontal, 8) + .scaleEffect(x: 1, y: 1.5, anchor: .center) + }, + alignment: .bottom + ) + + VStack(alignment: .leading) { + Text("Episode \(item.episodeNumber)") + .font(.caption) + .lineLimit(1) + .foregroundColor(.secondary) + + Text(item.mediaTitle) + .font(.caption) + .lineLimit(2) + .foregroundColor(.primary) + .multilineTextAlignment(.leading) + } + } + .frame(width: 240, height: 170) + } + .contextMenu { + Button(action: { markAsWatched() }) { + Label("Mark as Watched", systemImage: "checkmark.circle") + } + Button(role: .destructive, action: { removeItem() }) { + Label("Remove Item", systemImage: "trash") + } + } + } } diff --git a/Sora/Views/MediaInfoView/MediaInfoView.swift b/Sora/Views/MediaInfoView/MediaInfoView.swift index 24ac21a..583b778 100644 --- a/Sora/Views/MediaInfoView/MediaInfoView.swift +++ b/Sora/Views/MediaInfoView/MediaInfoView.swift @@ -167,10 +167,11 @@ struct MediaInfoView: View { title: title, imageUrl: imageUrl, href: href, - moduleId: module.id.uuidString + moduleId: module.id.uuidString, + moduleName: module.metadata.sourceName ) }) { - Image(systemName: libraryManager.isBookmarked(href: href) ? "bookmark.fill" : "bookmark") + Image(systemName: libraryManager.isBookmarked(href: href, moduleName: module.metadata.sourceName) ? "bookmark.fill" : "bookmark") .resizable() .frame(width: 20, height: 27) .foregroundColor(Color.accentColor) diff --git a/Sora/Views/SearchView.swift b/Sora/Views/SearchView.swift index d9db01d..914b585 100644 --- a/Sora/Views/SearchView.swift +++ b/Sora/Views/SearchView.swift @@ -130,7 +130,7 @@ struct SearchView: View { .navigationBarTitleDisplayMode(.large) .toolbar { ToolbarItem(placement: .navigationBarTrailing) { - HStack { + HStack(spacing: 4) { if let selectedModule = selectedModule { Text(selectedModule.metadata.sourceName) .font(.headline) @@ -161,6 +161,8 @@ struct SearchView: View { .foregroundColor(.secondary) } } + .id("moduleMenuHStack") + .fixedSize() } } } diff --git a/Sora/Views/SettingsView/SettingsSubViews/SettingsViewGeneral.swift b/Sora/Views/SettingsView/SettingsSubViews/SettingsViewGeneral.swift index 53060dc..9c1d866 100644 --- a/Sora/Views/SettingsView/SettingsSubViews/SettingsViewGeneral.swift +++ b/Sora/Views/SettingsView/SettingsSubViews/SettingsViewGeneral.swift @@ -12,6 +12,8 @@ struct SettingsViewGeneral: View { @AppStorage("refreshModulesOnLaunch") private var refreshModulesOnLaunch: Bool = false @AppStorage("fetchEpisodeMetadata") private var fetchEpisodeMetadata: Bool = true @AppStorage("analyticsEnabled") private var analyticsEnabled: Bool = false + @AppStorage("metadataProviders") private var metadataProviders: String = "AniList" + private let metadataProvidersList = ["AniList", "TMDB"] @EnvironmentObject var settings: Settings var body: some View { @@ -52,6 +54,20 @@ struct SettingsViewGeneral: View { } Toggle("Fetch Episode metadata", isOn: $fetchEpisodeMetadata) .tint(.accentColor) + HStack { + Text("Metadata Provider") + Spacer() + Menu(metadataProviders) { + ForEach(metadataProvidersList, id: \.self) { provider in + Button(action: { + metadataProviders = provider + }) { + Text(provider) + } + } + } + + } } Section(header: Text("Modules"), footer: Text("Note that the modules will be replaced only if there is a different version string inside the JSON file.")) { diff --git a/Sora/Views/SettingsView/SettingsSubViews/SettingsViewTrackingServices.swift b/Sora/Views/SettingsView/SettingsSubViews/SettingsViewTrackingServices.swift deleted file mode 100644 index 1625986..0000000 --- a/Sora/Views/SettingsView/SettingsSubViews/SettingsViewTrackingServices.swift +++ /dev/null @@ -1,51 +0,0 @@ -// -// SettingsViewTrackingServices.swift -// Sulfur -// -// Created by Francesco on 05/03/25. -// - -import SwiftUI -import Kingfisher - -struct SettingsViewTrackingServices: View { - @AppStorage("trackingService") private var trackingService: String = "AniList" - @EnvironmentObject var settings: Settings - - var body: some View { - Form { - Section(header: Text("Tracking Service")) { - HStack { - Text("Service") - Spacer() - Menu { - Button(action: { trackingService = "AniList" }) { - HStack { - KFImage(URL(string: "https://avatars.githubusercontent.com/u/18018524?s=280&v=4")) - .resizable() - .frame(width: 20, height: 20) - Text("AniList") - } - } - Button(action: { trackingService = "TMDB" }) { - HStack { - KFImage(URL(string: "https://pbs.twimg.com/profile_images/1243623122089041920/gVZIvphd_400x400.jpg")) - .resizable() - .frame(width: 20, height: 20) - Text("TMDB") - } - } - } label: { - HStack { - KFImage(URL(string: trackingService == "TMDB" ? "https://pbs.twimg.com/profile_images/1243623122089041920/gVZIvphd_400x400.jpg" : "https://avatars.githubusercontent.com/u/18018524?s=280&v=4")) - .resizable() - .frame(width: 20, height: 20) - Text(trackingService) - } - } - } - } - } - .navigationTitle("Tracking Service") - } -} diff --git a/Sora/Views/SettingsView/SettingsView.swift b/Sora/Views/SettingsView/SettingsView.swift index e6295f2..ee43405 100644 --- a/Sora/Views/SettingsView/SettingsView.swift +++ b/Sora/Views/SettingsView/SettingsView.swift @@ -21,9 +21,6 @@ struct SettingsView: View { NavigationLink(destination: SettingsViewModule()) { Text("Modules") } - NavigationLink(destination: SettingsViewTrackingServices()) { - Text("Tracking Services") - } } Section(header: Text("Info")) { @@ -49,6 +46,19 @@ struct SettingsView: View { .foregroundColor(.secondary) } } + Button(action: { + if let url = URL(string: "https://discord.gg/x7hppDWFDZ") { + UIApplication.shared.open(url) + } + }) { + HStack { + Text("Join the Discord") + .foregroundColor(.primary) + Spacer() + Image(systemName: "safari") + .foregroundColor(.secondary) + } + } Button(action: { if let url = URL(string: "https://github.com/cranci1/Sora/issues") { UIApplication.shared.open(url) @@ -63,12 +73,12 @@ struct SettingsView: View { } } Button(action: { - if let url = URL(string: "https://discord.gg/x7hppDWFDZ") { + if let url = URL(string: "https://github.com/cranci1/Sora/blob/dev/LICENSE") { UIApplication.shared.open(url) } }) { HStack { - Text("Join the Discord") + Text("License (GPLv3.0)") .foregroundColor(.primary) Spacer() Image(systemName: "safari") @@ -76,7 +86,7 @@ struct SettingsView: View { } } } - Section(footer: Text("Running Sora 0.2.1")) {} + Section(footer: Text("Running Sora 0.2.1 - cranci1")) {} } .navigationTitle("Settings") } diff --git a/Sulfur.xcodeproj/project.pbxproj b/Sulfur.xcodeproj/project.pbxproj index d696058..b352de6 100644 --- a/Sulfur.xcodeproj/project.pbxproj +++ b/Sulfur.xcodeproj/project.pbxproj @@ -20,13 +20,11 @@ 1334FF4F2D786C9E007E289F /* TMDB-Trending.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1334FF4E2D786C9E007E289F /* TMDB-Trending.swift */; }; 1334FF522D7871B7007E289F /* TMDBItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1334FF512D7871B7007E289F /* TMDBItem.swift */; }; 1334FF542D787217007E289F /* TMDBRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1334FF532D787217007E289F /* TMDBRequest.swift */; }; - 1334FF562D7872E9007E289F /* SettingsViewTrackingServices.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1334FF552D7872E9007E289F /* SettingsViewTrackingServices.swift */; }; 133D7C6E2D2BE2500075467E /* SoraApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 133D7C6D2D2BE2500075467E /* SoraApp.swift */; }; 133D7C702D2BE2500075467E /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 133D7C6F2D2BE2500075467E /* ContentView.swift */; }; 133D7C722D2BE2520075467E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 133D7C712D2BE2520075467E /* Assets.xcassets */; }; 133D7C752D2BE2520075467E /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 133D7C742D2BE2520075467E /* Preview Assets.xcassets */; }; 133D7C8C2D2BE2640075467E /* SearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 133D7C7C2D2BE2630075467E /* SearchView.swift */; }; - 133D7C8D2D2BE2640075467E /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 133D7C7D2D2BE2630075467E /* HomeView.swift */; }; 133D7C8E2D2BE2640075467E /* LibraryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 133D7C7E2D2BE2630075467E /* LibraryView.swift */; }; 133D7C8F2D2BE2640075467E /* MediaInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 133D7C802D2BE2630075467E /* MediaInfoView.swift */; }; 133D7C902D2BE2640075467E /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 133D7C822D2BE2630075467E /* SettingsView.swift */; }; @@ -77,14 +75,12 @@ 1334FF4E2D786C9E007E289F /* TMDB-Trending.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TMDB-Trending.swift"; sourceTree = ""; }; 1334FF512D7871B7007E289F /* TMDBItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TMDBItem.swift; sourceTree = ""; }; 1334FF532D787217007E289F /* TMDBRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TMDBRequest.swift; sourceTree = ""; }; - 1334FF552D7872E9007E289F /* SettingsViewTrackingServices.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewTrackingServices.swift; sourceTree = ""; }; 133D7C6A2D2BE2500075467E /* Sulfur.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Sulfur.app; sourceTree = BUILT_PRODUCTS_DIR; }; 133D7C6D2D2BE2500075467E /* SoraApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SoraApp.swift; sourceTree = ""; }; 133D7C6F2D2BE2500075467E /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 133D7C712D2BE2520075467E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 133D7C742D2BE2520075467E /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 133D7C7C2D2BE2630075467E /* SearchView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchView.swift; sourceTree = ""; }; - 133D7C7D2D2BE2630075467E /* HomeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomeView.swift; sourceTree = ""; }; 133D7C7E2D2BE2630075467E /* LibraryView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LibraryView.swift; sourceTree = ""; }; 133D7C802D2BE2630075467E /* MediaInfoView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaInfoView.swift; sourceTree = ""; }; 133D7C822D2BE2630075467E /* SettingsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; @@ -260,7 +256,6 @@ 1399FAD22D3AB34F00E97C31 /* SettingsView */, 133F55B92D33B53E00E08EEA /* LibraryView */, 133D7C7C2D2BE2630075467E /* SearchView.swift */, - 133D7C7D2D2BE2630075467E /* HomeView.swift */, ); path = Views; sourceTree = ""; @@ -283,7 +278,6 @@ 131845F82D47C62D00CA7A54 /* SettingsViewGeneral.swift */, 135CCBE12D4D1138008B9C0E /* SettingsViewPlayer.swift */, 130C6BF92D53AB1F00DC1432 /* SettingsViewData.swift */, - 1334FF552D7872E9007E289F /* SettingsViewTrackingServices.swift */, ); path = SettingsSubViews; sourceTree = ""; @@ -525,7 +519,6 @@ 1E9FF1D32D403E49008AC100 /* SettingsViewLoggerFilter.swift in Sources */, 13EA2BD92D32D98400C1EBD7 /* NormalPlayer.swift in Sources */, 133D7C932D2BE2640075467E /* Modules.swift in Sources */, - 1334FF562D7872E9007E289F /* SettingsViewTrackingServices.swift in Sources */, 136F21B92D5B8DD8006409AC /* AniList-MediaInfo.swift in Sources */, 13DB7CC32D7D99C0004371D3 /* SubtitleSettingsManager.swift in Sources */, 133D7C702D2BE2500075467E /* ContentView.swift in Sources */, @@ -539,7 +532,6 @@ 13103E892D58A39A000F0673 /* AniListItem.swift in Sources */, 131845F92D47C62D00CA7A54 /* SettingsViewGeneral.swift in Sources */, 13103E8E2D58E04A000F0673 /* SkeletonCell.swift in Sources */, - 133D7C8D2D2BE2640075467E /* HomeView.swift in Sources */, 13D842552D45267500EBBFA6 /* DropManager.swift in Sources */, 13103E8B2D58E028000F0673 /* View.swift in Sources */, 1327FBA92D758DEA00FC6689 /* UIDevice+Model.swift in Sources */,