mirror of
https://github.com/cranci1/Sora.git
synced 2026-04-18 23:22:08 +00:00
This commit is contained in:
parent
13d666fcf7
commit
74e03d9733
6 changed files with 160 additions and 18 deletions
|
|
@ -21,6 +21,7 @@
|
|||
133D7C932D2BE2640075467E /* Modules.swift in Sources */ = {isa = PBXBuildFile; fileRef = 133D7C892D2BE2640075467E /* Modules.swift */; };
|
||||
133D7C942D2BE2640075467E /* JSController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 133D7C8B2D2BE2640075467E /* JSController.swift */; };
|
||||
133D7C972D2BE2AF0075467E /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 133D7C962D2BE2AF0075467E /* Kingfisher */; };
|
||||
133F55BB2D33B55100E08EEA /* LibraryManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 133F55BA2D33B55100E08EEA /* LibraryManager.swift */; };
|
||||
138AA1B82D2D66FD0021F9DF /* EpisodeCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 138AA1B62D2D66FD0021F9DF /* EpisodeCell.swift */; };
|
||||
138AA1B92D2D66FD0021F9DF /* CircularProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 138AA1B72D2D66FD0021F9DF /* CircularProgressBar.swift */; };
|
||||
13DC0C462D302C7500D0F966 /* VideoPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13DC0C452D302C7500D0F966 /* VideoPlayer.swift */; };
|
||||
|
|
@ -46,6 +47,7 @@
|
|||
133D7C872D2BE2640075467E /* URLSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLSession.swift; sourceTree = "<group>"; };
|
||||
133D7C892D2BE2640075467E /* Modules.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Modules.swift; sourceTree = "<group>"; };
|
||||
133D7C8B2D2BE2640075467E /* JSController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSController.swift; sourceTree = "<group>"; };
|
||||
133F55BA2D33B55100E08EEA /* LibraryManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryManager.swift; sourceTree = "<group>"; };
|
||||
138AA1B62D2D66FD0021F9DF /* EpisodeCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EpisodeCell.swift; sourceTree = "<group>"; };
|
||||
138AA1B72D2D66FD0021F9DF /* CircularProgressBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CircularProgressBar.swift; sourceTree = "<group>"; };
|
||||
13DC0C412D2EC9BA00D0F966 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
|
||||
|
|
@ -111,10 +113,10 @@
|
|||
133D7C7B2D2BE2630075467E /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
133F55B92D33B53E00E08EEA /* LibraryView */,
|
||||
133D7C832D2BE2630075467E /* SettingsSubViews */,
|
||||
133D7C7F2D2BE2630075467E /* MediaInfoView */,
|
||||
133D7C7D2D2BE2630075467E /* HomeView.swift */,
|
||||
133D7C7E2D2BE2630075467E /* LibraryView.swift */,
|
||||
133D7C7C2D2BE2630075467E /* SearchView.swift */,
|
||||
133D7C822D2BE2630075467E /* SettingsView.swift */,
|
||||
);
|
||||
|
|
@ -173,6 +175,15 @@
|
|||
path = Loaders;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
133F55B92D33B53E00E08EEA /* LibraryView */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
133D7C7E2D2BE2630075467E /* LibraryView.swift */,
|
||||
133F55BA2D33B55100E08EEA /* LibraryManager.swift */,
|
||||
);
|
||||
path = LibraryView;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
138AA1B52D2D66EC0021F9DF /* EpisodeCell */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
|
@ -309,6 +320,7 @@
|
|||
133D7C942D2BE2640075467E /* JSController.swift in Sources */,
|
||||
133D7C922D2BE2640075467E /* URLSession.swift in Sources */,
|
||||
133D7C912D2BE2640075467E /* SettingsViewModule.swift in Sources */,
|
||||
133F55BB2D33B55100E08EEA /* LibraryManager.swift in Sources */,
|
||||
133D7C8E2D2BE2640075467E /* LibraryView.swift in Sources */,
|
||||
133D7C6E2D2BE2500075467E /* SoraApp.swift in Sources */,
|
||||
138AA1B92D2D66FD0021F9DF /* CircularProgressBar.swift in Sources */,
|
||||
|
|
|
|||
|
|
@ -11,12 +11,14 @@ import SwiftUI
|
|||
struct SoraApp: App {
|
||||
@StateObject private var settings = Settings()
|
||||
@StateObject private var moduleManager = ModuleManager()
|
||||
@StateObject private var librarykManager = LibraryManager()
|
||||
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ContentView()
|
||||
.environmentObject(moduleManager)
|
||||
.environmentObject(settings)
|
||||
.environmentObject(librarykManager)
|
||||
.accentColor(settings.accentColor)
|
||||
.onAppear {
|
||||
settings.updateAppearance()
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
//
|
||||
// LibraryView.swift
|
||||
// Sora
|
||||
//
|
||||
// Created by Francesco on 05/01/25.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct LibraryView: View {
|
||||
var body: some View {
|
||||
Text("Library View")
|
||||
.font(.largeTitle)
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
63
Sora/Views/LibraryView/LibraryManager.swift
Normal file
63
Sora/Views/LibraryView/LibraryManager.swift
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
//
|
||||
// LibraryManager.swift
|
||||
// Sora
|
||||
//
|
||||
// Created by Francesco on 12/01/25.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
struct LibraryItem: Codable, Identifiable {
|
||||
let id: UUID
|
||||
let title: String
|
||||
let imageUrl: String
|
||||
let href: String
|
||||
let moduleId: String
|
||||
let dateAdded: Date
|
||||
|
||||
init(title: String, imageUrl: String, href: String, moduleId: String) {
|
||||
self.id = UUID()
|
||||
self.title = title
|
||||
self.imageUrl = imageUrl
|
||||
self.href = href
|
||||
self.moduleId = moduleId
|
||||
self.dateAdded = Date()
|
||||
}
|
||||
}
|
||||
|
||||
class LibraryManager: ObservableObject {
|
||||
@Published var bookmarks: [LibraryItem] = []
|
||||
private let bookmarksKey = "bookmarkedItems"
|
||||
|
||||
init() {
|
||||
loadBookmarks()
|
||||
}
|
||||
|
||||
private func loadBookmarks() {
|
||||
if let data = UserDefaults.standard.data(forKey: bookmarksKey),
|
||||
let decoded = try? JSONDecoder().decode([LibraryItem].self, from: data) {
|
||||
bookmarks = decoded
|
||||
}
|
||||
}
|
||||
|
||||
private func saveBookmarks() {
|
||||
if let encoded = try? JSONEncoder().encode(bookmarks) {
|
||||
UserDefaults.standard.set(encoded, forKey: bookmarksKey)
|
||||
}
|
||||
}
|
||||
|
||||
func isBookmarked(href: String) -> Bool {
|
||||
bookmarks.contains { $0.href == href }
|
||||
}
|
||||
|
||||
func toggleBookmark(title: String, imageUrl: String, href: String, moduleId: 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)
|
||||
bookmarks.insert(bookmark, at: 0)
|
||||
}
|
||||
saveBookmarks()
|
||||
}
|
||||
}
|
||||
73
Sora/Views/LibraryView/LibraryView.swift
Normal file
73
Sora/Views/LibraryView/LibraryView.swift
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
//
|
||||
// LibraryView.swift
|
||||
// Sora
|
||||
//
|
||||
// Created by Francesco on 05/01/25.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Kingfisher
|
||||
|
||||
struct LibraryView: View {
|
||||
@EnvironmentObject private var libraryManager: LibraryManager
|
||||
@EnvironmentObject private var moduleManager: ModuleManager
|
||||
|
||||
private let columns = [
|
||||
GridItem(.adaptive(minimum: 150), spacing: 16)
|
||||
]
|
||||
|
||||
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 then find them easily here")
|
||||
.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))
|
||||
.resizable()
|
||||
.aspectRatio(2/3, contentMode: .fill)
|
||||
.cornerRadius(10)
|
||||
.frame(width: 150, height: 225)
|
||||
|
||||
KFImage(URL(string: module.metadata.iconUrl))
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 35, height: 35)
|
||||
.clipShape(Circle())
|
||||
.padding(5)
|
||||
}
|
||||
|
||||
Text(item.title)
|
||||
.font(.subheadline)
|
||||
.foregroundColor(.primary)
|
||||
.lineLimit(2)
|
||||
.multilineTextAlignment(.center)
|
||||
.padding(.horizontal, 8)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
.navigationTitle("Library")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -34,6 +34,7 @@ struct MediaInfoView: View {
|
|||
|
||||
@StateObject private var jsController = JSController()
|
||||
@EnvironmentObject var moduleManager: ModuleManager
|
||||
@EnvironmentObject private var libraryManager: LibraryManager
|
||||
|
||||
var body: some View {
|
||||
Group {
|
||||
|
|
@ -147,10 +148,17 @@ struct MediaInfoView: View {
|
|||
}
|
||||
|
||||
Button(action: {
|
||||
libraryManager.toggleBookmark(
|
||||
title: title,
|
||||
imageUrl: imageUrl,
|
||||
href: href,
|
||||
moduleId: module.id.uuidString
|
||||
)
|
||||
}) {
|
||||
Image(systemName: "bookmark")
|
||||
Image(systemName: libraryManager.isBookmarked(href: href) ? "bookmark.fill" : "bookmark")
|
||||
.resizable()
|
||||
.frame(width: 20, height: 27)
|
||||
.foregroundColor(Color.accentColor)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue