Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
folium-app
GitHub Repository: folium-app/Folium
Path: blob/a-new-beginning/Folium-iOS/SceneDelegate.swift
2 views
//
//  SceneDelegate.swift
//  Folium-iOS
//
//  Created by Jarrod Norwell on 12/6/2025.
//

import AVFoundation
import Cherry
import CombinedCores
import Cytrus
import FilesManager
import FirebaseAppCheck
import FirebaseAuth
import FirebaseCore
import Guava
import Kiwi
import Mango
import OnboardingKit
import Plum
import StoreKit
import SwiftUI
import Tomato
import UIKit

fileprivate typealias OnboardingButtonConfiguration = OnboardingController.Onboarding.Button.Configuration

class AppAttestProviderFactory: NSObject, AppCheckProviderFactory {
    func createProvider(with app: FirebaseApp) -> AppCheckProvider? {
        AppAttestProvider(app: app)
    }
}

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    var window: UIWindow? = nil
    
    let combinedCores: CombinedCores = CombinedCores()
    
    var filesManager: FilesManager = .shared
    var layoutManager: LayoutManager = .shared
    
    let cherry: Cherry = Cherry()
    let cytrus: Cytrus = Cytrus()
    let guava: Guava = Guava()
    let kiwi: Kiwi = Kiwi()
    let mango: Mango = Mango()
    let plum: Plum = Plum()
    let tomato: Tomato = Tomato()
    
    func scene(_ scene: UIScene,
               willConnectTo session: UISceneSession,
               options connectionOptions: UIScene.ConnectionOptions) {
        AppCheck.setAppCheckProviderFactory(AppAttestProviderFactory())
        FirebaseApp.configure()
        
        let task = Task {
            try await filesManager.moveOutdatedCoreDirectories()
            try await filesManager.initializeDirectories(for: Core.coresAsStrings)
            
            try AVAudioSession.sharedInstance().setCategory(.playback, options: .mixWithOthers)
            try AVAudioSession.sharedInstance().setActive(true)
        }
        
        configureDefaultUserDefaults()
        
        let applicationModel: ApplicationModel = ApplicationModel(combinedCores,
                                                                  filesManager,
                                                                  layoutManager,
                                                                  cherry,
                                                                  cytrus,
                                                                  guava,
                                                                  kiwi,
                                                                  mango,
                                                                  plum,
                                                                  tomato)
        
        guard let windowScene = scene as? UIWindowScene else {
            return
        }
        
        window = UIWindow(windowScene: windowScene)
        guard let window else {
            return
        }
        
#if targetEnvironment(simulator)
        if let url: URL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
            print(url.path(percentEncoded: false))
        }
        
        // UserDefaults.standard.removeObject(forKey: "folium.v1.38.filteredCores")
        // UserDefaults.standard.removeObject(forKey: "folium.v1.38.onboardingComplete")
