1
0
Fork 0
pdsman-ios/PDSMan/ViewModels/PDSViewModel.swift

301 lines
No EOL
9.6 KiB
Swift

import Foundation
import SwiftUI
import Combine
@MainActor
class PDSViewModel: ObservableObject {
@Published var pdsService = PDSService()
@Published var alertItem: AlertItem?
@Published var demoMode: Bool = false
// Mock data for demo mode
private var mockUsers: [PDSUser] = []
private var mockInviteCodes: [InviteCode] = []
var errorMessage: String? {
pdsService.errorMessage
}
var isLoading: Bool {
pdsService.isLoading
}
var isAuthenticated: Bool {
get {
if demoMode {
return true // Always authenticated in demo mode
}
let value = pdsService.isAuthenticated
print("PDSViewModel: isAuthenticated getter called, value = \(value)")
return value
}
}
var users: [PDSUser] {
if demoMode {
return mockUsers
}
return pdsService.users
}
var inviteCodes: [InviteCode] {
if demoMode {
return mockInviteCodes
}
return pdsService.inviteCodes
}
// Add listeners for PDSService changes
init() {
// Subscribe to PDSService objectWillChange events
pdsService.objectWillChange.sink { [weak self] _ in
// Forward the change notification to our own objectWillChange
DispatchQueue.main.async {
self?.objectWillChange.send()
}
}
.store(in: &cancellables)
}
// Storage for cancellables
private var cancellables = Set<AnyCancellable>()
// Method to manually refresh UI data
func refreshUI() {
print("PDSViewModel: refreshUI called")
DispatchQueue.main.async {
print("PDSViewModel: sending objectWillChange notification")
self.objectWillChange.send()
if self.demoMode {
print("Demo users status: \(self.mockUsers.map { "\($0.handle): \($0.isActive)" }.joined(separator: ", "))")
}
}
}
// Enable demo mode with mock data
func enableDemoMode() {
demoMode = true
createMockData()
refreshUI()
}
// Disable demo mode
func disableDemoMode() {
demoMode = false
refreshUI()
}
// Create mock data for demo mode
private func createMockData() {
// Create mock users
mockUsers = [
PDSUser(
id: "did:plc:abcdef123456",
handle: "alice",
displayName: "Alice Smith",
description: "Product designer and developer. Working on decentralized social apps.",
joinedAt: Date().addingTimeInterval(-86400 * 30), // 30 days ago
avatar: nil,
isActive: true
),
PDSUser(
id: "did:plc:ghijkl789012",
handle: "bob",
displayName: "Bob Johnson",
description: "Software engineer. Interested in decentralized protocols and privacy.",
joinedAt: Date().addingTimeInterval(-86400 * 15), // 15 days ago
avatar: nil,
isActive: true
),
PDSUser(
id: "did:plc:mnopqr345678",
handle: "charlie",
displayName: "Charlie Brown",
description: "Community manager and content creator.",
joinedAt: Date().addingTimeInterval(-86400 * 5), // 5 days ago
avatar: nil,
isActive: false
)
]
// Create mock invite codes
mockInviteCodes = [
InviteCode(
id: "abc-123-xyz",
uses: [],
createdAt: Date().addingTimeInterval(-86400 * 20), // 20 days ago
disabled: false
),
InviteCode(
id: "def-456-uvw",
uses: [
CodeUse(usedBy: "did:plc:abcdef123456", usedAt: ISO8601DateFormatter().string(from: Date().addingTimeInterval(-86400 * 10)))
],
createdAt: Date().addingTimeInterval(-86400 * 25), // 25 days ago
disabled: false
),
InviteCode(
id: "ghi-789-rst",
uses: [],
createdAt: Date().addingTimeInterval(-86400 * 15), // 15 days ago
disabled: true
)
]
}
// Refresh invite codes with UI update
func refreshInviteCodes() async {
if demoMode {
// No need to do anything in demo mode, data is already loaded
refreshUI()
return
}
await pdsService.fetchInviteCodes()
refreshUI()
}
// Refresh users with UI update
func refreshUsers() async {
if demoMode {
// No need to do anything in demo mode, data is already loaded
refreshUI()
return
}
await pdsService.fetchUsers()
refreshUI()
}
// Disable invite code with guaranteed UI update
func disableInviteCode(_ code: String) async -> Bool {
if demoMode {
// In demo mode, just update our mock data
if let index = mockInviteCodes.firstIndex(where: { $0.id == code }) {
mockInviteCodes[index].disabled = true
refreshUI()
return true
}
return false
}
let result = await pdsService.disableInviteCode(code)
refreshUI()
return result
}
// Create invite code in demo mode
func createInviteCode() async -> InviteCode? {
if demoMode {
// Generate a random code in demo mode
let randomCode = "demo-\(Int.random(in: 100...999))-\(UUID().uuidString.prefix(4))"
let newCode = InviteCode(
id: randomCode,
uses: [],
createdAt: Date(),
disabled: false
)
mockInviteCodes.append(newCode)
refreshUI()
return newCode
}
let code = await pdsService.createInviteCode()
await refreshInviteCodes()
return code
}
// Suspend user in demo mode
func suspendUser(userId: String) async -> Bool {
if demoMode {
print("Suspending user in demo mode: \(userId)")
return await withCheckedContinuation { continuation in
DispatchQueue.main.async {
if let user = self.mockUsers.first(where: { $0.id == userId }) {
print("Found user \(user.displayName), setting isActive to false")
user.isActive = false
self.refreshUI()
continuation.resume(returning: true)
} else {
print("User not found in mockUsers: \(userId)")
continuation.resume(returning: false)
}
}
}
}
let success = await pdsService.suspendUser(userId: userId, reason: "Demo suspension")
await refreshUsers()
return success
}
// Reactivate user in demo mode
func reactivateUser(userId: String) async -> Bool {
if demoMode {
print("Reactivating user in demo mode: \(userId)")
return await withCheckedContinuation { continuation in
DispatchQueue.main.async {
if let user = self.mockUsers.first(where: { $0.id == userId }) {
print("Found user \(user.displayName), setting isActive to true")
user.isActive = true
self.refreshUI()
continuation.resume(returning: true)
} else {
print("User not found in mockUsers: \(userId)")
continuation.resume(returning: false)
}
}
}
}
let success = await pdsService.reactivateUser(userId: userId)
await refreshUsers()
return success
}
// Edit user handle in demo mode
func editUserHandle(userId: String, newHandle: String) async -> Bool {
if demoMode {
if let user = mockUsers.first(where: { $0.id == userId }) {
user.handle = newHandle
refreshUI()
return true
}
return false
}
let success = await pdsService.editUserHandle(userId: userId, newHandle: newHandle)
await refreshUsers()
return success
}
func login(serverURL: String, username: String, password: String) async {
print("PDSViewModel: login called")
if let credentials = PDSCredentials(serverURL: serverURL, username: username, password: password) {
let success = await pdsService.login(credentials: credentials)
print("PDSViewModel: login completed, success = \(success), isAuthenticated = \(pdsService.isAuthenticated)")
// Force update the view by triggering objectWillChange
objectWillChange.send()
} else {
pdsService.errorMessage = "Invalid credentials"
}
}
func logout() {
print("PDSViewModel: logout called")
if demoMode {
disableDemoMode()
} else {
pdsService.logout()
}
objectWillChange.send()
}
}
struct AlertItem: Identifiable {
let id = UUID()
let title: String
let message: String
}