diff --git a/.gitignore b/.gitignore index 10460a19..be15d602 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,10 @@ *.iml .gradle -/local.properties -/.idea +.idea +local.properties .DS_Store build/ -/captures +captures +xcuserdata .externalNativeBuild .cxx -local.properties -Carthage/ -Cartfile.resolved diff --git a/build.gradle.kts b/build.gradle.kts index 559f5ea7..2a90d3cf 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,43 +1,42 @@ import java.util.Properties plugins { - id("com.google.gms.google-services") version "4.3.15" apply false - id("io.github.gradle-nexus.publish-plugin") version "1.3.0" + alias(libs.plugins.ktlint) + alias(libs.plugins.nexus) + alias(libs.plugins.jetbrains.compose) apply false } -allprojects { - val localProps = Properties() - val localPropertiesFile = rootProject.file("local.properties") - if (localPropertiesFile.exists()) { - localPropertiesFile.inputStream().use { localProps.load(it) } - } +val localProps = Properties() +val localPropertiesFile = rootProject.file("local.properties") +if (localPropertiesFile.exists()) { + localPropertiesFile.inputStream().use { localProps.load(it) } +} - val signingKey by extra( - localProps.getOrDefault("signing.key", System.getenv("SIGNING_KEY") ?: "") - ) - val signingPassword by extra( - localProps.getOrDefault("signing.password", System.getenv("SIGNING_PASSWORD") ?: "") - ) - val ossrhUsername by extra( - localProps.getOrDefault("ossrhUsername", System.getenv("OSSRH_USERNAME") ?: "") +val signingKey by extra( + localProps.getOrDefault("signing.key", System.getenv("SIGNING_KEY") ?: "") +) +val signingPassword by extra( + localProps.getOrDefault("signing.password", System.getenv("SIGNING_PASSWORD") ?: "") +) +val ossrhUsername by extra( + localProps.getOrDefault("ossrhUsername", System.getenv("OSSRH_USERNAME") ?: "") +) +val ossrhPassword by extra( + localProps.getOrDefault("ossrhPassword", System.getenv("OSSRH_PASSWORD") ?: "") +) +val sonatypeStagingProfileId by extra( + localProps.getOrDefault( + "sonatypeStagingProfileId", + System.getenv("SONATYPE_STAGING_PROFILE_ID") ?: "" ) - val ossrhPassword by extra( - localProps.getOrDefault("ossrhPassword", System.getenv("OSSRH_PASSWORD") ?: "") - ) - val sonatypeStagingProfileId by extra( - localProps.getOrDefault( - "sonatypeStagingProfileId", - System.getenv("SONATYPE_STAGING_PROFILE_ID") ?: "" - ) - ) -} +) nexusPublishing { this.repositories { sonatype { - val sonatypeStagingProfileId: String by extra - val ossrhUsername: String by extra - val ossrhPassword: String by extra + val sonatypeStagingProfileId: String by rootProject.extra + val ossrhUsername: String by rootProject.extra + val ossrhPassword: String by rootProject.extra stagingProfileId.set(sonatypeStagingProfileId) username.set(ossrhUsername) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 31e7ee59..618f6814 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -2,14 +2,7 @@ plugins { `kotlin-dsl` } -repositories { - gradlePluginPortal() - mavenCentral() - google() -} - dependencies { - implementation("com.android.tools.build:gradle:8.0.2") - implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.23") - implementation("org.jlleitschuh.gradle:ktlint-gradle:10.3.0") + implementation(libs.kotlin.plugin) + implementation(libs.agp.plugin) } diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts index e69de29b..75df2751 100644 --- a/buildSrc/settings.gradle.kts +++ b/buildSrc/settings.gradle.kts @@ -0,0 +1,13 @@ +dependencyResolutionManagement { + versionCatalogs { + create("libs") { + from(files("../gradle/libs.versions.toml")) + } + } + + repositories { + gradlePluginPortal() + mavenCentral() + google() + } +} diff --git a/buildSrc/src/main/kotlin/AndroidConfig.kt b/buildSrc/src/main/kotlin/AndroidConfig.kt deleted file mode 100644 index c5a3388c..00000000 --- a/buildSrc/src/main/kotlin/AndroidConfig.kt +++ /dev/null @@ -1,5 +0,0 @@ -object AndroidConfig { - const val minSdkVersion = 21 - const val compileSdkVersion = 33 - const val targetSdkVersion = 33 -} diff --git a/buildSrc/src/main/kotlin/KotlinAndroidTarget.kt b/buildSrc/src/main/kotlin/KotlinAndroidTarget.kt new file mode 100644 index 00000000..4acc43b1 --- /dev/null +++ b/buildSrc/src/main/kotlin/KotlinAndroidTarget.kt @@ -0,0 +1,7 @@ +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget + +fun KotlinAndroidTarget.configureJvmTarget(jvmVersion: String = "1.8") { + compilations.all { + kotlinOptions.jvmTarget = jvmVersion + } +} diff --git a/buildSrc/src/main/kotlin/KotlinMultiplatformExtension.kt b/buildSrc/src/main/kotlin/KotlinMultiplatformExtension.kt new file mode 100644 index 00000000..00627579 --- /dev/null +++ b/buildSrc/src/main/kotlin/KotlinMultiplatformExtension.kt @@ -0,0 +1,15 @@ +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension + +fun KotlinMultiplatformExtension.configureKotlinCompilerArgs(vararg args: String) { + targets.all { + compilations.all { + kotlinOptions { + freeCompilerArgs += setOf( + "-opt-in=kotlin.RequiresOptIn", + "-Xexpect-actual-classes", + *args + ) + } + } + } +} diff --git a/buildSrc/src/main/kotlin/multiplatform-setup.gradle.kts b/buildSrc/src/main/kotlin/multiplatform-setup.gradle.kts deleted file mode 100644 index bd2ce71f..00000000 --- a/buildSrc/src/main/kotlin/multiplatform-setup.gradle.kts +++ /dev/null @@ -1,37 +0,0 @@ -plugins { - id("com.android.library") - kotlin("multiplatform") - id("org.jlleitschuh.gradle.ktlint") -} - -kotlin { - targets.all { - compilations.all { - kotlinOptions { - freeCompilerArgs += listOf( - "-opt-in=kotlin.RequiresOptIn", - "-Xexpect-actual-classes", - ) - } - } - } -} - -android { - compileSdk = AndroidConfig.compileSdkVersion - - sourceSets.named("main") { - manifest.srcFile("src/androidMain/AndroidManifest.xml") - res.srcDir("src/androidMain/res") - } - - defaultConfig { - minSdk = AndroidConfig.minSdkVersion - targetSdk = AndroidConfig.targetSdkVersion - } - - compileOptions { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 - } -} diff --git a/buildSrc/src/main/kotlin/webrtc.multiplatform.gradle.kts b/buildSrc/src/main/kotlin/webrtc.multiplatform.gradle.kts new file mode 100644 index 00000000..747520de --- /dev/null +++ b/buildSrc/src/main/kotlin/webrtc.multiplatform.gradle.kts @@ -0,0 +1,37 @@ +plugins { + id("com.android.library") + kotlin("multiplatform") +} + +kotlin { + configureKotlinCompilerArgs() + + androidTarget { + configureJvmTarget() + } +} + +android { + compileSdk = androidCompileSdkVersion + + sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml") + sourceSets["main"].res.srcDir("src/androidMain/res") + + defaultConfig { + minSdk = androidMinSdkVersion + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } +} + +private val Project.versionCatalog: VersionCatalog + get() = extensions.getByType().named("libs") + +private val Project.androidCompileSdkVersion: Int + get() = "${versionCatalog.findVersion("compileSdk").get()}".toInt() + +private val Project.androidMinSdkVersion: Int + get() = "${versionCatalog.findVersion("minSdk").get()}".toInt() diff --git a/gradle.properties b/gradle.properties index a69d6ad6..af87efa2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,17 +1,26 @@ +# Gradle org.gradle.caching=true org.gradle.daemon=true org.gradle.parallel=true org.gradle.jvmargs=-Xmx2g +# Kotlin kotlin.code.style=official -kotlin.mpp.enableCInteropCommonization=true kotlin.js.compiler=ir +# Android +android.nonTransitiveRClass=true android.useAndroidX=true - # Workaround for java.lang.NoSuchMethodError: No static method createEgl14([I)Lorg/webrtc/EglBase14; exception # https://issuetracker.google.com/issues/265195801 -android.enableDexingArtifactTransform=false +android.useFullClasspathForDexingTransform = true + +# KMP +kotlin.mpp.androidSourceSetLayoutVersion=2 +kotlin.mpp.enableCInteropCommonization=true + +#Compose +org.jetbrains.compose.experimental.jscanvas.enabled=true # Versions webRtcKmpVersion=0.114.4 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 00000000..ae0623c4 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,58 @@ +[versions] +kotlin = "1.9.23" +kotlin-coroutines = "1.8.0" +androidx-activity-compose = "1.9.0" +androidx-appcompat = "1.6.1" +androidx-core = "1.13.0" +androidx-material = "1.11.0" +androidx-lifecycle = "2.7.0" +androidx-test-core = "1.5.0" +androidx-test-runner = "1.5.2" +androidx-test-rules = "1.5.0" +accompanist-permision = "0.34.0" +compose = "1.6.6" +kermit = "2.0.3" +kotlin-wrappers = "1.0.0-pre.732" +webrtc-sdk = "114.5735.02" + +#Android +minSdk = "21" +compileSdk = "34" +targetSdk = "34" + +# Plugins +agp = "8.2.2" +ktlint = "10.3.0" +nexus = "1.3.0" +compose-plugin = "1.6.2" + +[libraries] +webrtc-sdk = { module = "io.github.webrtc-sdk:android", version.ref = "webrtc-sdk" } +kotlin-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlin-coroutines" } +kotlin-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlin-coroutines" } +androidx-coreKtx = { module = "androidx.core:core-ktx", version.ref = "androidx-core" } +androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidx-appcompat" } +androidx-lifecycle-runtime = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "androidx-lifecycle" } +androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activity-compose" } +androidx-material = { module = "com.google.android.material:material", version.ref = "androidx-material" } +accompanist-permissions = { module = "com.google.accompanist:accompanist-permissions", version.ref = "accompanist-permision" } +compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling", version.ref = "compose" } +compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview", version.ref = "compose" } +kermit = { module = "co.touchlab:kermit", version.ref = "kermit" } +androidx-test-core = { module = "androidx.test:core", version.ref = "androidx-test-core" } +androidx-test-runner = { module = "androidx.test:runner", version.ref = "androidx-test-runner" } +androidx-test-rules = { module = "androidx.test:rules", version.ref = "androidx-test-rules" } +kotlin-wrappers-bom = { module = "org.jetbrains.kotlin-wrappers:kotlin-wrappers-bom", version.ref = "kotlin-wrappers" } +kotlin-wrappers-emotion = { module = "org.jetbrains.kotlin-wrappers:kotlin-emotion" } +kotlin-wrappers-react = { module = "org.jetbrains.kotlin-wrappers:kotlin-react" } +kotlin-wrappers-reactDom = { module = "org.jetbrains.kotlin-wrappers:kotlin-react-dom" } +kotlin-wrappers-mui = { module = "org.jetbrains.kotlin-wrappers:kotlin-mui-material" } + +# Plugin dependencies +kotlin-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" } +agp-plugin = { module = "com.android.tools.build:gradle", version.ref = "agp" } + +[plugins] +ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint" } +nexus = { id = "io.github.gradle-nexus.publish-plugin", version.ref = "nexus" } +jetbrains-compose = { id = "org.jetbrains.compose", version.ref = "compose-plugin" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 15de9024..e411586a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/kotlin-js-store/yarn.lock b/kotlin-js-store/yarn.lock index f4e39534..2cedcd06 100644 --- a/kotlin-js-store/yarn.lock +++ b/kotlin-js-store/yarn.lock @@ -3,64 +3,54 @@ "@babel/code-frame@^7.0.0": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" - integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== + version "7.24.2" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.2.tgz#718b4b19841809a58b29b68cde80bc5e1aa6d9ae" + integrity sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ== dependencies: - "@babel/highlight" "^7.18.6" + "@babel/highlight" "^7.24.2" + picocolors "^1.0.0" "@babel/helper-module-imports@^7.16.7": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e" - integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== - dependencies: - "@babel/types" "^7.18.6" - -"@babel/helper-plugin-utils@^7.18.6": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz#4b8aea3b069d8cb8a72cdfe28ddf5ceca695ef2f" - integrity sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w== - -"@babel/helper-string-parser@^7.18.10": - version "7.18.10" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz#181f22d28ebe1b3857fa575f5c290b1aaf659b56" - integrity sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw== - -"@babel/helper-validator-identifier@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz#9c97e30d31b2b8c72a1d08984f2ca9b574d7a076" - integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g== - -"@babel/highlight@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" - integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== - dependencies: - "@babel/helper-validator-identifier" "^7.18.6" - chalk "^2.0.0" - js-tokens "^4.0.0" + version "7.24.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz#6ac476e6d168c7c23ff3ba3cf4f7841d46ac8128" + integrity sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg== + dependencies: + "@babel/types" "^7.24.0" + +"@babel/helper-string-parser@^7.23.4": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz#f99c36d3593db9540705d0739a1f10b5e20c696e" + integrity sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ== -"@babel/plugin-syntax-jsx@^7.17.12": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz#a8feef63b010150abd97f1649ec296e849943ca0" - integrity sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q== +"@babel/helper-validator-identifier@^7.22.20": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" + integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== + +"@babel/highlight@^7.24.2": + version "7.24.2" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.2.tgz#3f539503efc83d3c59080a10e6634306e0370d26" + integrity sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-validator-identifier" "^7.22.20" + chalk "^2.4.2" + js-tokens "^4.0.0" + picocolors "^1.0.0" -"@babel/runtime@^7.12.5", "@babel/runtime@^7.17.2", "@babel/runtime@^7.18.3", "@babel/runtime@^7.18.6", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7": - version "7.18.9" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.9.tgz#b4fcfce55db3d2e5e080d2490f608a3b9f407f4a" - integrity sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw== +"@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.23.9", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.4.tgz#de795accd698007a66ba44add6cc86542aff1edd" + integrity sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA== dependencies: - regenerator-runtime "^0.13.4" + regenerator-runtime "^0.14.0" -"@babel/types@^7.18.6": - version "7.18.10" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.10.tgz#4908e81b6b339ca7c6b7a555a5fc29446f26dde6" - integrity sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ== +"@babel/types@^7.24.0": + version "7.24.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.0.tgz#3b951f435a92e7333eba05b7566fd297960ea1bf" + integrity sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w== dependencies: - "@babel/helper-string-parser" "^7.18.10" - "@babel/helper-validator-identifier" "^7.18.6" + "@babel/helper-string-parser" "^7.23.4" + "@babel/helper-validator-identifier" "^7.22.20" to-fast-properties "^2.0.0" "@colors/colors@1.5.0": @@ -68,568 +58,155 @@ resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== -"@date-io/core@^2.14.0": - version "2.14.0" - resolved "https://registry.yarnpkg.com/@date-io/core/-/core-2.14.0.tgz#03e9b9b9fc8e4d561c32dd324df0f3ccd967ef14" - integrity sha512-qFN64hiFjmlDHJhu+9xMkdfDG2jLsggNxKXglnekUpXSq8faiqZgtHm2lsHCUuaPDTV6wuXHcCl8J1GQ5wLmPw== - -"@date-io/date-fns@^2.14.0": - version "2.14.0" - resolved "https://registry.yarnpkg.com/@date-io/date-fns/-/date-fns-2.14.0.tgz#92ab150f488f294c135c873350d154803cebdbea" - integrity sha512-4fJctdVyOd5cKIKGaWUM+s3MUXMuzkZaHuTY15PH70kU1YTMrCoauA7hgQVx9qj0ZEbGrH9VSPYJYnYro7nKiA== - dependencies: - "@date-io/core" "^2.14.0" - -"@date-io/dayjs@^2.14.0": - version "2.14.0" - resolved "https://registry.yarnpkg.com/@date-io/dayjs/-/dayjs-2.14.0.tgz#8d4e93e1d473bb5f25210866204dc33384ca4c20" - integrity sha512-4fRvNWaOh7AjvOyJ4h6FYMS7VHLQnIEeAV5ahv6sKYWx+1g1UwYup8h7+gPuoF+sW2hTScxi7PVaba2Jk/U8Og== - dependencies: - "@date-io/core" "^2.14.0" - -"@date-io/luxon@^2.14.0": - version "2.14.0" - resolved "https://registry.yarnpkg.com/@date-io/luxon/-/luxon-2.14.0.tgz#cd1641229e00a899625895de3a31e3aaaf66629f" - integrity sha512-KmpBKkQFJ/YwZgVd0T3h+br/O0uL9ZdE7mn903VPAG2ZZncEmaUfUdYKFT7v7GyIKJ4KzCp379CRthEbxevEVg== - dependencies: - "@date-io/core" "^2.14.0" - -"@date-io/moment@^2.14.0": - version "2.14.0" - resolved "https://registry.yarnpkg.com/@date-io/moment/-/moment-2.14.0.tgz#8300abd6ae8c55d8edee90d118db3cef0b1d4f58" - integrity sha512-VsoLXs94GsZ49ecWuvFbsa081zEv2xxG7d+izJsqGa2L8RPZLlwk27ANh87+SNnOUpp+qy2AoCAf0mx4XXhioA== - dependencies: - "@date-io/core" "^2.14.0" - "@discoveryjs/json-ext@^0.5.0": version "0.5.7" resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== -"@emotion/babel-plugin@^11.10.0": - version "11.10.0" - resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.10.0.tgz#ae545b8faa6b42d3a50ec86b70b758296f3c4467" - integrity sha512-xVnpDAAbtxL1dsuSelU5A7BnY/lftws0wUexNJZTPsvX/1tM4GZJbclgODhvW4E+NH7E5VFcH0bBn30NvniPJA== +"@emotion/babel-plugin@^11.11.0": + version "11.11.0" + resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz#c2d872b6a7767a9d176d007f5b31f7d504bb5d6c" + integrity sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ== dependencies: "@babel/helper-module-imports" "^7.16.7" - "@babel/plugin-syntax-jsx" "^7.17.12" "@babel/runtime" "^7.18.3" - "@emotion/hash" "^0.9.0" - "@emotion/memoize" "^0.8.0" - "@emotion/serialize" "^1.1.0" + "@emotion/hash" "^0.9.1" + "@emotion/memoize" "^0.8.1" + "@emotion/serialize" "^1.1.2" babel-plugin-macros "^3.1.0" convert-source-map "^1.5.0" escape-string-regexp "^4.0.0" find-root "^1.1.0" source-map "^0.5.7" - stylis "4.0.13" - -"@emotion/cache@^11.10.0", "@emotion/cache@^11.9.3": - version "11.10.1" - resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.10.1.tgz#75a157c2a6bb9220450f73ebef1df2e1467dc65d" - integrity sha512-uZTj3Yz5D69GE25iFZcIQtibnVCFsc/6+XIozyL3ycgWvEdif2uEw9wlUt6umjLr4Keg9K6xRPHmD8LGi+6p1A== - dependencies: - "@emotion/memoize" "^0.8.0" - "@emotion/sheet" "^1.2.0" - "@emotion/utils" "^1.2.0" - "@emotion/weak-memoize" "^0.3.0" - stylis "4.0.13" - -"@emotion/css@^11.9.0": - version "11.10.0" - resolved "https://registry.yarnpkg.com/@emotion/css/-/css-11.10.0.tgz#270b4fdf2419e59cb07081d0e9f7940d88b8b443" - integrity sha512-dH9f+kSCucc8ilMg0MUA1AemabcyzYpe5EKX24F528PJjD7HyIY/VBNJHxfUdc8l400h2ncAjR6yEDu+DBj2cg== - dependencies: - "@emotion/babel-plugin" "^11.10.0" - "@emotion/cache" "^11.10.0" - "@emotion/serialize" "^1.1.0" - "@emotion/sheet" "^1.2.0" - "@emotion/utils" "^1.2.0" - -"@emotion/hash@^0.9.0": - version "0.9.0" - resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.0.tgz#c5153d50401ee3c027a57a177bc269b16d889cb7" - integrity sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ== - -"@emotion/is-prop-valid@^1.1.3", "@emotion/is-prop-valid@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz#7f2d35c97891669f7e276eb71c83376a5dc44c83" - integrity sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg== - dependencies: - "@emotion/memoize" "^0.8.0" - -"@emotion/memoize@^0.8.0": - version "0.8.0" - resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.0.tgz#f580f9beb67176fa57aae70b08ed510e1b18980f" - integrity sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA== - -"@emotion/react@^11.9.0": - version "11.10.0" - resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.10.0.tgz#53c577f063f26493f68a05188fb87528d912ff2e" - integrity sha512-K6z9zlHxxBXwN8TcpwBKcEsBsOw4JWCCmR+BeeOWgqp8GIU1yA2Odd41bwdAAr0ssbQrbJbVnndvv7oiv1bZeQ== + stylis "4.2.0" + +"@emotion/cache@^11.11.0": + version "11.11.0" + resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.11.0.tgz#809b33ee6b1cb1a625fef7a45bc568ccd9b8f3ff" + integrity sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ== + dependencies: + "@emotion/memoize" "^0.8.1" + "@emotion/sheet" "^1.2.2" + "@emotion/utils" "^1.2.1" + "@emotion/weak-memoize" "^0.3.1" + stylis "4.2.0" + +"@emotion/css@^11.11.2": + version "11.11.2" + resolved "https://registry.yarnpkg.com/@emotion/css/-/css-11.11.2.tgz#e5fa081d0c6e335352e1bc2b05953b61832dca5a" + integrity sha512-VJxe1ucoMYMS7DkiMdC2T7PWNbrEI0a39YRiyDvK2qq4lXwjRbVP/z4lpG+odCsRzadlR+1ywwrTzhdm5HNdew== + dependencies: + "@emotion/babel-plugin" "^11.11.0" + "@emotion/cache" "^11.11.0" + "@emotion/serialize" "^1.1.2" + "@emotion/sheet" "^1.2.2" + "@emotion/utils" "^1.2.1" + +"@emotion/hash@^0.9.1": + version "0.9.1" + resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.1.tgz#4ffb0055f7ef676ebc3a5a91fb621393294e2f43" + integrity sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ== + +"@emotion/is-prop-valid@^1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz#d4175076679c6a26faa92b03bb786f9e52612337" + integrity sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw== + dependencies: + "@emotion/memoize" "^0.8.1" + +"@emotion/memoize@^0.8.1": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.1.tgz#c1ddb040429c6d21d38cc945fe75c818cfb68e17" + integrity sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA== + +"@emotion/react@^11.11.4": + version "11.11.4" + resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.11.4.tgz#3a829cac25c1f00e126408fab7f891f00ecc3c1d" + integrity sha512-t8AjMlF0gHpvvxk5mAtCqR4vmxiGHCeJBaQO6gncUSdklELOgtwjerNY2yuJNfwnc6vi16U/+uMF+afIawJ9iw== dependencies: "@babel/runtime" "^7.18.3" - "@emotion/babel-plugin" "^11.10.0" - "@emotion/cache" "^11.10.0" - "@emotion/serialize" "^1.1.0" - "@emotion/utils" "^1.2.0" - "@emotion/weak-memoize" "^0.3.0" + "@emotion/babel-plugin" "^11.11.0" + "@emotion/cache" "^11.11.0" + "@emotion/serialize" "^1.1.3" + "@emotion/use-insertion-effect-with-fallbacks" "^1.0.1" + "@emotion/utils" "^1.2.1" + "@emotion/weak-memoize" "^0.3.1" hoist-non-react-statics "^3.3.1" -"@emotion/serialize@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.1.0.tgz#b1f97b1011b09346a40e9796c37a3397b4ea8ea8" - integrity sha512-F1ZZZW51T/fx+wKbVlwsfchr5q97iW8brAnXmsskz4d0hVB4O3M/SiA3SaeH06x02lSNzkkQv+n3AX3kCXKSFA== +"@emotion/serialize@^1.1.2", "@emotion/serialize@^1.1.3", "@emotion/serialize@^1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.1.4.tgz#fc8f6d80c492cfa08801d544a05331d1cc7cd451" + integrity sha512-RIN04MBT8g+FnDwgvIUi8czvr1LU1alUMI05LekWB5DGyTm8cCBMCRpq3GqaiyEDRptEXOyXnvZ58GZYu4kBxQ== dependencies: - "@emotion/hash" "^0.9.0" - "@emotion/memoize" "^0.8.0" - "@emotion/unitless" "^0.8.0" - "@emotion/utils" "^1.2.0" + "@emotion/hash" "^0.9.1" + "@emotion/memoize" "^0.8.1" + "@emotion/unitless" "^0.8.1" + "@emotion/utils" "^1.2.1" csstype "^3.0.2" -"@emotion/sheet@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.2.0.tgz#771b1987855839e214fc1741bde43089397f7be5" - integrity sha512-OiTkRgpxescko+M51tZsMq7Puu/KP55wMT8BgpcXVG2hqXc0Vo0mfymJ/Uj24Hp0i083ji/o0aLddh08UEjq8w== +"@emotion/sheet@^1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.2.2.tgz#d58e788ee27267a14342303e1abb3d508b6d0fec" + integrity sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA== -"@emotion/styled@^11.8.1": - version "11.10.0" - resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.10.0.tgz#c19484dab4206ae46727c07efb4316423dd21312" - integrity sha512-V9oaEH6V4KePeQpgUE83i8ht+4Ri3E8Djp/ZPJ4DQlqWhSKITvgzlR3/YQE2hdfP4Jw3qVRkANJz01LLqK9/TA== +"@emotion/styled@^11.11.0": + version "11.11.5" + resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.11.5.tgz#0c5c8febef9d86e8a926e663b2e5488705545dfb" + integrity sha512-/ZjjnaNKvuMPxcIiUkf/9SHoG4Q196DRl1w82hQ3WCsjo1IUR8uaGWrC6a87CrYAW0Kb/pK7hk8BnLgLRi9KoQ== dependencies: "@babel/runtime" "^7.18.3" - "@emotion/babel-plugin" "^11.10.0" - "@emotion/is-prop-valid" "^1.2.0" - "@emotion/serialize" "^1.1.0" - "@emotion/utils" "^1.2.0" - -"@emotion/unitless@^0.8.0": - version "0.8.0" - resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.8.0.tgz#a4a36e9cbdc6903737cd20d38033241e1b8833db" - integrity sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw== - -"@emotion/utils@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.2.0.tgz#9716eaccbc6b5ded2ea5a90d65562609aab0f561" - integrity sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw== - -"@emotion/weak-memoize@^0.3.0": - version "0.3.0" - resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz#ea89004119dc42db2e1dba0f97d553f7372f6fcb" - integrity sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg== - -"@firebase/analytics-compat@0.1.13": - version "0.1.13" - resolved "https://registry.yarnpkg.com/@firebase/analytics-compat/-/analytics-compat-0.1.13.tgz#61e1d6f9e4d033c3ed9943d91530eb3e0f382f92" - integrity sha512-QC1DH/Dwc8fBihn0H+jocBWyE17GF1fOCpCrpAiQ2u16F/NqsVDVG4LjIqdhq963DXaXneNY7oDwa25Up682AA== - dependencies: - "@firebase/analytics" "0.8.0" - "@firebase/analytics-types" "0.7.0" - "@firebase/component" "0.5.17" - "@firebase/util" "1.6.3" - tslib "^2.1.0" - -"@firebase/analytics-types@0.7.0": - version "0.7.0" - resolved "https://registry.yarnpkg.com/@firebase/analytics-types/-/analytics-types-0.7.0.tgz#91960e7c87ce8bf18cf8dd9e55ccbf5dc3989b5d" - integrity sha512-DNE2Waiwy5+zZnCfintkDtBfaW6MjIG883474v6Z0K1XZIvl76cLND4iv0YUb48leyF+PJK1KO2XrgHb/KpmhQ== - -"@firebase/analytics@0.8.0": - version "0.8.0" - resolved "https://registry.yarnpkg.com/@firebase/analytics/-/analytics-0.8.0.tgz#b5d595082f57d33842b1fd9025d88f83065e87fe" - integrity sha512-wkcwainNm8Cu2xkJpDSHfhBSdDJn86Q1TZNmLWc67VrhZUHXIKXxIqb65/tNUVE+I8+sFiDDNwA+9R3MqTQTaA== - dependencies: - "@firebase/component" "0.5.17" - "@firebase/installations" "0.5.12" - "@firebase/logger" "0.3.3" - "@firebase/util" "1.6.3" - tslib "^2.1.0" - -"@firebase/app-check-compat@0.2.12": - version "0.2.12" - resolved "https://registry.yarnpkg.com/@firebase/app-check-compat/-/app-check-compat-0.2.12.tgz#e30b2395e3d30f8cfcf3554fc87875f82c1aa086" - integrity sha512-GFppNLlUyMN9Iq31ME/+GkjRVKlc+MeanzUKQ9UaR73ZsYH3oX3Ja+xjoYgixaVJDDG+ofBYR7ZXTkkQdSR/pw== - dependencies: - "@firebase/app-check" "0.5.12" - "@firebase/app-check-types" "0.4.0" - "@firebase/component" "0.5.17" - "@firebase/logger" "0.3.3" - "@firebase/util" "1.6.3" - tslib "^2.1.0" - -"@firebase/app-check-interop-types@0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@firebase/app-check-interop-types/-/app-check-interop-types-0.1.0.tgz#83afd9d41f99166c2bdb2d824e5032e9edd8fe53" - integrity sha512-uZfn9s4uuRsaX5Lwx+gFP3B6YsyOKUE+Rqa6z9ojT4VSRAsZFko9FRn6OxQUA1z5t5d08fY4pf+/+Dkd5wbdbA== - -"@firebase/app-check-types@0.4.0": - version "0.4.0" - resolved "https://registry.yarnpkg.com/@firebase/app-check-types/-/app-check-types-0.4.0.tgz#7007a9d1d720db20bcf466fe6785c96feaa0a82d" - integrity sha512-SsWafqMABIOu7zLgWbmwvHGOeQQVQlwm42kwwubsmfLmL4Sf5uGpBfDhQ0CAkpi7bkJ/NwNFKafNDL9prRNP0Q== - -"@firebase/app-check@0.5.12": - version "0.5.12" - resolved "https://registry.yarnpkg.com/@firebase/app-check/-/app-check-0.5.12.tgz#82f305cc01bfe4d32c35e425941b2eca2ce9f089" - integrity sha512-l+MmvupSGT/F+I5ei7XjhEfpoL4hLVJr0vUwcG5NEf2hAkQnySli9fnbl9fZu1BJaQ2kthrMmtg1gcbcM9BUCQ== - dependencies: - "@firebase/component" "0.5.17" - "@firebase/logger" "0.3.3" - "@firebase/util" "1.6.3" - tslib "^2.1.0" - -"@firebase/app-compat@0.1.30": - version "0.1.30" - resolved "https://registry.yarnpkg.com/@firebase/app-compat/-/app-compat-0.1.30.tgz#027542ec59e1a482edb8dc90b611f3c47e0a7a9b" - integrity sha512-t51oJEJzjts4D5C7Nol0Ua7dqhpQSlcWSa7X1VtL+zjcTZ92ibYmwQjXomexBmlKvCUamGClMAEBfEgUtr0Wug== - dependencies: - "@firebase/app" "0.7.29" - "@firebase/component" "0.5.17" - "@firebase/logger" "0.3.3" - "@firebase/util" "1.6.3" - tslib "^2.1.0" - -"@firebase/app-types@0.7.0": - version "0.7.0" - resolved "https://registry.yarnpkg.com/@firebase/app-types/-/app-types-0.7.0.tgz#c9e16d1b8bed1a991840b8d2a725fb58d0b5899f" - integrity sha512-6fbHQwDv2jp/v6bXhBw2eSRbNBpxHcd1NBF864UksSMVIqIyri9qpJB1Mn6sGZE+bnDsSQBC5j2TbMxYsJQkQg== - -"@firebase/app@0.7.29": - version "0.7.29" - resolved "https://registry.yarnpkg.com/@firebase/app/-/app-0.7.29.tgz#404fcc7f130b1829350d3a2e20d2d350e0c54b91" - integrity sha512-jT47plTi/O0lpXEXPx5t/dH/3BVnP9Tq/D8SZkhMUXPYlYDudvepIiV3VOW8XxbbHU/X+JyY0qG5CoWxIk0teg== - dependencies: - "@firebase/component" "0.5.17" - "@firebase/logger" "0.3.3" - "@firebase/util" "1.6.3" - idb "7.0.1" - tslib "^2.1.0" - -"@firebase/auth-compat@0.2.18": - version "0.2.18" - resolved "https://registry.yarnpkg.com/@firebase/auth-compat/-/auth-compat-0.2.18.tgz#c7bb254fbb23447069f81abb15f96e91de40b285" - integrity sha512-Fw2PJS0G/tGrfyEBcYJQ42sfy5+sANrK5xd7tuzgV7zLFW5rYkHUIZngXjuOBwLOcfO2ixa/FavfeJle3oJ38Q== - dependencies: - "@firebase/auth" "0.20.5" - "@firebase/auth-types" "0.11.0" - "@firebase/component" "0.5.17" - "@firebase/util" "1.6.3" - node-fetch "2.6.7" - selenium-webdriver "4.1.2" - tslib "^2.1.0" - -"@firebase/auth-interop-types@0.1.6": - version "0.1.6" - resolved "https://registry.yarnpkg.com/@firebase/auth-interop-types/-/auth-interop-types-0.1.6.tgz#5ce13fc1c527ad36f1bb1322c4492680a6cf4964" - integrity sha512-etIi92fW3CctsmR9e3sYM3Uqnoq861M0Id9mdOPF6PWIg38BXL5k4upCNBggGUpLIS0H1grMOvy/wn1xymwe2g== - -"@firebase/auth-types@0.11.0": - version "0.11.0" - resolved "https://registry.yarnpkg.com/@firebase/auth-types/-/auth-types-0.11.0.tgz#b9c73c60ca07945b3bbd7a097633e5f78fa9e886" - integrity sha512-q7Bt6cx+ySj9elQHTsKulwk3+qDezhzRBFC9zlQ1BjgMueUOnGMcvqmU0zuKlQ4RhLSH7MNAdBV2znVaoN3Vxw== - -"@firebase/auth@0.20.5": - version "0.20.5" - resolved "https://registry.yarnpkg.com/@firebase/auth/-/auth-0.20.5.tgz#a2e6c6b593d8f9cf8276a7d1f8ab5b055d65cc50" - integrity sha512-SbKj7PCAuL0lXEToUOoprc1im2Lr/bzOePXyPC7WWqVgdVBt0qovbfejlzKYwJLHUAPg9UW1y3XYe3IlbXr77w== - dependencies: - "@firebase/component" "0.5.17" - "@firebase/logger" "0.3.3" - "@firebase/util" "1.6.3" - node-fetch "2.6.7" - selenium-webdriver "4.1.2" - tslib "^2.1.0" - -"@firebase/component@0.5.17": - version "0.5.17" - resolved "https://registry.yarnpkg.com/@firebase/component/-/component-0.5.17.tgz#89291f378714df05d44430c524708669380d8ea6" - integrity sha512-mTM5CBSIlmI+i76qU4+DhuExnWtzcPS3cVgObA3VAjliPPr3GrUlTaaa8KBGfxsD27juQxMsYA0TvCR5X+GQ3Q== - dependencies: - "@firebase/util" "1.6.3" - tslib "^2.1.0" - -"@firebase/database-compat@0.2.3": - version "0.2.3" - resolved "https://registry.yarnpkg.com/@firebase/database-compat/-/database-compat-0.2.3.tgz#023ee1444088dd49714f93dcb2dff63d4b9a8589" - integrity sha512-uwSMnbjlSQM5gQRq8OoBLs7uc7obwsl0D6kSDAnMOlPtPl9ert79Rq9faU/COjybsJ8l7tNXMVYYJo3mQ5XNrA== - dependencies: - "@firebase/component" "0.5.17" - "@firebase/database" "0.13.3" - "@firebase/database-types" "0.9.11" - "@firebase/logger" "0.3.3" - "@firebase/util" "1.6.3" - tslib "^2.1.0" - -"@firebase/database-types@0.9.11": - version "0.9.11" - resolved "https://registry.yarnpkg.com/@firebase/database-types/-/database-types-0.9.11.tgz#ac8881e20e490d1557c8975aa3e7815dbf03b2e6" - integrity sha512-27V3eFomWCZqLR6qb3Q9eS2lsUtulhSHeDNaL6fImwnhvMYTmf6ZwMfRWupgi8AFwW4s91g9Oc1/fkQtJGHKQw== - dependencies: - "@firebase/app-types" "0.7.0" - "@firebase/util" "1.6.3" - -"@firebase/database@0.13.3": - version "0.13.3" - resolved "https://registry.yarnpkg.com/@firebase/database/-/database-0.13.3.tgz#cf9acc03434c89e0bcb8b8ab3a6d2a70e342b8c5" - integrity sha512-ZE+QJqQUaCTZiIzGq3RJLo64HRMtbdaEwyDhfZyPEzMJV4kyLsw3cHdEHVCtBmdasTvwtpO2YRFmd4AXAoKtNw== - dependencies: - "@firebase/auth-interop-types" "0.1.6" - "@firebase/component" "0.5.17" - "@firebase/logger" "0.3.3" - "@firebase/util" "1.6.3" - faye-websocket "0.11.4" - tslib "^2.1.0" - -"@firebase/firestore-compat@0.1.22": - version "0.1.22" - resolved "https://registry.yarnpkg.com/@firebase/firestore-compat/-/firestore-compat-0.1.22.tgz#535e51d9034c08a7f4ebb67e0de86459ab4c5494" - integrity sha512-1HWmJtbxhDzAV7984XSQX7tp0MzjhRFnBygpU6k6H2m0Ey9JVDTPK8lIlZCctjCCA2cBsek7yAD+rDnpWC+KRw== - dependencies: - "@firebase/component" "0.5.17" - "@firebase/firestore" "3.4.13" - "@firebase/firestore-types" "2.5.0" - "@firebase/util" "1.6.3" - tslib "^2.1.0" - -"@firebase/firestore-types@2.5.0": - version "2.5.0" - resolved "https://registry.yarnpkg.com/@firebase/firestore-types/-/firestore-types-2.5.0.tgz#16fca40b6980fdb000de86042d7a96635f2bcdd7" - integrity sha512-I6c2m1zUhZ5SH0cWPmINabDyH5w0PPFHk2UHsjBpKdZllzJZ2TwTkXbDtpHUZNmnc/zAa0WNMNMvcvbb/xJLKA== - -"@firebase/firestore@3.4.13": - version "3.4.13" - resolved "https://registry.yarnpkg.com/@firebase/firestore/-/firestore-3.4.13.tgz#c934f72fed311f9359cff3c836ab43d492c85b55" - integrity sha512-wLsbWflFoWDg9NprulzTAjtapLA3dfaG1Dsa9OUsgPRDGg5jfeo60n43d94fesX4crE+C5vkFhLQKMgsEGpr9w== - dependencies: - "@firebase/component" "0.5.17" - "@firebase/logger" "0.3.3" - "@firebase/util" "1.6.3" - "@firebase/webchannel-wrapper" "0.6.2" - "@grpc/grpc-js" "^1.3.2" - "@grpc/proto-loader" "^0.6.13" - node-fetch "2.6.7" - tslib "^2.1.0" - -"@firebase/functions-compat@0.2.4": - version "0.2.4" - resolved "https://registry.yarnpkg.com/@firebase/functions-compat/-/functions-compat-0.2.4.tgz#afa5d8eefe6d51c7b89e44d9262700b68fbcb73f" - integrity sha512-Crfn6il1yXGuXkjSd8nKrqR4XxPvuP19g64bXpM6Ix67qOkQg676kyOuww0FF17xN0NSXHfG8Pyf+CUrx8wJ5g== - dependencies: - "@firebase/component" "0.5.17" - "@firebase/functions" "0.8.4" - "@firebase/functions-types" "0.5.0" - "@firebase/util" "1.6.3" - tslib "^2.1.0" - -"@firebase/functions-types@0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@firebase/functions-types/-/functions-types-0.5.0.tgz#b50ba95ccce9e96f7cda453228ffe1684645625b" - integrity sha512-qza0M5EwX+Ocrl1cYI14zoipUX4gI/Shwqv0C1nB864INAD42Dgv4v94BCyxGHBg2kzlWy8PNafdP7zPO8aJQA== - -"@firebase/functions@0.8.4": - version "0.8.4" - resolved "https://registry.yarnpkg.com/@firebase/functions/-/functions-0.8.4.tgz#a9b7a10314f286df1ded87d8546fb8d9107a9c06" - integrity sha512-o1bB0xMyQKe+b246zGnjwHj4R6BH4mU2ZrSaa/3QvTpahUQ3hqYfkZPLOXCU7+vEFxHb3Hd4UUjkFhxoAcPqLA== - dependencies: - "@firebase/app-check-interop-types" "0.1.0" - "@firebase/auth-interop-types" "0.1.6" - "@firebase/component" "0.5.17" - "@firebase/messaging-interop-types" "0.1.0" - "@firebase/util" "1.6.3" - node-fetch "2.6.7" - tslib "^2.1.0" - -"@firebase/installations-compat@0.1.12": - version "0.1.12" - resolved "https://registry.yarnpkg.com/@firebase/installations-compat/-/installations-compat-0.1.12.tgz#d0394127f71aff596cb8bb607840095d1617246e" - integrity sha512-BIhFpWIn/GkuOa+jnXkp3SDJT2RLYJF6MWpinHIBKFJs7MfrgYZ3zQ1AlhobDEql+bkD1dK4dB5sNcET2T+EyA== - dependencies: - "@firebase/component" "0.5.17" - "@firebase/installations" "0.5.12" - "@firebase/installations-types" "0.4.0" - "@firebase/util" "1.6.3" - tslib "^2.1.0" - -"@firebase/installations-types@0.4.0": - version "0.4.0" - resolved "https://registry.yarnpkg.com/@firebase/installations-types/-/installations-types-0.4.0.tgz#256782ff9adfb390ac658c25bc32f89635ddce7c" - integrity sha512-nXxWKQDvBGctuvsizbUEJKfxXU9WAaDhon+j0jpjIfOJkvkj3YHqlLB/HeYjpUn85Pb22BjplpTnDn4Gm9pc3A== + "@emotion/babel-plugin" "^11.11.0" + "@emotion/is-prop-valid" "^1.2.2" + "@emotion/serialize" "^1.1.4" + "@emotion/use-insertion-effect-with-fallbacks" "^1.0.1" + "@emotion/utils" "^1.2.1" + +"@emotion/unitless@^0.8.1": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.8.1.tgz#182b5a4704ef8ad91bde93f7a860a88fd92c79a3" + integrity sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ== + +"@emotion/use-insertion-effect-with-fallbacks@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz#08de79f54eb3406f9daaf77c76e35313da963963" + integrity sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw== -"@firebase/installations@0.5.12": - version "0.5.12" - resolved "https://registry.yarnpkg.com/@firebase/installations/-/installations-0.5.12.tgz#1d5764aa6f0b73d9d6d1a81a07eab5cd71a5ea27" - integrity sha512-Zq43fCE0PB5tGJ3ojzx5RNQzKdej1188qgAk22rwjuhP7npaG/PlJqDG1/V0ZjTLRePZ1xGrfXSPlA17c/vtNw== - dependencies: - "@firebase/component" "0.5.17" - "@firebase/util" "1.6.3" - idb "7.0.1" - tslib "^2.1.0" +"@emotion/utils@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.2.1.tgz#bbab58465738d31ae4cb3dbb6fc00a5991f755e4" + integrity sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg== -"@firebase/logger@0.3.3": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@firebase/logger/-/logger-0.3.3.tgz#0f724b1e0b166d17ac285aac5c8ec14d136beed4" - integrity sha512-POTJl07jOKTOevLXrTvJD/VZ0M6PnJXflbAh5J9VGkmtXPXNG6MdZ9fmRgqYhXKTaDId6AQenQ262uwgpdtO0Q== - dependencies: - tslib "^2.1.0" +"@emotion/weak-memoize@^0.3.1": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz#d0fce5d07b0620caa282b5131c297bb60f9d87e6" + integrity sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww== -"@firebase/messaging-compat@0.1.16": - version "0.1.16" - resolved "https://registry.yarnpkg.com/@firebase/messaging-compat/-/messaging-compat-0.1.16.tgz#4fe4e2c1b496e62f63e815cb242a2ab323cd7899" - integrity sha512-uG7rWcXJzU8vvlEBFpwG1ndw/GURrrmKcwsHopEWbsPGjMRaVWa7XrdKbvIR7IZohqPzcC/V9L8EeqF4Q4lz8w== +"@floating-ui/core@^1.0.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.0.tgz#fa41b87812a16bf123122bf945946bae3fdf7fc1" + integrity sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g== dependencies: - "@firebase/component" "0.5.17" - "@firebase/messaging" "0.9.16" - "@firebase/util" "1.6.3" - tslib "^2.1.0" - -"@firebase/messaging-interop-types@0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@firebase/messaging-interop-types/-/messaging-interop-types-0.1.0.tgz#bdac02dd31edd5cb9eec37b1db698ea5e2c1a631" - integrity sha512-DbvUl/rXAZpQeKBnwz0NYY5OCqr2nFA0Bj28Fmr3NXGqR4PAkfTOHuQlVtLO1Nudo3q0HxAYLa68ZDAcuv2uKQ== - -"@firebase/messaging@0.9.16": - version "0.9.16" - resolved "https://registry.yarnpkg.com/@firebase/messaging/-/messaging-0.9.16.tgz#96b57ebbb054e57f78585f85f59d521c5ba5cd85" - integrity sha512-Yl9gGrAvJF6C1gg3+Cr2HxlL6APsDEkrorkFafmSP1l+rg1epZKoOAcKJbSF02Vtb50wfb9FqGGy8tzodgETxg== - dependencies: - "@firebase/component" "0.5.17" - "@firebase/installations" "0.5.12" - "@firebase/messaging-interop-types" "0.1.0" - "@firebase/util" "1.6.3" - idb "7.0.1" - tslib "^2.1.0" - -"@firebase/performance-compat@0.1.12": - version "0.1.12" - resolved "https://registry.yarnpkg.com/@firebase/performance-compat/-/performance-compat-0.1.12.tgz#ac50b0cd29bf7f5e1e33c640dba25e2f8db95f0b" - integrity sha512-IBORzUeGY1MGdZnsix9Mu5z4+C3WHIwalu0usxvygL0EZKHztGG8bppYPGH/b5vvg8QyHs9U+Pn1Ot2jZhffQQ== - dependencies: - "@firebase/component" "0.5.17" - "@firebase/logger" "0.3.3" - "@firebase/performance" "0.5.12" - "@firebase/performance-types" "0.1.0" - "@firebase/util" "1.6.3" - tslib "^2.1.0" - -"@firebase/performance-types@0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@firebase/performance-types/-/performance-types-0.1.0.tgz#5e6efa9dc81860aee2cb7121b39ae8fa137e69fc" - integrity sha512-6p1HxrH0mpx+622Ql6fcxFxfkYSBpE3LSuwM7iTtYU2nw91Hj6THC8Bc8z4nboIq7WvgsT/kOTYVVZzCSlXl8w== + "@floating-ui/utils" "^0.2.1" -"@firebase/performance@0.5.12": - version "0.5.12" - resolved "https://registry.yarnpkg.com/@firebase/performance/-/performance-0.5.12.tgz#4eae3eb91eeffb29b996e7908172052d4a901856" - integrity sha512-MPVTkOkGrm2SMQgI1FPNBm85y2pPqlPb6VDjIMCWkVpAr6G1IZzUT24yEMySRcIlK/Hh7/Qu1Nu5ASRzRuX6+Q== +"@floating-ui/dom@^1.6.1": + version "1.6.3" + resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.6.3.tgz#954e46c1dd3ad48e49db9ada7218b0985cee75ef" + integrity sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw== dependencies: - "@firebase/component" "0.5.17" - "@firebase/installations" "0.5.12" - "@firebase/logger" "0.3.3" - "@firebase/util" "1.6.3" - tslib "^2.1.0" + "@floating-ui/core" "^1.0.0" + "@floating-ui/utils" "^0.2.0" -"@firebase/polyfill@0.3.36": - version "0.3.36" - resolved "https://registry.yarnpkg.com/@firebase/polyfill/-/polyfill-0.3.36.tgz#c057cce6748170f36966b555749472b25efdb145" - integrity sha512-zMM9oSJgY6cT2jx3Ce9LYqb0eIpDE52meIzd/oe/y70F+v9u1LDqk5kUF5mf16zovGBWMNFmgzlsh6Wj0OsFtg== - dependencies: - core-js "3.6.5" - promise-polyfill "8.1.3" - whatwg-fetch "2.0.4" - -"@firebase/remote-config-compat@0.1.12": - version "0.1.12" - resolved "https://registry.yarnpkg.com/@firebase/remote-config-compat/-/remote-config-compat-0.1.12.tgz#7606752d7bfe2701d58568345ca536beda14ee53" - integrity sha512-Yz7Gtb2rLa7ykXZX9DnSTId8CXd++jFFLW3foUImrYwJEtWgLJc7gwkRfd1M73IlKGNuQAY+DpUNF0n1dLbecA== - dependencies: - "@firebase/component" "0.5.17" - "@firebase/logger" "0.3.3" - "@firebase/remote-config" "0.3.11" - "@firebase/remote-config-types" "0.2.0" - "@firebase/util" "1.6.3" - tslib "^2.1.0" - -"@firebase/remote-config-types@0.2.0": - version "0.2.0" - resolved "https://registry.yarnpkg.com/@firebase/remote-config-types/-/remote-config-types-0.2.0.tgz#1e2759fc01f20b58c564db42196f075844c3d1fd" - integrity sha512-hqK5sCPeZvcHQ1D6VjJZdW6EexLTXNMJfPdTwbD8NrXUw6UjWC4KWhLK/TSlL0QPsQtcKRkaaoP+9QCgKfMFPw== - -"@firebase/remote-config@0.3.11": - version "0.3.11" - resolved "https://registry.yarnpkg.com/@firebase/remote-config/-/remote-config-0.3.11.tgz#93c82b5944a20c027f4ee82c145813ca96b430bb" - integrity sha512-qA84dstrvVpO7rWT/sb2CLv1kjHVmz59SRFPKohJJYFBcPOGK4Pe4FWWhKAE9yg1Gnl0qYAGkahOwNawq3vE0g== - dependencies: - "@firebase/component" "0.5.17" - "@firebase/installations" "0.5.12" - "@firebase/logger" "0.3.3" - "@firebase/util" "1.6.3" - tslib "^2.1.0" - -"@firebase/storage-compat@0.1.17": - version "0.1.17" - resolved "https://registry.yarnpkg.com/@firebase/storage-compat/-/storage-compat-0.1.17.tgz#da721071e006d066fb9b1cff69481bd59a02346b" - integrity sha512-nOYmnpI0gwoz5nROseMi9WbmHGf+xumfsOvdPyMZAjy0VqbDnpKIwmTUZQBdR+bLuB5oIkHQsvw9nbb1SH+PzQ== - dependencies: - "@firebase/component" "0.5.17" - "@firebase/storage" "0.9.9" - "@firebase/storage-types" "0.6.0" - "@firebase/util" "1.6.3" - tslib "^2.1.0" - -"@firebase/storage-types@0.6.0": - version "0.6.0" - resolved "https://registry.yarnpkg.com/@firebase/storage-types/-/storage-types-0.6.0.tgz#0b1af64a2965af46fca138e5b70700e9b7e6312a" - integrity sha512-1LpWhcCb1ftpkP/akhzjzeFxgVefs6eMD2QeKiJJUGH1qOiows2w5o0sKCUSQrvrRQS1lz3SFGvNR1Ck/gqxeA== - -"@firebase/storage@0.9.9": - version "0.9.9" - resolved "https://registry.yarnpkg.com/@firebase/storage/-/storage-0.9.9.tgz#3d0080dd130bc3315731483384a7ef7c00f76e22" - integrity sha512-Zch7srLT2SIh9y2nCVv/4Kne0HULn7OPkmreY70BJTUJ+g5WLRjggBq6x9fV5ls9V38iqMWfn4prxzX8yIc08A== +"@floating-ui/react-dom@^2.0.8": + version "2.0.8" + resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.0.8.tgz#afc24f9756d1b433e1fe0d047c24bd4d9cefaa5d" + integrity sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw== dependencies: - "@firebase/component" "0.5.17" - "@firebase/util" "1.6.3" - node-fetch "2.6.7" - tslib "^2.1.0" + "@floating-ui/dom" "^1.6.1" -"@firebase/util@1.6.3": - version "1.6.3" - resolved "https://registry.yarnpkg.com/@firebase/util/-/util-1.6.3.tgz#76128c1b5684c031823e95f6c08a7fb8560655c6" - integrity sha512-FujteO6Zjv6v8A4HS+t7c+PjU0Kaxj+rOnka0BsI/twUaCC9t8EQPmXpWZdk7XfszfahJn2pqsflUWUhtUkRlg== - dependencies: - tslib "^2.1.0" - -"@firebase/webchannel-wrapper@0.6.2": - version "0.6.2" - resolved "https://registry.yarnpkg.com/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.6.2.tgz#6d05fa126104c9907573364dc04147b89b530e15" - integrity sha512-zThUKcqIU6utWzM93uEvhlh8qj8A5LMPFJPvk/ODb+8GSSif19xM2Lw1M2ijyBy8+6skSkQBbavPzOU5Oh/8tQ== - -"@grpc/grpc-js@^1.3.2": - version "1.6.8" - resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.6.8.tgz#77cc8b2d841c34dea8b105d45ff1732caefae4f2" - integrity sha512-Nt5tufF/O5Q310kP0cDzxznWMZW58GCTZhUUiAQ9B0K0ANKNQ4Lj/K9XK0vZg+UBKq5/7z7+8mXHHfrcwoeFJQ== - dependencies: - "@grpc/proto-loader" "^0.7.0" - "@types/node" ">=12.12.47" - -"@grpc/proto-loader@^0.6.13": - version "0.6.13" - resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.6.13.tgz#008f989b72a40c60c96cd4088522f09b05ac66bc" - integrity sha512-FjxPYDRTn6Ec3V0arm1FtSpmP6V50wuph2yILpyvTKzjc76oDdoihXqM1DzOW5ubvCC8GivfCnNtfaRE8myJ7g== - dependencies: - "@types/long" "^4.0.1" - lodash.camelcase "^4.3.0" - long "^4.0.0" - protobufjs "^6.11.3" - yargs "^16.2.0" - -"@grpc/proto-loader@^0.7.0": - version "0.7.0" - resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.0.tgz#743cc8a941cc251620c66ebe0d330e1411a33535" - integrity sha512-SGPZtVmqOvNfPFOA/nNPn+0Weqa5wubBgQ56+JgTbeLY2VezwtMjwPPFzh0kvQccwWT3a2TXT0ZGK/pJoOTk1A== - dependencies: - "@types/long" "^4.0.1" - lodash.camelcase "^4.3.0" - long "^4.0.0" - protobufjs "^7.0.0" - yargs "^16.2.0" +"@floating-ui/utils@^0.2.0", "@floating-ui/utils@^0.2.1": + version "0.2.1" + resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.1.tgz#16308cea045f0fc777b6ff20a9f25474dd8293d2" + integrity sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q== "@jridgewell/resolve-uri@^3.1.0": version "3.1.2" @@ -655,191 +232,124 @@ "@jridgewell/sourcemap-codec" "^1.4.14" "@leichtgewicht/ip-codec@^2.0.1": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b" - integrity sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A== - -"@mui/base@5.0.0-alpha.92": - version "5.0.0-alpha.92" - resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-alpha.92.tgz#5c2ca31801fe21a8fec9bfda2cf5f44b1e3c7284" - integrity sha512-ZgnSLrTXL4iUdLQhjp01dAOTQPQlnwrqjZRwDT3E6LZXEYn6cMv1MY6LZkWcF/zxrUnyasnsyMAgZ5d8AXS7bA== - dependencies: - "@babel/runtime" "^7.17.2" - "@emotion/is-prop-valid" "^1.1.3" - "@mui/types" "^7.1.5" - "@mui/utils" "^5.9.3" - "@popperjs/core" "^2.11.5" - clsx "^1.2.1" + version "2.0.5" + resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz#4fc56c15c580b9adb7dc3c333a134e540b44bfb1" + integrity sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw== + +"@mui/base@5.0.0-beta.37": + version "5.0.0-beta.37" + resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-beta.37.tgz#0e7e0f28402391fcfbb05476d5acc6c4f2d817b1" + integrity sha512-/o3anbb+DeCng8jNsd3704XtmmLDZju1Fo8R2o7ugrVtPQ/QpcqddwKNzKPZwa0J5T8YNW3ZVuHyQgbTnQLisQ== + dependencies: + "@babel/runtime" "^7.23.9" + "@floating-ui/react-dom" "^2.0.8" + "@mui/types" "^7.2.13" + "@mui/utils" "^5.15.11" + "@popperjs/core" "^2.11.8" + clsx "^2.1.0" prop-types "^15.8.1" - react-is "^18.2.0" -"@mui/lab@^5.0.0-alpha.82": - version "5.0.0-alpha.93" - resolved "https://registry.yarnpkg.com/@mui/lab/-/lab-5.0.0-alpha.93.tgz#b0a1662ae478e791f083fdf49143766b890671e6" - integrity sha512-PGrI6tGwKGpLEv4sG7Jkhh/gqk5SE3KRCY8SKmC7JIOUpHEdPKIPH7kId/UZUd8+NOkr8YsljXmozpWv9PLsBQ== - dependencies: - "@babel/runtime" "^7.17.2" - "@mui/base" "5.0.0-alpha.92" - "@mui/system" "^5.9.3" - "@mui/utils" "^5.9.3" - clsx "^1.2.1" +"@mui/base@^5.0.0-beta.37": + version "5.0.0-beta.40" + resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-beta.40.tgz#1f8a782f1fbf3f84a961e954c8176b187de3dae2" + integrity sha512-I/lGHztkCzvwlXpjD2+SNmvNQvB4227xBXhISPjEaJUXGImOQ9f3D2Yj/T3KasSI/h0MLWy74X0J6clhPmsRbQ== + dependencies: + "@babel/runtime" "^7.23.9" + "@floating-ui/react-dom" "^2.0.8" + "@mui/types" "^7.2.14" + "@mui/utils" "^5.15.14" + "@popperjs/core" "^2.11.8" + clsx "^2.1.0" prop-types "^15.8.1" - react-is "^18.2.0" -"@mui/material@^5.8.0": - version "5.9.3" - resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.9.3.tgz#23aa8a6f651f3f139a38e0eea39468ced7f509d0" - integrity sha512-idDJajnfnDr+2pI6h2tzWtWoZJmVHNk6aSjISirMuVOGy0ugWpsCE+KW4++GS7aTCujXm9+cl5bWAyXvGjiPIQ== - dependencies: - "@babel/runtime" "^7.17.2" - "@mui/base" "5.0.0-alpha.92" - "@mui/system" "^5.9.3" - "@mui/types" "^7.1.5" - "@mui/utils" "^5.9.3" - "@types/react-transition-group" "^4.4.5" - clsx "^1.2.1" - csstype "^3.1.0" +"@mui/core-downloads-tracker@^5.15.11": + version "5.15.15" + resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.15.15.tgz#2bc2bda50db66c12f10aefec907c48c8f669ef59" + integrity sha512-aXnw29OWQ6I5A47iuWEI6qSSUfH6G/aCsW9KmW3LiFqr7uXZBK4Ks+z8G+qeIub8k0T5CMqlT2q0L+ZJTMrqpg== + +"@mui/material@5.15.11": + version "5.15.11" + resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.15.11.tgz#4f42ee30443699ffb5836029c6d8464154eca603" + integrity sha512-FA3eEuEZaDaxgN3CgfXezMWbCZ4VCeU/sv0F0/PK5n42qIgsPVD6q+j71qS7/62sp6wRFMHtDMpXRlN+tT/7NA== + dependencies: + "@babel/runtime" "^7.23.9" + "@mui/base" "5.0.0-beta.37" + "@mui/core-downloads-tracker" "^5.15.11" + "@mui/system" "^5.15.11" + "@mui/types" "^7.2.13" + "@mui/utils" "^5.15.11" + "@types/react-transition-group" "^4.4.10" + clsx "^2.1.0" + csstype "^3.1.3" prop-types "^15.8.1" react-is "^18.2.0" react-transition-group "^4.4.5" -"@mui/private-theming@^5.9.3": - version "5.9.3" - resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.9.3.tgz#8ea06dbe0522b0cf4ba5ee19b1a4d7f74539ae1c" - integrity sha512-Ys3WO39WqoGciGX9k5AIi/k2zJhlydv4FzlEEwtw9OqdMaV0ydK/TdZekKzjP9sTI/JcdAP3H5DWtUaPLQJjWg== +"@mui/private-theming@^5.15.14": + version "5.15.14" + resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.15.14.tgz#edd9a82948ed01586a01c842eb89f0e3f68970ee" + integrity sha512-UH0EiZckOWcxiXLX3Jbb0K7rC8mxTr9L9l6QhOZxYc4r8FHUkefltV9VDGLrzCaWh30SQiJvAEd7djX3XXY6Xw== dependencies: - "@babel/runtime" "^7.17.2" - "@mui/utils" "^5.9.3" + "@babel/runtime" "^7.23.9" + "@mui/utils" "^5.15.14" prop-types "^15.8.1" -"@mui/styled-engine@^5.8.7": - version "5.8.7" - resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.8.7.tgz#63d0779c07677fe76d4705a02c7ae99f89b50780" - integrity sha512-tVqtowjbYmiRq+qcqXK731L9eWoL9H8xTRhuTgaDGKdch1zlt4I2UwInUe1w2N9N/u3/jHsFbLcl1Un3uOwpQg== +"@mui/styled-engine@^5.15.14": + version "5.15.14" + resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.15.14.tgz#168b154c4327fa4ccc1933a498331d53f61c0de2" + integrity sha512-RILkuVD8gY6PvjZjqnWhz8fu68dVkqhM5+jYWfB5yhlSQKg+2rHkmEwm75XIeAqI3qwOndK6zELK5H6Zxn4NHw== dependencies: - "@babel/runtime" "^7.17.2" - "@emotion/cache" "^11.9.3" - csstype "^3.1.0" + "@babel/runtime" "^7.23.9" + "@emotion/cache" "^11.11.0" + csstype "^3.1.3" prop-types "^15.8.1" -"@mui/system@^5.9.3": - version "5.9.3" - resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.9.3.tgz#5d2d06db2b2454573639de394f81b6be3608a1ce" - integrity sha512-EXQV2POwncstHLYII+G4VSYdEFun1TjBbQSBDK76DbIkug8nPjtjAZ+3Kgk3/NoFIigW+vQ9cDVUZtlbRH6YMQ== - dependencies: - "@babel/runtime" "^7.17.2" - "@mui/private-theming" "^5.9.3" - "@mui/styled-engine" "^5.8.7" - "@mui/types" "^7.1.5" - "@mui/utils" "^5.9.3" - clsx "^1.2.1" - csstype "^3.1.0" +"@mui/system@^5.15.11": + version "5.15.15" + resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.15.15.tgz#658771b200ce3c4a0f28e58169f02e5e718d1c53" + integrity sha512-aulox6N1dnu5PABsfxVGOZffDVmlxPOVgj56HrUnJE8MCSh8lOvvkd47cebIVQQYAjpwieXQXiDPj5pwM40jTQ== + dependencies: + "@babel/runtime" "^7.23.9" + "@mui/private-theming" "^5.15.14" + "@mui/styled-engine" "^5.15.14" + "@mui/types" "^7.2.14" + "@mui/utils" "^5.15.14" + clsx "^2.1.0" + csstype "^3.1.3" prop-types "^15.8.1" -"@mui/types@^7.1.5": - version "7.1.5" - resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.1.5.tgz#5e5cc49d719bc86522983359bc1f90eddcff0624" - integrity sha512-HnRXrxgHJYJcT8ZDdDCQIlqk0s0skOKD7eWs9mJgBUu70hyW4iA6Kiv3yspJR474RFH8hysKR65VVSzUSzkuwA== +"@mui/types@^7.2.13", "@mui/types@^7.2.14": + version "7.2.14" + resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.14.tgz#8a02ac129b70f3d82f2f9b76ded2c8d48e3fc8c9" + integrity sha512-MZsBZ4q4HfzBsywtXgM1Ksj6HDThtiwmOKUXH1pKYISI9gAVXCNHNpo7TlGoGrBaYWZTdNoirIN7JsQcQUjmQQ== -"@mui/utils@^5.4.1", "@mui/utils@^5.9.3": - version "5.9.3" - resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.9.3.tgz#a11e0824f00b7ea40257b390060ce167fe861d02" - integrity sha512-l0N5bcrenE9hnwZ/jPecpIRqsDFHkPXoFUcmkgysaJwVZzJ3yQkGXB47eqmXX5yyGrSc6HksbbqXEaUya+siew== +"@mui/utils@^5.15.11", "@mui/utils@^5.15.14": + version "5.15.14" + resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.15.14.tgz#e414d7efd5db00bfdc875273a40c0a89112ade3a" + integrity sha512-0lF/7Hh/ezDv5X7Pry6enMsbYyGKjADzvHyo3Qrc/SSlTsQ1VkbDMbH0m2t3OR5iIVLwMoxwM7yGd+6FCMtTFA== dependencies: - "@babel/runtime" "^7.17.2" - "@types/prop-types" "^15.7.5" - "@types/react-is" "^16.7.1 || ^17.0.0" + "@babel/runtime" "^7.23.9" + "@types/prop-types" "^15.7.11" prop-types "^15.8.1" react-is "^18.2.0" -"@mui/x-date-pickers@^5.0.0-alpha.3": - version "5.0.0-beta.4" - resolved "https://registry.yarnpkg.com/@mui/x-date-pickers/-/x-date-pickers-5.0.0-beta.4.tgz#85132b8c8ad030823106adc1ce329330275dc7c7" - integrity sha512-MvfZVsTS99Bz4ZxlkgA3PU7beQ1ET5Aejj9T3sPhnnmb2f4YysIZqhReYl5r4IOEuU/enhMKUYwsqgB0GB0MTg== - dependencies: - "@babel/runtime" "^7.18.6" - "@date-io/core" "^2.14.0" - "@date-io/date-fns" "^2.14.0" - "@date-io/dayjs" "^2.14.0" - "@date-io/luxon" "^2.14.0" - "@date-io/moment" "^2.14.0" - "@mui/utils" "^5.4.1" - "@types/react-transition-group" "^4.4.5" - clsx "^1.2.1" - prop-types "^15.7.2" - react-transition-group "^4.4.2" - rifm "^0.12.1" - -"@popperjs/core@^2.11.5": - version "2.11.5" - resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.5.tgz#db5a11bf66bdab39569719555b0f76e138d7bd64" - integrity sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw== - -"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" - integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ== - -"@protobufjs/base64@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" - integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== - -"@protobufjs/codegen@^2.0.4": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" - integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== - -"@protobufjs/eventemitter@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" - integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== - -"@protobufjs/fetch@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" - integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== - dependencies: - "@protobufjs/aspromise" "^1.1.1" - "@protobufjs/inquire" "^1.1.0" - -"@protobufjs/float@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" - integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== - -"@protobufjs/inquire@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" - integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== - -"@protobufjs/path@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" - integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA== - -"@protobufjs/pool@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" - integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== - -"@protobufjs/utf8@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" - integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== +"@popperjs/core@^2.11.8": + version "2.11.8" + resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f" + integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== "@types/body-parser@*": - version "1.19.2" - resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0" - integrity sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g== + version "1.19.5" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.5.tgz#04ce9a3b677dc8bd681a17da1ab9835dc9d3ede4" + integrity sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg== dependencies: "@types/connect" "*" "@types/node" "*" "@types/bonjour@^3.5.9": - version "3.5.10" - resolved "https://registry.yarnpkg.com/@types/bonjour/-/bonjour-3.5.10.tgz#0f6aadfe00ea414edc86f5d106357cda9701e275" - integrity sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw== + version "3.5.13" + resolved "https://registry.yarnpkg.com/@types/bonjour/-/bonjour-3.5.13.tgz#adf90ce1a105e81dd1f9c61fdc5afda1bfb92956" + integrity sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ== dependencies: "@types/node" "*" @@ -849,17 +359,17 @@ integrity sha512-SRXjM+tfsSlA9VuG8hGO2nft2p8zjXCK1VcC6N4NXbBbYbSia9kzCChYQajIjzIqOOOuh5Ock6MmV2oux4jDZQ== "@types/connect-history-api-fallback@^1.3.5": - version "1.3.5" - resolved "https://registry.yarnpkg.com/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz#d1f7a8a09d0ed5a57aee5ae9c18ab9b803205dae" - integrity sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw== + version "1.5.4" + resolved "https://registry.yarnpkg.com/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz#7de71645a103056b48ac3ce07b3520b819c1d5b3" + integrity sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw== dependencies: "@types/express-serve-static-core" "*" "@types/node" "*" "@types/connect@*": - version "3.4.35" - resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" - integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== + version "3.4.38" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.38.tgz#5ba7f3bc4fbbdeaff8dded952e5ff2cc53f8d858" + integrity sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug== dependencies: "@types/node" "*" @@ -899,46 +409,52 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== -"@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.18": - version "4.17.30" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.30.tgz#0f2f99617fa8f9696170c46152ccf7500b34ac04" - integrity sha512-gstzbTWro2/nFed1WXtf+TtrpwxH7Ggs4RLYTLbeVgIkUQOI3WG/JKjgeOU1zXDvezllupjrf8OPIdvTbIaVOQ== +"@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.33": + version "4.19.0" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.19.0.tgz#3ae8ab3767d98d0b682cda063c3339e1e86ccfaa" + integrity sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ== dependencies: "@types/node" "*" "@types/qs" "*" "@types/range-parser" "*" + "@types/send" "*" "@types/express@*", "@types/express@^4.17.13": - version "4.17.13" - resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.13.tgz#a76e2995728999bab51a33fabce1d705a3709034" - integrity sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA== + version "4.17.21" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.21.tgz#c26d4a151e60efe0084b23dc3369ebc631ed192d" + integrity sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ== dependencies: "@types/body-parser" "*" - "@types/express-serve-static-core" "^4.17.18" + "@types/express-serve-static-core" "^4.17.33" "@types/qs" "*" "@types/serve-static" "*" +"@types/http-errors@*": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.4.tgz#7eb47726c391b7345a6ec35ad7f4de469cf5ba4f" + integrity sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA== + "@types/http-proxy@^1.17.8": - version "1.17.9" - resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.9.tgz#7f0e7931343761efde1e2bf48c40f02f3f75705a" - integrity sha512-QsbSjA/fSk7xB+UXlCT3wHBy5ai9wOcNDWwZAtud+jXhwOM3l+EYZh8Lng4+/6n8uar0J7xILzqftJdJ/Wdfkw== + version "1.17.14" + resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.14.tgz#57f8ccaa1c1c3780644f8a94f9c6b5000b5e2eec" + integrity sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w== dependencies: "@types/node" "*" -"@types/json-schema@*", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": +"@types/json-schema@*", "@types/json-schema@^7.0.8": version "7.0.11" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== -"@types/long@^4.0.1": - version "4.0.2" - resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a" - integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA== +"@types/json-schema@^7.0.9": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== -"@types/mime@*": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10" - integrity sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA== +"@types/mime@^1": + version "1.3.5" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690" + integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w== "@types/node-forge@^1.3.0": version "1.3.11" @@ -952,52 +468,39 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.41.tgz#1607b2fd3da014ae5d4d1b31bc792a39348dfb9b" integrity sha512-xA6drNNeqb5YyV5fO3OAEsnXLfO7uF0whiOfPTz5AeDo8KeZFmODKnvwPymMNO8qE/an8pVY/O50tig2SQCrGw== -"@types/node@>=12.12.47", "@types/node@>=13.7.0": - version "18.6.5" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.6.5.tgz#06caea822caf9e59d5034b695186ee74154d2802" - integrity sha512-Xjt5ZGUa5WusGZJ4WJPbOT8QOqp6nDynVFRKcUt32bOgvXEoc6o085WNkYTMO7ifAj2isEfQQ2cseE+wT6jsRw== - "@types/parse-json@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" - integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== + version "4.0.2" + resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.2.tgz#5950e50960793055845e956c427fc2b0d70c5239" + integrity sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw== -"@types/prop-types@*", "@types/prop-types@^15.7.5": - version "15.7.5" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" - integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== +"@types/prop-types@*", "@types/prop-types@^15.7.11": + version "15.7.12" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.12.tgz#12bb1e2be27293c1406acb6af1c3f3a1481d98c6" + integrity sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q== "@types/qs@*": - version "6.9.7" - resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" - integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== + version "6.9.15" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.15.tgz#adde8a060ec9c305a82de1babc1056e73bd64dce" + integrity sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg== "@types/range-parser@*": - version "1.2.4" - resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" - integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== - -"@types/react-is@^16.7.1 || ^17.0.0": - version "17.0.3" - resolved "https://registry.yarnpkg.com/@types/react-is/-/react-is-17.0.3.tgz#2d855ba575f2fc8d17ef9861f084acc4b90a137a" - integrity sha512-aBTIWg1emtu95bLTLx0cpkxwGW3ueZv71nE2YFBpL8k/z5czEW8yYpOo8Dp+UUAFAtKwNaOsh/ioSeQnWlZcfw== - dependencies: - "@types/react" "*" + version "1.2.7" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.7.tgz#50ae4353eaaddc04044279812f52c8c65857dbcb" + integrity sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ== -"@types/react-transition-group@^4.4.5": - version "4.4.5" - resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.5.tgz#aae20dcf773c5aa275d5b9f7cdbca638abc5e416" - integrity sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA== +"@types/react-transition-group@^4.4.10": + version "4.4.10" + resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.10.tgz#6ee71127bdab1f18f11ad8fb3322c6da27c327ac" + integrity sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q== dependencies: "@types/react" "*" "@types/react@*": - version "18.0.17" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.17.tgz#4583d9c322d67efe4b39a935d223edcc7050ccf4" - integrity sha512-38ETy4tL+rn4uQQi7mB81G7V1g0u2ryquNmsVIOKUAEIDK+3CUjZ6rSRpdvS99dNBnkLFL83qfmtLacGOTIhwQ== + version "18.2.79" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.79.tgz#c40efb4f255711f554d47b449f796d1c7756d865" + integrity sha512-RwGAGXPl9kSXwdNTafkOEuFrTBD5SA2B3iEB96xi8+xu5ddUa/cpvyVCSNn+asgLCTHkb5ZxN8gbuibYJi4s1w== dependencies: "@types/prop-types" "*" - "@types/scheduler" "*" csstype "^3.0.2" "@types/retry@0.12.0": @@ -1005,37 +508,41 @@ resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d" integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA== -"@types/scheduler@*": - version "0.16.2" - resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" - integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== +"@types/send@*": + version "0.17.4" + resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.4.tgz#6619cd24e7270793702e4e6a4b958a9010cfc57a" + integrity sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA== + dependencies: + "@types/mime" "^1" + "@types/node" "*" "@types/serve-index@^1.9.1": - version "1.9.1" - resolved "https://registry.yarnpkg.com/@types/serve-index/-/serve-index-1.9.1.tgz#1b5e85370a192c01ec6cec4735cf2917337a6278" - integrity sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg== + version "1.9.4" + resolved "https://registry.yarnpkg.com/@types/serve-index/-/serve-index-1.9.4.tgz#e6ae13d5053cb06ed36392110b4f9a49ac4ec898" + integrity sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug== dependencies: "@types/express" "*" "@types/serve-static@*", "@types/serve-static@^1.13.10": - version "1.15.0" - resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.0.tgz#c7930ff61afb334e121a9da780aac0d9b8f34155" - integrity sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg== + version "1.15.7" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.7.tgz#22174bbd74fb97fe303109738e9b5c2f3064f714" + integrity sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw== dependencies: - "@types/mime" "*" + "@types/http-errors" "*" "@types/node" "*" + "@types/send" "*" "@types/sockjs@^0.3.33": - version "0.3.33" - resolved "https://registry.yarnpkg.com/@types/sockjs/-/sockjs-0.3.33.tgz#570d3a0b99ac995360e3136fd6045113b1bd236f" - integrity sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw== + version "0.3.36" + resolved "https://registry.yarnpkg.com/@types/sockjs/-/sockjs-0.3.36.tgz#ce322cf07bcc119d4cbf7f88954f3a3bd0f67535" + integrity sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q== dependencies: "@types/node" "*" "@types/ws@^8.5.1": - version "8.5.3" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.3.tgz#7d25a1ffbecd3c4f2d35068d0b283c037003274d" - integrity sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w== + version "8.5.10" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.10.tgz#4acfb517970853fa6574a3a6886791d04a396787" + integrity sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A== dependencies: "@types/node" "*" @@ -1220,7 +727,7 @@ ajv-keywords@^3.5.2: resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== -ajv-keywords@^5.0.0: +ajv-keywords@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16" integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw== @@ -1237,10 +744,10 @@ ajv@^6.12.5: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.0.0, ajv@^8.8.0: - version "8.11.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f" - integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg== +ajv@^8.0.0, ajv@^8.9.0: + version "8.12.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" + integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== dependencies: fast-deep-equal "^3.1.1" json-schema-traverse "^1.0.0" @@ -1294,11 +801,6 @@ array-flatten@1.1.1: resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== -array-flatten@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" - integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== - babel-plugin-macros@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz#9ef6dc74deb934b4db344dc973ee851d148c50c1" @@ -1328,7 +830,25 @@ binary-extensions@^2.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== -body-parser@1.20.0, body-parser@^1.19.0: +body-parser@1.20.2: + version "1.20.2" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd" + integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== + dependencies: + bytes "3.1.2" + content-type "~1.0.5" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.11.0" + raw-body "2.5.2" + type-is "~1.6.18" + unpipe "1.0.0" + +body-parser@^1.19.0: version "1.20.0" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.0.tgz#3de69bd89011c11573d7bfee6a64f11b6bd27cc5" integrity sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg== @@ -1347,12 +867,10 @@ body-parser@1.20.0, body-parser@^1.19.0: unpipe "1.0.0" bonjour-service@^1.0.11: - version "1.0.13" - resolved "https://registry.yarnpkg.com/bonjour-service/-/bonjour-service-1.0.13.tgz#4ac003dc1626023252d58adf2946f57e5da450c1" - integrity sha512-LWKRU/7EqDUC9CTAQtuZl5HzBALoCYwtLhffW3et7vZMwv3bWLpJf8bRYlMD5OCcDpTfnPgNCV4yo9ZIaJGMiA== + version "1.2.1" + resolved "https://registry.yarnpkg.com/bonjour-service/-/bonjour-service-1.2.1.tgz#eb41b3085183df3321da1264719fbada12478d02" + integrity sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw== dependencies: - array-flatten "^2.1.2" - dns-equal "^1.0.0" fast-deep-equal "^3.1.3" multicast-dns "^7.2.5" @@ -1432,7 +950,7 @@ caniuse-lite@^1.0.30001349: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001352.tgz#cc6f5da3f983979ad1e2cdbae0505dccaa7c6a12" integrity sha512-GUgH8w6YergqPQDGWhJGt8GDRnY0L/iJVQcU3eJ46GYf52R8tk0Wxp0PymuFVZboJYXGiCqwozAYZNRjVj6IcA== -chalk@^2.0.0: +chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -1449,7 +967,7 @@ chalk@^4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chokidar@3.5.3, chokidar@^3.5.1, chokidar@^3.5.3: +chokidar@3.5.3, chokidar@^3.5.1: version "3.5.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== @@ -1464,6 +982,21 @@ chokidar@3.5.3, chokidar@^3.5.1, chokidar@^3.5.3: optionalDependencies: fsevents "~2.3.2" +chokidar@^3.5.3: + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + chrome-trace-event@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" @@ -1487,10 +1020,10 @@ clone-deep@^4.0.1: kind-of "^6.0.2" shallow-clone "^3.0.0" -clsx@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12" - integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== +clsx@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.0.tgz#e851283bcb5c80ee7608db18487433f7b23f77cb" + integrity sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg== color-convert@^1.9.0: version "1.9.3" @@ -1517,9 +1050,9 @@ color-name@~1.1.4: integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== colorette@^2.0.10: - version "2.0.19" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798" - integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ== + version "2.0.20" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== colorette@^2.0.14: version "2.0.17" @@ -1593,33 +1126,31 @@ content-type@~1.0.4: resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== +content-type@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + convert-source-map@^1.5.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" - integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== - dependencies: - safe-buffer "~5.1.1" + version "1.9.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" + integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== cookie-signature@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== -cookie@0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" - integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== +cookie@0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" + integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== cookie@~0.4.1: version "0.4.2" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== -core-js@3.6.5: - version "3.6.5" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.5.tgz#7395dc273af37fb2e50e9bd3d9fe841285231d1a" - integrity sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA== - core-util-is@~1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" @@ -1634,9 +1165,9 @@ cors@~2.8.5: vary "^1" cosmiconfig@^7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d" - integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ== + version "7.1.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6" + integrity sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA== dependencies: "@types/parse-json" "^4.0.0" import-fresh "^3.2.1" @@ -1653,10 +1184,10 @@ cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" -csstype@^3.0.2, csstype@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.0.tgz#4ddcac3718d787cf9df0d1b7d15033925c8f29f2" - integrity sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA== +csstype@^3.0.2, csstype@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" + integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== custom-event@~1.0.0: version "1.0.1" @@ -1729,15 +1260,10 @@ diff@5.0.0: resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== -dns-equal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" - integrity sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg== - dns-packet@^5.2.2: - version "5.4.0" - resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-5.4.0.tgz#1f88477cf9f27e78a213fb6d118ae38e759a879b" - integrity sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g== + version "5.6.1" + resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-5.6.1.tgz#ae888ad425a9d1478a0674256ab866de1012cf2f" + integrity sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw== dependencies: "@leichtgewicht/ip-codec" "^2.0.1" @@ -1759,14 +1285,6 @@ dom-serialize@^2.2.1: extend "^3.0.0" void-elements "^2.0.0" -dukat@0.5.8-rc.4: - version "0.5.8-rc.4" - resolved "https://registry.yarnpkg.com/dukat/-/dukat-0.5.8-rc.4.tgz#90384dcb50b14c26f0e99dae92b2dea44f5fce21" - integrity sha512-ZnMt6DGBjlVgK2uQamXfd7uP/AxH7RqI0BL9GLrrJb2gKdDxvJChWy+M9AQEaL+7/6TmxzJxFOsRiInY9oGWTA== - dependencies: - google-protobuf "3.12.2" - typescript "3.9.5" - ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" @@ -1914,16 +1432,16 @@ execa@^5.0.0: strip-final-newline "^2.0.0" express@^4.17.3: - version "4.18.1" - resolved "https://registry.yarnpkg.com/express/-/express-4.18.1.tgz#7797de8b9c72c857b9cd0e14a5eea80666267caf" - integrity sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q== + version "4.19.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.19.2.tgz#e25437827a3aa7f2a827bc8171bbbb664a356465" + integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q== dependencies: accepts "~1.3.8" array-flatten "1.1.1" - body-parser "1.20.0" + body-parser "1.20.2" content-disposition "0.5.4" content-type "~1.0.4" - cookie "0.5.0" + cookie "0.6.0" cookie-signature "1.0.6" debug "2.6.9" depd "2.0.0" @@ -1939,7 +1457,7 @@ express@^4.17.3: parseurl "~1.3.3" path-to-regexp "0.1.7" proxy-addr "~2.0.7" - qs "6.10.3" + qs "6.11.0" range-parser "~1.2.1" safe-buffer "5.2.1" send "0.18.0" @@ -1970,7 +1488,7 @@ fastest-levenshtein@^1.0.12: resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz#9990f7d3a88cc5a9ffd1f1745745251700d497e2" integrity sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow== -faye-websocket@0.11.4, faye-websocket@^0.11.3: +faye-websocket@^0.11.3: version "0.11.4" resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.4.tgz#7f0d9275cfdd86a1c963dc8b65fcc451edcbb1da" integrity sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g== @@ -2031,39 +1549,6 @@ find-up@^4.0.0: locate-path "^5.0.0" path-exists "^4.0.0" -firebase@9.9.1: - version "9.9.1" - resolved "https://registry.yarnpkg.com/firebase/-/firebase-9.9.1.tgz#3a4539ab64176196b981d296f7a0b819bb97530b" - integrity sha512-1saLd91mmfNWOdP3DpkCAyXcrwB0iJXZoYY8S98ljp1erL+eUPHu+AHw8ImjynVIejSX07NHgla3mQP0bIniZA== - dependencies: - "@firebase/analytics" "0.8.0" - "@firebase/analytics-compat" "0.1.13" - "@firebase/app" "0.7.29" - "@firebase/app-check" "0.5.12" - "@firebase/app-check-compat" "0.2.12" - "@firebase/app-compat" "0.1.30" - "@firebase/app-types" "0.7.0" - "@firebase/auth" "0.20.5" - "@firebase/auth-compat" "0.2.18" - "@firebase/database" "0.13.3" - "@firebase/database-compat" "0.2.3" - "@firebase/firestore" "3.4.13" - "@firebase/firestore-compat" "0.1.22" - "@firebase/functions" "0.8.4" - "@firebase/functions-compat" "0.2.4" - "@firebase/installations" "0.5.12" - "@firebase/installations-compat" "0.1.12" - "@firebase/messaging" "0.9.16" - "@firebase/messaging-compat" "0.1.16" - "@firebase/performance" "0.5.12" - "@firebase/performance-compat" "0.1.12" - "@firebase/polyfill" "0.3.36" - "@firebase/remote-config" "0.3.11" - "@firebase/remote-config-compat" "0.1.12" - "@firebase/storage" "0.9.9" - "@firebase/storage-compat" "0.1.17" - "@firebase/util" "1.6.3" - flat@^5.0.2: version "5.0.2" resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" @@ -2103,10 +1588,10 @@ fs-extra@^8.1.0: jsonfile "^4.0.0" universalify "^0.1.0" -fs-monkey@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.3.tgz#ae3ac92d53bb328efe0e9a1d9541f6ad8d48e2d3" - integrity sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q== +fs-monkey@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.5.tgz#fe450175f0db0d7ea758102e1d84096acb925788" + integrity sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew== fs.realpath@^1.0.0: version "1.0.0" @@ -2183,11 +1668,6 @@ glob@^7.1.3, glob@^7.1.7: once "^1.3.0" path-is-absolute "^1.0.0" -google-protobuf@3.12.2: - version "3.12.2" - resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.12.2.tgz#50ce9f9b6281235724eb243d6a83e969a2176e53" - integrity sha512-4CZhpuRr1d6HjlyrxoXoocoGFnRYgKULgMtikMddA9ztRyYR59Aondv2FioyxWVamRo0rF2XpYawkTCBEQOSkA== - graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: version "4.2.10" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" @@ -2255,9 +1735,9 @@ hpack.js@^2.1.6: wbuf "^1.1.0" html-entities@^2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.3.3.tgz#117d7626bece327fc8baace8868fa6f5ef856e46" - integrity sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA== + version "2.5.2" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.5.2.tgz#201a3cf95d3a15be7099521620d19dfb4f65359f" + integrity sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA== http-deceiver@^1.2.7: version "1.2.7" @@ -2329,16 +1809,6 @@ iconv-lite@^0.6.3: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" -idb@7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/idb/-/idb-7.0.1.tgz#d2875b3a2f205d854ee307f6d196f246fea590a7" - integrity sha512-UUxlE7vGWK5RfB/fDwEGgRf84DY/ieqNha6msMV99UsEMQhJ1RwbCd8AYBj3QMgnE3VZnfQvm4oKVCJTYlqIgg== - -immediate@~3.0.5: - version "3.0.6" - resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" - integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== - import-fresh@^3.2.1: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" @@ -2384,9 +1854,9 @@ ipaddr.js@1.9.1: integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== ipaddr.js@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.0.1.tgz#eca256a7a877e917aeb368b0a7497ddf42ef81c0" - integrity sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng== + version "2.2.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.2.0.tgz#d33fa7bac284f4de7af949638c9d68157c6b92e8" + integrity sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA== is-arrayish@^0.2.1: version "0.2.1" @@ -2407,13 +1877,6 @@ is-core-module@^2.13.0: dependencies: hasown "^2.0.0" -is-core-module@^2.9.0: - version "2.10.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.10.0.tgz#9012ede0a91c69587e647514e1d5277019e728ed" - integrity sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg== - dependencies: - has "^1.0.3" - is-docker@^2.0.0, is-docker@^2.1.1: version "2.2.1" resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" @@ -2538,16 +2001,6 @@ jsonfile@^4.0.0: optionalDependencies: graceful-fs "^4.1.6" -jszip@^3.6.0: - version "3.10.1" - resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.10.1.tgz#34aee70eb18ea1faec2f589208a157d1feb091c2" - integrity sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g== - dependencies: - lie "~3.3.0" - pako "~1.0.2" - readable-stream "~2.3.6" - setimmediate "^1.0.5" - karma-chrome-launcher@3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/karma-chrome-launcher/-/karma-chrome-launcher-3.2.0.tgz#eb9c95024f2d6dfbb3748d3415ac9b381906b9a9" @@ -2621,13 +2074,6 @@ launch-editor@^2.6.0: picocolors "^1.0.0" shell-quote "^1.8.1" -lie@~3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a" - integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ== - dependencies: - immediate "~3.0.5" - lines-and-columns@^1.1.6: version "1.2.4" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" @@ -2652,11 +2098,6 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" -lodash.camelcase@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" - integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== - lodash@^4.17.15, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" @@ -2681,16 +2122,6 @@ log4js@^6.4.1: rfdc "^1.3.0" streamroller "^3.1.2" -long@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" - integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== - -long@^5.0.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/long/-/long-5.2.0.tgz#2696dadf4b4da2ce3f6f6b89186085d94d52fd61" - integrity sha512-9RTUNjK60eJbx3uz+TEGF7fUr29ZDxR5QzXcyDpeSfeH28S9ycINflOgOlppit5U+4kNTe83KQnMEerw7GmE8w== - loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" @@ -2704,11 +2135,11 @@ media-typer@0.3.0: integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== memfs@^3.4.3: - version "3.4.7" - resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.4.7.tgz#e5252ad2242a724f938cb937e3c4f7ceb1f70e5a" - integrity sha512-ygaiUSNalBX85388uskeCyhSAoOSgzBbtVCr9jA2RROssFL9Q19/ZXFqS+2Th2sr1ewNIWgFdLzLC3Yl1Zv+lw== + version "3.6.0" + resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.6.0.tgz#d7a2110f86f79dd950a8b6df6d57bc984aa185f6" + integrity sha512-EGowvkkgbMcIChjMTMkESFDbZeSh8xZ7kNSF0hAiAN4Jh6jgHCRS0Ga/+C8y6Au+oqpezRHCfPsmJ2+DwAgiwQ== dependencies: - fs-monkey "^1.0.3" + fs-monkey "^1.0.4" merge-descriptors@1.0.1: version "1.0.1" @@ -2856,13 +2287,6 @@ neo-async@^2.6.2: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== -node-fetch@2.6.7: - version "2.6.7" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" - integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== - dependencies: - whatwg-url "^5.0.0" - node-forge@^1: version "1.3.1" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" @@ -2934,9 +2358,9 @@ onetime@^5.1.2: mimic-fn "^2.1.0" open@^8.0.9: - version "8.4.0" - resolved "https://registry.yarnpkg.com/open/-/open-8.4.0.tgz#345321ae18f8138f82565a910fdc6b39e8c244f8" - integrity sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q== + version "8.4.2" + resolved "https://registry.yarnpkg.com/open/-/open-8.4.2.tgz#5b5ffe2a8f793dcd2aad73e550cb87b59cb084f9" + integrity sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ== dependencies: define-lazy-prop "^2.0.0" is-docker "^2.1.1" @@ -2983,11 +2407,6 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== -pako@~1.0.2: - version "1.0.11" - resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" - integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== - parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -3062,12 +2481,7 @@ process-nextick-args@~2.0.0: resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== -promise-polyfill@8.1.3: - version "8.1.3" - resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-8.1.3.tgz#8c99b3cf53f3a91c68226ffde7bde81d7f904116" - integrity sha512-MG5r82wBzh7pSKDRa9y+vllNHz3e3d4CNj1PQE4BQYxLme0gKYYBm9YENq+UkEikyZ0XbiGWxYlVw3Rl9O/U8g== - -prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: +prop-types@^15.6.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -3076,44 +2490,6 @@ prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: object-assign "^4.1.1" react-is "^16.13.1" -protobufjs@^6.11.3: - version "6.11.3" - resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.11.3.tgz#637a527205a35caa4f3e2a9a4a13ddffe0e7af74" - integrity sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg== - dependencies: - "@protobufjs/aspromise" "^1.1.2" - "@protobufjs/base64" "^1.1.2" - "@protobufjs/codegen" "^2.0.4" - "@protobufjs/eventemitter" "^1.1.0" - "@protobufjs/fetch" "^1.1.0" - "@protobufjs/float" "^1.0.2" - "@protobufjs/inquire" "^1.1.0" - "@protobufjs/path" "^1.1.2" - "@protobufjs/pool" "^1.1.0" - "@protobufjs/utf8" "^1.1.0" - "@types/long" "^4.0.1" - "@types/node" ">=13.7.0" - long "^4.0.0" - -protobufjs@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.0.0.tgz#8c678e1351fd926178fce5a4213913e8d990974f" - integrity sha512-ffNIEm+quOcYtQvHdW406v1NQmZSuqVklxsXk076BtuFnlYZfigLU+JOMrTD8TUOyqHYbRI/fSVNvgd25YeN3w== - dependencies: - "@protobufjs/aspromise" "^1.1.2" - "@protobufjs/base64" "^1.1.2" - "@protobufjs/codegen" "^2.0.4" - "@protobufjs/eventemitter" "^1.1.0" - "@protobufjs/fetch" "^1.1.0" - "@protobufjs/float" "^1.0.2" - "@protobufjs/inquire" "^1.1.0" - "@protobufjs/path" "^1.1.2" - "@protobufjs/pool" "^1.1.0" - "@protobufjs/utf8" "^1.1.0" - "@types/long" "^4.0.1" - "@types/node" ">=13.7.0" - long "^5.0.0" - proxy-addr@~2.0.7: version "2.0.7" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" @@ -3139,6 +2515,13 @@ qs@6.10.3: dependencies: side-channel "^1.0.4" +qs@6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== + dependencies: + side-channel "^1.0.4" + randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" @@ -3161,7 +2544,17 @@ raw-body@2.5.1: iconv-lite "0.4.24" unpipe "1.0.0" -react-dom@^18.1.0: +raw-body@2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" + integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + +react-dom@^18.2.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d" integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== @@ -3179,7 +2572,7 @@ react-is@^18.2.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== -react-transition-group@^4.4.2, react-transition-group@^4.4.5: +react-transition-group@^4.4.5: version "4.4.5" resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1" integrity sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g== @@ -3189,17 +2582,17 @@ react-transition-group@^4.4.2, react-transition-group@^4.4.5: loose-envify "^1.4.0" prop-types "^15.6.2" -react@^18.1.0: +react@^18.2.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== dependencies: loose-envify "^1.1.0" -readable-stream@^2.0.1, readable-stream@~2.3.6: - version "2.3.7" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" - integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== +readable-stream@^2.0.1: + version "2.3.8" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== dependencies: core-util-is "~1.0.0" inherits "~2.0.3" @@ -3210,9 +2603,9 @@ readable-stream@^2.0.1, readable-stream@~2.3.6: util-deprecate "~1.0.1" readable-stream@^3.0.6: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" - integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== dependencies: inherits "^2.0.3" string_decoder "^1.1.1" @@ -3232,10 +2625,10 @@ rechoir@^0.8.0: dependencies: resolve "^1.20.0" -regenerator-runtime@^0.13.4: - version "0.13.9" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" - integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== +regenerator-runtime@^0.14.0: + version "0.14.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" + integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== require-directory@^2.1.1: version "2.1.1" @@ -3269,16 +2662,7 @@ resolve-from@^5.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== -resolve@^1.19.0: - version "1.22.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" - integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== - dependencies: - is-core-module "^2.9.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - -resolve@^1.20.0: +resolve@^1.19.0, resolve@^1.20.0: version "1.22.8" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== @@ -3297,11 +2681,6 @@ rfdc@^1.3.0: resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== -rifm@^0.12.1: - version "0.12.1" - resolved "https://registry.yarnpkg.com/rifm/-/rifm-0.12.1.tgz#8fa77f45b7f1cda2a0068787ac821f0593967ac4" - integrity sha512-OGA1Bitg/dSJtI/c4dh90svzaUPt228kzFsUkJbtA2c964IqEAwWXeL9ZJi86xWv3j5SMqRvGULl7bA6cK0Bvg== - rimraf@^3.0.0, rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" @@ -3350,14 +2729,14 @@ schema-utils@^3.1.2: ajv-keywords "^3.5.2" schema-utils@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.0.0.tgz#60331e9e3ae78ec5d16353c467c34b3a0a1d3df7" - integrity sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg== + version "4.2.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.2.0.tgz#70d7c93e153a273a805801882ebd3bff20d89c8b" + integrity sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw== dependencies: "@types/json-schema" "^7.0.9" - ajv "^8.8.0" + ajv "^8.9.0" ajv-formats "^2.1.1" - ajv-keywords "^5.0.0" + ajv-keywords "^5.1.0" sdp@^3.0.2: version "3.2.0" @@ -3369,15 +2748,6 @@ select-hose@^2.0.0: resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" integrity sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg== -selenium-webdriver@4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-4.1.2.tgz#d463b4335632d2ea41a9e988e435a55dc41f5314" - integrity sha512-e4Ap8vQvhipgBB8Ry9zBiKGkU6kHKyNnWiavGGLKkrdW81Zv7NVMtFOL/j3yX0G8QScM7XIXijKssNd4EUxSOw== - dependencies: - jszip "^3.6.0" - tmp "^0.2.1" - ws ">=7.4.6" - selfsigned@^2.1.1: version "2.4.1" resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-2.4.1.tgz#560d90565442a3ed35b674034cec4e95dceb4ae0" @@ -3442,11 +2812,6 @@ serve-static@1.15.0: parseurl "~1.3.3" send "0.18.0" -setimmediate@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== - setprototypeof@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" @@ -3644,10 +3009,10 @@ strip-json-comments@3.1.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -stylis@4.0.13: - version "4.0.13" - resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.0.13.tgz#f5db332e376d13cc84ecfe5dace9a2a51d954c91" - integrity sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag== +stylis@4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.2.0.tgz#79daee0208964c8fe695a42fcffcac633a211a51" + integrity sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw== supports-color@8.1.1, supports-color@^8.0.0: version "8.1.1" @@ -3730,16 +3095,6 @@ toidentifier@1.0.1: resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== -tr46@~0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" - integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== - -tslib@^2.1.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" - integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== - type-is@~1.6.18: version "1.6.18" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" @@ -3748,11 +3103,6 @@ type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" -typescript@3.9.5: - version "3.9.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.5.tgz#586f0dba300cde8be52dd1ac4f7e1009c1b13f36" - integrity sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ== - typescript@5.0.4: version "5.0.4" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.0.4.tgz#b217fd20119bd61a94d4011274e0ab369058da3b" @@ -3820,11 +3170,6 @@ wbuf@^1.1.0, wbuf@^1.7.3: dependencies: minimalistic-assert "^1.0.0" -webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" - integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== - webpack-cli@5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-5.1.0.tgz#abc4b1f44b50250f2632d8b8b536cfe2f6257891" @@ -3845,9 +3190,9 @@ webpack-cli@5.1.0: webpack-merge "^5.7.3" webpack-dev-middleware@^5.3.1: - version "5.3.3" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz#efae67c2793908e7311f1d9b06f2a08dcc97e51f" - integrity sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA== + version "5.3.4" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz#eb7b39281cbce10e104eb2b8bf2b63fce49a3517" + integrity sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q== dependencies: colorette "^2.0.10" memfs "^3.4.3" @@ -3962,19 +3307,6 @@ websocket-extensions@>=0.1.1: resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== -whatwg-fetch@2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f" - integrity sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng== - -whatwg-url@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" - integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== - dependencies: - tr46 "~0.0.3" - webidl-conversions "^3.0.0" - which@^1.2.1: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" @@ -4013,11 +3345,6 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -ws@>=7.4.6: - version "8.8.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.8.1.tgz#5dbad0feb7ade8ecc99b830c1d77c913d4955ff0" - integrity sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA== - ws@^8.13.0: version "8.16.0" resolved "https://registry.yarnpkg.com/ws/-/ws-8.16.0.tgz#d1cd774f36fbc07165066a60e40323eab6446fd4" @@ -4058,7 +3385,7 @@ yargs-unparser@2.0.0: flat "^5.0.2" is-plain-obj "^2.1.0" -yargs@16.2.0, yargs@^16.1.1, yargs@^16.2.0: +yargs@16.2.0, yargs@^16.1.1: version "16.2.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== diff --git a/libs.versions.toml b/libs.versions.toml deleted file mode 100644 index 805afb49..00000000 --- a/libs.versions.toml +++ /dev/null @@ -1,39 +0,0 @@ -[versions] - -kotlinCoroutines = "1.6.4" -kotlinWrappers = "1.0.0-pre.343" -androidxCompose = "1.4.3" -decompose = "1.0.0-alpha-01" - -[libraries] -webrtcSdk = "io.github.webrtc-sdk:android:114.5735.02" - -kotlin-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinCoroutines" } -kotlin-coroutinesPlayServices = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-play-services", version.ref = "kotlinCoroutines" } -kotlin-wrappers-bom = { module = "org.jetbrains.kotlin-wrappers:kotlin-wrappers-bom", version.ref = "kotlinWrappers" } -kotlin-wrappers-emotion = { module = "org.jetbrains.kotlin-wrappers:kotlin-emotion", version.ref = "kotlinWrappers" } -kotlin-wrappers-react = { module = "org.jetbrains.kotlin-wrappers:kotlin-react", version.ref = "kotlinWrappers" } -kotlin-wrappers-reactDom = { module = "org.jetbrains.kotlin-wrappers:kotlin-react-dom", version.ref = "kotlinWrappers" } -kotlin-wrappers-mui = { module = "org.jetbrains.kotlin-wrappers:kotlin-mui", version.ref = "kotlinWrappers" } -kotlin-serialization-json = "org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.3" - -androidx-coreKtx = "androidx.core:core-ktx:1.10.1" -androidx-appcompat = "androidx.appcompat:appcompat:1.6.1" -androidx-activity-activityKtx = "androidx.activity:activity-ktx:1.7.2" -androidx-compose-activity = "androidx.activity:activity-compose:1.7.2" -androidx-compose-material = { module = "androidx.compose.material:material", version.ref = "androidxCompose" } -androidx-compose-animation = { module = "androidx.compose.animation:animation", version.ref = "androidxCompose" } -androidx-lifecycle-runtime = "androidx.lifecycle:lifecycle-runtime-ktx:2.6.1" -androidx-test-core = "androidx.test:core:1.5.0" -androidx-test-runner = "androidx.test:runner:1.5.2" -androidx-test-rules = "androidx.test:rules:1.5.0" - -accompanist-permissions = "com.google.accompanist:accompanist-permissions:0.25.0" - -decompose = { module = "com.arkivanov.decompose:decompose", version.ref = "decompose" } -decompose-compose = { module = "com.arkivanov.decompose:extensions-compose-jetpack", version.ref = "decompose" } - -firebase-bom = "com.google.firebase:firebase-bom:32.2.0" -firebase-firestore = { module = "com.google.firebase:firebase-firestore-ktx" } - -kermit = "co.touchlab:kermit:1.1.2" diff --git a/sample/.gitignore b/sample/.gitignore new file mode 100644 index 00000000..b0505b38 --- /dev/null +++ b/sample/.gitignore @@ -0,0 +1,16 @@ +*.iml +.gradle +.idea +local.properties +.DS_Store +build/ +captures +xcuserdata +.externalNativeBuild +.cxx +*.xcodeproj/* +!*.xcodeproj/project.pbxproj +!*.xcodeproj/xcshareddata/ +!*.xcodeproj/project.xcworkspace/ +!*.xcworkspace/contents.xcworkspacedata +**/xcshareddata/WorkspaceSettings.xcsettings diff --git a/sample/README.md b/sample/README.md index 4517766c..d3cac238 100644 --- a/sample/README.md +++ b/sample/README.md @@ -19,10 +19,10 @@ Run Android emulator or connect real device. ### iOS -Open `sample/app-ios/app-ios.xcworkspace` in XCode build and run +Open `sample/iosApp/iosApp.xcodeproj` in XCode build and run ### Web ```bash -./gradlew browserRun +./gradlew jsBrowserRun ``` diff --git a/sample/app-android/build.gradle.kts b/sample/app-android/build.gradle.kts deleted file mode 100644 index 1b512f67..00000000 --- a/sample/app-android/build.gradle.kts +++ /dev/null @@ -1,59 +0,0 @@ -plugins { - id("com.android.application") - id("kotlin-android") - id("com.google.gms.google-services") - id("org.jlleitschuh.gradle.ktlint") -} - -android { - namespace = "com.shepeliev.webrtckmp.sample" - - compileSdk = AndroidConfig.compileSdkVersion - - defaultConfig { - minSdk = AndroidConfig.minSdkVersion - targetSdk = AndroidConfig.targetSdkVersion - versionCode = 1 - versionName = "1.0.0" - applicationId = "com.shepeliev.webrtckmp.sample" - } - - buildFeatures { - compose = true - } - - compileOptions { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 - } - - kotlinOptions { - jvmTarget = "17" - } - - composeOptions { - kotlinCompilerExtensionVersion = "1.4.8" - } -} - -tasks.withType() { - kotlinOptions { - freeCompilerArgs += listOf( - "-P", - "plugin:androidx.compose.compiler.plugins.kotlin:suppressKotlinVersionCompatibilityCheck=true" - ) - } -} - -dependencies { - implementation(project(":sample:shared")) - implementation(deps.androidx.coreKtx) - implementation(deps.androidx.appcompat) - implementation(deps.androidx.activity.activityKtx) - implementation(deps.androidx.compose.activity) - implementation(deps.androidx.compose.material) - implementation(deps.androidx.compose.animation) - implementation(deps.androidx.lifecycle.runtime) - implementation(deps.decompose.compose) - implementation(deps.accompanist.permissions) -} diff --git a/sample/app-android/google-services.json b/sample/app-android/google-services.json deleted file mode 100644 index b7563842..00000000 --- a/sample/app-android/google-services.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "project_info": { - "project_number": "216132728347", - "project_id": "app-rtc-kmp", - "storage_bucket": "app-rtc-kmp.appspot.com" - }, - "client": [ - { - "client_info": { - "mobilesdk_app_id": "1:216132728347:android:811fd8165c6b3b9f872abe", - "android_client_info": { - "package_name": "com.shepeliev.webrtckmp.sample" - } - }, - "oauth_client": [ - { - "client_id": "216132728347-mv1pltdn889q4vqnmuqs3tn02lcmqbbl.apps.googleusercontent.com", - "client_type": 3 - } - ], - "api_key": [ - { - "current_key": "AIzaSyCWRlpT3OPlT2C8H5rk0S-Xg7rsIRmSxdU" - } - ], - "services": { - "appinvite_service": { - "other_platform_oauth_client": [ - { - "client_id": "216132728347-mv1pltdn889q4vqnmuqs3tn02lcmqbbl.apps.googleusercontent.com", - "client_type": 3 - } - ] - } - } - } - ], - "configuration_version": "1" -} \ No newline at end of file diff --git a/sample/app-android/src/main/java/com/shepeliev/webrtckmp/sample/App.kt b/sample/app-android/src/main/java/com/shepeliev/webrtckmp/sample/App.kt deleted file mode 100644 index 0e6cd522..00000000 --- a/sample/app-android/src/main/java/com/shepeliev/webrtckmp/sample/App.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.shepeliev.webrtckmp.sample - -import androidx.compose.animation.Crossfade -import androidx.compose.material.Scaffold -import androidx.compose.material.Text -import androidx.compose.material.TopAppBar -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import com.arkivanov.decompose.extensions.compose.jetpack.subscribeAsState -import com.shepeliev.webrtckmp.sample.shared.Room - -@Composable -fun App(room: Room) { - Scaffold( - topBar = { - TopAppBar( - title = { Text("WebRTC KMP") } - ) - } - ) { - - val roomModel by room.model.subscribeAsState() - - Crossfade(targetState = roomModel) { model -> - when (model.localStream) { - null -> OpenMicrophoneAndCameraScreen(room) - else -> VideoScreen(room) - } - } - } -} diff --git a/sample/app-android/src/main/java/com/shepeliev/webrtckmp/sample/JoinRoomButton.kt b/sample/app-android/src/main/java/com/shepeliev/webrtckmp/sample/JoinRoomButton.kt deleted file mode 100644 index 39291502..00000000 --- a/sample/app-android/src/main/java/com/shepeliev/webrtckmp/sample/JoinRoomButton.kt +++ /dev/null @@ -1,57 +0,0 @@ -package com.shepeliev.webrtckmp.sample - -import androidx.compose.material.AlertDialog -import androidx.compose.material.Button -import androidx.compose.material.OutlinedTextField -import androidx.compose.material.Text -import androidx.compose.material.TextButton -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue - -@Composable -fun JoinRoomButton(onJoin: (String) -> Unit, enabled: Boolean) { - var isJoinDialogVisible by remember { mutableStateOf(false) } - - if (isJoinDialogVisible) { - var roomId by remember { mutableStateOf("") } - - AlertDialog( - onDismissRequest = { isJoinDialogVisible = false }, - - confirmButton = { - TextButton( - onClick = { - onJoin(roomId) - isJoinDialogVisible = false - }, - enabled = roomId.isNotBlank() - ) { - Text("Join") - } - }, - - dismissButton = { - TextButton(onClick = { isJoinDialogVisible = false }) { - Text("Cancel") - } - }, - - title = { Text("Join into room") }, - - text = { - OutlinedTextField( - value = roomId, - onValueChange = { roomId = it }, - placeholder = { Text("Room ID") } - ) - } - ) - } - - Button(onClick = { isJoinDialogVisible = true }, enabled = enabled) { - Text("Join") -} -} diff --git a/sample/app-android/src/main/java/com/shepeliev/webrtckmp/sample/MainActivity.kt b/sample/app-android/src/main/java/com/shepeliev/webrtckmp/sample/MainActivity.kt deleted file mode 100644 index d3ce5f24..00000000 --- a/sample/app-android/src/main/java/com/shepeliev/webrtckmp/sample/MainActivity.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.shepeliev.webrtckmp.sample - -import android.os.Bundle -import androidx.activity.compose.setContent -import androidx.appcompat.app.AppCompatActivity -import com.arkivanov.decompose.defaultComponentContext -import com.shepeliev.webrtckmp.sample.shared.RoomComponent - -class MainActivity : AppCompatActivity() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - val room = RoomComponent(componentContext = defaultComponentContext()) - setContent { App(room) } - } -} diff --git a/sample/app-android/src/main/java/com/shepeliev/webrtckmp/sample/OpenMicrophoneAndCameraScreen.kt b/sample/app-android/src/main/java/com/shepeliev/webrtckmp/sample/OpenMicrophoneAndCameraScreen.kt deleted file mode 100644 index ca29faab..00000000 --- a/sample/app-android/src/main/java/com/shepeliev/webrtckmp/sample/OpenMicrophoneAndCameraScreen.kt +++ /dev/null @@ -1,78 +0,0 @@ -package com.shepeliev.webrtckmp.sample - -import android.Manifest -import android.preference.PreferenceManager -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.material.AlertDialog -import androidx.compose.material.Button -import androidx.compose.material.Text -import androidx.compose.material.TextButton -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import androidx.core.content.edit -import com.google.accompanist.permissions.ExperimentalPermissionsApi -import com.google.accompanist.permissions.rememberMultiplePermissionsState -import com.shepeliev.webrtckmp.sample.shared.Room - -@Composable -fun OpenMicrophoneAndCameraScreen(room: Room) { - Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { - OpenCameraAndMicrophoneButton(onClick = room::openUserMedia) - } -} - -@OptIn(ExperimentalPermissionsApi::class) -@Composable -private fun OpenCameraAndMicrophoneButton(onClick: () -> Unit) { - val permissions = rememberMultiplePermissionsState( - listOf( - Manifest.permission.CAMERA, - Manifest.permission.RECORD_AUDIO, - ) - ) - - var isRationaleVisible by remember { mutableStateOf(false) } - - val context = LocalContext.current - val preferences = PreferenceManager.getDefaultSharedPreferences(context) - - if (isRationaleVisible) { - AlertDialog( - text = { Text("Please grant camera and microphone permissions") }, - onDismissRequest = { isRationaleVisible = false }, - confirmButton = { - TextButton(onClick = { - if (!permissions.shouldShowRationale && preferences.getBoolean("should_open_app_settings", false)) { - context.navigateToAppSettings() - } else { - permissions.launchMultiplePermissionRequest() - preferences.edit { putBoolean("should_open_app_settings", true) } - } - isRationaleVisible = false - }) { - Text("Grant permissions") - } - } - ) - } - - Button(onClick = { - when { - permissions.allPermissionsGranted -> { - preferences.edit { putBoolean("should_open_app_settings", false) } - onClick() - } - - else -> isRationaleVisible = true - } - }) { - Text("Open camera and microphone") - } -} diff --git a/sample/app-android/src/main/java/com/shepeliev/webrtckmp/sample/VideoScreen.kt b/sample/app-android/src/main/java/com/shepeliev/webrtckmp/sample/VideoScreen.kt deleted file mode 100644 index cde2256e..00000000 --- a/sample/app-android/src/main/java/com/shepeliev/webrtckmp/sample/VideoScreen.kt +++ /dev/null @@ -1,124 +0,0 @@ -package com.shepeliev.webrtckmp.sample - -import android.widget.Toast -import androidx.compose.animation.Crossfade -import androidx.compose.animation.core.animateFloatAsState -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.size -import androidx.compose.material.Button -import androidx.compose.material.CircularProgressIndicator -import androidx.compose.material.Icon -import androidx.compose.material.IconButton -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalClipboardManager -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.text.buildAnnotatedString -import androidx.compose.ui.unit.dp -import com.arkivanov.decompose.extensions.compose.jetpack.subscribeAsState -import com.shepeliev.webrtckmp.sample.shared.Room -import com.shepeliev.webrtckmp.videoTracks -import org.webrtc.RendererCommon - -@Composable -fun VideoScreen(room: Room) { - val roomModel by room.model.subscribeAsState() - Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.BottomCenter) { - Column(modifier = Modifier.fillMaxSize()) { - val remoteStream = roomModel.remoteStream - - val animatedWeight by animateFloatAsState( - targetValue = remoteStream?.let { 1f } ?: 0.01f - ) - - remoteStream?.let { - Video( - track = it.videoTracks.first(), - modifier = Modifier.weight(animatedWeight), - scalingTypeMatchOrientation = RendererCommon.ScalingType.SCALE_ASPECT_FILL, - scalingTypeMismatchOrientation = RendererCommon.ScalingType.SCALE_ASPECT_FILL, - ) - } - - roomModel.localStream?.let { - Video( - track = it.videoTracks.first(), - modifier = Modifier.weight(1f), - scalingTypeMatchOrientation = RendererCommon.ScalingType.SCALE_ASPECT_FILL, - scalingTypeMismatchOrientation = RendererCommon.ScalingType.SCALE_ASPECT_FILL, - ) - } - } - - Column(horizontalAlignment = Alignment.CenterHorizontally) { - - Crossfade(targetState = roomModel) { - when { - it.isJoining -> CircularProgressIndicator() - - it.roomId != null -> { - val roomId = roomModel.roomId - val context = LocalContext.current - val clipboardManager = LocalClipboardManager.current - - Row( - horizontalArrangement = Arrangement.Center, - verticalAlignment = Alignment.CenterVertically - ) { - Text(text = "Room ID: $roomId", color = Color.White) - - IconButton(onClick = { - val text = buildAnnotatedString { append(roomId!!) } - clipboardManager.setText(text) - Toast.makeText(context, "Room ID is copied.", Toast.LENGTH_SHORT) - .show() - }) { - Icon( - painter = painterResource(id = R.drawable.ic_content_copy), - contentDescription = "Copy room ID", - modifier = Modifier.size(24.dp), - tint = Color.White, - ) - } - } - } - } - } - - Column( - modifier = Modifier.fillMaxWidth(), - horizontalAlignment = Alignment.CenterHorizontally, - ) { - Button(onClick = room::switchCamera) { - Text("Switch camera") - } - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceEvenly - ) { - if (roomModel.roomId == null) { - Button(onClick = room::createRoom, enabled = !roomModel.isJoining) { - Text("Create") - } - - JoinRoomButton(onJoin = room::joinRoom, enabled = !roomModel.isJoining) - } - - Button(onClick = room::hangup) { - Text("Hangup") - } - } - } - } - } -} diff --git a/sample/app-android/src/main/java/com/shepeliev/webrtckmp/sample/navigateToAppSettings.kt b/sample/app-android/src/main/java/com/shepeliev/webrtckmp/sample/navigateToAppSettings.kt deleted file mode 100644 index d11867f8..00000000 --- a/sample/app-android/src/main/java/com/shepeliev/webrtckmp/sample/navigateToAppSettings.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.shepeliev.webrtckmp.sample - -import android.content.Context -import android.content.Intent -import android.net.Uri -import android.provider.Settings - -fun Context.navigateToAppSettings() { - val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { - data = Uri.fromParts("package", packageName, null) - addCategory(Intent.CATEGORY_DEFAULT) - addFlags( - Intent.FLAG_ACTIVITY_NEW_TASK or - Intent.FLAG_ACTIVITY_NO_HISTORY or - Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS - ) - } - startActivity(intent) -} diff --git a/sample/app-android/src/main/res/drawable/ic_content_copy.xml b/sample/app-android/src/main/res/drawable/ic_content_copy.xml deleted file mode 100644 index cda8345f..00000000 --- a/sample/app-android/src/main/res/drawable/ic_content_copy.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/sample/app-android/src/main/res/drawable/ic_launcher.xml b/sample/app-android/src/main/res/drawable/ic_launcher.xml deleted file mode 100644 index d974bafb..00000000 --- a/sample/app-android/src/main/res/drawable/ic_launcher.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - diff --git a/sample/app-android/src/main/res/values/strings.xml b/sample/app-android/src/main/res/values/strings.xml deleted file mode 100644 index 9598352e..00000000 --- a/sample/app-android/src/main/res/values/strings.xml +++ /dev/null @@ -1,3 +0,0 @@ - - WebRTC KMP Sample - diff --git a/sample/app-ios/.gitignore b/sample/app-ios/.gitignore deleted file mode 100644 index 7e6b5400..00000000 --- a/sample/app-ios/.gitignore +++ /dev/null @@ -1,221 +0,0 @@ -# Created by https://www.toptal.com/developers/gitignore/api/swift,xcode,C,objective-c,osx -# Edit at https://www.toptal.com/developers/gitignore?templates=swift,xcode,C,objective-c,osx - -### C ### -# Prerequisites -*.d - -# Object files -*.o -*.ko -*.obj -*.elf - -# Linker output -*.ilk -*.map -*.exp - -# Precompiled Headers -*.gch -*.pch - -# Libraries -*.lib -*.a -*.la -*.lo - -# Shared objects (inc. Windows DLLs) -*.dll -*.so -*.so.* -*.dylib - -# Executables -*.exe -*.out -*.app -*.i*86 -*.x86_64 -*.hex - -# Debug files -*.dSYM/ -*.su -*.idb -*.pdb - -# Kernel Module Compile Results -*.mod* -*.cmd -.tmp_versions/ -modules.order -Module.symvers -Mkfile.old -dkms.conf - -### Objective-C ### -# Xcode -# -# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore - -## User settings -xcuserdata/ - -## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) -*.xcscmblueprint -*.xccheckout - -## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) -build/ -DerivedData/ -*.moved-aside -*.pbxuser -!default.pbxuser -*.mode1v3 -!default.mode1v3 -*.mode2v3 -!default.mode2v3 -*.perspectivev3 -!default.perspectivev3 - -## Obj-C/Swift specific -*.hmap - -## App packaging -*.ipa -*.dSYM.zip -*.dSYM - -# CocoaPods -# We recommend against adding the Pods directory to your .gitignore. However -# you should judge for yourself, the pros and cons are mentioned at: -# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control -# Pods/ -# Add this line if you want to avoid checking in source code from the Xcode workspace -# *.xcworkspace - -# Carthage -# Add this line if you want to avoid checking in source code from Carthage dependencies. -# Carthage/Checkouts - -Carthage/Build/ - -# fastlane -# It is recommended to not store the screenshots in the git repo. -# Instead, use fastlane to re-generate the screenshots whenever they are needed. -# For more information about the recommended setup visit: -# https://docs.fastlane.tools/best-practices/source-control/#source-control - -fastlane/report.xml -fastlane/Preview.html -fastlane/screenshots/**/*.png -fastlane/test_output - -# Code Injection -# After new code Injection tools there's a generated folder /iOSInjectionProject -# https://github.com/johnno1962/injectionforxcode - -iOSInjectionProject/ - -### Objective-C Patch ### - -### OSX ### -# General -.DS_Store -.AppleDouble -.LSOverride - -# Icon must end with two \r -Icon - - -# Thumbnails -._* - -# Files that might appear in the root of a volume -.DocumentRevisions-V100 -.fseventsd -.Spotlight-V100 -.TemporaryItems -.Trashes -.VolumeIcon.icns -.com.apple.timemachine.donotpresent - -# Directories potentially created on remote AFP share -.AppleDB -.AppleDesktop -Network Trash Folder -Temporary Items -.apdisk - -### Swift ### -# Xcode -# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore - - - - - - -## Playgrounds -timeline.xctimeline -playground.xcworkspace - -# Swift Package Manager -# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. -# Packages/ -# Package.pins -# Package.resolved -# *.xcodeproj -# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata -# hence it is not needed unless you have added a package configuration file to your project -# .swiftpm - -.build/ - -# CocoaPods -# We recommend against adding the Pods directory to your .gitignore. However -# you should judge for yourself, the pros and cons are mentioned at: -# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control -# Pods/ -# Add this line if you want to avoid checking in source code from the Xcode workspace -# *.xcworkspace - -# Carthage -# Add this line if you want to avoid checking in source code from Carthage dependencies. -# Carthage/Checkouts - - -# Accio dependency management -Dependencies/ -.accio/ - -# fastlane -# It is recommended to not store the screenshots in the git repo. -# Instead, use fastlane to re-generate the screenshots whenever they are needed. -# For more information about the recommended setup visit: -# https://docs.fastlane.tools/best-practices/source-control/#source-control - - -# Code Injection -# After new code Injection tools there's a generated folder /iOSInjectionProject -# https://github.com/johnno1962/injectionforxcode - - -### Xcode ### - -## Xcode 8 and earlier - -### Xcode Patch ### -*.xcodeproj/* -!*.xcodeproj/project.pbxproj -!*.xcodeproj/xcshareddata/ -!*.xcworkspace/contents.xcworkspacedata -/*.gcno -**/xcshareddata/WorkspaceSettings.xcsettings - -# End of https://www.toptal.com/developers/gitignore/api/swift,xcode,C,objective-c,osx - -Pods/ diff --git a/sample/app-ios/Podfile b/sample/app-ios/Podfile deleted file mode 100644 index 223b4909..00000000 --- a/sample/app-ios/Podfile +++ /dev/null @@ -1,6 +0,0 @@ -platform :ios, '11.0' - -target 'app-ios' do - use_frameworks! - pod 'shared', :path => '../shared' -end diff --git a/sample/app-ios/Podfile.lock b/sample/app-ios/Podfile.lock deleted file mode 100644 index 21fbfc8b..00000000 --- a/sample/app-ios/Podfile.lock +++ /dev/null @@ -1,774 +0,0 @@ -PODS: - - abseil/algorithm (1.20220623.0): - - abseil/algorithm/algorithm (= 1.20220623.0) - - abseil/algorithm/container (= 1.20220623.0) - - abseil/algorithm/algorithm (1.20220623.0): - - abseil/base/config - - abseil/algorithm/container (1.20220623.0): - - abseil/algorithm/algorithm - - abseil/base/core_headers - - abseil/meta/type_traits - - abseil/base (1.20220623.0): - - abseil/base/atomic_hook (= 1.20220623.0) - - abseil/base/base (= 1.20220623.0) - - abseil/base/base_internal (= 1.20220623.0) - - abseil/base/config (= 1.20220623.0) - - abseil/base/core_headers (= 1.20220623.0) - - abseil/base/dynamic_annotations (= 1.20220623.0) - - abseil/base/endian (= 1.20220623.0) - - abseil/base/errno_saver (= 1.20220623.0) - - abseil/base/fast_type_id (= 1.20220623.0) - - abseil/base/log_severity (= 1.20220623.0) - - abseil/base/malloc_internal (= 1.20220623.0) - - abseil/base/prefetch (= 1.20220623.0) - - abseil/base/pretty_function (= 1.20220623.0) - - abseil/base/raw_logging_internal (= 1.20220623.0) - - abseil/base/spinlock_wait (= 1.20220623.0) - - abseil/base/strerror (= 1.20220623.0) - - abseil/base/throw_delegate (= 1.20220623.0) - - abseil/base/atomic_hook (1.20220623.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/base (1.20220623.0): - - abseil/base/atomic_hook - - abseil/base/base_internal - - abseil/base/config - - abseil/base/core_headers - - abseil/base/dynamic_annotations - - abseil/base/log_severity - - abseil/base/raw_logging_internal - - abseil/base/spinlock_wait - - abseil/meta/type_traits - - abseil/base/base_internal (1.20220623.0): - - abseil/base/config - - abseil/meta/type_traits - - abseil/base/config (1.20220623.0) - - abseil/base/core_headers (1.20220623.0): - - abseil/base/config - - abseil/base/dynamic_annotations (1.20220623.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/endian (1.20220623.0): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/errno_saver (1.20220623.0): - - abseil/base/config - - abseil/base/fast_type_id (1.20220623.0): - - abseil/base/config - - abseil/base/log_severity (1.20220623.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/malloc_internal (1.20220623.0): - - abseil/base/base - - abseil/base/base_internal - - abseil/base/config - - abseil/base/core_headers - - abseil/base/dynamic_annotations - - abseil/base/raw_logging_internal - - abseil/base/prefetch (1.20220623.0): - - abseil/base/config - - abseil/base/pretty_function (1.20220623.0) - - abseil/base/raw_logging_internal (1.20220623.0): - - abseil/base/atomic_hook - - abseil/base/config - - abseil/base/core_headers - - abseil/base/errno_saver - - abseil/base/log_severity - - abseil/base/spinlock_wait (1.20220623.0): - - abseil/base/base_internal - - abseil/base/core_headers - - abseil/base/errno_saver - - abseil/base/strerror (1.20220623.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/errno_saver - - abseil/base/throw_delegate (1.20220623.0): - - abseil/base/config - - abseil/base/raw_logging_internal - - abseil/cleanup/cleanup (1.20220623.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/cleanup/cleanup_internal - - abseil/cleanup/cleanup_internal (1.20220623.0): - - abseil/base/base_internal - - abseil/base/core_headers - - abseil/utility/utility - - abseil/container/common (1.20220623.0): - - abseil/meta/type_traits - - abseil/types/optional - - abseil/container/compressed_tuple (1.20220623.0): - - abseil/utility/utility - - abseil/container/container_memory (1.20220623.0): - - abseil/base/config - - abseil/memory/memory - - abseil/meta/type_traits - - abseil/utility/utility - - abseil/container/fixed_array (1.20220623.0): - - abseil/algorithm/algorithm - - abseil/base/config - - abseil/base/core_headers - - abseil/base/dynamic_annotations - - abseil/base/throw_delegate - - abseil/container/compressed_tuple - - abseil/memory/memory - - abseil/container/flat_hash_map (1.20220623.0): - - abseil/algorithm/container - - abseil/base/core_headers - - abseil/container/container_memory - - abseil/container/hash_function_defaults - - abseil/container/raw_hash_map - - abseil/memory/memory - - abseil/container/flat_hash_set (1.20220623.0): - - abseil/algorithm/container - - abseil/base/core_headers - - abseil/container/container_memory - - abseil/container/hash_function_defaults - - abseil/container/raw_hash_set - - abseil/memory/memory - - abseil/container/hash_function_defaults (1.20220623.0): - - abseil/base/config - - abseil/hash/hash - - abseil/strings/cord - - abseil/strings/strings - - abseil/container/hash_policy_traits (1.20220623.0): - - abseil/meta/type_traits - - abseil/container/hashtable_debug_hooks (1.20220623.0): - - abseil/base/config - - abseil/container/hashtablez_sampler (1.20220623.0): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/debugging/stacktrace - - abseil/memory/memory - - abseil/profiling/exponential_biased - - abseil/profiling/sample_recorder - - abseil/synchronization/synchronization - - abseil/utility/utility - - abseil/container/inlined_vector (1.20220623.0): - - abseil/algorithm/algorithm - - abseil/base/core_headers - - abseil/base/throw_delegate - - abseil/container/inlined_vector_internal - - abseil/memory/memory - - abseil/container/inlined_vector_internal (1.20220623.0): - - abseil/base/core_headers - - abseil/container/compressed_tuple - - abseil/memory/memory - - abseil/meta/type_traits - - abseil/types/span - - abseil/container/layout (1.20220623.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/meta/type_traits - - abseil/strings/strings - - abseil/types/span - - abseil/utility/utility - - abseil/container/raw_hash_map (1.20220623.0): - - abseil/base/throw_delegate - - abseil/container/container_memory - - abseil/container/raw_hash_set - - abseil/container/raw_hash_set (1.20220623.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/endian - - abseil/base/prefetch - - abseil/container/common - - abseil/container/compressed_tuple - - abseil/container/container_memory - - abseil/container/hash_policy_traits - - abseil/container/hashtable_debug_hooks - - abseil/container/hashtablez_sampler - - abseil/memory/memory - - abseil/meta/type_traits - - abseil/numeric/bits - - abseil/utility/utility - - abseil/debugging/debugging_internal (1.20220623.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/dynamic_annotations - - abseil/base/errno_saver - - abseil/base/raw_logging_internal - - abseil/debugging/demangle_internal (1.20220623.0): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/debugging/stacktrace (1.20220623.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/debugging/debugging_internal - - abseil/debugging/symbolize (1.20220623.0): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/dynamic_annotations - - abseil/base/malloc_internal - - abseil/base/raw_logging_internal - - abseil/debugging/debugging_internal - - abseil/debugging/demangle_internal - - abseil/strings/strings - - abseil/functional/any_invocable (1.20220623.0): - - abseil/base/base_internal - - abseil/base/config - - abseil/base/core_headers - - abseil/meta/type_traits - - abseil/utility/utility - - abseil/functional/bind_front (1.20220623.0): - - abseil/base/base_internal - - abseil/container/compressed_tuple - - abseil/meta/type_traits - - abseil/utility/utility - - abseil/functional/function_ref (1.20220623.0): - - abseil/base/base_internal - - abseil/base/core_headers - - abseil/meta/type_traits - - abseil/hash/city (1.20220623.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/endian - - abseil/hash/hash (1.20220623.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/endian - - abseil/container/fixed_array - - abseil/functional/function_ref - - abseil/hash/city - - abseil/hash/low_level_hash - - abseil/meta/type_traits - - abseil/numeric/int128 - - abseil/strings/strings - - abseil/types/optional - - abseil/types/variant - - abseil/utility/utility - - abseil/hash/low_level_hash (1.20220623.0): - - abseil/base/config - - abseil/base/endian - - abseil/numeric/bits - - abseil/numeric/int128 - - abseil/memory (1.20220623.0): - - abseil/memory/memory (= 1.20220623.0) - - abseil/memory/memory (1.20220623.0): - - abseil/base/core_headers - - abseil/meta/type_traits - - abseil/meta (1.20220623.0): - - abseil/meta/type_traits (= 1.20220623.0) - - abseil/meta/type_traits (1.20220623.0): - - abseil/base/config - - abseil/numeric/bits (1.20220623.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/numeric/int128 (1.20220623.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/numeric/bits - - abseil/numeric/representation (1.20220623.0): - - abseil/base/config - - abseil/profiling/exponential_biased (1.20220623.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/profiling/sample_recorder (1.20220623.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/synchronization/synchronization - - abseil/time/time - - abseil/random/distributions (1.20220623.0): - - abseil/base/base_internal - - abseil/base/config - - abseil/base/core_headers - - abseil/meta/type_traits - - abseil/numeric/bits - - abseil/random/internal/distribution_caller - - abseil/random/internal/fast_uniform_bits - - abseil/random/internal/fastmath - - abseil/random/internal/generate_real - - abseil/random/internal/iostream_state_saver - - abseil/random/internal/traits - - abseil/random/internal/uniform_helper - - abseil/random/internal/wide_multiply - - abseil/strings/strings - - abseil/random/internal/distribution_caller (1.20220623.0): - - abseil/base/config - - abseil/base/fast_type_id - - abseil/utility/utility - - abseil/random/internal/fast_uniform_bits (1.20220623.0): - - abseil/base/config - - abseil/meta/type_traits - - abseil/random/internal/traits - - abseil/random/internal/fastmath (1.20220623.0): - - abseil/numeric/bits - - abseil/random/internal/generate_real (1.20220623.0): - - abseil/meta/type_traits - - abseil/numeric/bits - - abseil/random/internal/fastmath - - abseil/random/internal/traits - - abseil/random/internal/iostream_state_saver (1.20220623.0): - - abseil/meta/type_traits - - abseil/numeric/int128 - - abseil/random/internal/nonsecure_base (1.20220623.0): - - abseil/base/core_headers - - abseil/container/inlined_vector - - abseil/meta/type_traits - - abseil/random/internal/pool_urbg - - abseil/random/internal/salted_seed_seq - - abseil/random/internal/seed_material - - abseil/types/span - - abseil/random/internal/pcg_engine (1.20220623.0): - - abseil/base/config - - abseil/meta/type_traits - - abseil/numeric/bits - - abseil/numeric/int128 - - abseil/random/internal/fastmath - - abseil/random/internal/iostream_state_saver - - abseil/random/internal/platform (1.20220623.0): - - abseil/base/config - - abseil/random/internal/pool_urbg (1.20220623.0): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/endian - - abseil/base/raw_logging_internal - - abseil/random/internal/randen - - abseil/random/internal/seed_material - - abseil/random/internal/traits - - abseil/random/seed_gen_exception - - abseil/types/span - - abseil/random/internal/randen (1.20220623.0): - - abseil/base/raw_logging_internal - - abseil/random/internal/platform - - abseil/random/internal/randen_hwaes - - abseil/random/internal/randen_slow - - abseil/random/internal/randen_engine (1.20220623.0): - - abseil/base/endian - - abseil/meta/type_traits - - abseil/random/internal/iostream_state_saver - - abseil/random/internal/randen - - abseil/random/internal/randen_hwaes (1.20220623.0): - - abseil/base/config - - abseil/random/internal/platform - - abseil/random/internal/randen_hwaes_impl - - abseil/random/internal/randen_hwaes_impl (1.20220623.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/numeric/int128 - - abseil/random/internal/platform - - abseil/random/internal/randen_slow (1.20220623.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/endian - - abseil/numeric/int128 - - abseil/random/internal/platform - - abseil/random/internal/salted_seed_seq (1.20220623.0): - - abseil/container/inlined_vector - - abseil/meta/type_traits - - abseil/random/internal/seed_material - - abseil/types/optional - - abseil/types/span - - abseil/random/internal/seed_material (1.20220623.0): - - abseil/base/core_headers - - abseil/base/dynamic_annotations - - abseil/base/raw_logging_internal - - abseil/random/internal/fast_uniform_bits - - abseil/strings/strings - - abseil/types/optional - - abseil/types/span - - abseil/random/internal/traits (1.20220623.0): - - abseil/base/config - - abseil/numeric/bits - - abseil/numeric/int128 - - abseil/random/internal/uniform_helper (1.20220623.0): - - abseil/base/config - - abseil/meta/type_traits - - abseil/numeric/int128 - - abseil/random/internal/traits - - abseil/random/internal/wide_multiply (1.20220623.0): - - abseil/base/config - - abseil/numeric/bits - - abseil/numeric/int128 - - abseil/random/internal/traits - - abseil/random/random (1.20220623.0): - - abseil/random/distributions - - abseil/random/internal/nonsecure_base - - abseil/random/internal/pcg_engine - - abseil/random/internal/pool_urbg - - abseil/random/internal/randen_engine - - abseil/random/seed_sequences - - abseil/random/seed_gen_exception (1.20220623.0): - - abseil/base/config - - abseil/random/seed_sequences (1.20220623.0): - - abseil/base/config - - abseil/random/internal/pool_urbg - - abseil/random/internal/salted_seed_seq - - abseil/random/internal/seed_material - - abseil/random/seed_gen_exception - - abseil/types/span - - abseil/status/status (1.20220623.0): - - abseil/base/atomic_hook - - abseil/base/core_headers - - abseil/base/raw_logging_internal - - abseil/base/strerror - - abseil/container/inlined_vector - - abseil/debugging/stacktrace - - abseil/debugging/symbolize - - abseil/functional/function_ref - - abseil/strings/cord - - abseil/strings/str_format - - abseil/strings/strings - - abseil/types/optional - - abseil/status/statusor (1.20220623.0): - - abseil/base/base - - abseil/base/core_headers - - abseil/base/raw_logging_internal - - abseil/meta/type_traits - - abseil/status/status - - abseil/strings/strings - - abseil/types/variant - - abseil/utility/utility - - abseil/strings/cord (1.20220623.0): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/endian - - abseil/base/raw_logging_internal - - abseil/container/fixed_array - - abseil/container/inlined_vector - - abseil/functional/function_ref - - abseil/meta/type_traits - - abseil/numeric/bits - - abseil/strings/cord_internal - - abseil/strings/cordz_functions - - abseil/strings/cordz_info - - abseil/strings/cordz_statistics - - abseil/strings/cordz_update_scope - - abseil/strings/cordz_update_tracker - - abseil/strings/internal - - abseil/strings/str_format - - abseil/strings/strings - - abseil/types/optional - - abseil/types/span - - abseil/strings/cord_internal (1.20220623.0): - - abseil/base/base_internal - - abseil/base/config - - abseil/base/core_headers - - abseil/base/endian - - abseil/base/raw_logging_internal - - abseil/base/throw_delegate - - abseil/container/compressed_tuple - - abseil/container/inlined_vector - - abseil/container/layout - - abseil/functional/function_ref - - abseil/meta/type_traits - - abseil/strings/strings - - abseil/types/span - - abseil/strings/cordz_functions (1.20220623.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/raw_logging_internal - - abseil/profiling/exponential_biased - - abseil/strings/cordz_handle (1.20220623.0): - - abseil/base/base - - abseil/base/config - - abseil/base/raw_logging_internal - - abseil/synchronization/synchronization - - abseil/strings/cordz_info (1.20220623.0): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/raw_logging_internal - - abseil/container/inlined_vector - - abseil/debugging/stacktrace - - abseil/strings/cord_internal - - abseil/strings/cordz_functions - - abseil/strings/cordz_handle - - abseil/strings/cordz_statistics - - abseil/strings/cordz_update_tracker - - abseil/synchronization/synchronization - - abseil/types/span - - abseil/strings/cordz_statistics (1.20220623.0): - - abseil/base/config - - abseil/strings/cordz_update_tracker - - abseil/strings/cordz_update_scope (1.20220623.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/strings/cord_internal - - abseil/strings/cordz_info - - abseil/strings/cordz_update_tracker - - abseil/strings/cordz_update_tracker (1.20220623.0): - - abseil/base/config - - abseil/strings/internal (1.20220623.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/endian - - abseil/base/raw_logging_internal - - abseil/meta/type_traits - - abseil/strings/str_format (1.20220623.0): - - abseil/strings/str_format_internal - - abseil/strings/str_format_internal (1.20220623.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/functional/function_ref - - abseil/meta/type_traits - - abseil/numeric/bits - - abseil/numeric/int128 - - abseil/numeric/representation - - abseil/strings/strings - - abseil/types/optional - - abseil/types/span - - abseil/utility/utility - - abseil/strings/strings (1.20220623.0): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/endian - - abseil/base/raw_logging_internal - - abseil/base/throw_delegate - - abseil/memory/memory - - abseil/meta/type_traits - - abseil/numeric/bits - - abseil/numeric/int128 - - abseil/strings/internal - - abseil/synchronization/graphcycles_internal (1.20220623.0): - - abseil/base/base - - abseil/base/base_internal - - abseil/base/config - - abseil/base/core_headers - - abseil/base/malloc_internal - - abseil/base/raw_logging_internal - - abseil/synchronization/kernel_timeout_internal (1.20220623.0): - - abseil/base/core_headers - - abseil/base/raw_logging_internal - - abseil/time/time - - abseil/synchronization/synchronization (1.20220623.0): - - abseil/base/atomic_hook - - abseil/base/base - - abseil/base/base_internal - - abseil/base/config - - abseil/base/core_headers - - abseil/base/dynamic_annotations - - abseil/base/malloc_internal - - abseil/base/raw_logging_internal - - abseil/debugging/stacktrace - - abseil/debugging/symbolize - - abseil/synchronization/graphcycles_internal - - abseil/synchronization/kernel_timeout_internal - - abseil/time/time - - abseil/time (1.20220623.0): - - abseil/time/internal (= 1.20220623.0) - - abseil/time/time (= 1.20220623.0) - - abseil/time/internal (1.20220623.0): - - abseil/time/internal/cctz (= 1.20220623.0) - - abseil/time/internal/cctz (1.20220623.0): - - abseil/time/internal/cctz/civil_time (= 1.20220623.0) - - abseil/time/internal/cctz/time_zone (= 1.20220623.0) - - abseil/time/internal/cctz/civil_time (1.20220623.0): - - abseil/base/config - - abseil/time/internal/cctz/time_zone (1.20220623.0): - - abseil/base/config - - abseil/time/internal/cctz/civil_time - - abseil/time/time (1.20220623.0): - - abseil/base/base - - abseil/base/core_headers - - abseil/base/raw_logging_internal - - abseil/numeric/int128 - - abseil/strings/strings - - abseil/time/internal/cctz/civil_time - - abseil/time/internal/cctz/time_zone - - abseil/types (1.20220623.0): - - abseil/types/any (= 1.20220623.0) - - abseil/types/bad_any_cast (= 1.20220623.0) - - abseil/types/bad_any_cast_impl (= 1.20220623.0) - - abseil/types/bad_optional_access (= 1.20220623.0) - - abseil/types/bad_variant_access (= 1.20220623.0) - - abseil/types/compare (= 1.20220623.0) - - abseil/types/optional (= 1.20220623.0) - - abseil/types/span (= 1.20220623.0) - - abseil/types/variant (= 1.20220623.0) - - abseil/types/any (1.20220623.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/fast_type_id - - abseil/meta/type_traits - - abseil/types/bad_any_cast - - abseil/utility/utility - - abseil/types/bad_any_cast (1.20220623.0): - - abseil/base/config - - abseil/types/bad_any_cast_impl - - abseil/types/bad_any_cast_impl (1.20220623.0): - - abseil/base/config - - abseil/base/raw_logging_internal - - abseil/types/bad_optional_access (1.20220623.0): - - abseil/base/config - - abseil/base/raw_logging_internal - - abseil/types/bad_variant_access (1.20220623.0): - - abseil/base/config - - abseil/base/raw_logging_internal - - abseil/types/compare (1.20220623.0): - - abseil/base/core_headers - - abseil/meta/type_traits - - abseil/types/optional (1.20220623.0): - - abseil/base/base_internal - - abseil/base/config - - abseil/base/core_headers - - abseil/memory/memory - - abseil/meta/type_traits - - abseil/types/bad_optional_access - - abseil/utility/utility - - abseil/types/span (1.20220623.0): - - abseil/algorithm/algorithm - - abseil/base/core_headers - - abseil/base/throw_delegate - - abseil/meta/type_traits - - abseil/types/variant (1.20220623.0): - - abseil/base/base_internal - - abseil/base/config - - abseil/base/core_headers - - abseil/meta/type_traits - - abseil/types/bad_variant_access - - abseil/utility/utility - - abseil/utility/utility (1.20220623.0): - - abseil/base/base_internal - - abseil/base/config - - abseil/meta/type_traits - - BoringSSL-GRPC (0.0.24): - - BoringSSL-GRPC/Implementation (= 0.0.24) - - BoringSSL-GRPC/Interface (= 0.0.24) - - BoringSSL-GRPC/Implementation (0.0.24): - - BoringSSL-GRPC/Interface (= 0.0.24) - - BoringSSL-GRPC/Interface (0.0.24) - - FirebaseCore (10.11.0): - - FirebaseCoreInternal (~> 10.0) - - GoogleUtilities/Environment (~> 7.8) - - GoogleUtilities/Logger (~> 7.8) - - FirebaseCoreInternal (10.11.0): - - "GoogleUtilities/NSData+zlib (~> 7.8)" - - FirebaseFirestore (10.11.0): - - abseil/algorithm (~> 1.20220623.0) - - abseil/base (~> 1.20220623.0) - - abseil/container/flat_hash_map (~> 1.20220623.0) - - abseil/memory (~> 1.20220623.0) - - abseil/meta (~> 1.20220623.0) - - abseil/strings/strings (~> 1.20220623.0) - - abseil/time (~> 1.20220623.0) - - abseil/types (~> 1.20220623.0) - - FirebaseCore (~> 10.0) - - "gRPC-C++ (~> 1.50.1)" - - leveldb-library (~> 1.22) - - nanopb (< 2.30910.0, >= 2.30908.0) - - GoogleUtilities/Environment (7.11.1): - - PromisesObjC (< 3.0, >= 1.2) - - GoogleUtilities/Logger (7.11.1): - - GoogleUtilities/Environment - - "GoogleUtilities/NSData+zlib (7.11.1)" - - "gRPC-C++ (1.50.1)": - - "gRPC-C++/Implementation (= 1.50.1)" - - "gRPC-C++/Interface (= 1.50.1)" - - "gRPC-C++/Implementation (1.50.1)": - - abseil/base/base (= 1.20220623.0) - - abseil/base/core_headers (= 1.20220623.0) - - abseil/cleanup/cleanup (= 1.20220623.0) - - abseil/container/flat_hash_map (= 1.20220623.0) - - abseil/container/flat_hash_set (= 1.20220623.0) - - abseil/container/inlined_vector (= 1.20220623.0) - - abseil/functional/any_invocable (= 1.20220623.0) - - abseil/functional/bind_front (= 1.20220623.0) - - abseil/functional/function_ref (= 1.20220623.0) - - abseil/hash/hash (= 1.20220623.0) - - abseil/memory/memory (= 1.20220623.0) - - abseil/meta/type_traits (= 1.20220623.0) - - abseil/random/random (= 1.20220623.0) - - abseil/status/status (= 1.20220623.0) - - abseil/status/statusor (= 1.20220623.0) - - abseil/strings/cord (= 1.20220623.0) - - abseil/strings/str_format (= 1.20220623.0) - - abseil/strings/strings (= 1.20220623.0) - - abseil/synchronization/synchronization (= 1.20220623.0) - - abseil/time/time (= 1.20220623.0) - - abseil/types/optional (= 1.20220623.0) - - abseil/types/span (= 1.20220623.0) - - abseil/types/variant (= 1.20220623.0) - - abseil/utility/utility (= 1.20220623.0) - - "gRPC-C++/Interface (= 1.50.1)" - - gRPC-Core (= 1.50.1) - - "gRPC-C++/Interface (1.50.1)" - - gRPC-Core (1.50.1): - - gRPC-Core/Implementation (= 1.50.1) - - gRPC-Core/Interface (= 1.50.1) - - gRPC-Core/Implementation (1.50.1): - - abseil/base/base (= 1.20220623.0) - - abseil/base/core_headers (= 1.20220623.0) - - abseil/container/flat_hash_map (= 1.20220623.0) - - abseil/container/flat_hash_set (= 1.20220623.0) - - abseil/container/inlined_vector (= 1.20220623.0) - - abseil/functional/any_invocable (= 1.20220623.0) - - abseil/functional/bind_front (= 1.20220623.0) - - abseil/functional/function_ref (= 1.20220623.0) - - abseil/hash/hash (= 1.20220623.0) - - abseil/memory/memory (= 1.20220623.0) - - abseil/meta/type_traits (= 1.20220623.0) - - abseil/random/random (= 1.20220623.0) - - abseil/status/status (= 1.20220623.0) - - abseil/status/statusor (= 1.20220623.0) - - abseil/strings/cord (= 1.20220623.0) - - abseil/strings/str_format (= 1.20220623.0) - - abseil/strings/strings (= 1.20220623.0) - - abseil/synchronization/synchronization (= 1.20220623.0) - - abseil/time/time (= 1.20220623.0) - - abseil/types/optional (= 1.20220623.0) - - abseil/types/span (= 1.20220623.0) - - abseil/types/variant (= 1.20220623.0) - - abseil/utility/utility (= 1.20220623.0) - - BoringSSL-GRPC (= 0.0.24) - - gRPC-Core/Interface (= 1.50.1) - - gRPC-Core/Interface (1.50.1) - - leveldb-library (1.22.2) - - nanopb (2.30909.0): - - nanopb/decode (= 2.30909.0) - - nanopb/encode (= 2.30909.0) - - nanopb/decode (2.30909.0) - - nanopb/encode (2.30909.0) - - PromisesObjC (2.2.0) - - shared (1.0.0): - - FirebaseCore - - FirebaseFirestore - - WebRTC-SDK (= 114.5735.02) - - WebRTC-SDK (114.5735.02) - -DEPENDENCIES: - - shared (from `../shared`) - -SPEC REPOS: - trunk: - - abseil - - BoringSSL-GRPC - - FirebaseCore - - FirebaseCoreInternal - - FirebaseFirestore - - GoogleUtilities - - "gRPC-C++" - - gRPC-Core - - leveldb-library - - nanopb - - PromisesObjC - - WebRTC-SDK - -EXTERNAL SOURCES: - shared: - :path: "../shared" - -SPEC CHECKSUMS: - abseil: 926fb7a82dc6d2b8e1f2ed7f3a718bce691d1e46 - BoringSSL-GRPC: 3175b25143e648463a56daeaaa499c6cb86dad33 - FirebaseCore: 62fd4d549f5e3f3bd52b7998721c5fa0557fb355 - FirebaseCoreInternal: 9e46c82a14a3b3a25be4e1e151ce6d21536b89c0 - FirebaseFirestore: 09be82b113fbcb225b9797d2c525ae8886abc7a3 - GoogleUtilities: 9aa0ad5a7bc171f8bae016300bfcfa3fb8425749 - "gRPC-C++": 0968bace703459fd3e5dcb0b2bed4c573dbff046 - gRPC-Core: 17108291d84332196d3c8466b48f016fc17d816d - leveldb-library: f03246171cce0484482ec291f88b6d563699ee06 - nanopb: b552cce312b6c8484180ef47159bc0f65a1f0431 - PromisesObjC: 09985d6d70fbe7878040aa746d78236e6946d2ef - shared: cf27933a6f2b84a6642d82be3a8ab8c890a0be05 - WebRTC-SDK: dd913fd31cfbf1d43b9a22d83f4c6354c960c623 - -PODFILE CHECKSUM: 0e3d5ba6f75052d9af66e13da5a081f724211aa3 - -COCOAPODS: 1.15.2 diff --git a/sample/app-ios/app-ios.xcodeproj/project.pbxproj b/sample/app-ios/app-ios.xcodeproj/project.pbxproj deleted file mode 100644 index 81e757c0..00000000 --- a/sample/app-ios/app-ios.xcodeproj/project.pbxproj +++ /dev/null @@ -1,473 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 55; - objects = { - -/* Begin PBXBuildFile section */ - 6ACDDCE04906D276376CC975 /* Pods_app_ios.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F3341A31D5C24E958B40A16B /* Pods_app_ios.framework */; }; - FA11F3382899C22A00676143 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA11F3372899C22A00676143 /* AppDelegate.swift */; }; - FA11F33A2899C22A00676143 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA11F3392899C22A00676143 /* SceneDelegate.swift */; }; - FA11F33C2899C22A00676143 /* StartViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA11F33B2899C22A00676143 /* StartViewController.swift */; }; - FA11F33F2899C22B00676143 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FA11F33D2899C22B00676143 /* Main.storyboard */; }; - FA11F3412899C22C00676143 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FA11F3402899C22C00676143 /* Assets.xcassets */; }; - FA11F3442899C22C00676143 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FA11F3422899C22C00676143 /* LaunchScreen.storyboard */; }; - FAAF8FF7289A988C004FB1B1 /* RoomViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAAF8FF6289A988C004FB1B1 /* RoomViewController.swift */; }; - FAFB7A41289BF42C002B18FD /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = FAFB7A40289BF42C002B18FD /* GoogleService-Info.plist */; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - FA9BD2A428E0A17700E7A36C /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 5D7E487A4CEE7EB53148FE53 /* Pods-app-ios.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-app-ios.debug.xcconfig"; path = "Target Support Files/Pods-app-ios/Pods-app-ios.debug.xcconfig"; sourceTree = ""; }; - 7BFC8A98B5397F3BAC737F4D /* Pods-app-ios.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-app-ios.release.xcconfig"; path = "Target Support Files/Pods-app-ios/Pods-app-ios.release.xcconfig"; sourceTree = ""; }; - F3341A31D5C24E958B40A16B /* Pods_app_ios.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_app_ios.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - FA11F3342899C22A00676143 /* app-ios.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "app-ios.app"; sourceTree = BUILT_PRODUCTS_DIR; }; - FA11F3372899C22A00676143 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - FA11F3392899C22A00676143 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; - FA11F33B2899C22A00676143 /* StartViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartViewController.swift; sourceTree = ""; }; - FA11F33E2899C22B00676143 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - FA11F3402899C22C00676143 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - FA11F3432899C22C00676143 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - FA11F3452899C22C00676143 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - FAAF8FF6289A988C004FB1B1 /* RoomViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomViewController.swift; sourceTree = ""; }; - FAFB7A40289BF42C002B18FD /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - FA11F3312899C22A00676143 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 6ACDDCE04906D276376CC975 /* Pods_app_ios.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 043F32BC1BEEF67A45BD5794 /* Pods */ = { - isa = PBXGroup; - children = ( - 5D7E487A4CEE7EB53148FE53 /* Pods-app-ios.debug.xcconfig */, - 7BFC8A98B5397F3BAC737F4D /* Pods-app-ios.release.xcconfig */, - ); - path = Pods; - sourceTree = ""; - }; - FA11F32B2899C22A00676143 = { - isa = PBXGroup; - children = ( - FA11F3362899C22A00676143 /* app-ios */, - FA11F3352899C22A00676143 /* Products */, - FA11F34B2899C70E00676143 /* Frameworks */, - 043F32BC1BEEF67A45BD5794 /* Pods */, - ); - sourceTree = ""; - }; - FA11F3352899C22A00676143 /* Products */ = { - isa = PBXGroup; - children = ( - FA11F3342899C22A00676143 /* app-ios.app */, - ); - name = Products; - sourceTree = ""; - }; - FA11F3362899C22A00676143 /* app-ios */ = { - isa = PBXGroup; - children = ( - FA11F3372899C22A00676143 /* AppDelegate.swift */, - FA11F3392899C22A00676143 /* SceneDelegate.swift */, - FA11F33B2899C22A00676143 /* StartViewController.swift */, - FAAF8FF6289A988C004FB1B1 /* RoomViewController.swift */, - FA11F33D2899C22B00676143 /* Main.storyboard */, - FA11F3402899C22C00676143 /* Assets.xcassets */, - FA11F3422899C22C00676143 /* LaunchScreen.storyboard */, - FA11F3452899C22C00676143 /* Info.plist */, - FAFB7A40289BF42C002B18FD /* GoogleService-Info.plist */, - ); - path = "app-ios"; - sourceTree = ""; - }; - FA11F34B2899C70E00676143 /* Frameworks */ = { - isa = PBXGroup; - children = ( - F3341A31D5C24E958B40A16B /* Pods_app_ios.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - FA11F3332899C22A00676143 /* app-ios */ = { - isa = PBXNativeTarget; - buildConfigurationList = FA11F3482899C22C00676143 /* Build configuration list for PBXNativeTarget "app-ios" */; - buildPhases = ( - C3DBAC6BF516EA57841C92C2 /* [CP] Check Pods Manifest.lock */, - FA11F3302899C22A00676143 /* Sources */, - FA11F3312899C22A00676143 /* Frameworks */, - FA11F3322899C22A00676143 /* Resources */, - FA9BD2A428E0A17700E7A36C /* Embed Frameworks */, - 12628261B270E57875EAEDFA /* [CP] Embed Pods Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "app-ios"; - productName = "app-ios"; - productReference = FA11F3342899C22A00676143 /* app-ios.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - FA11F32C2899C22A00676143 /* Project object */ = { - isa = PBXProject; - attributes = { - BuildIndependentTargetsInParallel = 1; - LastSwiftUpdateCheck = 1340; - LastUpgradeCheck = 1340; - TargetAttributes = { - FA11F3332899C22A00676143 = { - CreatedOnToolsVersion = 13.4.1; - }; - }; - }; - buildConfigurationList = FA11F32F2899C22A00676143 /* Build configuration list for PBXProject "app-ios" */; - compatibilityVersion = "Xcode 13.0"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = FA11F32B2899C22A00676143; - productRefGroup = FA11F3352899C22A00676143 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - FA11F3332899C22A00676143 /* app-ios */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - FA11F3322899C22A00676143 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - FA11F3442899C22C00676143 /* LaunchScreen.storyboard in Resources */, - FAFB7A41289BF42C002B18FD /* GoogleService-Info.plist in Resources */, - FA11F3412899C22C00676143 /* Assets.xcassets in Resources */, - FA11F33F2899C22B00676143 /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 12628261B270E57875EAEDFA /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-app-ios/Pods-app-ios-frameworks-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-app-ios/Pods-app-ios-frameworks-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-app-ios/Pods-app-ios-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - C3DBAC6BF516EA57841C92C2 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-app-ios-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - 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"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - FA11F3302899C22A00676143 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - FA11F33C2899C22A00676143 /* StartViewController.swift in Sources */, - FA11F3382899C22A00676143 /* AppDelegate.swift in Sources */, - FA11F33A2899C22A00676143 /* SceneDelegate.swift in Sources */, - FAAF8FF7289A988C004FB1B1 /* RoomViewController.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - FA11F33D2899C22B00676143 /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - FA11F33E2899C22B00676143 /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - FA11F3422899C22C00676143 /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - FA11F3432899C22C00676143 /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - FA11F3462899C22C00676143 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; - 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; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - 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 = 13.0; - 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; - }; - FA11F3472899C22C00676143 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; - 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; - 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 = 13.0; - MTL_ENABLE_DEBUG_INFO = NO; - MTL_FAST_MATH = YES; - SDKROOT = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - FA11F3492899C22C00676143 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 5D7E487A4CEE7EB53148FE53 /* Pods-app-ios.debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = Q86C89UZUH; - ENABLE_BITCODE = NO; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = "app-ios/Info.plist"; - INFOPLIST_KEY_CFBundleDisplayName = "WebRTC KMP Sample"; - INFOPLIST_KEY_NSCameraUsageDescription = "Access to the camera is required."; - INFOPLIST_KEY_NSMicrophoneUsageDescription = "Access to the microphone is required."; - INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; - INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; - INFOPLIST_KEY_UIMainStoryboardFile = Main; - INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = UIInterfaceOrientationPortrait; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = UIInterfaceOrientationPortrait; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - OTHER_LDFLAGS = "$(inherited)"; - PRODUCT_BUNDLE_IDENTIFIER = com.shepeliev.webrtckmp.sampleapp; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Debug; - }; - FA11F34A2899C22C00676143 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7BFC8A98B5397F3BAC737F4D /* Pods-app-ios.release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = Q86C89UZUH; - ENABLE_BITCODE = NO; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = "app-ios/Info.plist"; - INFOPLIST_KEY_CFBundleDisplayName = "WebRTC KMP Sample"; - INFOPLIST_KEY_NSCameraUsageDescription = "Access to the camera is required."; - INFOPLIST_KEY_NSMicrophoneUsageDescription = "Access to the microphone is required."; - INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; - INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; - INFOPLIST_KEY_UIMainStoryboardFile = Main; - INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = UIInterfaceOrientationPortrait; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = UIInterfaceOrientationPortrait; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - OTHER_LDFLAGS = "$(inherited)"; - PRODUCT_BUNDLE_IDENTIFIER = com.shepeliev.webrtckmp.sampleapp; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - FA11F32F2899C22A00676143 /* Build configuration list for PBXProject "app-ios" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - FA11F3462899C22C00676143 /* Debug */, - FA11F3472899C22C00676143 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - FA11F3482899C22C00676143 /* Build configuration list for PBXNativeTarget "app-ios" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - FA11F3492899C22C00676143 /* Debug */, - FA11F34A2899C22C00676143 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = FA11F32C2899C22A00676143 /* Project object */; -} diff --git a/sample/app-ios/app-ios.xcodeproj/xcshareddata/xcschemes/app-ios.xcscheme b/sample/app-ios/app-ios.xcodeproj/xcshareddata/xcschemes/app-ios.xcscheme deleted file mode 100644 index 068c29d4..00000000 --- a/sample/app-ios/app-ios.xcodeproj/xcshareddata/xcschemes/app-ios.xcscheme +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/sample/app-ios/app-ios.xcworkspace/contents.xcworkspacedata b/sample/app-ios/app-ios.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index ad23cfa3..00000000 --- a/sample/app-ios/app-ios.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/sample/app-ios/app-ios.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/sample/app-ios/app-ios.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/sample/app-ios/app-ios.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/sample/app-ios/app-ios/AppDelegate.swift b/sample/app-ios/app-ios/AppDelegate.swift deleted file mode 100644 index 3b5220c0..00000000 --- a/sample/app-ios/app-ios/AppDelegate.swift +++ /dev/null @@ -1,51 +0,0 @@ -// -// AppDelegate.swift -// app-ios -// -// Created by Aleksandr Shepeliev on 02.08.2022. -// - -import UIKit -import shared - -@main -class AppDelegate: UIResponder, UIApplicationDelegate { - - var lifecycle: LifecycleRegistry! - var room: Room! - - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - lifecycle = LifecycleRegistryKt.LifecycleRegistry() - let context = DefaultComponentContext(lifecycle: self.lifecycle) - room = RoomComponent(componentContext: context) - - lifecycle.onCreate() - lifecycle.onStart() - lifecycle.onResume() - - return true - } - - func applicationWillTerminate(_ application: UIApplication) { - lifecycle.onPause() - lifecycle.onStop() - lifecycle.onDestroy() - } - - // MARK: UISceneSession Lifecycle - - func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { - // Called when a new scene session is being created. - // Use this method to select a configuration to create the new scene with. - return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) - } - - func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { - // Called when the user discards a scene session. - // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. - // Use this method to release any resources that were specific to the discarded scenes, as they will not return. - } - - -} - diff --git a/sample/app-ios/app-ios/Assets.xcassets/AppIcon.appiconset/Contents.json b/sample/app-ios/app-ios/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 9221b9bb..00000000 --- a/sample/app-ios/app-ios/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "20x20" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "20x20" - }, - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "29x29" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "29x29" - }, - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "40x40" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "40x40" - }, - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "60x60" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "60x60" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "20x20" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "20x20" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "29x29" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "29x29" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "40x40" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "40x40" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "76x76" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "76x76" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "83.5x83.5" - }, - { - "idiom" : "ios-marketing", - "scale" : "1x", - "size" : "1024x1024" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/sample/app-ios/app-ios/Base.lproj/LaunchScreen.storyboard b/sample/app-ios/app-ios/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index 865e9329..00000000 --- a/sample/app-ios/app-ios/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/sample/app-ios/app-ios/Base.lproj/Main.storyboard b/sample/app-ios/app-ios/Base.lproj/Main.storyboard deleted file mode 100644 index 484b0fb6..00000000 --- a/sample/app-ios/app-ios/Base.lproj/Main.storyboard +++ /dev/null @@ -1,137 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/sample/app-ios/app-ios/GoogleService-Info.plist b/sample/app-ios/app-ios/GoogleService-Info.plist deleted file mode 100644 index 259baa6e..00000000 --- a/sample/app-ios/app-ios/GoogleService-Info.plist +++ /dev/null @@ -1,34 +0,0 @@ - - - - - CLIENT_ID - 216132728347-n1k42tu2k9n6iigihgrfesrnu7e5bvtk.apps.googleusercontent.com - REVERSED_CLIENT_ID - com.googleusercontent.apps.216132728347-n1k42tu2k9n6iigihgrfesrnu7e5bvtk - API_KEY - AIzaSyD26yvz58nr-cH1LGiccfT4MJXFSagcWmU - GCM_SENDER_ID - 216132728347 - PLIST_VERSION - 1 - BUNDLE_ID - com.shepeliev.webrtckmp.sample - PROJECT_ID - app-rtc-kmp - STORAGE_BUCKET - app-rtc-kmp.appspot.com - IS_ADS_ENABLED - - IS_ANALYTICS_ENABLED - - IS_APPINVITE_ENABLED - - IS_GCM_ENABLED - - IS_SIGNIN_ENABLED - - GOOGLE_APP_ID - 1:216132728347:ios:d76057bc501cb5da872abe - - \ No newline at end of file diff --git a/sample/app-ios/app-ios/Info.plist b/sample/app-ios/app-ios/Info.plist deleted file mode 100644 index 9f650035..00000000 --- a/sample/app-ios/app-ios/Info.plist +++ /dev/null @@ -1,29 +0,0 @@ - - - - - UIApplicationSceneManifest - - UIApplicationSupportsMultipleScenes - - UISceneConfigurations - - UIWindowSceneSessionRoleApplication - - - UISceneConfigurationName - Default Configuration - UISceneDelegateClassName - $(PRODUCT_MODULE_NAME).SceneDelegate - UISceneStoryboardFile - Main - - - - - NSCameraUsageDescription - Access to the camera is required. - NSMicrophoneUsageDescription - Access to the microphone is required. - - diff --git a/sample/app-ios/app-ios/RoomViewController.swift b/sample/app-ios/app-ios/RoomViewController.swift deleted file mode 100644 index fc09f74f..00000000 --- a/sample/app-ios/app-ios/RoomViewController.swift +++ /dev/null @@ -1,164 +0,0 @@ -// -// RoomViewController.swift -// app-ios -// -// Created by Aleksandr Shepeliev on 03.08.2022. -// - -import UIKit -import WebRTC -import shared - -class RoomViewController: UIViewController { - - @IBOutlet weak var createRoomButton: UIButton! - - @IBOutlet weak var joinRoomButton: UIButton! - - @IBOutlet weak var roomIdContainer: UIStackView! - - @IBOutlet weak var roomIdLabel: UILabel! - -#if arch(x86_64) - private var localVideo = RTCEAGLVideoView() - private var remoteVideo = RTCEAGLVideoView() -#else - private var localVideo = RTCMTLVideoView() - private var remoteVideo = RTCMTLVideoView() -#endif - - private var room: Room! = (UIApplication.shared.delegate as! AppDelegate).room - private var isLocalVideoAttached = false - private var isRemoteVideoAttached = false - private var localVideoTopConstraint: NSLayoutConstraint! - - override func viewDidLoad() { - super.viewDidLoad() - - setupLocalVideo() - - room.model.subscribe(observer: roomModelObserver) - room.openUserMedia() - } - - private func roomModelObserver(_ model: RoomModel) { - NSLog("Room model updated: \(model)") - - if let localStream = model.localStream { - localStreamReady(localStream) - } - - if let remoteStream = model.remoteStream { - remoteStreamReady(remoteStream) - } - - if let roomId = model.roomId { - createRoomButton.isHidden = true - joinRoomButton.isHidden = true - roomIdContainer.isHidden = false - roomIdLabel.text = roomId - } - } - - private func localStreamReady(_ localStream: MediaStream) { - if !isLocalVideoAttached { - isLocalVideoAttached = true - localStream.videoTracks.first?.addRenderer(renderer: localVideo) - } - } - - private func remoteStreamReady(_ remoteStream: MediaStream) { - if !isRemoteVideoAttached { - isRemoteVideoAttached = true - setupRemoteVideo() - - if let track = remoteStream.videoTracks.first { - track.addRenderer(renderer: remoteVideo) - } - } - } - - override func viewWillDisappear(_ animated: Bool) { - room.hangup() - room.model.unsubscribe(observer: roomModelObserver) - } - - // MARK: Actions - - @IBAction func createRoomButtonDidClick(_ sender: Any) { - room.createRoom() - } - - @IBAction func joinRoomButtonDidClick(_ sender: Any) { - let joinDialog = UIAlertController(title: "Join room", message: "Enter room ID", preferredStyle: .alert) - let okAction = UIAlertAction(title: "OK", style: .default) { [weak self] _ in - if let roomId = joinDialog.textFields?.first?.text { - self?.room?.joinRoom(roomId: roomId) - } - } - let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) - joinDialog.addTextField() - joinDialog.addAction(okAction) - joinDialog.addAction(cancelAction) - present(joinDialog, animated: true) - } - - @IBAction func copyRoomIdDidClick(_ sender: Any) { - if let roomId = roomIdLabel.text { - UIPasteboard.general.string = roomId - NSLog("Room ID \(roomId) copied.") - } - } - - @IBAction func switchCamera(_ sender: Any) { - room.switchCamera() - } - - // MARK: - UI - private func setupLocalVideo() { - localVideo.contentMode = .scaleAspectFill - view.insertSubview(localVideo, at: 0) - localVideo.translatesAutoresizingMaskIntoConstraints = false - setupLocalVideoConstraints() - } - - private func setupLocalVideoConstraints() { - localVideo.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true - localVideo.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true - localVideo.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true - - localVideoTopConstraint = localVideo.topAnchor.constraint(equalTo: view.topAnchor) - localVideoTopConstraint.isActive = true - } - - private func setupRemoteVideo() { - view.insertSubview(remoteVideo, at: 0) - remoteVideo.translatesAutoresizingMaskIntoConstraints = false - setupRemoteVideoConstraints() - } - - private func setupRemoteVideoConstraints() { - localVideoTopConstraint.isActive = false - - remoteVideo.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true - remoteVideo.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true - remoteVideo.topAnchor.constraint(equalTo: view.topAnchor).isActive = true - remoteVideo.heightAnchor.constraint(equalTo: localVideo.heightAnchor).isActive = true - - localVideoTopConstraint = localVideo.topAnchor.constraint(equalTo: remoteVideo.bottomAnchor) - localVideoTopConstraint.isActive = true - - localVideo.layoutIfNeeded() - } - - /* - // MARK: - Navigation - - // In a storyboard-based application, you will often want to do a little preparation before navigation - override func prepare(for segue: UIStoryboardSegue, sender: Any?) { - // Get the new view controller using segue.destination. - // Pass the selected object to the new view controller. - } - */ - -} diff --git a/sample/app-ios/app-ios/SceneDelegate.swift b/sample/app-ios/app-ios/SceneDelegate.swift deleted file mode 100644 index 85e56a02..00000000 --- a/sample/app-ios/app-ios/SceneDelegate.swift +++ /dev/null @@ -1,52 +0,0 @@ -// -// SceneDelegate.swift -// app-ios -// -// Created by Aleksandr Shepeliev on 02.08.2022. -// - -import UIKit - -class SceneDelegate: UIResponder, UIWindowSceneDelegate { - - var window: UIWindow? - - - func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { - // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. - // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. - // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). - guard let _ = (scene as? UIWindowScene) else { return } - } - - func sceneDidDisconnect(_ scene: UIScene) { - // Called as the scene is being released by the system. - // This occurs shortly after the scene enters the background, or when its session is discarded. - // Release any resources associated with this scene that can be re-created the next time the scene connects. - // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). - } - - func sceneDidBecomeActive(_ scene: UIScene) { - // Called when the scene has moved from an inactive state to an active state. - // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. - } - - func sceneWillResignActive(_ scene: UIScene) { - // Called when the scene will move from an active state to an inactive state. - // This may occur due to temporary interruptions (ex. an incoming phone call). - } - - func sceneWillEnterForeground(_ scene: UIScene) { - // Called as the scene transitions from the background to the foreground. - // Use this method to undo the changes made on entering the background. - } - - func sceneDidEnterBackground(_ scene: UIScene) { - // Called as the scene transitions from the foreground to the background. - // Use this method to save data, release shared resources, and store enough scene-specific state information - // to restore the scene back to its current state. - } - - -} - diff --git a/sample/app-ios/app-ios/StartViewController.swift b/sample/app-ios/app-ios/StartViewController.swift deleted file mode 100644 index 762b71a2..00000000 --- a/sample/app-ios/app-ios/StartViewController.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// ViewController.swift -// app-ios -// -// Created by Aleksandr Shepeliev on 02.08.2022. -// - -import UIKit - -class StartViewController: UIViewController { - - override func viewDidLoad() { - super.viewDidLoad() - // Do any additional setup after loading the view. - } - - @IBAction func hangupAction(unwindSegue: UIStoryboardSegue) { - - } -} - diff --git a/sample/app-web/build.gradle.kts b/sample/app-web/build.gradle.kts deleted file mode 100644 index 69ae22f7..00000000 --- a/sample/app-web/build.gradle.kts +++ /dev/null @@ -1,20 +0,0 @@ -plugins { - kotlin("js") - id("org.jlleitschuh.gradle.ktlint") -} - -kotlin { - js(IR) { - browser() - binaries.executable() - } -} - -dependencies { - implementation(project(":sample:shared")) - implementation(project.dependencies.enforcedPlatform(deps.kotlin.wrappers.bom)) - implementation(deps.kotlin.wrappers.emotion) - implementation(deps.kotlin.wrappers.react) - implementation(deps.kotlin.wrappers.reactDom) - implementation(deps.kotlin.wrappers.mui) -} diff --git a/sample/app-web/src/main/kotlin/App.kt b/sample/app-web/src/main/kotlin/App.kt deleted file mode 100644 index ece82835..00000000 --- a/sample/app-web/src/main/kotlin/App.kt +++ /dev/null @@ -1,109 +0,0 @@ -import com.arkivanov.decompose.value.Value -import com.shepeliev.webrtckmp.sample.shared.Room -import csstype.px -import emotion.react.css -import kotlinx.browser.window -import mui.material.Button -import mui.material.ButtonVariant -import org.w3c.dom.HTMLVideoElement -import react.FC -import react.Props -import react.dom.html.ReactHTML.div -import react.dom.html.ReactHTML.h1 -import react.dom.html.ReactHTML.p -import react.dom.html.ReactHTML.video -import react.useEffect -import react.useRef -import react.useState - -external interface AppProps : Props { - var room: Room -} - -val App = FC { props -> - h1 { +"WebRTC KMP Sample" } - - val room = props.room - val roomModel: Room.Model = useValue(room.model) - - roomModel.roomId?.let { - p { +"Room ID: ${roomModel.roomId}" } - } - - div { - Button { - variant = ButtonVariant.contained - onClick = { room.openUserMedia() } - disabled = roomModel.localStream != null - +"Open camera and microphone" - } - - Button { - variant = ButtonVariant.contained - onClick = { room.createRoom() } - disabled = roomModel.isJoining || roomModel.localStream == null || roomModel.roomId != null - +"Create room" - } - - Button { - variant = ButtonVariant.contained - onClick = { - // TODO replace by Material UI dialog - window.prompt("Room ID:")?.let { room.joinRoom(it) } - } - disabled = roomModel.isJoining || roomModel.localStream == null || roomModel.roomId != null - +"Join room" - } - - Button { - variant = ButtonVariant.contained - onClick = { room.hangup() } - disabled = roomModel.localStream == null - +"Hangup" - } - } - - val localVideoRef = useRef(null) - useEffect(roomModel, localVideoRef) { - localVideoRef.current?.srcObject = roomModel.localStream?.js - } - - val remoteVideoRef = useRef(null) - useEffect { - remoteVideoRef.current?.srcObject = roomModel.remoteStream?.js - } - - div { - video { - css { - width = 640.px - height = 480.px - } - ref = localVideoRef - autoPlay = true - } - - if (roomModel.remoteStream != null) { - video { - css { - width = 640.px - height = 480.px - } - ref = remoteVideoRef - autoPlay = true - } - } - } -} - -fun useValue(value: Value): T { - var result by useState(value.value) - - useEffect(value, result) { - val valueObserver: (T) -> Unit = { result = it } - value.subscribe(valueObserver) - cleanup { value.unsubscribe(valueObserver) } - } - - return result -} diff --git a/sample/app-web/src/main/kotlin/LifecycleRegistry.kt b/sample/app-web/src/main/kotlin/LifecycleRegistry.kt deleted file mode 100644 index 6f184e66..00000000 --- a/sample/app-web/src/main/kotlin/LifecycleRegistry.kt +++ /dev/null @@ -1,18 +0,0 @@ -import com.arkivanov.essenty.lifecycle.LifecycleRegistry -import com.arkivanov.essenty.lifecycle.resume -import com.arkivanov.essenty.lifecycle.stop -import kotlinx.browser.document -import org.w3c.dom.Document - -fun LifecycleRegistry.attachToDocument() { - fun onVisibilityChanged() { - when (document.visibilityState) { - "visible" -> resume() - else -> stop() - } - } - - document.addEventListener("visibilitychange", callback = { onVisibilityChanged() }) -} - -private val Document.visibilityState: String get() = asDynamic().visibilityState.unsafeCast() diff --git a/sample/app-web/src/main/kotlin/Main.kt b/sample/app-web/src/main/kotlin/Main.kt deleted file mode 100644 index 62112ac3..00000000 --- a/sample/app-web/src/main/kotlin/Main.kt +++ /dev/null @@ -1,22 +0,0 @@ -import com.arkivanov.decompose.DefaultComponentContext -import com.arkivanov.essenty.lifecycle.LifecycleRegistry -import com.shepeliev.webrtckmp.sample.shared.RoomComponent -import kotlinx.browser.document -import react.Fragment -import react.create -import react.dom.client.createRoot - -fun main() { - val container = document.getElementById("root") ?: error("No root element.") - val root = createRoot(container) - - root.render( - Fragment.create { - App { - val lifecycle = LifecycleRegistry().apply { attachToDocument() } - val context = DefaultComponentContext(lifecycle) - room = RoomComponent(context) - } - } - ) -} diff --git a/sample/composeApp/build.gradle.kts b/sample/composeApp/build.gradle.kts new file mode 100644 index 00000000..a73ab43c --- /dev/null +++ b/sample/composeApp/build.gradle.kts @@ -0,0 +1,135 @@ +import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl +import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget + + +plugins { + kotlin("multiplatform") + id("com.android.application") + kotlin("native.cocoapods") + alias(libs.plugins.jetbrains.compose) +} + +kotlin { + configureKotlinCompilerArgs() + + cocoapods { + version = "1.0" + summary = "Compose app" + homepage = "not published" + ios.deploymentTarget = "13.0" + + pod("WebRTC-SDK") { + version = "114.5735.02" + moduleName = "WebRTC" + packageName = "WebRTC" + } + } + + androidTarget { + configureJvmTarget() + } + + listOf( + iosX64 { configureWebRtcCinterops() }, + iosArm64 { configureWebRtcCinterops() }, + iosSimulatorArm64 { configureWebRtcCinterops() } + ).forEach { iosTarget -> + iosTarget.binaries.framework { + baseName = "ComposeApp" + isStatic = true + } + } + + js { + browser { + binaries.executable() + } + } + + sourceSets { + commonMain.dependencies { + implementation(compose.runtime) + implementation(compose.foundation) + implementation(compose.material) + implementation(compose.ui) + implementation(compose.components.resources) + implementation(compose.components.uiToolingPreview) + implementation(libs.kotlin.coroutines) + implementation(libs.kermit) + implementation(project(":webrtc-kmp")) + } + + androidMain.dependencies { + implementation(libs.kotlin.coroutines.android) + implementation(libs.compose.ui.tooling.preview) + implementation(libs.androidx.activity.compose) + implementation(libs.accompanist.permissions) + } + + jsMain.dependencies { + implementation(project.dependencies.platform(libs.kotlin.wrappers.bom)) + implementation(libs.kotlin.wrappers.mui) + implementation(libs.kotlin.wrappers.react) + implementation(libs.kotlin.wrappers.reactDom) + implementation(libs.kotlin.wrappers.emotion) + } + } +} + +android { + namespace = "com.shepeliev.webrtckmp.sample" + compileSdk = libs.versions.compileSdk.get().toInt() + + sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml") + sourceSets["main"].res.srcDirs("src/androidMain/res") + sourceSets["main"].resources.srcDirs("src/commonMain/resources") + + defaultConfig { + applicationId = "com.shepeliev.webrtckmp.sample" + minSdk = libs.versions.minSdk.get().toInt() + targetSdk = libs.versions.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_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + dependencies { + debugImplementation(libs.compose.ui.tooling) + } +} + +fun KotlinNativeTarget.configureWebRtcCinterops() { + val webRtcFrameworkPath = file("$buildDir/cocoapods/synthetic/IOS/Pods/WebRTC-SDK") + .resolveArchPath(konanTarget, "WebRTC") + compilations.getByName("main") { + cinterops.getByName("WebRTC") { + compilerOpts("-framework", "WebRTC", "-F$webRtcFrameworkPath") + } + } + + binaries { + getTest("DEBUG").apply { + linkerOpts( + "-framework", + "WebRTC", + "-F$webRtcFrameworkPath", + "-rpath", + "$webRtcFrameworkPath", + "-ObjC" + ) + } + } +} diff --git a/sample/shared/shared.podspec b/sample/composeApp/composeApp.podspec similarity index 61% rename from sample/shared/shared.podspec rename to sample/composeApp/composeApp.podspec index 0a8d7056..470d17da 100644 --- a/sample/shared/shared.podspec +++ b/sample/composeApp/composeApp.podspec @@ -1,37 +1,35 @@ Pod::Spec.new do |spec| - spec.name = 'shared' - spec.version = '1.0.0' - spec.homepage = 'https://github.com/shepeliev/webrtc-kmp/tree/main/sample' + spec.name = 'composeApp' + spec.version = '1.0' + spec.homepage = 'not published' spec.source = { :http=> ''} spec.authors = '' spec.license = '' - spec.summary = 'Shared framework for WebRTC KMP sample' - spec.vendored_frameworks = 'build/cocoapods/framework/shared.framework' + spec.summary = 'Compose app' + spec.vendored_frameworks = 'build/cocoapods/framework/composeApp.framework' spec.libraries = 'c++' - spec.ios.deployment_target = '11.0' - spec.dependency 'FirebaseCore' - spec.dependency 'FirebaseFirestore' + spec.ios.deployment_target = '13.0' spec.dependency 'WebRTC-SDK', '114.5735.02' - if !Dir.exist?('build/cocoapods/framework/shared.framework') || Dir.empty?('build/cocoapods/framework/shared.framework') + if !Dir.exist?('build/cocoapods/framework/composeApp.framework') || Dir.empty?('build/cocoapods/framework/composeApp.framework') raise " - Kotlin framework 'shared' doesn't exist yet, so a proper Xcode project can't be generated. + Kotlin framework 'composeApp' doesn't exist yet, so a proper Xcode project can't be generated. 'pod install' should be executed after running ':generateDummyFramework' Gradle task: - ./gradlew :sample:shared:generateDummyFramework + ./gradlew :sample:composeApp:generateDummyFramework Alternatively, proper pod installation is performed during Gradle sync in the IDE (if Podfile location is set)" end spec.pod_target_xcconfig = { - 'KOTLIN_PROJECT_PATH' => ':sample:shared', - 'PRODUCT_MODULE_NAME' => 'shared', + 'KOTLIN_PROJECT_PATH' => ':sample:composeApp', + 'PRODUCT_MODULE_NAME' => 'composeApp', } spec.script_phases = [ { - :name => 'Build shared', + :name => 'Build composeApp', :execution_position => :before_compile, :shell_path => '/bin/sh', :script => <<-SCRIPT @@ -48,5 +46,5 @@ Pod::Spec.new do |spec| SCRIPT } ] - + spec.resources = ['build/compose/ios/composeApp/compose-resources'] end \ No newline at end of file diff --git a/sample/app-android/src/main/AndroidManifest.xml b/sample/composeApp/src/androidMain/AndroidManifest.xml similarity index 50% rename from sample/app-android/src/main/AndroidManifest.xml rename to sample/composeApp/src/androidMain/AndroidManifest.xml index 94b8ac46..7083d7c6 100644 --- a/sample/app-android/src/main/AndroidManifest.xml +++ b/sample/composeApp/src/androidMain/AndroidManifest.xml @@ -1,16 +1,25 @@ + + + + + android:roundIcon="@mipmap/ic_launcher_round" + android:supportsRtl="true" + android:theme="@android:style/Theme.Material.Light.NoActionBar"> diff --git a/sample/composeApp/src/androidMain/kotlin/StartButton.android.kt b/sample/composeApp/src/androidMain/kotlin/StartButton.android.kt new file mode 100644 index 00000000..c22227c5 --- /dev/null +++ b/sample/composeApp/src/androidMain/kotlin/StartButton.android.kt @@ -0,0 +1,61 @@ +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.preference.PreferenceManager +import android.provider.Settings +import androidx.compose.material.Button +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.core.content.edit +import com.google.accompanist.permissions.ExperimentalPermissionsApi +import com.google.accompanist.permissions.rememberMultiplePermissionsState + +@OptIn(ExperimentalPermissionsApi::class) +@Composable +actual fun StartButton(onClick: () -> Unit, modifier: Modifier) { + val context = LocalContext.current + + val permissions = rememberMultiplePermissionsState( + listOf( + android.Manifest.permission.CAMERA, + android.Manifest.permission.RECORD_AUDIO + ) + ) { + if (it.all { (_, granted) -> granted }) { + onClick() + } + } + + Button(onClick = { + if (permissions.allPermissionsGranted) { + onClick() + } else { + val prefs = PreferenceManager.getDefaultSharedPreferences(context) + val permissionsRequested = prefs.getBoolean("permissionsRequested", false) + if (!permissions.shouldShowRationale && permissionsRequested) { + context.navigateToAppSettings() + return@Button + } + + prefs.edit { putBoolean("permissionsRequested", true) } + permissions.launchMultiplePermissionRequest() + } + }, modifier = modifier) { + Text("Start") + } +} + +private fun Context.navigateToAppSettings() { + val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { + data = Uri.fromParts("package", packageName, null) + addCategory(Intent.CATEGORY_DEFAULT) + addFlags( + Intent.FLAG_ACTIVITY_NEW_TASK or + Intent.FLAG_ACTIVITY_NO_HISTORY or + Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS + ) + } + startActivity(intent) +} diff --git a/sample/app-android/src/main/java/com/shepeliev/webrtckmp/sample/Video.kt b/sample/composeApp/src/androidMain/kotlin/Video.android.kt similarity index 83% rename from sample/app-android/src/main/java/com/shepeliev/webrtckmp/sample/Video.kt rename to sample/composeApp/src/androidMain/kotlin/Video.android.kt index 9f943794..260fa44d 100644 --- a/sample/app-android/src/main/java/com/shepeliev/webrtckmp/sample/Video.kt +++ b/sample/composeApp/src/androidMain/kotlin/Video.android.kt @@ -1,5 +1,3 @@ -package com.shepeliev.webrtckmp.sample - import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.getValue @@ -18,12 +16,7 @@ import org.webrtc.SurfaceViewRenderer import org.webrtc.VideoSink @Composable -fun Video( - track: VideoStreamTrack, - modifier: Modifier = Modifier, - scalingTypeMatchOrientation: RendererCommon.ScalingType = RendererCommon.ScalingType.SCALE_ASPECT_BALANCED, - scalingTypeMismatchOrientation: RendererCommon.ScalingType = RendererCommon.ScalingType.SCALE_ASPECT_FIT, -) { +actual fun Video(track: VideoStreamTrack, modifier: Modifier) { var renderer by remember { mutableStateOf(null) } val lifecycleEventObserver = remember(renderer, track) { @@ -63,7 +56,10 @@ fun Video( modifier = modifier, factory = { context -> SurfaceViewRenderer(context).apply { - setScalingType(scalingTypeMatchOrientation, scalingTypeMismatchOrientation) + setScalingType( + RendererCommon.ScalingType.SCALE_ASPECT_BALANCED, + RendererCommon.ScalingType.SCALE_ASPECT_FIT + ) renderer = this } }, @@ -71,11 +67,11 @@ fun Video( } private fun VideoStreamTrack.addSinkCatching(sink: VideoSink) { - // runCatching as track may be disposed while activity was in pause mode + // runCatching as track may be disposed while activity was in pause runCatching { addSink(sink) } } private fun VideoStreamTrack.removeSinkCatching(sink: VideoSink) { - // runCatching as track may be disposed while activity was in pause mode + // runCatching as track may be disposed while activity was in pause runCatching { removeSink(sink) } } diff --git a/sample/composeApp/src/androidMain/kotlin/com/shepeliev/webrtckmp/sample/MainActivity.kt b/sample/composeApp/src/androidMain/kotlin/com/shepeliev/webrtckmp/sample/MainActivity.kt new file mode 100644 index 00000000..bf7357a0 --- /dev/null +++ b/sample/composeApp/src/androidMain/kotlin/com/shepeliev/webrtckmp/sample/MainActivity.kt @@ -0,0 +1,45 @@ +package com.shepeliev.webrtckmp.sample + +import App +import android.os.Bundle +import android.util.Log +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.Preview +import com.shepeliev.webrtckmp.WebRtc +import org.webrtc.Loggable +import org.webrtc.Logging + +class MainActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + WebRtc.factoryInitializationOptionsBuilder + .setInjectableLogger(WebRtcLogger, Logging.Severity.LS_ERROR) + + setContent { + App() + } + } +} + +private object WebRtcLogger : Loggable { + override fun onLogMessage(message: String, severity: Logging.Severity, tag: String) { + when (severity) { + Logging.Severity.LS_ERROR -> Log.e(tag, message) + Logging.Severity.LS_WARNING -> Log.w(tag, message) + Logging.Severity.LS_INFO -> Log.i(tag, message) + Logging.Severity.LS_VERBOSE -> Log.v(tag, message) + Logging.Severity.LS_NONE -> { + + } + } + } +} + +@Preview +@Composable +fun AppAndroidPreview() { + App() +} diff --git a/sample/composeApp/src/androidMain/res/drawable-v24/ic_launcher_foreground.xml b/sample/composeApp/src/androidMain/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 00000000..2b068d11 --- /dev/null +++ b/sample/composeApp/src/androidMain/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/sample/composeApp/src/androidMain/res/drawable/ic_launcher_background.xml b/sample/composeApp/src/androidMain/res/drawable/ic_launcher_background.xml new file mode 100644 index 00000000..07d5da9c --- /dev/null +++ b/sample/composeApp/src/androidMain/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sample/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher.xml b/sample/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 00000000..eca70cfe --- /dev/null +++ b/sample/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/sample/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher_round.xml b/sample/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 00000000..eca70cfe --- /dev/null +++ b/sample/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/sample/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher.png b/sample/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 00000000..a571e600 Binary files /dev/null and b/sample/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher.png differ diff --git a/sample/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher_round.png b/sample/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 00000000..61da551c Binary files /dev/null and b/sample/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/sample/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher.png b/sample/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 00000000..c41dd285 Binary files /dev/null and b/sample/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher.png differ diff --git a/sample/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher_round.png b/sample/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 00000000..db5080a7 Binary files /dev/null and b/sample/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/sample/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher.png b/sample/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 00000000..6dba46da Binary files /dev/null and b/sample/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/sample/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher_round.png b/sample/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 00000000..da31a871 Binary files /dev/null and b/sample/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/sample/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher.png b/sample/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 00000000..15ac6817 Binary files /dev/null and b/sample/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/sample/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher_round.png b/sample/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 00000000..b216f2d3 Binary files /dev/null and b/sample/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/sample/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher.png b/sample/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 00000000..f25a4197 Binary files /dev/null and b/sample/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/sample/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_round.png b/sample/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 00000000..e96783cc Binary files /dev/null and b/sample/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/sample/composeApp/src/androidMain/res/values/strings.xml b/sample/composeApp/src/androidMain/res/values/strings.xml new file mode 100644 index 00000000..a56cc825 --- /dev/null +++ b/sample/composeApp/src/androidMain/res/values/strings.xml @@ -0,0 +1,3 @@ + + WebRTC KMP Playground + \ No newline at end of file diff --git a/sample/composeApp/src/commonMain/kotlin/App.kt b/sample/composeApp/src/commonMain/kotlin/App.kt new file mode 100644 index 00000000..7cbdb24e --- /dev/null +++ b/sample/composeApp/src/commonMain/kotlin/App.kt @@ -0,0 +1,122 @@ +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.material.Button +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import co.touchlab.kermit.Logger +import co.touchlab.kermit.platformLogWriter +import com.shepeliev.webrtckmp.MediaDevices +import com.shepeliev.webrtckmp.MediaStream +import com.shepeliev.webrtckmp.PeerConnection +import com.shepeliev.webrtckmp.VideoStreamTrack +import com.shepeliev.webrtckmp.videoTracks +import kotlinx.coroutines.launch +import org.jetbrains.compose.ui.tooling.preview.Preview + +@Composable +@Preview +fun App() { + LaunchedEffect(Unit) { + Logger.setLogWriters(platformLogWriter()) + } + + MaterialTheme { + val scope = rememberCoroutineScope() + val (localStream, setLocalStream) = remember { mutableStateOf(null) } + val (remoteVideoTrack, setRemoteVideoTrack) = remember { mutableStateOf(null) } + val (peerConnections, setPeerConnections) = remember { + mutableStateOf?>(null) + } + + LaunchedEffect(localStream, peerConnections) { + if (peerConnections == null || localStream == null) return@LaunchedEffect + makeCall(peerConnections, localStream, setRemoteVideoTrack) + } + + Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) { + val localVideoTrack = localStream?.videoTracks?.firstOrNull() + + localVideoTrack?.let { Video(track = it, modifier = Modifier.weight(1f)) } + ?: Box(modifier = Modifier.weight(1f)) + + remoteVideoTrack?.let { Video(track = it, modifier = Modifier.weight(1f)) } + ?: Box(modifier = Modifier.weight(1f)) + + Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { + if (localStream == null) { + StartButton(onClick = { + scope.launch { + val stream = MediaDevices.getUserMedia(audio = true, video = true) + setLocalStream(stream) + } + }) + + return@MaterialTheme + } + + StopButton( + onClick = { + hangup(peerConnections, setPeerConnections, setRemoteVideoTrack) + localStream.release() + setLocalStream(null) + } + ) + + SwitchCameraButton( + onClick = { + scope.launch { localStream.videoTracks.firstOrNull()?.switchCamera() } + } + ) + + if (peerConnections == null) { + CallButton( + onClick = { setPeerConnections(Pair(PeerConnection(), PeerConnection())) }, + ) + } else { + HangupButton(onClick = { + hangup(peerConnections, setPeerConnections, setRemoteVideoTrack) + }) + } + } + } + } +} + +@Composable +private fun CallButton(onClick: () -> Unit, modifier: Modifier = Modifier) { + Button(onClick, modifier = modifier) { + Text("Call") + } +} + +@Composable +private fun HangupButton(onClick: () -> Unit, modifier: Modifier = Modifier) { + Button(onClick, modifier = modifier) { + Text("Hangup") + } +} + +@Composable +private fun SwitchCameraButton(onClick: () -> Unit, modifier: Modifier = Modifier) { + Button(onClick = onClick, modifier = modifier) { + Text("Switch Camera") + } +} + +@Composable +private fun StopButton(onClick: () -> Unit, modifier: Modifier = Modifier) { + Button(onClick = onClick, modifier = modifier) { + Text("Stop") + } +} diff --git a/sample/composeApp/src/commonMain/kotlin/Hangup.kt b/sample/composeApp/src/commonMain/kotlin/Hangup.kt new file mode 100644 index 00000000..034d1c3d --- /dev/null +++ b/sample/composeApp/src/commonMain/kotlin/Hangup.kt @@ -0,0 +1,15 @@ +import com.shepeliev.webrtckmp.PeerConnection +import com.shepeliev.webrtckmp.VideoStreamTrack + +fun hangup( + peerConnections: Pair?, + setPeerConnections: (Pair?) -> Unit, + setRemoteVideoTrack: (VideoStreamTrack?) -> Unit +) { + val (pc1, pc2) = peerConnections ?: return + pc1.getTransceivers().forEach { pc1.removeTrack(it.sender) } + pc1.close() + pc2.close() + setPeerConnections(null) + setRemoteVideoTrack(null) +} diff --git a/sample/composeApp/src/commonMain/kotlin/MakeCall.kt b/sample/composeApp/src/commonMain/kotlin/MakeCall.kt new file mode 100644 index 00000000..e2be7bc5 --- /dev/null +++ b/sample/composeApp/src/commonMain/kotlin/MakeCall.kt @@ -0,0 +1,95 @@ +import co.touchlab.kermit.Logger +import com.shepeliev.webrtckmp.IceCandidate +import com.shepeliev.webrtckmp.MediaStream +import com.shepeliev.webrtckmp.MediaStreamTrackKind +import com.shepeliev.webrtckmp.OfferAnswerOptions +import com.shepeliev.webrtckmp.PeerConnection +import com.shepeliev.webrtckmp.SignalingState +import com.shepeliev.webrtckmp.VideoStreamTrack +import com.shepeliev.webrtckmp.onConnectionStateChange +import com.shepeliev.webrtckmp.onIceCandidate +import com.shepeliev.webrtckmp.onIceConnectionStateChange +import com.shepeliev.webrtckmp.onSignalingStateChange +import com.shepeliev.webrtckmp.onTrack +import kotlinx.coroutines.awaitCancellation +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach + +suspend fun makeCall( + peerConnections: Pair, + localStream: MediaStream, + setRemoteVideoTrack: (VideoStreamTrack?) -> Unit +): Nothing = coroutineScope { + val (pc1, pc2) = peerConnections + localStream.tracks.forEach { pc1.addTrack(it) } + val pc1IceCandidates = mutableListOf() + val pc2IceCandidates = mutableListOf() + pc1.onIceCandidate + .onEach { Logger.d { "PC1 onIceCandidate: $it" } } + .onEach { + if (pc2.signalingState == SignalingState.HaveRemoteOffer) { + pc2.addIceCandidate(it) + } else { + pc1IceCandidates.add(it) + } + } + .launchIn(this) + pc2.onIceCandidate + .onEach { Logger.d { "PC2 onIceCandidate: $it" } } + .onEach { + if (pc1.signalingState == SignalingState.HaveRemoteOffer) { + pc1.addIceCandidate(it) + } else { + pc2IceCandidates.add(it) + } + } + .launchIn(this) + pc1.onSignalingStateChange + .onEach { signalingState -> + Logger.d { "PC1 onSignalingStateChange: $signalingState" } + if (signalingState == SignalingState.HaveRemoteOffer) { + pc2IceCandidates.forEach { pc1.addIceCandidate(it) } + pc2IceCandidates.clear() + } + } + .launchIn(this) + pc2.onSignalingStateChange + .onEach { signalingState -> + Logger.d { "PC2 onSignalingStateChange: $signalingState" } + if (signalingState == SignalingState.HaveRemoteOffer) { + pc1IceCandidates.forEach { pc2.addIceCandidate(it) } + pc1IceCandidates.clear() + } + } + .launchIn(this) + pc1.onIceConnectionStateChange + .onEach { Logger.d { "PC1 onIceConnectionStateChange: $it" } } + .launchIn(this) + pc2.onIceConnectionStateChange + .onEach { Logger.d { "PC2 onIceConnectionStateChange: $it" } } + .launchIn(this) + pc1.onConnectionStateChange + .onEach { Logger.d { "PC1 onConnectionStateChange: $it" } } + .launchIn(this) + pc2.onConnectionStateChange + .onEach { Logger.d { "PC2 onConnectionStateChange: $it" } } + .launchIn(this) + pc1.onTrack + .onEach { Logger.d { "PC1 onTrack: $it" } } + .launchIn(this) + pc2.onTrack + .onEach { Logger.d { "PC2 onTrack: ${it.track?.kind}" } } + .filter { it.track?.kind == MediaStreamTrackKind.Video } + .onEach { setRemoteVideoTrack(it.track as VideoStreamTrack) } + .launchIn(this) + val offer = pc1.createOffer(OfferAnswerOptions(offerToReceiveVideo = true, offerToReceiveAudio = true)) + pc1.setLocalDescription(offer) + pc2.setRemoteDescription(offer) + val answer = pc2.createAnswer(options = OfferAnswerOptions()) + pc2.setLocalDescription(answer) + pc1.setRemoteDescription(answer) + + awaitCancellation() +} diff --git a/sample/composeApp/src/commonMain/kotlin/StartButton.kt b/sample/composeApp/src/commonMain/kotlin/StartButton.kt new file mode 100644 index 00000000..331c7c98 --- /dev/null +++ b/sample/composeApp/src/commonMain/kotlin/StartButton.kt @@ -0,0 +1,5 @@ +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier + +@Composable +expect fun StartButton(onClick: () -> Unit, modifier: Modifier = Modifier) diff --git a/sample/composeApp/src/commonMain/kotlin/Video.kt b/sample/composeApp/src/commonMain/kotlin/Video.kt new file mode 100644 index 00000000..41449a61 --- /dev/null +++ b/sample/composeApp/src/commonMain/kotlin/Video.kt @@ -0,0 +1,6 @@ +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.shepeliev.webrtckmp.VideoStreamTrack + +@Composable +expect fun Video(track: VideoStreamTrack, modifier: Modifier = Modifier) diff --git a/sample/composeApp/src/iosMain/kotlin/MainViewController.kt b/sample/composeApp/src/iosMain/kotlin/MainViewController.kt new file mode 100644 index 00000000..6c54c55d --- /dev/null +++ b/sample/composeApp/src/iosMain/kotlin/MainViewController.kt @@ -0,0 +1,36 @@ +import WebRTC.RTCAudioSession +import WebRTC.RTCAudioSessionConfiguration +import WebRTC.setConfiguration +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.ui.window.ComposeUIViewController +import co.touchlab.kermit.Logger +import kotlinx.cinterop.BetaInteropApi +import kotlinx.cinterop.ExperimentalForeignApi +import kotlinx.cinterop.ObjCObjectVar +import kotlinx.cinterop.alloc +import kotlinx.cinterop.memScoped +import kotlinx.cinterop.ptr +import kotlinx.cinterop.value +import platform.Foundation.NSError + +@Suppress("unused", "FunctionName") +@OptIn(ExperimentalForeignApi::class, BetaInteropApi::class) +fun MainViewController() = ComposeUIViewController { + LaunchedEffect(Unit) { + RTCAudioSessionConfiguration.initialize() + memScoped { + val error = alloc>() + with(RTCAudioSession.sharedInstance()) { + lockForConfiguration() + useManualAudio = false + setConfiguration(RTCAudioSessionConfiguration.webRTCConfiguration(), error.ptr) + error.value?.let { + Logger.e { "Error setting WebRTC audio session configuration: ${it.localizedDescription}" } + } + unlockForConfiguration() + } + } + } + + App() +} diff --git a/sample/composeApp/src/iosMain/kotlin/StartButton.ios.kt b/sample/composeApp/src/iosMain/kotlin/StartButton.ios.kt new file mode 100644 index 00000000..62dc1b82 --- /dev/null +++ b/sample/composeApp/src/iosMain/kotlin/StartButton.ios.kt @@ -0,0 +1,11 @@ +import androidx.compose.material.Button +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier + +@Composable +actual fun StartButton(onClick: () -> Unit, modifier: Modifier) { + Button(onClick = onClick, modifier = modifier) { + Text("Start") + } +} diff --git a/sample/composeApp/src/iosMain/kotlin/Video.ios.kt b/sample/composeApp/src/iosMain/kotlin/Video.ios.kt new file mode 100644 index 00000000..2de7bab9 --- /dev/null +++ b/sample/composeApp/src/iosMain/kotlin/Video.ios.kt @@ -0,0 +1,21 @@ +import WebRTC.RTCMTLVideoView +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.interop.UIKitView +import com.shepeliev.webrtckmp.VideoStreamTrack +import kotlinx.cinterop.ExperimentalForeignApi +import platform.UIKit.UIViewContentMode + +@OptIn(ExperimentalForeignApi::class) +@Composable +actual fun Video(track: VideoStreamTrack, modifier: Modifier) { + UIKitView( + factory = { + RTCMTLVideoView().apply { + contentMode = UIViewContentMode.UIViewContentModeScaleAspectFit + track.addRenderer(this) + } + }, + modifier = modifier, + ) +} diff --git a/sample/composeApp/src/jsMain/kotlin/App.kt b/sample/composeApp/src/jsMain/kotlin/App.kt new file mode 100644 index 00000000..5829a316 --- /dev/null +++ b/sample/composeApp/src/jsMain/kotlin/App.kt @@ -0,0 +1,139 @@ +import com.shepeliev.webrtckmp.MediaDevices +import com.shepeliev.webrtckmp.MediaStream +import com.shepeliev.webrtckmp.PeerConnection +import com.shepeliev.webrtckmp.VideoStreamTrack +import emotion.react.css +import kotlinx.coroutines.launch +import mui.material.Button +import mui.material.ButtonVariant +import react.FC +import react.Props +import react.dom.html.ReactHTML.div +import react.dom.html.ReactHTML.h1 +import react.dom.html.ReactHTML.video +import react.useEffect +import react.useRef +import react.useState +import web.cssom.Display +import web.cssom.JustifyContent +import web.cssom.px +import web.html.HTMLVideoElement + +val ReactApp = FC { _ -> + h1 { +"WebRTC KMP Sample" } + + val scope = useCoroutineScope() + val localVideoRef = useRef(null) + val remoteVideoRef = useRef(null) + val (localStream, setLocalStream) = useState(null) + val (remoteVideoTrack, setRemoteVideoTrack) = useState(null) + val (peerConnections, setPeerConnections) = useState?>(null) + + useEffect(localStream) { + localVideoRef.current?.srcObject = localStream?.js + } + + useEffect(remoteVideoTrack) { + val stream = org.w3c.dom.mediacapture.MediaStream().apply { + remoteVideoTrack?.js?.let { addTrack(it) } + } + remoteVideoRef.current?.srcObject = stream + } + + useEffect(localStream, peerConnections) { + if (peerConnections == null || localStream == null) return@useEffect + val job = scope.launch { + makeCall( + peerConnections = peerConnections, + localStream = localStream, + setRemoteVideoTrack = { setRemoteVideoTrack(it) } + ) + } + + cleanup { job.cancel() } + } + + div { + video { + css { + width = 640.px + height = 480.px + paddingRight = 32.px + } + ref = localVideoRef + autoPlay = true + } + + video { + css { + width = 640.px + height = 480.px + } + ref = remoteVideoRef + autoPlay = true + } + } + + div { + css { + width = 640.px + display = Display.flex + justifyContent = JustifyContent.spaceBetween + } + + if (localStream == null) { + Button { + css { + width = 200.px + } + variant = ButtonVariant.contained + onClick = { + scope.launch { + val stream = MediaDevices.getUserMedia(audio = true, video = true) + setLocalStream(stream) + } + } + +"Start" + } + + return@div + } + + Button { + css { + width = 200.px + } + variant = ButtonVariant.contained + onClick = { + hangup(peerConnections, { setPeerConnections(it) }, { setRemoteVideoTrack(it) }) + localStream.release() + setLocalStream(null) + } + +"Stop" + } + + if (peerConnections == null) { + Button { + css { + width = 200.px + } + variant = ButtonVariant.contained + onClick = { + setPeerConnections(Pair(PeerConnection(), PeerConnection())) + } + +"Call" + } + } else { + Button { + css { + width = 200.px + } + variant = ButtonVariant.contained + onClick = { + hangup(peerConnections, { setPeerConnections(it) }, { setRemoteVideoTrack(it) }) + } + +"Hangup" + } + } + } +} diff --git a/sample/composeApp/src/jsMain/kotlin/Main.kt b/sample/composeApp/src/jsMain/kotlin/Main.kt new file mode 100644 index 00000000..77801aa2 --- /dev/null +++ b/sample/composeApp/src/jsMain/kotlin/Main.kt @@ -0,0 +1,17 @@ +import kotlinx.browser.document +import react.Fragment +import react.create +import react.dom.client.createRoot +import web.dom.Element + +fun main() { + val container = document.getElementById("root") ?: error("No root element.") + val root = createRoot(container as Element) + + root.render( + Fragment.create { + ReactApp { + } + } + ) +} diff --git a/sample/composeApp/src/jsMain/kotlin/StartButton.js.kt b/sample/composeApp/src/jsMain/kotlin/StartButton.js.kt new file mode 100644 index 00000000..56a0aa63 --- /dev/null +++ b/sample/composeApp/src/jsMain/kotlin/StartButton.js.kt @@ -0,0 +1,7 @@ +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier + +@Composable +actual fun StartButton(onClick: () -> Unit, modifier: Modifier) { + // Dummy actual for JS +} diff --git a/sample/composeApp/src/jsMain/kotlin/UseCoroutineScope.kt b/sample/composeApp/src/jsMain/kotlin/UseCoroutineScope.kt new file mode 100644 index 00000000..5ae43781 --- /dev/null +++ b/sample/composeApp/src/jsMain/kotlin/UseCoroutineScope.kt @@ -0,0 +1,12 @@ +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.cancel +import react.useEffect + +fun useCoroutineScope(): CoroutineScope { + val scope = CoroutineScope(Dispatchers.Main) + useEffect(Unit) { + cleanup { scope.cancel() } + } + return scope +} diff --git a/sample/composeApp/src/jsMain/kotlin/Video.js.kt b/sample/composeApp/src/jsMain/kotlin/Video.js.kt new file mode 100644 index 00000000..b93ab349 --- /dev/null +++ b/sample/composeApp/src/jsMain/kotlin/Video.js.kt @@ -0,0 +1,8 @@ +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.shepeliev.webrtckmp.VideoStreamTrack + +@Composable +actual fun Video(track: VideoStreamTrack, modifier: Modifier) { + // Dummy actual for JS +} diff --git a/sample/app-web/src/main/resources/index.html b/sample/composeApp/src/jsMain/resources/index.html similarity index 79% rename from sample/app-web/src/main/resources/index.html rename to sample/composeApp/src/jsMain/resources/index.html index f4b8adfa..878af099 100644 --- a/sample/app-web/src/main/resources/index.html +++ b/sample/composeApp/src/jsMain/resources/index.html @@ -6,6 +6,6 @@
- + diff --git a/sample/iosApp/Configuration/Config.xcconfig b/sample/iosApp/Configuration/Config.xcconfig new file mode 100644 index 00000000..96b2549d --- /dev/null +++ b/sample/iosApp/Configuration/Config.xcconfig @@ -0,0 +1,3 @@ +TEAM_ID=Q86C89UZUH +BUNDLE_ID=com.shepeliev.webrtckmp.sample.WebRTCKMPPlayground +APP_NAME=WebRTC KMP Playground \ No newline at end of file diff --git a/sample/iosApp/iosApp.xcodeproj/project.pbxproj b/sample/iosApp/iosApp.xcodeproj/project.pbxproj new file mode 100644 index 00000000..1fb7b0f7 --- /dev/null +++ b/sample/iosApp/iosApp.xcodeproj/project.pbxproj @@ -0,0 +1,421 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + 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 */; }; + FA64F57B2BD3B81C008C0A82 /* WebRTC in Frameworks */ = {isa = PBXBuildFile; productRef = FA64F57A2BD3B81C008C0A82 /* WebRTC */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 058557BA273AAA24004C7B11 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; + 2152FB032600AC8F00CF470E /* iOSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iOSApp.swift; sourceTree = ""; }; + 7555FF7B242A565900829871 /* iosApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; name = iosApp.app; path = "WebRTC KMP Playground.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 7555FF82242A565900829871 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + 7555FF8C242A565B00829871 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + AB3632DC29227652001CCB65 /* Config.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + B92378962B6B1156000C7307 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + FA64F57B2BD3B81C008C0A82 /* WebRTC in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 058557D7273AAEEB004C7B11 /* Preview Content */ = { + isa = PBXGroup; + children = ( + 058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */, + ); + path = "Preview Content"; + sourceTree = ""; + }; + 42799AB246E5F90AF97AA0EF /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; + 7555FF72242A565900829871 = { + isa = PBXGroup; + children = ( + AB1DB47929225F7C00F7AF9C /* Configuration */, + 7555FF7D242A565900829871 /* iosApp */, + 7555FF7C242A565900829871 /* Products */, + 42799AB246E5F90AF97AA0EF /* Frameworks */, + ); + sourceTree = ""; + }; + 7555FF7C242A565900829871 /* Products */ = { + isa = PBXGroup; + children = ( + 7555FF7B242A565900829871 /* iosApp.app */, + ); + name = Products; + sourceTree = ""; + }; + 7555FF7D242A565900829871 /* iosApp */ = { + isa = PBXGroup; + children = ( + 058557BA273AAA24004C7B11 /* Assets.xcassets */, + 7555FF82242A565900829871 /* ContentView.swift */, + 7555FF8C242A565B00829871 /* Info.plist */, + 2152FB032600AC8F00CF470E /* iOSApp.swift */, + 058557D7273AAEEB004C7B11 /* Preview Content */, + ); + path = iosApp; + sourceTree = ""; + }; + AB1DB47929225F7C00F7AF9C /* Configuration */ = { + isa = PBXGroup; + children = ( + AB3632DC29227652001CCB65 /* Config.xcconfig */, + ); + path = Configuration; + sourceTree = ""; + }; +/* 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 = ( + FA64F57A2BD3B81C008C0A82 /* WebRTC */, + ); + productName = iosApp; + productReference = 7555FF7B242A565900829871 /* iosApp.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 7555FF73242A565900829871 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1130; + LastUpgradeCheck = 1130; + ORGANIZATIONNAME = orgName; + TargetAttributes = { + 7555FF7A242A565900829871 = { + CreatedOnToolsVersion = 11.3.1; + }; + }; + }; + buildConfigurationList = 7555FF76242A565900829871 /* Build configuration list for PBXProject "iosApp" */; + compatibilityVersion = "Xcode 12.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 7555FF72242A565900829871; + packageReferences = ( + FA64F5792BD3B81C008C0A82 /* XCRemoteSwiftPackageReference "Specs" */, + ); + 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/../..\"\npwd\n./gradlew :sample: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; + 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; + 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 = ( + "$(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", + ); + OTHER_LDFLAGS = ( + "$(inherited)", + "-framework", + composeApp, + ); + 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 = ( + "$(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", + ); + OTHER_LDFLAGS = ( + "$(inherited)", + "-framework", + composeApp, + ); + 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 */ + FA64F5792BD3B81C008C0A82 /* XCRemoteSwiftPackageReference "Specs" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/webrtc-sdk/Specs"; + requirement = { + kind = exactVersion; + version = 114.5735.9; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + FA64F57A2BD3B81C008C0A82 /* WebRTC */ = { + isa = XCSwiftPackageProductDependency; + package = FA64F5792BD3B81C008C0A82 /* XCRemoteSwiftPackageReference "Specs" */; + productName = WebRTC; + }; +/* End XCSwiftPackageProductDependency section */ + }; + rootObject = 7555FF73242A565900829871 /* Project object */; +} diff --git a/sample/app-ios/app-ios.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/sample/iosApp/iosApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from sample/app-ios/app-ios.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to sample/iosApp/iosApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/sample/app-ios/app-ios.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/sample/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from sample/app-ios/app-ios.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to sample/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/sample/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/sample/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 00000000..fdff2912 --- /dev/null +++ b/sample/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,14 @@ +{ + "pins" : [ + { + "identity" : "specs", + "kind" : "remoteSourceControl", + "location" : "https://github.com/webrtc-sdk/Specs", + "state" : { + "revision" : "fa02befe57f72c52d48d913b46ae183f6b63e042", + "version" : "114.5735.9" + } + } + ], + "version" : 2 +} diff --git a/sample/app-ios/app-ios/Assets.xcassets/AccentColor.colorset/Contents.json b/sample/iosApp/iosApp/Assets.xcassets/AccentColor.colorset/Contents.json similarity index 98% rename from sample/app-ios/app-ios/Assets.xcassets/AccentColor.colorset/Contents.json rename to sample/iosApp/iosApp/Assets.xcassets/AccentColor.colorset/Contents.json index eb878970..ee7e3ca0 100644 --- a/sample/app-ios/app-ios/Assets.xcassets/AccentColor.colorset/Contents.json +++ b/sample/iosApp/iosApp/Assets.xcassets/AccentColor.colorset/Contents.json @@ -8,4 +8,4 @@ "author" : "xcode", "version" : 1 } -} +} \ No newline at end of file diff --git a/sample/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/Contents.json b/sample/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..8edf56e7 --- /dev/null +++ b/sample/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,14 @@ +{ + "images" : [ + { + "filename" : "app-icon-1024.png", + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/sample/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/app-icon-1024.png b/sample/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/app-icon-1024.png new file mode 100644 index 00000000..53fc536f Binary files /dev/null and b/sample/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/app-icon-1024.png differ diff --git a/sample/app-ios/app-ios/Assets.xcassets/Contents.json b/sample/iosApp/iosApp/Assets.xcassets/Contents.json similarity index 96% rename from sample/app-ios/app-ios/Assets.xcassets/Contents.json rename to sample/iosApp/iosApp/Assets.xcassets/Contents.json index 73c00596..4aa7c535 100644 --- a/sample/app-ios/app-ios/Assets.xcassets/Contents.json +++ b/sample/iosApp/iosApp/Assets.xcassets/Contents.json @@ -3,4 +3,4 @@ "author" : "xcode", "version" : 1 } -} +} \ No newline at end of file diff --git a/sample/iosApp/iosApp/ContentView.swift b/sample/iosApp/iosApp/ContentView.swift new file mode 100644 index 00000000..3cd5c325 --- /dev/null +++ b/sample/iosApp/iosApp/ContentView.swift @@ -0,0 +1,21 @@ +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 + } +} + + + diff --git a/sample/iosApp/iosApp/Info.plist b/sample/iosApp/iosApp/Info.plist new file mode 100644 index 00000000..273e44a5 --- /dev/null +++ b/sample/iosApp/iosApp/Info.plist @@ -0,0 +1,54 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + CADisableMinimumFrameDurationOnPhone + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + + UILaunchScreen + + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + NSCameraUsageDescription + Access to the camera is required. + NSMicrophoneUsageDescription + Access to the microphone is required. + + diff --git a/sample/iosApp/iosApp/Preview Content/Preview Assets.xcassets/Contents.json b/sample/iosApp/iosApp/Preview Content/Preview Assets.xcassets/Contents.json new file mode 100644 index 00000000..4aa7c535 --- /dev/null +++ b/sample/iosApp/iosApp/Preview Content/Preview Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} \ No newline at end of file diff --git a/sample/iosApp/iosApp/iOSApp.swift b/sample/iosApp/iosApp/iOSApp.swift new file mode 100644 index 00000000..0648e860 --- /dev/null +++ b/sample/iosApp/iosApp/iOSApp.swift @@ -0,0 +1,10 @@ +import SwiftUI + +@main +struct iOSApp: App { + var body: some Scene { + WindowGroup { + ContentView() + } + } +} \ No newline at end of file diff --git a/sample/shared/build.gradle.kts b/sample/shared/build.gradle.kts deleted file mode 100644 index b6386e33..00000000 --- a/sample/shared/build.gradle.kts +++ /dev/null @@ -1,68 +0,0 @@ -import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType - -plugins { - id("multiplatform-setup") - kotlin("native.cocoapods") -} - -kotlin { - cocoapods { - version = "1.0.0" - summary = "Shared framework for WebRTC KMP sample" - homepage = "https://github.com/shepeliev/webrtc-kmp/tree/main/sample" - ios.deploymentTarget = "11.0" - - pod("FirebaseCore") - pod("FirebaseFirestore") - pod("WebRTC-SDK") { - version = "114.5735.02" - linkOnly = true - } - - podfile = project.file("../app-ios/Podfile") - - framework { - baseName = "shared" - export(project(":webrtc-kmp")) - export(deps.decompose) - transitiveExport = true - } - - xcodeConfigurationToNativeBuildType["CUSTOM_DEBUG"] = NativeBuildType.DEBUG - xcodeConfigurationToNativeBuildType["CUSTOM_RELEASE"] = NativeBuildType.RELEASE - } - - androidTarget() - - iosX64() - iosArm64() - iosSimulatorArm64() - - js { - useCommonJs() - browser() - } - - sourceSets { - commonMain.dependencies { - api(project(":webrtc-kmp")) - api(deps.decompose) - implementation(deps.kotlin.coroutines) - implementation(deps.kermit) - } - - androidMain.dependencies { - implementation(project.dependencies.platform(deps.firebase.bom)) - implementation(deps.firebase.firestore) - implementation(deps.kotlin.coroutinesPlayServices) - } - - jsMain.dependencies { - implementation(npm("firebase", version = "9.9.1")) - } - } -} - -android { - namespace = "com.shepeliev.webrtckmp.sample.shared" -} diff --git a/sample/shared/src/androidMain/kotlin/com/shepeliev/webrtckmp/sample/shared/RoomDataSource.kt b/sample/shared/src/androidMain/kotlin/com/shepeliev/webrtckmp/sample/shared/RoomDataSource.kt deleted file mode 100644 index 57a2b3d8..00000000 --- a/sample/shared/src/androidMain/kotlin/com/shepeliev/webrtckmp/sample/shared/RoomDataSource.kt +++ /dev/null @@ -1,98 +0,0 @@ -@file:JvmName("AndroidRoomDataSource") - -package com.shepeliev.webrtckmp.sample.shared - -import com.google.firebase.firestore.DocumentChange -import com.google.firebase.firestore.ktx.firestore -import com.google.firebase.ktx.Firebase -import kotlinx.coroutines.channels.awaitClose -import kotlinx.coroutines.channels.trySendBlocking -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.callbackFlow -import kotlinx.coroutines.suspendCancellableCoroutine -import kotlinx.coroutines.tasks.await -import java.util.Date -import kotlin.coroutines.resume -import kotlin.coroutines.resumeWithException - -actual class RoomDataSource actual constructor() { - - private val firestore by lazy { Firebase.firestore } - private val roomsRef by lazy { firestore.collection("rooms") } - - actual fun createRoom(): String { - return roomsRef.document().id - } - - actual suspend fun insertOffer(roomId: String, description: SessionDescription) { - roomsRef.document(roomId).set( - mapOf( - "offer" to description.sdp, - "expireAt" to getExpireAtTime() - ) - ).await() - } - - actual suspend fun insertAnswer(roomId: String, description: SessionDescription) { - roomsRef.document(roomId).update(mapOf("answer" to description.sdp)).await() - } - - actual suspend fun insertIceCandidate(roomId: String, peerName: String, candidate: IceCandidate) { - roomsRef.document(roomId) - .collection(peerName) - .add( - mapOf( - "candidate" to candidate.candidate, - "sdpMLineIndex" to candidate.sdpMLineIndex, - "sdpMid" to candidate.sdpMid, - "expireAt" to getExpireAtTime(), - ) - ) - .await() - } - - private fun getExpireAtTime(): Date { - val expireAt = System.currentTimeMillis() + FIRESTORE_DOCUMENT_TTL_SECONDS * 1000 - return Date(expireAt) - } - - actual suspend fun getOffer(roomId: String): SessionDescription? { - val snapshot = roomsRef.document(roomId).get().await() - val offerSdp = snapshot.takeIf { it.exists() }?.getString("offer") - return offerSdp?.let { SessionDescription(SessionDescriptionType.Offer, it) } - } - - actual suspend fun getAnswer(roomId: String): SessionDescription = suspendCancellableCoroutine { cont -> - val registration = roomsRef.document(roomId).addSnapshotListener { value, error -> - val answer = value?.data?.get("answer") as? String - when { - answer != null -> cont.resume(SessionDescription(SessionDescriptionType.Answer, answer)) - error != null -> cont.resumeWithException(error) - } - } - - cont.invokeOnCancellation { registration.remove() } - } - - actual fun observeIceCandidates(roomId: String, peerName: String): Flow = callbackFlow { - val registration = roomsRef.document(roomId).collection(peerName).addSnapshotListener { value, error -> - if (error != null) { - channel.close(error) - } - - val dc = value?.documentChanges ?: return@addSnapshotListener - - dc.filter { it.type == DocumentChange.Type.ADDED } - .map { - IceCandidate( - sdpMid = it.document.data["sdpMid"] as String, - sdpMLineIndex = (it.document.data["sdpMLineIndex"] as Long).toInt(), - candidate = it.document.data["candidate"] as String, - ) - } - .forEach { trySendBlocking(it) } - } - - awaitClose { registration.remove() } - } -} diff --git a/sample/shared/src/commonMain/kotlin/com/shepeliev/webrtckmp/sample/shared/Room.kt b/sample/shared/src/commonMain/kotlin/com/shepeliev/webrtckmp/sample/shared/Room.kt deleted file mode 100644 index 6e997ad8..00000000 --- a/sample/shared/src/commonMain/kotlin/com/shepeliev/webrtckmp/sample/shared/Room.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.shepeliev.webrtckmp.sample.shared - -import com.arkivanov.decompose.value.Value -import com.shepeliev.webrtckmp.MediaStream - -interface Room { - - val model: Value - - fun openUserMedia() - fun switchCamera() - fun createRoom() - fun joinRoom(roomId: String) - fun hangup() - - data class Model( - val localStream: MediaStream? = null, - val remoteStream: MediaStream? = null, - val roomId: String? = null, - val isCaller: Boolean? = null, - val isJoining: Boolean = false, - ) -} diff --git a/sample/shared/src/commonMain/kotlin/com/shepeliev/webrtckmp/sample/shared/RoomComponent.kt b/sample/shared/src/commonMain/kotlin/com/shepeliev/webrtckmp/sample/shared/RoomComponent.kt deleted file mode 100644 index f4df3f56..00000000 --- a/sample/shared/src/commonMain/kotlin/com/shepeliev/webrtckmp/sample/shared/RoomComponent.kt +++ /dev/null @@ -1,249 +0,0 @@ -package com.shepeliev.webrtckmp.sample.shared - -import co.touchlab.kermit.Logger -import co.touchlab.kermit.platformLogWriter -import com.arkivanov.decompose.ComponentContext -import com.arkivanov.decompose.value.MutableValue -import com.arkivanov.decompose.value.Value -import com.arkivanov.decompose.value.reduce -import com.arkivanov.essenty.instancekeeper.InstanceKeeper -import com.arkivanov.essenty.instancekeeper.getOrCreate -import com.arkivanov.essenty.lifecycle.doOnCreate -import com.arkivanov.essenty.lifecycle.doOnDestroy -import com.arkivanov.essenty.lifecycle.doOnPause -import com.arkivanov.essenty.lifecycle.doOnResume -import com.arkivanov.essenty.lifecycle.doOnStart -import com.arkivanov.essenty.lifecycle.doOnStop -import com.shepeliev.webrtckmp.IceServer -import com.shepeliev.webrtckmp.MediaDevices -import com.shepeliev.webrtckmp.MediaStreamTrack -import com.shepeliev.webrtckmp.MediaStreamTrackKind -import com.shepeliev.webrtckmp.MediaStreamTrackState -import com.shepeliev.webrtckmp.OfferAnswerOptions -import com.shepeliev.webrtckmp.PeerConnection -import com.shepeliev.webrtckmp.RtcConfiguration -import com.shepeliev.webrtckmp.audioTracks -import com.shepeliev.webrtckmp.onConnectionStateChange -import com.shepeliev.webrtckmp.onIceCandidate -import com.shepeliev.webrtckmp.onIceConnectionStateChange -import com.shepeliev.webrtckmp.onIceGatheringState -import com.shepeliev.webrtckmp.onSignalingStateChange -import com.shepeliev.webrtckmp.onTrack -import com.shepeliev.webrtckmp.videoTracks -import kotlinx.coroutines.Job -import kotlinx.coroutines.MainScope -import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.cancel -import kotlinx.coroutines.flow.catch -import kotlinx.coroutines.flow.filter -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.launch -import kotlinx.coroutines.plus - -class RoomComponent( - componentContext: ComponentContext, - viewModel: Room, -) : Room by viewModel, ComponentContext by componentContext { - - constructor(componentContext: ComponentContext) : this(componentContext, componentContext.instanceKeeper.getOrCreate { ViewModel() }) - - private val logger = Logger.withTag("RoomComponent") - - init { - Logger.setLogWriters(platformLogWriter()) - - lifecycle.doOnCreate { logger.d { "onCreate" } } - lifecycle.doOnStart { logger.d { "onStart" } } - lifecycle.doOnResume { logger.d { "onResume" } } - lifecycle.doOnPause { logger.d { "onPause" } } - lifecycle.doOnStop { logger.d { "onStop" } } - lifecycle.doOnDestroy { logger.d { "onDestroy" } } - } - - private class ViewModel : InstanceKeeper.Instance, Room { - - private val logger = Logger.withTag("RoomComponent => ViewModel") - private val _model = MutableValue(Room.Model()) - override val model: Value get() = _model - - private val scope = MainScope() - - private val roomDataSource = RoomDataSource() - private var peerConnection: PeerConnection? = null - private var roomSessionJob: Job? = null - - override fun openUserMedia() { - logger.i { "Open user media" } - roomSessionJob = SupervisorJob() - - scope.launch { - try { - val stream = MediaDevices.getUserMedia(audio = true, video = true) - _model.reduce { it.copy(localStream = stream) } - listenTrackState(stream.videoTracks.first(), "Local video") - } catch (e: Throwable) { - logger.e(e) { "Getting user media failed" } - } - } - } - - override fun switchCamera() { - logger.i { "Switch camera" } - scope.launch { - model.value.localStream?.videoTracks?.first()?.switchCamera() - logger.i { "Camera switched" } - } - } - - override fun createRoom() { - logger.i { "Create room" } - - _model.reduce { it.copy(isJoining = true, isCaller = true) } - val peerConnection = createPeerConnection() - this@ViewModel.peerConnection = peerConnection - - scope.launch { - val roomId = roomDataSource.createRoom() - logger.d { "Room ID: $roomId" } - - collectIceCandidates(peerConnection, roomId, "caller", "callee") - - val offer = peerConnection.createOffer(DefaultOfferAnswerOptions).also { - peerConnection.setLocalDescription(it) - } - - roomDataSource.insertOffer(roomId, offer) - _model.reduce { it.copy(roomId = roomId, isJoining = false) } - - logger.d { "Waiting answer" } - val answer = roomDataSource.getAnswer(roomId) - logger.d { "Answer received." } - peerConnection.setRemoteDescription(answer) - } - } - - override fun joinRoom(roomId: String) { - logger.i { "Join room: $roomId" } - - _model.reduce { it.copy(isJoining = true, roomId = roomId, isCaller = false) } - roomSessionJob = SupervisorJob() - - val peerConnection = createPeerConnection() - this@ViewModel.peerConnection = peerConnection - - scope.launch { - val offer = roomDataSource.getOffer(roomId) - if (offer == null) { - logger.e { "No offer SDP in the room [id = $roomId]" } - _model.reduce { it.copy(isJoining = false, isCaller = null) } - return@launch - } - - collectIceCandidates(peerConnection, roomId, "callee", "caller") - - peerConnection.setRemoteDescription(offer) - peerConnection.createAnswer(DefaultOfferAnswerOptions).also { - peerConnection.setLocalDescription(it) - roomDataSource.insertAnswer(roomId, it) - } - - _model.reduce { it.copy(isJoining = false) } - } - } - - private fun createPeerConnection(): PeerConnection { - logger.i { "Create PeerConnection." } - val peerConnection = PeerConnection(DefaultRtcConfig) - - model.value.localStream?.let { - peerConnection.addTrack(it.audioTracks.first(), it) - peerConnection.addTrack(it.videoTracks.first(), it) - } - - listenRemoteTracks(peerConnection) - registerListeners(peerConnection) - return peerConnection - } - - private fun registerListeners(peerConnection: PeerConnection) { - peerConnection.onIceGatheringState - .onEach { logger.i { "ICE gathering state changed: $it" } } - .launchIn(scope + roomSessionJob!!) - - peerConnection.onConnectionStateChange - .onEach { logger.i { "Connection state changed: $it" } } - .launchIn(scope + roomSessionJob!!) - - peerConnection.onSignalingStateChange - .onEach { logger.i { "Signaling state changed: $it" } } - .launchIn(scope + roomSessionJob!!) - - peerConnection.onIceConnectionStateChange - .onEach { logger.i { "ICE connection state changed: $it" } } - .launchIn(scope + roomSessionJob!!) - } - - private fun listenRemoteTracks(peerConnection: PeerConnection) { - peerConnection.onTrack - .onEach { logger.i { "Remote track received: [id = ${it.track?.id}, kind: ${it.track?.kind} ]" } } - .filter { it.track?.kind == MediaStreamTrackKind.Video } - .onEach { event -> _model.reduce { it.copy(remoteStream = event.streams.first()) } } - .onEach { listenTrackState(it.track!!, "Remote video") } - .launchIn(scope + roomSessionJob!!) - } - - private fun listenTrackState(track: MediaStreamTrack, logPrefix: String) { - track.state - .filter { it is MediaStreamTrackState.Live } - .onEach { logger.w { "$logPrefix track [id = ${track.id}] state changed: $it" } } - .launchIn(scope + roomSessionJob!!) - } - - private fun collectIceCandidates( - peerConnection: PeerConnection, - roomId: String, - localName: String, - remoteName: String - ) { - peerConnection.onIceCandidate - .onEach { logger.i { "New local ICE candidate: $it" } } - .onEach { roomDataSource.insertIceCandidate(roomId, localName, it) } - .launchIn(scope + roomSessionJob!!) - - roomDataSource.observeIceCandidates(roomId, remoteName) - .catch { logger.e(it) { "Observing ice candidate failed [roomId = $roomId, peerName = $remoteName]" } } - .onEach { logger.d { "New remote ICE candidate: $it" } } - .onEach(peerConnection::addIceCandidate) - .launchIn(scope + roomSessionJob!!) - } - - override fun hangup() { - logger.i { "Hangup" } - - roomSessionJob?.cancel() - roomSessionJob = null - _model.value.localStream?.release() - _model.reduce { Room.Model() } - - peerConnection?.close() - peerConnection = null - } - - override fun onDestroy() { - logger.i { "Destroy" } - scope.cancel() - } - } -} - -private val DefaultRtcConfig = RtcConfiguration( - iceServers = listOf( - IceServer(listOf("stun:stun1.l.google.com:19302", "stun:stun2.l.google.com:19302")), - ) -) - -private val DefaultOfferAnswerOptions = OfferAnswerOptions( - offerToReceiveVideo = true, - offerToReceiveAudio = true, -) diff --git a/sample/shared/src/commonMain/kotlin/com/shepeliev/webrtckmp/sample/shared/RoomDataSource.kt b/sample/shared/src/commonMain/kotlin/com/shepeliev/webrtckmp/sample/shared/RoomDataSource.kt deleted file mode 100644 index ea151162..00000000 --- a/sample/shared/src/commonMain/kotlin/com/shepeliev/webrtckmp/sample/shared/RoomDataSource.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.shepeliev.webrtckmp.sample.shared - -import kotlinx.coroutines.flow.Flow - -typealias SessionDescription = com.shepeliev.webrtckmp.SessionDescription -typealias IceCandidate = com.shepeliev.webrtckmp.IceCandidate -typealias SessionDescriptionType = com.shepeliev.webrtckmp.SessionDescriptionType - -expect class RoomDataSource() { - fun createRoom(): String - suspend fun insertOffer(roomId: String, description: SessionDescription) - suspend fun insertAnswer(roomId: String, description: SessionDescription) - suspend fun insertIceCandidate(roomId: String, peerName: String, candidate: IceCandidate) - suspend fun getOffer(roomId: String): SessionDescription? - suspend fun getAnswer(roomId: String): SessionDescription - fun observeIceCandidates(roomId: String, peerName: String): Flow -} - -internal const val FIRESTORE_DOCUMENT_TTL_SECONDS = 60 * 60 * 5 // 5 hours diff --git a/sample/shared/src/iosMain/kotlin/com/shepeliev/webrtckmp/sample/shared/RoomDataSource.kt b/sample/shared/src/iosMain/kotlin/com/shepeliev/webrtckmp/sample/shared/RoomDataSource.kt deleted file mode 100644 index 22601538..00000000 --- a/sample/shared/src/iosMain/kotlin/com/shepeliev/webrtckmp/sample/shared/RoomDataSource.kt +++ /dev/null @@ -1,143 +0,0 @@ -package com.shepeliev.webrtckmp.sample.shared - -import cocoapods.FirebaseCore.FIRApp -import cocoapods.FirebaseFirestore.FIRDocumentChange -import cocoapods.FirebaseFirestore.FIRDocumentChangeType -import cocoapods.FirebaseFirestore.FIRDocumentSnapshot -import cocoapods.FirebaseFirestore.FIRFirestore -import cocoapods.FirebaseFirestore.FIRQuerySnapshot -import com.shepeliev.webrtckmp.SessionDescription -import kotlinx.coroutines.channels.awaitClose -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.callbackFlow -import kotlinx.coroutines.suspendCancellableCoroutine -import platform.Foundation.NSDate -import platform.Foundation.NSError -import platform.Foundation.dateByAddingTimeInterval -import kotlin.coroutines.resume -import kotlin.coroutines.resumeWithException - -actual class RoomDataSource actual constructor() { - - private val roomsRef by lazy { - FIRApp.configure() - FIRFirestore.firestore().collectionWithPath("rooms") - } - - actual fun createRoom(): String { - return roomsRef.documentWithAutoID().documentID - } - - actual suspend fun insertOffer(roomId: String, description: SessionDescription) = - suspendCancellableCoroutine { cont -> - roomsRef.documentWithPath(roomId) - .setData( - documentData = mapOf( - "offer" to description.sdp, - "expireAt" to getExpireAtTime() - ), - merge = true, - completion = { error -> - error - ?.let { cont.resumeWithException(Exception(it.description)) } - ?: cont.resume(Unit) - } - ) - } - - actual suspend fun insertAnswer(roomId: String, description: SessionDescription) = - suspendCancellableCoroutine { cont -> - roomsRef.documentWithPath(roomId) - .updateData( - fields = mapOf( - "answer" to description.sdp, - "expireAt" to getExpireAtTime() - ), - completion = { error -> - error - ?.let { cont.resumeWithException(Exception(it.description)) } - ?: cont.resume(Unit) - } - ) - } - - actual suspend fun insertIceCandidate(roomId: String, peerName: String, candidate: IceCandidate) = - suspendCancellableCoroutine { cont -> - roomsRef - .documentWithPath(roomId) - .collectionWithPath(peerName) - .documentWithAutoID() - .setData( - documentData = mapOf( - "candidate" to candidate.candidate, - "sdpMLineIndex" to candidate.sdpMLineIndex, - "sdpMid" to candidate.sdpMid, - "expireAt" to getExpireAtTime(), - ), - completion = { error -> - error - ?.let { cont.resumeWithException(Exception(it.description)) } - ?: cont.resume(Unit) - } - ) - } - - actual suspend fun getOffer(roomId: String): SessionDescription? = suspendCancellableCoroutine { cont -> - roomsRef.documentWithPath(roomId).getDocumentWithCompletion { snapshot, error -> - error?.let { cont.resumeWithException(Exception(it.description)) } - val offerSdp = snapshot - ?.takeIf { it.exists } - ?.data() - ?.get("offer") as? String - cont.resume(offerSdp?.let { SessionDescription(SessionDescriptionType.Offer, it) }) - } - } - - actual suspend fun getAnswer(roomId: String): SessionDescription = suspendCancellableCoroutine { cont -> - val snapshotListener = { snapshot: FIRDocumentSnapshot?, error: NSError? -> - if (cont.isActive) { - error?.let { cont.resumeWithException(Exception(it.description)) } - val answer = snapshot?.data()?.get("answer") as? String - answer?.let { cont.resume(SessionDescription(SessionDescriptionType.Answer, it)) } - } - Unit - } - - val registration = roomsRef - .documentWithPath(roomId) - .addSnapshotListener(snapshotListener) - - cont.invokeOnCancellation { registration.remove() } - } - - actual fun observeIceCandidates(roomId: String, peerName: String): Flow = callbackFlow { - val listener = { snapshot: FIRQuerySnapshot?, error: NSError? -> - error?.let { channel.close(Exception(it.description)) } - - snapshot?.documentChanges - ?.map { it as FIRDocumentChange } - ?.filter { it.type == FIRDocumentChangeType.FIRDocumentChangeTypeAdded } - ?.map { - IceCandidate( - sdpMid = it.document.data()["sdpMid"] as String, - sdpMLineIndex = (it.document.data()["sdpMLineIndex"] as Long).toInt(), - candidate = it.document.data()["candidate"] as String, - ) - } - ?.forEach { trySend(it) } - - Unit - } - - val registration = roomsRef - .documentWithPath(roomId) - .collectionWithPath(peerName) - .addSnapshotListener(listener) - - awaitClose { registration.remove() } - } - - private fun getExpireAtTime(): NSDate { - return NSDate().dateByAddingTimeInterval(FIRESTORE_DOCUMENT_TTL_SECONDS.toDouble()) - } -} diff --git a/sample/shared/src/jsMain/kotlin/com/shepeliev/webrtckmp/sample/shared/DocumentSnapshotObserver.kt b/sample/shared/src/jsMain/kotlin/com/shepeliev/webrtckmp/sample/shared/DocumentSnapshotObserver.kt deleted file mode 100644 index cc914ebb..00000000 --- a/sample/shared/src/jsMain/kotlin/com/shepeliev/webrtckmp/sample/shared/DocumentSnapshotObserver.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.shepeliev.webrtckmp.sample.shared - -data class DocumentSnapshotObserver( - @JsName("next") - val next: (DocumentSnapshot) -> Unit, - @JsName("error") - val error: (Throwable) -> Unit, - @JsName("complete") - val complete: () -> Unit, -) diff --git a/sample/shared/src/jsMain/kotlin/com/shepeliev/webrtckmp/sample/shared/FirebaseApp.kt b/sample/shared/src/jsMain/kotlin/com/shepeliev/webrtckmp/sample/shared/FirebaseApp.kt deleted file mode 100644 index 6dbfed66..00000000 --- a/sample/shared/src/jsMain/kotlin/com/shepeliev/webrtckmp/sample/shared/FirebaseApp.kt +++ /dev/null @@ -1,10 +0,0 @@ -@file:JsModule("firebase/app") -@file:JsNonModule - -package com.shepeliev.webrtckmp.sample.shared - -import kotlin.js.Json - -external class FirebaseApp - -external fun initializeApp(config: Json): FirebaseApp diff --git a/sample/shared/src/jsMain/kotlin/com/shepeliev/webrtckmp/sample/shared/Firestore.kt b/sample/shared/src/jsMain/kotlin/com/shepeliev/webrtckmp/sample/shared/Firestore.kt deleted file mode 100644 index 57c3ee11..00000000 --- a/sample/shared/src/jsMain/kotlin/com/shepeliev/webrtckmp/sample/shared/Firestore.kt +++ /dev/null @@ -1,52 +0,0 @@ -@file:JsModule("firebase/firestore") -@file:JsNonModule - -package com.shepeliev.webrtckmp.sample.shared - -import kotlin.js.Json -import kotlin.js.Promise - -external class Firestore - -external interface Query - -external interface CollectionReference : Query - -external interface DocumentReference { - val id: String -} - -external interface DocumentSnapshot { - val id: String - fun data(): Json - fun exists(): Boolean -} - -external interface DocumentChange { - val doc: DocumentSnapshot - val type: String -} - -external interface QuerySnapshot { - fun docChanges(): Array -} - -external fun getFirestore(app: FirebaseApp): Firestore - -external fun collection(firestore: Firestore, path: String): CollectionReference - -external fun collection(reference: CollectionReference, path: String): CollectionReference - -external fun doc(reference: CollectionReference, path: String? = definedExternally): DocumentReference - -external fun addDoc(reference: CollectionReference, data: Json): Promise - -external fun setDoc(reference: DocumentReference, data: Json): Promise - -external fun updateDoc(reference: DocumentReference, data: Json): Promise - -external fun getDoc(reference: DocumentReference): Promise - -external fun onSnapshot(query: Query, observer: QuerySnapshotObserver): () -> Unit - -external fun onSnapshot(reference: DocumentReference, observer: DocumentSnapshotObserver): () -> Unit diff --git a/sample/shared/src/jsMain/kotlin/com/shepeliev/webrtckmp/sample/shared/QuerySnapshotObserver.kt b/sample/shared/src/jsMain/kotlin/com/shepeliev/webrtckmp/sample/shared/QuerySnapshotObserver.kt deleted file mode 100644 index d9c6e447..00000000 --- a/sample/shared/src/jsMain/kotlin/com/shepeliev/webrtckmp/sample/shared/QuerySnapshotObserver.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.shepeliev.webrtckmp.sample.shared - -data class QuerySnapshotObserver( - @JsName("next") - val next: (QuerySnapshot) -> Unit, - @JsName("error") - val error: (Throwable) -> Unit, - @JsName("complete") - val complete: () -> Unit, -) diff --git a/sample/shared/src/jsMain/kotlin/com/shepeliev/webrtckmp/sample/shared/RoomDataSource.kt b/sample/shared/src/jsMain/kotlin/com/shepeliev/webrtckmp/sample/shared/RoomDataSource.kt deleted file mode 100644 index 760ca30a..00000000 --- a/sample/shared/src/jsMain/kotlin/com/shepeliev/webrtckmp/sample/shared/RoomDataSource.kt +++ /dev/null @@ -1,120 +0,0 @@ -package com.shepeliev.webrtckmp.sample.shared - -import kotlinx.coroutines.await -import kotlinx.coroutines.channels.awaitClose -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.callbackFlow -import kotlinx.coroutines.suspendCancellableCoroutine -import kotlin.coroutines.resume -import kotlin.coroutines.resumeWithException -import kotlin.js.Date -import kotlin.js.json - -actual class RoomDataSource actual constructor() { - - private val firestore by lazy { - initializeApp( - json( - "applicationId" to "1:216132728347:web:f10a385863ec2d43872abe", - "apiKey" to "AIzaSyDa0FDyeGNZZcKKBXnALeJSqfUxSNKut4w", - "authDomain" to "app-rtc-kmp.firebaseapp.com", - "projectId" to "app-rtc-kmp", - "storageBucket" to "app-rtc-kmp.appspot.com", - "gcmSenderId" to "216132728347", - ) - ).let { getFirestore(it) } - } - - private val roomsRef by lazy { collection(firestore, "rooms") } - - actual fun createRoom(): String { - return doc(roomsRef).id - } - - actual suspend fun insertOffer(roomId: String, description: SessionDescription) { - val docRef = doc(roomsRef, roomId) - setDoc( - docRef, - json( - "offer" to description.sdp, - "expireAt" to getExpireAtTime() - ) - ).await() - } - - actual suspend fun insertAnswer(roomId: String, description: SessionDescription) { - val docRef = doc(roomsRef, roomId) - updateDoc( - docRef, - json( - "answer" to description.sdp, - "expireAt" to getExpireAtTime() - ) - ).await() - } - - actual suspend fun insertIceCandidate(roomId: String, peerName: String, candidate: IceCandidate) { - val colRef = collection(roomsRef, "$roomId/$peerName") - addDoc( - colRef, - json( - "candidate" to candidate.candidate, - "sdpMLineIndex" to candidate.sdpMLineIndex, - "sdpMid" to candidate.sdpMid, - "expireAt" to getExpireAtTime(), - ) - ).await() - } - - private fun getExpireAtTime(): Date { - val expireAt = Date().getTime() + FIRESTORE_DOCUMENT_TTL_SECONDS * 1000 - return Date(expireAt) - } - - actual suspend fun getOffer(roomId: String): SessionDescription? { - val snapshot = getDoc(doc(roomsRef, roomId)).await() - val offerSdp = snapshot.takeIf { it.exists() }?.data()?.get("offer") as? String - return offerSdp?.let { SessionDescription(SessionDescriptionType.Offer, it) } - } - - actual suspend fun getAnswer(roomId: String): SessionDescription = suspendCancellableCoroutine { cont -> - val observer = DocumentSnapshotObserver( - next = { snapshot -> - val answer = snapshot.data()["answer"] as? String - answer?.let { cont.resume(SessionDescription(SessionDescriptionType.Answer, it)) } - }, - - error = cont::resumeWithException, - - complete = cont::cancel - ) - val unsubscribe = onSnapshot(doc(roomsRef, roomId), observer) - cont.invokeOnCancellation { unsubscribe() } - } - - actual fun observeIceCandidates(roomId: String, peerName: String): Flow = callbackFlow { - val observer = QuerySnapshotObserver( - next = { querySnapshot -> - - querySnapshot.docChanges() - .filter { it.type == "added" } - .map { - IceCandidate( - sdpMid = it.doc.data()["sdpMid"] as String, - sdpMLineIndex = it.doc.data()["sdpMLineIndex"] as Int, - candidate = it.doc.data()["candidate"] as String, - ) - } - .forEach { trySend(it) } - }, - - error = channel::close, - - complete = channel::close - ) - - val unsubscribe = onSnapshot(collection(roomsRef, "$roomId/$peerName"), observer) - - awaitClose { unsubscribe() } - } -} diff --git a/sample/shared/src/nativeInterop/cinterop/FirebaseCore.def b/sample/shared/src/nativeInterop/cinterop/FirebaseCore.def deleted file mode 100644 index 1559a5f6..00000000 --- a/sample/shared/src/nativeInterop/cinterop/FirebaseCore.def +++ /dev/null @@ -1,3 +0,0 @@ -language = Objective-C -modules = FirebaseCore -package = FirebaseCore diff --git a/sample/shared/src/nativeInterop/cinterop/FirebaseFirestore.def b/sample/shared/src/nativeInterop/cinterop/FirebaseFirestore.def deleted file mode 100644 index 2a978f45..00000000 --- a/sample/shared/src/nativeInterop/cinterop/FirebaseFirestore.def +++ /dev/null @@ -1,3 +0,0 @@ -language = Objective-C -modules = FirebaseFirestore -package = FirebaseFirestore diff --git a/settings.gradle.kts b/settings.gradle.kts index 8bf0b79b..d8fa1376 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,11 +1,5 @@ @Suppress("UnstableApiUsage") dependencyResolutionManagement { - versionCatalogs { - create("deps") { - from(files("libs.versions.toml")) - } - } - repositories { mavenLocal() mavenCentral() @@ -21,7 +15,6 @@ pluginManagement { } } +rootProject.name = "webrtc-kmp" include(":webrtc-kmp") -include(":sample:shared") -include(":sample:app-android") -include(":sample:app-web") +include(":sample:composeApp") diff --git a/webrtc-kmp/build.gradle.kts b/webrtc-kmp/build.gradle.kts index cfbd4add..ec8da3ea 100644 --- a/webrtc-kmp/build.gradle.kts +++ b/webrtc-kmp/build.gradle.kts @@ -1,5 +1,7 @@ +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget + plugins { - id("multiplatform-setup") + id("webrtc.multiplatform") kotlin("native.cocoapods") id("maven-publish") id("signing") @@ -28,9 +30,9 @@ kotlin { publishAllLibraryVariants() } - iosX64 { configureIos() } - iosArm64 { configureIos() } - iosSimulatorArm64 { configureIos() } + iosX64 { configureWebRtcCinterops() } + iosArm64 { configureWebRtcCinterops() } + iosSimulatorArm64 { configureWebRtcCinterops() } js { useCommonJs() @@ -39,13 +41,13 @@ kotlin { sourceSets { commonMain.dependencies { - implementation(deps.kotlin.coroutines) + implementation(libs.kotlin.coroutines) } androidMain.dependencies { - implementation(deps.kotlin.coroutines) - implementation(deps.androidx.coreKtx) - api(deps.webrtcSdk) + implementation(libs.kotlin.coroutines.android) + implementation(libs.androidx.coreKtx) + api(libs.webrtc.sdk) } jsMain.dependencies { @@ -67,8 +69,8 @@ android { } dependencies { - androidTestImplementation(deps.androidx.test.core) - androidTestImplementation(deps.androidx.test.runner) + androidTestImplementation(libs.androidx.test.core) + androidTestImplementation(libs.androidx.test.runner) } } @@ -113,14 +115,14 @@ publishing { } signing { - val signingKey: String by extra - val signingPassword: String by extra + val signingKey: String by rootProject.extra + val signingPassword: String by rootProject.extra useInMemoryPgpKeys(signingKey, signingPassword) sign(publishing.publications) } -fun org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget.configureIos() { +fun KotlinNativeTarget.configureWebRtcCinterops() { val webRtcFrameworkPath = file("$buildDir/cocoapods/synthetic/IOS/Pods/WebRTC-SDK") .resolveArchPath(konanTarget, "WebRTC") compilations.getByName("main") { diff --git a/webrtc-kmp/src/androidMain/kotlin/com/shepeliev/webrtckmp/ApplicationContextHolder.kt b/webrtc-kmp/src/androidMain/kotlin/com/shepeliev/webrtckmp/ApplicationContextHolder.kt index f5deaaeb..d0540431 100644 --- a/webrtc-kmp/src/androidMain/kotlin/com/shepeliev/webrtckmp/ApplicationContextHolder.kt +++ b/webrtc-kmp/src/androidMain/kotlin/com/shepeliev/webrtckmp/ApplicationContextHolder.kt @@ -6,11 +6,13 @@ import android.content.ContentValues import android.content.Context import android.database.Cursor import android.net.Uri +import org.webrtc.PeerConnectionFactory internal class ApplicationContextHolder : ContentProvider() { override fun onCreate(): Boolean { ApplicationContextHolder.context = checkNotNull(context) + WebRtc.factoryInitializationOptionsBuilder = PeerConnectionFactory.InitializationOptions.builder(context) return true } diff --git a/webrtc-kmp/src/androidMain/kotlin/com/shepeliev/webrtckmp/PeerConnection.kt b/webrtc-kmp/src/androidMain/kotlin/com/shepeliev/webrtckmp/PeerConnection.kt index 6e79af5c..8e30b5c7 100644 --- a/webrtc-kmp/src/androidMain/kotlin/com/shepeliev/webrtckmp/PeerConnection.kt +++ b/webrtc-kmp/src/androidMain/kotlin/com/shepeliev/webrtckmp/PeerConnection.kt @@ -11,12 +11,20 @@ import com.shepeliev.webrtckmp.PeerConnectionEvent.RemovedIceCandidates import com.shepeliev.webrtckmp.PeerConnectionEvent.SignalingStateChange import com.shepeliev.webrtckmp.PeerConnectionEvent.StandardizedIceConnectionChange import com.shepeliev.webrtckmp.PeerConnectionEvent.Track +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.cancel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.launch +import org.webrtc.AudioTrack import org.webrtc.CandidatePairChangeEvent import org.webrtc.MediaConstraints +import org.webrtc.MediaStreamTrack.AUDIO_TRACK_KIND +import org.webrtc.MediaStreamTrack.VIDEO_TRACK_KIND import org.webrtc.SdpObserver +import org.webrtc.VideoTrack import kotlin.coroutines.Continuation import kotlin.coroutines.resume import kotlin.coroutines.resumeWithException @@ -57,6 +65,7 @@ actual class PeerConnection actual constructor(rtcConfiguration: RtcConfiguratio MutableSharedFlow(extraBufferCapacity = FLOW_BUFFER_CAPACITY) internal actual val peerConnectionEvent: Flow = _peerConnectionEvent.asSharedFlow() + private val coroutineScope = CoroutineScope(Dispatchers.Main) private val localTracks = mutableMapOf() private val remoteTracks = mutableMapOf() @@ -209,37 +218,38 @@ actual class PeerConnection actual constructor(rtcConfiguration: RtcConfiguratio remoteTracks.values.forEach(MediaStreamTrack::stop) remoteTracks.clear() android.dispose() + coroutineScope.cancel() } internal inner class AndroidPeerConnectionObserver : AndroidPeerConnection.Observer { override fun onSignalingChange(newState: AndroidPeerConnection.SignalingState) { - _peerConnectionEvent.tryEmit(SignalingStateChange(newState.asCommon())) + coroutineScope.launch { _peerConnectionEvent.emit(SignalingStateChange(newState.asCommon())) } } override fun onIceConnectionChange(newState: AndroidPeerConnection.IceConnectionState) { - _peerConnectionEvent.tryEmit(IceConnectionStateChange(newState.asCommon())) + coroutineScope.launch { _peerConnectionEvent.emit(IceConnectionStateChange(newState.asCommon())) } } override fun onStandardizedIceConnectionChange(newState: AndroidPeerConnection.IceConnectionState) { - _peerConnectionEvent.tryEmit(StandardizedIceConnectionChange(newState.asCommon())) + coroutineScope.launch { _peerConnectionEvent.emit(StandardizedIceConnectionChange(newState.asCommon())) } } override fun onConnectionChange(newState: AndroidPeerConnection.PeerConnectionState) { - _peerConnectionEvent.tryEmit(ConnectionStateChange(newState.asCommon())) + coroutineScope.launch { _peerConnectionEvent.emit(ConnectionStateChange(newState.asCommon())) } } override fun onIceConnectionReceivingChange(receiving: Boolean) {} override fun onIceGatheringChange(newState: AndroidPeerConnection.IceGatheringState) { - _peerConnectionEvent.tryEmit(IceGatheringStateChange(newState.asCommon())) + coroutineScope.launch { _peerConnectionEvent.emit(IceGatheringStateChange(newState.asCommon())) } } override fun onIceCandidate(candidate: AndroidIceCandidate) { - _peerConnectionEvent.tryEmit(NewIceCandidate(IceCandidate(candidate))) + coroutineScope.launch { _peerConnectionEvent.emit(NewIceCandidate(IceCandidate(candidate))) } } override fun onIceCandidatesRemoved(candidates: Array) { - _peerConnectionEvent.tryEmit(RemovedIceCandidates(candidates.map { IceCandidate(it) })) + coroutineScope.launch { _peerConnectionEvent.emit(RemovedIceCandidates(candidates.map { IceCandidate(it) })) } } override fun onAddStream(nativeStream: AndroidMediaStream) { @@ -257,11 +267,11 @@ actual class PeerConnection actual constructor(rtcConfiguration: RtcConfiguratio } override fun onDataChannel(dataChannel: AndroidDataChannel) { - _peerConnectionEvent.tryEmit(NewDataChannel(DataChannel(dataChannel))) + coroutineScope.launch { _peerConnectionEvent.emit(NewDataChannel(DataChannel(dataChannel))) } } override fun onRenegotiationNeeded() { - _peerConnectionEvent.tryEmit(NegotiationNeeded) + coroutineScope.launch { _peerConnectionEvent.emit(NegotiationNeeded) } } override fun onAddTrack( @@ -269,28 +279,28 @@ actual class PeerConnection actual constructor(rtcConfiguration: RtcConfiguratio androidStreams: Array ) { val transceiver = android.transceivers.find { it.receiver.id() == receiver.id() } ?: return + val senderTrack = localTracks[transceiver.sender.track()?.id()] - val audioTracks = androidStreams - .flatMap { it.audioTracks } - .map { remoteTracks.getOrPut(it.id()) { RemoteAudioStreamTrack(it) } } - - val videoTracks = androidStreams - .flatMap { it.videoTracks } - .map { remoteTracks.getOrPut(it.id()) { RemoteVideoStreamTrack(it) } } + val receiverTrack = receiver.track()?.let { + remoteTracks.getOrPut(it.id()) { + when (it.kind()) { + AUDIO_TRACK_KIND -> RemoteAudioStreamTrack(it as AudioTrack) + VIDEO_TRACK_KIND -> RemoteVideoStreamTrack(it as VideoTrack) + else -> error("Unsupported track kind: ${it.kind()}") + } + } + } val streams = androidStreams.map { androidStream -> MediaStream( android = androidStream, id = androidStream.id, ).also { stream -> - audioTracks.forEach(stream::addTrack) - videoTracks.forEach(stream::addTrack) + androidStream.audioTracks.forEach { stream.addTrack(RemoteAudioStreamTrack(it)) } + androidStream.videoTracks.forEach { stream.addTrack(RemoteVideoStreamTrack(it)) } } } - val senderTrack = localTracks[transceiver.sender.track()?.id()] - val receiverTrack = remoteTracks[receiver.track()?.id()] - val trackEvent = TrackEvent( receiver = RtpReceiver(receiver, receiverTrack), streams = streams, @@ -298,12 +308,12 @@ actual class PeerConnection actual constructor(rtcConfiguration: RtcConfiguratio transceiver = RtpTransceiver(transceiver, senderTrack, receiverTrack) ) - _peerConnectionEvent.tryEmit(Track(trackEvent)) + coroutineScope.launch { _peerConnectionEvent.emit(Track(trackEvent)) } } override fun onRemoveTrack(receiver: AndroidRtpReceiver) { val track = remoteTracks.remove(receiver.track()?.id()) - _peerConnectionEvent.tryEmit(RemoveTrack(RtpReceiver(receiver, track))) + coroutineScope.launch { _peerConnectionEvent.emit(RemoveTrack(RtpReceiver(receiver, track))) } track?.stop() } diff --git a/webrtc-kmp/src/androidMain/kotlin/com/shepeliev/webrtckmp/WebRtc.kt b/webrtc-kmp/src/androidMain/kotlin/com/shepeliev/webrtckmp/WebRtc.kt index 2acbc892..d21263dd 100644 --- a/webrtc-kmp/src/androidMain/kotlin/com/shepeliev/webrtckmp/WebRtc.kt +++ b/webrtc-kmp/src/androidMain/kotlin/com/shepeliev/webrtckmp/WebRtc.kt @@ -8,42 +8,22 @@ import org.webrtc.CameraEnumerator import org.webrtc.DefaultVideoDecoderFactory import org.webrtc.DefaultVideoEncoderFactory import org.webrtc.EglBase -import org.webrtc.Logging import org.webrtc.PeerConnectionFactory +import org.webrtc.VideoDecoderFactory +import org.webrtc.VideoEncoderFactory +@Suppress("MemberVisibilityCanBePrivate") object WebRtc { - private const val TAG = "WebRtcKmp" - - var peerConnectionFactoryInitOptions: PeerConnectionFactory.InitializationOptions? = null - set(value) { - field = value - if (_eglBase != null) { - Logging.e( - TAG, - "Peer connection factory is already initialized. Setting " + - "peerConnectionFactoryInitOptions after initialization has no effect." - ) - } - } - - var peerConnectionFactoryBuilder: PeerConnectionFactory.Builder? = null - set(value) { - field = value - if (_peerConnectionFactory != null) { - Logging.e( - TAG, - "Peer connection factory is already initialized. Setting " + - "peerConnectionFactoryBuilder after initialization has no effect." - ) - } - } - - private var _eglBase: EglBase? = null - val rootEglBase: EglBase - get() { - if (_eglBase == null) initialize() - return checkNotNull(_eglBase) - } + var videoEncoderFactory: VideoEncoderFactory? = null + var videoDecoderFactory: VideoDecoderFactory? = null + var customPeerConnectionFactory: PeerConnectionFactory? = null + lateinit var factoryInitializationOptionsBuilder: PeerConnectionFactory.InitializationOptions.Builder + internal set + + private var _rootEglBase: EglBase? = null + val rootEglBase: EglBase by lazy { + _rootEglBase ?: EglBase.create().also { _rootEglBase = it } + } var cameraEnumerator: CameraEnumerator = if (Camera2Enumerator.isSupported(ApplicationContextHolder.context)) { @@ -52,54 +32,25 @@ object WebRtc { Camera1Enumerator() } - private var _peerConnectionFactory: PeerConnectionFactory? = null - internal val peerConnectionFactory: PeerConnectionFactory - get() { - if (_peerConnectionFactory == null) initialize() - return checkNotNull(_peerConnectionFactory) - } - - private fun initialize() { - check(_eglBase == null) { "Peer connection factory is already initialized." } - _eglBase = EglBase.create() - initializePeerConnectionFactory() - val builder = peerConnectionFactoryBuilder ?: getDefaultPeerConnectionBuilder() - _peerConnectionFactory = builder.createPeerConnectionFactory() - } - - private fun initializePeerConnectionFactory() { - val initOptions = peerConnectionFactoryInitOptions - ?: getDefaultPeerConnectionFactoryInitOptions() - PeerConnectionFactory.initialize(initOptions) - } + internal val peerConnectionFactory: PeerConnectionFactory by lazy { + customPeerConnectionFactory ?: run { + PeerConnectionFactory.initialize(factoryInitializationOptionsBuilder.createInitializationOptions()) - private fun getDefaultPeerConnectionFactoryInitOptions() = - PeerConnectionFactory.InitializationOptions - .builder(ApplicationContextHolder.context) - .createInitializationOptions() + val videoEncoderFactory = videoEncoderFactory + ?: DefaultVideoEncoderFactory(rootEglBase.eglBaseContext, true, true) + val videoDecoderFactory = videoDecoderFactory ?: DefaultVideoDecoderFactory(rootEglBase.eglBaseContext) - private fun getDefaultPeerConnectionBuilder(): PeerConnectionFactory.Builder { - val videoEncoderFactory = DefaultVideoEncoderFactory( - rootEglBase.eglBaseContext, - true, - false - ) + val factoryBuilder = PeerConnectionFactory.builder() + .setVideoEncoderFactory(videoEncoderFactory) + .setVideoDecoderFactory(videoDecoderFactory) - val videoDecoderFactory = DefaultVideoDecoderFactory(rootEglBase.eglBaseContext) - return PeerConnectionFactory.builder() - .setVideoEncoderFactory(videoEncoderFactory) - .setVideoDecoderFactory(videoDecoderFactory) + factoryBuilder.createPeerConnectionFactory() + } } - fun disposePeerConnectionFactory() { - if (_peerConnectionFactory == null) return - - _eglBase?.release() - _eglBase = null - - _peerConnectionFactory?.dispose() - _peerConnectionFactory = null - - PeerConnectionFactory.shutdownInternalTracer() + @Suppress("unused") + fun setRootEglBase(eglBase: EglBase) { + check(_rootEglBase == null) { "Root EglBase is already set" } + _rootEglBase = eglBase } } diff --git a/webrtc-kmp/src/iosMain/kotlin/com/shepeliev/webrtckmp/PeerConnection.kt b/webrtc-kmp/src/iosMain/kotlin/com/shepeliev/webrtckmp/PeerConnection.kt index 5aafec55..1186dc4b 100644 --- a/webrtc-kmp/src/iosMain/kotlin/com/shepeliev/webrtckmp/PeerConnection.kt +++ b/webrtc-kmp/src/iosMain/kotlin/com/shepeliev/webrtckmp/PeerConnection.kt @@ -20,6 +20,8 @@ import WebRTC.RTCSessionDescription import WebRTC.RTCSignalingState import WebRTC.RTCVideoTrack import WebRTC.dataChannelForLabel +import WebRTC.kRTCMediaStreamTrackKindAudio +import WebRTC.kRTCMediaStreamTrackKindVideo import com.shepeliev.webrtckmp.PeerConnectionEvent.ConnectionStateChange import com.shepeliev.webrtckmp.PeerConnectionEvent.IceConnectionStateChange import com.shepeliev.webrtckmp.PeerConnectionEvent.IceGatheringStateChange @@ -32,9 +34,13 @@ import com.shepeliev.webrtckmp.PeerConnectionEvent.SignalingStateChange import com.shepeliev.webrtckmp.PeerConnectionEvent.StandardizedIceConnectionChange import com.shepeliev.webrtckmp.PeerConnectionEvent.Track import kotlinx.cinterop.ExperimentalForeignApi +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.cancel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.asSharedFlow +import kotlinx.coroutines.launch import platform.darwin.NSObject actual class PeerConnection actual constructor( @@ -69,6 +75,7 @@ actual class PeerConnection actual constructor( MutableSharedFlow(extraBufferCapacity = FLOW_BUFFER_CAPACITY) internal actual val peerConnectionEvent: Flow = _peerConnectionEvent.asSharedFlow() + private val coroutineScope = CoroutineScope(Dispatchers.Main) private val localTracks = mutableMapOf() private val remoteTracks = mutableMapOf() @@ -180,11 +187,12 @@ actual class PeerConnection actual constructor( remoteTracks.values.forEach(MediaStreamTrack::stop) remoteTracks.clear() ios.close() + coroutineScope.cancel() } override fun peerConnection(peerConnection: RTCPeerConnection, didChangeSignalingState: RTCSignalingState) { val event = SignalingStateChange(rtcSignalingStateAsCommon(didChangeSignalingState)) - _peerConnectionEvent.tryEmit(event) + coroutineScope.launch { _peerConnectionEvent.emit(event) } } @Suppress("CONFLICTING_OVERLOADS", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") @@ -204,34 +212,34 @@ actual class PeerConnection actual constructor( } override fun peerConnectionShouldNegotiate(peerConnection: RTCPeerConnection) { - _peerConnectionEvent.tryEmit(NegotiationNeeded) + coroutineScope.launch { _peerConnectionEvent.emit(NegotiationNeeded) } } @Suppress("CONFLICTING_OVERLOADS", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") override fun peerConnection(peerConnection: RTCPeerConnection, didChangeIceConnectionState: RTCIceConnectionState) { val event = IceConnectionStateChange(rtcIceConnectionStateAsCommon(didChangeIceConnectionState)) - _peerConnectionEvent.tryEmit(event) + coroutineScope.launch { _peerConnectionEvent.emit(event) } } override fun peerConnection(peerConnection: RTCPeerConnection, didChangeIceGatheringState: RTCIceGatheringState) { val event = IceGatheringStateChange(rtcIceGatheringStateAsCommon(didChangeIceGatheringState)) - _peerConnectionEvent.tryEmit(event) + coroutineScope.launch { _peerConnectionEvent.emit(event) } } override fun peerConnection(peerConnection: RTCPeerConnection, didGenerateIceCandidate: RTCIceCandidate) { val event = NewIceCandidate(IceCandidate(didGenerateIceCandidate)) - _peerConnectionEvent.tryEmit(event) + coroutineScope.launch { _peerConnectionEvent.emit(event) } } override fun peerConnection(peerConnection: RTCPeerConnection, didRemoveIceCandidates: List<*>) { val candidates = didRemoveIceCandidates.map { IceCandidate(it as RTCIceCandidate) } val event = RemovedIceCandidates(candidates) - _peerConnectionEvent.tryEmit(event) + coroutineScope.launch { _peerConnectionEvent.emit(event) } } override fun peerConnection(peerConnection: RTCPeerConnection, didOpenDataChannel: RTCDataChannel) { val event = NewDataChannel(DataChannel(didOpenDataChannel)) - _peerConnectionEvent.tryEmit(event) + coroutineScope.launch { _peerConnectionEvent.emit(event) } } @Suppress("CONFLICTING_OVERLOADS", "PARAMETER_NAME_CHANGED_ON_OVERRIDE") @@ -242,12 +250,12 @@ actual class PeerConnection actual constructor( val event = StandardizedIceConnectionChange( rtcIceConnectionStateAsCommon(didChangeStandardizedIceConnectionState) ) - _peerConnectionEvent.tryEmit(event) + coroutineScope.launch { _peerConnectionEvent.emit(event) } } override fun peerConnection(peerConnection: RTCPeerConnection, didChangeConnectionState: RTCPeerConnectionState) { val event = ConnectionStateChange(rtcPeerConnectionStateAsCommon(didChangeConnectionState)) - _peerConnectionEvent.tryEmit(event) + coroutineScope.launch { _peerConnectionEvent.emit(event) } } override fun peerConnection(peerConnection: RTCPeerConnection, didAddReceiver: RTCRtpReceiver, streams: List<*>) { @@ -256,28 +264,27 @@ actual class PeerConnection actual constructor( .find { it.receiver.receiverId == didAddReceiver.receiverId } ?: return - val iosStreams = streams.map { it as RTCMediaStream } + val senderTrack = localTracks[transceiver.sender.track?.trackId] - val audioTracks = iosStreams - .flatMap { it.audioTracks } - .map { it as RTCAudioTrack } - .map { remoteTracks.getOrPut(it.trackId) { RemoteAudioStreamTrack(it) } } + val receiverTrack = didAddReceiver.track()?.let { + remoteTracks.getOrPut(it.trackId) { + when (val kind = it.kind()) { + kRTCMediaStreamTrackKindAudio -> RemoteAudioStreamTrack(it as RTCAudioTrack) + kRTCMediaStreamTrackKindVideo -> RemoteVideoStreamTrack(it as RTCVideoTrack) + else -> error("Unsupported track kind: $kind") + } + } + } - val videoTracks = iosStreams - .flatMap { it.videoTracks } - .map { it as RTCVideoTrack } - .map { remoteTracks.getOrPut(it.trackId) { RemoteVideoStreamTrack(it) } } + val iosStreams = streams.map { it as RTCMediaStream } val commonStreams = iosStreams.map { iosStream -> MediaStream(ios = iosStream, id = iosStream.streamId).also { stream -> - audioTracks.forEach(stream::addTrack) - videoTracks.forEach(stream::addTrack) + iosStream.audioTracks.forEach { stream.addTrack(RemoteAudioStreamTrack(it as RTCAudioTrack)) } + iosStream.videoTracks.forEach { stream.addTrack(RemoteVideoStreamTrack(it as RTCVideoTrack)) } } } - val receiverTrack = remoteTracks[didAddReceiver.track?.trackId] - val senderTrack = localTracks[transceiver.sender.track?.trackId] - val trackEvent = TrackEvent( receiver = RtpReceiver(didAddReceiver, receiverTrack), streams = commonStreams, @@ -286,13 +293,13 @@ actual class PeerConnection actual constructor( ) val event = Track(trackEvent) - _peerConnectionEvent.tryEmit(event) + coroutineScope.launch { _peerConnectionEvent.emit(event) } } override fun peerConnection(peerConnection: RTCPeerConnection, didRemoveReceiver: RTCRtpReceiver) { val track = remoteTracks.remove(didRemoveReceiver.track?.trackId) val event = RemoveTrack(RtpReceiver(didRemoveReceiver, track)) - _peerConnectionEvent.tryEmit(event) + coroutineScope.launch { _peerConnectionEvent.emit(event) } track?.stop() } } diff --git a/webrtc-kmp/src/iosMain/kotlin/com/shepeliev/webrtckmp/WebRtc.kt b/webrtc-kmp/src/iosMain/kotlin/com/shepeliev/webrtckmp/WebRtc.kt index 5334c077..3e3c31a0 100644 --- a/webrtc-kmp/src/iosMain/kotlin/com/shepeliev/webrtckmp/WebRtc.kt +++ b/webrtc-kmp/src/iosMain/kotlin/com/shepeliev/webrtckmp/WebRtc.kt @@ -2,75 +2,30 @@ package com.shepeliev.webrtckmp -import WebRTC.RTCCleanupSSL import WebRTC.RTCDefaultVideoDecoderFactory import WebRTC.RTCDefaultVideoEncoderFactory import WebRTC.RTCInitializeSSL -import WebRTC.RTCLogEx -import WebRTC.RTCLoggingSeverity import WebRTC.RTCPeerConnectionFactory import WebRTC.RTCPeerConnectionFactoryOptions -import WebRTC.RTCShutdownInternalTracer import WebRTC.RTCVideoDecoderFactoryProtocol import WebRTC.RTCVideoEncoderFactoryProtocol import kotlinx.cinterop.ExperimentalForeignApi object WebRtc { var videoEncoderFactory: RTCVideoEncoderFactoryProtocol? = null - set(value) { - field = value - if (_peerConnectionFactory != null) { - RTCLogEx( - RTCLoggingSeverity.RTCLoggingSeverityError, - "Peer connection factory is already initialized. " + - "Setting video encoder factory after initialization has no effect." - ) - } - } - var videoDecoderFactory: RTCVideoDecoderFactoryProtocol? = null - set(value) { - field = value - if (_peerConnectionFactory != null) { - RTCLogEx( - RTCLoggingSeverity.RTCLoggingSeverityError, - "Peer connection factory is already initialized. " + - "Setting video decoder factory after initialization has no effect." - ) - } - } - var peerConnectionFactoryOptions: RTCPeerConnectionFactoryOptions? = null - set(value) { - field = value - if (_peerConnectionFactory != null) { - RTCLogEx( - RTCLoggingSeverity.RTCLoggingSeverityError, - "Peer connection factory is already initialized. " + - "Setting peer connection factory options after initialization has no effect." - ) + var customPeerConnectionFactory: RTCPeerConnectionFactory? = null + + internal val peerConnectionFactory: RTCPeerConnectionFactory by lazy { + customPeerConnectionFactory ?: run { + RTCInitializeSSL() + RTCPeerConnectionFactory( + videoEncoderFactory ?: RTCDefaultVideoEncoderFactory(), + videoDecoderFactory ?: RTCDefaultVideoDecoderFactory() + ).apply { + peerConnectionFactoryOptions?.let { setOptions(it) } } } - - private var _peerConnectionFactory: RTCPeerConnectionFactory? = null - internal val peerConnectionFactory: RTCPeerConnectionFactory - get() { - if (_peerConnectionFactory == null) initialize() - return checkNotNull(_peerConnectionFactory) - } - - private fun initialize() { - RTCInitializeSSL() - _peerConnectionFactory = RTCPeerConnectionFactory( - videoEncoderFactory ?: RTCDefaultVideoEncoderFactory(), - videoDecoderFactory ?: RTCDefaultVideoDecoderFactory() - ).apply { - peerConnectionFactoryOptions?.let { setOptions(it) } - } - } - - fun disposePeerConnectionFactory() { - RTCShutdownInternalTracer() - RTCCleanupSSL() } } diff --git a/webrtc-kmp/src/jsMain/kotlin/com/shepeliev/webrtckmp/MediaStreamTrackImpl.kt b/webrtc-kmp/src/jsMain/kotlin/com/shepeliev/webrtckmp/MediaStreamTrackImpl.kt index 246fbfa5..50582349 100644 --- a/webrtc-kmp/src/jsMain/kotlin/com/shepeliev/webrtckmp/MediaStreamTrackImpl.kt +++ b/webrtc-kmp/src/jsMain/kotlin/com/shepeliev/webrtckmp/MediaStreamTrackImpl.kt @@ -9,7 +9,7 @@ import org.w3c.dom.mediacapture.LIVE import org.w3c.dom.mediacapture.MediaStreamTrack as JsMediaStreamTrack import org.w3c.dom.mediacapture.MediaStreamTrackState as JsMediaStreamTrackState -internal abstract class MediaStreamTrackImpl(val js: JsMediaStreamTrack) : MediaStreamTrack { +abstract class MediaStreamTrackImpl(val js: JsMediaStreamTrack) : MediaStreamTrack { override val id: String get() = js.id diff --git a/webrtc-kmp/src/jsMain/kotlin/com/shepeliev/webrtckmp/VideoStreamTrack.kt b/webrtc-kmp/src/jsMain/kotlin/com/shepeliev/webrtckmp/VideoStreamTrack.kt index 9cc4ff6f..6b3d364d 100644 --- a/webrtc-kmp/src/jsMain/kotlin/com/shepeliev/webrtckmp/VideoStreamTrack.kt +++ b/webrtc-kmp/src/jsMain/kotlin/com/shepeliev/webrtckmp/VideoStreamTrack.kt @@ -1,5 +1,9 @@ package com.shepeliev.webrtckmp +import org.w3c.dom.mediacapture.MediaStreamTrack as DomMediaStreamTrack + + actual interface VideoStreamTrack : MediaStreamTrack { + val js: DomMediaStreamTrack actual suspend fun switchCamera(deviceId: String?) }