a scrappy gimbal that insults you in shakespearean english

iOS work, Gemini, TTS

+487 -152
+6
mobile/composeApp/build.gradle.kts
··· 46 implementation(libs.androidx.lifecycle.runtime.compose) 47 implementation(libs.camerak) 48 implementation(libs.androidx.graphics.shapes) 49 } 50 } 51 }
··· 46 implementation(libs.androidx.lifecycle.runtime.compose) 47 implementation(libs.camerak) 48 implementation(libs.androidx.graphics.shapes) 49 + implementation(libs.generativeai.google) 50 + implementation(libs.kotlinx.coroutines.core) 51 + implementation(libs.tts) 52 + 53 + // Optional: Extensions for Compose 54 + implementation(libs.tts.compose) 55 } 56 } 57 }
+6
mobile/composeApp/src/androidMain/AndroidManifest.xml
··· 28 <category android:name="android.intent.category.LAUNCHER" /> 29 </intent-filter> 30 </activity> 31 </application> 32 33 </manifest>
··· 28 <category android:name="android.intent.category.LAUNCHER" /> 29 </intent-filter> 30 </activity> 31 + 32 </application> 33 + <queries> 34 + <intent> 35 + <action android:name="android.intent.action.TTS_SERVICE" /> 36 + </intent> 37 + </queries> 38 39 </manifest>
+8 -9
mobile/composeApp/src/androidMain/kotlin/com/paytondeveloper/myrus_mobile/MLFace.android.kt
··· 35 import java.io.FileOutputStream 36 import java.io.IOException 37 38 - actual fun CameraController.getResolution(): Size? { 39 - val field = this::class.java.getDeclaredField("imageCapture") 40 - field.isAccessible = true 41 - val imgCapture = field.get(this) as ImageCapture? 42 - val res = imgCapture?.resolutionInfo?.resolution 43 - return if (res != null) Size(width = res.width.toFloat(), height = res.height.toFloat()) else null 44 - 45 - } 46 47 actual fun analyzeImage(img: ByteArray, callback: (Rect, Size) -> Unit) { 48 // println("res2: ${saveByteArrayToMediaStore(AppInfo.app.applicationContext, img)}") ··· 61 AppInfo.canDetectFace = true 62 res.result.forEach { 63 println("FACE @ ${it.boundingBox.top}") 64 - 65 callback(Rect(it.boundingBox.top.toFloat(), it.boundingBox.left.toFloat(), it.boundingBox.bottom.toFloat(), it.boundingBox.right.toFloat()), Size(width = bitmap.width.toFloat(), height = bitmap.height.toFloat())) 66 } 67 }
··· 35 import java.io.FileOutputStream 36 import java.io.IOException 37 38 + //actual fun CameraController.getResolution(): Size? { 39 + // val field = this::class.java.getDeclaredField("imageCapture") 40 + // field.isAccessible = true 41 + // val imgCapture = field.get(this) as ImageCapture? 42 + // val res = imgCapture?.resolutionInfo?.resolution 43 + // return if (res != null) Size(width = res.width.toFloat(), height = res.height.toFloat()) else null 44 + // 45 + //} 46 47 actual fun analyzeImage(img: ByteArray, callback: (Rect, Size) -> Unit) { 48 // println("res2: ${saveByteArrayToMediaStore(AppInfo.app.applicationContext, img)}") ··· 61 AppInfo.canDetectFace = true 62 res.result.forEach { 63 println("FACE @ ${it.boundingBox.top}") 64 callback(Rect(it.boundingBox.top.toFloat(), it.boundingBox.left.toFloat(), it.boundingBox.bottom.toFloat(), it.boundingBox.right.toFloat()), Size(width = bitmap.width.toFloat(), height = bitmap.height.toFloat())) 65 } 66 }
+75
mobile/composeApp/src/androidMain/kotlin/com/paytondeveloper/myrus_mobile/MainActivity.kt
··· 1 package com.paytondeveloper.myrus_mobile 2 3 import android.app.Activity 4 import android.app.Application 5 import android.os.Bundle 6 import androidx.activity.ComponentActivity 7 import androidx.activity.compose.setContent 8 import androidx.activity.enableEdgeToEdge 9 import androidx.compose.runtime.Composable 10 import androidx.compose.ui.tooling.preview.Preview 11 12 class MainActivity : ComponentActivity() { 13 override fun onCreate(savedInstanceState: Bundle?) { ··· 18 setContent { 19 App() 20 } 21 } 22 } 23
··· 1 package com.paytondeveloper.myrus_mobile 2 3 + import android.R.attr.bitmap 4 import android.app.Activity 5 import android.app.Application 6 + import android.graphics.Bitmap 7 import android.os.Bundle 8 + import android.speech.tts.TextToSpeech 9 + import android.speech.tts.UtteranceProgressListener 10 import androidx.activity.ComponentActivity 11 import androidx.activity.compose.setContent 12 import androidx.activity.enableEdgeToEdge 13 import androidx.compose.runtime.Composable 14 + import androidx.compose.ui.platform.LocalContext 15 + import androidx.compose.ui.platform.LocalView 16 import androidx.compose.ui.tooling.preview.Preview 17 + import androidx.core.graphics.applyCanvas 18 + import kotlinx.coroutines.suspendCancellableCoroutine 19 + import java.nio.ByteBuffer 20 + import kotlin.coroutines.resume 21 + import kotlin.coroutines.suspendCoroutine 22 + 23 24 class MainActivity : ComponentActivity() { 25 override fun onCreate(savedInstanceState: Bundle?) { ··· 30 setContent { 31 App() 32 } 33 + } 34 + } 35 + 36 + actual fun epochMillis() = System.currentTimeMillis() 37 + 38 + actual suspend fun sayText(text: String) { 39 + return suspendCancellableCoroutine { continuation -> 40 + var tts: TextToSpeech? = null 41 + 42 + tts = TextToSpeech(AppInfo.app.applicationContext) { status -> 43 + println("init'd with status: $status") 44 + 45 + if (status == TextToSpeech.SUCCESS) { 46 + // Now the TTS instance is initialized and can be used 47 + tts?.let { ttsInstance -> 48 + val result = ttsInstance.speak(text, TextToSpeech.QUEUE_FLUSH, null, "utteranceId") 49 + 50 + if (result == TextToSpeech.SUCCESS) { 51 + ttsInstance.setOnUtteranceProgressListener(object : UtteranceProgressListener() { 52 + override fun onStart(utteranceId: String?) {} 53 + 54 + override fun onDone(utteranceId: String?) { 55 + continuation.resume(Unit) 56 + ttsInstance.shutdown() 57 + } 58 + 59 + override fun onError(utteranceId: String?) { 60 + continuation.resume(Unit) 61 + ttsInstance.shutdown() 62 + } 63 + }) 64 + } else { 65 + continuation.resume(Unit) 66 + ttsInstance.shutdown() 67 + } 68 + } 69 + } else { 70 + continuation.resume(Unit) 71 + tts?.shutdown() 72 + } 73 + } 74 + 75 + continuation.invokeOnCancellation { 76 + tts?.stop() 77 + tts?.shutdown() 78 + } 79 + } 80 + } 81 + 82 + @Composable 83 + fun CaptureView(): ByteArray { 84 + val view = LocalView.current 85 + val context = LocalContext.current 86 + val bmp = Bitmap.createBitmap(view.width, view.height, 87 + Bitmap.Config.ARGB_8888).applyCanvas { 88 + view.draw(this) 89 + } 90 + bmp.let { 91 + val lnth: Int = bmp.getByteCount() 92 + val dst = ByteBuffer.allocate(lnth) 93 + bmp.copyPixelsToBuffer(dst) 94 + val barray = dst.array() 95 + return barray 96 } 97 } 98
+65 -40
mobile/composeApp/src/commonMain/kotlin/com/paytondeveloper/myrus_mobile/App.kt
··· 7 import androidx.compose.foundation.layout.fillMaxSize 8 import androidx.compose.foundation.layout.fillMaxWidth 9 import androidx.compose.foundation.layout.offset 10 import androidx.compose.material.Button 11 import androidx.compose.material.MaterialTheme 12 import androidx.compose.material.Text 13 import androidx.compose.runtime.* 14 import androidx.compose.ui.Alignment ··· 30 import com.kashif.cameraK.permissions.providePermissions 31 import com.kashif.cameraK.result.ImageCaptureResult 32 import com.kashif.cameraK.ui.CameraPreview 33 import io.ktor.util.Identity.encode 34 import kotlinx.coroutines.delay 35 import org.jetbrains.compose.resources.painterResource 36 import org.jetbrains.compose.ui.tooling.preview.Preview 37 38 import myrus_mobile.composeapp.generated.resources.Res 39 import myrus_mobile.composeapp.generated.resources.compose_multiplatform 40 41 expect fun analyzeImage(img: ByteArray, callback: (Rect, Size) -> Unit) 42 ··· 44 data class Rect(val top: Float, val left: Float, val bottom: Float, val right: Float) 45 data class FaceData(val boundingBox: Rect) 46 47 48 - expect fun CameraController.getResolution(): Size? 49 50 @Composable 51 @Preview ··· 67 var camController by remember { mutableStateOf<CameraController?>(null) } 68 var camSize by remember { mutableStateOf<Size?>(null) } 69 var currentThingy by remember { mutableStateOf<Rect?>(Rect(0f,0f,0f,0f)) } 70 LaunchedEffect(Unit) { 71 //not proud of this. 72 suspend fun runloop() { 73 74 - val res = camController?.takePicture() 75 - res?.let { 76 - when (it) { 77 - is ImageCaptureResult.Error -> { 78 - println("error taking pic. skipping frame: ${it.exception}") 79 - } 80 - is ImageCaptureResult.Success -> { 81 - analyzeImage(it.byteArray, { it, size -> 82 // println("offset: ${it.top} ${it.left}") 83 - val factorY = it.top.toFloat() / size.height.toFloat() 84 - val factorX = it.left.toFloat() / size.width.toFloat() 85 86 - val newY = factorY * camSize!!.height.toFloat() 87 - val newX = factorX * camSize!!.width.toFloat() 88 89 - currentThingy = it.copy(top = newY, left = newX) 90 - }) 91 } 92 } 93 } 94 - delay(1000) 95 runloop() 96 } 97 runloop() 98 } 99 - Box(modifier = Modifier/*.drawWithCache { 100 - if (currentThingy != null) { 101 - val roundedPolygon = RoundedPolygon( 102 - numVertices = 6, 103 - radius = (currentThingy!!.right - currentThingy!!.left).toFloat(), 104 - centerX = currentThingy!!.left.toFloat(), 105 - centerY = currentThingy!!.top.toFloat() 106 - ) 107 - val roundedPolygonPath = roundedPolygon 108 - onDrawBehind { 109 - // drawPath(roundedPolygonPath, color = Color.Blue) 110 - drawRect( 111 - color = Color.Red, 112 - topLeft = Offset(currentThingy!!.left.toFloat(), currentThingy!!.top.toFloat()), 113 - size = androidx.compose.ui.geometry.Size(width = (currentThingy!!.right - currentThingy!!.left).toFloat(), height = (currentThingy!!.bottom - currentThingy!!.top).toFloat()) 114 - ) 115 - } 116 - 117 - } else { 118 - onDrawBehind { } 119 - } 120 - }*/) { 121 val topPx = with(LocalDensity.current) { 122 currentThingy!!.top.toDp() 123 } ··· 136 setCameraLens(CameraLens.FRONT) 137 setImageFormat(ImageFormat.PNG) 138 setDirectory(Directory.PICTURES) 139 - 140 - 141 }, onCameraControllerReady = { 142 camController = it 143 }) 144 Text("Face", modifier = Modifier.offset(x = leftPx, y = topPx)) 145 } 146 } else { 147 Text("no permissions!! can't do anything :(") 148 }
··· 7 import androidx.compose.foundation.layout.fillMaxSize 8 import androidx.compose.foundation.layout.fillMaxWidth 9 import androidx.compose.foundation.layout.offset 10 + import androidx.compose.foundation.layout.padding 11 import androidx.compose.material.Button 12 import androidx.compose.material.MaterialTheme 13 + import androidx.compose.material.Slider 14 import androidx.compose.material.Text 15 import androidx.compose.runtime.* 16 import androidx.compose.ui.Alignment ··· 32 import com.kashif.cameraK.permissions.providePermissions 33 import com.kashif.cameraK.result.ImageCaptureResult 34 import com.kashif.cameraK.ui.CameraPreview 35 + import dev.shreyaspatil.ai.client.generativeai.GenerativeModel 36 + import dev.shreyaspatil.ai.client.generativeai.type.content 37 import io.ktor.util.Identity.encode 38 + import kotlinx.coroutines.CoroutineScope 39 + import kotlinx.coroutines.Dispatchers 40 + import kotlinx.coroutines.IO 41 import kotlinx.coroutines.delay 42 + import kotlinx.coroutines.launch 43 import org.jetbrains.compose.resources.painterResource 44 import org.jetbrains.compose.ui.tooling.preview.Preview 45 46 import myrus_mobile.composeapp.generated.resources.Res 47 import myrus_mobile.composeapp.generated.resources.compose_multiplatform 48 + import nl.marc_apps.tts.TextToSpeechEngine 49 + import nl.marc_apps.tts.rememberTextToSpeechOrNull 50 51 expect fun analyzeImage(img: ByteArray, callback: (Rect, Size) -> Unit) 52 ··· 54 data class Rect(val top: Float, val left: Float, val bottom: Float, val right: Float) 55 data class FaceData(val boundingBox: Rect) 56 57 + expect suspend fun sayText(text: String) 58 59 + val genAI = GenerativeModel( 60 + "gemini-2.0-flash", 61 + apiKey = "AIzaSyCy56R6_T3Neu54W45MMSTGpXFEb92V2yI" 62 + ) 63 + 64 + expect fun epochMillis(): Long 65 + 66 67 @Composable 68 @Preview ··· 84 var camController by remember { mutableStateOf<CameraController?>(null) } 85 var camSize by remember { mutableStateOf<Size?>(null) } 86 var currentThingy by remember { mutableStateOf<Rect?>(Rect(0f,0f,0f,0f)) } 87 + var delayMillis by remember { mutableStateOf(1000) } 88 + var analyzing by remember { mutableStateOf(true) } 89 + val tts = rememberTextToSpeechOrNull(TextToSpeechEngine.Google) 90 LaunchedEffect(Unit) { 91 //not proud of this. 92 + suspend fun roast(image: ByteArray) { 93 + var content = content { 94 + image(image) 95 + text("make a shakespearean insult for the person in the middle of the image. return only the insult. be specific to the person in the image") 96 + } 97 + val res = genAI.generateContent(content) 98 + println("RES: ${res.text} TTS: ${tts}") 99 + // tts?.let { tts -> 100 + // tts.say(res.text ?: "uh oh its broken", true) 101 + // } 102 + sayText(res.text ?: "uh oh its borken") 103 + analyzing = true 104 + } 105 suspend fun runloop() { 106 107 + if (analyzing) { 108 + 109 + val res = camController?.takePicture() 110 + res?.let { 111 + when (it) { 112 + is ImageCaptureResult.Error -> { 113 + println("error taking pic. skipping frame: ${it.exception}") 114 + } 115 + is ImageCaptureResult.Success -> { 116 + analyzeImage(it.byteArray, { bounds, size -> 117 // println("offset: ${it.top} ${it.left}") 118 + val factorY = bounds.top / size.height 119 + val factorX = bounds.left / size.width 120 121 + val newY = factorY * camSize!!.height 122 + val newX = factorX * camSize!!.width 123 124 + currentThingy = bounds.copy(top = newY, left = newX) 125 + analyzing = false 126 + CoroutineScope(Dispatchers.IO).launch { 127 + roast(it.byteArray) 128 + } 129 + }) 130 + 131 + } 132 } 133 } 134 } 135 + delay(delayMillis.toLong()) 136 runloop() 137 } 138 + 139 runloop() 140 } 141 + Box(modifier = Modifier) { 142 val topPx = with(LocalDensity.current) { 143 currentThingy!!.top.toDp() 144 } ··· 157 setCameraLens(CameraLens.FRONT) 158 setImageFormat(ImageFormat.PNG) 159 setDirectory(Directory.PICTURES) 160 }, onCameraControllerReady = { 161 camController = it 162 + if (getPlatform().name.contains("iOS")) { 163 + camController!!.toggleCameraLens() 164 + } 165 }) 166 Text("Face", modifier = Modifier.offset(x = leftPx, y = topPx)) 167 } 168 + Slider(modifier = Modifier.padding(top = 64.dp), value = delayMillis.toFloat(), onValueChange = { 169 + delayMillis = it.toInt() 170 + }, valueRange = 16.67f..5000f) 171 } else { 172 Text("no permissions!! can't do anything :(") 173 }
+21 -2
mobile/composeApp/src/iosMain/kotlin/com/paytondeveloper/myrus_mobile/MLFace.ios.kt
··· 2 3 import com.kashif.cameraK.builder.CameraControllerBuilder 4 import com.kashif.cameraK.controller.CameraController 5 6 - actual fun analyzeImage(img: ByteArray, callback:(Rect, Size) -> Unit) {} 7 8 - actual fun CameraController.getResolution(): Size? {return null}
··· 2 3 import com.kashif.cameraK.builder.CameraControllerBuilder 4 import com.kashif.cameraK.controller.CameraController 5 + import kotlinx.cinterop.BetaInteropApi 6 + import kotlinx.cinterop.ExperimentalForeignApi 7 + import kotlinx.cinterop.memScoped 8 + import kotlinx.cinterop.toCValues 9 + import platform.Foundation.NSData 10 + import platform.Foundation.create 11 12 + object NativeAnalyzer { 13 + lateinit var analyzeImageNative: (img: ByteArray, callback: (Rect, Size) -> Unit) -> Unit 14 + @OptIn(ExperimentalForeignApi::class, BetaInteropApi::class) 15 + fun byteArrayToData(byteArray: ByteArray): NSData = memScoped { 16 + return NSData.create( 17 + bytes = byteArray.toCValues().getPointer(this), 18 + length = byteArray.size.toULong() 19 + ) 20 + } 21 + } 22 + 23 + actual fun analyzeImage(img: ByteArray, callback:(Rect, Size) -> Unit) { 24 + NativeAnalyzer.analyzeImageNative(img, callback) 25 + } 26 + 27
+22 -1
mobile/composeApp/src/iosMain/kotlin/com/paytondeveloper/myrus_mobile/MainViewController.kt
··· 1 package com.paytondeveloper.myrus_mobile 2 3 import androidx.compose.ui.window.ComposeUIViewController 4 5 - fun MainViewController() = ComposeUIViewController { App() }
··· 1 package com.paytondeveloper.myrus_mobile 2 3 + import androidx.compose.runtime.Composable 4 + import androidx.compose.ui.interop.LocalUIViewController 5 import androidx.compose.ui.window.ComposeUIViewController 6 + import kotlinx.cinterop.ExperimentalForeignApi 7 + import kotlinx.cinterop.addressOf 8 + import kotlinx.cinterop.usePinned 9 + import platform.Foundation.NSData 10 + import platform.Foundation.NSDate 11 + import platform.Foundation.timeIntervalSince1970 12 + import platform.UIKit.UIGraphicsImageRenderer 13 + import platform.posix.memcpy 14 + 15 + fun MainViewController() = ComposeUIViewController { App() } 16 17 + actual fun epochMillis(): Long = (NSDate().timeIntervalSince1970 * 1000).toLong() 18 + 19 + @OptIn(ExperimentalForeignApi::class) 20 + fun NSDataToByteArray(data: NSData): ByteArray = ByteArray(data.length.toInt()).apply { 21 + usePinned { 22 + memcpy(it.addressOf(0), data.bytes, data.length) 23 + } 24 + } 25 + 26 + actual suspend fun sayText(text: String) {}
+13
mobile/gradle/libs.versions.toml
··· 14 camerak = "0.0.10" 15 compose-multiplatform = "1.7.0" 16 faceDetection = "16.1.7" 17 graphicsShapes = "1.0.1" 18 junit = "4.13.2" 19 kotlin = "2.1.0" 20 21 [libraries] 22 androidx-graphics-shapes = { module = "androidx.graphics:graphics-shapes", version.ref = "graphicsShapes" } 23 camerak = { module = "io.github.kashif-mehmood-km:camerak", version.ref = "camerak" } 24 face-detection = { module = "com.google.mlkit:face-detection", version.ref = "faceDetection" } 25 kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" } 26 kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" } 27 junit = { group = "junit", name = "junit", version.ref = "junit" } ··· 34 androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activityCompose" } 35 androidx-lifecycle-viewmodel = { group = "org.jetbrains.androidx.lifecycle", name = "lifecycle-viewmodel", version.ref = "androidx-lifecycle" } 36 androidx-lifecycle-runtime-compose = { group = "org.jetbrains.androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "androidx-lifecycle" } 37 38 [plugins] 39 androidApplication = { id = "com.android.application", version.ref = "agp" }
··· 14 camerak = "0.0.10" 15 compose-multiplatform = "1.7.0" 16 faceDetection = "16.1.7" 17 + generativeai = "0.9.0" 18 + generativeaiGoogle = "0.9.0-1.0.1" 19 graphicsShapes = "1.0.1" 20 junit = "4.13.2" 21 kotlin = "2.1.0" 22 + kotlinxCoroutinesCore = "1.9.0" 23 + ktorClientCio = "2.3.2" 24 + openaiClient = "4.0.1" 25 + ttsCompose = "2.5.0" 26 27 [libraries] 28 androidx-graphics-shapes = { module = "androidx.graphics:graphics-shapes", version.ref = "graphicsShapes" } 29 camerak = { module = "io.github.kashif-mehmood-km:camerak", version.ref = "camerak" } 30 face-detection = { module = "com.google.mlkit:face-detection", version.ref = "faceDetection" } 31 + generativeai = { module = "com.google.ai.client.generativeai:generativeai", version.ref = "generativeai" } 32 + generativeai-google = { module = "dev.shreyaspatil.generativeai:generativeai-google", version.ref = "generativeaiGoogle" } 33 kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" } 34 kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" } 35 junit = { group = "junit", name = "junit", version.ref = "junit" } ··· 42 androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activityCompose" } 43 androidx-lifecycle-viewmodel = { group = "org.jetbrains.androidx.lifecycle", name = "lifecycle-viewmodel", version.ref = "androidx-lifecycle" } 44 androidx-lifecycle-runtime-compose = { group = "org.jetbrains.androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "androidx-lifecycle" } 45 + kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinxCoroutinesCore" } 46 + ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktorClientCio" } 47 + openai-client = { module = "com.aallam.openai:openai-client", version.ref = "openaiClient" } 48 + tts = { module = "nl.marc-apps:tts", version.ref = "ttsCompose" } 49 + tts-compose = { module = "nl.marc-apps:tts-compose", version.ref = "ttsCompose" } 50 51 [plugins] 52 androidApplication = { id = "com.android.application", version.ref = "agp" }
+1
mobile/iosApp/.gitignore
···
··· 1 + Pods/
+10
mobile/iosApp/Podfile
···
··· 1 + # Uncomment the next line to define a global platform for your project 2 + # platform :ios, '16.0' 3 + 4 + target 'iosApp' do 5 + # Comment the next line if you don't want to use dynamic frameworks 6 + use_frameworks! 7 + 8 + # Pods for iosApp 9 + pod 'GoogleMLKit/FaceDetection', '7.0.0' 10 + end
+81
mobile/iosApp/Podfile.lock
···
··· 1 + PODS: 2 + - GoogleDataTransport (10.1.0): 3 + - nanopb (~> 3.30910.0) 4 + - PromisesObjC (~> 2.4) 5 + - GoogleMLKit/FaceDetection (7.0.0): 6 + - GoogleMLKit/MLKitCore 7 + - MLKitFaceDetection (~> 6.0.0) 8 + - GoogleMLKit/MLKitCore (7.0.0): 9 + - MLKitCommon (~> 12.0.0) 10 + - GoogleToolboxForMac/Defines (4.2.1) 11 + - GoogleToolboxForMac/Logger (4.2.1): 12 + - GoogleToolboxForMac/Defines (= 4.2.1) 13 + - "GoogleToolboxForMac/NSData+zlib (4.2.1)": 14 + - GoogleToolboxForMac/Defines (= 4.2.1) 15 + - GoogleUtilities/Environment (8.0.2): 16 + - GoogleUtilities/Privacy 17 + - GoogleUtilities/Logger (8.0.2): 18 + - GoogleUtilities/Environment 19 + - GoogleUtilities/Privacy 20 + - GoogleUtilities/Privacy (8.0.2) 21 + - GoogleUtilities/UserDefaults (8.0.2): 22 + - GoogleUtilities/Logger 23 + - GoogleUtilities/Privacy 24 + - GTMSessionFetcher/Core (3.5.0) 25 + - MLImage (1.0.0-beta6) 26 + - MLKitCommon (12.0.0): 27 + - GoogleDataTransport (~> 10.0) 28 + - GoogleToolboxForMac/Logger (< 5.0, >= 4.2.1) 29 + - "GoogleToolboxForMac/NSData+zlib (< 5.0, >= 4.2.1)" 30 + - GoogleUtilities/Logger (~> 8.0) 31 + - GoogleUtilities/UserDefaults (~> 8.0) 32 + - GTMSessionFetcher/Core (< 4.0, >= 3.3.2) 33 + - MLKitFaceDetection (6.0.0): 34 + - MLKitCommon (~> 12.0) 35 + - MLKitVision (~> 8.0) 36 + - MLKitVision (8.0.0): 37 + - GoogleToolboxForMac/Logger (< 5.0, >= 4.2.1) 38 + - "GoogleToolboxForMac/NSData+zlib (< 5.0, >= 4.2.1)" 39 + - GTMSessionFetcher/Core (< 4.0, >= 3.3.2) 40 + - MLImage (= 1.0.0-beta6) 41 + - MLKitCommon (~> 12.0) 42 + - nanopb (3.30910.0): 43 + - nanopb/decode (= 3.30910.0) 44 + - nanopb/encode (= 3.30910.0) 45 + - nanopb/decode (3.30910.0) 46 + - nanopb/encode (3.30910.0) 47 + - PromisesObjC (2.4.0) 48 + 49 + DEPENDENCIES: 50 + - GoogleMLKit/FaceDetection (= 7.0.0) 51 + 52 + SPEC REPOS: 53 + trunk: 54 + - GoogleDataTransport 55 + - GoogleMLKit 56 + - GoogleToolboxForMac 57 + - GoogleUtilities 58 + - GTMSessionFetcher 59 + - MLImage 60 + - MLKitCommon 61 + - MLKitFaceDetection 62 + - MLKitVision 63 + - nanopb 64 + - PromisesObjC 65 + 66 + SPEC CHECKSUMS: 67 + GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 68 + GoogleMLKit: eff9e23ec1d90ea4157a1ee2e32a4f610c5b3318 69 + GoogleToolboxForMac: d1a2cbf009c453f4d6ded37c105e2f67a32206d8 70 + GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d 71 + GTMSessionFetcher: 5aea5ba6bd522a239e236100971f10cb71b96ab6 72 + MLImage: 0ad1c5f50edd027672d8b26b0fee78a8b4a0fc56 73 + MLKitCommon: 07c2c33ae5640e5380beaaa6e4b9c249a205542d 74 + MLKitFaceDetection: 2a593db4837db503ad3426b565e7aab045cefea5 75 + MLKitVision: 45e79d68845a2de77e2dd4d7f07947f0ed157b0e 76 + nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 77 + PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 78 + 79 + PODFILE CHECKSUM: dc40bfac79d7daca47a5105ced3cb04958e00832 80 + 81 + COCOAPODS: 1.16.2
+81 -39
mobile/iosApp/iosApp.xcodeproj/project.pbxproj
··· 7 objects = { 8 9 /* Begin PBXBuildFile section */ 10 058557BB273AAA24004C7B11 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 058557BA273AAA24004C7B11 /* Assets.xcassets */; }; 11 058557D9273AAEEB004C7B11 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */; }; 12 2152FB042600AC8F00CF470E /* iOSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2152FB032600AC8F00CF470E /* iOSApp.swift */; }; 13 7555FF83242A565900829871 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7555FF82242A565900829871 /* ContentView.swift */; }; 14 - E9B512A52D862B0F00D52AB6 /* MLKitBarcodeScanning in Frameworks */ = {isa = PBXBuildFile; productRef = E9B512A42D862B0F00D52AB6 /* MLKitBarcodeScanning */; }; 15 - E9B512A72D862B0F00D52AB6 /* MLKitFaceDetection in Frameworks */ = {isa = PBXBuildFile; productRef = E9B512A62D862B0F00D52AB6 /* MLKitFaceDetection */; }; 16 /* End PBXBuildFile section */ 17 18 /* Begin PBXFileReference section */ 19 058557BA273AAA24004C7B11 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; 20 058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; }; 21 2152FB032600AC8F00CF470E /* iOSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iOSApp.swift; sourceTree = "<group>"; }; 22 7555FF7B242A565900829871 /* myrus-mobile.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "myrus-mobile.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 23 7555FF82242A565900829871 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; }; 24 7555FF8C242A565B00829871 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 25 AB3632DC29227652001CCB65 /* Config.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; }; 26 /* End PBXFileReference section */ 27 28 /* Begin PBXFrameworksBuildPhase section */ ··· 30 isa = PBXFrameworksBuildPhase; 31 buildActionMask = 2147483647; 32 files = ( 33 - E9B512A52D862B0F00D52AB6 /* MLKitBarcodeScanning in Frameworks */, 34 - E9B512A72D862B0F00D52AB6 /* MLKitFaceDetection in Frameworks */, 35 ); 36 runOnlyForDeploymentPostprocessing = 0; 37 }; ··· 46 path = "Preview Content"; 47 sourceTree = "<group>"; 48 }; 49 42799AB246E5F90AF97AA0EF /* Frameworks */ = { 50 isa = PBXGroup; 51 children = ( 52 ); 53 name = Frameworks; 54 sourceTree = "<group>"; ··· 60 7555FF7D242A565900829871 /* iosApp */, 61 7555FF7C242A565900829871 /* Products */, 62 42799AB246E5F90AF97AA0EF /* Frameworks */, 63 ); 64 sourceTree = "<group>"; 65 }; ··· 98 isa = PBXNativeTarget; 99 buildConfigurationList = 7555FFA5242A565B00829871 /* Build configuration list for PBXNativeTarget "iosApp" */; 100 buildPhases = ( 101 F36B1CEB2AD83DDC00CB74D5 /* Compile Kotlin Framework */, 102 7555FF77242A565900829871 /* Sources */, 103 B92378962B6B1156000C7307 /* Frameworks */, 104 7555FF79242A565900829871 /* Resources */, 105 ); 106 buildRules = ( 107 ); 108 dependencies = ( 109 ); 110 name = iosApp; 111 - packageProductDependencies = ( 112 - E9B512A42D862B0F00D52AB6 /* MLKitBarcodeScanning */, 113 - E9B512A62D862B0F00D52AB6 /* MLKitFaceDetection */, 114 - ); 115 productName = iosApp; 116 productReference = 7555FF7B242A565900829871 /* myrus-mobile.app */; 117 productType = "com.apple.product-type.application"; ··· 141 Base, 142 ); 143 mainGroup = 7555FF72242A565900829871; 144 - packageReferences = ( 145 - E9B512A32D862B0F00D52AB6 /* XCRemoteSwiftPackageReference "google-mlkit-swiftpm" */, 146 - ); 147 productRefGroup = 7555FF7C242A565900829871 /* Products */; 148 projectDirPath = ""; 149 projectRoot = ""; ··· 166 /* End PBXResourcesBuildPhase section */ 167 168 /* Begin PBXShellScriptBuildPhase section */ 169 F36B1CEB2AD83DDC00CB74D5 /* Compile Kotlin Framework */ = { 170 isa = PBXShellScriptBuildPhase; 171 buildActionMask = 2147483647; ··· 321 }; 322 7555FFA6242A565B00829871 /* Debug */ = { 323 isa = XCBuildConfiguration; 324 buildSettings = { 325 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 326 CODE_SIGN_IDENTITY = "Apple Development"; 327 CODE_SIGN_STYLE = Automatic; 328 DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\""; 329 - DEVELOPMENT_TEAM = "${TEAM_ID}"; 330 ENABLE_PREVIEWS = YES; 331 FRAMEWORK_SEARCH_PATHS = ( 332 "$(inherited)", 333 "$(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)\n$(SRCROOT)/../composeApp/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)", 334 ); 335 INFOPLIST_FILE = iosApp/Info.plist; 336 - IPHONEOS_DEPLOYMENT_TARGET = 15.3; 337 LD_RUNPATH_SEARCH_PATHS = ( 338 "$(inherited)", 339 "@executable_path/Frameworks", ··· 348 }; 349 7555FFA7242A565B00829871 /* Release */ = { 350 isa = XCBuildConfiguration; 351 buildSettings = { 352 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 353 CODE_SIGN_IDENTITY = "Apple Development"; 354 CODE_SIGN_STYLE = Automatic; 355 DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\""; 356 - DEVELOPMENT_TEAM = "${TEAM_ID}"; 357 ENABLE_PREVIEWS = YES; 358 FRAMEWORK_SEARCH_PATHS = ( 359 "$(inherited)", 360 "$(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)\n$(SRCROOT)/../composeApp/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)", 361 ); 362 INFOPLIST_FILE = iosApp/Info.plist; 363 - IPHONEOS_DEPLOYMENT_TARGET = 15.3; 364 LD_RUNPATH_SEARCH_PATHS = ( 365 "$(inherited)", 366 "@executable_path/Frameworks", ··· 395 defaultConfigurationName = Release; 396 }; 397 /* End XCConfigurationList section */ 398 - 399 - /* Begin XCRemoteSwiftPackageReference section */ 400 - E9B512A32D862B0F00D52AB6 /* XCRemoteSwiftPackageReference "google-mlkit-swiftpm" */ = { 401 - isa = XCRemoteSwiftPackageReference; 402 - repositoryURL = "https://github.com/d-date/google-mlkit-swiftpm"; 403 - requirement = { 404 - kind = upToNextMajorVersion; 405 - minimumVersion = 6.0.0; 406 - }; 407 - }; 408 - /* End XCRemoteSwiftPackageReference section */ 409 - 410 - /* Begin XCSwiftPackageProductDependency section */ 411 - E9B512A42D862B0F00D52AB6 /* MLKitBarcodeScanning */ = { 412 - isa = XCSwiftPackageProductDependency; 413 - package = E9B512A32D862B0F00D52AB6 /* XCRemoteSwiftPackageReference "google-mlkit-swiftpm" */; 414 - productName = MLKitBarcodeScanning; 415 - }; 416 - E9B512A62D862B0F00D52AB6 /* MLKitFaceDetection */ = { 417 - isa = XCSwiftPackageProductDependency; 418 - package = E9B512A32D862B0F00D52AB6 /* XCRemoteSwiftPackageReference "google-mlkit-swiftpm" */; 419 - productName = MLKitFaceDetection; 420 - }; 421 - /* End XCSwiftPackageProductDependency section */ 422 }; 423 rootObject = 7555FF73242A565900829871 /* Project object */; 424 }
··· 7 objects = { 8 9 /* Begin PBXBuildFile section */ 10 + 00FBAE687F5BCD32801C67BA /* Pods_iosApp.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 07734A1087237371E675AE3E /* Pods_iosApp.framework */; }; 11 058557BB273AAA24004C7B11 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 058557BA273AAA24004C7B11 /* Assets.xcassets */; }; 12 058557D9273AAEEB004C7B11 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */; }; 13 2152FB042600AC8F00CF470E /* iOSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2152FB032600AC8F00CF470E /* iOSApp.swift */; }; 14 7555FF83242A565900829871 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7555FF82242A565900829871 /* ContentView.swift */; }; 15 /* End PBXBuildFile section */ 16 17 /* Begin PBXFileReference section */ 18 058557BA273AAA24004C7B11 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; 19 058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; }; 20 + 07734A1087237371E675AE3E /* Pods_iosApp.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_iosApp.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 21 2152FB032600AC8F00CF470E /* iOSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iOSApp.swift; sourceTree = "<group>"; }; 22 7555FF7B242A565900829871 /* myrus-mobile.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "myrus-mobile.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 23 7555FF82242A565900829871 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; }; 24 7555FF8C242A565B00829871 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 25 + 95ADA54C8FE56AF9CA35ABD0 /* Pods-iosApp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iosApp.debug.xcconfig"; path = "Target Support Files/Pods-iosApp/Pods-iosApp.debug.xcconfig"; sourceTree = "<group>"; }; 26 AB3632DC29227652001CCB65 /* Config.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; }; 27 + F7B9AA6F955C972BAA204DE2 /* Pods-iosApp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iosApp.release.xcconfig"; path = "Target Support Files/Pods-iosApp/Pods-iosApp.release.xcconfig"; sourceTree = "<group>"; }; 28 /* End PBXFileReference section */ 29 30 /* Begin PBXFrameworksBuildPhase section */ ··· 32 isa = PBXFrameworksBuildPhase; 33 buildActionMask = 2147483647; 34 files = ( 35 + 00FBAE687F5BCD32801C67BA /* Pods_iosApp.framework in Frameworks */, 36 ); 37 runOnlyForDeploymentPostprocessing = 0; 38 }; ··· 47 path = "Preview Content"; 48 sourceTree = "<group>"; 49 }; 50 + 2A2D659B26830710A9A8E8BE /* Pods */ = { 51 + isa = PBXGroup; 52 + children = ( 53 + 95ADA54C8FE56AF9CA35ABD0 /* Pods-iosApp.debug.xcconfig */, 54 + F7B9AA6F955C972BAA204DE2 /* Pods-iosApp.release.xcconfig */, 55 + ); 56 + path = Pods; 57 + sourceTree = "<group>"; 58 + }; 59 42799AB246E5F90AF97AA0EF /* Frameworks */ = { 60 isa = PBXGroup; 61 children = ( 62 + 07734A1087237371E675AE3E /* Pods_iosApp.framework */, 63 ); 64 name = Frameworks; 65 sourceTree = "<group>"; ··· 71 7555FF7D242A565900829871 /* iosApp */, 72 7555FF7C242A565900829871 /* Products */, 73 42799AB246E5F90AF97AA0EF /* Frameworks */, 74 + 2A2D659B26830710A9A8E8BE /* Pods */, 75 ); 76 sourceTree = "<group>"; 77 }; ··· 110 isa = PBXNativeTarget; 111 buildConfigurationList = 7555FFA5242A565B00829871 /* Build configuration list for PBXNativeTarget "iosApp" */; 112 buildPhases = ( 113 + 7A2DFE5500B1B3090857DA1E /* [CP] Check Pods Manifest.lock */, 114 F36B1CEB2AD83DDC00CB74D5 /* Compile Kotlin Framework */, 115 7555FF77242A565900829871 /* Sources */, 116 B92378962B6B1156000C7307 /* Frameworks */, 117 7555FF79242A565900829871 /* Resources */, 118 + 05A9CE664DBE199AF7FBD83E /* [CP] Embed Pods Frameworks */, 119 + 97BC41D49C174C6809B569F2 /* [CP] Copy Pods Resources */, 120 ); 121 buildRules = ( 122 ); 123 dependencies = ( 124 ); 125 name = iosApp; 126 productName = iosApp; 127 productReference = 7555FF7B242A565900829871 /* myrus-mobile.app */; 128 productType = "com.apple.product-type.application"; ··· 152 Base, 153 ); 154 mainGroup = 7555FF72242A565900829871; 155 productRefGroup = 7555FF7C242A565900829871 /* Products */; 156 projectDirPath = ""; 157 projectRoot = ""; ··· 174 /* End PBXResourcesBuildPhase section */ 175 176 /* Begin PBXShellScriptBuildPhase section */ 177 + 05A9CE664DBE199AF7FBD83E /* [CP] Embed Pods Frameworks */ = { 178 + isa = PBXShellScriptBuildPhase; 179 + buildActionMask = 2147483647; 180 + files = ( 181 + ); 182 + inputFileListPaths = ( 183 + "${PODS_ROOT}/Target Support Files/Pods-iosApp/Pods-iosApp-frameworks-${CONFIGURATION}-input-files.xcfilelist", 184 + ); 185 + name = "[CP] Embed Pods Frameworks"; 186 + outputFileListPaths = ( 187 + "${PODS_ROOT}/Target Support Files/Pods-iosApp/Pods-iosApp-frameworks-${CONFIGURATION}-output-files.xcfilelist", 188 + ); 189 + runOnlyForDeploymentPostprocessing = 0; 190 + shellPath = /bin/sh; 191 + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-iosApp/Pods-iosApp-frameworks.sh\"\n"; 192 + showEnvVarsInLog = 0; 193 + }; 194 + 7A2DFE5500B1B3090857DA1E /* [CP] Check Pods Manifest.lock */ = { 195 + isa = PBXShellScriptBuildPhase; 196 + buildActionMask = 2147483647; 197 + files = ( 198 + ); 199 + inputFileListPaths = ( 200 + ); 201 + inputPaths = ( 202 + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 203 + "${PODS_ROOT}/Manifest.lock", 204 + ); 205 + name = "[CP] Check Pods Manifest.lock"; 206 + outputFileListPaths = ( 207 + ); 208 + outputPaths = ( 209 + "$(DERIVED_FILE_DIR)/Pods-iosApp-checkManifestLockResult.txt", 210 + ); 211 + runOnlyForDeploymentPostprocessing = 0; 212 + shellPath = /bin/sh; 213 + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 214 + showEnvVarsInLog = 0; 215 + }; 216 + 97BC41D49C174C6809B569F2 /* [CP] Copy Pods Resources */ = { 217 + isa = PBXShellScriptBuildPhase; 218 + buildActionMask = 2147483647; 219 + files = ( 220 + ); 221 + inputFileListPaths = ( 222 + "${PODS_ROOT}/Target Support Files/Pods-iosApp/Pods-iosApp-resources-${CONFIGURATION}-input-files.xcfilelist", 223 + ); 224 + name = "[CP] Copy Pods Resources"; 225 + outputFileListPaths = ( 226 + "${PODS_ROOT}/Target Support Files/Pods-iosApp/Pods-iosApp-resources-${CONFIGURATION}-output-files.xcfilelist", 227 + ); 228 + runOnlyForDeploymentPostprocessing = 0; 229 + shellPath = /bin/sh; 230 + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-iosApp/Pods-iosApp-resources.sh\"\n"; 231 + showEnvVarsInLog = 0; 232 + }; 233 F36B1CEB2AD83DDC00CB74D5 /* Compile Kotlin Framework */ = { 234 isa = PBXShellScriptBuildPhase; 235 buildActionMask = 2147483647; ··· 385 }; 386 7555FFA6242A565B00829871 /* Debug */ = { 387 isa = XCBuildConfiguration; 388 + baseConfigurationReference = 95ADA54C8FE56AF9CA35ABD0 /* Pods-iosApp.debug.xcconfig */; 389 buildSettings = { 390 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 391 CODE_SIGN_IDENTITY = "Apple Development"; 392 CODE_SIGN_STYLE = Automatic; 393 DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\""; 394 + DEVELOPMENT_TEAM = BR926NY9FS; 395 ENABLE_PREVIEWS = YES; 396 FRAMEWORK_SEARCH_PATHS = ( 397 "$(inherited)", 398 "$(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)\n$(SRCROOT)/../composeApp/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)", 399 ); 400 INFOPLIST_FILE = iosApp/Info.plist; 401 + IPHONEOS_DEPLOYMENT_TARGET = 18.0; 402 LD_RUNPATH_SEARCH_PATHS = ( 403 "$(inherited)", 404 "@executable_path/Frameworks", ··· 413 }; 414 7555FFA7242A565B00829871 /* Release */ = { 415 isa = XCBuildConfiguration; 416 + baseConfigurationReference = F7B9AA6F955C972BAA204DE2 /* Pods-iosApp.release.xcconfig */; 417 buildSettings = { 418 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 419 CODE_SIGN_IDENTITY = "Apple Development"; 420 CODE_SIGN_STYLE = Automatic; 421 DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\""; 422 + DEVELOPMENT_TEAM = BR926NY9FS; 423 ENABLE_PREVIEWS = YES; 424 FRAMEWORK_SEARCH_PATHS = ( 425 "$(inherited)", 426 "$(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)\n$(SRCROOT)/../composeApp/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)", 427 ); 428 INFOPLIST_FILE = iosApp/Info.plist; 429 + IPHONEOS_DEPLOYMENT_TARGET = 18.0; 430 LD_RUNPATH_SEARCH_PATHS = ( 431 "$(inherited)", 432 "@executable_path/Frameworks", ··· 461 defaultConfigurationName = Release; 462 }; 463 /* End XCConfigurationList section */ 464 }; 465 rootObject = 7555FF73242A565900829871 /* Project object */; 466 }
-60
mobile/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
··· 1 - { 2 - "originHash" : "891cce1a2e5740e9da5b83f5ae8318d7657deb75e81f6a5d7be479fbdadf82e9", 3 - "pins" : [ 4 - { 5 - "identity" : "google-mlkit-swiftpm", 6 - "kind" : "remoteSourceControl", 7 - "location" : "https://github.com/d-date/google-mlkit-swiftpm", 8 - "state" : { 9 - "revision" : "064418cee64470417fbc5c726e22815dc92c56c9", 10 - "version" : "6.0.0" 11 - } 12 - }, 13 - { 14 - "identity" : "googledatatransport", 15 - "kind" : "remoteSourceControl", 16 - "location" : "https://github.com/google/GoogleDataTransport.git", 17 - "state" : { 18 - "revision" : "a637d318ae7ae246b02d7305121275bc75ed5565", 19 - "version" : "9.4.0" 20 - } 21 - }, 22 - { 23 - "identity" : "googleutilities", 24 - "kind" : "remoteSourceControl", 25 - "location" : "https://github.com/google/GoogleUtilities.git", 26 - "state" : { 27 - "revision" : "8e5d57ed87057cd7b0e4e8f474d9e78f73eb85f7", 28 - "version" : "7.13.2" 29 - } 30 - }, 31 - { 32 - "identity" : "gtm-session-fetcher", 33 - "kind" : "remoteSourceControl", 34 - "location" : "https://github.com/google/gtm-session-fetcher.git", 35 - "state" : { 36 - "revision" : "0382ca27f22fb3494cf657d8dc356dc282cd1193", 37 - "version" : "3.4.1" 38 - } 39 - }, 40 - { 41 - "identity" : "nanopb", 42 - "kind" : "remoteSourceControl", 43 - "location" : "https://github.com/firebase/nanopb.git", 44 - "state" : { 45 - "revision" : "b7e1104502eca3a213b46303391ca4d3bc8ddec1", 46 - "version" : "2.30910.0" 47 - } 48 - }, 49 - { 50 - "identity" : "promises", 51 - "kind" : "remoteSourceControl", 52 - "location" : "https://github.com/google/promises.git", 53 - "state" : { 54 - "revision" : "540318ecedd63d883069ae7f1ed811a2df00b6ac", 55 - "version" : "2.4.0" 56 - } 57 - } 58 - ], 59 - "version" : 3 60 - }
···
+10
mobile/iosApp/iosApp.xcworkspace/contents.xcworkspacedata
···
··· 1 + <?xml version="1.0" encoding="UTF-8"?> 2 + <Workspace 3 + version = "1.0"> 4 + <FileRef 5 + location = "group:iosApp.xcodeproj"> 6 + </FileRef> 7 + <FileRef 8 + location = "group:Pods/Pods.xcodeproj"> 9 + </FileRef> 10 + </Workspace>
+88 -1
mobile/iosApp/iosApp/ContentView.swift
··· 1 import UIKit 2 import SwiftUI 3 import ComposeApp 4 5 struct ComposeView: UIViewControllerRepresentable { 6 func makeUIViewController(context: Context) -> UIViewController { 7 - MainViewControllerKt.MainViewController() 8 } 9 10 func updateUIViewController(_ uiViewController: UIViewController, context: Context) {} 11 } 12 13 struct ContentView: View {
··· 1 import UIKit 2 import SwiftUI 3 import ComposeApp 4 + import MLKitFaceDetection 5 + import MLKitCommon 6 + import MLKitVision 7 + import AVKit 8 + import Vision 9 + 10 11 struct ComposeView: UIViewControllerRepresentable { 12 func makeUIViewController(context: Context) -> UIViewController { 13 + NativeAnalyzer.shared.analyzeImageNative = { img, callback in 14 + Analyzer().analyzeImageNative(img: NativeAnalyzer.shared.byteArrayToData(byteArray: img)) { rect, size in 15 + _ = callback(rect, size) 16 + } 17 + } 18 + return MainViewControllerKt.MainViewController() 19 } 20 21 func updateUIViewController(_ uiViewController: UIViewController, context: Context) {} 22 + } 23 + 24 + class Analyzer { 25 + @available(iOS 18.0, *) 26 + func analyzeImageNative(img: Data, callback: @escaping (ComposeApp.Rect, ComposeApp.Size) -> ()) { 27 + // let options = FaceDetectorOptions() 28 + // options.performanceMode = .fast 29 + // options.landmarkMode = .none 30 + // options.classificationMode = .none 31 + // 32 + // do { 33 + // if let image = UIImage(data: img) { 34 + // let vizImg = VisionImage(image: image) 35 + //// UIImageWriteToSavedPhotosAlbum(image, self, nil, nil) 36 + // vizImg.orientation = Analyzer.imageOrientation(deviceOrientation: .portrait, cameraPosition: .front) 37 + // 38 + // let faceDetector = FaceDetector.faceDetector(options: options) 39 + // faceDetector.process(vizImg) { faces, err in 40 + // 41 + // if err == nil { 42 + // if let faces { 43 + // print("faces not nil: \(faces.count)") 44 + // for face in faces { 45 + // callback(Rect(top: Float(face.frame.minY), left: Float(face.frame.minX), bottom: Float(face.frame.maxY), right: Float(face.frame.maxX)), Size(width: Float(image.size.width), height: Float(image.size.height))) 46 + // 47 + // } 48 + // } else { 49 + // print("faces nil") 50 + // } 51 + // } else { 52 + // print("skipping frame - error processing image: \(err)") 53 + // } 54 + // } 55 + // 56 + // 57 + // } 58 + // } catch { 59 + // print("skipping frame - error processing image: \(error)") 60 + // } 61 + if let image = UIImage(data: img) { 62 + UIImageWriteToSavedPhotosAlbum(image, self, nil, nil) 63 + let faceDetectionRequest = DetectFaceRectanglesRequest() 64 + Task { 65 + do { 66 + let res = try await faceDetectionRequest.perform(on: CIImage(image: image)!) 67 + res.forEach { face in 68 + 69 + var newSize = face.boundingBox.toImageCoordinates(image.size, origin: .upperLeft) 70 + print("FACE RESULT @ \(newSize)") 71 + callback(Rect(top: Float(newSize.minY), left: Float(newSize.minX), bottom: 0, right: 0), Size(width: Float(image.size.width), height: Float(image.size.height))) 72 + } 73 + } catch { 74 + print("error processing image: \(error)") 75 + } 76 + } 77 + } 78 + 79 + 80 + } 81 + static func imageOrientation( 82 + deviceOrientation: UIDeviceOrientation, 83 + cameraPosition: AVCaptureDevice.Position 84 + ) -> UIImage.Orientation { 85 + switch deviceOrientation { 86 + case .portrait: 87 + return cameraPosition == .front ? .leftMirrored : .right 88 + case .landscapeLeft: 89 + return cameraPosition == .front ? .downMirrored : .up 90 + case .portraitUpsideDown: 91 + return cameraPosition == .front ? .rightMirrored : .left 92 + case .landscapeRight: 93 + return cameraPosition == .front ? .upMirrored : .down 94 + case .faceDown, .faceUp, .unknown: 95 + return .up 96 + } 97 + } 98 } 99 100 struct ContentView: View {