Files
telegram-tui/apps/ios/TeleTuiIOS/Sources/TeleTuiIOSCore/ViewModels.swift
2026-05-20 15:43:07 +03:00

204 lines
5.7 KiB
Swift

import Foundation
import Combine
@MainActor
public final class SessionStore: ObservableObject {
@Published public private(set) var account: Account
@Published public private(set) var authState: AuthState = .waitTdlibParameters
@Published public private(set) var networkState: NetworkState = .ready
@Published public private(set) var errorMessage: String?
public let bridge: SessionBridge
public init(account: Account, bridge: SessionBridge) {
self.account = account
self.bridge = bridge
}
public func refreshAuthState() async {
do {
authState = try await bridge.authState()
errorMessage = nil
} catch {
errorMessage = error.localizedDescription
}
}
public func apply(events: [SessionEvent]) {
for event in events {
if case let .authChanged(state) = event {
authState = state
}
}
}
}
@MainActor
public final class AuthViewModel: ObservableObject {
@Published public var phone = ""
@Published public var code = ""
@Published public var password = ""
@Published public private(set) var isLoading = false
@Published public private(set) var errorMessage: String?
private let store: SessionStore
public init(store: SessionStore) {
self.store = store
}
public func submitCurrentStep() async {
isLoading = true
defer { isLoading = false }
do {
switch store.authState {
case .waitPhoneNumber:
try await store.bridge.sendPhoneNumber(phone)
case .waitCode:
try await store.bridge.sendCode(code)
case .waitPassword:
try await store.bridge.sendPassword(password)
default:
break
}
let events = try await store.bridge.pollEvents()
store.apply(events: events)
errorMessage = nil
} catch {
errorMessage = error.localizedDescription
}
}
}
@MainActor
public final class ChatListViewModel: ObservableObject {
@Published public private(set) var folders: [Folder] = []
@Published public private(set) var chats: [ChatSummary] = []
@Published public var selectedFolderId: Int32?
@Published public var searchText = ""
@Published public private(set) var isLoading = false
@Published public private(set) var errorMessage: String?
private let bridge: SessionBridge
public init(bridge: SessionBridge) {
self.bridge = bridge
}
public var filteredChats: [ChatSummary] {
guard !searchText.isEmpty else {
return chats
}
return chats.filter { chat in
chat.title.localizedCaseInsensitiveContains(searchText)
|| (chat.username?.localizedCaseInsensitiveContains(searchText) ?? false)
}
}
public func load() async {
isLoading = true
defer { isLoading = false }
do {
folders = try await bridge.loadFolders()
chats = try await bridge.loadChats(folderId: selectedFolderId)
errorMessage = nil
} catch {
errorMessage = error.localizedDescription
}
}
}
@MainActor
public final class ChatViewModel: ObservableObject {
@Published public private(set) var chat: ChatSummary
@Published public private(set) var messages: [Message] = []
@Published public var composeText: String
@Published public var replyTo: Message?
@Published public private(set) var isLoading = false
@Published public private(set) var errorMessage: String?
private let bridge: SessionBridge
public init(chat: ChatSummary, bridge: SessionBridge) {
self.chat = chat
self.bridge = bridge
self.composeText = chat.draft?.text ?? ""
}
public func load() async {
isLoading = true
defer { isLoading = false }
do {
messages = try await bridge.loadHistory(chatId: chat.id)
errorMessage = nil
} catch {
errorMessage = error.localizedDescription
}
}
public func send() async {
let text = composeText.trimmingCharacters(in: .whitespacesAndNewlines)
guard !text.isEmpty else {
return
}
do {
let sent = try await bridge.sendMessage(
chatId: chat.id,
text: text,
replyToMessageId: replyTo?.id
)
messages.append(sent)
composeText = ""
replyTo = nil
errorMessage = nil
} catch {
errorMessage = error.localizedDescription
}
}
}
@MainActor
public final class ProfileViewModel: ObservableObject {
@Published public private(set) var profile: Profile?
@Published public private(set) var isLoading = false
@Published public private(set) var errorMessage: String?
private let bridge: SessionBridge
public init(bridge: SessionBridge) {
self.bridge = bridge
}
public func load(chatId: Int64) async {
isLoading = true
defer { isLoading = false }
do {
profile = try await bridge.openProfile(chatId: chatId)
errorMessage = nil
} catch {
errorMessage = error.localizedDescription
}
}
}
@MainActor
public final class MediaViewModel: ObservableObject {
@Published public private(set) var activePhotoPath: String?
@Published public private(set) var activeVoicePath: String?
public init() {}
public func showPhoto(path: String) {
activePhotoPath = path
}
public func showVoice(path: String) {
activeVoicePath = path
}
}