stremio/apps/ios/VMCTV/Data/SessionStore.swift
Jos Vooges | STH ac951617cb Add Live Events across API/admin/Android TV, mobile ClearKey/DASH fixes, and tvOS app.
Wire FAAB schedule-events into master-api and admin IPTV settings, add Android TV Events UI, fix mobile ClearKey/stream playback (DASH + bump 1.0.23), and scaffold the Apple TV (VMCTV) client with docs/scripts.
2026-09-18 23:34:42 +02:00

127 lines
4.8 KiB
Swift

import Foundation
@MainActor
final class SessionStore: ObservableObject {
/// Readable from ApiClient (actor) without MainActor hop.
nonisolated static let defaultApiBase = "https://master.vonas.nl"
@Published var refreshToken: String?
@Published var apiBase: String
@Published var profileId: String?
@Published var profileName: String?
@Published var profileAvatarId: String?
@Published var profileShowAvatar: Bool = true
@Published var profileAvatarUrl: String?
@Published var iptvFavoriteIds: Set<Int> = []
@Published var lastIptvStreamId: Int?
private let defaults = UserDefaults.standard
private enum Key {
static let token = "vmc.tv.refresh_token"
static let api = "vmc.tv.api_base"
static let profileId = "vmc.tv.profile_id"
static let profileName = "vmc.tv.profile_name"
static let profileAvatar = "vmc.tv.profile_avatar"
static let profileShowAvatar = "vmc.tv.profile_show_avatar"
static let profileAvatarUrl = "vmc.tv.profile_avatar_url"
static let iptvFavorites = "vmc.tv.iptv.favorites"
static let iptvLastStream = "vmc.tv.iptv.last_stream"
}
init() {
refreshToken = defaults.string(forKey: Key.token)
apiBase = defaults.string(forKey: Key.api) ?? Self.defaultApiBase
profileId = defaults.string(forKey: Key.profileId)
profileName = defaults.string(forKey: Key.profileName)
profileAvatarId = defaults.string(forKey: Key.profileAvatar)
let showRaw = defaults.string(forKey: Key.profileShowAvatar)
profileShowAvatar = showRaw != "0"
profileAvatarUrl = defaults.string(forKey: Key.profileAvatarUrl)
let favs = defaults.array(forKey: Key.iptvFavorites) as? [Int] ?? []
iptvFavoriteIds = Set(favs)
let last = defaults.integer(forKey: Key.iptvLastStream)
lastIptvStreamId = last > 0 ? last : nil
}
var isAuthed: Bool { !(refreshToken ?? "").isEmpty }
var hasProfile: Bool { !(profileId ?? "").isEmpty }
func setToken(_ token: String?) {
refreshToken = token
if let token, !token.isEmpty {
defaults.set(token, forKey: Key.token)
} else {
defaults.removeObject(forKey: Key.token)
setProfile(id: nil, name: nil, avatarId: nil)
}
}
func setApiBase(_ url: String) {
let clean = url.trimmingCharacters(in: .whitespacesAndNewlines)
.trimmingCharacters(in: CharacterSet(charactersIn: "/"))
apiBase = clean.isEmpty ? Self.defaultApiBase : clean
defaults.set(apiBase, forKey: Key.api)
}
func setProfile(
id: String?,
name: String?,
avatarId: String?,
showAvatar: Bool? = nil,
avatarUrl: String? = nil
) {
profileId = id
profileName = name
profileAvatarId = avatarId
if let id, !id.isEmpty {
defaults.set(id, forKey: Key.profileId)
if let name, !name.isEmpty { defaults.set(name, forKey: Key.profileName) }
else { defaults.removeObject(forKey: Key.profileName) }
if let avatarId, !avatarId.isEmpty { defaults.set(avatarId, forKey: Key.profileAvatar) }
else { defaults.removeObject(forKey: Key.profileAvatar) }
if let showAvatar {
profileShowAvatar = showAvatar
defaults.set(showAvatar ? "1" : "0", forKey: Key.profileShowAvatar)
}
if let avatarUrl {
if avatarUrl.isEmpty {
profileAvatarUrl = nil
defaults.removeObject(forKey: Key.profileAvatarUrl)
} else {
profileAvatarUrl = avatarUrl
defaults.set(avatarUrl, forKey: Key.profileAvatarUrl)
}
}
} else {
defaults.removeObject(forKey: Key.profileId)
defaults.removeObject(forKey: Key.profileName)
defaults.removeObject(forKey: Key.profileAvatar)
defaults.removeObject(forKey: Key.profileShowAvatar)
defaults.removeObject(forKey: Key.profileAvatarUrl)
profileName = nil
profileAvatarId = nil
profileShowAvatar = true
profileAvatarUrl = nil
}
}
func isIptvFavorite(_ streamId: Int) -> Bool {
iptvFavoriteIds.contains(streamId)
}
@discardableResult
func toggleIptvFavorite(_ streamId: Int) -> Bool {
if iptvFavoriteIds.contains(streamId) {
iptvFavoriteIds.remove(streamId)
} else {
iptvFavoriteIds.insert(streamId)
}
defaults.set(Array(iptvFavoriteIds), forKey: Key.iptvFavorites)
return iptvFavoriteIds.contains(streamId)
}
func setLastIptvStream(_ streamId: Int) {
lastIptvStreamId = streamId
defaults.set(streamId, forKey: Key.iptvLastStream)
}
}