185 lines
5.9 KiB
Swift
185 lines
5.9 KiB
Swift
/*
|
|
* Copyright 2024 LiveKit
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
import KeychainAccess
|
|
import LiveKit
|
|
import Logging
|
|
import SwiftUI
|
|
|
|
let sync = ValueStore<Preferences>(store: Keychain(service: "io.openvidu.ios"),
|
|
key: "preferences",
|
|
default: Preferences())
|
|
|
|
struct RoomSwitchView: View {
|
|
@EnvironmentObject var appCtx: AppContext
|
|
@EnvironmentObject var roomCtx: RoomContext
|
|
@EnvironmentObject var room: Room
|
|
|
|
var shouldShowRoomView: Bool {
|
|
room.connectionState == .connected || room.connectionState == .reconnecting
|
|
}
|
|
|
|
var shouldShowConfigureUrlsView: Bool {
|
|
appCtx.applicationServerUrl.isEmpty || roomCtx.livekitUrl.isEmpty
|
|
|
|
}
|
|
|
|
func computeTitle() -> String {
|
|
if shouldShowRoomView {
|
|
var elements: [String] = []
|
|
if let roomName = room.name {
|
|
elements.append(roomName)
|
|
}
|
|
if let localParticipantName = room.localParticipant.name {
|
|
elements.append(localParticipantName)
|
|
}
|
|
if let localParticipantIdentity = room.localParticipant.identity {
|
|
elements.append(String(describing: localParticipantIdentity))
|
|
}
|
|
return elements.joined(separator: " ")
|
|
}
|
|
|
|
return "OpenVidu"
|
|
}
|
|
|
|
var body: some View {
|
|
ZStack {
|
|
Color.black
|
|
.ignoresSafeArea()
|
|
|
|
if shouldShowRoomView {
|
|
RoomView()
|
|
} else {
|
|
if shouldShowConfigureUrlsView {
|
|
ConfigureUrlsView()
|
|
} else {
|
|
ConnectView()
|
|
}
|
|
}
|
|
}
|
|
.navigationTitle(computeTitle())
|
|
}
|
|
}
|
|
|
|
// Attaches RoomContext and Room to the environment
|
|
struct RoomContextView: View {
|
|
@EnvironmentObject var appCtx: AppContext
|
|
@StateObject var roomCtx = RoomContext(store: sync)
|
|
|
|
var body: some View {
|
|
RoomSwitchView()
|
|
.environmentObject(roomCtx)
|
|
.environmentObject(roomCtx.room)
|
|
.environment(\.colorScheme, .dark)
|
|
.foregroundColor(Color.white)
|
|
.onDisappear {
|
|
print("\(String(describing: type(of: self))) onDisappear")
|
|
Task {
|
|
await roomCtx.disconnect()
|
|
}
|
|
}
|
|
.onOpenURL(perform: { url in
|
|
|
|
guard let urlComponent = URLComponents(url: url, resolvingAgainstBaseURL: false) else { return }
|
|
guard let host = url.host else { return }
|
|
|
|
let secureValue = urlComponent.queryItems?.first(where: { $0.name == "secure" })?.value?.lowercased()
|
|
let secure = ["true", "1"].contains { $0 == secureValue }
|
|
|
|
let tokenValue = urlComponent.queryItems?.first(where: { $0.name == "token" })?.value ?? ""
|
|
|
|
var builder = URLComponents()
|
|
builder.scheme = secure ? "wss" : "ws"
|
|
builder.host = host
|
|
builder.port = url.port
|
|
|
|
guard let builtUrl = builder.url?.absoluteString else { return }
|
|
|
|
print("built URL: \(builtUrl), token: \(tokenValue)")
|
|
|
|
Task { @MainActor in
|
|
roomCtx.livekitUrl = builtUrl
|
|
roomCtx.token = tokenValue
|
|
if !roomCtx.token.isEmpty {
|
|
try await roomCtx.connect()
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
extension Decimal {
|
|
mutating func round(_ scale: Int, _ roundingMode: NSDecimalNumber.RoundingMode) {
|
|
var localCopy = self
|
|
NSDecimalRound(&self, &localCopy, scale, roundingMode)
|
|
}
|
|
|
|
func rounded(_ scale: Int, _ roundingMode: NSDecimalNumber.RoundingMode) -> Decimal {
|
|
var result = Decimal()
|
|
var localCopy = self
|
|
NSDecimalRound(&result, &localCopy, scale, roundingMode)
|
|
return result
|
|
}
|
|
|
|
func remainder(of divisor: Decimal) -> Decimal {
|
|
let s = self as NSDecimalNumber
|
|
let d = divisor as NSDecimalNumber
|
|
let b = NSDecimalNumberHandler(roundingMode: .down,
|
|
scale: 0,
|
|
raiseOnExactness: false,
|
|
raiseOnOverflow: false,
|
|
raiseOnUnderflow: false,
|
|
raiseOnDivideByZero: false)
|
|
let quotient = s.dividing(by: d, withBehavior: b)
|
|
|
|
let subtractAmount = quotient.multiplying(by: d)
|
|
return s.subtracting(subtractAmount) as Decimal
|
|
}
|
|
}
|
|
|
|
@main
|
|
struct OpenViduApp: App {
|
|
@StateObject var appCtx = AppContext(store: sync)
|
|
|
|
func nearestSafeScale(for target: Int, scale: Double) -> Decimal {
|
|
let p = Decimal(sign: .plus, exponent: -3, significand: 1)
|
|
let t = Decimal(target)
|
|
var s = Decimal(scale).rounded(3, .down)
|
|
|
|
while (t * s / 2).remainder(of: 2) != 0 {
|
|
s = s + p
|
|
}
|
|
|
|
return s
|
|
}
|
|
|
|
init() {
|
|
LoggingSystem.bootstrap {
|
|
var logHandler = StreamLogHandler.standardOutput(label: $0)
|
|
logHandler.logLevel = .debug
|
|
return logHandler
|
|
}
|
|
}
|
|
|
|
var body: some Scene {
|
|
WindowGroup {
|
|
RoomContextView()
|
|
.environmentObject(appCtx)
|
|
}
|
|
.handlesExternalEvents(matching: Set(arrayLiteral: "*"))
|
|
}
|
|
}
|