a scrappy gimbal that insults you in shakespearean english

android support-ish (iOS soon)

paytondev 8fb264cd 24e7ac84

Changed files
+1901
mobile
.fleet
composeApp
src
androidMain
commonMain
composeResources
kotlin
com
paytondeveloper
iosMain
kotlin
com
paytondeveloper
gradle
iosApp
Configuration
iosApp
Assets.xcassets
AccentColor.colorset
AppIcon.appiconset
Preview Content
Preview Assets.xcassets
iosApp.xcodeproj
project.xcworkspace
+19
mobile/.fleet/receipt.json
···
+
// Project generated by Kotlin Multiplatform Wizard
+
{
+
"spec": {
+
"template_id": "kmt",
+
"targets": {
+
"android": {
+
"ui": [
+
"compose"
+
]
+
},
+
"ios": {
+
"ui": [
+
"compose"
+
]
+
}
+
}
+
},
+
"timestamp": "2025-03-15T18:00:33.935977603Z"
+
}
+18
mobile/.gitignore
···
+
*.iml
+
.kotlin
+
.gradle
+
**/build/
+
xcuserdata
+
!src/**/build/
+
local.properties
+
.idea
+
.DS_Store
+
captures
+
.externalNativeBuild
+
.cxx
+
*.xcodeproj/*
+
!*.xcodeproj/project.pbxproj
+
!*.xcodeproj/xcshareddata/
+
!*.xcodeproj/project.xcworkspace/
+
!*.xcworkspace/contents.xcworkspacedata
+
**/xcshareddata/WorkspaceSettings.xcsettings
+14
mobile/README.md
···
+
This is a Kotlin Multiplatform project targeting Android, iOS.
+
+
* `/composeApp` is for code that will be shared across your Compose Multiplatform applications.
+
It contains several subfolders:
+
- `commonMain` is for code that’s common for all targets.
+
- Other folders are for Kotlin code that will be compiled for only the platform indicated in the folder name.
+
For example, if you want to use Apple’s CoreCrypto for the iOS part of your Kotlin app,
+
`iosMain` would be the right folder for such calls.
+
+
* `/iosApp` contains iOS applications. Even if you’re sharing your UI with Compose Multiplatform,
+
you need this entry point for your iOS app. This is also where you should add SwiftUI code for your project.
+
+
+
Learn more about [Kotlin Multiplatform](https://www.jetbrains.com/help/kotlin-multiplatform-dev/get-started.html)…
+9
mobile/build.gradle.kts
···
+
plugins {
+
// this is necessary to avoid the plugins to be loaded multiple times
+
// in each subproject's classloader
+
alias(libs.plugins.androidApplication) apply false
+
alias(libs.plugins.androidLibrary) apply false
+
alias(libs.plugins.composeMultiplatform) apply false
+
alias(libs.plugins.composeCompiler) apply false
+
alias(libs.plugins.kotlinMultiplatform) apply false
+
}
+83
mobile/composeApp/build.gradle.kts
···
+
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
+
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
+
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
+
+
plugins {
+
alias(libs.plugins.kotlinMultiplatform)
+
alias(libs.plugins.androidApplication)
+
alias(libs.plugins.composeMultiplatform)
+
alias(libs.plugins.composeCompiler)
+
}
+
+
kotlin {
+
androidTarget {
+
@OptIn(ExperimentalKotlinGradlePluginApi::class)
+
compilerOptions {
+
jvmTarget.set(JvmTarget.JVM_11)
+
}
+
}
+
+
listOf(
+
iosX64(),
+
iosArm64(),
+
iosSimulatorArm64()
+
).forEach { iosTarget ->
+
iosTarget.binaries.framework {
+
baseName = "ComposeApp"
+
isStatic = true
+
}
+
}
+
+
sourceSets {
+
+
androidMain.dependencies {
+
implementation(compose.preview)
+
implementation(libs.androidx.activity.compose)
+
implementation(libs.face.detection)
+
}
+
commonMain.dependencies {
+
implementation(compose.runtime)
+
implementation(compose.foundation)
+
implementation(compose.material)
+
implementation(compose.ui)
+
implementation(compose.components.resources)
+
implementation(compose.components.uiToolingPreview)
+
implementation(libs.androidx.lifecycle.viewmodel)
+
implementation(libs.androidx.lifecycle.runtime.compose)
+
implementation(libs.camerak)
+
implementation(libs.androidx.graphics.shapes)
+
}
+
}
+
}
+
+
android {
+
namespace = "com.paytondeveloper.myrus_mobile"
+
compileSdk = libs.versions.android.compileSdk.get().toInt()
+
+
defaultConfig {
+
applicationId = "com.paytondeveloper.myrus_mobile"
+
minSdk = libs.versions.android.minSdk.get().toInt()
+
targetSdk = libs.versions.android.targetSdk.get().toInt()
+
versionCode = 1
+
versionName = "1.0"
+
}
+
packaging {
+
resources {
+
excludes += "/META-INF/{AL2.0,LGPL2.1}"
+
}
+
}
+
buildTypes {
+
getByName("release") {
+
isMinifyEnabled = false
+
}
+
}
+
compileOptions {
+
sourceCompatibility = JavaVersion.VERSION_11
+
targetCompatibility = JavaVersion.VERSION_11
+
}
+
}
+
+
dependencies {
+
debugImplementation(compose.uiTooling)
+
}
+
+33
mobile/composeApp/src/androidMain/AndroidManifest.xml
···
+
<?xml version="1.0" encoding="utf-8"?>
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
+
+
<uses-feature
+
android:name="android.hardware.camera"
+
android:required="false" />
+
+
<uses-permission android:name="android.permission.CAMERA" />
+
<uses-permission
+
android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
<meta-data
+
android:name="com.google.mlkit.vision.DEPENDENCIES"
+
android:value="face"/>
+
<application
+
android:allowBackup="true"
+
android:icon="@mipmap/ic_launcher"
+
android:label="@string/app_name"
+
android:roundIcon="@mipmap/ic_launcher_round"
+
android:supportsRtl="true"
+
android:theme="@android:style/Theme.Material.Light.NoActionBar">
+
<activity
+
android:exported="true"
+
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden|mnc|colorMode|density|fontScale|fontWeightAdjustment|keyboard|layoutDirection|locale|mcc|navigation|smallestScreenSize|touchscreen|uiMode"
+
android:name=".MainActivity">
+
<intent-filter>
+
<action android:name="android.intent.action.MAIN" />
+
+
<category android:name="android.intent.category.LAUNCHER" />
+
</intent-filter>
+
</activity>
+
</application>
+
+
</manifest>
+189
mobile/composeApp/src/androidMain/kotlin/com/paytondeveloper/myrus_mobile/MLFace.android.kt
···
+
package com.paytondeveloper.myrus_mobile
+
+
import android.app.Activity
+
import android.content.ContentValues
+
import android.content.Context
+
import android.content.Context.CAMERA_SERVICE
+
import android.graphics.Bitmap
+
import android.graphics.BitmapFactory
+
import android.hardware.camera2.CameraAccessException
+
import android.hardware.camera2.CameraCharacteristics
+
import android.hardware.camera2.CameraManager
+
import android.net.Uri
+
import android.os.Build
+
import android.os.Environment
+
import android.provider.MediaStore
+
import android.util.Log
+
import android.util.SparseIntArray
+
import android.view.Surface
+
import androidx.annotation.RequiresApi
+
import androidx.camera.core.Camera
+
import androidx.camera.core.CameraSelector
+
import androidx.camera.core.ImageCapture
+
import androidx.camera.core.impl.CameraInternal
+
import androidx.camera.core.impl.Config
+
import com.google.mlkit.vision.common.InputImage
+
import com.google.mlkit.vision.face.FaceDetection
+
import com.google.mlkit.vision.face.FaceDetector
+
import com.google.mlkit.vision.face.FaceDetectorOptions
+
import com.google.mlkit.vision.face.FaceDetectorOptions.LandmarkMode
+
import com.kashif.cameraK.builder.CameraControllerBuilder
+
import com.kashif.cameraK.controller.CameraController
+
import com.kashif.cameraK.enums.Directory
+
import com.kashif.cameraK.utils.getActivityOrNull
+
import org.slf4j.MDC.put
+
import java.io.FileOutputStream
+
import java.io.IOException
+
+
actual fun CameraController.getResolution(): Size? {
+
val field = this::class.java.getDeclaredField("imageCapture")
+
field.isAccessible = true
+
val imgCapture = field.get(this) as ImageCapture?
+
val res = imgCapture?.resolutionInfo?.resolution
+
return if (res != null) Size(width = res.width.toFloat(), height = res.height.toFloat()) else null
+
+
}
+
+
actual fun analyzeImage(img: ByteArray, callback: (Rect, Size) -> Unit) {
+
// println("res2: ${saveByteArrayToMediaStore(AppInfo.app.applicationContext, img)}")
+
try {
+
+
val rotationDegrees = rotationDegrees(AppInfo.activity, isFrontFacing = true)
+
// val img = InputImage.fromByteArray(img, options.outWidth, options.outHeight, rotationDegrees, InputImage.IMAGE_FORMAT_NV21)
+
val bitmap = BitmapFactory.decodeByteArray(img, 0, img.size)
+
val img = InputImage.fromBitmap(bitmap, 0)
+
val detector = FaceDetection.getClient()
+
if (AppInfo.canDetectFace) {
+
AppInfo.canDetectFace = false
+
val res = detector.process(img)
+
res.addOnCompleteListener {
+
println("ml completed: ${it.isSuccessful} ${it.exception} ${res.result.count()}")
+
AppInfo.canDetectFace = true
+
res.result.forEach {
+
println("FACE @ ${it.boundingBox.top}")
+
+
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()))
+
}
+
}
+
}
+
+
} catch (e: Exception) {
+
println("error: ${e}")
+
}
+
}
+
+
+
+
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+
@Throws(CameraAccessException::class)
+
fun rotationDegrees(activity: Activity, isFrontFacing: Boolean): Int {
+
val ORIENTATIONS = SparseIntArray()
+
ORIENTATIONS.append(Surface.ROTATION_0, 0)
+
ORIENTATIONS.append(Surface.ROTATION_90, 90)
+
ORIENTATIONS.append(Surface.ROTATION_180, 180)
+
ORIENTATIONS.append(Surface.ROTATION_270, 270)
+
+
/**
+
* Get the angle by which an image must be rotated given the device's current
+
* orientation.
+
*/
+
+
// Get the device's current rotation relative to its "native" orientation.
+
// Then, from the ORIENTATIONS table, look up the angle the image must be
+
// rotated to compensate for the device's rotation.
+
val deviceRotation = activity.windowManager.defaultDisplay.rotation
+
var rotationCompensation = ORIENTATIONS.get(deviceRotation)
+
+
// Get the device's sensor orientation.
+
val cameraManager = activity.getSystemService(CAMERA_SERVICE) as CameraManager
+
var cameraId = ""
+
cameraManager.cameraIdList.forEach {
+
if (cameraManager.getCameraCharacteristics(it).get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT) cameraId = it
+
}
+
val sensorOrientation = cameraManager
+
.getCameraCharacteristics(cameraId)
+
.get(CameraCharacteristics.SENSOR_ORIENTATION)!!
+
+
if (isFrontFacing) {
+
rotationCompensation = (sensorOrientation + rotationCompensation) % 360
+
} else { // back-facing
+
rotationCompensation = (sensorOrientation - rotationCompensation + 360) % 360
+
}
+
return rotationCompensation
+
}
+
+
//DEBUG ONLY
+
+
fun saveByteArrayToMediaStore(
+
context: Context,
+
byteArray: ByteArray,
+
filename: String = "image_${System.currentTimeMillis()}.jpg",
+
mimeType: String = "image/png",
+
quality: Int = 100
+
): Uri? {
+
// First decode the image to get its dimensions
+
val options = BitmapFactory.Options().apply {
+
inJustDecodeBounds = true // This option decodes only the dimensions without loading the full bitmap
+
}
+
+
BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size, options)
+
+
// Check if we could decode the image dimensions
+
if (options.outWidth <= 0 || options.outHeight <= 0) {
+
return null // Invalid image data
+
}
+
+
// Now decode the actual bitmap
+
val bitmap = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size)
+
?: return null // Failed to decode
+
+
// Set up the MediaStore ContentValues
+
val contentValues = ContentValues().apply {
+
put(MediaStore.Images.Media.DISPLAY_NAME, filename)
+
put(MediaStore.Images.Media.MIME_TYPE, mimeType)
+
put(MediaStore.Images.Media.WIDTH, bitmap.width)
+
put(MediaStore.Images.Media.HEIGHT, bitmap.height)
+
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+
put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES)
+
put(MediaStore.Images.Media.IS_PENDING, 1)
+
}
+
}
+
+
// Insert and get the URI
+
val contentResolver = context.contentResolver
+
val uri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
+
+
uri?.let {
+
try {
+
contentResolver.openOutputStream(it)?.use { outputStream ->
+
bitmap.compress(
+
when (mimeType) {
+
"image/png" -> Bitmap.CompressFormat.PNG
+
"image/webp" -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+
Bitmap.CompressFormat.WEBP_LOSSLESS
+
} else {
+
@Suppress("DEPRECATION")
+
Bitmap.CompressFormat.WEBP
+
}
+
else -> Bitmap.CompressFormat.JPEG
+
},
+
quality,
+
outputStream
+
)
+
}
+
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+
contentValues.clear()
+
contentValues.put(MediaStore.Images.Media.IS_PENDING, 0)
+
contentResolver.update(it, contentValues, null, null)
+
}
+
} catch (e: IOException) {
+
contentResolver.delete(it, null, null)
+
return null
+
}
+
}
+
+
bitmap.recycle()
+
return uri
+
}
+34
mobile/composeApp/src/androidMain/kotlin/com/paytondeveloper/myrus_mobile/MainActivity.kt
···
+
package com.paytondeveloper.myrus_mobile
+
+
import android.app.Activity
+
import android.app.Application
+
import android.os.Bundle
+
import androidx.activity.ComponentActivity
+
import androidx.activity.compose.setContent
+
import androidx.activity.enableEdgeToEdge
+
import androidx.compose.runtime.Composable
+
import androidx.compose.ui.tooling.preview.Preview
+
+
class MainActivity : ComponentActivity() {
+
override fun onCreate(savedInstanceState: Bundle?) {
+
super.onCreate(savedInstanceState)
+
AppInfo.app = this.application
+
AppInfo.activity = this
+
enableEdgeToEdge()
+
setContent {
+
App()
+
}
+
}
+
}
+
+
@Preview
+
@Composable
+
fun AppAndroidPreview() {
+
App()
+
}
+
+
object AppInfo {
+
lateinit var app: Application
+
lateinit var activity: Activity
+
var canDetectFace: Boolean = true
+
}
+12
mobile/composeApp/src/androidMain/kotlin/com/paytondeveloper/myrus_mobile/Platform.android.kt
···
+
package com.paytondeveloper.myrus_mobile
+
+
import android.os.Build
+
import com.kashif.cameraK.controller.CameraController
+
+
class AndroidPlatform : Platform {
+
override val name: String = "Android ${Build.VERSION.SDK_INT}"
+
}
+
+
actual fun getPlatform(): Platform = AndroidPlatform()
+
+
+30
mobile/composeApp/src/androidMain/res/drawable-v24/ic_launcher_foreground.xml
···
+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
+
xmlns:aapt="http://schemas.android.com/aapt"
+
android:width="108dp"
+
android:height="108dp"
+
android:viewportWidth="108"
+
android:viewportHeight="108">
+
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
+
<aapt:attr name="android:fillColor">
+
<gradient
+
android:endX="85.84757"
+
android:endY="92.4963"
+
android:startX="42.9492"
+
android:startY="49.59793"
+
android:type="linear">
+
<item
+
android:color="#44000000"
+
android:offset="0.0" />
+
<item
+
android:color="#00000000"
+
android:offset="1.0" />
+
</gradient>
+
</aapt:attr>
+
</path>
+
<path
+
android:fillColor="#FFFFFF"
+
android:fillType="nonZero"
+
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
+
android:strokeWidth="1"
+
android:strokeColor="#00000000" />
+
</vector>
+170
mobile/composeApp/src/androidMain/res/drawable/ic_launcher_background.xml
···
+
<?xml version="1.0" encoding="utf-8"?>
+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
+
android:width="108dp"
+
android:height="108dp"
+
android:viewportWidth="108"
+
android:viewportHeight="108">
+
<path
+
android:fillColor="#3DDC84"
+
android:pathData="M0,0h108v108h-108z" />
+
<path
+
android:fillColor="#00000000"
+
android:pathData="M9,0L9,108"
+
android:strokeWidth="0.8"
+
android:strokeColor="#33FFFFFF" />
+
<path
+
android:fillColor="#00000000"
+
android:pathData="M19,0L19,108"
+
android:strokeWidth="0.8"
+
android:strokeColor="#33FFFFFF" />
+
<path
+
android:fillColor="#00000000"
+
android:pathData="M29,0L29,108"
+
android:strokeWidth="0.8"
+
android:strokeColor="#33FFFFFF" />
+
<path
+
android:fillColor="#00000000"
+
android:pathData="M39,0L39,108"
+
android:strokeWidth="0.8"
+
android:strokeColor="#33FFFFFF" />
+
<path
+
android:fillColor="#00000000"
+
android:pathData="M49,0L49,108"
+
android:strokeWidth="0.8"
+
android:strokeColor="#33FFFFFF" />
+
<path
+
android:fillColor="#00000000"
+
android:pathData="M59,0L59,108"
+
android:strokeWidth="0.8"
+
android:strokeColor="#33FFFFFF" />
+
<path
+
android:fillColor="#00000000"
+
android:pathData="M69,0L69,108"
+
android:strokeWidth="0.8"
+
android:strokeColor="#33FFFFFF" />
+
<path
+
android:fillColor="#00000000"
+
android:pathData="M79,0L79,108"
+
android:strokeWidth="0.8"
+
android:strokeColor="#33FFFFFF" />
+
<path
+
android:fillColor="#00000000"
+
android:pathData="M89,0L89,108"
+
android:strokeWidth="0.8"
+
android:strokeColor="#33FFFFFF" />
+
<path
+
android:fillColor="#00000000"
+
android:pathData="M99,0L99,108"
+
android:strokeWidth="0.8"
+
android:strokeColor="#33FFFFFF" />
+
<path
+
android:fillColor="#00000000"
+
android:pathData="M0,9L108,9"
+
android:strokeWidth="0.8"
+
android:strokeColor="#33FFFFFF" />
+
<path
+
android:fillColor="#00000000"
+
android:pathData="M0,19L108,19"
+
android:strokeWidth="0.8"
+
android:strokeColor="#33FFFFFF" />
+
<path
+
android:fillColor="#00000000"
+
android:pathData="M0,29L108,29"
+
android:strokeWidth="0.8"
+
android:strokeColor="#33FFFFFF" />
+
<path
+
android:fillColor="#00000000"
+
android:pathData="M0,39L108,39"
+
android:strokeWidth="0.8"
+
android:strokeColor="#33FFFFFF" />
+
<path
+
android:fillColor="#00000000"
+
android:pathData="M0,49L108,49"
+
android:strokeWidth="0.8"
+
android:strokeColor="#33FFFFFF" />
+
<path
+
android:fillColor="#00000000"
+
android:pathData="M0,59L108,59"
+
android:strokeWidth="0.8"
+
android:strokeColor="#33FFFFFF" />
+
<path
+
android:fillColor="#00000000"
+
android:pathData="M0,69L108,69"
+
android:strokeWidth="0.8"
+
android:strokeColor="#33FFFFFF" />
+
<path
+
android:fillColor="#00000000"
+
android:pathData="M0,79L108,79"
+
android:strokeWidth="0.8"
+
android:strokeColor="#33FFFFFF" />
+
<path
+
android:fillColor="#00000000"
+
android:pathData="M0,89L108,89"
+
android:strokeWidth="0.8"
+
android:strokeColor="#33FFFFFF" />
+
<path
+
android:fillColor="#00000000"
+
android:pathData="M0,99L108,99"
+
android:strokeWidth="0.8"
+
android:strokeColor="#33FFFFFF" />
+
<path
+
android:fillColor="#00000000"
+
android:pathData="M19,29L89,29"
+
android:strokeWidth="0.8"
+
android:strokeColor="#33FFFFFF" />
+
<path
+
android:fillColor="#00000000"
+
android:pathData="M19,39L89,39"
+
android:strokeWidth="0.8"
+
android:strokeColor="#33FFFFFF" />
+
<path
+
android:fillColor="#00000000"
+
android:pathData="M19,49L89,49"
+
android:strokeWidth="0.8"
+
android:strokeColor="#33FFFFFF" />
+
<path
+
android:fillColor="#00000000"
+
android:pathData="M19,59L89,59"
+
android:strokeWidth="0.8"
+
android:strokeColor="#33FFFFFF" />
+
<path
+
android:fillColor="#00000000"
+
android:pathData="M19,69L89,69"
+
android:strokeWidth="0.8"
+
android:strokeColor="#33FFFFFF" />
+
<path
+
android:fillColor="#00000000"
+
android:pathData="M19,79L89,79"
+
android:strokeWidth="0.8"
+
android:strokeColor="#33FFFFFF" />
+
<path
+
android:fillColor="#00000000"
+
android:pathData="M29,19L29,89"
+
android:strokeWidth="0.8"
+
android:strokeColor="#33FFFFFF" />
+
<path
+
android:fillColor="#00000000"
+
android:pathData="M39,19L39,89"
+
android:strokeWidth="0.8"
+
android:strokeColor="#33FFFFFF" />
+
<path
+
android:fillColor="#00000000"
+
android:pathData="M49,19L49,89"
+
android:strokeWidth="0.8"
+
android:strokeColor="#33FFFFFF" />
+
<path
+
android:fillColor="#00000000"
+
android:pathData="M59,19L59,89"
+
android:strokeWidth="0.8"
+
android:strokeColor="#33FFFFFF" />
+
<path
+
android:fillColor="#00000000"
+
android:pathData="M69,19L69,89"
+
android:strokeWidth="0.8"
+
android:strokeColor="#33FFFFFF" />
+
<path
+
android:fillColor="#00000000"
+
android:pathData="M79,19L79,89"
+
android:strokeWidth="0.8"
+
android:strokeColor="#33FFFFFF" />
+
</vector>
+5
mobile/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher.xml
···
+
<?xml version="1.0" encoding="utf-8"?>
+
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+
<background android:drawable="@drawable/ic_launcher_background" />
+
<foreground android:drawable="@drawable/ic_launcher_foreground" />
+
</adaptive-icon>
+5
mobile/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher_round.xml
···
+
<?xml version="1.0" encoding="utf-8"?>
+
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+
<background android:drawable="@drawable/ic_launcher_background" />
+
<foreground android:drawable="@drawable/ic_launcher_foreground" />
+
</adaptive-icon>
mobile/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher.png

