7e1c37db7f
The previous commit hardcoded https://preview.org-social.org/ as the preview service for the Share button on each post. Now both the toggle and the URL are user-configurable: - New UserDefaults keys, registered with sensible defaults in OrgSocialApp.init: previewServiceEnabled (true), previewServiceURL ("https://preview.org-social.org/"). - SettingsViewModel exposes both as @Observable properties, persists them in saveIfValid, and adds previewServiceValid -> canSave so the URL must be a valid HTTP(S) URL when the toggle is on (when off the field is irrelevant and validation passes). - SettingsView gets a new "Sharing" section between Relay and Migration, with a Toggle and a conditionally-shown Preview URL field. Field disappears entirely when the toggle is off. - PostRowView reads previewServiceEnabled at render time, hiding the ShareLink when off, and reads previewServiceURL when building the share URL (tolerates trailing slash both ways). Bundle behaviour: existing installs default to "on" + the public preview service, so nothing changes for current users until they opt out.
158 lines
6.4 KiB
Swift
158 lines
6.4 KiB
Swift
import Foundation
|
|
import Observation
|
|
import OrgSocialKit
|
|
|
|
@Observable @MainActor
|
|
final class SettingsViewModel {
|
|
|
|
// Common
|
|
var uploadMethod: UploadMethod
|
|
var publicFeedURL: String
|
|
var relayURL: String
|
|
var maxPostAgeDays: Int
|
|
var useRelay: Bool
|
|
var showAllRelayFeeds: Bool
|
|
|
|
// Sharing — preview service used by the per-post Share button.
|
|
var previewServiceEnabled: Bool
|
|
var previewServiceURL: String
|
|
|
|
// VFile
|
|
var vfileURL: String
|
|
|
|
// GitHub
|
|
var githubToken: String
|
|
var githubOwner: String
|
|
var githubRepo: String
|
|
var githubPath: String
|
|
var githubBranch: String
|
|
|
|
// Codeberg
|
|
var codebergToken: String
|
|
var codebergOwner: String
|
|
var codebergRepo: String
|
|
var codebergPath: String
|
|
var codebergBranch: String
|
|
var codebergInstance: String
|
|
|
|
// WebDAV
|
|
var webdavURL: String
|
|
var webdavUsername: String
|
|
var webdavPassword: String
|
|
|
|
private let d = UserDefaults.standard
|
|
|
|
init() {
|
|
uploadMethod = UploadMethod(rawValue: UserDefaults.standard.string(forKey: "uploadMethod") ?? "") ?? .vfile
|
|
publicFeedURL = UserDefaults.standard.string(forKey: "publicFeedURL") ?? ""
|
|
relayURL = UserDefaults.standard.string(forKey: "relayURL") ?? "https://relay.org-social.org"
|
|
maxPostAgeDays = UserDefaults.standard.integer(forKey: "maxPostAgeDays").nonZero ?? 7
|
|
useRelay = UserDefaults.standard.object(forKey: "useRelay") as? Bool ?? true
|
|
showAllRelayFeeds = UserDefaults.standard.object(forKey: "showAllRelayFeeds") as? Bool ?? false
|
|
previewServiceEnabled = UserDefaults.standard.object(forKey: "previewServiceEnabled") as? Bool ?? true
|
|
previewServiceURL = UserDefaults.standard.string(forKey: "previewServiceURL") ?? "https://preview.org-social.org/"
|
|
|
|
vfileURL = UserDefaults.standard.string(forKey: "vfileURL") ?? ""
|
|
|
|
githubToken = UserDefaults.standard.string(forKey: "githubToken") ?? ""
|
|
githubOwner = UserDefaults.standard.string(forKey: "githubOwner") ?? ""
|
|
githubRepo = UserDefaults.standard.string(forKey: "githubRepo") ?? ""
|
|
githubPath = UserDefaults.standard.string(forKey: "githubPath").nilIfEmpty ?? "social.org"
|
|
githubBranch = UserDefaults.standard.string(forKey: "githubBranch").nilIfEmpty ?? "main"
|
|
|
|
codebergToken = UserDefaults.standard.string(forKey: "codebergToken") ?? ""
|
|
codebergOwner = UserDefaults.standard.string(forKey: "codebergOwner") ?? ""
|
|
codebergRepo = UserDefaults.standard.string(forKey: "codebergRepo") ?? ""
|
|
codebergPath = UserDefaults.standard.string(forKey: "codebergPath").nilIfEmpty ?? "social.org"
|
|
codebergBranch = UserDefaults.standard.string(forKey: "codebergBranch").nilIfEmpty ?? "main"
|
|
codebergInstance = UserDefaults.standard.string(forKey: "codebergInstance").nilIfEmpty ?? "https://codeberg.org"
|
|
|
|
webdavURL = UserDefaults.standard.string(forKey: "webdavURL") ?? ""
|
|
webdavUsername = UserDefaults.standard.string(forKey: "webdavUsername") ?? ""
|
|
webdavPassword = UserDefaults.standard.string(forKey: "webdavPassword") ?? ""
|
|
}
|
|
|
|
// MARK: - Validation
|
|
|
|
var publicFeedURLValid: Bool { isHTTPURL(publicFeedURL) }
|
|
var relayURLValid: Bool { isHTTPURL(relayURL) }
|
|
|
|
var uploadConfigValid: Bool {
|
|
switch uploadMethod {
|
|
case .vfile: return isHTTPURL(vfileURL)
|
|
case .github: return !githubToken.isEmpty && !githubOwner.isEmpty && !githubRepo.isEmpty
|
|
case .codeberg: return !codebergToken.isEmpty && !codebergOwner.isEmpty && !codebergRepo.isEmpty
|
|
case .webdav: return isHTTPURL(webdavURL)
|
|
}
|
|
}
|
|
|
|
/// When the preview toggle is off the URL is irrelevant (the field is
|
|
/// disabled), so we only require validity in the on state.
|
|
var previewServiceValid: Bool { !previewServiceEnabled || isHTTPURL(previewServiceURL) }
|
|
|
|
var canSave: Bool { publicFeedURLValid && relayURLValid && uploadConfigValid && previewServiceValid }
|
|
|
|
// MARK: - Derived public URL hints
|
|
|
|
var githubDerivedPublicURL: String {
|
|
guard !githubOwner.isEmpty, !githubRepo.isEmpty else { return "" }
|
|
let p = githubPath.isEmpty ? "social.org" : githubPath
|
|
let b = githubBranch.isEmpty ? "main" : githubBranch
|
|
return "https://raw.githubusercontent.com/\(githubOwner)/\(githubRepo)/\(b)/\(p)"
|
|
}
|
|
|
|
var codebergDerivedPublicURL: String {
|
|
guard !codebergOwner.isEmpty, !codebergRepo.isEmpty else { return "" }
|
|
let inst = codebergInstance.isEmpty ? "https://codeberg.org" : codebergInstance
|
|
let p = codebergPath.isEmpty ? "social.org" : codebergPath
|
|
let b = codebergBranch.isEmpty ? "main" : codebergBranch
|
|
return "\(inst)/\(codebergOwner)/\(codebergRepo)/raw/branch/\(b)/\(p)"
|
|
}
|
|
|
|
// MARK: - Save
|
|
|
|
func saveIfValid() {
|
|
guard canSave else { return }
|
|
d.set(uploadMethod.rawValue, forKey: "uploadMethod")
|
|
d.set(publicFeedURL, forKey: "publicFeedURL")
|
|
d.set(relayURL, forKey: "relayURL")
|
|
d.set(maxPostAgeDays, forKey: "maxPostAgeDays")
|
|
d.set(useRelay, forKey: "useRelay")
|
|
d.set(showAllRelayFeeds, forKey: "showAllRelayFeeds")
|
|
d.set(previewServiceEnabled, forKey: "previewServiceEnabled")
|
|
d.set(previewServiceURL, forKey: "previewServiceURL")
|
|
|
|
d.set(vfileURL, forKey: "vfileURL")
|
|
|
|
d.set(githubToken, forKey: "githubToken")
|
|
d.set(githubOwner, forKey: "githubOwner")
|
|
d.set(githubRepo, forKey: "githubRepo")
|
|
d.set(githubPath, forKey: "githubPath")
|
|
d.set(githubBranch, forKey: "githubBranch")
|
|
|
|
d.set(codebergToken, forKey: "codebergToken")
|
|
d.set(codebergOwner, forKey: "codebergOwner")
|
|
d.set(codebergRepo, forKey: "codebergRepo")
|
|
d.set(codebergPath, forKey: "codebergPath")
|
|
d.set(codebergBranch, forKey: "codebergBranch")
|
|
d.set(codebergInstance, forKey: "codebergInstance")
|
|
|
|
d.set(webdavURL, forKey: "webdavURL")
|
|
d.set(webdavUsername, forKey: "webdavUsername")
|
|
d.set(webdavPassword, forKey: "webdavPassword")
|
|
}
|
|
|
|
private func isHTTPURL(_ raw: String) -> Bool {
|
|
guard let url = URL(string: raw) else { return false }
|
|
return url.scheme?.hasPrefix("http") == true && url.host != nil
|
|
}
|
|
}
|
|
|
|
private extension Int {
|
|
var nonZero: Int? { self == 0 ? nil : self }
|
|
}
|
|
|
|
private extension String? {
|
|
var nilIfEmpty: String? { self?.isEmpty == false ? self : nil }
|
|
}
|