#endif
        let onboardingModel: OnboardingModel = OnboardingModel(applicationModel: applicationModel)
        
        let buttons: [OnboardingButtonConfiguration] = [
            OnboardingButtonConfiguration(text: LocalisedCommon.continue) { button, controller in
                await onboardingModel.camera(controller: controller)
            }
        ]
        
        window.rootViewController = if UserDefaults.standard.bool(forKey: "folium.onboardingComplete") {
            UINavigationController(rootViewController: LibraryController(applicationModel: applicationModel))
        } else {
            OnboardingController(configuration: .init(buttons: buttons,
                                                      colours: Color.vibrantGreens,
                                                      image: UIImage(systemName: "leaf.fill"),
                                                      text: LocalisedOnboarding.folium,
                                                      secondaryText: LocalisedOnboarding.foliumSecondaryText,
                                                      tertiaryText: LocalisedOnboarding.foliumTertiaryText))
        }
   
        window.tintColor = .systemGreen
        window.makeKeyAndVisible()
        
        let updatesTask = Task(priority: .background) {
            for await result in Transaction.updates {
                switch result {
                case .unverified(let transaction, let error):
                    print(#line, transaction.productID, error.localizedDescription)
                case .verified(let transaction):
                    print(#line, transaction.productID)
                    await transaction.finish()
                }
            }
        }
        
        Task {
            switch await task.result {
            case .success:
                break
            case .failure(let error):
                print(#function, #line, error.localizedDescription)
            }
            
            _ = updatesTask
        }
    }

    func sceneDidDisconnect(_ scene: UIScene) {
        NotificationCenter.default.post(name: .applicationStateDidChange, object: ApplicationState.disconnected)
    }

    func sceneDidBecomeActive(_ scene: UIScene) {}

    func sceneWillResignActive(_ scene: UIScene) {}

    func sceneWillEnterForeground(_ scene: UIScene) {
        NotificationCenter.default.post(name: .applicationStateDidChange, object: ApplicationState.foregrounded)
    }

    func sceneDidEnterBackground(_ scene: UIScene) {
        NotificationCenter.default.post(name: .applicationStateDidChange, object: ApplicationState.backgrounded)
    }
    
    fileprivate func configureDefaultUserDefaults() {
        if #available(iOS 26, *) {
            UserDefaults.standard.set(false, forKey: "cytrus.v1.38.cpuJIT")
            UserDefaults.standard.set(false, forKey: "cytrus.v1.38.useShaderJIT")
        } else {
            UserDefaults.standard.set(false, forKey: "cytrus.v1.38.cpuJIT")
            UserDefaults.standard.set(true, forKey: "cytrus.v1.38.useShaderJIT")
        }
        
        let defaults: [String : [String : Any]] = [
            "Cytrus" : [
                // Core
                "mode" : 0,
                "cpuClockPercentage" : 100,
                "new3DS" : true,
                "lleApplets" : true,
                "deterministicAsyncOperations" : false,
                "enableRequiredOnlineLLEModules" : false,
                
                // Data Storage
                "compressCIAInstalls" : false,
                
                // System
                "regionValue" : -1,
                "pluginLoader" : false,
                "allowPluginLoader" : true,
                "stepsPerHour" : 0,
                "applyRegionFreePatch" : true,
                
                // Renderer
                "spirvShaderGeneration" : true,
                "disableSpirvOptimizer" : true,
                "useAsyncShaderCompilation" : false,
                "useAsyncPresentation" : true,
                "useHardwareShaders" : true,
                "useDiskShaderCache" : true,
                "useShadersAccurateMul" : true,
                "useNewVSync" : true,
                "resolutionFactor" : 1,
                // frame_limit
                // turbo_limit
                "textureFilter" : 0,
                "textureSampling" : 0,
                "delayGameRenderThreadUS" : 0,
                "layoutOption" : 0,
                // swap_screen
                // upright_screen
                // large_screen_proportion
                // screen_gap
                // small_screen_position
                "customTopX" : 0,
                "customTopY" : 0,
                "customTopWidth" : 800,
                "customTopHeight" : 480,
                "customBottomX" : 80,
                "customBottomY" : 500,
                "customBottomWidth" : 640,
                "customBottomHeight" : 480,
                "customSecondLayerOpacity" : 100,
                "aspectRatio" : 0,
                // screen_top_stretch
                // screen_top_leftright_padding
                // screen_top_topbottom_padding
                // screen_bottom_stretch
                // screen_bottom_leftright_padding
                // screen_bottom_topbottom_padding
                // portrait_layout_option
                // custom_portrait_top_x
                // custom_portrait_top_y
                // custom_portrait_top_width
                // custom_portrait_top_height
                // custom_portrait_bottom_x
                // custom_portrait_bottom_y
                // custom_portrait_bottom_width
                // custom_portrait_bottom_height
                // bg_red
                // bg_green
                // bg_blue
                "render3D" : 0,
                "factor3D" : 0,
                "monoRender" : 0,
                // cardboard_screen_size
                // cardboard_x_shift
                // cardboard_y_shift
                "filterMode" : true,
                "ppShaderName" : "None (builtin)",
                "anaglyphShaderName" : "Dubois (builtin)",
                "dumpTextures" : false,
                "customTextures" : false,
                "preloadTextures" : false,
                "asyncCustomLoading" : true,
                "disableRightEyeRender" : false,
                
                "audioMuted" : false,
                "audioEmulation" : 0,
                "audioStretching" : true,
                "realtimeAudio" : false,
                "volume" : 1,
                "outputType" : 6,
                "inputType" : 0,
                
                // Miscellaneous
                "logLevel" : 2,
                "webAPIURL" : "http://88.198.47.46:5000",
                
                "systemLanguage" : 1,
                "username" : "Cytrus"
            ],
            "Folium" : [
                "buttonTransparency" : 1,
                "expandButtonsBy" : 0,
                "filteredCores" : Core.cores.filter {
                    core in !core.isBeta
                }.map { core in
                    core.string
                }
            ],
            "Grape" : [
                "directBoot" : true,
                "dsiMode" : false
            ],
            "Mandarine" : [
                "height" : 640,
                "widescreen" : false,
                "width" : 480
            ],
            "Plum" : [
                "region" : 0,
                "tvStandard" : 0
            ]
        ]
        
        defaults.forEach { core, values in
            values.forEach { key, value in
                if UserDefaults.standard.value(forKey: "\(core.lowercased()).v1.38.\(key)") == nil {
                    UserDefaults.standard.set(value, forKey: "\(core.lowercased()).v1.38.\(key)")
                }
            }
        }
    }
}