Make iOS application work

This commit is contained in:
Syer10
2023-12-01 22:08:05 -05:00
parent c5c83b5e51
commit 0b4e201808
7 changed files with 68 additions and 66 deletions

View File

@@ -24,6 +24,7 @@ kotlin {
binaries { binaries {
framework { framework {
baseName = "i18n" baseName = "i18n"
isStatic = true
} }
} }
} }

View File

@@ -1,3 +1,5 @@
@file:OptIn(ExperimentalForeignApi::class, BetaInteropApi::class)
package ca.gosyer.jui.ios package ca.gosyer.jui.ios
import androidx.compose.animation.Crossfade import androidx.compose.animation.Crossfade
@@ -24,11 +26,13 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.Application import androidx.compose.ui.window.ComposeUIViewController
import ca.gosyer.jui.ui.base.theme.AppTheme import ca.gosyer.jui.ui.base.theme.AppTheme
import ca.gosyer.jui.ui.main.MainMenu import ca.gosyer.jui.ui.main.MainMenu
import ca.gosyer.jui.uicore.vm.ContextWrapper import ca.gosyer.jui.uicore.vm.ContextWrapper
import ca.gosyer.jui.uicore.vm.Length import ca.gosyer.jui.uicore.vm.Length
import kotlinx.cinterop.BetaInteropApi
import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.autoreleasepool import kotlinx.cinterop.autoreleasepool
import kotlinx.cinterop.cstr import kotlinx.cinterop.cstr
import kotlinx.cinterop.memScoped import kotlinx.cinterop.memScoped
@@ -37,7 +41,16 @@ import kotlinx.cinterop.useContents
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import org.lighthousegames.logging.FixedLogLevel
import org.lighthousegames.logging.KmLog
import org.lighthousegames.logging.KmLogging
import org.lighthousegames.logging.LogFactory
import org.lighthousegames.logging.LogLevel
import org.lighthousegames.logging.LogLevelController
import org.lighthousegames.logging.Logger
import org.lighthousegames.logging.TagProvider
import platform.Foundation.NSStringFromClass import platform.Foundation.NSStringFromClass
import platform.Foundation.NSThread
import platform.UIKit.UIApplication import platform.UIKit.UIApplication
import platform.UIKit.UIApplicationDelegateProtocol import platform.UIKit.UIApplicationDelegateProtocol
import platform.UIKit.UIApplicationDelegateProtocolMeta import platform.UIKit.UIApplicationDelegateProtocolMeta
@@ -45,77 +58,41 @@ import platform.UIKit.UIApplicationMain
import platform.UIKit.UIResponder import platform.UIKit.UIResponder
import platform.UIKit.UIResponderMeta import platform.UIKit.UIResponderMeta
import platform.UIKit.UIScreen import platform.UIKit.UIScreen
import platform.UIKit.UIViewController
import platform.UIKit.UIWindow import platform.UIKit.UIWindow
import platform.UIKit.safeAreaInsets import platform.UIKit.safeAreaInsets
import kotlin.time.Duration import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds import kotlin.time.Duration.Companion.seconds
fun main() { fun initializeApplication(): UIViewController {
val args = emptyArray<String>() val appComponent = AppComponent.getInstance(ContextWrapper())
memScoped {
val argc = args.size + 1 appComponent.migrations.runMigrations()
val argv = (arrayOf("skikoApp") + args).map { it.cstr.ptr }.toCValues() appComponent.appMigrations.runMigrations()
autoreleasepool {
UIApplicationMain(argc, argv, null, NSStringFromClass(SkikoAppDelegate)) appComponent.downloadService.init()
appComponent.libraryUpdateService.init()
val uiHooks = appComponent.hooks
val context = appComponent.context
return ComposeUIViewController {
CompositionLocalProvider(*uiHooks) {
AppTheme {
Box(Modifier.fillMaxSize()) {
MainMenu()
ToastOverlay(
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(bottom = 64.dp),
context = context,
)
}
}
} }
} }
} }
class SkikoAppDelegate
@OverrideInit
constructor() : UIResponder(), UIApplicationDelegateProtocol {
companion object : UIResponderMeta(), UIApplicationDelegateProtocolMeta
private var _window: UIWindow? = null
override fun window() = _window
override fun setWindow(window: UIWindow?) {
_window = window
}
private val context = ContextWrapper()
private val appComponent = AppComponent.getInstance(context)
init {
appComponent.migrations.runMigrations()
appComponent.appMigrations.runMigrations()
appComponent.downloadService.init()
appComponent.libraryUpdateService.init()
}
val uiHooks = appComponent.hooks
override fun application(
application: UIApplication,
didFinishLaunchingWithOptions: Map<Any?, *>?,
): Boolean {
window = UIWindow(frame = UIScreen.mainScreen.bounds).apply {
val insets = safeAreaInsets.useContents {
WindowInsets(left.dp, top.dp, right.dp, bottom.dp)
}
rootViewController = Application("Tachidesk-JUI") {
CompositionLocalProvider(*uiHooks) {
AppTheme {
Box(Modifier.fillMaxSize().windowInsetsPadding(insets)) {
MainMenu()
ToastOverlay(
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(bottom = 64.dp),
context = context,
)
}
}
}
}
makeKeyAndVisible()
}
return true
}
}
@Composable @Composable
fun ToastOverlay( fun ToastOverlay(
modifier: Modifier, modifier: Modifier,

View File

@@ -17,7 +17,7 @@
058557BA273AAA24004C7B11 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; 058557BA273AAA24004C7B11 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; }; 058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
2152FB032600AC8F00CF470E /* iOSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iOSApp.swift; sourceTree = "<group>"; }; 2152FB032600AC8F00CF470E /* iOSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iOSApp.swift; sourceTree = "<group>"; };
7555FF7B242A565900829871 /* .app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = .app; sourceTree = BUILT_PRODUCTS_DIR; }; 7555FF7B242A565900829871 /* .app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; name = .app; path = "Tachidesk-JUI.app"; sourceTree = BUILT_PRODUCTS_DIR; };
7555FF82242A565900829871 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; }; 7555FF82242A565900829871 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
7555FF8C242A565B00829871 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 7555FF8C242A565B00829871 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
AB3632DC29227652001CCB65 /* Config.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; }; AB3632DC29227652001CCB65 /* Config.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; };
@@ -87,6 +87,7 @@
F36B1CEB2AD83DDC00CB74D5 /* Compile Kotlin Framework */, F36B1CEB2AD83DDC00CB74D5 /* Compile Kotlin Framework */,
7555FF77242A565900829871 /* Sources */, 7555FF77242A565900829871 /* Sources */,
7555FF79242A565900829871 /* Resources */, 7555FF79242A565900829871 /* Resources */,
899476382B1ACFC30060F0C4 /* ShellScript */,
); );
buildRules = ( buildRules = (
); );
@@ -143,6 +144,23 @@
/* End PBXResourcesBuildPhase section */ /* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */
899476382B1ACFC30060F0C4 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"$SRCROOT/../gradlew\" -p \"$SRCROOT/../\" :i18n:copyFrameworkResourcesToApp \\\n -Pmoko.resources.PLATFORM_NAME=\"$PLATFORM_NAME\" \\\n -Pmoko.resources.CONFIGURATION=\"$CONFIGURATION\" \\\n -Pmoko.resources.ARCHS=\"$ARCHS\" \\\n -Pmoko.resources.BUILT_PRODUCTS_DIR=\"$BUILT_PRODUCTS_DIR\" \\\n -Pmoko.resources.CONTENTS_FOLDER_PATH=\"$CONTENTS_FOLDER_PATH\" \n";
};
F36B1CEB2AD83DDC00CB74D5 /* Compile Kotlin Framework */ = { F36B1CEB2AD83DDC00CB74D5 /* Compile Kotlin Framework */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;

View File

@@ -1,10 +1,10 @@
import UIKit import UIKit
import SwiftUI import SwiftUI
import ComposeApp import ios
struct ComposeView: UIViewControllerRepresentable { struct ComposeView: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> UIViewController { func makeUIViewController(context: Context) -> UIViewController {
MainViewControllerKt.MainViewController() MainKt.initializeApplication()
} }
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {} func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}

View File

@@ -16,6 +16,7 @@ import com.seiko.imageloader.cache.memory.maxSizePercent
import com.seiko.imageloader.component.ComponentRegistryBuilder import com.seiko.imageloader.component.ComponentRegistryBuilder
import com.seiko.imageloader.component.setupDefaultComponents import com.seiko.imageloader.component.setupDefaultComponents
import com.seiko.imageloader.option.OptionsBuilder import com.seiko.imageloader.option.OptionsBuilder
import kotlinx.cinterop.ExperimentalForeignApi
import okio.Path.Companion.toPath import okio.Path.Companion.toPath
import platform.Foundation.NSCachesDirectory import platform.Foundation.NSCachesDirectory
import platform.Foundation.NSFileManager import platform.Foundation.NSFileManager
@@ -39,6 +40,7 @@ actual fun DiskCacheBuilder.configure(
maxSizeBytes(1024 * 1024 * 150) // 150 MB maxSizeBytes(1024 * 1024 * 150) // 150 MB
} }
@OptIn(ExperimentalForeignApi::class)
private fun getCacheDir(): String { private fun getCacheDir(): String {
return NSFileManager.defaultManager.URLForDirectory( return NSFileManager.defaultManager.URLForDirectory(
NSCachesDirectory, NSCachesDirectory,

View File

@@ -7,6 +7,7 @@
package ca.gosyer.jui.ui.base.prefs package ca.gosyer.jui.ui.base.prefs
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.alloc import kotlinx.cinterop.alloc
import kotlinx.cinterop.memScoped import kotlinx.cinterop.memScoped
import kotlinx.cinterop.ptr import kotlinx.cinterop.ptr
@@ -16,6 +17,7 @@ import platform.UIKit.UIColor
fun Color.toUIColor() = UIColor(red = red.toDouble(), green = green.toDouble(), blue = blue.toDouble(), alpha = 1.0) fun Color.toUIColor() = UIColor(red = red.toDouble(), green = green.toDouble(), blue = blue.toDouble(), alpha = 1.0)
@OptIn(ExperimentalForeignApi::class)
internal actual fun Color.toHsv(): FloatArray = internal actual fun Color.toHsv(): FloatArray =
memScoped { memScoped {
val uiColor = toUIColor() val uiColor = toUIColor()

View File

@@ -15,6 +15,7 @@ import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.toComposeImageBitmap import androidx.compose.ui.graphics.toComposeImageBitmap
import androidx.compose.ui.graphics.vector.rememberVectorPainter import androidx.compose.ui.graphics.vector.rememberVectorPainter
import dev.icerock.moko.resources.ImageResource import dev.icerock.moko.resources.ImageResource
import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.get import kotlinx.cinterop.get
import org.jetbrains.skia.ColorAlphaType import org.jetbrains.skia.ColorAlphaType
import org.jetbrains.skia.ColorType import org.jetbrains.skia.ColorType
@@ -42,6 +43,7 @@ actual fun ImageResource.toPainter(): Painter {
// Taken from https://github.com/touchlab/DroidconKotlin/blob/main/shared-ui/src/iosMain/kotlin/co/touchlab/droidcon/ui/util/ToSkiaImage.kt // Taken from https://github.com/touchlab/DroidconKotlin/blob/main/shared-ui/src/iosMain/kotlin/co/touchlab/droidcon/ui/util/ToSkiaImage.kt
// TODO: Add support for remaining color spaces when the Skia library supports them. // TODO: Add support for remaining color spaces when the Skia library supports them.
@OptIn(ExperimentalForeignApi::class)
private fun UIImage.toSkiaImage(): Image? { private fun UIImage.toSkiaImage(): Image? {
val imageRef = CGImageCreateCopyWithColorSpace(this.CGImage, CGColorSpaceCreateDeviceRGB()) ?: return null val imageRef = CGImageCreateCopyWithColorSpace(this.CGImage, CGColorSpaceCreateDeviceRGB()) ?: return null