This is a binary file and will not be displayed.

mobile/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher_round.png

This is a binary file and will not be displayed.

mobile/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher.png

This is a binary file and will not be displayed.

mobile/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher_round.png

This is a binary file and will not be displayed.

mobile/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher.png

This is a binary file and will not be displayed.

mobile/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher_round.png

This is a binary file and will not be displayed.

mobile/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher.png

This is a binary file and will not be displayed.

mobile/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher_round.png

This is a binary file and will not be displayed.

mobile/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher.png

This is a binary file and will not be displayed.

mobile/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_round.png

This is a binary file and will not be displayed.

+3
mobile/composeApp/src/androidMain/res/values/strings.xml
···
+
<resources>
+
<string name="app_name">myrus-mobile</string>
+
</resources>
+36
mobile/composeApp/src/commonMain/composeResources/drawable/compose-multiplatform.xml
···
+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
+
android:width="600dp"
+
android:height="600dp"
+
android:viewportWidth="600"
+
android:viewportHeight="600">
+
<path
+
android:pathData="M301.21,418.53C300.97,418.54 300.73,418.56 300.49,418.56C297.09,418.59 293.74,417.72 290.79,416.05L222.6,377.54C220.63,376.43 219,374.82 217.85,372.88C216.7,370.94 216.09,368.73 216.07,366.47L216.07,288.16C216.06,287.32 216.09,286.49 216.17,285.67C216.38,283.54 216.91,281.5 217.71,279.6L199.29,268.27L177.74,256.19C175.72,260.43 174.73,265.23 174.78,270.22L174.79,387.05C174.85,393.89 178.57,400.2 184.53,403.56L286.26,461.02C290.67,463.51 295.66,464.8 300.73,464.76C300.91,464.76 301.09,464.74 301.27,464.74C301.24,449.84 301.22,439.23 301.22,439.23L301.21,418.53Z"
+
android:fillColor="#041619"
+
android:fillType="nonZero"/>
+
<path
+
android:pathData="M409.45,242.91L312.64,188.23C303.64,183.15 292.58,183.26 283.68,188.51L187.92,245C183.31,247.73 179.93,251.62 177.75,256.17L177.74,256.19L199.29,268.27L217.71,279.6C217.83,279.32 217.92,279.02 218.05,278.74C218.24,278.36 218.43,277.98 218.64,277.62C219.06,276.88 219.52,276.18 220.04,275.51C221.37,273.8 223.01,272.35 224.87,271.25L289.06,233.39C290.42,232.59 291.87,231.96 293.39,231.51C295.53,230.87 297.77,230.6 300,230.72C302.98,230.88 305.88,231.73 308.47,233.2L373.37,269.85C375.54,271.08 377.49,272.68 379.13,274.57C379.68,275.19 380.18,275.85 380.65,276.53C380.86,276.84 381.05,277.15 381.24,277.47L397.79,266.39L420.34,252.93L420.31,252.88C417.55,248.8 413.77,245.35 409.45,242.91Z"
+
android:fillColor="#37BF6E"
+
android:fillType="nonZero"/>
+
<path
+
android:pathData="M381.24,277.47C381.51,277.92 381.77,278.38 382.01,278.84C382.21,279.24 382.39,279.65 382.57,280.06C382.91,280.88 383.19,281.73 383.41,282.59C383.74,283.88 383.92,285.21 383.93,286.57L383.93,361.1C383.96,363.95 383.35,366.77 382.16,369.36C381.93,369.86 381.69,370.35 381.42,370.83C379.75,373.79 377.32,376.27 374.39,378L310.2,415.87C307.47,417.48 304.38,418.39 301.21,418.53L301.22,439.23C301.22,439.23 301.24,449.84 301.27,464.74C306.1,464.61 310.91,463.3 315.21,460.75L410.98,404.25C419.88,399 425.31,389.37 425.22,379.03L425.22,267.85C425.17,262.48 423.34,257.34 420.34,252.93L397.79,266.39L381.24,277.47Z"
+
android:fillColor="#3870B2"
+
android:fillType="nonZero"/>
+
<path
+
android:pathData="M177.75,256.17C179.93,251.62 183.31,247.73 187.92,245L283.68,188.51C292.58,183.26 303.64,183.15 312.64,188.23L409.45,242.91C413.77,245.35 417.55,248.8 420.31,252.88L420.34,252.93L498.59,206.19C494.03,199.46 487.79,193.78 480.67,189.75L320.86,99.49C306.01,91.1 287.75,91.27 273.07,99.95L114.99,193.2C107.39,197.69 101.81,204.11 98.21,211.63L177.74,256.19L177.75,256.17ZM301.27,464.74C301.09,464.74 300.91,464.76 300.73,464.76C295.66,464.8 290.67,463.51 286.26,461.02L184.53,403.56C178.57,400.2 174.85,393.89 174.79,387.05L174.78,270.22C174.73,265.23 175.72,260.43 177.74,256.19L98.21,211.63C94.86,218.63 93.23,226.58 93.31,234.82L93.31,427.67C93.42,438.97 99.54,449.37 109.4,454.92L277.31,549.77C284.6,553.88 292.84,556.01 301.2,555.94L301.2,555.8C301.39,543.78 301.33,495.26 301.27,464.74Z"
+
android:strokeWidth="10"
+
android:fillColor="#00000000"
+
android:strokeColor="#083042"
+
android:fillType="nonZero"/>
+
<path
+
android:pathData="M498.59,206.19L420.34,252.93C423.34,257.34 425.17,262.48 425.22,267.85L425.22,379.03C425.31,389.37 419.88,399 410.98,404.25L315.21,460.75C310.91,463.3 306.1,464.61 301.27,464.74C301.33,495.26 301.39,543.78 301.2,555.8L301.2,555.94C309.48,555.87 317.74,553.68 325.11,549.32L483.18,456.06C497.87,447.39 506.85,431.49 506.69,414.43L506.69,230.91C506.6,222.02 503.57,213.5 498.59,206.19Z"
+
android:strokeWidth="10"
+
android:fillColor="#00000000"
+
android:strokeColor="#083042"
+
android:fillType="nonZero"/>
+
<path
+
android:pathData="M301.2,555.94C292.84,556.01 284.6,553.88 277.31,549.76L109.4,454.92C99.54,449.37 93.42,438.97 93.31,427.67L93.31,234.82C93.23,226.58 94.86,218.63 98.21,211.63C101.81,204.11 107.39,197.69 114.99,193.2L273.07,99.95C287.75,91.27 306.01,91.1 320.86,99.49L480.67,189.75C487.79,193.78 494.03,199.46 498.59,206.19C503.57,213.5 506.6,222.02 506.69,230.91L506.69,414.43C506.85,431.49 497.87,447.39 483.18,456.06L325.11,549.32C317.74,553.68 309.48,555.87 301.2,555.94Z"
+
android:strokeWidth="10"
+
android:fillColor="#00000000"
+
android:strokeColor="#083042"
+
android:fillType="nonZero"/>
+
</vector>
+150
mobile/composeApp/src/commonMain/kotlin/com/paytondeveloper/myrus_mobile/App.kt
···
+
package com.paytondeveloper.myrus_mobile
+
+
import androidx.compose.animation.AnimatedVisibility
+
import androidx.compose.foundation.Image
+
import androidx.compose.foundation.layout.Box
+
import androidx.compose.foundation.layout.Column
+
import androidx.compose.foundation.layout.fillMaxSize
+
import androidx.compose.foundation.layout.fillMaxWidth
+
import androidx.compose.foundation.layout.offset
+
import androidx.compose.material.Button
+
import androidx.compose.material.MaterialTheme
+
import androidx.compose.material.Text
+
import androidx.compose.runtime.*
+
import androidx.compose.ui.Alignment
+
import androidx.compose.ui.Modifier
+
import androidx.compose.ui.draw.drawWithCache
+
import androidx.compose.ui.geometry.Offset
+
import androidx.compose.ui.graphics.Color
+
import androidx.compose.ui.graphics.RectangleShape
+
import androidx.compose.ui.layout.onSizeChanged
+
import androidx.compose.ui.platform.LocalDensity
+
import androidx.compose.ui.platform.LocalViewConfiguration
+
import androidx.compose.ui.unit.dp
+
import androidx.graphics.shapes.RoundedPolygon
+
import com.kashif.cameraK.builder.CameraControllerBuilder
+
import com.kashif.cameraK.controller.CameraController
+
import com.kashif.cameraK.enums.CameraLens
+
import com.kashif.cameraK.enums.Directory
+
import com.kashif.cameraK.enums.ImageFormat
+
import com.kashif.cameraK.permissions.providePermissions
+
import com.kashif.cameraK.result.ImageCaptureResult
+
import com.kashif.cameraK.ui.CameraPreview
+
import io.ktor.util.Identity.encode
+
import kotlinx.coroutines.delay
+
import org.jetbrains.compose.resources.painterResource
+
import org.jetbrains.compose.ui.tooling.preview.Preview
+
+
import myrus_mobile.composeapp.generated.resources.Res
+
import myrus_mobile.composeapp.generated.resources.compose_multiplatform
+
+
expect fun analyzeImage(img: ByteArray, callback: (Rect, Size) -> Unit)
+
+
data class Size(val width: Float, val height: Float)
+
data class Rect(val top: Float, val left: Float, val bottom: Float, val right: Float)
+
data class FaceData(val boundingBox: Rect)
+
+
+
expect fun CameraController.getResolution(): Size?
+
+
@Composable
+
@Preview
+
fun App() {
+
MaterialTheme {
+
val permissions = providePermissions()
+
val camPermission = remember { mutableStateOf(permissions.hasCameraPermission()) }
+
if (!camPermission.value) {
+
permissions.RequestCameraPermission( {
+
camPermission.value = true
+
}, onDenied = {
+
camPermission.value = false
+
})
+
}
+
+
+
+
if (camPermission.value) {
+
var camController by remember { mutableStateOf<CameraController?>(null) }
+
var camSize by remember { mutableStateOf<Size?>(null) }
+
var currentThingy by remember { mutableStateOf<Rect?>(Rect(0f,0f,0f,0f)) }
+
LaunchedEffect(Unit) {
+
//not proud of this.
+
suspend fun runloop() {
+
+
val res = camController?.takePicture()
+
res?.let {
+
when (it) {
+
is ImageCaptureResult.Error -> {
+
println("error taking pic. skipping frame: ${it.exception}")
+
}
+
is ImageCaptureResult.Success -> {
+
analyzeImage(it.byteArray, { it, size ->
+
// println("offset: ${it.top} ${it.left}")
+
val factorY = it.top.toFloat() / size.height.toFloat()
+
val factorX = it.left.toFloat() / size.width.toFloat()
+
+
val newY = factorY * camSize!!.height.toFloat()
+
val newX = factorX * camSize!!.width.toFloat()
+
+
currentThingy = it.copy(top = newY, left = newX)
+
})
+
}
+
}
+
}
+
delay(1000)
+
runloop()
+
}
+
runloop()
+
}
+
Box(modifier = Modifier/*.drawWithCache {
+
if (currentThingy != null) {
+
val roundedPolygon = RoundedPolygon(
+
numVertices = 6,
+
radius = (currentThingy!!.right - currentThingy!!.left).toFloat(),
+
centerX = currentThingy!!.left.toFloat(),
+
centerY = currentThingy!!.top.toFloat()
+
)
+
val roundedPolygonPath = roundedPolygon
+
onDrawBehind {
+
// drawPath(roundedPolygonPath, color = Color.Blue)
+
drawRect(
+
color = Color.Red,
+
topLeft = Offset(currentThingy!!.left.toFloat(), currentThingy!!.top.toFloat()),
+
size = androidx.compose.ui.geometry.Size(width = (currentThingy!!.right - currentThingy!!.left).toFloat(), height = (currentThingy!!.bottom - currentThingy!!.top).toFloat())
+
)
+
}
+
+
} else {
+
onDrawBehind { }
+
}
+
}*/) {
+
val topPx = with(LocalDensity.current) {
+
currentThingy!!.top.toDp()
+
}
+
val leftPx = with(LocalDensity.current) {
+
currentThingy!!.left.toDp()
+
}
+
println("offset (dp) ${topPx} ${leftPx}")
+
+
CameraPreview(modifier = Modifier.fillMaxSize().onSizeChanged {
+
camSize = Size(
+
width = it.width.toFloat(),
+
height = it.height.toFloat()
+
)
+
println("camsize: ${camSize?.width}x${camSize?.height}")
+
}, {
+
setCameraLens(CameraLens.FRONT)
+
setImageFormat(ImageFormat.PNG)
+
setDirectory(Directory.PICTURES)
+
+
+
}, onCameraControllerReady = {
+
camController = it
+
})
+
Text("Face", modifier = Modifier.offset(x = leftPx, y = topPx))
+
}
+
} else {
+
Text("no permissions!! can't do anything :(")
+
}
+
}
+
}
+9
mobile/composeApp/src/commonMain/kotlin/com/paytondeveloper/myrus_mobile/Greeting.kt
···
+
package com.paytondeveloper.myrus_mobile
+
+
class Greeting {
+
private val platform = getPlatform()
+
+
fun greet(): String {
+
return "Hello, ${platform.name}!"
+
}
+
}
+7
mobile/composeApp/src/commonMain/kotlin/com/paytondeveloper/myrus_mobile/Platform.kt
···
+
package com.paytondeveloper.myrus_mobile
+
+
interface Platform {
+
val name: String
+
}
+
+
expect fun getPlatform(): Platform
+8
mobile/composeApp/src/iosMain/kotlin/com/paytondeveloper/myrus_mobile/MLFace.ios.kt
···
+
package com.paytondeveloper.myrus_mobile
+
+
import com.kashif.cameraK.builder.CameraControllerBuilder
+
import com.kashif.cameraK.controller.CameraController
+
+
actual fun analyzeImage(img: ByteArray, callback:(Rect, Size) -> Unit) {}
+
+
actual fun CameraController.getResolution(): Size? {return null}
+5
mobile/composeApp/src/iosMain/kotlin/com/paytondeveloper/myrus_mobile/MainViewController.kt
···
+
package com.paytondeveloper.myrus_mobile
+
+
import androidx.compose.ui.window.ComposeUIViewController
+
+
fun MainViewController() = ComposeUIViewController { App() }
+9
mobile/composeApp/src/iosMain/kotlin/com/paytondeveloper/myrus_mobile/Platform.ios.kt
···
+
package com.paytondeveloper.myrus_mobile
+
+
import platform.UIKit.UIDevice
+
+
class IOSPlatform: Platform {
+
override val name: String = UIDevice.currentDevice.systemName() + " " + UIDevice.currentDevice.systemVersion
+
}
+
+
actual fun getPlatform(): Platform = IOSPlatform()
+10
mobile/gradle.properties
···
+
#Kotlin
+
kotlin.code.style=official
+
kotlin.daemon.jvmargs=-Xmx2048M
+
+
#Gradle
+
org.gradle.jvmargs=-Xmx2048M -Dfile.encoding=UTF-8
+
+
#Android
+
android.nonTransitiveRClass=true
+
android.useAndroidX=true
+43
mobile/gradle/libs.versions.toml
···
+
[versions]
+
agp = "8.5.2"
+
android-compileSdk = "34"
+
android-minSdk = "24"
+
android-targetSdk = "34"
+
androidx-activityCompose = "1.9.3"
+
androidx-appcompat = "1.7.0"
+
androidx-constraintlayout = "2.2.0"
+
androidx-core-ktx = "1.15.0"
+
androidx-espresso-core = "3.6.1"
+
androidx-lifecycle = "2.8.4"
+
androidx-material = "1.12.0"
+
androidx-test-junit = "1.2.1"
+
camerak = "0.0.10"
+
compose-multiplatform = "1.7.0"
+
faceDetection = "16.1.7"
+
graphicsShapes = "1.0.1"
+
junit = "4.13.2"
+
kotlin = "2.1.0"
+
+
[libraries]
+
androidx-graphics-shapes = { module = "androidx.graphics:graphics-shapes", version.ref = "graphicsShapes" }
+
camerak = { module = "io.github.kashif-mehmood-km:camerak", version.ref = "camerak" }
+
face-detection = { module = "com.google.mlkit:face-detection", version.ref = "faceDetection" }
+
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
+
kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" }
+
junit = { group = "junit", name = "junit", version.ref = "junit" }
+
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "androidx-core-ktx" }
+
androidx-test-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test-junit" }
+
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "androidx-espresso-core" }
+
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "androidx-appcompat" }
+
androidx-material = { group = "com.google.android.material", name = "material", version.ref = "androidx-material" }
+
androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "androidx-constraintlayout" }
+
androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activityCompose" }
+
androidx-lifecycle-viewmodel = { group = "org.jetbrains.androidx.lifecycle", name = "lifecycle-viewmodel", version.ref = "androidx-lifecycle" }
+
androidx-lifecycle-runtime-compose = { group = "org.jetbrains.androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "androidx-lifecycle" }
+
+
[plugins]
+
androidApplication = { id = "com.android.application", version.ref = "agp" }
+
androidLibrary = { id = "com.android.library", version.ref = "agp" }
+
composeMultiplatform = { id = "org.jetbrains.compose", version.ref = "compose-multiplatform" }
+
composeCompiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
+
kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
mobile/gradle/wrapper/gradle-wrapper.jar

This is a binary file and will not be displayed.

+7
mobile/gradle/wrapper/gradle-wrapper.properties
···
+
distributionBase=GRADLE_USER_HOME
+
distributionPath=wrapper/dists
+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
+
networkTimeout=10000
+
validateDistributionUrl=true
+
zipStoreBase=GRADLE_USER_HOME
+
zipStorePath=wrapper/dists
+252
mobile/gradlew
···
+
#!/bin/sh
+
+
#
+
# Copyright © 2015-2021 the original authors.
+
#
+
# Licensed under the Apache License, Version 2.0 (the "License");
+
# you may not use this file except in compliance with the License.
+
# You may obtain a copy of the License at
+
#
+
# https://www.apache.org/licenses/LICENSE-2.0
+
#
+
# Unless required by applicable law or agreed to in writing, software
+
# distributed under the License is distributed on an "AS IS" BASIS,
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+
# See the License for the specific language governing permissions and
+
# limitations under the License.
+
#
+
# SPDX-License-Identifier: Apache-2.0
+
#
+
+
##############################################################################
+
#
+
# Gradle start up script for POSIX generated by Gradle.
+
#
+
# Important for running:
+
#
+
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+
# noncompliant, but you have some other compliant shell such as ksh or
+
# bash, then to run this script, type that shell name before the whole
+
# command line, like:
+
#
+
# ksh Gradle
+
#
+
# Busybox and similar reduced shells will NOT work, because this script
+
# requires all of these POSIX shell features:
+
# * functions;
+
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+
# * compound commands having a testable exit status, especially «case»;
+
# * various built-in commands including «command», «set», and «ulimit».
+
#
+
# Important for patching:
+
#
+
# (2) This script targets any POSIX shell, so it avoids extensions provided
+
# by Bash, Ksh, etc; in particular arrays are avoided.
+
#
+
# The "traditional" practice of packing multiple parameters into a
+
# space-separated string is a well documented source of bugs and security
+
# problems, so this is (mostly) avoided, by progressively accumulating
+
# options in "$@", and eventually passing that to Java.
+
#
+
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+
# see the in-line comments for details.
+
#
+
# There are tweaks for specific operating systems such as AIX, CygWin,
+
# Darwin, MinGW, and NonStop.
+
#
+
# (3) This script is generated from the Groovy template
+
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+
# within the Gradle project.
+
#
+
# You can find Gradle at https://github.com/gradle/gradle/.
+
#
+
##############################################################################
+
+
# Attempt to set APP_HOME
+
+
# Resolve links: $0 may be a link
+
app_path=$0
+
+
# Need this for daisy-chained symlinks.
+
while
+
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+
[ -h "$app_path" ]
+
do
+
ls=$( ls -ld "$app_path" )
+
link=${ls#*' -> '}
+
case $link in #(
+
/*) app_path=$link ;; #(
+
*) app_path=$APP_HOME$link ;;
+
esac
+
done
+
+
# This is normally unused
+
# shellcheck disable=SC2034
+
APP_BASE_NAME=${0##*/}
+
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
+
' "$PWD" ) || exit
+
+
# Use the maximum available, or set MAX_FD != -1 to use that value.
+
MAX_FD=maximum
+
+
warn () {
+
echo "$*"
+
} >&2
+
+
die () {
+
echo
+
echo "$*"
+
echo
+
exit 1
+
} >&2
+
+
# OS specific support (must be 'true' or 'false').
+
cygwin=false
+
msys=false
+
darwin=false
+
nonstop=false
+
case "$( uname )" in #(
+
CYGWIN* ) cygwin=true ;; #(
+
Darwin* ) darwin=true ;; #(
+
MSYS* | MINGW* ) msys=true ;; #(
+
NONSTOP* ) nonstop=true ;;
+
esac
+
+
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+
# Determine the Java command to use to start the JVM.
+
if [ -n "$JAVA_HOME" ] ; then
+
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+
# IBM's JDK on AIX uses strange locations for the executables
+
JAVACMD=$JAVA_HOME/jre/sh/java
+
else
+
JAVACMD=$JAVA_HOME/bin/java
+
fi
+
if [ ! -x "$JAVACMD" ] ; then
+
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+
Please set the JAVA_HOME variable in your environment to match the
+
location of your Java installation."
+
fi
+
else
+
JAVACMD=java
+
if ! command -v java >/dev/null 2>&1
+
then
+
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+
Please set the JAVA_HOME variable in your environment to match the
+
location of your Java installation."
+
fi
+
fi
+
+
# Increase the maximum file descriptors if we can.
+
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+
case $MAX_FD in #(
+
max*)
+
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+
# shellcheck disable=SC2039,SC3045
+
MAX_FD=$( ulimit -H -n ) ||
+
warn "Could not query maximum file descriptor limit"
+
esac
+
case $MAX_FD in #(
+
'' | soft) :;; #(
+
*)
+
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+
# shellcheck disable=SC2039,SC3045
+
ulimit -n "$MAX_FD" ||
+
warn "Could not set maximum file descriptor limit to $MAX_FD"
+
esac
+
fi
+
+
# Collect all arguments for the java command, stacking in reverse order:
+
# * args from the command line
+
# * the main class name
+
# * -classpath
+
# * -D...appname settings
+
# * --module-path (only if needed)
+
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+
# For Cygwin or MSYS, switch paths to Windows format before running java
+
if "$cygwin" || "$msys" ; then
+
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+
JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+
# Now convert the arguments - kludge to limit ourselves to /bin/sh
+
for arg do
+
if
+
case $arg in #(
+
-*) false ;; # don't mess with options #(
+
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+
[ -e "$t" ] ;; #(
+
*) false ;;
+
esac
+
then
+
arg=$( cygpath --path --ignore --mixed "$arg" )
+
fi
+
# Roll the args list around exactly as many times as the number of
+
# args, so each arg winds up back in the position where it started, but
+
# possibly modified.
+
#
+
# NB: a `for` loop captures its iteration list before it begins, so
+
# changing the positional parameters here affects neither the number of
+
# iterations, nor the values presented in `arg`.
+
shift # remove old arg
+
set -- "$@" "$arg" # push replacement arg
+
done
+
fi
+
+
+
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+
# Collect all arguments for the java command:
+
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+
# and any embedded shellness will be escaped.
+
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+
# treated as '${Hostname}' itself on the command line.
+
+
set -- \
+
"-Dorg.gradle.appname=$APP_BASE_NAME" \
+
-classpath "$CLASSPATH" \
+
org.gradle.wrapper.GradleWrapperMain \
+
"$@"
+
+
# Stop when "xargs" is not available.
+
if ! command -v xargs >/dev/null 2>&1
+
then
+
die "xargs is not available"
+
fi
+
+
# Use "xargs" to parse quoted args.
+
#
+
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+
#
+
# In Bash we could simply go:
+
#
+
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+
# set -- "${ARGS[@]}" "$@"
+
#
+
# but POSIX shell has neither arrays nor command substitution, so instead we
+
# post-process each arg (as a line of input to sed) to backslash-escape any
+
# character that might be a shell metacharacter, then use eval to reverse
+
# that process (while maintaining the separation between arguments), and wrap
+
# the whole thing up as a single "set" statement.
+
#
+
# This will of course break if any of these variables contains a newline or
+
# an unmatched quote.
+
#
+
+
eval "set -- $(
+
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+
xargs -n1 |
+
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+
tr '\n' ' '
+
)" '"$@"'
+
+
exec "$JAVACMD" "$@"
+94
mobile/gradlew.bat
···
+
@rem
+
@rem Copyright 2015 the original author or authors.
+
@rem
+
@rem Licensed under the Apache License, Version 2.0 (the "License");
+
@rem you may not use this file except in compliance with the License.
+
@rem You may obtain a copy of the License at
+
@rem
+
@rem https://www.apache.org/licenses/LICENSE-2.0
+
@rem
+
@rem Unless required by applicable law or agreed to in writing, software
+
@rem distributed under the License is distributed on an "AS IS" BASIS,
+
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+
@rem See the License for the specific language governing permissions and
+
@rem limitations under the License.
+
@rem
+
@rem SPDX-License-Identifier: Apache-2.0
+
@rem
+
+
@if "%DEBUG%"=="" @echo off
+
@rem ##########################################################################
+
@rem
+
@rem Gradle startup script for Windows
+
@rem
+
@rem ##########################################################################
+
+
@rem Set local scope for the variables with windows NT shell
+
if "%OS%"=="Windows_NT" setlocal
+
+
set DIRNAME=%~dp0
+
if "%DIRNAME%"=="" set DIRNAME=.
+
@rem This is normally unused
+
set APP_BASE_NAME=%~n0
+
set APP_HOME=%DIRNAME%
+
+
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+
@rem Find java.exe
+
if defined JAVA_HOME goto findJavaFromJavaHome
+
+
set JAVA_EXE=java.exe
+
%JAVA_EXE% -version >NUL 2>&1
+
if %ERRORLEVEL% equ 0 goto execute
+
+
echo. 1>&2
+
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+
echo. 1>&2
+
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+
echo location of your Java installation. 1>&2
+
+
goto fail
+
+
:findJavaFromJavaHome
+
set JAVA_HOME=%JAVA_HOME:"=%
+
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+
if exist "%JAVA_EXE%" goto execute
+
+
echo. 1>&2
+
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+
echo. 1>&2
+
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+
echo location of your Java installation. 1>&2
+
+
goto fail
+
+
:execute
+
@rem Setup the command line
+
+
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+
@rem Execute Gradle
+
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+
:end
+
@rem End local scope for the variables with windows NT shell
+
if %ERRORLEVEL% equ 0 goto mainEnd
+
+
:fail
+
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+
rem the _cmd.exe /c_ return code!
+
set EXIT_CODE=%ERRORLEVEL%
+
if %EXIT_CODE% equ 0 set EXIT_CODE=1
+
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+
exit /b %EXIT_CODE%
+
+
:mainEnd
+
if "%OS%"=="Windows_NT" endlocal
+
+
:omega
+3
mobile/iosApp/Configuration/Config.xcconfig
···
+
TEAM_ID=
+
BUNDLE_ID=com.paytondeveloper.myrus_mobile.myrus-mobile
+
APP_NAME=myrus-mobile
+424
mobile/iosApp/iosApp.xcodeproj/project.pbxproj
···
+
// !$*UTF8*$!
+
{
+
archiveVersion = 1;
+
classes = {
+
};
+
objectVersion = 56;
+
objects = {
+
+
/* Begin PBXBuildFile section */
+
058557BB273AAA24004C7B11 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 058557BA273AAA24004C7B11 /* Assets.xcassets */; };
+
058557D9273AAEEB004C7B11 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */; };
+
2152FB042600AC8F00CF470E /* iOSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2152FB032600AC8F00CF470E /* iOSApp.swift */; };
+
7555FF83242A565900829871 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7555FF82242A565900829871 /* ContentView.swift */; };
+
E9B512A52D862B0F00D52AB6 /* MLKitBarcodeScanning in Frameworks */ = {isa = PBXBuildFile; productRef = E9B512A42D862B0F00D52AB6 /* MLKitBarcodeScanning */; };
+
E9B512A72D862B0F00D52AB6 /* MLKitFaceDetection in Frameworks */ = {isa = PBXBuildFile; productRef = E9B512A62D862B0F00D52AB6 /* MLKitFaceDetection */; };
+
/* End PBXBuildFile section */
+
+
/* Begin PBXFileReference section */
+
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>"; };
+
2152FB032600AC8F00CF470E /* iOSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iOSApp.swift; sourceTree = "<group>"; };
+
7555FF7B242A565900829871 /* myrus-mobile.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "myrus-mobile.app"; sourceTree = BUILT_PRODUCTS_DIR; };
+
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>"; };
+
AB3632DC29227652001CCB65 /* Config.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; };
+
/* End PBXFileReference section */
+
+
/* Begin PBXFrameworksBuildPhase section */
+
B92378962B6B1156000C7307 /* Frameworks */ = {
+
isa = PBXFrameworksBuildPhase;
+
buildActionMask = 2147483647;
+
files = (
+
E9B512A52D862B0F00D52AB6 /* MLKitBarcodeScanning in Frameworks */,
+
E9B512A72D862B0F00D52AB6 /* MLKitFaceDetection in Frameworks */,
+
);
+
runOnlyForDeploymentPostprocessing = 0;
+
};
+
/* End PBXFrameworksBuildPhase section */
+
+
/* Begin PBXGroup section */
+
058557D7273AAEEB004C7B11 /* Preview Content */ = {
+
isa = PBXGroup;
+
children = (
+
058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */,
+
);
+
path = "Preview Content";
+
sourceTree = "<group>";
+
};
+
42799AB246E5F90AF97AA0EF /* Frameworks */ = {
+
isa = PBXGroup;
+
children = (
+
);
+
name = Frameworks;
+
sourceTree = "<group>";
+
};
+
7555FF72242A565900829871 = {
+
isa = PBXGroup;
+
children = (
+
AB1DB47929225F7C00F7AF9C /* Configuration */,
+
7555FF7D242A565900829871 /* iosApp */,
+
7555FF7C242A565900829871 /* Products */,
+
42799AB246E5F90AF97AA0EF /* Frameworks */,
+
);
+
sourceTree = "<group>";
+
};
+
7555FF7C242A565900829871 /* Products */ = {
+
isa = PBXGroup;
+
children = (
+
7555FF7B242A565900829871 /* myrus-mobile.app */,
+
);
+
name = Products;
+
sourceTree = "<group>";
+
};
+
7555FF7D242A565900829871 /* iosApp */ = {
+
isa = PBXGroup;
+
children = (
+
058557BA273AAA24004C7B11 /* Assets.xcassets */,
+
7555FF82242A565900829871 /* ContentView.swift */,
+
7555FF8C242A565B00829871 /* Info.plist */,
+
2152FB032600AC8F00CF470E /* iOSApp.swift */,
+
058557D7273AAEEB004C7B11 /* Preview Content */,
+
);
+
path = iosApp;
+
sourceTree = "<group>";
+
};
+
AB1DB47929225F7C00F7AF9C /* Configuration */ = {
+
isa = PBXGroup;
+
children = (
+
AB3632DC29227652001CCB65 /* Config.xcconfig */,
+
);
+
path = Configuration;
+
sourceTree = "<group>";
+
};
+
/* End PBXGroup section */
+
+
/* Begin PBXNativeTarget section */
+
7555FF7A242A565900829871 /* iosApp */ = {
+
isa = PBXNativeTarget;
+
buildConfigurationList = 7555FFA5242A565B00829871 /* Build configuration list for PBXNativeTarget "iosApp" */;
+
buildPhases = (
+
F36B1CEB2AD83DDC00CB74D5 /* Compile Kotlin Framework */,
+
7555FF77242A565900829871 /* Sources */,
+
B92378962B6B1156000C7307 /* Frameworks */,
+
7555FF79242A565900829871 /* Resources */,
+
);
+
buildRules = (
+
);
+
dependencies = (
+
);
+
name = iosApp;
+
packageProductDependencies = (
+
E9B512A42D862B0F00D52AB6 /* MLKitBarcodeScanning */,
+
E9B512A62D862B0F00D52AB6 /* MLKitFaceDetection */,
+
);
+
productName = iosApp;
+
productReference = 7555FF7B242A565900829871 /* myrus-mobile.app */;
+
productType = "com.apple.product-type.application";
+
};
+
/* End PBXNativeTarget section */
+
+
/* Begin PBXProject section */
+
7555FF73242A565900829871 /* Project object */ = {
+
isa = PBXProject;
+
attributes = {
+
BuildIndependentTargetsInParallel = YES;
+
LastSwiftUpdateCheck = 1130;
+
LastUpgradeCheck = 1540;
+
ORGANIZATIONNAME = orgName;
+
TargetAttributes = {
+
7555FF7A242A565900829871 = {
+
CreatedOnToolsVersion = 11.3.1;
+
};
+
};
+
};
+
buildConfigurationList = 7555FF76242A565900829871 /* Build configuration list for PBXProject "iosApp" */;
+
compatibilityVersion = "Xcode 14.0";
+
developmentRegion = en;
+
hasScannedForEncodings = 0;
+
knownRegions = (
+
en,
+
Base,
+
);
+
mainGroup = 7555FF72242A565900829871;
+
packageReferences = (
+
E9B512A32D862B0F00D52AB6 /* XCRemoteSwiftPackageReference "google-mlkit-swiftpm" */,
+
);
+
productRefGroup = 7555FF7C242A565900829871 /* Products */;
+
projectDirPath = "";
+
projectRoot = "";
+
targets = (
+
7555FF7A242A565900829871 /* iosApp */,
+
);
+
};
+
/* End PBXProject section */
+
+
/* Begin PBXResourcesBuildPhase section */
+
7555FF79242A565900829871 /* Resources */ = {
+
isa = PBXResourcesBuildPhase;
+
buildActionMask = 2147483647;
+
files = (
+
058557D9273AAEEB004C7B11 /* Preview Assets.xcassets in Resources */,
+
058557BB273AAA24004C7B11 /* Assets.xcassets in Resources */,
+
);
+
runOnlyForDeploymentPostprocessing = 0;
+
};
+
/* End PBXResourcesBuildPhase section */
+
+
/* Begin PBXShellScriptBuildPhase section */
+
F36B1CEB2AD83DDC00CB74D5 /* Compile Kotlin Framework */ = {
+
isa = PBXShellScriptBuildPhase;
+
buildActionMask = 2147483647;
+
files = (
+
);
+
inputFileListPaths = (
+
);
+
inputPaths = (
+
);
+
name = "Compile Kotlin Framework";
+
outputFileListPaths = (
+
);
+
outputPaths = (
+
);
+
runOnlyForDeploymentPostprocessing = 0;
+
shellPath = /bin/sh;
+
shellScript = "if [ \"YES\" = \"$OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED\" ]; then\n echo \"Skipping Gradle build task invocation due to OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED environment variable set to \\\"YES\\\"\"\n exit 0\nfi\ncd \"$SRCROOT/..\"\n./gradlew :composeApp:embedAndSignAppleFrameworkForXcode\n";
+
};
+
/* End PBXShellScriptBuildPhase section */
+
+
/* Begin PBXSourcesBuildPhase section */
+
7555FF77242A565900829871 /* Sources */ = {
+
isa = PBXSourcesBuildPhase;
+
buildActionMask = 2147483647;
+
files = (
+
2152FB042600AC8F00CF470E /* iOSApp.swift in Sources */,
+
7555FF83242A565900829871 /* ContentView.swift in Sources */,
+
);
+
runOnlyForDeploymentPostprocessing = 0;
+
};
+
/* End PBXSourcesBuildPhase section */
+
+
/* Begin XCBuildConfiguration section */
+
7555FFA3242A565B00829871 /* Debug */ = {
+
isa = XCBuildConfiguration;
+
baseConfigurationReference = AB3632DC29227652001CCB65 /* Config.xcconfig */;
+
buildSettings = {
+
ALWAYS_SEARCH_USER_PATHS = NO;
+
CLANG_ANALYZER_NONNULL = YES;
+
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+
CLANG_CXX_LIBRARY = "libc++";
+
CLANG_ENABLE_MODULES = YES;
+
CLANG_ENABLE_OBJC_ARC = YES;
+
CLANG_ENABLE_OBJC_WEAK = YES;
+
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+
CLANG_WARN_BOOL_CONVERSION = YES;
+
CLANG_WARN_COMMA = YES;
+
CLANG_WARN_CONSTANT_CONVERSION = YES;
+
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+
CLANG_WARN_EMPTY_BODY = YES;
+
CLANG_WARN_ENUM_CONVERSION = YES;
+
CLANG_WARN_INFINITE_RECURSION = YES;
+
CLANG_WARN_INT_CONVERSION = YES;
+
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+
CLANG_WARN_STRICT_PROTOTYPES = YES;
+
CLANG_WARN_SUSPICIOUS_MOVE = YES;
+
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+
CLANG_WARN_UNREACHABLE_CODE = YES;
+
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+
COPY_PHASE_STRIP = NO;
+
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+
ENABLE_STRICT_OBJC_MSGSEND = YES;
+
ENABLE_TESTABILITY = YES;
+
ENABLE_USER_SCRIPT_SANDBOXING = NO;
+
GCC_C_LANGUAGE_STANDARD = gnu11;
+
GCC_DYNAMIC_NO_PIC = NO;
+
GCC_NO_COMMON_BLOCKS = YES;
+
GCC_OPTIMIZATION_LEVEL = 0;
+
GCC_PREPROCESSOR_DEFINITIONS = (
+
"DEBUG=1",
+
"$(inherited)",
+
);
+
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+
GCC_WARN_UNDECLARED_SELECTOR = YES;
+
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+
GCC_WARN_UNUSED_FUNCTION = YES;
+
GCC_WARN_UNUSED_VARIABLE = YES;
+
IPHONEOS_DEPLOYMENT_TARGET = 15.3;
+
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+
MTL_FAST_MATH = YES;
+
ONLY_ACTIVE_ARCH = YES;
+
SDKROOT = iphoneos;
+
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+
};
+
name = Debug;
+
};
+
7555FFA4242A565B00829871 /* Release */ = {
+
isa = XCBuildConfiguration;
+
baseConfigurationReference = AB3632DC29227652001CCB65 /* Config.xcconfig */;
+
buildSettings = {
+
ALWAYS_SEARCH_USER_PATHS = NO;
+
CLANG_ANALYZER_NONNULL = YES;
+
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+
CLANG_CXX_LIBRARY = "libc++";
+
CLANG_ENABLE_MODULES = YES;
+
CLANG_ENABLE_OBJC_ARC = YES;
+
CLANG_ENABLE_OBJC_WEAK = YES;
+
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+
CLANG_WARN_BOOL_CONVERSION = YES;
+
CLANG_WARN_COMMA = YES;
+
CLANG_WARN_CONSTANT_CONVERSION = YES;
+
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+
CLANG_WARN_EMPTY_BODY = YES;
+
CLANG_WARN_ENUM_CONVERSION = YES;
+
CLANG_WARN_INFINITE_RECURSION = YES;
+
CLANG_WARN_INT_CONVERSION = YES;
+
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+
CLANG_WARN_STRICT_PROTOTYPES = YES;
+
CLANG_WARN_SUSPICIOUS_MOVE = YES;
+
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+
CLANG_WARN_UNREACHABLE_CODE = YES;
+
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+
COPY_PHASE_STRIP = NO;
+
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+
ENABLE_NS_ASSERTIONS = NO;
+
ENABLE_STRICT_OBJC_MSGSEND = YES;
+
ENABLE_USER_SCRIPT_SANDBOXING = NO;
+
GCC_C_LANGUAGE_STANDARD = gnu11;
+
GCC_NO_COMMON_BLOCKS = YES;
+
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+
GCC_WARN_UNDECLARED_SELECTOR = YES;
+
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+
GCC_WARN_UNUSED_FUNCTION = YES;
+
GCC_WARN_UNUSED_VARIABLE = YES;
+
IPHONEOS_DEPLOYMENT_TARGET = 15.3;
+
MTL_ENABLE_DEBUG_INFO = NO;
+
MTL_FAST_MATH = YES;
+
SDKROOT = iphoneos;
+
SWIFT_COMPILATION_MODE = wholemodule;
+
SWIFT_OPTIMIZATION_LEVEL = "-O";
+
VALIDATE_PRODUCT = YES;
+
};
+
name = Release;
+
};
+
7555FFA6242A565B00829871 /* Debug */ = {
+
isa = XCBuildConfiguration;
+
buildSettings = {
+
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+
CODE_SIGN_IDENTITY = "Apple Development";
+
CODE_SIGN_STYLE = Automatic;
+
DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\"";
+
DEVELOPMENT_TEAM = "${TEAM_ID}";
+
ENABLE_PREVIEWS = YES;
+
FRAMEWORK_SEARCH_PATHS = (
+
"$(inherited)",
+
"$(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)\n$(SRCROOT)/../composeApp/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)",
+
);
+
INFOPLIST_FILE = iosApp/Info.plist;
+
IPHONEOS_DEPLOYMENT_TARGET = 15.3;
+
LD_RUNPATH_SEARCH_PATHS = (
+
"$(inherited)",
+
"@executable_path/Frameworks",
+
);
+
PRODUCT_BUNDLE_IDENTIFIER = "${BUNDLE_ID}${TEAM_ID}";
+
PRODUCT_NAME = "${APP_NAME}";
+
PROVISIONING_PROFILE_SPECIFIER = "";
+
SWIFT_VERSION = 5.0;
+
TARGETED_DEVICE_FAMILY = "1,2";
+
};
+
name = Debug;
+
};
+
7555FFA7242A565B00829871 /* Release */ = {
+
isa = XCBuildConfiguration;
+
buildSettings = {
+
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+
CODE_SIGN_IDENTITY = "Apple Development";
+
CODE_SIGN_STYLE = Automatic;
+
DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\"";
+
DEVELOPMENT_TEAM = "${TEAM_ID}";
+
ENABLE_PREVIEWS = YES;
+
FRAMEWORK_SEARCH_PATHS = (
+
"$(inherited)",
+
"$(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)\n$(SRCROOT)/../composeApp/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)",
+
);
+
INFOPLIST_FILE = iosApp/Info.plist;
+
IPHONEOS_DEPLOYMENT_TARGET = 15.3;
+
LD_RUNPATH_SEARCH_PATHS = (
+
"$(inherited)",
+
"@executable_path/Frameworks",
+
);
+
PRODUCT_BUNDLE_IDENTIFIER = "${BUNDLE_ID}${TEAM_ID}";
+
PRODUCT_NAME = "${APP_NAME}";
+
PROVISIONING_PROFILE_SPECIFIER = "";
+
SWIFT_VERSION = 5.0;
+
TARGETED_DEVICE_FAMILY = "1,2";
+
};
+
name = Release;
+
};
+
/* End XCBuildConfiguration section */
+
+
/* Begin XCConfigurationList section */
+
7555FF76242A565900829871 /* Build configuration list for PBXProject "iosApp" */ = {
+
isa = XCConfigurationList;
+
buildConfigurations = (
+
7555FFA3242A565B00829871 /* Debug */,
+
7555FFA4242A565B00829871 /* Release */,
+
);
+
defaultConfigurationIsVisible = 0;
+
defaultConfigurationName = Release;
+
};
+
7555FFA5242A565B00829871 /* Build configuration list for PBXNativeTarget "iosApp" */ = {
+
isa = XCConfigurationList;
+
buildConfigurations = (
+
7555FFA6242A565B00829871 /* Debug */,
+
7555FFA7242A565B00829871 /* Release */,
+
);
+
defaultConfigurationIsVisible = 0;
+
defaultConfigurationName = Release;
+
};
+
/* End XCConfigurationList section */
+
+
/* Begin XCRemoteSwiftPackageReference section */
+
E9B512A32D862B0F00D52AB6 /* XCRemoteSwiftPackageReference "google-mlkit-swiftpm" */ = {
+
isa = XCRemoteSwiftPackageReference;
+
repositoryURL = "https://github.com/d-date/google-mlkit-swiftpm";
+
requirement = {
+
kind = upToNextMajorVersion;
+
minimumVersion = 6.0.0;
+
};
+
};
+
/* End XCRemoteSwiftPackageReference section */
+
+
/* Begin XCSwiftPackageProductDependency section */
+
E9B512A42D862B0F00D52AB6 /* MLKitBarcodeScanning */ = {
+
isa = XCSwiftPackageProductDependency;
+
package = E9B512A32D862B0F00D52AB6 /* XCRemoteSwiftPackageReference "google-mlkit-swiftpm" */;
+
productName = MLKitBarcodeScanning;
+
};
+
E9B512A62D862B0F00D52AB6 /* MLKitFaceDetection */ = {
+
isa = XCSwiftPackageProductDependency;
+
package = E9B512A32D862B0F00D52AB6 /* XCRemoteSwiftPackageReference "google-mlkit-swiftpm" */;
+
productName = MLKitFaceDetection;
+
};
+
/* End XCSwiftPackageProductDependency section */
+
};
+
rootObject = 7555FF73242A565900829871 /* Project object */;
+
}
+7
mobile/iosApp/iosApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata
···
+
<?xml version="1.0" encoding="UTF-8"?>
+
<Workspace
+
version = "1.0">
+
<FileRef
+
location = "self:">
+
</FileRef>
+
</Workspace>
+60
mobile/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
···
+
{
+
"originHash" : "891cce1a2e5740e9da5b83f5ae8318d7657deb75e81f6a5d7be479fbdadf82e9",
+
"pins" : [
+
{
+
"identity" : "google-mlkit-swiftpm",
+
"kind" : "remoteSourceControl",
+
"location" : "https://github.com/d-date/google-mlkit-swiftpm",
+
"state" : {
+
"revision" : "064418cee64470417fbc5c726e22815dc92c56c9",
+
"version" : "6.0.0"
+
}
+
},
+
{
+
"identity" : "googledatatransport",
+
"kind" : "remoteSourceControl",
+
"location" : "https://github.com/google/GoogleDataTransport.git",
+
"state" : {
+
"revision" : "a637d318ae7ae246b02d7305121275bc75ed5565",
+
"version" : "9.4.0"
+
}
+
},
+
{
+
"identity" : "googleutilities",
+
"kind" : "remoteSourceControl",
+
"location" : "https://github.com/google/GoogleUtilities.git",
+
"state" : {
+
"revision" : "8e5d57ed87057cd7b0e4e8f474d9e78f73eb85f7",
+
"version" : "7.13.2"
+
}
+
},
+
{
+
"identity" : "gtm-session-fetcher",
+
"kind" : "remoteSourceControl",
+
"location" : "https://github.com/google/gtm-session-fetcher.git",
+
"state" : {
+
"revision" : "0382ca27f22fb3494cf657d8dc356dc282cd1193",
+
"version" : "3.4.1"
+
}
+
},
+
{
+
"identity" : "nanopb",
+
"kind" : "remoteSourceControl",
+
"location" : "https://github.com/firebase/nanopb.git",
+
"state" : {
+
"revision" : "b7e1104502eca3a213b46303391ca4d3bc8ddec1",
+
"version" : "2.30910.0"
+
}
+
},
+
{
+
"identity" : "promises",
+
"kind" : "remoteSourceControl",
+
"location" : "https://github.com/google/promises.git",
+
"state" : {
+
"revision" : "540318ecedd63d883069ae7f1ed811a2df00b6ac",
+
"version" : "2.4.0"
+
}
+
}
+
],
+
"version" : 3
+
}
+11
mobile/iosApp/iosApp/Assets.xcassets/AccentColor.colorset/Contents.json
···
+
{
+
"colors" : [
+
{
+
"idiom" : "universal"
+
}
+
],
+
"info" : {
+
"author" : "xcode",
+
"version" : 1
+
}
+
}
+14
mobile/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/Contents.json
···
+
{
+
"images" : [
+
{
+
"filename" : "app-icon-1024.png",
+
"idiom" : "universal",
+
"platform" : "ios",
+
"size" : "1024x1024"
+
}
+
],
+
"info" : {
+
"author" : "xcode",
+
"version" : 1
+
}
+
}
mobile/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/app-icon-1024.png

