Add server page
This commit is contained in:
parent
8a2b75dbfa
commit
5ed7d2551c
11
Info.plist
Normal file
11
Info.plist
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
@ -7,6 +7,10 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
3D1015D92B27F57400F5C29A /* AddServerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D1015D82B27F57400F5C29A /* AddServerView.swift */; };
|
||||
3D1015DC2B27F5D300F5C29A /* Model.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 3D1015DA2B27F5D300F5C29A /* Model.xcdatamodeld */; };
|
||||
3D1015DE2B27F79900F5C29A /* DatamodelController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D1015DD2B27F79900F5C29A /* DatamodelController.swift */; };
|
||||
3D1015E42B28000E00F5C29A /* AuthStateController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D1015E32B28000E00F5C29A /* AuthStateController.swift */; };
|
||||
3D9063CB2B279A310063DD2A /* JelApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D9063CA2B279A310063DD2A /* JelApp.swift */; };
|
||||
3D9063CD2B279A310063DD2A /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D9063CC2B279A310063DD2A /* ContentView.swift */; };
|
||||
3D9063CF2B279A320063DD2A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3D9063CE2B279A320063DD2A /* Assets.xcassets */; };
|
||||
@ -14,6 +18,8 @@
|
||||
3D9063DD2B279A320063DD2A /* JelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D9063DC2B279A320063DD2A /* JelTests.swift */; };
|
||||
3D9063E72B279A320063DD2A /* JelUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D9063E62B279A320063DD2A /* JelUITests.swift */; };
|
||||
3D9063E92B279A320063DD2A /* JelUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D9063E82B279A320063DD2A /* JelUITestsLaunchTests.swift */; };
|
||||
3D9064592B27E4C70063DD2A /* JellyfinKit in Frameworks */ = {isa = PBXBuildFile; productRef = 3D9064582B27E4C70063DD2A /* JellyfinKit */; };
|
||||
3DF1ED3E2B282836000AD8EA /* JellyfinClientController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DF1ED3D2B282836000AD8EA /* JellyfinClientController.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@ -33,7 +39,25 @@
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
3D9064142B279A450063DD2A /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
3D1015D42B27F49000F5C29A /* JellyfinKit */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = JellyfinKit; path = ../JellyfinKit; sourceTree = "<group>"; };
|
||||
3D1015D82B27F57400F5C29A /* AddServerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddServerView.swift; sourceTree = "<group>"; };
|
||||
3D1015DB2B27F5D300F5C29A /* Model.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Model.xcdatamodel; sourceTree = "<group>"; };
|
||||
3D1015DD2B27F79900F5C29A /* DatamodelController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatamodelController.swift; sourceTree = "<group>"; };
|
||||
3D1015E32B28000E00F5C29A /* AuthStateController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthStateController.swift; sourceTree = "<group>"; };
|
||||
3D9063C72B279A310063DD2A /* Jel.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Jel.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
3D9063CA2B279A310063DD2A /* JelApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JelApp.swift; sourceTree = "<group>"; };
|
||||
3D9063CC2B279A310063DD2A /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
||||
@ -45,6 +69,8 @@
|
||||
3D9063E22B279A320063DD2A /* JelUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = JelUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
3D9063E62B279A320063DD2A /* JelUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JelUITests.swift; sourceTree = "<group>"; };
|
||||
3D9063E82B279A320063DD2A /* JelUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JelUITestsLaunchTests.swift; sourceTree = "<group>"; };
|
||||
3DC0E5802B2832B9001CCE96 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
3DF1ED3D2B282836000AD8EA /* JellyfinClientController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JellyfinClientController.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -52,6 +78,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
3D9064592B27E4C70063DD2A /* JellyfinKit in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -72,12 +99,39 @@
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
3D1015D72B27F54A00F5C29A /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3D1015D82B27F57400F5C29A /* AddServerView.swift */,
|
||||
);
|
||||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3D1015DF2B27F8EE00F5C29A /* Controllers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3D1015DD2B27F79900F5C29A /* DatamodelController.swift */,
|
||||
3D1015E32B28000E00F5C29A /* AuthStateController.swift */,
|
||||
3DF1ED3D2B282836000AD8EA /* JellyfinClientController.swift */,
|
||||
);
|
||||
path = Controllers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3D1015E02B27FE5700F5C29A /* Models */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
);
|
||||
path = Models;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
3D9063BE2B279A310063DD2A = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3DC0E5802B2832B9001CCE96 /* Info.plist */,
|
||||
3D9063C92B279A310063DD2A /* Jel */,
|
||||
3D9063DB2B279A320063DD2A /* JelTests */,
|
||||
3D9063E52B279A320063DD2A /* JelUITests */,
|
||||
3D1015D42B27F49000F5C29A /* JellyfinKit */,
|
||||
3D9063C82B279A310063DD2A /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
@ -95,11 +149,15 @@
|
||||
3D9063C92B279A310063DD2A /* Jel */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3D1015E02B27FE5700F5C29A /* Models */,
|
||||
3D1015DF2B27F8EE00F5C29A /* Controllers */,
|
||||
3D1015D72B27F54A00F5C29A /* Views */,
|
||||
3D9063CA2B279A310063DD2A /* JelApp.swift */,
|
||||
3D9063CC2B279A310063DD2A /* ContentView.swift */,
|
||||
3D9063CE2B279A320063DD2A /* Assets.xcassets */,
|
||||
3D9063D02B279A320063DD2A /* Jel.entitlements */,
|
||||
3D9063D12B279A320063DD2A /* Preview Content */,
|
||||
3D1015DA2B27F5D300F5C29A /* Model.xcdatamodeld */,
|
||||
);
|
||||
path = Jel;
|
||||
sourceTree = "<group>";
|
||||
@ -139,12 +197,16 @@
|
||||
3D9063C32B279A310063DD2A /* Sources */,
|
||||
3D9063C42B279A310063DD2A /* Frameworks */,
|
||||
3D9063C52B279A310063DD2A /* Resources */,
|
||||
3D9064142B279A450063DD2A /* Embed Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = Jel;
|
||||
packageProductDependencies = (
|
||||
3D9064582B27E4C70063DD2A /* JellyfinKit */,
|
||||
);
|
||||
productName = Jel;
|
||||
productReference = 3D9063C72B279A310063DD2A /* Jel.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
@ -217,6 +279,8 @@
|
||||
Base,
|
||||
);
|
||||
mainGroup = 3D9063BE2B279A310063DD2A;
|
||||
packageReferences = (
|
||||
);
|
||||
productRefGroup = 3D9063C82B279A310063DD2A /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
@ -259,8 +323,13 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
3D1015DE2B27F79900F5C29A /* DatamodelController.swift in Sources */,
|
||||
3D9063CD2B279A310063DD2A /* ContentView.swift in Sources */,
|
||||
3DF1ED3E2B282836000AD8EA /* JellyfinClientController.swift in Sources */,
|
||||
3D1015D92B27F57400F5C29A /* AddServerView.swift in Sources */,
|
||||
3D9063CB2B279A310063DD2A /* JelApp.swift in Sources */,
|
||||
3D1015DC2B27F5D300F5C29A /* Model.xcdatamodeld in Sources */,
|
||||
3D1015E42B28000E00F5C29A /* AuthStateController.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -353,6 +422,7 @@
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
};
|
||||
@ -407,6 +477,7 @@
|
||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
};
|
||||
name = Release;
|
||||
@ -414,6 +485,7 @@
|
||||
3D9063ED2B279A320063DD2A /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_ENTITLEMENTS = Jel/Jel.entitlements;
|
||||
@ -424,6 +496,7 @@
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = Info.plist;
|
||||
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
|
||||
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
|
||||
"INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES;
|
||||
@ -452,6 +525,7 @@
|
||||
3D9063EE2B279A320063DD2A /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_ENTITLEMENTS = Jel/Jel.entitlements;
|
||||
@ -462,6 +536,7 @@
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = Info.plist;
|
||||
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
|
||||
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
|
||||
"INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES;
|
||||
@ -617,6 +692,26 @@
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
3D9064582B27E4C70063DD2A /* JellyfinKit */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = JellyfinKit;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
|
||||
/* Begin XCVersionGroup section */
|
||||
3D1015DA2B27F5D300F5C29A /* Model.xcdatamodeld */ = {
|
||||
isa = XCVersionGroup;
|
||||
children = (
|
||||
3D1015DB2B27F5D300F5C29A /* Model.xcdatamodel */,
|
||||
);
|
||||
currentVersion = 3D1015DB2B27F5D300F5C29A /* Model.xcdatamodel */;
|
||||
path = Model.xcdatamodeld;
|
||||
sourceTree = "<group>";
|
||||
versionGroupType = wrapper.xcdatamodel;
|
||||
};
|
||||
/* End XCVersionGroup section */
|
||||
};
|
||||
rootObject = 3D9063BF2B279A310063DD2A /* Project object */;
|
||||
}
|
||||
|
@ -0,0 +1,25 @@
|
||||
{
|
||||
"object": {
|
||||
"pins": [
|
||||
{
|
||||
"package": "Get",
|
||||
"repositoryURL": "https://github.com/kean/Get",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "12830cc64f31789ae6f4352d2d51d03a25fc3741",
|
||||
"version": "2.1.6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "URLQueryEncoder",
|
||||
"repositoryURL": "https://github.com/CreateAPI/URLQueryEncoder",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "4ce950479707ea109f229d7230ec074a133b15d7",
|
||||
"version": "0.2.1"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": 1
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Bucket
|
||||
uuid = "26628D67-145A-45DA-9022-10BF196E0789"
|
||||
type = "1"
|
||||
version = "2.0">
|
||||
</Bucket>
|
@ -9,6 +9,16 @@
|
||||
<key>orderHint</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<key>JellyfinClient.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
<key>JellyfinKit.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>2</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
|
@ -8,17 +8,24 @@
|
||||
import SwiftUI
|
||||
|
||||
struct ContentView: 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())
|
||||
}
|
||||
|
38
Jel/Controllers/AuthStateController.swift
Normal file
38
Jel/Controllers/AuthStateController.swift
Normal file
@ -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")
|
||||
}
|
||||
}
|
25
Jel/Controllers/DatamodelController.swift
Normal file
25
Jel/Controllers/DatamodelController.swift
Normal file
@ -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
|
||||
}
|
||||
}
|
30
Jel/Controllers/JellyfinClientController.swift
Normal file
30
Jel/Controllers/JellyfinClientController.swift
Normal file
@ -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
|
||||
}
|
||||
}
|
@ -9,9 +9,16 @@ import SwiftUI
|
||||
|
||||
@main
|
||||
struct JelApp: App {
|
||||
let datamodelController = DatamodelController.shared
|
||||
let authStateController = AuthStateController()
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ContentView()
|
||||
ContentView(authState: authStateController)
|
||||
.environment(\.managedObjectContext,
|
||||
datamodelController.container.viewContext)
|
||||
.task {
|
||||
authStateController.load()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
2
Jel/Model.xcdatamodeld/Model.xcdatamodel/contents
Normal file
2
Jel/Model.xcdatamodeld/Model.xcdatamodel/contents
Normal file
@ -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=""/>
|
109
Jel/Views/AddServerView.swift
Normal file
109
Jel/Views/AddServerView.swift
Normal file
@ -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())
|
||||
}
|
Loading…
Reference in New Issue
Block a user