summaryrefslogtreecommitdiff
path: root/Jel
diff options
context:
space:
mode:
Diffstat (limited to 'Jel')
-rw-r--r--Jel/ContentView.swift19
-rw-r--r--Jel/Controllers/AuthStateController.swift38
-rw-r--r--Jel/Controllers/DatamodelController.swift25
-rw-r--r--Jel/Controllers/JellyfinClientController.swift30
-rw-r--r--Jel/JelApp.swift13
-rw-r--r--Jel/Model.xcdatamodeld/Model.xcdatamodel/contents2
-rw-r--r--Jel/Views/AddServerView.swift109
7 files changed, 227 insertions, 9 deletions
diff --git a/Jel/ContentView.swift b/Jel/ContentView.swift
index 69609c1..2c388be 100644
--- a/Jel/ContentView.swift
+++ b/Jel/ContentView.swift
@@ -8,17 +8,24 @@
import SwiftUI
struct ContentView: View {
- var body: some View {
+ @ObservedObject var authState: AuthStateController
+
+ var body: some View {
VStack {
- Image(systemName: "globe")
- .imageScale(.large)
- .foregroundStyle(.tint)
- Text("Hello, world!")
+ if !authState.loggedIn {
+ AddServerView(authState: authState)
+ } else {
+ Text("Logged in")
+ Button("Log out") {
+ authState.loggedIn = false
+ authState.save()
+ }
+ }
}
.padding()
}
}
#Preview {
- ContentView()
+ ContentView(authState: AuthStateController())
}
diff --git a/Jel/Controllers/AuthStateController.swift b/Jel/Controllers/AuthStateController.swift
new file mode 100644
index 0000000..1629556
--- /dev/null
+++ b/Jel/Controllers/AuthStateController.swift
@@ -0,0 +1,38 @@
+//
+// AuthStateController.swift
+// Jel
+//
+// Created by zerocool on 12/11/23.
+//
+
+import Foundation
+
+class AuthStateController: ObservableObject {
+ @Published var loggedIn: Bool
+ @Published var serverUrl: URL?
+ @Published var authToken: String?
+
+ private let defaults = UserDefaults.standard
+
+ init(loggedIn: Bool = false, serverUrl: URL? = nil, authToken: String? = nil) {
+ self.loggedIn = loggedIn
+ self.serverUrl = serverUrl
+ self.authToken = authToken
+ }
+
+ func load() {
+ self.loggedIn = defaults.bool(forKey: "AuthState_loggedIn")
+ if let oldServerUrl = defaults.url(forKey: "AuthState_serverUrl") {
+ self.serverUrl = oldServerUrl
+ }
+ if let oldAuthToken = defaults.string(forKey: "AuthState_authToken") {
+ self.authToken = oldAuthToken
+ }
+ }
+
+ func save() {
+ defaults.set(self.loggedIn, forKey: "AuthState_loggedIn")
+ defaults.set(self.serverUrl, forKey: "AuthState_serverUrl")
+ defaults.set(self.authToken, forKey: "AuthState_authToken")
+ }
+}
diff --git a/Jel/Controllers/DatamodelController.swift b/Jel/Controllers/DatamodelController.swift
new file mode 100644
index 0000000..4beb173
--- /dev/null
+++ b/Jel/Controllers/DatamodelController.swift
@@ -0,0 +1,25 @@
+//
+// DatamodelController.swift
+// Jel
+//
+// Created by zerocool on 12/11/23.
+//
+
+import CoreData
+
+struct DatamodelController {
+ static let shared = DatamodelController()
+
+ let container: NSPersistentContainer
+
+ init() {
+ container = NSPersistentContainer(name: "Model")
+
+ container.loadPersistentStores(completionHandler: {(storeDescription, error) in
+ if let error = error as NSError? {
+ fatalError("Unresolved error \(error), \(error.userInfo)")
+ }
+ })
+ container.viewContext.automaticallyMergesChangesFromParent = true
+ }
+}
diff --git a/Jel/Controllers/JellyfinClientController.swift b/Jel/Controllers/JellyfinClientController.swift
new file mode 100644
index 0000000..343efe1
--- /dev/null
+++ b/Jel/Controllers/JellyfinClientController.swift
@@ -0,0 +1,30 @@
+//
+// JellyfinClientController.swift
+// Jel
+//
+// Created by zerocool on 12/12/23.
+//
+
+import Foundation
+import Get
+import JellyfinKit
+
+class JellyfinClientController {
+ let api: APIClient
+
+ init(serverUrl: URL) {
+ self.api = APIClient(
+ baseURL: serverUrl
+ )
+ }
+
+ func isJellyfinServer() async -> Bool {
+ let request = Paths.getPublicUsers
+ do {
+ try await api.send(request)
+ } catch {
+ return false
+ }
+ return true
+ }
+}
diff --git a/Jel/JelApp.swift b/Jel/JelApp.swift
index ddff76b..d70e444 100644
--- a/Jel/JelApp.swift
+++ b/Jel/JelApp.swift
@@ -9,9 +9,16 @@ import SwiftUI
@main
struct JelApp: App {
- var body: some Scene {
- WindowGroup {
- ContentView()
+ let datamodelController = DatamodelController.shared
+ let authStateController = AuthStateController()
+ var body: some Scene {
+ WindowGroup {
+ ContentView(authState: authStateController)
+ .environment(\.managedObjectContext,
+ datamodelController.container.viewContext)
+ .task {
+ authStateController.load()
}
}
+ }
}
diff --git a/Jel/Model.xcdatamodeld/Model.xcdatamodel/contents b/Jel/Model.xcdatamodeld/Model.xcdatamodel/contents
new file mode 100644
index 0000000..38ef213
--- /dev/null
+++ b/Jel/Model.xcdatamodeld/Model.xcdatamodel/contents
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="22225" systemVersion="23A344" minimumToolsVersion="Automatic" sourceLanguage="Swift" usedWithSwiftData="YES" userDefinedModelVersionIdentifier=""/> \ No newline at end of file
diff --git a/Jel/Views/AddServerView.swift b/Jel/Views/AddServerView.swift
new file mode 100644
index 0000000..beab5e7
--- /dev/null
+++ b/Jel/Views/AddServerView.swift
@@ -0,0 +1,109 @@
+//
+// AddServerView.swift
+// Jel
+//
+// Created by zerocool on 12/11/23.
+//
+
+import SwiftUI
+
+struct AddServerView: View {
+ @ObservedObject var authState: AuthStateController
+
+ @State var serverUrlString: String = ""
+ @State var urlHasError: Bool = false
+ @State var currentErrorMessage: String = ""
+ @State var loading: Bool = false
+
+ @FocusState var serverUrlIsFocused: Bool
+
+ var body: some View {
+ VStack {
+ Text("Connect to a server")
+ .font(.title)
+ HStack {
+
+ TextField(text: $serverUrlString) {
+ Text("http://jellyfin.example.com")
+ .foregroundStyle(.placeholder)
+ }
+ .keyboardType(.URL)
+ .textContentType(.URL)
+ .textFieldStyle(.roundedBorder)
+ .textInputAutocapitalization(.never)
+ .autocorrectionDisabled()
+ .focused($serverUrlIsFocused)
+ .onChange(of: serverUrlIsFocused) {
+ if serverUrlIsFocused {
+ urlHasError = false
+ }
+ }
+ .onSubmit {
+ Task {
+ await checkServerUrl()
+ }
+ }
+
+
+ if !loading {
+ Button(action: {
+ Task {
+ await checkServerUrl()
+ }
+ }) {
+ Label("Connect", systemImage: "arrow.right")
+ .labelStyle(.iconOnly)
+ }
+ .buttonStyle(.bordered)
+ .disabled(urlHasError)
+ } else {
+ ProgressView()
+ .progressViewStyle(.circular)
+ .padding()
+ }
+ }
+ .padding()
+
+ if urlHasError {
+ Text(currentErrorMessage)
+ .font(.callout)
+ .foregroundStyle(.red)
+ }
+ }
+ }
+
+ func checkServerUrl() async {
+ loading = true
+ serverUrlIsFocused = false
+ if isValidUrl(data: serverUrlString) {
+ let url = URL(string: serverUrlString)!
+ if await JellyfinClientController(serverUrl: url).isJellyfinServer() {
+ authState.serverUrl = url
+ urlHasError = false
+ } else {
+ urlHasError = true
+ currentErrorMessage = "Server not responding"
+ }
+
+ } else {
+ urlHasError = true
+ currentErrorMessage = "Invalid url"
+ }
+
+ loading = false
+ }
+
+ func isValidUrl(data: String) -> Bool {
+ if let url = URL(string: data) {
+ if UIApplication.shared.canOpenURL(url) {
+ return true
+ }
+ }
+ return false
+ }
+
+}
+
+#Preview {
+ AddServerView(authState: AuthStateController())
+}