Allow setting self-host backends from the iOS app
This commit is contained in:
@ -8,7 +8,7 @@ struct DebugMenuView: View {
|
||||
@EnvironmentObject var dataService: DataService
|
||||
@Binding var selectedEnvironment: AppEnvironment
|
||||
|
||||
let appEnvironments: [AppEnvironment] = [.local, .demo, .dev, .prod]
|
||||
let appEnvironments: [AppEnvironment] = [.local, .demo, .prod]
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
|
||||
@ -0,0 +1,86 @@
|
||||
import Models
|
||||
import Services
|
||||
import SwiftUI
|
||||
import Utils
|
||||
import Views
|
||||
|
||||
class SelfHostSettingsViewModel: ObservableObject {
|
||||
@State var showCreateError = false
|
||||
}
|
||||
|
||||
struct SelfHostSettingsView: View {
|
||||
@State var apiServerAddress = ""
|
||||
@State var webServerAddress = ""
|
||||
@State var ttsServerAddress = ""
|
||||
|
||||
@State var showConfirmAlert = false
|
||||
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
|
||||
@EnvironmentObject var dataService: DataService
|
||||
@StateObject var viewModel = SelfHostSettingsViewModel()
|
||||
|
||||
var allFieldsSet: Bool {
|
||||
apiServerAddress.count > 0 && webServerAddress.count > 0 && ttsServerAddress.count > 0
|
||||
}
|
||||
|
||||
var saveButton: some View {
|
||||
Button(action: {
|
||||
showConfirmAlert = true
|
||||
}, label: {
|
||||
Text("Save")
|
||||
})
|
||||
.disabled(!allFieldsSet)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
Section("API Server Base URL") {
|
||||
TextField("URL", text: $apiServerAddress, prompt: Text("https://api-prod.omnivore.app"))
|
||||
.keyboardType(.URL)
|
||||
}
|
||||
|
||||
Section("Web Server URL") {
|
||||
TextField("URL", text: $webServerAddress, prompt: Text("https://omnivore.app"))
|
||||
.keyboardType(.URL)
|
||||
}
|
||||
|
||||
Section("Text-to-speech Server URL") {
|
||||
TextField("URL", text: $ttsServerAddress, prompt: Text("https://tts.omnivore.app"))
|
||||
.keyboardType(.URL)
|
||||
}
|
||||
|
||||
Section {
|
||||
Section {
|
||||
Text("""
|
||||
Omnivore is a free and open-source project and allows self-hosting.
|
||||
|
||||
If you have chosen to deploy your own server instance, fill in the \
|
||||
above fields to connect to your private self-hosted instance.
|
||||
|
||||
[Learn more about self-hosting Omnivore](https://docs.omnivore.app/self-hosting/self-hosting.html)
|
||||
""")
|
||||
.accentColor(.blue)
|
||||
}
|
||||
}
|
||||
}
|
||||
.accentColor(.appGrayText)
|
||||
.alert(isPresented: $showConfirmAlert) {
|
||||
Alert(
|
||||
title: Text("Changing your environment settings will close the app."),
|
||||
dismissButton: .cancel(Text("Ok")) {
|
||||
AppEnvironment.setCustom(serverBaseURL: apiServerAddress, webAppBaseURL: webServerAddress, ttsBaseURL: ttsServerAddress)
|
||||
dataService.switchAppEnvironment(appEnvironment: AppEnvironment.custom)
|
||||
}
|
||||
)
|
||||
}
|
||||
.navigationViewStyle(.stack)
|
||||
.navigationTitle("Self-hosting Options")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.navigationBarItems(leading:
|
||||
Button(action: {
|
||||
dismiss()
|
||||
}, label: { Text("Cancel") }),
|
||||
trailing: saveButton)
|
||||
}
|
||||
}
|
||||
@ -18,6 +18,7 @@ struct WelcomeView: View {
|
||||
@State private var showTermsModal = false
|
||||
@State private var showPrivacyModal = false
|
||||
@State private var showEmailLoginModal = false
|
||||
@State private var showAdvancedLogin = false
|
||||
@State private var showAboutPage = false
|
||||
@State private var selectedEnvironment = AppEnvironment.initialAppEnvironment
|
||||
@State private var containerSize: CGSize = .zero
|
||||
@ -83,6 +84,8 @@ struct WelcomeView: View {
|
||||
Button("View Privacy Policy") {
|
||||
showPrivacyModal = true
|
||||
}
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.sheet(isPresented: $showPrivacyModal) {
|
||||
VStack {
|
||||
@ -235,6 +238,18 @@ struct WelcomeView: View {
|
||||
}
|
||||
footerView
|
||||
Spacer()
|
||||
|
||||
Button(
|
||||
action: { showAdvancedLogin = true },
|
||||
label: {
|
||||
Text("Self-hosting options")
|
||||
.font(Font.appCaption)
|
||||
.foregroundColor(.appGrayTextContrast)
|
||||
.underline()
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
}
|
||||
)
|
||||
.padding(.vertical)
|
||||
}
|
||||
.padding()
|
||||
.sheet(isPresented: $showEmailLoginModal) {
|
||||
@ -243,6 +258,11 @@ struct WelcomeView: View {
|
||||
.sheet(isPresented: $showDebugModal) {
|
||||
DebugMenuView(selectedEnvironment: $selectedEnvironment)
|
||||
}
|
||||
.sheet(isPresented: $showAdvancedLogin) {
|
||||
NavigationView {
|
||||
SelfHostSettingsView()
|
||||
}
|
||||
}
|
||||
.alert(deletedAccountConfirmationMessage, isPresented: $authenticator.showAppleRevokeTokenAlert) {
|
||||
Button("View Details") {
|
||||
openURL(URL(string: "https://support.apple.com/en-us/HT210426")!)
|
||||
|
||||
@ -3,10 +3,10 @@ import Utils
|
||||
|
||||
public enum AppEnvironment: String {
|
||||
case local
|
||||
case dev
|
||||
case prod
|
||||
case demo
|
||||
case test
|
||||
case custom
|
||||
|
||||
public static let initialAppEnvironment: AppEnvironment = {
|
||||
#if DEBUG
|
||||
@ -32,47 +32,68 @@ private let devWebURL = "https://web-dev.omnivore.app"
|
||||
private let demoWebURL = "https://demo.omnivore.app"
|
||||
private let prodWebURL = "https://omnivore.app"
|
||||
|
||||
private enum AppEnvironmentUserDefaultKey: String {
|
||||
case serverBaseURL = "AppEnvironment_serverBaseURL"
|
||||
case webAppBaseURL = "AppEnvironment_webAppBaseURL"
|
||||
case ttsBaseURL = "AppEnvironment_ttsBaseURL"
|
||||
}
|
||||
|
||||
public extension AppEnvironment {
|
||||
static func setCustom(serverBaseURL: String, webAppBaseURL: String, ttsBaseURL: String) {
|
||||
UserDefaults.standard.set(serverBaseURL, forKey: AppEnvironmentUserDefaultKey.serverBaseURL.rawValue)
|
||||
UserDefaults.standard.set(webAppBaseURL, forKey: AppEnvironmentUserDefaultKey.webAppBaseURL.rawValue)
|
||||
UserDefaults.standard.set(ttsBaseURL, forKey: AppEnvironmentUserDefaultKey.ttsBaseURL.rawValue)
|
||||
}
|
||||
|
||||
var graphqlPath: String {
|
||||
"\(serverBaseURL.absoluteString)/api/graphql"
|
||||
}
|
||||
|
||||
var serverBaseURL: URL {
|
||||
switch self {
|
||||
case .dev:
|
||||
return URL(string: devBaseURL)!
|
||||
case .demo:
|
||||
return URL(string: demoBaseURL)!
|
||||
case .prod:
|
||||
return URL(string: prodBaseURL)!
|
||||
case .test, .local:
|
||||
return URL(string: "http://localhost:4000")!
|
||||
case .custom:
|
||||
guard let str = UserDefaults.standard.string(forKey: AppEnvironmentUserDefaultKey.serverBaseURL.rawValue), let url = URL(string: str) else {
|
||||
fatalError("custom serverBaseURL not set")
|
||||
}
|
||||
return url
|
||||
}
|
||||
}
|
||||
|
||||
var webAppBaseURL: URL {
|
||||
switch self {
|
||||
case .dev:
|
||||
return URL(string: devWebURL)!
|
||||
case .demo:
|
||||
return URL(string: demoWebURL)!
|
||||
case .prod:
|
||||
return URL(string: prodWebURL)!
|
||||
case .test, .local:
|
||||
return URL(string: "http://localhost:3000")!
|
||||
case .custom:
|
||||
guard let str = UserDefaults.standard.string(forKey: AppEnvironmentUserDefaultKey.webAppBaseURL.rawValue), let url = URL(string: str) else {
|
||||
fatalError("custom webAppBaseURL not set")
|
||||
}
|
||||
return url
|
||||
}
|
||||
}
|
||||
|
||||
var ttsBaseURL: URL {
|
||||
switch self {
|
||||
case .dev:
|
||||
return URL(string: "notimplemented")!
|
||||
case .demo:
|
||||
return URL(string: demoTtsURL)!
|
||||
case .prod:
|
||||
return URL(string: prodTtsURL)!
|
||||
case .test, .local:
|
||||
return URL(string: "http://localhost:4000")!
|
||||
case .custom:
|
||||
guard let str = UserDefaults.standard.string(forKey: AppEnvironmentUserDefaultKey.ttsBaseURL.rawValue), let url = URL(string: str) else {
|
||||
fatalError("custom ttsBaseURL not set")
|
||||
}
|
||||
return url
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user