This is a binary file and will not be displayed.

+6
mobile/iosApp/iosApp/Assets.xcassets/Contents.json
···
+
{
+
"info" : {
+
"author" : "xcode",
+
"version" : 1
+
}
+
}
+21
mobile/iosApp/iosApp/ContentView.swift
···
+
import UIKit
+
import SwiftUI
+
import ComposeApp
+
+
struct ComposeView: UIViewControllerRepresentable {
+
func makeUIViewController(context: Context) -> UIViewController {
+
MainViewControllerKt.MainViewController()
+
}
+
+
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
+
}
+
+
struct ContentView: View {
+
var body: some View {
+
ComposeView()
+
.ignoresSafeArea(.keyboard) // Compose has own keyboard handler
+
}
+
}
+
+
+
+54
mobile/iosApp/iosApp/Info.plist
···
+
<?xml version="1.0" encoding="UTF-8"?>
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+
<plist version="1.0">
+
<dict>
+
<key>CFBundleDevelopmentRegion</key>
+
<string>$(DEVELOPMENT_LANGUAGE)</string>
+
<key>CFBundleExecutable</key>
+
<string>$(EXECUTABLE_NAME)</string>
+
<key>CFBundleIdentifier</key>
+
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+
<key>CFBundleInfoDictionaryVersion</key>
+
<string>6.0</string>
+
<key>CFBundleName</key>
+
<string>$(PRODUCT_NAME)</string>
+
<key>CFBundlePackageType</key>
+
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
+
<key>CFBundleShortVersionString</key>
+
<string>1.0</string>
+
<key>CFBundleVersion</key>
+
<string>1</string>
+
<key>LSRequiresIPhoneOS</key>
+
<true/>
+
<key>CADisableMinimumFrameDurationOnPhone</key>
+
<true/>
+
<key>UIApplicationSceneManifest</key>
+
<dict>
+
<key>UIApplicationSupportsMultipleScenes</key>
+
<false/>
+
</dict>
+
<key>UILaunchScreen</key>
+
<dict/>
+
<key>UIRequiredDeviceCapabilities</key>
+
<array>
+
<string>armv7</string>
+
</array>
+
<key>UISupportedInterfaceOrientations</key>
+
<array>
+
<string>UIInterfaceOrientationPortrait</string>
+
<string>UIInterfaceOrientationLandscapeLeft</string>
+
<string>UIInterfaceOrientationLandscapeRight</string>
+
</array>
+
<key>UISupportedInterfaceOrientations~ipad</key>
+
<array>
+
<string>UIInterfaceOrientationPortrait</string>
+
<string>UIInterfaceOrientationPortraitUpsideDown</string>
+
<string>UIInterfaceOrientationLandscapeLeft</string>
+
<string>UIInterfaceOrientationLandscapeRight</string>
+
</array>
+
<key>NSCameraUsageDescription</key><string>Camera permission is required for the app to work.
+
</string><key>NSPhotoLibraryUsageDescription</key><string>Photo Library permission is required for
+
the app to work.
+
</string>
+
</dict>
+
</plist>
+6
mobile/iosApp/iosApp/Preview Content/Preview Assets.xcassets/Contents.json
···
+
{
+
"info" : {
+
"author" : "xcode",
+
"version" : 1
+
}
+
}
+10
mobile/iosApp/iosApp/iOSApp.swift
···
+
import SwiftUI
+
+
@main
+
struct iOSApp: App {
+
var body: some Scene {
+
WindowGroup {
+
ContentView()
+
}
+
}
+
}
+31
mobile/settings.gradle.kts
···
+
rootProject.name = "myrus-mobile"
+
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
+
+
pluginManagement {
+
repositories {
+
google {
+
mavenContent {
+
includeGroupAndSubgroups("androidx")
+
includeGroupAndSubgroups("com.android")
+
includeGroupAndSubgroups("com.google")
+
}
+
}
+
mavenCentral()
+
gradlePluginPortal()
+
}
+
}
+
+
dependencyResolutionManagement {
+
repositories {
+
google {
+
mavenContent {
+
includeGroupAndSubgroups("androidx")
+
includeGroupAndSubgroups("com.android")
+
includeGroupAndSubgroups("com.google")
+
}
+
}
+
mavenCentral()
+
}
+
}
+
+
include(":composeApp")