SimpleX-Chat/apps/ios/Shared/SimpleXApp.swift

168 lines
7.2 KiB
Swift
Raw Normal View History

//
// SimpleXApp.swift
// Shared
//
// Created by Evgeny Poberezkin on 17/01/2022.
//
import SwiftUI
import OSLog
import SimpleXChat
let logger = Logger()
@main
struct SimpleXApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
@StateObject private var chatModel = ChatModel.shared
@ObservedObject var alertManager = AlertManager.shared
2023-12-18 22:04:49 +04:00
@Environment(\.scenePhase) var scenePhase
2023-12-18 22:04:49 +04:00
@State private var enteredBackgroundAuthenticated: TimeInterval? = nil
2022-01-22 17:54:22 +00:00
init() {
DispatchQueue.global(qos: .background).sync {
haskell_init()
2023-11-22 22:12:42 +00:00
// hs_init(0, nil)
}
UserDefaults.standard.register(defaults: appDefaults)
setGroupDefaults()
registerGroupDefaults()
setDbContainer()
BGManager.shared.register()
NtfManager.shared.registerCategories()
2022-01-22 17:54:22 +00:00
}
var body: some Scene {
2023-12-18 22:04:49 +04:00
WindowGroup {
// contentAccessAuthenticationExtended has to be passed to ContentView on view initialization,
// so that it's computed by the time view renders, and not on event after rendering
ContentView(contentAccessAuthenticationExtended: !authenticationExpired())
.environmentObject(chatModel)
ios: chat themes and wallpapers (#4376) * ios: wallpapers (#4304) * ios: wallpapers * theme selection * applied theme colors and preset wallpaper * more places with background * one more * accent color * defaults * rename * background * no change to cell color * unneeded * changes * no global tint * defaults * removed unneeded class * for merging * ios: wallpapers types (#4325) * types and api * divided types per target * creating directory for wallpapers * creating wallpaper dir at launch * ios: wallpapers appearance (#4335) * appearance * changes * refactor * scale * lambda to function --------- Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> * ios: wallpapers user/chat overrides (#4345) * ios: wallpapers user/chat overrides * chat overrides * color picker updates colors correctly * fix state update * labels * background for light theme * small optimization * removed commented code * ios: enhancements to wallpapers (#4361) * ios: enhancements to wallpapers * colors for background * ios: wallpapers import/export (#4362) * ios: wallpapers import/export * comment * ios: wallpapers theme updates (#4365) * ios: wallpapers theme updates * group member background * colors * profile picture colors * unneeded * optimizations, images, state fixes * fixes * no editing of title color * rename Menus and alerts, refactor * tint applying fix * fixes * migration of accent and themes * fix updating system theme * migration changes * limiting color range * ios: wallpapers rename enum (#4384) * ios: wallpapers rename enum2 (#4385) * ios: wallpapers rename enum2 * change * colors were commented * fix build and look --------- Co-authored-by: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com>
2024-07-03 22:42:13 +01:00
.environmentObject(AppTheme.shared)
.onOpenURL { url in
logger.debug("ContentView.onOpenURL: \(url)")
chatModel.appOpenUrl = url
}
.onAppear() {
// Present screen for continue migration if it wasn't finished yet
if chatModel.migrationState != nil {
// It's important, otherwise, user may be locked in undefined state
onboardingStageDefault.set(.step1_SimpleXInfo)
chatModel.onboardingStage = onboardingStageDefault.get()
} else if kcAppPassword.get() == nil || kcSelfDestructPassword.get() == nil {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.15) {
initChatAndMigrate()
}
}
}
.onChange(of: scenePhase) { phase in
logger.debug("scenePhase was \(String(describing: scenePhase)), now \(String(describing: phase))")
AppSheetState.shared.scenePhaseActive = phase == .active
switch (phase) {
case .background:
2023-12-18 22:04:49 +04:00
// --- authentication
// see ContentView .onChange(of: scenePhase) for remaining authentication logic
if chatModel.contentViewAccessAuthenticated {
enteredBackgroundAuthenticated = ProcessInfo.processInfo.systemUptime
}
chatModel.contentViewAccessAuthenticated = false
// authentication ---
if CallController.useCallKit() && chatModel.activeCall != nil {
CallController.shared.shouldSuspendChat = true
} else {
suspendChat()
BGManager.shared.schedule()
}
NtfManager.shared.setNtfBadgeCount(chatModel.totalUnreadCountForAllUsers())
case .active:
CallController.shared.shouldSuspendChat = false
let appState = AppChatState.shared.value
2023-12-18 22:04:49 +04:00
if appState != .stopped {
startChatAndActivate {
if chatModel.chatRunning == true {
if let ntfResponse = chatModel.notificationResponse {
chatModel.notificationResponse = nil
NtfManager.shared.processNotificationResponse(ntfResponse)
}
if appState.inactive {
Task {
await updateChats()
if !chatModel.showCallView && !CallController.shared.hasActiveCalls() {
await updateCallInvitations()
}
}
}
}
}
}
default:
break
}
}
}
}
private func setDbContainer() {
// Uncomment and run once to open DB in app documents folder:
// dbContainerGroupDefault.set(.documents)
// v3DBMigrationDefault.set(.offer)
// to create database in app documents folder also uncomment:
// let legacyDatabase = true
let legacyDatabase = hasLegacyDatabase()
if legacyDatabase, case .documents = dbContainerGroupDefault.get() {
dbContainerGroupDefault.set(.documents)
setMigrationState(.offer)
logger.debug("SimpleXApp init: using legacy DB in documents folder: \(getAppDatabasePath())*.db")
} else {
dbContainerGroupDefault.set(.group)
setMigrationState(.ready)
logger.debug("SimpleXApp init: using DB in app group container: \(getAppDatabasePath())*.db")
logger.debug("SimpleXApp init: legacy DB\(legacyDatabase ? "" : " not") present")
}
}
private func setMigrationState(_ state: V3DBMigrationState) {
if case .migrated = v3DBMigrationDefault.get() { return }
v3DBMigrationDefault.set(state)
}
private func authenticationExpired() -> Bool {
2023-12-18 22:04:49 +04:00
if let enteredBackgroundAuthenticated = enteredBackgroundAuthenticated {
let delay = Double(UserDefaults.standard.integer(forKey: DEFAULT_LA_LOCK_DELAY))
2023-12-18 22:04:49 +04:00
return ProcessInfo.processInfo.systemUptime - enteredBackgroundAuthenticated >= delay
} else {
return true
}
}
private func updateChats() async {
do {
let chats = try await apiGetChatsAsync()
await MainActor.run { chatModel.updateChats(chats) }
if let id = chatModel.chatId,
let chat = chatModel.getChat(id) {
Task { await loadChat(chat: chat, clearItems: false) }
}
if let ncr = chatModel.ntfContactRequest {
await MainActor.run { chatModel.ntfContactRequest = nil }
if case let .contactRequest(contactRequest) = chatModel.getChat(ncr.chatId)?.chatInfo {
Task { await acceptContactRequest(incognito: ncr.incognito, contactRequest: contactRequest) }
}
}
} catch let error {
logger.error("apiGetChats: cannot update chats \(responseError(error))")
}
}
private func updateCallInvitations() async {
do {
try await refreshCallInvitations()
} catch let error {
logger.error("apiGetCallInvitations: cannot update call invitations \(responseError(error))")
}
}
}