diff --git a/.gitignore b/.gitignore index bd6785e4..e599ccf5 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,5 @@ /captures .externalNativeBuild .cxx +.kotlin local.properties diff --git a/app/build.gradle.kts b/app/build.gradle.kts deleted file mode 100644 index 4292f07d..00000000 --- a/app/build.gradle.kts +++ /dev/null @@ -1,31 +0,0 @@ -@file:Suppress("UnstableApiUsage") - -plugins { - id("com.streamplayer.application") -} - -dependencies { - implementation(projects.featureFavorites) - implementation(projects.featureListStreams) - implementation(projects.featureProfile) - implementation(projects.coreShared) - implementation(projects.coreSharedUi) - implementation(projects.coreNavigation) - implementation(projects.coreNetworking) - implementation(projects.coreLocalStorage) - - implementation(platform(libs.compose.bom)) - androidTestImplementation(platform(libs.compose.bom)) - - implementation(libs.bundles.koin) - implementation(libs.bundles.androidSupport) - implementation(libs.bundles.compose) - implementation(libs.bundles.kotlin) - - implementation(libs.lottie) - implementation(libs.lottie) - testImplementation(libs.bundles.test) - - // Kover - Combined report - rootProject.subprojects.forEach { kover(it) } -} \ No newline at end of file diff --git a/app/src/main/java/com/codandotv/streamplayerapp/splah/presentation/screens/SplashScreen.kt b/app/src/main/java/com/codandotv/streamplayerapp/splah/presentation/screens/SplashScreen.kt deleted file mode 100644 index f08c7848..00000000 --- a/app/src/main/java/com/codandotv/streamplayerapp/splah/presentation/screens/SplashScreen.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.codandotv.streamplayerapp.splah.presentation.screens - -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize -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.tooling.preview.Preview -import com.airbnb.lottie.compose.LottieAnimation -import com.airbnb.lottie.compose.LottieCompositionSpec -import com.airbnb.lottie.compose.animateLottieCompositionAsState -import com.airbnb.lottie.compose.rememberLottieComposition -import com.codandotv.streamplayerapp.core.shared.ui.R as SharedUiR - -@Composable -fun SplashScreen( - onAnimationFinished: () -> Unit -) { - Column( - modifier = Modifier.fillMaxSize() - ) { - Box( - contentAlignment = Alignment.Center, - modifier = Modifier - .fillMaxSize() - .background(Color.Black) - ) { - val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(SharedUiR.raw.logo)) - val logoAnimationState = animateLottieCompositionAsState(composition = composition) - LottieAnimation(composition = composition, progress = { logoAnimationState.progress }) - if (logoAnimationState.isAtEnd && logoAnimationState.isPlaying) { - onAnimationFinished() - } - } - } -} - -@Composable -@Preview -fun SplashScreenPreview() { - SplashScreen(onAnimationFinished = {}) -} \ No newline at end of file diff --git a/app/src/main/res/xml/backup_rules.xml b/app/src/main/res/xml/backup_rules.xml deleted file mode 100644 index fa0f996d..00000000 --- a/app/src/main/res/xml/backup_rules.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/xml/data_extraction_rules.xml b/app/src/main/res/xml/data_extraction_rules.xml deleted file mode 100644 index 9ee9997b..00000000 --- a/app/src/main/res/xml/data_extraction_rules.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/app/src/test/java/com/codandotv/streamplayerapp/ExampleUnitTest.kt b/app/src/test/java/com/codandotv/streamplayerapp/ExampleUnitTest.kt deleted file mode 100644 index e83e0c8a..00000000 --- a/app/src/test/java/com/codandotv/streamplayerapp/ExampleUnitTest.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.codandotv.streamplayerapp - -import org.junit.Test - -import org.junit.Assert.assertEquals - -/** - * Example local unit test, which will execute on the development machine (host). - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -class ExampleUnitTest { - @Test - fun addition_isCorrect() { - assertEquals(4, 2 + 2) - } -} \ No newline at end of file diff --git a/build-logic/build.gradle.kts b/build-logic/build.gradle.kts index eaf67121..8377f141 100644 --- a/build-logic/build.gradle.kts +++ b/build-logic/build.gradle.kts @@ -6,8 +6,10 @@ plugins { } repositories { - mavenCentral() google() + mavenCentral() + gradlePluginPortal() + maven(url = "https://plugins.gradle.org/m2/") } dependencies { @@ -15,4 +17,6 @@ dependencies { implementation(libs.kotlin.gradle.plugin) implementation(libs.kover.gradle.plugin) implementation(libs.detekt.gradle.plugin) + implementation(libs.serialization) + implementation(libs.com.google.devtools.ksp.gradle.plugin) } \ No newline at end of file diff --git a/build-logic/src/main/java/Config.kt b/build-logic/src/main/java/Config.kt index 2ba49cd2..ede08d28 100644 --- a/build-logic/src/main/java/Config.kt +++ b/build-logic/src/main/java/Config.kt @@ -1,24 +1,26 @@ object Config { - const val applicationId = "com.codandotv.streamplayerapp" - const val compileSdkVersion = 34 - const val minSdkVersion = 24 - const val targetSdkVersion = 34 + const val appName = "streamplayerapp" + const val applicationId = "com.codandotv.$appName" + const val compileSdkVersion = 35 + const val minSdkVersion = 28 + const val targetSdkVersion = 35 const val versionName = "1.0" const val versionCode = 1 const val testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" object BuildField { - const val host_debug = "\"https://api.themoviedb.org/3/\"" - const val host_release = "\"https://api.themoviedb.org/3/\"" - const val api_profile_debug = "\"https://demo3364084.mockable.io/\"" - const val api_profile_release = "\"https://demo3364084.mockable.io/\"" + const val host_debug = "https://api.themoviedb.org/3/" + const val host_release = "https://api.themoviedb.org/3/" + const val api_profile_debug = "https://demo3364084.mockable.io/" + const val api_profile_release = "https://demo3364084.mockable.io/" private const val tmdb_token_name_debug = "TMDB_BEARER_TOKEN_DEBUG" private const val tmdb_token_name_release = "TMDB_BEARER_TOKEN_RELEASE" private const val bearear_without_environment = "eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJiNDg2NWM4YTAzNzhmM2I4NjI0OWU1ZjNiYWFiMjU2NyIsInN1YiI6IjY0Mjk4YTg5YTNlNGJhMWM0NDgzM2U4OCIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.9cIxv29vkaZ2yW88DIFRUFK_nXbK2b6KS8t96kA8WAE" - val api_bearer_debug = "\"Bearer ${System.getenv(tmdb_token_name_debug) ?: bearear_without_environment}\"" - val api_bearer_release = "\"Bearer ${System.getenv(tmdb_token_name_release) ?: bearear_without_environment}\"" + val api_bearer = System.getenv(tmdb_token_name_debug) ?: bearear_without_environment + val api_bearer_debug = System.getenv(tmdb_token_name_debug) ?: bearear_without_environment + val api_bearer_release = System.getenv(tmdb_token_name_release) ?: bearear_without_environment } } \ No newline at end of file diff --git a/build-logic/src/main/java/Keys.kt b/build-logic/src/main/java/Keys.kt deleted file mode 100644 index 4475b22e..00000000 --- a/build-logic/src/main/java/Keys.kt +++ /dev/null @@ -1,12 +0,0 @@ -object Keys { - private const val default_tmdb_token = "eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJiNDg2NWM4YTAzNzhmM2I4NjI0OWU1ZjNiYWFiMjU2NyIsInN1YiI6IjY0Mjk4YTg5YTNlNGJhMWM0NDgzM2U4OCIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.9cIxv29vkaZ2yW88DIFRUFK_nXbK2b6KS8t96kA8WAE" - private const val tmdb_token_name_debug = "TMDB_BEARER_TOKEN_DEBUG" - private const val tmdb_token_name_release = "TMDB_BEARER_TOKEN_RELEASE" - - object BuildField { - val api_bearer_debug = - "\"Bearer ${System.getenv(tmdb_token_name_debug) ?: default_tmdb_token}\"" - val api_bearer_release = - "\"Bearer ${System.getenv(tmdb_token_name_release) ?: default_tmdb_token}\"" - } -} \ No newline at end of file diff --git a/build-logic/src/main/java/com.streamplayer.application.gradle.kts b/build-logic/src/main/java/com.streamplayer.application.gradle.kts index e5af04a1..3c0fac6e 100644 --- a/build-logic/src/main/java/com.streamplayer.application.gradle.kts +++ b/build-logic/src/main/java/com.streamplayer.application.gradle.kts @@ -2,16 +2,18 @@ import extensions.dokkaPlugin import extensions.getLibrary +import extensions.iosTarget import extensions.setupAndroidDefaultConfig import extensions.setupCompileOptions -import extensions.setupCompose import extensions.setupPackingOptions +import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi +import org.jetbrains.kotlin.gradle.dsl.JvmTarget val libs: VersionCatalog = extensions.getByType().named("libs") plugins { id("com.android.application") - id("kotlin-android") + id("org.jetbrains.kotlin.multiplatform") id("kotlin-kapt") id("kotlin-parcelize") id("com.streamplayer.dokka") @@ -20,6 +22,16 @@ plugins { } val catalog: VersionCatalog = extensions.getByType().named("libs") +kotlin { + androidTarget { + @OptIn(ExperimentalKotlinGradlePluginApi::class) + compilerOptions { + jvmTarget.set(JvmTarget.JVM_17) + } + } + + iosTarget() +} android { namespace = Config.applicationId @@ -27,7 +39,6 @@ android { setupCompileOptions() setupPackingOptions() setupAndroidDefaultConfig() - setupCompose(catalog) defaultConfig { applicationId = Config.applicationId diff --git a/build-logic/src/main/java/com.streamplayer.compose.gradle.kts b/build-logic/src/main/java/com.streamplayer.compose.gradle.kts deleted file mode 100644 index c6542e3e..00000000 --- a/build-logic/src/main/java/com.streamplayer.compose.gradle.kts +++ /dev/null @@ -1,22 +0,0 @@ -@file:Suppress("UnstableApiUsage") -import extensions.getBundle -import extensions.getLibrary -import extensions.setupCompose - -plugins { - id("com.streamplayer.android-library") -} - -val libs: VersionCatalog = extensions.getByType().named("libs") - -android { - setupCompose(libs) -} - -dependencies { - implementation(platform(libs.getLibrary("compose.bom"))) - androidTestImplementation(platform(libs.getLibrary("compose.bom"))) - - implementation(libs.getBundle("compose")) - debugImplementation(libs.getLibrary("compose.ui.tooling")) -} \ No newline at end of file diff --git a/build-logic/src/main/java/com.streamplayer.android-library.gradle.kts b/build-logic/src/main/java/com.streamplayer.kmp-library.gradle.kts similarity index 71% rename from build-logic/src/main/java/com.streamplayer.android-library.gradle.kts rename to build-logic/src/main/java/com.streamplayer.kmp-library.gradle.kts index 6b0ea5af..5d5d4c7b 100644 --- a/build-logic/src/main/java/com.streamplayer.android-library.gradle.kts +++ b/build-logic/src/main/java/com.streamplayer.kmp-library.gradle.kts @@ -2,16 +2,20 @@ import extensions.dokkaPlugin import extensions.getLibrary +import extensions.iosTarget import extensions.setupAndroidDefaultConfig import extensions.setupCompileOptions import extensions.setupNameSpace import extensions.setupPackingOptions +import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi +import org.jetbrains.kotlin.gradle.dsl.JvmTarget -val libs: VersionCatalog = extensions.getByType().named("libs") +val libs: VersionCatalog = extensions.getByType().named("libs") plugins { + id("org.jetbrains.kotlin.multiplatform") id("com.android.library") - id("kotlin-android") + id("org.jetbrains.kotlin.plugin.serialization") id("kotlin-kapt") id("kotlin-parcelize") id("com.streamplayer.dokka") @@ -19,6 +23,17 @@ plugins { id("com.streamplayer.detekt") } +kotlin { + androidTarget { + @OptIn(ExperimentalKotlinGradlePluginApi::class) + compilerOptions { + jvmTarget.set(JvmTarget.JVM_17) + } + } + + iosTarget() +} + android { setupNameSpace(project) @@ -44,4 +59,4 @@ android { dependencies { dokkaPlugin(libs.getLibrary("dokka")) -} \ No newline at end of file +} diff --git a/build-logic/src/main/java/extensions/CommonExtensions.kt b/build-logic/src/main/java/extensions/CommonExtensions.kt index 84543ee2..a54f3d85 100644 --- a/build-logic/src/main/java/extensions/CommonExtensions.kt +++ b/build-logic/src/main/java/extensions/CommonExtensions.kt @@ -7,10 +7,10 @@ import com.android.build.api.dsl.CommonExtension import org.gradle.api.JavaVersion import org.gradle.api.Project import org.gradle.api.artifacts.VersionCatalog -import org.gradle.api.plugins.ExtensionAware -import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions +import org.gradle.api.artifacts.VersionCatalogsExtension +import org.gradle.kotlin.dsl.getByType -internal fun CommonExtension<*, *, *, *, *>.setupPackingOptions() { +internal fun CommonExtension<*, *, *, *, *, *>.setupPackingOptions() { packaging { resources { with(pickFirsts) { @@ -26,7 +26,7 @@ internal fun CommonExtension<*, *, *, *, *>.setupPackingOptions() { } } -internal fun CommonExtension<*, *, *, *, *>.setupAndroidDefaultConfig() { +internal fun CommonExtension<*, *, *, *, *, *>.setupAndroidDefaultConfig() { defaultConfig { compileSdk = Config.compileSdkVersion minSdk = Config.minSdkVersion @@ -36,39 +36,14 @@ internal fun CommonExtension<*, *, *, *, *>.setupAndroidDefaultConfig() { } } -internal fun CommonExtension<*, *, *, *, *>.setupCompileOptions() { +internal fun CommonExtension<*, *, *, *, *, *>.setupCompileOptions() { compileOptions { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } - - kotlinOptions { - jvmTarget = "17" - } -} - -fun CommonExtension<*, *, *, *, *>.setupCompose(catalog: VersionCatalog) { - buildFeatures { - compose = true - buildConfig = true - } - - composeOptions { - kotlinCompilerExtensionVersion = "${catalog.getVersion("compose")}" - } - - packaging { - resources { - excludes.apply { - add("META-INF/AL2.0") - add("META-INF/LGPL2.1") - } - } - } } - -internal fun CommonExtension<*, *, *, *, *>.setupNameSpace(project: Project) { +internal fun CommonExtension<*, *, *, *, *, *>.setupNameSpace(project: Project) { val moduleName = project.displayName .removePrefix("project ") .replace(":", ".") @@ -76,8 +51,12 @@ internal fun CommonExtension<*, *, *, *, *>.setupNameSpace(project: Project) { .replace("-", ".") namespace = "${Config.applicationId}$moduleName" -} -private fun CommonExtension<*, *, *, *, *>.kotlinOptions(block: KotlinJvmOptions.() -> Unit) { - (this as ExtensionAware).extensions.configure("kotlinOptions", block) + println(">>>> $namespace") } + +internal val Project.libs: VersionCatalog + get() { + return project.extensions.getByType() + .named("libs") + } \ No newline at end of file diff --git a/build-logic/src/main/java/extensions/KotlinMultiPlatformExt.kt b/build-logic/src/main/java/extensions/KotlinMultiPlatformExt.kt new file mode 100644 index 00000000..bd263ef0 --- /dev/null +++ b/build-logic/src/main/java/extensions/KotlinMultiPlatformExt.kt @@ -0,0 +1,17 @@ +package extensions + +import Config +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension + +fun KotlinMultiplatformExtension.iosTarget() { + listOf( + iosX64(), + iosArm64(), + iosSimulatorArm64() + ).forEach { iosTarget -> + iosTarget.binaries.framework { + baseName = Config.appName + isStatic = true + } + } +} diff --git a/build-logic/src/main/java/extensions/VersionCatalog.kt b/build-logic/src/main/java/extensions/VersionCatalog.kt index ee317e56..fcfdaf10 100644 --- a/build-logic/src/main/java/extensions/VersionCatalog.kt +++ b/build-logic/src/main/java/extensions/VersionCatalog.kt @@ -6,3 +6,11 @@ internal fun VersionCatalog.getLibrary(library: String) = findLibrary(library).g internal fun VersionCatalog.getVersion(library: String) = findVersion(library).get() internal fun VersionCatalog.getBundle(bundle: String) = findBundle(bundle).get() +internal fun VersionCatalog.koinCoreDependency() = findLibrary("koin_core").get() + +internal fun VersionCatalog.koinAnnotationsDependency() = findLibrary("koin_annotations").get() + +internal fun VersionCatalog.koinComposeDependency() = findLibrary("koin_compose").get() + +internal fun VersionCatalog.koinCompiler() = findLibrary("koin_ksp_compiler").get() + diff --git a/build.gradle.kts b/build.gradle.kts index df8846e7..4e1f6f7b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,9 +5,14 @@ plugins { alias(libs.plugins.android.application) apply false alias(libs.plugins.android.library) apply false alias(libs.plugins.kotlin.android) apply false + alias(libs.plugins.serialization) apply false + alias(libs.plugins.kotlin.multiplatform) apply false + alias(libs.plugins.jetbrains.compose) apply false + alias(libs.plugins.compose.compiler) apply false alias(libs.plugins.ksp) apply false alias(libs.plugins.dokka) apply false alias(libs.plugins.kover) apply false + alias(libs.plugins.buildkonfig.plugin) apply false } tasks.register("clean", Delete::class) { diff --git a/build/kotlin/commonizedNativeDistributionLocation.txt b/build/kotlin/commonizedNativeDistributionLocation.txt new file mode 100644 index 00000000..64f5ff0e --- /dev/null +++ b/build/kotlin/commonizedNativeDistributionLocation.txt @@ -0,0 +1 @@ +/Users/rodrigo/.konan/kotlin-native-prebuilt-macos-aarch64-2.1.10/klib/commonized/2.1.10 \ No newline at end of file diff --git a/app/.gitignore b/composeApp/.gitignore similarity index 100% rename from app/.gitignore rename to composeApp/.gitignore diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts new file mode 100644 index 00000000..21c08c2b --- /dev/null +++ b/composeApp/build.gradle.kts @@ -0,0 +1,40 @@ +@file:Suppress("UnstableApiUsage") + +plugins { + id("com.streamplayer.application") + alias(libs.plugins.jetbrains.compose) + alias(libs.plugins.compose.compiler) +} +kotlin { + sourceSets { + androidMain.dependencies { + implementation(libs.koin.android) + implementation(libs.lottie) + implementation(compose.preview) + } + commonMain.dependencies { + implementation(projects.featureListStreams) + implementation(projects.featureDetail) + implementation(projects.featureSearch) + implementation(projects.featureProfile) + implementation(projects.coreShared) + implementation(projects.coreSharedUi) + implementation(projects.coreNavigation) + implementation(projects.coreNetworking) + implementation(projects.coreLocalStorage) + + implementation(libs.navigation.compose) + + implementation(compose.material3) + implementation(compose.ui) + implementation(compose.components.resources) + + implementation(libs.koin.core) + } + } +} + +dependencies { + // Kover - Combined report + rootProject.subprojects.forEach { kover(it) } +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/composeApp/proguard-rules.pro similarity index 100% rename from app/proguard-rules.pro rename to composeApp/proguard-rules.pro diff --git a/app/src/main/AndroidManifest.xml b/composeApp/src/androidMain/AndroidManifest.xml similarity index 72% rename from app/src/main/AndroidManifest.xml rename to composeApp/src/androidMain/AndroidManifest.xml index 43b331ce..a074f2bb 100644 --- a/app/src/main/AndroidManifest.xml +++ b/composeApp/src/androidMain/AndroidManifest.xml @@ -3,16 +3,14 @@ + android:name=".presentation.CustomApplication"> diff --git a/app/src/main/java/com/codandotv/streamplayerapp/CustomApplication.kt b/composeApp/src/androidMain/kotlin/com.codandotv.streamplayerapp/presentation/CustomApplication.kt similarity index 88% rename from app/src/main/java/com/codandotv/streamplayerapp/CustomApplication.kt rename to composeApp/src/androidMain/kotlin/com.codandotv.streamplayerapp/presentation/CustomApplication.kt index 9c565d56..8cbc1494 100644 --- a/app/src/main/java/com/codandotv/streamplayerapp/CustomApplication.kt +++ b/composeApp/src/androidMain/kotlin/com.codandotv.streamplayerapp/presentation/CustomApplication.kt @@ -1,4 +1,4 @@ -package com.codandotv.streamplayerapp +package com.codandotv.streamplayerapp.presentation import android.app.Application import com.codandotv.streamplayerapp.di.AppModule diff --git a/composeApp/src/androidMain/kotlin/com.codandotv.streamplayerapp/presentation/MainActivity.kt b/composeApp/src/androidMain/kotlin/com.codandotv.streamplayerapp/presentation/MainActivity.kt new file mode 100644 index 00000000..d3824ddd --- /dev/null +++ b/composeApp/src/androidMain/kotlin/com.codandotv.streamplayerapp/presentation/MainActivity.kt @@ -0,0 +1,15 @@ +package com.codandotv.streamplayerapp.presentation + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import com.codandotv.streamplayerapp.StreamPlayerApp + +class MainActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + StreamPlayerApp() + } + } +} diff --git a/composeApp/src/androidMain/kotlin/com.codandotv.streamplayerapp/presentation/components/LottieComponentPlatform.android.kt b/composeApp/src/androidMain/kotlin/com.codandotv.streamplayerapp/presentation/components/LottieComponentPlatform.android.kt new file mode 100644 index 00000000..d7a7f74f --- /dev/null +++ b/composeApp/src/androidMain/kotlin/com.codandotv.streamplayerapp/presentation/components/LottieComponentPlatform.android.kt @@ -0,0 +1,34 @@ +package com.codandotv.streamplayerapp.presentation.components + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import com.airbnb.lottie.compose.LottieAnimation +import com.airbnb.lottie.compose.LottieCompositionSpec +import com.airbnb.lottie.compose.animateLottieCompositionAsState +import com.airbnb.lottie.compose.rememberLottieComposition + +@Composable +actual fun LottieComponent( + jsonString: String, + modifier: Modifier, + onAnimationFinished: () -> Unit +) { + val composition by rememberLottieComposition( + spec = LottieCompositionSpec.JsonString( + jsonString = jsonString + ) + ) + val logoAnimationState = animateLottieCompositionAsState( + composition = composition + ) + + LottieAnimation( + composition = composition, + progress = { logoAnimationState.progress } + ) + + if (logoAnimationState.isAtEnd && logoAnimationState.isPlaying) { + onAnimationFinished() + } +} diff --git a/composeApp/src/commonMain/composeResources/files/lottie/logo.json b/composeApp/src/commonMain/composeResources/files/lottie/logo.json new file mode 100644 index 00000000..32536ffa --- /dev/null +++ b/composeApp/src/commonMain/composeResources/files/lottie/logo.json @@ -0,0 +1,8141 @@ +{ + "v": "5.5.7", + "meta": { + "g": "LottieFiles AE 0.1.21", + "a": "", + "k": "", + "d": "", + "tc": "#FFFFFF" + }, + "fr": 60, + "ip": 0, + "op": 306, + "w": 512, + "h": 512, + "nm": "Nettflix", + "ddd": 0, + "assets": [], + "layers": [ + { + "ddd": 0, + "ind": 1, + "ty": 4, + "nm": "Big N 1", + "sr": 1, + "ks": { + "o": { + "a": 1, + "k": [ + { + "i": { + "x": [ + 0.667 + ], + "y": [ + 1 + ] + }, + "o": { + "x": [ + 0.333 + ], + "y": [ + 0 + ] + }, + "t": 18, + "s": [ + 0 + ] + }, + { + "i": { + "x": [ + 0.833 + ], + "y": [ + 1 + ] + }, + "o": { + "x": [ + 0.167 + ], + "y": [ + 0 + ] + }, + "t": 28.666, + "s": [ + 100 + ] + }, + { + "i": { + "x": [ + 1 + ], + "y": [ + 1 + ] + }, + "o": { + "x": [ + 0.612 + ], + "y": [ + 0 + ] + }, + "t": 114, + "s": [ + 100 + ] + }, + { + "t": 142, + "s": [ + 0 + ] + } + ], + "ix": 11 + }, + "r": { + "a": 0, + "k": 0, + "ix": 10 + }, + "p": { + "a": 1, + "k": [ + { + "i": { + "x": 0.455, + "y": 1 + }, + "o": { + "x": 0.684, + "y": 0 + }, + "t": 104, + "s": [ + 256, + 256, + 0 + ], + "to": [ + -24.667, + 0, + 0 + ], + "ti": [ + 24.667, + 0, + 0 + ] + }, + { + "t": 154.74609375, + "s": [ + 108, + 256, + 0 + ] + } + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + 0.209, + 0.143, + 0 + ], + "ix": 1 + }, + "s": { + "a": 1, + "k": [ + { + "i": { + "x": [ + 0.461, + 0.461, + 0.667 + ], + "y": [ + 1, + 1, + 1 + ] + }, + "o": { + "x": [ + 0.655, + 0.655, + 0.333 + ], + "y": [ + 0, + 0, + 0 + ] + }, + "t": 46, + "s": [ + 66, + 66, + 100 + ] + }, + { + "t": 104, + "s": [ + 21, + 21, + 100 + ] + } + ], + "ix": 6 + } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ix": 1, + "ks": { + "a": 1, + "k": [ + { + "i": { + "x": 0.252, + "y": 1 + }, + "o": { + "x": 0.434, + "y": 0 + }, + "t": 18, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 42.684, + 1.078 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + 120.607, + 218.722 + ], + [ + 31.805, + 211.525 + ], + [ + 31.977, + 211.212 + ], + [ + 120.318, + 218.496 + ] + ], + "c": true + } + ] + }, + { + "i": { + "x": 0.833, + "y": 1 + }, + "o": { + "x": 0.167, + "y": 0 + }, + "t": 46, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 42.684, + 1.078 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + -34.128, + -218.21 + ], + [ + -119.9, + -218.21 + ], + [ + 31.977, + 211.212 + ], + [ + 120.318, + 218.496 + ] + ], + "c": true + } + ] + }, + { + "i": { + "x": 0.833, + "y": 1 + }, + "o": { + "x": 0.167, + "y": 0 + }, + "t": 124, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 42.684, + 1.078 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + -34.128, + -218.21 + ], + [ + -119.9, + -218.21 + ], + [ + 31.977, + 211.212 + ], + [ + 120.318, + 218.496 + ] + ], + "c": true + } + ] + }, + { + "t": 156, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 44.422, + -6.307 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + -47.223, + -218.706 + ], + [ + -102.043, + -218.706 + ], + [ + 41.501, + 198.117 + ], + [ + 102.46, + 192.802 + ] + ], + "c": true + } + ] + } + ], + "ix": 2 + }, + "nm": "Path 1", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ty": "fl", + "c": { + "a": 0, + "k": [ + 0.898039215686, + 0.035294117647, + 0.078431372549, + 1 + ], + "ix": 4 + }, + "o": { + "a": 0, + "k": 100, + "ix": 5 + }, + "r": 1, + "bm": 0, + "nm": "Fill 1", + "mn": "ADBE Vector Graphic - Fill", + "hd": false + }, + { + "ty": "tr", + "p": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ], + "ix": 3 + }, + "r": { + "a": 0, + "k": 0, + "ix": 6 + }, + "o": { + "a": 0, + "k": 100, + "ix": 7 + }, + "sk": { + "a": 0, + "k": 0, + "ix": 4 + }, + "sa": { + "a": 0, + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Big N 1", + "np": 2, + "cix": 2, + "bm": 0, + "ix": 1, + "mn": "ADBE Vector Group", + "hd": false + } + ], + "ip": 0, + "op": 3868, + "st": 0, + "bm": 0 + }, + { + "ddd": 0, + "ind": 2, + "ty": 4, + "nm": "Big N 2 matte", + "parent": 1, + "td": 1, + "sr": 1, + "ks": { + "o": { + "a": 1, + "k": [ + { + "i": { + "x": [ + 0.667 + ], + "y": [ + 1 + ] + }, + "o": { + "x": [ + 0.333 + ], + "y": [ + 0 + ] + }, + "t": 0, + "s": [ + 0 + ] + }, + { + "i": { + "x": [ + 0.833 + ], + "y": [ + 1 + ] + }, + "o": { + "x": [ + 0.333 + ], + "y": [ + 0 + ] + }, + "t": 10.666, + "s": [ + 100 + ] + }, + { + "i": { + "x": [ + 1 + ], + "y": [ + 1 + ] + }, + "o": { + "x": [ + 0.612 + ], + "y": [ + 0 + ] + }, + "t": 114, + "s": [ + 100 + ] + }, + { + "t": 142, + "s": [ + 0 + ] + } + ], + "ix": 11 + }, + "r": { + "a": 0, + "k": 0, + "ix": 10 + }, + "p": { + "a": 0, + "k": [ + 77.223, + 0, + 0 + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + 77.223, + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100, + 100 + ], + "ix": 6 + } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ix": 1, + "ks": { + "a": 1, + "k": [ + { + "i": { + "x": 0.252, + "y": 1 + }, + "o": { + "x": 0.434, + "y": 0 + }, + "t": 0, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 1.198, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + -0.901, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + 34.099, + -359.119 + ], + [ + 120.288, + -359.43 + ], + [ + 120.49, + -359.888 + ], + [ + 33.164, + -359.117 + ] + ], + "c": true + } + ] + }, + { + "i": { + "x": 0.833, + "y": 1 + }, + "o": { + "x": 0.167, + "y": 0 + }, + "t": 24, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 28.673, + 0.875 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + -28.673, + -3.601 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + 34.128, + -218.21 + ], + [ + 120.318, + -218.521 + ], + [ + 120.318, + 218.521 + ], + [ + 34.128, + 211.337 + ] + ], + "c": true + } + ] + }, + { + "i": { + "x": 0.833, + "y": 1 + }, + "o": { + "x": 0.167, + "y": 0 + }, + "t": 124, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 28.673, + 0.875 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + -28.673, + -3.601 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + 34.128, + -218.21 + ], + [ + 120.318, + -218.521 + ], + [ + 120.318, + 218.521 + ], + [ + 34.128, + 211.337 + ] + ], + "c": true + } + ] + }, + { + "t": 156, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 28.249, + -4.53 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + -27.545, + 1.34 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + 48.414, + -218.706 + ], + [ + 114.365, + -217.965 + ], + [ + 116.869, + 194.041 + ], + [ + 44.408, + 201.102 + ] + ], + "c": true + } + ] + } + ], + "ix": 2 + }, + "nm": "Path 1", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ty": "fl", + "c": { + "a": 0, + "k": [ + 0.694117647059, + 0.023529411765, + 0.058823529412, + 1 + ], + "ix": 4 + }, + "o": { + "a": 0, + "k": 100, + "ix": 5 + }, + "r": 1, + "bm": 0, + "nm": "Fill 1", + "mn": "ADBE Vector Graphic - Fill", + "hd": false + }, + { + "ty": "tr", + "p": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ], + "ix": 3 + }, + "r": { + "a": 0, + "k": 0, + "ix": 6 + }, + "o": { + "a": 0, + "k": 100, + "ix": 7 + }, + "sk": { + "a": 0, + "k": 0, + "ix": 4 + }, + "sa": { + "a": 0, + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Big N 2", + "np": 2, + "cix": 2, + "bm": 0, + "ix": 1, + "mn": "ADBE Vector Group", + "hd": false + } + ], + "ip": 0, + "op": 3868, + "st": 0, + "bm": 0 + }, + { + "ddd": 0, + "ind": 3, + "ty": 4, + "nm": "Big N 1 shadow 2", + "tt": 1, + "sr": 1, + "ks": { + "o": { + "a": 1, + "k": [ + { + "i": { + "x": [ + 0.667 + ], + "y": [ + 1 + ] + }, + "o": { + "x": [ + 0.333 + ], + "y": [ + 0 + ] + }, + "t": 18, + "s": [ + 0 + ] + }, + { + "i": { + "x": [ + 0.833 + ], + "y": [ + 1 + ] + }, + "o": { + "x": [ + 0.167 + ], + "y": [ + 0 + ] + }, + "t": 28.666, + "s": [ + 100 + ] + }, + { + "i": { + "x": [ + 1 + ], + "y": [ + 1 + ] + }, + "o": { + "x": [ + 0.612 + ], + "y": [ + 0 + ] + }, + "t": 114, + "s": [ + 100 + ] + }, + { + "t": 142, + "s": [ + 0 + ] + } + ], + "ix": 11 + }, + "r": { + "a": 0, + "k": 0, + "ix": 10 + }, + "p": { + "a": 1, + "k": [ + { + "i": { + "x": 0.455, + "y": 1 + }, + "o": { + "x": 0.684, + "y": 0 + }, + "t": 104, + "s": [ + 256, + 256, + 0 + ], + "to": [ + -24.667, + 0, + 0 + ], + "ti": [ + 24.667, + 0, + 0 + ] + }, + { + "t": 154.74609375, + "s": [ + 108, + 256, + 0 + ] + } + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + 0.209, + 0.143, + 0 + ], + "ix": 1 + }, + "s": { + "a": 1, + "k": [ + { + "i": { + "x": [ + 0.461, + 0.461, + 0.667 + ], + "y": [ + 1, + 1, + 1 + ] + }, + "o": { + "x": [ + 0.655, + 0.655, + 0.333 + ], + "y": [ + 0, + 0, + 0 + ] + }, + "t": 46, + "s": [ + 66, + 66, + 100 + ] + }, + { + "t": 104, + "s": [ + 21, + 21, + 100 + ] + } + ], + "ix": 6 + } + }, + "ao": 0, + "ef": [ + { + "ty": 25, + "nm": "Drop Shadow", + "np": 8, + "mn": "ADBE Drop Shadow", + "ix": 1, + "en": 1, + "ef": [ + { + "ty": 2, + "nm": "Shadow Color", + "mn": "ADBE Drop Shadow-0001", + "ix": 1, + "v": { + "a": 0, + "k": [ + 0.086274512112, + 0, + 0.0074725952, + 1 + ], + "ix": 1 + } + }, + { + "ty": 0, + "nm": "Opacity", + "mn": "ADBE Drop Shadow-0002", + "ix": 2, + "v": { + "a": 0, + "k": 178.5, + "ix": 2 + } + }, + { + "ty": 0, + "nm": "Direction", + "mn": "ADBE Drop Shadow-0003", + "ix": 3, + "v": { + "a": 0, + "k": 0, + "ix": 3 + } + }, + { + "ty": 0, + "nm": "Distance", + "mn": "ADBE Drop Shadow-0004", + "ix": 4, + "v": { + "a": 0, + "k": 0, + "ix": 4 + } + }, + { + "ty": 0, + "nm": "Softness", + "mn": "ADBE Drop Shadow-0005", + "ix": 5, + "v": { + "a": 0, + "k": 100, + "ix": 5 + } + }, + { + "ty": 7, + "nm": "Shadow Only", + "mn": "ADBE Drop Shadow-0006", + "ix": 6, + "v": { + "a": 0, + "k": 0, + "ix": 6 + } + } + ] + } + ], + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ix": 1, + "ks": { + "a": 1, + "k": [ + { + "i": { + "x": 0.252, + "y": 1 + }, + "o": { + "x": 0.434, + "y": 0 + }, + "t": 18, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 42.684, + 1.078 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + 120.607, + 218.722 + ], + [ + 31.805, + 211.525 + ], + [ + 31.977, + 211.212 + ], + [ + 120.318, + 218.496 + ] + ], + "c": true + } + ] + }, + { + "i": { + "x": 0.833, + "y": 1 + }, + "o": { + "x": 0.167, + "y": 0 + }, + "t": 46, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 42.684, + 1.078 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + -34.128, + -218.21 + ], + [ + -119.9, + -218.21 + ], + [ + 31.977, + 211.212 + ], + [ + 120.318, + 218.496 + ] + ], + "c": true + } + ] + }, + { + "i": { + "x": 0.833, + "y": 1 + }, + "o": { + "x": 0.167, + "y": 0 + }, + "t": 124, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 42.684, + 1.078 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + -34.128, + -218.21 + ], + [ + -119.9, + -218.21 + ], + [ + 31.977, + 211.212 + ], + [ + 120.318, + 218.496 + ] + ], + "c": true + } + ] + }, + { + "t": 156, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 44.422, + -6.307 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + -47.223, + -218.706 + ], + [ + -102.043, + -218.706 + ], + [ + 41.501, + 198.117 + ], + [ + 102.46, + 192.802 + ] + ], + "c": true + } + ] + } + ], + "ix": 2 + }, + "nm": "Path 1", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ty": "fl", + "c": { + "a": 0, + "k": [ + 0.898039215686, + 0.035294117647, + 0.078431372549, + 1 + ], + "ix": 4 + }, + "o": { + "a": 0, + "k": 100, + "ix": 5 + }, + "r": 1, + "bm": 0, + "nm": "Fill 1", + "mn": "ADBE Vector Graphic - Fill", + "hd": false + }, + { + "ty": "tr", + "p": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ], + "ix": 3 + }, + "r": { + "a": 0, + "k": 0, + "ix": 6 + }, + "o": { + "a": 0, + "k": 100, + "ix": 7 + }, + "sk": { + "a": 0, + "k": 0, + "ix": 4 + }, + "sa": { + "a": 0, + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Big N 1", + "np": 2, + "cix": 2, + "bm": 0, + "ix": 1, + "mn": "ADBE Vector Group", + "hd": false + }, + { + "ty": "gr", + "it": [ + { + "ty": "tr", + "p": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ], + "ix": 3 + }, + "r": { + "a": 0, + "k": 0, + "ix": 6 + }, + "o": { + "a": 0, + "k": 100, + "ix": 7 + }, + "sk": { + "a": 0, + "k": 0, + "ix": 4 + }, + "sa": { + "a": 0, + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Group 1", + "np": 0, + "cix": 2, + "bm": 0, + "ix": 2, + "mn": "ADBE Vector Group", + "hd": false + } + ], + "ip": 0, + "op": 3868, + "st": 0, + "bm": 0 + }, + { + "ddd": 0, + "ind": 4, + "ty": 4, + "nm": "Big N 2", + "parent": 1, + "sr": 1, + "ks": { + "o": { + "a": 1, + "k": [ + { + "i": { + "x": [ + 0.667 + ], + "y": [ + 1 + ] + }, + "o": { + "x": [ + 0.333 + ], + "y": [ + 0 + ] + }, + "t": 0, + "s": [ + 0 + ] + }, + { + "i": { + "x": [ + 0.833 + ], + "y": [ + 1 + ] + }, + "o": { + "x": [ + 0.333 + ], + "y": [ + 0 + ] + }, + "t": 10.666, + "s": [ + 100 + ] + }, + { + "i": { + "x": [ + 1 + ], + "y": [ + 1 + ] + }, + "o": { + "x": [ + 0.612 + ], + "y": [ + 0 + ] + }, + "t": 114, + "s": [ + 100 + ] + }, + { + "t": 142, + "s": [ + 0 + ] + } + ], + "ix": 11 + }, + "r": { + "a": 0, + "k": 0, + "ix": 10 + }, + "p": { + "a": 0, + "k": [ + 77.223, + 0, + 0 + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + 77.223, + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100, + 100 + ], + "ix": 6 + } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ix": 1, + "ks": { + "a": 1, + "k": [ + { + "i": { + "x": 0.252, + "y": 1 + }, + "o": { + "x": 0.434, + "y": 0 + }, + "t": 0, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 1.198, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + -0.901, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + 34.099, + -359.119 + ], + [ + 120.288, + -359.43 + ], + [ + 120.49, + -359.888 + ], + [ + 33.164, + -359.117 + ] + ], + "c": true + } + ] + }, + { + "i": { + "x": 0.833, + "y": 1 + }, + "o": { + "x": 0.167, + "y": 0 + }, + "t": 24, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 28.673, + 0.875 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + -28.673, + -3.601 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + 34.128, + -218.21 + ], + [ + 120.318, + -218.521 + ], + [ + 120.318, + 218.521 + ], + [ + 34.128, + 211.337 + ] + ], + "c": true + } + ] + }, + { + "i": { + "x": 0.833, + "y": 1 + }, + "o": { + "x": 0.167, + "y": 0 + }, + "t": 124, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 28.673, + 0.875 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + -28.673, + -3.601 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + 34.128, + -218.21 + ], + [ + 120.318, + -218.521 + ], + [ + 120.318, + 218.521 + ], + [ + 34.128, + 211.337 + ] + ], + "c": true + } + ] + }, + { + "t": 156, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 28.249, + -4.53 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + -27.545, + 1.34 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + 48.414, + -218.706 + ], + [ + 114.365, + -217.965 + ], + [ + 116.869, + 194.041 + ], + [ + 44.408, + 201.102 + ] + ], + "c": true + } + ] + } + ], + "ix": 2 + }, + "nm": "Path 1", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ty": "fl", + "c": { + "a": 0, + "k": [ + 0.694117647059, + 0.023529411765, + 0.058823529412, + 1 + ], + "ix": 4 + }, + "o": { + "a": 0, + "k": 100, + "ix": 5 + }, + "r": 1, + "bm": 0, + "nm": "Fill 1", + "mn": "ADBE Vector Graphic - Fill", + "hd": false + }, + { + "ty": "tr", + "p": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ], + "ix": 3 + }, + "r": { + "a": 0, + "k": 0, + "ix": 6 + }, + "o": { + "a": 0, + "k": 100, + "ix": 7 + }, + "sk": { + "a": 0, + "k": 0, + "ix": 4 + }, + "sa": { + "a": 0, + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Big N 2", + "np": 2, + "cix": 2, + "bm": 0, + "ix": 1, + "mn": "ADBE Vector Group", + "hd": false + } + ], + "ip": 0, + "op": 3868, + "st": 0, + "bm": 0 + }, + { + "ddd": 0, + "ind": 5, + "ty": 4, + "nm": "Big N 3 matte", + "parent": 1, + "td": 1, + "sr": 1, + "ks": { + "o": { + "a": 1, + "k": [ + { + "i": { + "x": [ + 0.667 + ], + "y": [ + 1 + ] + }, + "o": { + "x": [ + 0.333 + ], + "y": [ + 0 + ] + }, + "t": 38, + "s": [ + 0 + ] + }, + { + "i": { + "x": [ + 0.833 + ], + "y": [ + 1 + ] + }, + "o": { + "x": [ + 0.167 + ], + "y": [ + 0 + ] + }, + "t": 48.666, + "s": [ + 100 + ] + }, + { + "i": { + "x": [ + 1 + ], + "y": [ + 1 + ] + }, + "o": { + "x": [ + 0.612 + ], + "y": [ + 0 + ] + }, + "t": 114, + "s": [ + 100 + ] + }, + { + "t": 142, + "s": [ + 0 + ] + } + ], + "ix": 11 + }, + "r": { + "a": 0, + "k": 0, + "ix": 10 + }, + "p": { + "a": 0, + "k": [ + -77.223, + 0, + 0 + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + -77.223, + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100, + 100 + ], + "ix": 6 + } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ix": 1, + "ks": { + "a": 1, + "k": [ + { + "i": { + "x": 0.252, + "y": 1 + }, + "o": { + "x": 0.434, + "y": 0 + }, + "t": 38, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 1.089 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 26.294, + 0.724 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + -34.128, + -218.21 + ], + [ + -120.318, + -218.521 + ], + [ + -120.72, + -218.979 + ], + [ + -34.705, + -218.587 + ] + ], + "c": true + } + ] + }, + { + "i": { + "x": 0.833, + "y": 1 + }, + "o": { + "x": 0.167, + "y": 0 + }, + "t": 60, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + -28.673, + 0.875 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 28.673, + -3.601 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + -34.128, + -218.21 + ], + [ + -120.318, + -218.521 + ], + [ + -120.318, + 218.521 + ], + [ + -34.128, + 211.337 + ] + ], + "c": true + } + ] + }, + { + "i": { + "x": 0.833, + "y": 1 + }, + "o": { + "x": 0.167, + "y": 0 + }, + "t": 124, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + -28.673, + 0.875 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 28.673, + -3.601 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + -34.128, + -218.21 + ], + [ + -120.318, + -218.521 + ], + [ + -120.318, + 218.521 + ], + [ + -34.128, + 211.337 + ] + ], + "c": true + } + ] + }, + { + "t": 156, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + -28.758, + -0.959 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 28.673, + -3.601 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + -43.652, + -218.74 + ], + [ + -106.032, + -218.137 + ], + [ + -106.032, + 217.33 + ], + [ + -37.7, + 211.816 + ] + ], + "c": true + } + ] + } + ], + "ix": 2 + }, + "nm": "Path 1", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ty": "fl", + "c": { + "a": 0, + "k": [ + 0.694117647059, + 0.023529411765, + 0.058823529412, + 1 + ], + "ix": 4 + }, + "o": { + "a": 0, + "k": 100, + "ix": 5 + }, + "r": 1, + "bm": 0, + "nm": "Fill 1", + "mn": "ADBE Vector Graphic - Fill", + "hd": false + }, + { + "ty": "tr", + "p": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ], + "ix": 3 + }, + "r": { + "a": 0, + "k": 0, + "ix": 6 + }, + "o": { + "a": 0, + "k": 100, + "ix": 7 + }, + "sk": { + "a": 0, + "k": 0, + "ix": 4 + }, + "sa": { + "a": 0, + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Big N 3", + "np": 2, + "cix": 2, + "bm": 0, + "ix": 1, + "mn": "ADBE Vector Group", + "hd": false + } + ], + "ip": 0, + "op": 3868, + "st": 0, + "bm": 0 + }, + { + "ddd": 0, + "ind": 6, + "ty": 4, + "nm": "Big N 1 shadow", + "tt": 1, + "sr": 1, + "ks": { + "o": { + "a": 1, + "k": [ + { + "i": { + "x": [ + 0.667 + ], + "y": [ + 1 + ] + }, + "o": { + "x": [ + 0.333 + ], + "y": [ + 0 + ] + }, + "t": 18, + "s": [ + 0 + ] + }, + { + "i": { + "x": [ + 0.833 + ], + "y": [ + 1 + ] + }, + "o": { + "x": [ + 0.167 + ], + "y": [ + 0 + ] + }, + "t": 28.666, + "s": [ + 100 + ] + }, + { + "i": { + "x": [ + 1 + ], + "y": [ + 1 + ] + }, + "o": { + "x": [ + 0.612 + ], + "y": [ + 0 + ] + }, + "t": 114, + "s": [ + 100 + ] + }, + { + "t": 142, + "s": [ + 0 + ] + } + ], + "ix": 11 + }, + "r": { + "a": 0, + "k": 0, + "ix": 10 + }, + "p": { + "a": 1, + "k": [ + { + "i": { + "x": 0.455, + "y": 1 + }, + "o": { + "x": 0.684, + "y": 0 + }, + "t": 104, + "s": [ + 256, + 256, + 0 + ], + "to": [ + -24.667, + 0, + 0 + ], + "ti": [ + 24.667, + 0, + 0 + ] + }, + { + "t": 154.74609375, + "s": [ + 108, + 256, + 0 + ] + } + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + 0.209, + 0.143, + 0 + ], + "ix": 1 + }, + "s": { + "a": 1, + "k": [ + { + "i": { + "x": [ + 0.461, + 0.461, + 0.667 + ], + "y": [ + 1, + 1, + 1 + ] + }, + "o": { + "x": [ + 0.655, + 0.655, + 0.333 + ], + "y": [ + 0, + 0, + 0 + ] + }, + "t": 46, + "s": [ + 66, + 66, + 100 + ] + }, + { + "t": 104, + "s": [ + 21, + 21, + 100 + ] + } + ], + "ix": 6 + } + }, + "ao": 0, + "ef": [ + { + "ty": 25, + "nm": "Drop Shadow", + "np": 8, + "mn": "ADBE Drop Shadow", + "ix": 1, + "en": 1, + "ef": [ + { + "ty": 2, + "nm": "Shadow Color", + "mn": "ADBE Drop Shadow-0001", + "ix": 1, + "v": { + "a": 0, + "k": [ + 0.086274512112, + 0, + 0.0074725952, + 1 + ], + "ix": 1 + } + }, + { + "ty": 0, + "nm": "Opacity", + "mn": "ADBE Drop Shadow-0002", + "ix": 2, + "v": { + "a": 0, + "k": 178.5, + "ix": 2 + } + }, + { + "ty": 0, + "nm": "Direction", + "mn": "ADBE Drop Shadow-0003", + "ix": 3, + "v": { + "a": 0, + "k": 0, + "ix": 3 + } + }, + { + "ty": 0, + "nm": "Distance", + "mn": "ADBE Drop Shadow-0004", + "ix": 4, + "v": { + "a": 0, + "k": 0, + "ix": 4 + } + }, + { + "ty": 0, + "nm": "Softness", + "mn": "ADBE Drop Shadow-0005", + "ix": 5, + "v": { + "a": 0, + "k": 100, + "ix": 5 + } + }, + { + "ty": 7, + "nm": "Shadow Only", + "mn": "ADBE Drop Shadow-0006", + "ix": 6, + "v": { + "a": 0, + "k": 0, + "ix": 6 + } + } + ] + } + ], + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ix": 1, + "ks": { + "a": 1, + "k": [ + { + "i": { + "x": 0.252, + "y": 1 + }, + "o": { + "x": 0.434, + "y": 0 + }, + "t": 18, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 42.684, + 1.078 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + 120.607, + 218.722 + ], + [ + 31.805, + 211.525 + ], + [ + 31.977, + 211.212 + ], + [ + 120.318, + 218.496 + ] + ], + "c": true + } + ] + }, + { + "i": { + "x": 0.833, + "y": 1 + }, + "o": { + "x": 0.167, + "y": 0 + }, + "t": 46, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 42.684, + 1.078 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + -34.128, + -218.21 + ], + [ + -119.9, + -218.21 + ], + [ + 31.977, + 211.212 + ], + [ + 120.318, + 218.496 + ] + ], + "c": true + } + ] + }, + { + "i": { + "x": 0.833, + "y": 1 + }, + "o": { + "x": 0.167, + "y": 0 + }, + "t": 124, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 42.684, + 1.078 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + -34.128, + -218.21 + ], + [ + -119.9, + -218.21 + ], + [ + 31.977, + 211.212 + ], + [ + 120.318, + 218.496 + ] + ], + "c": true + } + ] + }, + { + "t": 156, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 44.422, + -6.307 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + -47.223, + -218.706 + ], + [ + -102.043, + -218.706 + ], + [ + 41.501, + 198.117 + ], + [ + 102.46, + 192.802 + ] + ], + "c": true + } + ] + } + ], + "ix": 2 + }, + "nm": "Path 1", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ty": "fl", + "c": { + "a": 0, + "k": [ + 0.898039215686, + 0.035294117647, + 0.078431372549, + 1 + ], + "ix": 4 + }, + "o": { + "a": 0, + "k": 100, + "ix": 5 + }, + "r": 1, + "bm": 0, + "nm": "Fill 1", + "mn": "ADBE Vector Graphic - Fill", + "hd": false + }, + { + "ty": "tr", + "p": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ], + "ix": 3 + }, + "r": { + "a": 0, + "k": 0, + "ix": 6 + }, + "o": { + "a": 0, + "k": 100, + "ix": 7 + }, + "sk": { + "a": 0, + "k": 0, + "ix": 4 + }, + "sa": { + "a": 0, + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Big N 1", + "np": 2, + "cix": 2, + "bm": 0, + "ix": 1, + "mn": "ADBE Vector Group", + "hd": false + } + ], + "ip": 0, + "op": 3868, + "st": 0, + "bm": 0 + }, + { + "ddd": 0, + "ind": 7, + "ty": 4, + "nm": "Big N 3", + "parent": 1, + "sr": 1, + "ks": { + "o": { + "a": 1, + "k": [ + { + "i": { + "x": [ + 0.667 + ], + "y": [ + 1 + ] + }, + "o": { + "x": [ + 0.333 + ], + "y": [ + 0 + ] + }, + "t": 38, + "s": [ + 0 + ] + }, + { + "i": { + "x": [ + 0.833 + ], + "y": [ + 1 + ] + }, + "o": { + "x": [ + 0.167 + ], + "y": [ + 0 + ] + }, + "t": 48.666, + "s": [ + 100 + ] + }, + { + "i": { + "x": [ + 1 + ], + "y": [ + 1 + ] + }, + "o": { + "x": [ + 0.612 + ], + "y": [ + 0 + ] + }, + "t": 114, + "s": [ + 100 + ] + }, + { + "t": 142, + "s": [ + 0 + ] + } + ], + "ix": 11 + }, + "r": { + "a": 0, + "k": 0, + "ix": 10 + }, + "p": { + "a": 0, + "k": [ + -77.223, + 0, + 0 + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + -77.223, + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100, + 100 + ], + "ix": 6 + } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ix": 1, + "ks": { + "a": 1, + "k": [ + { + "i": { + "x": 0.252, + "y": 1 + }, + "o": { + "x": 0.434, + "y": 0 + }, + "t": 38, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 1.089 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 26.294, + 0.724 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + -34.128, + -218.21 + ], + [ + -120.318, + -218.521 + ], + [ + -120.72, + -218.979 + ], + [ + -34.705, + -218.587 + ] + ], + "c": true + } + ] + }, + { + "i": { + "x": 0.833, + "y": 1 + }, + "o": { + "x": 0.167, + "y": 0 + }, + "t": 60, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + -28.673, + 0.875 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 28.673, + -3.601 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + -34.128, + -218.21 + ], + [ + -120.318, + -218.521 + ], + [ + -120.318, + 218.521 + ], + [ + -34.128, + 211.337 + ] + ], + "c": true + } + ] + }, + { + "i": { + "x": 0.833, + "y": 1 + }, + "o": { + "x": 0.167, + "y": 0 + }, + "t": 124, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + -28.673, + 0.875 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 28.673, + -3.601 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + -34.128, + -218.21 + ], + [ + -120.318, + -218.521 + ], + [ + -120.318, + 218.521 + ], + [ + -34.128, + 211.337 + ] + ], + "c": true + } + ] + }, + { + "t": 156, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + -28.758, + -0.959 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 28.673, + -3.601 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + -43.652, + -218.74 + ], + [ + -106.032, + -218.137 + ], + [ + -106.032, + 217.33 + ], + [ + -37.7, + 211.816 + ] + ], + "c": true + } + ] + } + ], + "ix": 2 + }, + "nm": "Path 1", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ty": "fl", + "c": { + "a": 0, + "k": [ + 0.694117647059, + 0.023529411765, + 0.058823529412, + 1 + ], + "ix": 4 + }, + "o": { + "a": 0, + "k": 100, + "ix": 5 + }, + "r": 1, + "bm": 0, + "nm": "Fill 1", + "mn": "ADBE Vector Graphic - Fill", + "hd": false + }, + { + "ty": "tr", + "p": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ], + "ix": 3 + }, + "r": { + "a": 0, + "k": 0, + "ix": 6 + }, + "o": { + "a": 0, + "k": 100, + "ix": 7 + }, + "sk": { + "a": 0, + "k": 0, + "ix": 4 + }, + "sa": { + "a": 0, + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Big N 3", + "np": 2, + "cix": 2, + "bm": 0, + "ix": 1, + "mn": "ADBE Vector Group", + "hd": false + } + ], + "ip": 0, + "op": 3868, + "st": 0, + "bm": 0 + }, + { + "ddd": 0, + "ind": 8, + "ty": 4, + "nm": "Netflix reveal", + "parent": 9, + "td": 1, + "sr": 1, + "ks": { + "o": { + "a": 0, + "k": 100, + "ix": 11 + }, + "r": { + "a": 0, + "k": 0, + "ix": 10 + }, + "p": { + "a": 0, + "k": [ + 0, + 0, + 0 + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + 0, + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100, + 100 + ], + "ix": 6 + } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ix": 1, + "ks": { + "a": 1, + "k": [ + { + "i": { + "x": 0.715, + "y": 1 + }, + "o": { + "x": 0.414, + "y": 0 + }, + "t": 206.207, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + 166, + -55 + ], + [ + 165, + -52 + ] + ], + "c": false + } + ] + }, + { + "t": 220, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + 164, + -51 + ], + [ + 125, + 45.5 + ] + ], + "c": false + } + ] + } + ], + "ix": 2 + }, + "nm": "Path 1", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ty": "st", + "c": { + "a": 0, + "k": [ + 1, + 1, + 1, + 1 + ], + "ix": 3 + }, + "o": { + "a": 0, + "k": 100, + "ix": 4 + }, + "w": { + "a": 0, + "k": 20, + "ix": 5 + }, + "lc": 1, + "lj": 1, + "ml": 4, + "bm": 0, + "nm": "Stroke 1", + "mn": "ADBE Vector Graphic - Stroke", + "hd": false + }, + { + "ty": "tr", + "p": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ], + "ix": 3 + }, + "r": { + "a": 0, + "k": 0, + "ix": 6 + }, + "o": { + "a": 0, + "k": 100, + "ix": 7 + }, + "sk": { + "a": 0, + "k": 0, + "ix": 4 + }, + "sa": { + "a": 0, + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Shape 2", + "np": 3, + "cix": 2, + "bm": 0, + "ix": 1, + "mn": "ADBE Vector Group", + "hd": false + }, + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ix": 1, + "ks": { + "a": 1, + "k": [ + { + "i": { + "x": 0.715, + "y": 1 + }, + "o": { + "x": 0.414, + "y": 0 + }, + "t": 200.297, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + 125, + -54.5 + ], + [ + 125, + -52 + ] + ], + "c": false + } + ] + }, + { + "t": 214.08984375, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + 126.5, + -52 + ], + [ + 164, + 50 + ] + ], + "c": false + } + ] + } + ], + "ix": 2 + }, + "nm": "Path 1", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ty": "st", + "c": { + "a": 0, + "k": [ + 1, + 1, + 1, + 1 + ], + "ix": 3 + }, + "o": { + "a": 0, + "k": 100, + "ix": 4 + }, + "w": { + "a": 0, + "k": 20, + "ix": 5 + }, + "lc": 1, + "lj": 1, + "ml": 4, + "bm": 0, + "nm": "Stroke 1", + "mn": "ADBE Vector Graphic - Stroke", + "hd": false + }, + { + "ty": "tr", + "p": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ], + "ix": 3 + }, + "r": { + "a": 0, + "k": 0, + "ix": 6 + }, + "o": { + "a": 0, + "k": 100, + "ix": 7 + }, + "sk": { + "a": 0, + "k": 0, + "ix": 4 + }, + "sa": { + "a": 0, + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Shape 1", + "np": 3, + "cix": 2, + "bm": 0, + "ix": 2, + "mn": "ADBE Vector Group", + "hd": false + }, + { + "ty": "tr", + "p": { + "a": 0, + "k": [ + 144.5, + -1 + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + 144.5, + -1 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ], + "ix": 3 + }, + "r": { + "a": 0, + "k": 0, + "ix": 6 + }, + "o": { + "a": 0, + "k": 100, + "ix": 7 + }, + "sk": { + "a": 0, + "k": 0, + "ix": 4 + }, + "sa": { + "a": 0, + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "X", + "np": 2, + "cix": 2, + "bm": 0, + "ix": 1, + "mn": "ADBE Vector Group", + "hd": false + }, + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ix": 1, + "ks": { + "a": 1, + "k": [ + { + "i": { + "x": 0.715, + "y": 1 + }, + "o": { + "x": 0.414, + "y": 0 + }, + "t": 186.271, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + 100, + -51 + ], + [ + 100, + -48 + ] + ], + "c": false + } + ] + }, + { + "t": 198.09375, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + 100, + -47 + ], + [ + 100, + 42 + ] + ], + "c": false + } + ] + } + ], + "ix": 2 + }, + "nm": "Path 1", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ty": "st", + "c": { + "a": 0, + "k": [ + 1, + 1, + 1, + 1 + ], + "ix": 3 + }, + "o": { + "a": 0, + "k": 100, + "ix": 4 + }, + "w": { + "a": 0, + "k": 20, + "ix": 5 + }, + "lc": 1, + "lj": 1, + "ml": 4, + "bm": 0, + "nm": "Stroke 1", + "mn": "ADBE Vector Graphic - Stroke", + "hd": false + }, + { + "ty": "tr", + "p": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ], + "ix": 3 + }, + "r": { + "a": 0, + "k": 0, + "ix": 6 + }, + "o": { + "a": 0, + "k": 100, + "ix": 7 + }, + "sk": { + "a": 0, + "k": 0, + "ix": 4 + }, + "sa": { + "a": 0, + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "I", + "np": 3, + "cix": 2, + "bm": 0, + "ix": 2, + "mn": "ADBE Vector Group", + "hd": false + }, + { + "ty": "gr", + "it": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ix": 1, + "ks": { + "a": 1, + "k": [ + { + "i": { + "x": 0.715, + "y": 1 + }, + "o": { + "x": 0.414, + "y": 0 + }, + "t": 175.586, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + 37, + 29 + ], + [ + 40.5, + 29 + ] + ], + "c": false + } + ] + }, + { + "t": 189.37890625, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + 37, + 29 + ], + [ + 83.5, + 28.5 + ] + ], + "c": false + } + ] + } + ], + "ix": 2 + }, + "nm": "Path 1", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ty": "st", + "c": { + "a": 0, + "k": [ + 1, + 1, + 1, + 1 + ], + "ix": 3 + }, + "o": { + "a": 0, + "k": 100, + "ix": 4 + }, + "w": { + "a": 0, + "k": 20, + "ix": 5 + }, + "lc": 1, + "lj": 1, + "ml": 4, + "bm": 0, + "nm": "Stroke 1", + "mn": "ADBE Vector Graphic - Stroke", + "hd": false + }, + { + "ty": "tr", + "p": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ], + "ix": 3 + }, + "r": { + "a": 0, + "k": 0, + "ix": 6 + }, + "o": { + "a": 0, + "k": 100, + "ix": 7 + }, + "sk": { + "a": 0, + "k": 0, + "ix": 4 + }, + "sa": { + "a": 0, + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "L 2", + "np": 3, + "cix": 2, + "bm": 0, + "ix": 1, + "mn": "ADBE Vector Group", + "hd": false + }, + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ix": 1, + "ks": { + "a": 1, + "k": [ + { + "i": { + "x": 0.715, + "y": 1 + }, + "o": { + "x": 0.414, + "y": 0 + }, + "t": 171.645, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + 49, + -50.5 + ], + [ + 49, + -48.5 + ] + ], + "c": true + } + ] + }, + { + "t": 185.4375, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + 49, + -47.5 + ], + [ + 49.5, + 38 + ] + ], + "c": false + } + ] + } + ], + "ix": 2 + }, + "nm": "Path 1", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ty": "st", + "c": { + "a": 0, + "k": [ + 1, + 1, + 1, + 1 + ], + "ix": 3 + }, + "o": { + "a": 0, + "k": 100, + "ix": 4 + }, + "w": { + "a": 0, + "k": 20, + "ix": 5 + }, + "lc": 1, + "lj": 1, + "ml": 4, + "bm": 0, + "nm": "Stroke 1", + "mn": "ADBE Vector Graphic - Stroke", + "hd": false + }, + { + "ty": "tr", + "p": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ], + "ix": 3 + }, + "r": { + "a": 0, + "k": 0, + "ix": 6 + }, + "o": { + "a": 0, + "k": 100, + "ix": 7 + }, + "sk": { + "a": 0, + "k": 0, + "ix": 4 + }, + "sa": { + "a": 0, + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "L1", + "np": 3, + "cix": 2, + "bm": 0, + "ix": 2, + "mn": "ADBE Vector Group", + "hd": false + }, + { + "ty": "tr", + "p": { + "a": 0, + "k": [ + 60.25, + -4.75 + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + 60.25, + -4.75 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ], + "ix": 3 + }, + "r": { + "a": 0, + "k": 0, + "ix": 6 + }, + "o": { + "a": 0, + "k": 100, + "ix": 7 + }, + "sk": { + "a": 0, + "k": 0, + "ix": 4 + }, + "sa": { + "a": 0, + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "L", + "np": 2, + "cix": 2, + "bm": 0, + "ix": 3, + "mn": "ADBE Vector Group", + "hd": false + }, + { + "ty": "gr", + "it": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ix": 1, + "ks": { + "a": 1, + "k": [ + { + "i": { + "x": 0.715, + "y": 1 + }, + "o": { + "x": 0.414, + "y": 0 + }, + "t": 159.992, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + -9.5, + -7.5 + ], + [ + -11.5, + -7.5 + ] + ], + "c": false + } + ] + }, + { + "t": 175.75390625, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + 28, + -7.5 + ], + [ + -9.5, + -7.5 + ] + ], + "c": false + } + ] + } + ], + "ix": 2 + }, + "nm": "Path 1", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ty": "st", + "c": { + "a": 0, + "k": [ + 1, + 1, + 1, + 1 + ], + "ix": 3 + }, + "o": { + "a": 0, + "k": 100, + "ix": 4 + }, + "w": { + "a": 0, + "k": 20, + "ix": 5 + }, + "lc": 1, + "lj": 1, + "ml": 4, + "bm": 0, + "nm": "Stroke 1", + "mn": "ADBE Vector Graphic - Stroke", + "hd": false + }, + { + "ty": "tr", + "p": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ], + "ix": 3 + }, + "r": { + "a": 0, + "k": 0, + "ix": 6 + }, + "o": { + "a": 0, + "k": 100, + "ix": 7 + }, + "sk": { + "a": 0, + "k": 0, + "ix": 4 + }, + "sa": { + "a": 0, + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Shape 2", + "np": 3, + "cix": 2, + "bm": 0, + "ix": 1, + "mn": "ADBE Vector Group", + "hd": false + }, + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ix": 1, + "ks": { + "a": 1, + "k": [ + { + "i": { + "x": 0.715, + "y": 1 + }, + "o": { + "x": 0.414, + "y": 0 + }, + "t": 154.08, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + 0.5, + -50 + ], + [ + 0.5, + -48 + ] + ], + "c": false + } + ] + }, + { + "t": 169.84375, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + 0.5, + -48 + ], + [ + 0, + 37 + ] + ], + "c": false + } + ] + } + ], + "ix": 2 + }, + "nm": "Path 1", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ty": "st", + "c": { + "a": 0, + "k": [ + 1, + 1, + 1, + 1 + ], + "ix": 3 + }, + "o": { + "a": 0, + "k": 100, + "ix": 4 + }, + "w": { + "a": 0, + "k": 20, + "ix": 5 + }, + "lc": 1, + "lj": 1, + "ml": 4, + "bm": 0, + "nm": "Stroke 1", + "mn": "ADBE Vector Graphic - Stroke", + "hd": false + }, + { + "ty": "tr", + "p": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ], + "ix": 3 + }, + "r": { + "a": 0, + "k": 0, + "ix": 6 + }, + "o": { + "a": 0, + "k": 100, + "ix": 7 + }, + "sk": { + "a": 0, + "k": 0, + "ix": 4 + }, + "sa": { + "a": 0, + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Shape 3", + "np": 3, + "cix": 2, + "bm": 0, + "ix": 2, + "mn": "ADBE Vector Group", + "hd": false + }, + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ix": 1, + "ks": { + "a": 1, + "k": [ + { + "i": { + "x": 0.715, + "y": 1 + }, + "o": { + "x": 0.414, + "y": 0 + }, + "t": 145.266, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + -10.5, + -39.5 + ], + [ + -12, + -39.5 + ] + ], + "c": false + } + ] + }, + { + "t": 160.693359375, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + 36, + -39.5 + ], + [ + -9, + -39.5 + ] + ], + "c": false + } + ] + } + ], + "ix": 2 + }, + "nm": "Path 1", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ty": "st", + "c": { + "a": 0, + "k": [ + 1, + 1, + 1, + 1 + ], + "ix": 3 + }, + "o": { + "a": 0, + "k": 100, + "ix": 4 + }, + "w": { + "a": 0, + "k": 20, + "ix": 5 + }, + "lc": 1, + "lj": 1, + "ml": 4, + "bm": 0, + "nm": "Stroke 1", + "mn": "ADBE Vector Graphic - Stroke", + "hd": false + }, + { + "ty": "tr", + "p": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ], + "ix": 3 + }, + "r": { + "a": 0, + "k": 0, + "ix": 6 + }, + "o": { + "a": 0, + "k": 100, + "ix": 7 + }, + "sk": { + "a": 0, + "k": 0, + "ix": 4 + }, + "sa": { + "a": 0, + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Shape 1", + "np": 3, + "cix": 2, + "bm": 0, + "ix": 3, + "mn": "ADBE Vector Group", + "hd": false + }, + { + "ty": "tr", + "p": { + "a": 0, + "k": [ + 13.25, + -5.5 + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + 13.25, + -5.5 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ], + "ix": 3 + }, + "r": { + "a": 0, + "k": 0, + "ix": 6 + }, + "o": { + "a": 0, + "k": 100, + "ix": 7 + }, + "sk": { + "a": 0, + "k": 0, + "ix": 4 + }, + "sa": { + "a": 0, + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "F", + "np": 3, + "cix": 2, + "bm": 0, + "ix": 4, + "mn": "ADBE Vector Group", + "hd": false + }, + { + "ty": "gr", + "it": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ix": 1, + "ks": { + "a": 1, + "k": [ + { + "i": { + "x": 0.715, + "y": 1 + }, + "o": { + "x": 0.414, + "y": 0 + }, + "t": 136.115, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + -40.5, + -54 + ], + [ + -40.5, + -49.5 + ] + ], + "c": false + } + ] + }, + { + "t": 151.876953125, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + -38.5, + -45.5 + ], + [ + -39, + 38.5 + ] + ], + "c": false + } + ] + } + ], + "ix": 2 + }, + "nm": "Path 1", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ty": "st", + "c": { + "a": 0, + "k": [ + 1, + 1, + 1, + 1 + ], + "ix": 3 + }, + "o": { + "a": 0, + "k": 100, + "ix": 4 + }, + "w": { + "a": 0, + "k": 20, + "ix": 5 + }, + "lc": 1, + "lj": 1, + "ml": 4, + "bm": 0, + "nm": "Stroke 1", + "mn": "ADBE Vector Graphic - Stroke", + "hd": false + }, + { + "ty": "tr", + "p": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ], + "ix": 3 + }, + "r": { + "a": 0, + "k": 0, + "ix": 6 + }, + "o": { + "a": 0, + "k": 100, + "ix": 7 + }, + "sk": { + "a": 0, + "k": 0, + "ix": 4 + }, + "sa": { + "a": 0, + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Shape 2", + "np": 3, + "cix": 2, + "bm": 0, + "ix": 1, + "mn": "ADBE Vector Group", + "hd": false + }, + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ix": 1, + "ks": { + "a": 1, + "k": [ + { + "i": { + "x": 0.715, + "y": 1 + }, + "o": { + "x": 0.414, + "y": 0 + }, + "t": 132.174, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + -62.5, + -38.5 + ], + [ + -66, + -38.5 + ] + ], + "c": false + } + ] + }, + { + "t": 147.9375, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + -14.5, + -40.5 + ], + [ + -63.5, + -38.5 + ] + ], + "c": false + } + ] + } + ], + "ix": 2 + }, + "nm": "Path 1", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ty": "st", + "c": { + "a": 0, + "k": [ + 1, + 1, + 1, + 1 + ], + "ix": 3 + }, + "o": { + "a": 0, + "k": 100, + "ix": 4 + }, + "w": { + "a": 0, + "k": 20, + "ix": 5 + }, + "lc": 1, + "lj": 1, + "ml": 4, + "bm": 0, + "nm": "Stroke 1", + "mn": "ADBE Vector Graphic - Stroke", + "hd": false + }, + { + "ty": "tr", + "p": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ], + "ix": 3 + }, + "r": { + "a": 0, + "k": 0, + "ix": 6 + }, + "o": { + "a": 0, + "k": 100, + "ix": 7 + }, + "sk": { + "a": 0, + "k": 0, + "ix": 4 + }, + "sa": { + "a": 0, + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Shape 1", + "np": 3, + "cix": 2, + "bm": 0, + "ix": 2, + "mn": "ADBE Vector Group", + "hd": false + }, + { + "ty": "tr", + "p": { + "a": 0, + "k": [ + -39, + -3.5 + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + -39, + -3.5 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ], + "ix": 3 + }, + "r": { + "a": 0, + "k": 0, + "ix": 6 + }, + "o": { + "a": 0, + "k": 100, + "ix": 7 + }, + "sk": { + "a": 0, + "k": 0, + "ix": 4 + }, + "sa": { + "a": 0, + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "T", + "np": 2, + "cix": 2, + "bm": 0, + "ix": 5, + "mn": "ADBE Vector Group", + "hd": false + }, + { + "ty": "gr", + "it": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ix": 1, + "ks": { + "a": 1, + "k": [ + { + "i": { + "x": 0.715, + "y": 1 + }, + "o": { + "x": 0.414, + "y": 0 + }, + "t": 127.73, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + -114, + 32.5 + ], + [ + -119, + 32.5 + ] + ], + "c": false + } + ] + }, + { + "t": 147.435546875, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + -67.5, + 29 + ], + [ + -112, + 32.5 + ] + ], + "c": false + } + ] + } + ], + "ix": 2 + }, + "nm": "Path 1", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ty": "st", + "c": { + "a": 0, + "k": [ + 1, + 1, + 1, + 1 + ], + "ix": 3 + }, + "o": { + "a": 0, + "k": 100, + "ix": 4 + }, + "w": { + "a": 0, + "k": 20, + "ix": 5 + }, + "lc": 1, + "lj": 1, + "ml": 4, + "bm": 0, + "nm": "Stroke 1", + "mn": "ADBE Vector Graphic - Stroke", + "hd": false + }, + { + "ty": "tr", + "p": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ], + "ix": 3 + }, + "r": { + "a": 0, + "k": 0, + "ix": 6 + }, + "o": { + "a": 0, + "k": 100, + "ix": 7 + }, + "sk": { + "a": 0, + "k": 0, + "ix": 4 + }, + "sa": { + "a": 0, + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Shape 3", + "np": 3, + "cix": 2, + "bm": 0, + "ix": 1, + "mn": "ADBE Vector Group", + "hd": false + }, + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ix": 1, + "ks": { + "a": 1, + "k": [ + { + "i": { + "x": 0.715, + "y": 1 + }, + "o": { + "x": 0.414, + "y": 0 + }, + "t": 121.82, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + -115, + -6.5 + ], + [ + -119.5, + -6.5 + ] + ], + "c": true + } + ] + }, + { + "t": 141.033203125, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + -74.5, + -6 + ], + [ + -113, + -6 + ] + ], + "c": true + } + ] + } + ], + "ix": 2 + }, + "nm": "Path 1", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ty": "st", + "c": { + "a": 0, + "k": [ + 1, + 1, + 1, + 1 + ], + "ix": 3 + }, + "o": { + "a": 0, + "k": 100, + "ix": 4 + }, + "w": { + "a": 0, + "k": 20, + "ix": 5 + }, + "lc": 1, + "lj": 1, + "ml": 4, + "bm": 0, + "nm": "Stroke 1", + "mn": "ADBE Vector Graphic - Stroke", + "hd": false + }, + { + "ty": "tr", + "p": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ], + "ix": 3 + }, + "r": { + "a": 0, + "k": 0, + "ix": 6 + }, + "o": { + "a": 0, + "k": 100, + "ix": 7 + }, + "sk": { + "a": 0, + "k": 0, + "ix": 4 + }, + "sa": { + "a": 0, + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Shape 2", + "np": 3, + "cix": 2, + "bm": 0, + "ix": 2, + "mn": "ADBE Vector Group", + "hd": false + }, + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ix": 1, + "ks": { + "a": 1, + "k": [ + { + "i": { + "x": 0.715, + "y": 1 + }, + "o": { + "x": 0.414, + "y": 0 + }, + "t": 117.881, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + -103.5, + -54.5 + ], + [ + -103.5, + -49 + ] + ], + "c": false + } + ] + }, + { + "t": 137.58203125, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + -103.5, + -48.5 + ], + [ + -102.5, + 42 + ] + ], + "c": false + } + ] + } + ], + "ix": 2 + }, + "nm": "Path 1", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ty": "st", + "c": { + "a": 0, + "k": [ + 1, + 1, + 1, + 1 + ], + "ix": 3 + }, + "o": { + "a": 0, + "k": 100, + "ix": 4 + }, + "w": { + "a": 0, + "k": 20, + "ix": 5 + }, + "lc": 1, + "lj": 1, + "ml": 4, + "bm": 0, + "nm": "Stroke 1", + "mn": "ADBE Vector Graphic - Stroke", + "hd": false + }, + { + "ty": "tr", + "p": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ], + "ix": 3 + }, + "r": { + "a": 0, + "k": 0, + "ix": 6 + }, + "o": { + "a": 0, + "k": 100, + "ix": 7 + }, + "sk": { + "a": 0, + "k": 0, + "ix": 4 + }, + "sa": { + "a": 0, + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Shape 4", + "np": 3, + "cix": 2, + "bm": 0, + "ix": 3, + "mn": "ADBE Vector Group", + "hd": false + }, + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ix": 1, + "ks": { + "a": 1, + "k": [ + { + "i": { + "x": 0.715, + "y": 1 + }, + "o": { + "x": 0.414, + "y": 0 + }, + "t": 110, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + -117, + -38 + ], + [ + -120.5, + -38 + ] + ], + "c": false + } + ] + }, + { + "t": 129.2109375, + "s": [ + { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + -68, + -38 + ], + [ + -114.5, + -38 + ] + ], + "c": false + } + ] + } + ], + "ix": 2 + }, + "nm": "Path 1", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ty": "st", + "c": { + "a": 0, + "k": [ + 1, + 1, + 1, + 1 + ], + "ix": 3 + }, + "o": { + "a": 0, + "k": 100, + "ix": 4 + }, + "w": { + "a": 0, + "k": 20, + "ix": 5 + }, + "lc": 1, + "lj": 1, + "ml": 4, + "bm": 0, + "nm": "Stroke 1", + "mn": "ADBE Vector Graphic - Stroke", + "hd": false + }, + { + "ty": "tr", + "p": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ], + "ix": 3 + }, + "r": { + "a": 0, + "k": 0, + "ix": 6 + }, + "o": { + "a": 0, + "k": 100, + "ix": 7 + }, + "sk": { + "a": 0, + "k": 0, + "ix": 4 + }, + "sa": { + "a": 0, + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Shape 1", + "np": 3, + "cix": 2, + "bm": 0, + "ix": 4, + "mn": "ADBE Vector Group", + "hd": false + }, + { + "ty": "tr", + "p": { + "a": 0, + "k": [ + -90, + -3.25 + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + -90, + -3.25 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ], + "ix": 3 + }, + "r": { + "a": 0, + "k": 0, + "ix": 6 + }, + "o": { + "a": 0, + "k": 100, + "ix": 7 + }, + "sk": { + "a": 0, + "k": 0, + "ix": 4 + }, + "sa": { + "a": 0, + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "E", + "np": 4, + "cix": 2, + "bm": 0, + "ix": 6, + "mn": "ADBE Vector Group", + "hd": false + } + ], + "ip": 101, + "op": 3868, + "st": 0, + "bm": 0 + }, + { + "ddd": 0, + "ind": 9, + "ty": 4, + "nm": "Etflix", + "tt": 1, + "sr": 1, + "ks": { + "o": { + "a": 0, + "k": 100, + "ix": 11 + }, + "r": { + "a": 0, + "k": 0, + "ix": 10 + }, + "p": { + "s": true, + "x": { + "a": 1, + "k": [ + { + "i": { + "x": [ + 0.455 + ], + "y": [ + 1 + ] + }, + "o": { + "x": [ + 0.684 + ], + "y": [ + 0 + ] + }, + "t": 104, + "s": [ + 402.75 + ] + }, + { + "t": 154.74609375, + "s": [ + 256 + ] + } + ], + "ix": 3 + }, + "y": { + "a": 0, + "k": 256, + "ix": 4 + } + }, + "a": { + "a": 0, + "k": [ + 0, + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100, + 100 + ], + "ix": 6 + } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 1, + "ty": "sh", + "ix": 2, + "ks": { + "a": 0, + "k": { + "i": [ + [ + 0, + 0 + ], + [ + -5.131, + 0 + ], + [ + 0, + 0 + ], + [ + 5.401, + -0.27 + ], + [ + 0, + 0 + ], + [ + -8.551, + 0.27 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 5.582, + 0 + ], + [ + 0, + 0 + ], + [ + -6.392, + 0 + ], + [ + 0, + 0 + ], + [ + 8.462, + -0.54 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + -95.285, + -12.333 + ], + [ + -76.021, + -12.603 + ], + [ + -76.021, + 1.8 + ], + [ + -95.285, + 2.07 + ], + [ + -95.285, + 23.495 + ], + [ + -69.81, + 21.964 + ], + [ + -69.81, + 35.826 + ], + [ + -109.689, + 38.978 + ], + [ + -109.689, + -46.09 + ], + [ + -69.81, + -46.09 + ], + [ + -69.81, + -31.687 + ], + [ + -95.285, + -31.687 + ] + ], + "c": true + }, + "ix": 2 + }, + "nm": "Path 2", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ind": 2, + "ty": "sh", + "ix": 3, + "ks": { + "a": 0, + "k": { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 4.68, + -0.18 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + -4.861, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + -16.249, + -31.686 + ], + [ + -31.192, + -31.686 + ], + [ + -31.192, + 34.568 + ], + [ + -45.594, + 34.747 + ], + [ + -45.594, + -31.686 + ], + [ + -60.537, + -31.686 + ], + [ + -60.537, + -46.09 + ], + [ + -16.248, + -46.09 + ] + ], + "c": true + }, + "ix": 2 + }, + "nm": "Path 3", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ind": 3, + "ty": "sh", + "ix": 4, + "ks": { + "a": 0, + "k": { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + 7.156, + -13.323 + ], + [ + 26.871, + -13.323 + ], + [ + 26.871, + 1.08 + ], + [ + 7.156, + 1.08 + ], + [ + 7.156, + 33.757 + ], + [ + -6.978, + 33.757 + ], + [ + -6.978, + -46.09 + ], + [ + 33.262, + -46.09 + ], + [ + 33.262, + -31.687 + ], + [ + 7.156, + -31.687 + ] + ], + "c": true + }, + "ix": 2 + }, + "nm": "Path 4", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ind": 4, + "ty": "sh", + "ix": 5, + "ks": { + "a": 0, + "k": { + "i": [ + [ + 0, + 0 + ], + [ + -8.012, + -0.449 + ], + [ + 0, + 0 + ], + [ + 13.143, + 0.271 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 8.192, + 0.18 + ], + [ + 0, + 0 + ], + [ + -12.873, + -0.811 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + 56.667, + 21.154 + ], + [ + 81.152, + 22.415 + ], + [ + 81.152, + 36.638 + ], + [ + 42.264, + 34.747 + ], + [ + 42.264, + -46.09 + ], + [ + 56.667, + -46.09 + ] + ], + "c": true + }, + "ix": 2 + }, + "nm": "Path 5", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ind": 5, + "ty": "sh", + "ix": 6, + "ks": { + "a": 0, + "k": { + "i": [ + [ + 0, + 0 + ], + [ + -4.681, + -0.539 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 4.591, + 0.27 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + 93.304, + 37.628 + ], + [ + 107.437, + 38.708 + ], + [ + 107.437, + -46.09 + ], + [ + 93.304, + -46.09 + ] + ], + "c": true + }, + "ix": 2 + }, + "nm": "Path 6", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ind": 6, + "ty": "sh", + "ix": 7, + "ks": { + "a": 0, + "k": { + "i": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 5.401, + 0.9 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 5.22, + 0.72 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + -5.403, + -0.72 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + -5.222, + -0.901 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + 170.541, + -46.09 + ], + [ + 152.267, + -2.25 + ], + [ + 170.541, + 46.09 + ], + [ + 154.337, + 43.479 + ], + [ + 143.985, + 16.834 + ], + [ + 133.454, + 41.319 + ], + [ + 117.971, + 39.428 + ], + [ + 136.515, + -2.791 + ], + [ + 119.771, + -46.09 + ], + [ + 135.253, + -46.09 + ], + [ + 144.705, + -21.875 + ], + [ + 154.788, + -46.09 + ] + ], + "c": true + }, + "ix": 2 + }, + "nm": "Path 7", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ty": "fl", + "c": { + "a": 0, + "k": [ + 0.898039215686, + 0.035294117647, + 0.078431372549, + 1 + ], + "ix": 4 + }, + "o": { + "a": 0, + "k": 100, + "ix": 5 + }, + "r": 1, + "bm": 0, + "nm": "Fill 1", + "mn": "ADBE Vector Graphic - Fill", + "hd": false + }, + { + "ty": "tr", + "p": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ], + "ix": 3 + }, + "r": { + "a": 0, + "k": 0, + "ix": 6 + }, + "o": { + "a": 0, + "k": 100, + "ix": 7 + }, + "sk": { + "a": 0, + "k": 0, + "ix": 4 + }, + "sa": { + "a": 0, + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Netflix Wordmark", + "np": 8, + "cix": 2, + "bm": 0, + "ix": 1, + "mn": "ADBE Vector Group", + "hd": false + } + ], + "ip": 102, + "op": 3868, + "st": 0, + "bm": 0 + }, + { + "ddd": 0, + "ind": 10, + "ty": 4, + "nm": "Netflix N", + "sr": 1, + "ks": { + "o": { + "a": 0, + "k": 100, + "ix": 11 + }, + "r": { + "a": 0, + "k": 0, + "ix": 10 + }, + "p": { + "s": true, + "x": { + "a": 1, + "k": [ + { + "i": { + "x": [ + 0.455 + ], + "y": [ + 1 + ] + }, + "o": { + "x": [ + 0.684 + ], + "y": [ + 0 + ] + }, + "t": 104, + "s": [ + 402.75 + ] + }, + { + "t": 154.74609375, + "s": [ + 256 + ] + } + ], + "ix": 3 + }, + "y": { + "a": 0, + "k": 256, + "ix": 4 + } + }, + "a": { + "a": 0, + "k": [ + 0, + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100, + 100 + ], + "ix": 6 + } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ix": 1, + "ks": { + "a": 0, + "k": { + "i": [ + [ + 0, + 0 + ], + [ + 5.401, + -0.719 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 4.861, + -0.72 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "o": [ + [ + -5.131, + 0.901 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + -5.131, + 0.54 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ], + [ + 0, + 0 + ] + ], + "v": [ + [ + -123.641, + 40.148 + ], + [ + -139.394, + 42.039 + ], + [ + -155.868, + -6.211 + ], + [ + -155.868, + 44.11 + ], + [ + -170.541, + 46.09 + ], + [ + -170.541, + -46.09 + ], + [ + -156.858, + -46.09 + ], + [ + -138.134, + 6.212 + ], + [ + -138.134, + -46.09 + ], + [ + -123.641, + -46.09 + ] + ], + "c": true + }, + "ix": 2 + }, + "nm": "N", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ty": "fl", + "c": { + "a": 0, + "k": [ + 0.898039215686, + 0.035294117647, + 0.078431372549, + 1 + ], + "ix": 4 + }, + "o": { + "a": 0, + "k": 100, + "ix": 5 + }, + "r": 1, + "bm": 0, + "nm": "Fill 1", + "mn": "ADBE Vector Graphic - Fill", + "hd": false + }, + { + "ty": "tr", + "p": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 2 + }, + "a": { + "a": 0, + "k": [ + 0, + 0 + ], + "ix": 1 + }, + "s": { + "a": 0, + "k": [ + 100, + 100 + ], + "ix": 3 + }, + "r": { + "a": 0, + "k": 0, + "ix": 6 + }, + "o": { + "a": 0, + "k": 100, + "ix": 7 + }, + "sk": { + "a": 0, + "k": 0, + "ix": 4 + }, + "sa": { + "a": 0, + "k": 0, + "ix": 5 + }, + "nm": "Transform" + } + ], + "nm": "Netflix Wordmark", + "np": 2, + "cix": 2, + "bm": 0, + "ix": 1, + "mn": "ADBE Vector Group", + "hd": false + } + ], + "ip": 102, + "op": 3868, + "st": 0, + "bm": 0 + } + ], + "markers": [] +} \ No newline at end of file diff --git a/app/src/main/java/com/codandotv/streamplayerapp/MainActivity.kt b/composeApp/src/commonMain/kotlin/com.codandotv.streamplayerapp/StreamPlayerApp.kt similarity index 58% rename from app/src/main/java/com/codandotv/streamplayerapp/MainActivity.kt rename to composeApp/src/commonMain/kotlin/com.codandotv.streamplayerapp/StreamPlayerApp.kt index 94deedd3..98362c68 100644 --- a/app/src/main/java/com/codandotv/streamplayerapp/MainActivity.kt +++ b/composeApp/src/commonMain/kotlin/com.codandotv.streamplayerapp/StreamPlayerApp.kt @@ -1,22 +1,10 @@ package com.codandotv.streamplayerapp -import android.os.Bundle -import androidx.activity.ComponentActivity -import androidx.activity.compose.setContent import androidx.compose.runtime.Composable import androidx.navigation.compose.rememberNavController import com.codandotv.streamplayerapp.core_shared_ui.theme.StreamPlayerTheme import com.codandotv.streamplayerapp.navigation.NavigationGraph -class MainActivity : ComponentActivity() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContent { - StreamPlayerApp() - } - } -} - @Composable fun StreamPlayerApp() { StreamPlayerTheme { diff --git a/app/src/main/java/com/codandotv/streamplayerapp/di/AppModule.kt b/composeApp/src/commonMain/kotlin/com.codandotv.streamplayerapp/di/AppModule.kt similarity index 78% rename from app/src/main/java/com/codandotv/streamplayerapp/di/AppModule.kt rename to composeApp/src/commonMain/kotlin/com.codandotv.streamplayerapp/di/AppModule.kt index 6fcc0006..d904287c 100644 --- a/app/src/main/java/com/codandotv/streamplayerapp/di/AppModule.kt +++ b/composeApp/src/commonMain/kotlin/com.codandotv.streamplayerapp/di/AppModule.kt @@ -1,16 +1,15 @@ package com.codandotv.streamplayerapp.di -import android.content.res.Resources import com.codandotv.streamplayerapp.core_local_storage.di.LocalStorageModule import com.codandotv.streamplayerapp.core_networking.di.NetworkModule import com.codandotv.streamplayerapp.core_shared.qualifier.QualifierDispatcherIO import kotlinx.coroutines.Dispatchers -import org.koin.android.ext.koin.androidContext +import kotlinx.coroutines.IO import org.koin.dsl.module object AppModule { private val module = module { - single { androidContext().resources } +// single { androidContext().resources } single(QualifierDispatcherIO) { Dispatchers.IO } } val list = module + NetworkModule.module + LocalStorageModule.module diff --git a/app/src/main/java/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt b/composeApp/src/commonMain/kotlin/com.codandotv.streamplayerapp/navigation/NavigationGraph.kt similarity index 75% rename from app/src/main/java/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt rename to composeApp/src/commonMain/kotlin/com.codandotv.streamplayerapp/navigation/NavigationGraph.kt index b8df253a..63251780 100644 --- a/app/src/main/java/com/codandotv/streamplayerapp/navigation/NavigationGraph.kt +++ b/composeApp/src/commonMain/kotlin/com.codandotv.streamplayerapp/navigation/NavigationGraph.kt @@ -1,7 +1,5 @@ package com.codandotv.streamplayerapp.navigation -import android.annotation.SuppressLint -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -14,11 +12,12 @@ import androidx.navigation.compose.composable import com.codandotv.streamplayerapp.core_navigation.bottomnavigation.StreamPlayerBottomNavigation import com.codandotv.streamplayerapp.core_navigation.routes.BottomNavRoutes import com.codandotv.streamplayerapp.core_navigation.routes.Routes -import com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.navigation.detailStreamNavGraph import com.codandotv.streamplayerapp.feature_list_streams.list.presentation.navigation.listStreamsNavGraph -import com.codandotv.streamplayerapp.feature_list_streams.search.presentation.navigation.searchStreamsNavGraph -import com.codandotv.streamplayerapp.feature_profile.profile.presentation.navigation.profilePickerStreamNavGraph -import com.codandotv.streamplayerapp.splah.presentation.navigation.splashNavGraph +import com.codandotv.streamplayerapp.profile.presentation.navigation.profilePickerStreamNavGraph + +import com.codandotv.streamplayerapp.presentation.navigation.splashNavGraph +import com.codandotv.streamplayerapp.feature_detail.presentation.navigation.detailStreamNavGraph +import com.codandotv.streamplayerapp.feature_search.presentation.navigation.searchStreamsNavGraph @Composable fun NavigationGraph(navController: NavHostController) { @@ -27,11 +26,11 @@ fun NavigationGraph(navController: NavHostController) { listStreamsNavGraph(navController = navController) searchStreamsNavGraph(navController = navController) detailStreamNavGraph(navController = navController) + profilePickerStreamNavGraph(navController = navController) temporaryFun(BottomNavRoutes.GAMES, navController) temporaryFun(BottomNavRoutes.NEWS, navController) temporaryFun(BottomNavRoutes.SCENES, navController) temporaryFun(BottomNavRoutes.DOWNLOADS, navController) - profilePickerStreamNavGraph(navController = navController) } } @@ -41,8 +40,6 @@ fun NavGraphBuilder.temporaryFun(route: String, navController: NavController) { } } -@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter") -@OptIn(ExperimentalMaterial3Api::class) @Composable fun example(navController: NavController, route: String) { Scaffold( diff --git a/composeApp/src/commonMain/kotlin/com.codandotv.streamplayerapp/presentation/components/LottieComponentPlatform.kt b/composeApp/src/commonMain/kotlin/com.codandotv.streamplayerapp/presentation/components/LottieComponentPlatform.kt new file mode 100644 index 00000000..56f103ff --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com.codandotv.streamplayerapp/presentation/components/LottieComponentPlatform.kt @@ -0,0 +1,11 @@ +package com.codandotv.streamplayerapp.presentation.components + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier + +@Composable +expect fun LottieComponent( + jsonString: String, + modifier: Modifier = Modifier, + onAnimationFinished: () -> Unit +) \ No newline at end of file diff --git a/app/src/main/java/com/codandotv/streamplayerapp/splah/presentation/navigation/SplashNavigation.kt b/composeApp/src/commonMain/kotlin/com.codandotv.streamplayerapp/presentation/navigation/SplashNavigation.kt similarity index 77% rename from app/src/main/java/com/codandotv/streamplayerapp/splah/presentation/navigation/SplashNavigation.kt rename to composeApp/src/commonMain/kotlin/com.codandotv.streamplayerapp/presentation/navigation/SplashNavigation.kt index a272c263..9952dc97 100644 --- a/app/src/main/java/com/codandotv/streamplayerapp/splah/presentation/navigation/SplashNavigation.kt +++ b/composeApp/src/commonMain/kotlin/com.codandotv.streamplayerapp/presentation/navigation/SplashNavigation.kt @@ -1,11 +1,11 @@ -package com.codandotv.streamplayerapp.splah.presentation.navigation +package com.codandotv.streamplayerapp.presentation.navigation import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController import androidx.navigation.compose.composable import com.codandotv.streamplayerapp.core_navigation.routes.BottomNavRoutes import com.codandotv.streamplayerapp.core_navigation.routes.Routes -import com.codandotv.streamplayerapp.splah.presentation.screens.SplashScreen +import com.codandotv.streamplayerapp.presentation.screens.SplashScreen fun NavGraphBuilder.splashNavGraph(navController: NavHostController) { composable(Routes.Splash) { diff --git a/composeApp/src/commonMain/kotlin/com.codandotv.streamplayerapp/presentation/screens/SplashScreen.kt b/composeApp/src/commonMain/kotlin/com.codandotv.streamplayerapp/presentation/screens/SplashScreen.kt new file mode 100644 index 00000000..ab8cc565 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com.codandotv.streamplayerapp/presentation/screens/SplashScreen.kt @@ -0,0 +1,55 @@ +package com.codandotv.streamplayerapp.presentation.screens + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +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.graphics.Color +import com.codandotv.streamplayerapp.presentation.components.LottieComponent +import org.jetbrains.compose.resources.ExperimentalResourceApi +import streamplayerapp_kmp.composeapp.generated.resources.Res + +@OptIn(ExperimentalResourceApi::class) +@Composable +fun SplashScreen( + onAnimationFinished: () -> Unit +) { + var lottieAnimationString: String? by remember { + mutableStateOf(null) + } + LaunchedEffect(Unit) { + lottieAnimationString = Res.readBytes( + "files/lottie/logo.json" + ).decodeToString() + } + Column( + modifier = Modifier.fillMaxSize() + ) { + Box( + contentAlignment = Alignment.Center, + modifier = Modifier + .fillMaxSize() + .background(Color.Black) + ) { + lottieAnimationString?.let { + LottieComponent( + jsonString = it, + modifier = Modifier + .fillMaxWidth() + .fillMaxHeight(), + onAnimationFinished = onAnimationFinished + ) + } + } + } +} diff --git a/composeApp/src/iosMain/kotlin/com.codandotv.streamplayerapp/MainViewController.kt b/composeApp/src/iosMain/kotlin/com.codandotv.streamplayerapp/MainViewController.kt new file mode 100644 index 00000000..2332ac68 --- /dev/null +++ b/composeApp/src/iosMain/kotlin/com.codandotv.streamplayerapp/MainViewController.kt @@ -0,0 +1,7 @@ +package com.codandotv.streamplayerapp + +import androidx.compose.ui.window.ComposeUIViewController + +fun MainViewController() = ComposeUIViewController { + StreamPlayerApp() +} \ No newline at end of file diff --git a/composeApp/src/iosMain/kotlin/com.codandotv.streamplayerapp/di/KoinIosHelper.kt b/composeApp/src/iosMain/kotlin/com.codandotv.streamplayerapp/di/KoinIosHelper.kt new file mode 100644 index 00000000..bd8d968c --- /dev/null +++ b/composeApp/src/iosMain/kotlin/com.codandotv.streamplayerapp/di/KoinIosHelper.kt @@ -0,0 +1,17 @@ +package com.codandotv.streamplayerapp.di + +import com.codandotv.streamplayerapp.presentation.components.LottieViewProvider +import org.koin.core.context.startKoin +import org.koin.dsl.module + +class KoinIosHelper { + fun initKoin(lottieViewProvider: LottieViewProvider) { + startKoin { + modules(AppModule.list + module { + single { + lottieViewProvider + } + }) + } + } +} \ No newline at end of file diff --git a/composeApp/src/iosMain/kotlin/com.codandotv.streamplayerapp/presentation/components/LottieComponentPlatform.ios.kt b/composeApp/src/iosMain/kotlin/com.codandotv.streamplayerapp/presentation/components/LottieComponentPlatform.ios.kt new file mode 100644 index 00000000..9ed08746 --- /dev/null +++ b/composeApp/src/iosMain/kotlin/com.codandotv.streamplayerapp/presentation/components/LottieComponentPlatform.ios.kt @@ -0,0 +1,26 @@ +package com.codandotv.streamplayerapp.presentation.components + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.viewinterop.UIKitView +import org.koin.mp.KoinPlatform +import platform.UIKit.UIColor +import platform.UIKit.UIView + +@Composable +actual fun LottieComponent( + jsonString: String, + modifier: Modifier, + onAnimationFinished: () -> Unit +) { + val provider = KoinPlatform.getKoin().get() + + UIKitView( + modifier = modifier, + factory = { + val view = provider.provideLottieView(jsonString,onAnimationFinished) + view.backgroundColor = UIColor.blackColor() + view + } + ) +} \ No newline at end of file diff --git a/composeApp/src/iosMain/kotlin/com.codandotv.streamplayerapp/presentation/components/LottieViewProvider.kt b/composeApp/src/iosMain/kotlin/com.codandotv.streamplayerapp/presentation/components/LottieViewProvider.kt new file mode 100644 index 00000000..f1bf123d --- /dev/null +++ b/composeApp/src/iosMain/kotlin/com.codandotv.streamplayerapp/presentation/components/LottieViewProvider.kt @@ -0,0 +1,7 @@ +package com.codandotv.streamplayerapp.presentation.components + +import platform.UIKit.UIView + +interface LottieViewProvider { + fun provideLottieView(lottieAnimationJson: String, onAnimationFinish : () -> Unit) : UIView +} \ No newline at end of file diff --git a/core-local-storage/build.gradle.kts b/core-local-storage/build.gradle.kts index c8e2ff05..408d1805 100644 --- a/core-local-storage/build.gradle.kts +++ b/core-local-storage/build.gradle.kts @@ -1,13 +1,27 @@ plugins { - id("com.streamplayer.android-library") + id("com.streamplayer.kmp-library") id("com.google.devtools.ksp") + alias(libs.plugins.room) +} + +kotlin { + sourceSets { + commonMain.dependencies { + implementation(libs.room.bundled) + implementation(libs.room.runtime) + + implementation(libs.koin.core) + } + } } dependencies { + add("kspAndroid", libs.room.compiler) + add("kspIosSimulatorArm64", libs.room.compiler) + add("kspIosX64", libs.room.compiler) + add("kspIosArm64", libs.room.compiler) +} - ksp(libs.roomCompiler) - implementation(libs.bundles.room) - implementation(libs.bundles.kotlin) - implementation(libs.bundles.koin) - testImplementation(libs.bundles.test) -} \ No newline at end of file +room { + schemaDirectory("$projectDir/schemas") +} diff --git a/core-local-storage/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/database/AppDatabasePlatform.android.kt b/core-local-storage/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/database/AppDatabasePlatform.android.kt new file mode 100644 index 00000000..8540c5f0 --- /dev/null +++ b/core-local-storage/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/database/AppDatabasePlatform.android.kt @@ -0,0 +1,12 @@ +package com.codandotv.streamplayerapp.core_local_storage.data.database + +import androidx.room.Room +import org.koin.mp.KoinPlatform + +actual fun databaseInstance(): AppDatabase { + return Room.databaseBuilder( + KoinPlatform.getKoin().get(), + AppDatabase::class.java, + dbFileName + ).build() +} \ No newline at end of file diff --git a/core-local-storage/src/main/java/com/codandotv/streamplayerapp/core_local_storage/data/dao/FavoriteDao.kt b/core-local-storage/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/dao/FavoriteDao.kt similarity index 100% rename from core-local-storage/src/main/java/com/codandotv/streamplayerapp/core_local_storage/data/dao/FavoriteDao.kt rename to core-local-storage/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/dao/FavoriteDao.kt diff --git a/core-local-storage/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/database/AppDatabasePlatform.kt b/core-local-storage/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/database/AppDatabasePlatform.kt new file mode 100644 index 00000000..64f0a620 --- /dev/null +++ b/core-local-storage/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/database/AppDatabasePlatform.kt @@ -0,0 +1,25 @@ +package com.codandotv.streamplayerapp.core_local_storage.data.database + +import androidx.room.ConstructedBy +import androidx.room.Database +import androidx.room.RoomDatabase +import androidx.room.RoomDatabaseConstructor +import com.codandotv.streamplayerapp.core_local_storage.data.dao.FavoriteDao +import com.codandotv.streamplayerapp.core_local_storage.domain.model.MovieEntity + + +@Database(entities = [MovieEntity::class], version = 1, exportSchema = false) +@ConstructedBy(AppDatabaseConstructor::class) +abstract class AppDatabase : RoomDatabase() { + abstract fun favoriteDao(): FavoriteDao +} + +// The Room compiler generates the `actual` implementations. +@Suppress("NO_ACTUAL_FOR_EXPECT") +expect object AppDatabaseConstructor : RoomDatabaseConstructor { + override fun initialize(): AppDatabase +} + +expect fun databaseInstance(): AppDatabase + +internal const val dbFileName = "app-database.db" \ No newline at end of file diff --git a/core-local-storage/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/di/LocalStorageModule.kt b/core-local-storage/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/di/LocalStorageModule.kt new file mode 100644 index 00000000..9d934c0d --- /dev/null +++ b/core-local-storage/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/di/LocalStorageModule.kt @@ -0,0 +1,12 @@ +package com.codandotv.streamplayerapp.core_local_storage.di + +import com.codandotv.streamplayerapp.core_local_storage.data.database.AppDatabase +import com.codandotv.streamplayerapp.core_local_storage.data.database.databaseInstance +import org.koin.dsl.module + +object LocalStorageModule { + val module = module { + single { databaseInstance() } + single { get().favoriteDao() } + } +} \ No newline at end of file diff --git a/core-local-storage/src/main/java/com/codandotv/streamplayerapp/core_local_storage/domain/model/MovieEntity.kt b/core-local-storage/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/domain/model/MovieEntity.kt similarity index 100% rename from core-local-storage/src/main/java/com/codandotv/streamplayerapp/core_local_storage/domain/model/MovieEntity.kt rename to core-local-storage/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/domain/model/MovieEntity.kt diff --git a/core-local-storage/src/iosMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/database/AppDatabasePlatform.ios.kt b/core-local-storage/src/iosMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/database/AppDatabasePlatform.ios.kt new file mode 100644 index 00000000..469b746b --- /dev/null +++ b/core-local-storage/src/iosMain/kotlin/com/codandotv/streamplayerapp/core_local_storage/data/database/AppDatabasePlatform.ios.kt @@ -0,0 +1,35 @@ +package com.codandotv.streamplayerapp.core_local_storage.data.database + +import androidx.room.Room +import androidx.room.util.findDatabaseConstructorAndInitDatabaseImpl +import androidx.sqlite.driver.bundled.BundledSQLiteDriver +import kotlinx.cinterop.ExperimentalForeignApi +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO +import platform.Foundation.NSDocumentDirectory +import platform.Foundation.NSFileManager +import platform.Foundation.NSURL +import platform.Foundation.NSUserDomainMask + +@OptIn(ExperimentalForeignApi::class) +private fun documentDirectory(): String { + val documentDirectory: NSURL? = NSFileManager.defaultManager.URLForDirectory( + directory = NSDocumentDirectory, + inDomain = NSUserDomainMask, + appropriateForURL = null, + create = false, + error = null + ) + return requireNotNull(documentDirectory).path!! +} + +actual fun databaseInstance(): AppDatabase { + val dbFile = "${documentDirectory()}/$dbFileName" + return Room.databaseBuilder( + name = dbFile, + factory = { findDatabaseConstructorAndInitDatabaseImpl(AppDatabase::class) } + ).setDriver(BundledSQLiteDriver()) + .setQueryCoroutineContext(Dispatchers.IO) + .build() +} + diff --git a/core-local-storage/src/main/java/com/codandotv/streamplayerapp/core_local_storage/data/database/StreamPlayerAppDatabase.kt b/core-local-storage/src/main/java/com/codandotv/streamplayerapp/core_local_storage/data/database/StreamPlayerAppDatabase.kt deleted file mode 100644 index d5d60723..00000000 --- a/core-local-storage/src/main/java/com/codandotv/streamplayerapp/core_local_storage/data/database/StreamPlayerAppDatabase.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.codandotv.streamplayerapp.core_local_storage.data.database - -import android.content.Context -import androidx.room.Database -import androidx.room.Room -import androidx.room.RoomDatabase -import com.codandotv.streamplayerapp.core_local_storage.data.dao.FavoriteDao -import com.codandotv.streamplayerapp.core_local_storage.domain.model.MovieEntity - -@Database(entities = [MovieEntity::class], version = 1) -abstract class StreamPlayerAppDatabase : RoomDatabase() { - - abstract fun favoriteDao(): FavoriteDao - - companion object { - - private var instance: StreamPlayerAppDatabase? = null - - fun getInstance(context: Context): StreamPlayerAppDatabase { - if (instance == null) { - synchronized(this) { - instance = Room.databaseBuilder( - context.applicationContext, - StreamPlayerAppDatabase::class.java, - DATABASE_NAME - ).build() - } - } - return instance!! - } - - const val DATABASE_NAME = "app-database.db" - } -} \ No newline at end of file diff --git a/core-local-storage/src/main/java/com/codandotv/streamplayerapp/core_local_storage/di/LocalStorageModule.kt b/core-local-storage/src/main/java/com/codandotv/streamplayerapp/core_local_storage/di/LocalStorageModule.kt deleted file mode 100644 index a42c8854..00000000 --- a/core-local-storage/src/main/java/com/codandotv/streamplayerapp/core_local_storage/di/LocalStorageModule.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.codandotv.streamplayerapp.core_local_storage.di - -import androidx.room.Room -import com.codandotv.streamplayerapp.core_local_storage.data.database.StreamPlayerAppDatabase -import com.codandotv.streamplayerapp.core_local_storage.data.database.StreamPlayerAppDatabase.Companion.DATABASE_NAME -import org.koin.android.ext.koin.androidContext -import org.koin.dsl.module - -object LocalStorageModule { - val module = module { - single { Room.databaseBuilder(androidContext(), StreamPlayerAppDatabase::class.java, DATABASE_NAME).build() } - single { StreamPlayerAppDatabase.getInstance(get()) } - single { get().favoriteDao() } - } -} \ No newline at end of file diff --git a/core-navigation/build.gradle.kts b/core-navigation/build.gradle.kts index f7a359d3..21fc6a77 100644 --- a/core-navigation/build.gradle.kts +++ b/core-navigation/build.gradle.kts @@ -1,9 +1,17 @@ @file:Suppress("UnstableApiUsage") plugins { - id("com.streamplayer.android-library") - id("com.streamplayer.compose") + id("com.streamplayer.kmp-library") + alias(libs.plugins.jetbrains.compose) + alias(libs.plugins.compose.compiler) } -dependencies { - implementation(libs.bundles.kotlin) +kotlin { + sourceSets { + commonMain.dependencies { + implementation(libs.navigation.compose) + + implementation(compose.material3) + implementation(compose.components.resources) + } + } } \ No newline at end of file diff --git a/core-navigation/src/main/res/drawable/ic_downloads_selected.xml b/core-navigation/src/commonMain/composeResources/drawable/ic_downloads_selected.xml similarity index 91% rename from core-navigation/src/main/res/drawable/ic_downloads_selected.xml rename to core-navigation/src/commonMain/composeResources/drawable/ic_downloads_selected.xml index e64c7219..93b67523 100644 --- a/core-navigation/src/main/res/drawable/ic_downloads_selected.xml +++ b/core-navigation/src/commonMain/composeResources/drawable/ic_downloads_selected.xml @@ -3,8 +3,8 @@ android:height="24dp" android:viewportWidth="960" android:viewportHeight="960" - android:tint="@android:color/white"> + android:tint="#FFFFFF"> diff --git a/core-navigation/src/main/res/drawable/ic_downloads_unselected.xml b/core-navigation/src/commonMain/composeResources/drawable/ic_downloads_unselected.xml similarity index 91% rename from core-navigation/src/main/res/drawable/ic_downloads_unselected.xml rename to core-navigation/src/commonMain/composeResources/drawable/ic_downloads_unselected.xml index c23d8c3b..c85cae47 100644 --- a/core-navigation/src/main/res/drawable/ic_downloads_unselected.xml +++ b/core-navigation/src/commonMain/composeResources/drawable/ic_downloads_unselected.xml @@ -3,8 +3,8 @@ android:height="24dp" android:viewportWidth="960" android:viewportHeight="960" - android:tint="@android:color/white"> + android:tint="#FFFFFF"> diff --git a/core-navigation/src/main/res/drawable/ic_games_selected.xml b/core-navigation/src/commonMain/composeResources/drawable/ic_games_selected.xml similarity index 94% rename from core-navigation/src/main/res/drawable/ic_games_selected.xml rename to core-navigation/src/commonMain/composeResources/drawable/ic_games_selected.xml index 7108c3be..1b5f631c 100644 --- a/core-navigation/src/main/res/drawable/ic_games_selected.xml +++ b/core-navigation/src/commonMain/composeResources/drawable/ic_games_selected.xml @@ -3,8 +3,8 @@ android:height="24dp" android:viewportWidth="960" android:viewportHeight="960" - android:tint="@android:color/white"> + android:tint="#FFFFFF"> diff --git a/core-navigation/src/main/res/drawable/ic_games_unselected.xml b/core-navigation/src/commonMain/composeResources/drawable/ic_games_unselected.xml similarity index 96% rename from core-navigation/src/main/res/drawable/ic_games_unselected.xml rename to core-navigation/src/commonMain/composeResources/drawable/ic_games_unselected.xml index 1b02d38d..ebad3d46 100644 --- a/core-navigation/src/main/res/drawable/ic_games_unselected.xml +++ b/core-navigation/src/commonMain/composeResources/drawable/ic_games_unselected.xml @@ -3,8 +3,8 @@ android:height="24dp" android:viewportWidth="960" android:viewportHeight="960" - android:tint="@android:color/white"> + android:tint="#FFFFFF"> diff --git a/core-navigation/src/main/res/drawable/ic_home_selected.xml b/core-navigation/src/commonMain/composeResources/drawable/ic_home_selected.xml similarity index 85% rename from core-navigation/src/main/res/drawable/ic_home_selected.xml rename to core-navigation/src/commonMain/composeResources/drawable/ic_home_selected.xml index 1ce23235..16cfe658 100644 --- a/core-navigation/src/main/res/drawable/ic_home_selected.xml +++ b/core-navigation/src/commonMain/composeResources/drawable/ic_home_selected.xml @@ -3,8 +3,8 @@ android:height="24dp" android:viewportWidth="960" android:viewportHeight="960" - android:tint="@android:color/white"> + android:tint="#FFFFFF"> diff --git a/core-navigation/src/main/res/drawable/ic_home_unselected.xml b/core-navigation/src/commonMain/composeResources/drawable/ic_home_unselected.xml similarity index 84% rename from core-navigation/src/main/res/drawable/ic_home_unselected.xml rename to core-navigation/src/commonMain/composeResources/drawable/ic_home_unselected.xml index 5dc49b78..9517ebda 100644 --- a/core-navigation/src/main/res/drawable/ic_home_unselected.xml +++ b/core-navigation/src/commonMain/composeResources/drawable/ic_home_unselected.xml @@ -3,8 +3,8 @@ android:height="24dp" android:viewportWidth="960" android:viewportHeight="960" - android:tint="@android:color/white"> + android:tint="#FFFFFF"> diff --git a/core-navigation/src/main/res/drawable/ic_news_selected.xml b/core-navigation/src/commonMain/composeResources/drawable/ic_news_selected.xml similarity index 94% rename from core-navigation/src/main/res/drawable/ic_news_selected.xml rename to core-navigation/src/commonMain/composeResources/drawable/ic_news_selected.xml index 50b53635..48906958 100644 --- a/core-navigation/src/main/res/drawable/ic_news_selected.xml +++ b/core-navigation/src/commonMain/composeResources/drawable/ic_news_selected.xml @@ -5,6 +5,6 @@ android:viewportHeight="960" android:tint="?attr/colorControlNormal"> diff --git a/core-navigation/src/main/res/drawable/ic_news_unselected.xml b/core-navigation/src/commonMain/composeResources/drawable/ic_news_unselected.xml similarity index 90% rename from core-navigation/src/main/res/drawable/ic_news_unselected.xml rename to core-navigation/src/commonMain/composeResources/drawable/ic_news_unselected.xml index b4d4c7a5..45cfe6ac 100644 --- a/core-navigation/src/main/res/drawable/ic_news_unselected.xml +++ b/core-navigation/src/commonMain/composeResources/drawable/ic_news_unselected.xml @@ -3,8 +3,8 @@ android:height="24dp" android:viewportWidth="960" android:viewportHeight="960" - android:tint="@android:color/white"> + android:tint="#FFFFFF"> diff --git a/core-navigation/src/main/res/values/strings.xml b/core-navigation/src/commonMain/composeResources/values/strings.xml similarity index 100% rename from core-navigation/src/main/res/values/strings.xml rename to core-navigation/src/commonMain/composeResources/values/strings.xml diff --git a/core-navigation/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_navigation/bottomnavigation/BottomNavItem.kt b/core-navigation/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_navigation/bottomnavigation/BottomNavItem.kt new file mode 100644 index 00000000..96c2e576 --- /dev/null +++ b/core-navigation/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_navigation/bottomnavigation/BottomNavItem.kt @@ -0,0 +1,56 @@ +package com.codandotv.streamplayerapp.core_navigation.bottomnavigation + +import com.codandotv.streamplayerapp.core_navigation.routes.BottomNavRoutes +import org.jetbrains.compose.resources.DrawableResource +import org.jetbrains.compose.resources.StringResource +import streamplayerapp_kmp.core_navigation.generated.resources.Res +import streamplayerapp_kmp.core_navigation.generated.resources.bottom_nav_downloads +import streamplayerapp_kmp.core_navigation.generated.resources.bottom_nav_games +import streamplayerapp_kmp.core_navigation.generated.resources.bottom_nav_home +import streamplayerapp_kmp.core_navigation.generated.resources.bottom_nav_news +import streamplayerapp_kmp.core_navigation.generated.resources.ic_downloads_selected +import streamplayerapp_kmp.core_navigation.generated.resources.ic_downloads_unselected +import streamplayerapp_kmp.core_navigation.generated.resources.ic_games_selected +import streamplayerapp_kmp.core_navigation.generated.resources.ic_games_unselected +import streamplayerapp_kmp.core_navigation.generated.resources.ic_home_selected +import streamplayerapp_kmp.core_navigation.generated.resources.ic_home_unselected +import streamplayerapp_kmp.core_navigation.generated.resources.ic_news_selected +import streamplayerapp_kmp.core_navigation.generated.resources.ic_news_unselected + +sealed class BottomNavItem( + val title: StringResource, + val iconUnselected: DrawableResource, + val iconSelected: DrawableResource, + val screenRoute: String +) { + object Home : + BottomNavItem( + Res.string.bottom_nav_home, + Res.drawable.ic_home_unselected, + Res.drawable.ic_home_selected, + BottomNavRoutes.HOME + ) + + object Games : + BottomNavItem( + Res.string.bottom_nav_games, + Res.drawable.ic_games_unselected, + Res.drawable.ic_games_selected, + BottomNavRoutes.GAMES + ) + + object News : + BottomNavItem( + Res.string.bottom_nav_news, + Res.drawable.ic_news_unselected, + Res.drawable.ic_news_selected, + BottomNavRoutes.NEWS + ) + + object Downloads : BottomNavItem( + Res.string.bottom_nav_downloads, + Res.drawable.ic_downloads_unselected, + Res.drawable.ic_downloads_selected, + BottomNavRoutes.DOWNLOADS + ) +} \ No newline at end of file diff --git a/core-navigation/src/main/java/com/codandotv/streamplayerapp/core_navigation/bottomnavigation/StreamPlayerBottomNavigation.kt b/core-navigation/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_navigation/bottomnavigation/StreamPlayerBottomNavigation.kt similarity index 88% rename from core-navigation/src/main/java/com/codandotv/streamplayerapp/core_navigation/bottomnavigation/StreamPlayerBottomNavigation.kt rename to core-navigation/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_navigation/bottomnavigation/StreamPlayerBottomNavigation.kt index aa9375b0..f4096a3a 100644 --- a/core-navigation/src/main/java/com/codandotv/streamplayerapp/core_navigation/bottomnavigation/StreamPlayerBottomNavigation.kt +++ b/core-navigation/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_navigation/bottomnavigation/StreamPlayerBottomNavigation.kt @@ -11,11 +11,11 @@ import androidx.compose.material3.Text import androidx.compose.material3.surfaceColorAtElevation import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.navigation.NavController import com.codandotv.streamplayerapp.core_navigation.helper.currentRoute +import org.jetbrains.compose.resources.painterResource +import org.jetbrains.compose.resources.stringResource private val bottomMenuItems = listOf( BottomNavItem.Home, @@ -46,7 +46,7 @@ fun StreamPlayerBottomNavigation(navController: NavController) { icon = { NavItemIcon(currentRoute, item) }, label = { Text( - text = stringResource(id = item.title), + text = stringResource(item.title), style = MaterialTheme.typography.bodySmall, ) }, @@ -62,8 +62,8 @@ private fun NavItemIcon( item: BottomNavItem ) { Icon( - painterResource(id = if (currentRoute == item.screenRoute) item.iconSelected else item.iconUnselected), - contentDescription = stringResource(id = item.title), + painterResource(if (currentRoute == item.screenRoute) item.iconSelected else item.iconUnselected), + contentDescription = stringResource(item.title), ) } diff --git a/core-navigation/src/main/java/com/codandotv/streamplayerapp/core_navigation/extensions/NavControllerExtension.kt b/core-navigation/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_navigation/extensions/NavControllerExtension.kt similarity index 100% rename from core-navigation/src/main/java/com/codandotv/streamplayerapp/core_navigation/extensions/NavControllerExtension.kt rename to core-navigation/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_navigation/extensions/NavControllerExtension.kt diff --git a/core-navigation/src/main/java/com/codandotv/streamplayerapp/core_navigation/helper/NavigationHelper.kt b/core-navigation/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_navigation/helper/NavigationHelper.kt similarity index 100% rename from core-navigation/src/main/java/com/codandotv/streamplayerapp/core_navigation/helper/NavigationHelper.kt rename to core-navigation/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_navigation/helper/NavigationHelper.kt diff --git a/core-navigation/src/main/java/com/codandotv/streamplayerapp/core_navigation/routes/BottomNavRoutes.kt b/core-navigation/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_navigation/routes/BottomNavRoutes.kt similarity index 100% rename from core-navigation/src/main/java/com/codandotv/streamplayerapp/core_navigation/routes/BottomNavRoutes.kt rename to core-navigation/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_navigation/routes/BottomNavRoutes.kt diff --git a/core-navigation/src/main/java/com/codandotv/streamplayerapp/core_navigation/routes/Routes.kt b/core-navigation/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_navigation/routes/Routes.kt similarity index 87% rename from core-navigation/src/main/java/com/codandotv/streamplayerapp/core_navigation/routes/Routes.kt rename to core-navigation/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_navigation/routes/Routes.kt index 572636d9..552cfc46 100644 --- a/core-navigation/src/main/java/com/codandotv/streamplayerapp/core_navigation/routes/Routes.kt +++ b/core-navigation/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_navigation/routes/Routes.kt @@ -4,7 +4,7 @@ import com.codandotv.streamplayerapp.core_navigation.routes.Routes.PARAM.ID object Routes { const val DETAIL = "DetailList/" - const val DETAIL_COMPLETE = "${DETAIL}{${ID}}" + const val DETAIL_COMPLETE = "$DETAIL{${ID}}" const val Splash = "splash" const val SEARCH = "Search" const val PROFILE_PICKER = "profilePicker" diff --git a/core-navigation/src/main/java/com/codandotv/streamplayerapp/core_navigation/bottomnavigation/BottomNavItem.kt b/core-navigation/src/main/java/com/codandotv/streamplayerapp/core_navigation/bottomnavigation/BottomNavItem.kt deleted file mode 100644 index b7cfb7b4..00000000 --- a/core-navigation/src/main/java/com/codandotv/streamplayerapp/core_navigation/bottomnavigation/BottomNavItem.kt +++ /dev/null @@ -1,44 +0,0 @@ -package com.codandotv.streamplayerapp.core_navigation.bottomnavigation - -import androidx.annotation.DrawableRes -import androidx.annotation.StringRes -import com.codandotv.streamplayerapp.core.navigation.R -import com.codandotv.streamplayerapp.core_navigation.routes.BottomNavRoutes - -sealed class BottomNavItem( - @StringRes var title: Int, - @DrawableRes var iconUnselected: Int, - @DrawableRes var iconSelected: Int, - var screenRoute: String -) { - object Home : - BottomNavItem( - R.string.bottom_nav_home, - R.drawable.ic_home_unselected, - R.drawable.ic_home_selected, - BottomNavRoutes.HOME - ) - - object Games : - BottomNavItem( - R.string.bottom_nav_games, - R.drawable.ic_games_unselected, - R.drawable.ic_games_selected, - BottomNavRoutes.GAMES - ) - - object News : - BottomNavItem( - R.string.bottom_nav_news, - R.drawable.ic_news_unselected, - R.drawable.ic_news_selected, - BottomNavRoutes.NEWS - ) - - object Downloads : BottomNavItem( - R.string.bottom_nav_downloads, - R.drawable.ic_downloads_unselected, - R.drawable.ic_downloads_selected, - BottomNavRoutes.DOWNLOADS - ) -} \ No newline at end of file diff --git a/core-networking/build.gradle.kts b/core-networking/build.gradle.kts index f5602562..367251c8 100644 --- a/core-networking/build.gradle.kts +++ b/core-networking/build.gradle.kts @@ -1,27 +1,54 @@ +import com.codingfeline.buildkonfig.compiler.FieldSpec + plugins { - id("com.streamplayer.android-library") + id("com.streamplayer.kmp-library") + alias(libs.plugins.jetbrains.compose) + alias(libs.plugins.compose.compiler) + alias(libs.plugins.buildkonfig.plugin) } -android { - buildFeatures { - buildConfig = true + +buildkonfig { + packageName = "core.networking" + + defaultConfigs { + buildConfigField(FieldSpec.Type.STRING, "HOST", Config.BuildField.host_debug) + buildConfigField(FieldSpec.Type.STRING, "API_BEARER_AUTH", Config.BuildField.api_bearer_debug) + buildConfigField(FieldSpec.Type.STRING, "PROFILE", Config.BuildField.api_profile_debug) + } + + defaultConfigs("release") { + buildConfigField(FieldSpec.Type.STRING, "HOST", Config.BuildField.host_release) + buildConfigField(FieldSpec.Type.STRING, "API_BEARER_AUTH", Config.BuildField.api_bearer_release) + buildConfigField(FieldSpec.Type.STRING, "PROFILE", Config.BuildField.api_profile_release) } - buildTypes { - debug { - buildConfigField("String", "HOST", Config.BuildField.host_debug) - buildConfigField("String", "API_BEARER_AUTH", Config.BuildField.api_bearer_debug) - buildConfigField("String", "PROFILE", Config.BuildField.api_profile_debug) +} + +kotlin { + sourceSets { + commonMain.dependencies { + implementation(libs.kotlin.stdlib) + + implementation(libs.koin.core) + implementation(libs.ktor.client.core) + implementation(libs.ktor.client.content.serialization.json) + implementation(libs.ktor.client.content.negotiation) + implementation(libs.ktor.client.logger) + implementation(libs.ktor.client.auth) + implementation(compose.components.resources) + implementation(compose.runtime) } - getByName("release") { - buildConfigField("String", "HOST", Config.BuildField.host_release) - buildConfigField("String", "API_BEARER_AUTH", Config.BuildField.api_bearer_release) - buildConfigField("String", "PROFILE", Config.BuildField.api_profile_release) + + androidMain.dependencies { + implementation(libs.okhttp) + + implementation(libs.interceptor) + + implementation(libs.ktor.client.okhttp) + } + + iosMain.dependencies { + implementation(libs.ktor.client.darwin) } } -} -dependencies { - implementation(libs.bundles.kotlin) - implementation(libs.bundles.networking) - implementation(libs.bundles.koin) - testImplementation(libs.bundles.test) -} +} \ No newline at end of file diff --git a/core-networking/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_networking/HttpClientEngineProviderPlatform.android.kt b/core-networking/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_networking/HttpClientEngineProviderPlatform.android.kt new file mode 100644 index 00000000..5373464e --- /dev/null +++ b/core-networking/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_networking/HttpClientEngineProviderPlatform.android.kt @@ -0,0 +1,7 @@ +package com.codandotv.streamplayerapp.core_networking + +import io.ktor.client.engine.HttpClientEngine +import io.ktor.client.engine.okhttp.OkHttpConfig +import io.ktor.client.engine.okhttp.OkHttpEngine + +actual fun httpClientEnginePlatform() : HttpClientEngine = OkHttpEngine(OkHttpConfig()) \ No newline at end of file diff --git a/core-networking/src/main/res/values/strings.xml b/core-networking/src/commonMain/composeResources/values/strings.xml similarity index 100% rename from core-networking/src/main/res/values/strings.xml rename to core-networking/src/commonMain/composeResources/values/strings.xml diff --git a/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/HttpClientEngineProviderPlatform.kt b/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/HttpClientEngineProviderPlatform.kt new file mode 100644 index 00000000..40eb9de0 --- /dev/null +++ b/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/HttpClientEngineProviderPlatform.kt @@ -0,0 +1,5 @@ +package com.codandotv.streamplayerapp.core_networking + +import io.ktor.client.engine.HttpClientEngine + +expect fun httpClientEnginePlatform(): HttpClientEngine \ No newline at end of file diff --git a/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt b/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt new file mode 100644 index 00000000..a55c169b --- /dev/null +++ b/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt @@ -0,0 +1,92 @@ +package com.codandotv.streamplayerapp.core_networking.di + +import com.codandotv.streamplayerapp.core_networking.di.Network.TIMEOUT +import com.codandotv.streamplayerapp.core_networking.httpClientEnginePlatform +import core.networking.BuildKonfig +import io.ktor.client.HttpClient +import io.ktor.client.plugins.HttpTimeout +import io.ktor.client.plugins.auth.Auth +import io.ktor.client.plugins.auth.providers.BearerTokens +import io.ktor.client.plugins.auth.providers.bearer +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import io.ktor.client.plugins.defaultRequest +import io.ktor.client.plugins.logging.LogLevel +import io.ktor.client.plugins.logging.Logger +import io.ktor.client.plugins.logging.Logging +import io.ktor.client.request.accept +import io.ktor.http.ContentType +import io.ktor.http.contentType +import io.ktor.serialization.kotlinx.json.json +import kotlinx.serialization.json.Json +import org.koin.dsl.module + +object NetworkModule { + val module = module { + single(QualifierHost) { BuildKonfig.HOST } + single(QualifierProfile) { BuildKonfig.PROFILE } + + single { + provideKtorHttpClient( + baseUrl = get(QualifierHost), + ) + } + + single(QualifierProfileHttpClient) { + provideKtorHttpClient( + baseUrl = get(QualifierProfile), + ) + } + } + + private fun provideKtorHttpClient( + baseUrl: String, + ): HttpClient { + return HttpClient(engine = httpClientEnginePlatform()) { + expectSuccess = false + + install(ContentNegotiation) { + json(Json { + explicitNulls = false + ignoreUnknownKeys = true + }) + } + + install(HttpTimeout) { + socketTimeoutMillis = TIMEOUT + requestTimeoutMillis = TIMEOUT + connectTimeoutMillis = TIMEOUT + } + + defaultRequest { + url(baseUrl) + contentType(ContentType.Application.Json) + accept(ContentType.Application.Json) + } + + install(Auth) { + bearer { + loadTokens { + BearerTokens( + accessToken = BuildKonfig.API_BEARER_AUTH, + refreshToken = "" + ) + } + } + } + + install(Logging) { + level = LogLevel.ALL + logger = object : Logger { + override fun log(message: String) { + //TODO: Migrar Logs para Utilizar Kermit + println("HttpClient${message}") + } + } + } + } + } +} + +internal object Network { + const val TIMEOUT = 10000L +} \ No newline at end of file diff --git a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/di/QualifierNetworking.kt b/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/di/QualifierNetworking.kt similarity index 93% rename from core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/di/QualifierNetworking.kt rename to core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/di/QualifierNetworking.kt index c3564c8f..b21a5e27 100644 --- a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/di/QualifierNetworking.kt +++ b/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/di/QualifierNetworking.kt @@ -13,12 +13,11 @@ object QualifierProfile : Qualifier { get() = "QualifierProfile" } -object QualifierProfileRetrofit : Qualifier { +object QualifierProfileHttpClient : Qualifier { override val value: QualifierValue get() = "QualifierProfileRetrofit" } - object QualifierLoggerInterceptor : Qualifier { override val value: QualifierValue get() = "QualifierLoggerInterceptor" diff --git a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/handleError/Failure.kt b/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/Failure.kt similarity index 71% rename from core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/handleError/Failure.kt rename to core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/Failure.kt index eeb1421a..f09b8b03 100644 --- a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/handleError/Failure.kt +++ b/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/Failure.kt @@ -1,6 +1,7 @@ package com.codandotv.streamplayerapp.core_networking.handleError -import com.codandotv.streamplayerapp.core.networking.R +import com.codandotv.streamplayerapp.core_networking.resources.StringNetworking +import kotlinx.serialization.Serializable import org.koin.core.component.KoinComponent /** @@ -11,19 +12,21 @@ import org.koin.core.component.KoinComponent "TooGenericExceptionCaught", "MagicNumber" ) + +@Serializable sealed class Failure( val code: Int? = -1, val errorMessage: String? = null, - val errorMessageRes: Int = R.string.core_networking_msg_default_error + val errorMessageResKey: String = StringNetworking.msgDefaultErrorKey() ) : Exception(), KoinComponent { data class NoDataContent(val codeStatus: Int? = null) : - Failure(codeStatus, errorMessageRes = R.string.core_networking_no_data_content) + Failure(codeStatus, errorMessageResKey = StringNetworking.msgNoDataContentKey()) data class ServerError(val codeStatus: Int? = null) : - Failure(codeStatus, errorMessageRes = R.string.core_networking_no_server_error) + Failure(codeStatus, errorMessageResKey = StringNetworking.msgServerErrorKey()) data class GenericError( - val codeStatus: Int? = -12, private val msg: String? = null + val codeStatus: Int? = -12, private val msg: String? = StringNetworking.msgNetworkErrorKey() ) : Failure( codeStatus ) @@ -31,7 +34,7 @@ sealed class Failure( data class NetworkError( val codeStatus: Int? = -13, private val throwable: Throwable ) : Failure( - codeStatus, errorMessageRes = R.string.core_networking_networking_error + codeStatus, errorMessageResKey = StringNetworking.msgNetworkErrorKey() ) data class UnknownError( diff --git a/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/HttpClientConfigExtensions.kt b/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/HttpClientConfigExtensions.kt new file mode 100644 index 00000000..5ccadb2c --- /dev/null +++ b/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/HttpClientConfigExtensions.kt @@ -0,0 +1,35 @@ +package com.codandotv.streamplayerapp.core_networking.handleError + +import io.ktor.client.HttpClient +import io.ktor.client.call.body +import io.ktor.client.plugins.ClientRequestException +import io.ktor.client.request.HttpRequestBuilder +import io.ktor.client.request.request +import io.ktor.client.statement.bodyAsText +import io.ktor.utils.io.errors.IOException +import kotlinx.serialization.SerializationException + +suspend inline fun HttpClient.safeRequest( + block: HttpRequestBuilder.() -> Unit, +): NetworkResponse = + try { + val response = request { block() } + NetworkResponse.Success(response.body()) + } catch (exception: ClientRequestException) { + NetworkResponse.Error( + body = exception.response.bodyAsText(), + exception = Failure.ServerError(exception.response.status.value) + ) + } catch (e: SerializationException) { + NetworkResponse.Error( + exception = Failure.UnparsableResponseException(throwable = e) + ) + } catch (e: IOException) { + NetworkResponse.Error( + exception = Failure.NetworkError(throwable = e) + ) + } catch (e: Exception) { + NetworkResponse.Error( + exception = Failure.GenericError(msg = e.message ?: "Unknown error") + ) + } diff --git a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/handleError/NetworkResponse.kt b/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/NetworkResponse.kt similarity index 86% rename from core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/handleError/NetworkResponse.kt rename to core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/NetworkResponse.kt index ca705691..51378aab 100644 --- a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/handleError/NetworkResponse.kt +++ b/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/NetworkResponse.kt @@ -2,14 +2,19 @@ package com.codandotv.streamplayerapp.core_networking.handleError import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow +import kotlinx.serialization.Serializable +import kotlinx.serialization.Transient +@Serializable sealed class NetworkResponse { + @Serializable data class Success( val value: T ) : NetworkResponse() + @Serializable data class Error( - val body: Any? = null, + val body: String? = null, @Transient val exception: Failure? = null ) : NetworkResponse() diff --git a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/handleError/ResultExtensions.kt b/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/ResultExtensions.kt similarity index 100% rename from core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/handleError/ResultExtensions.kt rename to core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/handleError/ResultExtensions.kt diff --git a/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/resources/StringNetworking.kt b/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/resources/StringNetworking.kt new file mode 100644 index 00000000..b7edb0a2 --- /dev/null +++ b/core-networking/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_networking/resources/StringNetworking.kt @@ -0,0 +1,25 @@ +package com.codandotv.streamplayerapp.core_networking.resources + +import org.jetbrains.compose.resources.StringResource +import streamplayerapp_kmp.core_networking.generated.resources.Res +import streamplayerapp_kmp.core_networking.generated.resources.core_networking_msg_default_error +import streamplayerapp_kmp.core_networking.generated.resources.core_networking_networking_error +import streamplayerapp_kmp.core_networking.generated.resources.core_networking_no_data_content +import streamplayerapp_kmp.core_networking.generated.resources.core_networking_no_server_error + +//Note: done this to search for strings in the innermost layers because you can't use them because they are not composable +object StringNetworking { + internal fun msgDefaultErrorKey(): String = Res.string.core_networking_msg_default_error.key + internal fun msgNoDataContentKey(): String = Res.string.core_networking_no_data_content.key + internal fun msgServerErrorKey(): String = Res.string.core_networking_no_server_error.key + internal fun msgNetworkErrorKey(): String = Res.string.core_networking_networking_error.key + + private val errorMessageMap = mapOf( + msgDefaultErrorKey() to Res.string.core_networking_msg_default_error, + msgNoDataContentKey() to Res.string.core_networking_no_data_content, + msgServerErrorKey() to Res.string.core_networking_no_server_error, + msgNetworkErrorKey() to Res.string.core_networking_networking_error + ) + + fun getStringResource(key: String): StringResource? = errorMessageMap[key] +} diff --git a/core-networking/src/iosMain/kotlin/com/codandotv/streamplayerapp/core_networking/HttpClientEngineProviderPlatform.ios.kt b/core-networking/src/iosMain/kotlin/com/codandotv/streamplayerapp/core_networking/HttpClientEngineProviderPlatform.ios.kt new file mode 100644 index 00000000..9470ffa4 --- /dev/null +++ b/core-networking/src/iosMain/kotlin/com/codandotv/streamplayerapp/core_networking/HttpClientEngineProviderPlatform.ios.kt @@ -0,0 +1,8 @@ +package com.codandotv.streamplayerapp.core_networking + +import io.ktor.client.engine.HttpClientEngine +import io.ktor.client.engine.darwin.Darwin + +actual fun httpClientEnginePlatform(): HttpClientEngine { + return Darwin.create() +} \ No newline at end of file diff --git a/core-networking/src/main/AndroidManifest.xml b/core-networking/src/main/AndroidManifest.xml deleted file mode 100644 index a8800291..00000000 --- a/core-networking/src/main/AndroidManifest.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/coroutines/NetworkResponseAdapter.kt b/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/coroutines/NetworkResponseAdapter.kt deleted file mode 100644 index eafeb5b9..00000000 --- a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/coroutines/NetworkResponseAdapter.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.codandotv.streamplayerapp.core_networking.coroutines - -import com.squareup.moshi.Moshi -import retrofit2.Call -import retrofit2.CallAdapter -import java.lang.reflect.Type - -class NetworkResponseAdapter( - private val responseType: Type, - private val moshi: Moshi -): CallAdapter { - - override fun responseType(): Type = responseType - override fun adapt(call: Call) = NetworkResponseCall(call,moshi) -} \ No newline at end of file diff --git a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/coroutines/NetworkResponseAdapterFactory.kt b/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/coroutines/NetworkResponseAdapterFactory.kt deleted file mode 100644 index d2626078..00000000 --- a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/coroutines/NetworkResponseAdapterFactory.kt +++ /dev/null @@ -1,50 +0,0 @@ -package com.codandotv.streamplayerapp.core_networking.coroutines - -import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse -import com.squareup.moshi.Moshi -import retrofit2.Call -import retrofit2.CallAdapter -import retrofit2.Retrofit -import java.lang.reflect.ParameterizedType -import java.lang.reflect.Type - -@Suppress("ReturnCount", "SwallowedException") -class NetworkResponseAdapterFactory(private val moshi: Moshi) : CallAdapter.Factory() { - override fun get( - returnType: Type, - annotations: Array, - retrofit: Retrofit - ): CallAdapter<*, *>? { - return try { - // suspend functions wrap the response type in `Call` - if (Call::class.java != getRawType(returnType)) { - return null - } - - // check first that the return type is `ParameterizedType` - check(returnType is ParameterizedType) { - "return type must be parameterized as Call> or Call>" - } - - // get the response type inside the `Call` type - val responseType = getParameterUpperBound(0, returnType) - - // if the response type is not ApiResponse then we can't handle this type, so we return null - if (getRawType(responseType) != NetworkResponse::class.java) { - return null - } - - // the response type is ApiResponse and should be parameterized - check(responseType is ParameterizedType) { - "Response must be parameterized as NetworkResponse " + - "or NetworkResponse" - } - - val successBodyType = getParameterUpperBound(0, responseType) - - return NetworkResponseAdapter(successBodyType, moshi) - } catch (ex: ClassCastException) { - null - } - } -} \ No newline at end of file diff --git a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/coroutines/NetworkResponseCall.kt b/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/coroutines/NetworkResponseCall.kt deleted file mode 100644 index 710ad937..00000000 --- a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/coroutines/NetworkResponseCall.kt +++ /dev/null @@ -1,158 +0,0 @@ -package com.codandotv.streamplayerapp.core_networking.coroutines - -import com.codandotv.streamplayerapp.core_networking.handleError.Failure -import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse -import com.squareup.moshi.Moshi -import okhttp3.Request -import okhttp3.ResponseBody -import okio.Timeout -import retrofit2.Call -import retrofit2.Callback -import retrofit2.HttpException -import retrofit2.Response -import java.io.IOException - -@Suppress("SwallowedException", "TooGenericExceptionCaught") -class NetworkResponseCall( - proxy: Call, - private val moshi: Moshi -) : - CallDelegate>(proxy) { - - override fun enqueueImpl(callback: Callback>) = - proxy.enqueue(object : Callback { - override fun onResponse(call: Call, response: Response) { - val body = response.body() - val code = response.code() - val error = response.errorBody() - if (response.isSuccessful) { - responseSuccessful(body, callback, code) - } else { - responseError(callback,error, code) - } - } - - override fun onFailure(call: Call, throwable: Throwable) { - val networkResponse = when (throwable) { - is IOException -> Failure.NetworkError(throwable = throwable) - is HttpException -> convertException(throwable) - else -> Failure.GenericError(msg = throwable.message) - } - callback.onResponse( - this@NetworkResponseCall, - Response.success(NetworkResponse.Error(exception = networkResponse)) - ) - } - - - private fun convertException(exception: HttpException): Failure { - return try { - val response = getErrorResponse(exception) - Failure.UnexpectedApiException(throwable = response.exception) - } catch (ex: Failure.ClientException) { - ex - }catch (ex : Failure.UnparsableResponseException){ - ex - } - } - - private fun getErrorResponse(ex: HttpException): NetworkResponse.Error { - val error = ex.response()?.errorBody()?.string() - if (error?.isEmpty() != false) { - throw Failure.ClientException(throwable = ex) - } - return parseError(error, ex) - } - - private fun parseError(error: String, ex: HttpException): NetworkResponse.Error { - try { - return moshi - .adapter(NetworkResponse.Error::class.java) - .fromJson(error)!! - } catch (e: Exception) { - throw Failure.UnparsableResponseException(throwable = ex) - } - } - }) - - private fun responseSuccessful( - body: T?, - callback: Callback>, - code: Int - ) { - if (body != null) { - callback.onResponse( - this@NetworkResponseCall, - Response.success(NetworkResponse.Success(body)) - ) - } else { - callback.onResponse( - this@NetworkResponseCall, - Response.success( - NetworkResponse.Error( - exception = Failure.NoDataContent( - code - ) - ) - ) - ) - } - } - - private fun responseError(callback: Callback>, error: ResponseBody?, code: Int) { - val errorBody = when { - error == null -> null - error.contentLength() == 0L -> null - else -> try { - moshi - .adapter(NetworkResponse.Error::class.java) - .fromJson(error.string()) - } catch (ex: Exception) { - null - } - } - if (errorBody != null) { - callback.onResponse( - this@NetworkResponseCall, - Response.success( - NetworkResponse.Error( - body = errorBody, - exception = Failure.ServerError(code) - ) - ) - ) - } else { - callback.onResponse( - this@NetworkResponseCall, - Response.success( - NetworkResponse.Error( - exception = Failure.UnknownError( - code - ) - ) - ) - ) - } - } - - - override fun cloneImpl(): Call> = - NetworkResponseCall(proxy.clone(), moshi) -} - -abstract class CallDelegate( - protected val proxy: Call -) : Call { - override fun execute(): Response = throw NotImplementedError() - final override fun enqueue(callback: Callback) = enqueueImpl(callback) - final override fun clone(): Call = cloneImpl() - - override fun cancel() = proxy.cancel() - override fun request(): Request = proxy.request() - override fun isExecuted() = proxy.isExecuted - override fun isCanceled() = proxy.isCanceled - - abstract fun enqueueImpl(callback: Callback) - abstract fun cloneImpl(): Call - override fun timeout(): Timeout = proxy.timeout() -} \ No newline at end of file diff --git a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt b/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt deleted file mode 100644 index 7b0dc322..00000000 --- a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/di/NetworkModule.kt +++ /dev/null @@ -1,103 +0,0 @@ -package com.codandotv.streamplayerapp.core_networking.di - -import com.codandotv.streamplayerapp.core.networking.BuildConfig -import com.codandotv.streamplayerapp.core_networking.coroutines.NetworkResponseAdapterFactory -import com.squareup.moshi.Moshi -import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory -import okhttp3.Interceptor -import okhttp3.OkHttpClient -import okhttp3.logging.HttpLoggingInterceptor -import org.koin.dsl.module -import retrofit2.Retrofit -import retrofit2.converter.moshi.MoshiConverterFactory -import java.util.concurrent.TimeUnit - -@Suppress("MagicNumber") -object NetworkModule { - val module = module { - single(QualifierHost) { - BuildConfig.HOST - } - - single(QualifierProfile) { - BuildConfig.PROFILE - } - - single { - Moshi.Builder() - .add(KotlinJsonAdapterFactory()) - .build() - } - - single(QualifierAuthInterceptor) { - Interceptor { chain -> - val newRequest = - chain.request() - .newBuilder() - .addHeader( - "Authorization", - BuildConfig.API_BEARER_AUTH - ) - .addHeader("Content-Type", "application/json;charset=utf-8") - .build() - chain.proceed(newRequest) - } - } - - single(QualifierLoggerInterceptor) { - HttpLoggingInterceptor().setLevel( - if (BuildConfig.DEBUG) { - HttpLoggingInterceptor.Level.BODY - } else { - HttpLoggingInterceptor.Level.NONE - } - ) - } - single { - provideRetrofit( - okHttpClient = get(), - moshi = get(), - baseUrl = get(QualifierHost) - ) - } - - single(QualifierProfileRetrofit) { - provideRetrofit( - okHttpClient = get(), - moshi = get(), - baseUrl = get(QualifierProfile) - ) - } - - single { - provideOkhttp( - get(QualifierAuthInterceptor), - get(QualifierLoggerInterceptor), - ) - } - } - - private fun provideOkhttp( - vararg interceptor: Interceptor - ): OkHttpClient { - val okHttpClientBuilder = OkHttpClient.Builder() - interceptor.forEach { - okHttpClientBuilder.addInterceptor(it) - } - return okHttpClientBuilder - .connectTimeout(15, TimeUnit.SECONDS) - .build() - } - - private fun provideRetrofit( - okHttpClient: OkHttpClient, - moshi: Moshi, - baseUrl: String - ): Retrofit = - Retrofit.Builder() - .baseUrl(baseUrl) - .client(okHttpClient) - .addConverterFactory(MoshiConverterFactory.create(moshi)) - .addCallAdapterFactory(NetworkResponseAdapterFactory(moshi)) - .build() -} \ No newline at end of file diff --git a/core-shared-ui/build.gradle.kts b/core-shared-ui/build.gradle.kts index 5f46ed8a..9af7989e 100644 --- a/core-shared-ui/build.gradle.kts +++ b/core-shared-ui/build.gradle.kts @@ -1,15 +1,36 @@ @file:Suppress("UnstableApiUsage") plugins { - id("com.streamplayer.android-library") - id("com.streamplayer.compose") + id("com.streamplayer.kmp-library") + alias(libs.plugins.jetbrains.compose) + alias(libs.plugins.compose.compiler) } -dependencies { - implementation(projects.coreShared) - implementation(libs.bundles.koin) - implementation(libs.bundles.kotlin) - implementation(libs.bundles.androidSupport) - implementation(libs.android.youtube.player) - testImplementation(libs.bundles.test) - implementation(libs.coil) -} \ No newline at end of file +kotlin { + sourceSets { + androidMain.dependencies { + implementation(compose.preview) + implementation(libs.android.youtube.player) + implementation(libs.ktor.client.okhttp) + } + commonMain.dependencies { + implementation(projects.coreShared) + implementation(compose.material3) + implementation(compose.ui) + implementation(compose.components.resources) + implementation(libs.navigation.compose) + + implementation(libs.coil) + implementation(libs.coil.network.ktor3) + + implementation(libs.paging.compose) + } + + iosMain.dependencies { + implementation(libs.ktor.client.darwin) + } + } +} + +compose.resources { + publicResClass = true +} diff --git a/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/extension/ErrorExtPlatform.android.kt b/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/extension/ErrorExtPlatform.android.kt new file mode 100644 index 00000000..eac583b7 --- /dev/null +++ b/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/extension/ErrorExtPlatform.android.kt @@ -0,0 +1,10 @@ +package com.codandotv.streamplayerapp.core_shared_ui.extension + +import android.widget.Toast +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext + +@Composable +actual fun ShowErrorMessage(errorMessage: String) { + Toast.makeText(LocalContext.current,errorMessage,Toast.LENGTH_SHORT).show() +} \ No newline at end of file diff --git a/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/extension/PackageExtension.kt b/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/extension/PackageExtension.kt new file mode 100644 index 00000000..b2131aad --- /dev/null +++ b/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/extension/PackageExtension.kt @@ -0,0 +1,12 @@ +package com.codandotv.streamplayerapp.core_shared_ui.extension + +import android.content.pm.PackageInfo +import android.content.pm.PackageManager +import android.os.Build + +fun PackageManager.getPackageInfoCompat(packageName: String, flags: Int = 0): PackageInfo = + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + getPackageInfo(packageName, PackageManager.PackageInfoFlags.of(flags.toLong())) + } else { + @Suppress("DEPRECATION") getPackageInfo(packageName, flags) + } diff --git a/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/theme/ThemePreviews.kt b/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/theme/ThemePreviews.kt similarity index 100% rename from core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/theme/ThemePreviews.kt rename to core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/theme/ThemePreviews.kt diff --git a/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/utils/SharingPlatform.android.kt b/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/utils/SharingPlatform.android.kt new file mode 100644 index 00000000..1b9ab4c2 --- /dev/null +++ b/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/utils/SharingPlatform.android.kt @@ -0,0 +1,17 @@ +package com.codandotv.streamplayerapp.core_shared_ui.utils + +import android.content.pm.PackageManager +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext +import com.codandotv.streamplayerapp.core_shared_ui.extension.getPackageInfoCompat + +@Composable +actual fun isPackageInstalled(packageName: String): Boolean { + val pm = LocalContext.current.packageManager + return try { + pm.getPackageInfoCompat(packageName) + true + } catch (e: PackageManager.NameNotFoundException) { + false + } +} \ No newline at end of file diff --git a/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/PlayerComponent.kt b/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/PlayerComponent.android.kt similarity index 91% rename from core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/PlayerComponent.kt rename to core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/PlayerComponent.android.kt index 3013210d..56986e93 100644 --- a/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/PlayerComponent.kt +++ b/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/PlayerComponent.android.kt @@ -13,14 +13,13 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView -import com.codandotv.streamplayerapp.core_shared_ui.theme.ThemePreviews import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.PlayerConstants import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.YouTubePlayer import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners.YouTubePlayerListener import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.views.YouTubePlayerView @Composable -fun PlayerComponent(videoId: String, modifier: Modifier = Modifier) { +actual fun PlayerComponentPlatform(videoId: String, modifier: Modifier) { val context = LocalContext.current @@ -93,13 +92,4 @@ fun PlayerComponent(videoId: String, modifier: Modifier = Modifier) { onDispose { youtubePlayerView.release() } }, ) -} - -@Composable -@ThemePreviews -fun PlayerComponentPreview() { - PlayerComponent( - videoId = "BigBuckBunny.mp4", - modifier = Modifier.fillMaxWidth() - ) -} +} \ No newline at end of file diff --git a/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/SharingStreamCustomView.kt b/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/SharingStreamPlatform.android.kt similarity index 78% rename from core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/SharingStreamCustomView.kt rename to core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/SharingStreamPlatform.android.kt index b3063630..88a4e83b 100644 --- a/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/SharingStreamCustomView.kt +++ b/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/SharingStreamPlatform.android.kt @@ -1,6 +1,5 @@ package com.codandotv.streamplayerapp.core_shared_ui.widget -import android.app.Activity import android.content.ActivityNotFoundException import android.content.ClipData import android.content.ClipboardManager @@ -33,6 +32,7 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.MutableState +import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope @@ -42,35 +42,45 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.colorResource -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.core.content.ContextCompat -import com.codandotv.streamplayerapp.core.shared.ui.R -import com.codandotv.streamplayerapp.core_shared.extension.getUriFromUrlImage import com.codandotv.streamplayerapp.core_shared_ui.resources.Colors import com.codandotv.streamplayerapp.core_shared_ui.utils.Sharing.ANIMATION_DURATION import com.codandotv.streamplayerapp.core_shared_ui.utils.Sharing.ANIMATION_EXECUTION_DELAY import com.codandotv.streamplayerapp.core_shared_ui.utils.Sharing.COPY_CONTENT_TYPE_TEXT -import com.codandotv.streamplayerapp.core_shared_ui.utils.Sharing.INSTAGRAM_PACKAGE_SHARING -import com.codandotv.streamplayerapp.core_shared_ui.utils.Sharing.INSTAGRAM_STORY_DESTINATION import com.codandotv.streamplayerapp.core_shared_ui.utils.Sharing.OPTIONS_TITLE_MESSAGE -import com.codandotv.streamplayerapp.core_shared_ui.utils.Sharing.SHARING_DATA_TYPE_IMAGE import com.codandotv.streamplayerapp.core_shared_ui.utils.Sharing.SHARING_DATA_TYPE_TEXT import com.codandotv.streamplayerapp.core_shared_ui.utils.Sharing.SMS_CONTENT_BODY import com.codandotv.streamplayerapp.core_shared_ui.utils.Sharing.SMS_CONTENT_TYPE -import com.codandotv.streamplayerapp.core_shared_ui.utils.Sharing.WHATSAPP_PACKAGE_SHARING -import com.codandotv.streamplayerapp.core_shared_ui.utils.isPackageInstalled import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch +import org.jetbrains.compose.resources.painterResource +import org.jetbrains.compose.resources.stringResource +import streamplayerapp_kmp.core_shared_ui.generated.resources.Res +import streamplayerapp_kmp.core_shared_ui.generated.resources.ic_close +import streamplayerapp_kmp.core_shared_ui.generated.resources.ic_copy_content +import streamplayerapp_kmp.core_shared_ui.generated.resources.ic_instagram +import streamplayerapp_kmp.core_shared_ui.generated.resources.ic_message +import streamplayerapp_kmp.core_shared_ui.generated.resources.ic_whatsapp +import streamplayerapp_kmp.core_shared_ui.generated.resources.instagram_not_installed_message +import streamplayerapp_kmp.core_shared_ui.generated.resources.sharing_link_copied_message +import streamplayerapp_kmp.core_shared_ui.generated.resources.sharing_title_instagram +import streamplayerapp_kmp.core_shared_ui.generated.resources.sharing_title_link +import streamplayerapp_kmp.core_shared_ui.generated.resources.sharing_title_message +import streamplayerapp_kmp.core_shared_ui.generated.resources.sharing_title_more_options +import streamplayerapp_kmp.core_shared_ui.generated.resources.sharing_title_sms +import streamplayerapp_kmp.core_shared_ui.generated.resources.sharing_title_whatsapp +import streamplayerapp_kmp.core_shared_ui.generated.resources.sharing_whatsapp_message +import streamplayerapp_kmp.core_shared_ui.generated.resources.sms_app_error_message +import streamplayerapp_kmp.core_shared_ui.generated.resources.whatsapp_not_installed_message -@Suppress("LongMethod") @Composable -fun SharingStreamCustomView( +actual fun SharingStreamPlatform( + modifier: Modifier, contentTitle: String, contentUrl: String, setShowDialog: (Boolean) -> Unit @@ -80,12 +90,12 @@ fun SharingStreamCustomView( val animateTrigger = remember { mutableStateOf(false) } val context = LocalContext.current - val linkCopiedMessage = stringResource(id = R.string.sharing_link_copied_message) + val linkCopiedMessage = stringResource(Res.string.sharing_link_copied_message) val contentMessage = - stringResource(id = R.string.sharing_whatsapp_message, contentTitle, contentUrl) - val whatsAppNotInstalledMessage = stringResource(id = R.string.whatsapp_not_installed_message) - val instagramNotInstalledMessage = stringResource(id = R.string.instagram_not_installed_message) - val smsErrorMessage = stringResource(id = R.string.sms_app_error_message) + stringResource(Res.string.sharing_whatsapp_message, contentTitle, contentUrl) + val whatsAppNotInstalledMessage = stringResource(Res.string.whatsapp_not_installed_message) + val instagramNotInstalledMessage = stringResource(Res.string.instagram_not_installed_message) + val smsErrorMessage = stringResource(Res.string.sms_app_error_message) LaunchedEffect(key1 = Unit) { launch { @@ -106,7 +116,7 @@ fun SharingStreamCustomView( ) { Column(horizontalAlignment = Alignment.CenterHorizontally) { Text( - text = stringResource(id = R.string.sharing_title_message), + text = stringResource(Res.string.sharing_title_message), style = TextStyle( fontSize = 16.sp, fontFamily = FontFamily.Default, @@ -130,7 +140,7 @@ fun SharingStreamCustomView( } ) { Image( - painter = painterResource(id = R.drawable.ic_whatsapp), + painter = painterResource(Res.drawable.ic_whatsapp), contentDescription = null, modifier = Modifier .width(24.dp) @@ -138,7 +148,7 @@ fun SharingStreamCustomView( ) Spacer(modifier = Modifier.width(8.dp)) Text( - text = stringResource(id = R.string.sharing_title_whatsapp), + text = stringResource(Res.string.sharing_title_whatsapp), style = TextStyle( fontSize = 18.sp, fontFamily = FontFamily.Default, @@ -163,7 +173,7 @@ fun SharingStreamCustomView( } ) { Image( - painter = painterResource(id = R.drawable.ic_message), + painter = painterResource(Res.drawable.ic_message), contentDescription = null, modifier = Modifier .width(24.dp) @@ -171,7 +181,7 @@ fun SharingStreamCustomView( ) Spacer(modifier = Modifier.width(8.dp)) Text( - text = stringResource(id = R.string.sharing_title_sms), + text = stringResource(Res.string.sharing_title_sms), style = TextStyle( fontSize = 18.sp, fontFamily = FontFamily.Default, @@ -192,7 +202,7 @@ fun SharingStreamCustomView( } ) { Image( - painter = painterResource(id = R.drawable.ic_instagram), + painter = painterResource(Res.drawable.ic_instagram), contentDescription = null, modifier = Modifier .width(24.dp) @@ -200,7 +210,7 @@ fun SharingStreamCustomView( ) Spacer(modifier = Modifier.width(8.dp)) Text( - text = stringResource(id = R.string.sharing_title_instagram), + text = stringResource(Res.string.sharing_title_instagram), style = TextStyle( fontSize = 18.sp, fontFamily = FontFamily.Default, @@ -221,7 +231,7 @@ fun SharingStreamCustomView( } ) { Image( - painter = painterResource(id = R.drawable.ic_copy_content), + painter = painterResource(Res.drawable.ic_copy_content), contentDescription = null, modifier = Modifier .width(28.dp) @@ -234,7 +244,7 @@ fun SharingStreamCustomView( ) Spacer(modifier = Modifier.width(8.dp)) Text( - text = stringResource(id = R.string.sharing_title_link), + text = stringResource(Res.string.sharing_title_link), style = TextStyle( fontSize = 18.sp, fontFamily = FontFamily.Default, @@ -244,7 +254,7 @@ fun SharingStreamCustomView( } Spacer(modifier = Modifier.height(20.dp)) Text( - text = stringResource(id = R.string.sharing_title_more_options), + text = stringResource(Res.string.sharing_title_more_options), style = TextStyle( fontSize = 18.sp, fontFamily = FontFamily.Default, @@ -281,7 +291,7 @@ fun SharingStreamCustomView( } ) { Image( - painter = painterResource(id = R.drawable.ic_close), + painter = painterResource(Res.drawable.ic_close), contentDescription = null, modifier = Modifier .width(32.dp) @@ -306,29 +316,30 @@ private fun shareInstagramStory( contentUrl: String, errorMessage: String ) { - if (isPackageInstalled(WHATSAPP_PACKAGE_SHARING, context)) { - Thread { - val imgBitmapUri = getUriFromUrlImage(contentUrl, context) - - val storiesIntent = Intent(INSTAGRAM_STORY_DESTINATION) - storiesIntent.setDataAndType(imgBitmapUri, SHARING_DATA_TYPE_IMAGE) - storiesIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) - storiesIntent.setPackage(INSTAGRAM_PACKAGE_SHARING) - - context.grantUriPermission( - INSTAGRAM_PACKAGE_SHARING, imgBitmapUri, Intent.FLAG_GRANT_READ_URI_PERMISSION - ) - (context as Activity).runOnUiThread { - context.startActivity(storiesIntent) - } - }.start() - } else { - Toast.makeText( - context, - errorMessage, - Toast.LENGTH_SHORT - ).show() - } +// if (isPackageInstalled(WHATSAPP_PACKAGE_SHARING)) { +// Thread { + //TODO: +// val imgBitmapUri = getUriFromUrlImage(contentUrl) +// +// val storiesIntent = Intent(INSTAGRAM_STORY_DESTINATION) +// storiesIntent.setDataAndType(imgBitmapUri, SHARING_DATA_TYPE_IMAGE) +// storiesIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) +// storiesIntent.setPackage(INSTAGRAM_PACKAGE_SHARING) +// +// context.grantUriPermission( +// INSTAGRAM_PACKAGE_SHARING, imgBitmapUri, Intent.FLAG_GRANT_READ_URI_PERMISSION +// ) +// (context as Activity).runOnUiThread { +// context.startActivity(storiesIntent) +// } +// }.start() +// } else { +// Toast.makeText( +// context, +// errorMessage, +// Toast.LENGTH_SHORT +// ).show() +// } } private fun shareWhatsAppMessage( @@ -336,19 +347,19 @@ private fun shareWhatsAppMessage( message: String, errorMessage: String ) { - if (isPackageInstalled(WHATSAPP_PACKAGE_SHARING, context)) { - val intent = Intent(Intent.ACTION_SEND) - intent.type = SHARING_DATA_TYPE_TEXT - intent.setPackage(WHATSAPP_PACKAGE_SHARING) - intent.putExtra(Intent.EXTRA_TEXT, message) - context.startActivity(intent) - } else { +// if (isPackageInstalled(WHATSAPP_PACKAGE_SHARING)) { +// val intent = Intent(Intent.ACTION_SEND) +// intent.type = SHARING_DATA_TYPE_TEXT +// intent.setPackage(WHATSAPP_PACKAGE_SHARING) +// intent.putExtra(Intent.EXTRA_TEXT, message) +// context.startActivity(intent) +// } else { Toast.makeText( context, errorMessage, Toast.LENGTH_SHORT ).show() - } +// } } private fun copyContentLink(context: Context, linkCopiedMessage: String, contentUrl: String) { diff --git a/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamPlayerTopBarPreview.kt b/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamPlayerTopBarPreview.kt new file mode 100644 index 00000000..40b01ddb --- /dev/null +++ b/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamPlayerTopBarPreview.kt @@ -0,0 +1,24 @@ +package com.codandotv.streamplayerapp.core_shared_ui.widget + +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.material3.rememberTopAppBarState +import androidx.compose.runtime.Composable +import com.codandotv.streamplayerapp.core_shared.extension.empty +import com.codandotv.streamplayerapp.core_shared_ui.theme.ThemePreview +import com.codandotv.streamplayerapp.core_shared_ui.theme.ThemePreviews + +@OptIn(ExperimentalMaterial3Api::class) +@ThemePreviews +@Composable +fun StreamPlayerTopBarPreview() { + ThemePreview { + StreamPlayerTopBar( + scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior( + rememberTopAppBarState() + ), + onNavigateProfilePicker = {}, + onSelectedProfilePicture = String.empty() + ) + } +} \ No newline at end of file diff --git a/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCardPreview.kt b/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCardPreview.kt new file mode 100644 index 00000000..ae074713 --- /dev/null +++ b/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCardPreview.kt @@ -0,0 +1,17 @@ +package com.codandotv.streamplayerapp.core_shared_ui.widget + +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.Preview +import com.codandotv.streamplayerapp.core_shared.Url.IMAGE_URL_SIZE_300 + +@Preview +@Composable +fun StreamsCardPreview() { + StreamsCard( + StreamsCardContent( + url = "${IMAGE_URL_SIZE_300}evgwd37VHBJhXvSr88Mrx5riFil.jpg", + contentDescription = "Test 1", + id = "", + ) + ) +} \ No newline at end of file diff --git a/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCarouselPreview.kt b/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCarouselPreview.kt new file mode 100644 index 00000000..e05cd728 --- /dev/null +++ b/core-shared-ui/src/androidMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCarouselPreview.kt @@ -0,0 +1,16 @@ +package com.codandotv.streamplayerapp.core_shared_ui.widget + +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.Preview +import kotlinx.coroutines.flow.emptyFlow + +@Composable +@Preview +fun StreamsCarouselPreview() { + StreamsCarousel( + content = StreamsCarouselContent( + genreTitle = "Ação", + contentList = emptyFlow() + ) + ) +} \ No newline at end of file diff --git a/core-shared-ui/src/main/res/drawable/transparent_image.xml b/core-shared-ui/src/androidMain/res/drawable/transparent_image.xml similarity index 100% rename from core-shared-ui/src/main/res/drawable/transparent_image.xml rename to core-shared-ui/src/androidMain/res/drawable/transparent_image.xml diff --git a/core-shared-ui/src/main/res/mipmap-hdpi/ic_netflix.png b/core-shared-ui/src/androidMain/res/mipmap-hdpi/ic_netflix.png similarity index 100% rename from core-shared-ui/src/main/res/mipmap-hdpi/ic_netflix.png rename to core-shared-ui/src/androidMain/res/mipmap-hdpi/ic_netflix.png diff --git a/core-shared-ui/src/main/res/mipmap-hdpi/ic_netflix_round.png b/core-shared-ui/src/androidMain/res/mipmap-hdpi/ic_netflix_round.png similarity index 100% rename from core-shared-ui/src/main/res/mipmap-hdpi/ic_netflix_round.png rename to core-shared-ui/src/androidMain/res/mipmap-hdpi/ic_netflix_round.png diff --git a/core-shared-ui/src/main/res/mipmap-mdpi/ic_netflix.png b/core-shared-ui/src/androidMain/res/mipmap-mdpi/ic_netflix.png similarity index 100% rename from core-shared-ui/src/main/res/mipmap-mdpi/ic_netflix.png rename to core-shared-ui/src/androidMain/res/mipmap-mdpi/ic_netflix.png diff --git a/core-shared-ui/src/main/res/mipmap-mdpi/ic_netflix_round.png b/core-shared-ui/src/androidMain/res/mipmap-mdpi/ic_netflix_round.png similarity index 100% rename from core-shared-ui/src/main/res/mipmap-mdpi/ic_netflix_round.png rename to core-shared-ui/src/androidMain/res/mipmap-mdpi/ic_netflix_round.png diff --git a/core-shared-ui/src/main/res/mipmap-xhdpi/ic_netflix.png b/core-shared-ui/src/androidMain/res/mipmap-xhdpi/ic_netflix.png similarity index 100% rename from core-shared-ui/src/main/res/mipmap-xhdpi/ic_netflix.png rename to core-shared-ui/src/androidMain/res/mipmap-xhdpi/ic_netflix.png diff --git a/core-shared-ui/src/main/res/mipmap-xhdpi/ic_netflix_round.png b/core-shared-ui/src/androidMain/res/mipmap-xhdpi/ic_netflix_round.png similarity index 100% rename from core-shared-ui/src/main/res/mipmap-xhdpi/ic_netflix_round.png rename to core-shared-ui/src/androidMain/res/mipmap-xhdpi/ic_netflix_round.png diff --git a/core-shared-ui/src/main/res/mipmap-xxhdpi/ic_netflix.png b/core-shared-ui/src/androidMain/res/mipmap-xxhdpi/ic_netflix.png similarity index 100% rename from core-shared-ui/src/main/res/mipmap-xxhdpi/ic_netflix.png rename to core-shared-ui/src/androidMain/res/mipmap-xxhdpi/ic_netflix.png diff --git a/core-shared-ui/src/main/res/mipmap-xxhdpi/ic_netflix_round.png b/core-shared-ui/src/androidMain/res/mipmap-xxhdpi/ic_netflix_round.png similarity index 100% rename from core-shared-ui/src/main/res/mipmap-xxhdpi/ic_netflix_round.png rename to core-shared-ui/src/androidMain/res/mipmap-xxhdpi/ic_netflix_round.png diff --git a/core-shared-ui/src/main/res/mipmap-xxxhdpi/ic_netflix.png b/core-shared-ui/src/androidMain/res/mipmap-xxxhdpi/ic_netflix.png similarity index 100% rename from core-shared-ui/src/main/res/mipmap-xxxhdpi/ic_netflix.png rename to core-shared-ui/src/androidMain/res/mipmap-xxxhdpi/ic_netflix.png diff --git a/core-shared-ui/src/main/res/mipmap-xxxhdpi/ic_netflix_round.png b/core-shared-ui/src/androidMain/res/mipmap-xxxhdpi/ic_netflix_round.png similarity index 100% rename from core-shared-ui/src/main/res/mipmap-xxxhdpi/ic_netflix_round.png rename to core-shared-ui/src/androidMain/res/mipmap-xxxhdpi/ic_netflix_round.png diff --git a/core-shared-ui/src/main/res/values-v31/themes.xml b/core-shared-ui/src/androidMain/res/values-v31/themes.xml similarity index 50% rename from core-shared-ui/src/main/res/values-v31/themes.xml rename to core-shared-ui/src/androidMain/res/values-v31/themes.xml index f234904b..d6657630 100644 --- a/core-shared-ui/src/main/res/values-v31/themes.xml +++ b/core-shared-ui/src/androidMain/res/values-v31/themes.xml @@ -2,8 +2,9 @@ \ No newline at end of file diff --git a/core-shared-ui/src/androidMain/res/values/strings.xml b/core-shared-ui/src/androidMain/res/values/strings.xml new file mode 100644 index 00000000..22f3d553 --- /dev/null +++ b/core-shared-ui/src/androidMain/res/values/strings.xml @@ -0,0 +1,3 @@ + + StreamPlayerApp + \ No newline at end of file diff --git a/core-shared-ui/src/androidMain/res/values/themes.xml b/core-shared-ui/src/androidMain/res/values/themes.xml new file mode 100644 index 00000000..4dfb4c91 --- /dev/null +++ b/core-shared-ui/src/androidMain/res/values/themes.xml @@ -0,0 +1,11 @@ + + + + + + + \ No newline at end of file diff --git a/core-shared-ui/src/main/res/drawable/ic_add.xml b/core-shared-ui/src/commonMain/composeResources/drawable/ic_add.xml similarity index 88% rename from core-shared-ui/src/main/res/drawable/ic_add.xml rename to core-shared-ui/src/commonMain/composeResources/drawable/ic_add.xml index eaf0cd27..7d46aa21 100644 --- a/core-shared-ui/src/main/res/drawable/ic_add.xml +++ b/core-shared-ui/src/commonMain/composeResources/drawable/ic_add.xml @@ -5,6 +5,6 @@ android:viewportHeight="960" android:tint="?attr/colorControlNormal"> diff --git a/core-shared-ui/src/main/res/drawable/ic_close.xml b/core-shared-ui/src/commonMain/composeResources/drawable/ic_close.xml similarity index 54% rename from core-shared-ui/src/main/res/drawable/ic_close.xml rename to core-shared-ui/src/commonMain/composeResources/drawable/ic_close.xml index 844b6b62..6df42aa8 100644 --- a/core-shared-ui/src/main/res/drawable/ic_close.xml +++ b/core-shared-ui/src/commonMain/composeResources/drawable/ic_close.xml @@ -1,5 +1,5 @@ - + diff --git a/core-shared-ui/src/commonMain/composeResources/drawable/ic_copy_content.xml b/core-shared-ui/src/commonMain/composeResources/drawable/ic_copy_content.xml new file mode 100644 index 00000000..32b6ed83 --- /dev/null +++ b/core-shared-ui/src/commonMain/composeResources/drawable/ic_copy_content.xml @@ -0,0 +1,5 @@ + + + diff --git a/core-shared-ui/src/main/res/drawable/ic_info.xml b/core-shared-ui/src/commonMain/composeResources/drawable/ic_info.xml similarity index 96% rename from core-shared-ui/src/main/res/drawable/ic_info.xml rename to core-shared-ui/src/commonMain/composeResources/drawable/ic_info.xml index a85cba3b..75a1da27 100644 --- a/core-shared-ui/src/main/res/drawable/ic_info.xml +++ b/core-shared-ui/src/commonMain/composeResources/drawable/ic_info.xml @@ -5,6 +5,6 @@ android:viewportHeight="960" android:tint="?attr/colorControlNormal"> diff --git a/core-shared-ui/src/main/res/drawable/ic_instagram.xml b/core-shared-ui/src/commonMain/composeResources/drawable/ic_instagram.xml similarity index 100% rename from core-shared-ui/src/main/res/drawable/ic_instagram.xml rename to core-shared-ui/src/commonMain/composeResources/drawable/ic_instagram.xml diff --git a/core-shared-ui/src/main/res/drawable/ic_message.xml b/core-shared-ui/src/commonMain/composeResources/drawable/ic_message.xml similarity index 100% rename from core-shared-ui/src/main/res/drawable/ic_message.xml rename to core-shared-ui/src/commonMain/composeResources/drawable/ic_message.xml diff --git a/core-shared-ui/src/main/res/drawable/ic_netflix.png b/core-shared-ui/src/commonMain/composeResources/drawable/ic_netflix.png similarity index 100% rename from core-shared-ui/src/main/res/drawable/ic_netflix.png rename to core-shared-ui/src/commonMain/composeResources/drawable/ic_netflix.png diff --git a/core-shared-ui/src/main/res/drawable/ic_netflix_background.xml b/core-shared-ui/src/commonMain/composeResources/drawable/ic_netflix_background.xml similarity index 100% rename from core-shared-ui/src/main/res/drawable/ic_netflix_background.xml rename to core-shared-ui/src/commonMain/composeResources/drawable/ic_netflix_background.xml diff --git a/core-shared-ui/src/main/res/drawable/ic_netflix_foreground.xml b/core-shared-ui/src/commonMain/composeResources/drawable/ic_netflix_foreground.xml similarity index 100% rename from core-shared-ui/src/main/res/drawable/ic_netflix_foreground.xml rename to core-shared-ui/src/commonMain/composeResources/drawable/ic_netflix_foreground.xml diff --git a/core-shared-ui/src/main/res/drawable/ic_play.xml b/core-shared-ui/src/commonMain/composeResources/drawable/ic_play.xml similarity index 100% rename from core-shared-ui/src/main/res/drawable/ic_play.xml rename to core-shared-ui/src/commonMain/composeResources/drawable/ic_play.xml diff --git a/core-shared-ui/src/main/res/drawable/ic_whatsapp.xml b/core-shared-ui/src/commonMain/composeResources/drawable/ic_whatsapp.xml similarity index 100% rename from core-shared-ui/src/main/res/drawable/ic_whatsapp.xml rename to core-shared-ui/src/commonMain/composeResources/drawable/ic_whatsapp.xml diff --git a/core-shared-ui/src/main/res/drawable/perfil_fake.png b/core-shared-ui/src/commonMain/composeResources/drawable/perfil_fake.png similarity index 100% rename from core-shared-ui/src/main/res/drawable/perfil_fake.png rename to core-shared-ui/src/commonMain/composeResources/drawable/perfil_fake.png diff --git a/core-shared-ui/src/commonMain/composeResources/drawable/transparent_image.xml b/core-shared-ui/src/commonMain/composeResources/drawable/transparent_image.xml new file mode 100644 index 00000000..fa4a79ea --- /dev/null +++ b/core-shared-ui/src/commonMain/composeResources/drawable/transparent_image.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/core-shared-ui/src/main/res/values/strings.xml b/core-shared-ui/src/commonMain/composeResources/values/strings.xml similarity index 77% rename from core-shared-ui/src/main/res/values/strings.xml rename to core-shared-ui/src/commonMain/composeResources/values/strings.xml index 61def186..b4a573fa 100644 --- a/core-shared-ui/src/main/res/values/strings.xml +++ b/core-shared-ui/src/commonMain/composeResources/values/strings.xml @@ -24,4 +24,12 @@ Preview + + Ícone Netflix + Ícone Perfil + Ícone Buscar + Ícone Fechar + Ícone Microfone + Ícone Voltar + Ícone Projetar \ No newline at end of file diff --git a/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/extension/ErrorExtPlatform.kt b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/extension/ErrorExtPlatform.kt new file mode 100644 index 00000000..d4884c7e --- /dev/null +++ b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/extension/ErrorExtPlatform.kt @@ -0,0 +1,6 @@ +package com.codandotv.streamplayerapp.core_shared_ui.extension + +import androidx.compose.runtime.Composable + +@Composable +expect fun ShowErrorMessage(errorMessage: String) \ No newline at end of file diff --git a/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/resources/Colors.kt b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/resources/Colors.kt similarity index 100% rename from core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/resources/Colors.kt rename to core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/resources/Colors.kt diff --git a/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/theme/StreamPlayerTheme.kt b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/theme/StreamPlayerTheme.kt similarity index 100% rename from core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/theme/StreamPlayerTheme.kt rename to core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/theme/StreamPlayerTheme.kt diff --git a/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/utils/Sharing.kt b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/utils/Sharing.kt new file mode 100644 index 00000000..0a53109c --- /dev/null +++ b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/utils/Sharing.kt @@ -0,0 +1,15 @@ +package com.codandotv.streamplayerapp.core_shared_ui.utils + +object Sharing { + const val SHARING_DATA_TYPE_TEXT = "text/plain" + const val SHARING_DATA_TYPE_IMAGE = "image/*" + const val COPY_CONTENT_TYPE_TEXT = "text" + const val WHATSAPP_PACKAGE_SHARING = "com.whatsapp" + const val INSTAGRAM_PACKAGE_SHARING = "com.instagram.android" + const val INSTAGRAM_STORY_DESTINATION = "com.instagram.share.ADD_TO_STORY" + const val SMS_CONTENT_TYPE = "sms:" + const val SMS_CONTENT_BODY = "sms_body" + const val OPTIONS_TITLE_MESSAGE = "Compartilhar usando" + const val ANIMATION_EXECUTION_DELAY = 100L + const val ANIMATION_DURATION = 300 +} \ No newline at end of file diff --git a/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/utils/SharingPlatform.kt b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/utils/SharingPlatform.kt new file mode 100644 index 00000000..f69166c8 --- /dev/null +++ b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/utils/SharingPlatform.kt @@ -0,0 +1,7 @@ +package com.codandotv.streamplayerapp.core_shared_ui.utils + +import androidx.compose.runtime.Composable + + +@Composable +expect fun isPackageInstalled(packageName: String) : Boolean \ No newline at end of file diff --git a/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/CloseButton.kt b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/CloseButton.kt new file mode 100644 index 00000000..02993088 --- /dev/null +++ b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/CloseButton.kt @@ -0,0 +1,19 @@ +package com.codandotv.streamplayerapp.core_shared_ui.widget + +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Close +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color +import org.jetbrains.compose.resources.stringResource +import streamplayerapp_kmp.core_shared_ui.generated.resources.Res +import streamplayerapp_kmp.core_shared_ui.generated.resources.icon_close + +@Composable +fun CloseButton(action: () -> Unit = {}) { + DefaultIcon( + searchIcon = Icons.Default.Close, + contentDescription = stringResource(Res.string.icon_close), + onIconClickAction = action, + iconColor = Color.Gray + ) +} diff --git a/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/DefaultIcon.kt b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/DefaultIcon.kt new file mode 100644 index 00000000..8ec6b8d2 --- /dev/null +++ b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/DefaultIcon.kt @@ -0,0 +1,30 @@ +package com.codandotv.streamplayerapp.core_shared_ui.widget + +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Search +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector + +@Composable +fun DefaultIcon( + modifier: Modifier = Modifier, + searchIcon: ImageVector = Icons.Default.Search, + iconColor: Color = Color.White, + contentDescription: String = "", + onIconClickAction: () -> Unit = {} +) { + IconButton( + modifier = modifier, + onClick = onIconClickAction + ) { + Icon( + imageVector = searchIcon, + contentDescription = contentDescription, + tint = iconColor + ) + } +} diff --git a/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/IconWithText.kt b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/IconWithText.kt similarity index 100% rename from core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/IconWithText.kt rename to core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/IconWithText.kt diff --git a/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/MicButton.kt b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/MicButton.kt new file mode 100644 index 00000000..53b1f4ea --- /dev/null +++ b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/MicButton.kt @@ -0,0 +1,19 @@ +package com.codandotv.streamplayerapp.core_shared_ui.widget + +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Check +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color +import org.jetbrains.compose.resources.stringResource +import streamplayerapp_kmp.core_shared_ui.generated.resources.Res +import streamplayerapp_kmp.core_shared_ui.generated.resources.icon_mic + +@Composable +fun MicButton(action: () -> Unit = {}) { + DefaultIcon( + searchIcon = Icons.Default.Check, + contentDescription = stringResource(Res.string.icon_mic), + onIconClickAction = action, + iconColor = Color.Gray + ) +} \ No newline at end of file diff --git a/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/PlayerComponentPlatform.kt b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/PlayerComponentPlatform.kt new file mode 100644 index 00000000..18dcb366 --- /dev/null +++ b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/PlayerComponentPlatform.kt @@ -0,0 +1,10 @@ +@file:Suppress("EXPECT_AND_ACTUAL_IN_THE_SAME_MODULE") + +package com.codandotv.streamplayerapp.core_shared_ui.widget + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier + +@Composable +expect fun PlayerComponentPlatform(videoId: String, modifier: Modifier = Modifier) + diff --git a/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/SearchIcon.kt b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/SearchIcon.kt new file mode 100644 index 00000000..c92c7987 --- /dev/null +++ b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/SearchIcon.kt @@ -0,0 +1,19 @@ +package com.codandotv.streamplayerapp.core_shared_ui.widget + +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Search +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color +import org.jetbrains.compose.resources.stringResource +import streamplayerapp_kmp.core_shared_ui.generated.resources.Res +import streamplayerapp_kmp.core_shared_ui.generated.resources.icon_search + +@Composable +fun SearchIcon(action: () -> Unit = {}) { + DefaultIcon( + searchIcon = Icons.Filled.Search, + contentDescription = stringResource(Res.string.icon_search), + onIconClickAction = action, + iconColor = Color.Gray + ) +} \ No newline at end of file diff --git a/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/SharingStreamPlatform.kt b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/SharingStreamPlatform.kt new file mode 100644 index 00000000..23ac5f44 --- /dev/null +++ b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/SharingStreamPlatform.kt @@ -0,0 +1,12 @@ +package com.codandotv.streamplayerapp.core_shared_ui.widget + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier + +@Composable +expect fun SharingStreamPlatform( + modifier : Modifier = Modifier, + contentTitle: String, + contentUrl: String, + setShowDialog: (Boolean) -> Unit +) \ No newline at end of file diff --git a/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamPlayerTopBar.kt b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamPlayerTopBar.kt similarity index 73% rename from core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamPlayerTopBar.kt rename to core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamPlayerTopBar.kt index 0b51a8db..062251f8 100644 --- a/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamPlayerTopBar.kt +++ b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamPlayerTopBar.kt @@ -19,20 +19,24 @@ import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarScrollBehavior -import androidx.compose.material3.rememberTopAppBarState import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import coil.compose.AsyncImage -import com.codandotv.streamplayerapp.core.shared.ui.R -import com.codandotv.streamplayerapp.core_shared.extension.empty +import coil3.compose.AsyncImage import com.codandotv.streamplayerapp.core_shared_ui.resources.Colors -import com.codandotv.streamplayerapp.core_shared_ui.theme.ThemePreview -import com.codandotv.streamplayerapp.core_shared_ui.theme.ThemePreviews +import org.jetbrains.compose.resources.painterResource +import org.jetbrains.compose.resources.stringResource +import streamplayerapp_kmp.core_shared_ui.generated.resources.Res +import streamplayerapp_kmp.core_shared_ui.generated.resources.ic_netflix +import streamplayerapp_kmp.core_shared_ui.generated.resources.icon_netflix +import streamplayerapp_kmp.core_shared_ui.generated.resources.icon_profile +import streamplayerapp_kmp.core_shared_ui.generated.resources.icon_search +import streamplayerapp_kmp.core_shared_ui.generated.resources.perfil_fake +import streamplayerapp_kmp.core_shared_ui.generated.resources.topbar_categories +import streamplayerapp_kmp.core_shared_ui.generated.resources.topbar_movies +import streamplayerapp_kmp.core_shared_ui.generated.resources.topbar_shows @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -69,8 +73,8 @@ private fun StreamPlayerTopBar( onClick = { /* todo */ } ) { Icon( - painter = painterResource(R.drawable.ic_netflix), - contentDescription = stringResource(id = R.string.icon_netflix), + painter = painterResource(Res.drawable.ic_netflix), + contentDescription = stringResource(Res.string.icon_netflix), tint = Color.Unspecified, ) } @@ -84,7 +88,7 @@ private fun StreamPlayerTopBar( ) { Icon( imageVector = Icons.Default.Search, - contentDescription = stringResource(id = R.string.icon_search), + contentDescription = stringResource(Res.string.icon_search), tint = Color.White, ) } @@ -98,9 +102,9 @@ private fun StreamPlayerTopBar( .height(24.dp) .clip(RoundedCornerShape(4.dp)), model = profilePicture, - error = painterResource(id = R.drawable.perfil_fake), - placeholder = painterResource(id = R.drawable.perfil_fake), - contentDescription = stringResource(id = R.string.icon_profile) + error = painterResource(Res.drawable.perfil_fake), + placeholder = painterResource(Res.drawable.perfil_fake), + contentDescription = stringResource(Res.string.icon_profile) ) } } @@ -120,36 +124,21 @@ private fun StreamPlayerOptionsTopBar(modifier: Modifier, scrollBehavior: TopApp modifier = Modifier.padding(horizontal = 40.dp) ) { Text( - text = stringResource(id = R.string.topbar_shows), + text = stringResource(Res.string.topbar_shows), modifier = Modifier.weight(1f), color = Color.White ) Text( - text = stringResource(id = R.string.topbar_movies), + text = stringResource(Res.string.topbar_movies), modifier = Modifier.weight(1f), color = Color.White ) Text( - text = stringResource(id = R.string.topbar_categories), + text = stringResource(Res.string.topbar_categories), modifier = Modifier.weight(1f), color = Color.White ) } }, colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Transparent) ) -} - -@OptIn(ExperimentalMaterial3Api::class) -@ThemePreviews -@Composable -fun StreamPlayerTopBarPreview() { - ThemePreview { - StreamPlayerTopBar( - scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior( - rememberTopAppBarState() - ), - onNavigateProfilePicker = {}, - onSelectedProfilePicture = String.empty() - ) - } } \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/StreamsCard.kt b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCard.kt similarity index 68% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/StreamsCard.kt rename to core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCard.kt index e58661be..e52ef1b4 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/StreamsCard.kt +++ b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCard.kt @@ -1,6 +1,5 @@ -package com.codandotv.streamplayerapp.feature_list_streams.list.presentation.widgets +package com.codandotv.streamplayerapp.core_shared_ui.widget -import android.os.Parcelable import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding @@ -10,11 +9,8 @@ import androidx.compose.material3.Card import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import coil.compose.AsyncImage -import com.codandotv.streamplayerapp.core_networking.Url.IMAGE_URL_SIZE_300 -import kotlinx.parcelize.Parcelize +import coil3.compose.AsyncImage @Composable fun StreamsCard( @@ -44,21 +40,8 @@ fun StreamsCard( } } -@Parcelize data class StreamsCardContent( val id: String, val url: String, val contentDescription: String, -) : Parcelable - -@Preview -@Composable -fun StreamsCardPreview() { - StreamsCard( - StreamsCardContent( - url = "${IMAGE_URL_SIZE_300}evgwd37VHBJhXvSr88Mrx5riFil.jpg", - contentDescription = "Test 1", - id = "", - ) - ) -} \ No newline at end of file +) \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/StreamsCarousel.kt b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCarousel.kt similarity index 86% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/StreamsCarousel.kt rename to core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCarousel.kt index 61b5e89f..fb47bacd 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/StreamsCarousel.kt +++ b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCarousel.kt @@ -1,4 +1,4 @@ -package com.codandotv.streamplayerapp.feature_list_streams.list.presentation.widgets +package com.codandotv.streamplayerapp.core_shared_ui.widget import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer @@ -12,7 +12,6 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.paging.PagingData @@ -69,14 +68,3 @@ data class StreamsCarouselContent( val genreTitle: String, val contentList: Flow> ) - -@Composable -@Preview -fun StreamsCarouselPreview() { - StreamsCarousel( - content = StreamsCarouselContent( - genreTitle = "Ação", - contentList = emptyFlow() - ) - ) -} \ No newline at end of file diff --git a/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/WebImage.kt b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/WebImage.kt new file mode 100644 index 00000000..18282996 --- /dev/null +++ b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/WebImage.kt @@ -0,0 +1,58 @@ +package com.codandotv.streamplayerapp.core_shared_ui.widget + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.widthIn +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.FilterQuality +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.unit.dp +import coil3.compose.LocalPlatformContext +import coil3.compose.SubcomposeAsyncImage +import coil3.network.ktor3.KtorNetworkFetcherFactory +import coil3.request.ImageRequest + +@Composable +fun WebImage( + imageUrl: String, + contentDescription: String?, + contentScale: ContentScale, + onFailure: (@Composable () -> Unit) = {}, + filterQuality: FilterQuality = FilterQuality.High, + modifier: Modifier = Modifier +) { + val platformContext = LocalPlatformContext.current + val imageRequest = remember { + ImageRequest.Builder( + context = platformContext + ).data( + imageUrl + ).fetcherFactory( + KtorNetworkFetcherFactory() + ).build() + } + + SubcomposeAsyncImage( + model = imageRequest, + filterQuality = filterQuality, + contentDescription = contentDescription, + contentScale = contentScale, + modifier = modifier, + loading = { + Box { + CircularProgressIndicator( + modifier = Modifier.align(Alignment.Center) + .heightIn(max = 52.dp) + .widthIn(max = 52.dp) + ) + } + }, + error = { + onFailure() + } + ) +} \ No newline at end of file diff --git a/core-shared-ui/src/iosMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/extension/ErrorExtPlatform.ios.kt b/core-shared-ui/src/iosMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/extension/ErrorExtPlatform.ios.kt new file mode 100644 index 00000000..fc9f5e50 --- /dev/null +++ b/core-shared-ui/src/iosMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/extension/ErrorExtPlatform.ios.kt @@ -0,0 +1,7 @@ +package com.codandotv.streamplayerapp.core_shared_ui.extension + +import androidx.compose.runtime.Composable + +@Composable +actual fun ShowErrorMessage(errorMessage: String) { +} \ No newline at end of file diff --git a/core-shared-ui/src/iosMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/utils/SharingPlatform.ios.kt b/core-shared-ui/src/iosMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/utils/SharingPlatform.ios.kt new file mode 100644 index 00000000..abf58cee --- /dev/null +++ b/core-shared-ui/src/iosMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/utils/SharingPlatform.ios.kt @@ -0,0 +1,9 @@ +package com.codandotv.streamplayerapp.core_shared_ui.utils + +import androidx.compose.runtime.Composable + +@Composable +actual fun isPackageInstalled(packageName: String): Boolean { + //TODO: + return false +} \ No newline at end of file diff --git a/core-shared-ui/src/iosMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/PlayerComponentPlatform.ios.kt b/core-shared-ui/src/iosMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/PlayerComponentPlatform.ios.kt new file mode 100644 index 00000000..9d06f243 --- /dev/null +++ b/core-shared-ui/src/iosMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/PlayerComponentPlatform.ios.kt @@ -0,0 +1,7 @@ +package com.codandotv.streamplayerapp.core_shared_ui.widget + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier + +@Composable +actual fun PlayerComponentPlatform(videoId: String, modifier: Modifier) = Unit \ No newline at end of file diff --git a/core-shared-ui/src/iosMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/SharingStreamPlatform.ios.kt b/core-shared-ui/src/iosMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/SharingStreamPlatform.ios.kt new file mode 100644 index 00000000..25cf421f --- /dev/null +++ b/core-shared-ui/src/iosMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/SharingStreamPlatform.ios.kt @@ -0,0 +1,13 @@ +package com.codandotv.streamplayerapp.core_shared_ui.widget + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier + +@Composable +actual fun SharingStreamPlatform( + modifier: Modifier, + contentTitle: String, + contentUrl: String, + setShowDialog: (Boolean) -> Unit +) { +} \ No newline at end of file diff --git a/core-shared-ui/src/main/AndroidManifest.xml b/core-shared-ui/src/main/AndroidManifest.xml deleted file mode 100644 index ee784d7a..00000000 --- a/core-shared-ui/src/main/AndroidManifest.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/utils/Sharing.kt b/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/utils/Sharing.kt deleted file mode 100644 index d7963573..00000000 --- a/core-shared-ui/src/main/java/com/codandotv/streamplayerapp/core_shared_ui/utils/Sharing.kt +++ /dev/null @@ -1,39 +0,0 @@ -package com.codandotv.streamplayerapp.core_shared_ui.utils - -import android.content.Context -import android.content.pm.PackageInfo -import android.content.pm.PackageManager -import android.os.Build - -object Sharing { - - const val SHARING_DATA_TYPE_TEXT = "text/plain" - const val SHARING_DATA_TYPE_IMAGE = "image/*" - const val COPY_CONTENT_TYPE_TEXT = "text" - const val WHATSAPP_PACKAGE_SHARING = "com.whatsapp" - const val INSTAGRAM_PACKAGE_SHARING = "com.instagram.android" - const val INSTAGRAM_STORY_DESTINATION = "com.instagram.share.ADD_TO_STORY" - const val SMS_CONTENT_TYPE = "sms:" - const val SMS_CONTENT_BODY = "sms_body" - const val OPTIONS_TITLE_MESSAGE = "Compartilhar usando" - const val ANIMATION_EXECUTION_DELAY = 100L - const val ANIMATION_DURATION = 300 -} - -@Suppress("SwallowedException") -fun isPackageInstalled(packageName: String, context: Context): Boolean { - val pm = context.packageManager - return try { - pm.getPackageInfoCompat(packageName) - true - } catch (e: PackageManager.NameNotFoundException) { - false - } -} - -fun PackageManager.getPackageInfoCompat(packageName: String, flags: Int = 0): PackageInfo = - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - getPackageInfo(packageName, PackageManager.PackageInfoFlags.of(flags.toLong())) - } else { - @Suppress("DEPRECATION") getPackageInfo(packageName, flags) - } \ No newline at end of file diff --git a/core-shared-ui/src/main/res/drawable/ic_copy_content.xml b/core-shared-ui/src/main/res/drawable/ic_copy_content.xml deleted file mode 100644 index 9b16f48a..00000000 --- a/core-shared-ui/src/main/res/drawable/ic_copy_content.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/core-shared-ui/src/main/res/mipmap-anydpi-v26/ic_netflix.xml b/core-shared-ui/src/main/res/mipmap-anydpi-v26/ic_netflix.xml deleted file mode 100644 index 4cc788ad..00000000 --- a/core-shared-ui/src/main/res/mipmap-anydpi-v26/ic_netflix.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/core-shared-ui/src/main/res/mipmap-anydpi-v26/ic_netflix_round.xml b/core-shared-ui/src/main/res/mipmap-anydpi-v26/ic_netflix_round.xml deleted file mode 100644 index 4cc788ad..00000000 --- a/core-shared-ui/src/main/res/mipmap-anydpi-v26/ic_netflix_round.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/core-shared-ui/src/main/res/raw/logo.json b/core-shared-ui/src/main/res/raw/logo.json deleted file mode 100644 index 11491082..00000000 --- a/core-shared-ui/src/main/res/raw/logo.json +++ /dev/null @@ -1 +0,0 @@ -{"v":"5.5.7","meta":{"g":"LottieFiles AE 0.1.21","a":"","k":"","d":"","tc":"#FFFFFF"},"fr":60,"ip":0,"op":306,"w":512,"h":512,"nm":"Nettflix","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Big N 1","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":18,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":28.666,"s":[100]},{"i":{"x":[1],"y":[1]},"o":{"x":[0.612],"y":[0]},"t":114,"s":[100]},{"t":142,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.455,"y":1},"o":{"x":0.684,"y":0},"t":104,"s":[256,256,0],"to":[-24.667,0,0],"ti":[24.667,0,0]},{"t":154.74609375,"s":[108,256,0]}],"ix":2},"a":{"a":0,"k":[0.209,0.143,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.461,0.461,0.667],"y":[1,1,1]},"o":{"x":[0.655,0.655,0.333],"y":[0,0,0]},"t":46,"s":[66,66,100]},{"t":104,"s":[21,21,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.252,"y":1},"o":{"x":0.434,"y":0},"t":18,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[42.684,1.078],[0,0]],"v":[[120.607,218.722],[31.805,211.525],[31.977,211.212],[120.318,218.496]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":46,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[42.684,1.078],[0,0]],"v":[[-34.128,-218.21],[-119.9,-218.21],[31.977,211.212],[120.318,218.496]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":124,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[42.684,1.078],[0,0]],"v":[[-34.128,-218.21],[-119.9,-218.21],[31.977,211.212],[120.318,218.496]],"c":true}]},{"t":156,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[44.422,-6.307],[0,0]],"v":[[-47.223,-218.706],[-102.043,-218.706],[41.501,198.117],[102.46,192.802]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.898039215686,0.035294117647,0.078431372549,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Big N 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3868,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Big N 2 matte","parent":1,"td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":10.666,"s":[100]},{"i":{"x":[1],"y":[1]},"o":{"x":[0.612],"y":[0]},"t":114,"s":[100]},{"t":142,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[77.223,0,0],"ix":2},"a":{"a":0,"k":[77.223,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.252,"y":1},"o":{"x":0.434,"y":0},"t":0,"s":[{"i":[[0,0],[0,0],[0,0],[1.198,0]],"o":[[0,0],[0,0],[-0.901,0],[0,0]],"v":[[34.099,-359.119],[120.288,-359.43],[120.49,-359.888],[33.164,-359.117]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":24,"s":[{"i":[[0,0],[0,0],[0,0],[28.673,0.875]],"o":[[0,0],[0,0],[-28.673,-3.601],[0,0]],"v":[[34.128,-218.21],[120.318,-218.521],[120.318,218.521],[34.128,211.337]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":124,"s":[{"i":[[0,0],[0,0],[0,0],[28.673,0.875]],"o":[[0,0],[0,0],[-28.673,-3.601],[0,0]],"v":[[34.128,-218.21],[120.318,-218.521],[120.318,218.521],[34.128,211.337]],"c":true}]},{"t":156,"s":[{"i":[[0,0],[0,0],[0,0],[28.249,-4.53]],"o":[[0,0],[0,0],[-27.545,1.34],[0,0]],"v":[[48.414,-218.706],[114.365,-217.965],[116.869,194.041],[44.408,201.102]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.694117647059,0.023529411765,0.058823529412,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Big N 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3868,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Big N 1 shadow 2","tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":18,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":28.666,"s":[100]},{"i":{"x":[1],"y":[1]},"o":{"x":[0.612],"y":[0]},"t":114,"s":[100]},{"t":142,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.455,"y":1},"o":{"x":0.684,"y":0},"t":104,"s":[256,256,0],"to":[-24.667,0,0],"ti":[24.667,0,0]},{"t":154.74609375,"s":[108,256,0]}],"ix":2},"a":{"a":0,"k":[0.209,0.143,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.461,0.461,0.667],"y":[1,1,1]},"o":{"x":[0.655,0.655,0.333],"y":[0,0,0]},"t":46,"s":[66,66,100]},{"t":104,"s":[21,21,100]}],"ix":6}},"ao":0,"ef":[{"ty":25,"nm":"Drop Shadow","np":8,"mn":"ADBE Drop Shadow","ix":1,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0.086274512112,0,0.0074725952,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":178.5,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":0,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":100,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.252,"y":1},"o":{"x":0.434,"y":0},"t":18,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[42.684,1.078],[0,0]],"v":[[120.607,218.722],[31.805,211.525],[31.977,211.212],[120.318,218.496]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":46,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[42.684,1.078],[0,0]],"v":[[-34.128,-218.21],[-119.9,-218.21],[31.977,211.212],[120.318,218.496]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":124,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[42.684,1.078],[0,0]],"v":[[-34.128,-218.21],[-119.9,-218.21],[31.977,211.212],[120.318,218.496]],"c":true}]},{"t":156,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[44.422,-6.307],[0,0]],"v":[[-47.223,-218.706],[-102.043,-218.706],[41.501,198.117],[102.46,192.802]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.898039215686,0.035294117647,0.078431372549,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Big N 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":0,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3868,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Big N 2","parent":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":10.666,"s":[100]},{"i":{"x":[1],"y":[1]},"o":{"x":[0.612],"y":[0]},"t":114,"s":[100]},{"t":142,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[77.223,0,0],"ix":2},"a":{"a":0,"k":[77.223,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.252,"y":1},"o":{"x":0.434,"y":0},"t":0,"s":[{"i":[[0,0],[0,0],[0,0],[1.198,0]],"o":[[0,0],[0,0],[-0.901,0],[0,0]],"v":[[34.099,-359.119],[120.288,-359.43],[120.49,-359.888],[33.164,-359.117]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":24,"s":[{"i":[[0,0],[0,0],[0,0],[28.673,0.875]],"o":[[0,0],[0,0],[-28.673,-3.601],[0,0]],"v":[[34.128,-218.21],[120.318,-218.521],[120.318,218.521],[34.128,211.337]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":124,"s":[{"i":[[0,0],[0,0],[0,0],[28.673,0.875]],"o":[[0,0],[0,0],[-28.673,-3.601],[0,0]],"v":[[34.128,-218.21],[120.318,-218.521],[120.318,218.521],[34.128,211.337]],"c":true}]},{"t":156,"s":[{"i":[[0,0],[0,0],[0,0],[28.249,-4.53]],"o":[[0,0],[0,0],[-27.545,1.34],[0,0]],"v":[[48.414,-218.706],[114.365,-217.965],[116.869,194.041],[44.408,201.102]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.694117647059,0.023529411765,0.058823529412,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Big N 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3868,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Big N 3 matte","parent":1,"td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":38,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":48.666,"s":[100]},{"i":{"x":[1],"y":[1]},"o":{"x":[0.612],"y":[0]},"t":114,"s":[100]},{"t":142,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-77.223,0,0],"ix":2},"a":{"a":0,"k":[-77.223,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.252,"y":1},"o":{"x":0.434,"y":0},"t":38,"s":[{"i":[[0,0],[0,0],[0,0],[0,1.089]],"o":[[0,0],[0,0],[26.294,0.724],[0,0]],"v":[[-34.128,-218.21],[-120.318,-218.521],[-120.72,-218.979],[-34.705,-218.587]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":60,"s":[{"i":[[0,0],[0,0],[0,0],[-28.673,0.875]],"o":[[0,0],[0,0],[28.673,-3.601],[0,0]],"v":[[-34.128,-218.21],[-120.318,-218.521],[-120.318,218.521],[-34.128,211.337]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":124,"s":[{"i":[[0,0],[0,0],[0,0],[-28.673,0.875]],"o":[[0,0],[0,0],[28.673,-3.601],[0,0]],"v":[[-34.128,-218.21],[-120.318,-218.521],[-120.318,218.521],[-34.128,211.337]],"c":true}]},{"t":156,"s":[{"i":[[0,0],[0,0],[0,0],[-28.758,-0.959]],"o":[[0,0],[0,0],[28.673,-3.601],[0,0]],"v":[[-43.652,-218.74],[-106.032,-218.137],[-106.032,217.33],[-37.7,211.816]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.694117647059,0.023529411765,0.058823529412,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Big N 3","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3868,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Big N 1 shadow","tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":18,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":28.666,"s":[100]},{"i":{"x":[1],"y":[1]},"o":{"x":[0.612],"y":[0]},"t":114,"s":[100]},{"t":142,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.455,"y":1},"o":{"x":0.684,"y":0},"t":104,"s":[256,256,0],"to":[-24.667,0,0],"ti":[24.667,0,0]},{"t":154.74609375,"s":[108,256,0]}],"ix":2},"a":{"a":0,"k":[0.209,0.143,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.461,0.461,0.667],"y":[1,1,1]},"o":{"x":[0.655,0.655,0.333],"y":[0,0,0]},"t":46,"s":[66,66,100]},{"t":104,"s":[21,21,100]}],"ix":6}},"ao":0,"ef":[{"ty":25,"nm":"Drop Shadow","np":8,"mn":"ADBE Drop Shadow","ix":1,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0.086274512112,0,0.0074725952,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":178.5,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":0,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":100,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.252,"y":1},"o":{"x":0.434,"y":0},"t":18,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[42.684,1.078],[0,0]],"v":[[120.607,218.722],[31.805,211.525],[31.977,211.212],[120.318,218.496]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":46,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[42.684,1.078],[0,0]],"v":[[-34.128,-218.21],[-119.9,-218.21],[31.977,211.212],[120.318,218.496]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":124,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[42.684,1.078],[0,0]],"v":[[-34.128,-218.21],[-119.9,-218.21],[31.977,211.212],[120.318,218.496]],"c":true}]},{"t":156,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[44.422,-6.307],[0,0]],"v":[[-47.223,-218.706],[-102.043,-218.706],[41.501,198.117],[102.46,192.802]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.898039215686,0.035294117647,0.078431372549,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Big N 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3868,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Big N 3","parent":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":38,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":48.666,"s":[100]},{"i":{"x":[1],"y":[1]},"o":{"x":[0.612],"y":[0]},"t":114,"s":[100]},{"t":142,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-77.223,0,0],"ix":2},"a":{"a":0,"k":[-77.223,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.252,"y":1},"o":{"x":0.434,"y":0},"t":38,"s":[{"i":[[0,0],[0,0],[0,0],[0,1.089]],"o":[[0,0],[0,0],[26.294,0.724],[0,0]],"v":[[-34.128,-218.21],[-120.318,-218.521],[-120.72,-218.979],[-34.705,-218.587]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":60,"s":[{"i":[[0,0],[0,0],[0,0],[-28.673,0.875]],"o":[[0,0],[0,0],[28.673,-3.601],[0,0]],"v":[[-34.128,-218.21],[-120.318,-218.521],[-120.318,218.521],[-34.128,211.337]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":124,"s":[{"i":[[0,0],[0,0],[0,0],[-28.673,0.875]],"o":[[0,0],[0,0],[28.673,-3.601],[0,0]],"v":[[-34.128,-218.21],[-120.318,-218.521],[-120.318,218.521],[-34.128,211.337]],"c":true}]},{"t":156,"s":[{"i":[[0,0],[0,0],[0,0],[-28.758,-0.959]],"o":[[0,0],[0,0],[28.673,-3.601],[0,0]],"v":[[-43.652,-218.74],[-106.032,-218.137],[-106.032,217.33],[-37.7,211.816]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.694117647059,0.023529411765,0.058823529412,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Big N 3","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3868,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Netflix reveal","parent":9,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.715,"y":1},"o":{"x":0.414,"y":0},"t":206.207,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[166,-55],[165,-52]],"c":false}]},{"t":220,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[164,-51],[125,45.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.715,"y":1},"o":{"x":0.414,"y":0},"t":200.297,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[125,-54.5],[125,-52]],"c":false}]},{"t":214.08984375,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[126.5,-52],[164,50]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[144.5,-1],"ix":2},"a":{"a":0,"k":[144.5,-1],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"X","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.715,"y":1},"o":{"x":0.414,"y":0},"t":186.271,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[100,-51],[100,-48]],"c":false}]},{"t":198.09375,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[100,-47],[100,42]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"I","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.715,"y":1},"o":{"x":0.414,"y":0},"t":175.586,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[37,29],[40.5,29]],"c":false}]},{"t":189.37890625,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[37,29],[83.5,28.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"L 2","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.715,"y":1},"o":{"x":0.414,"y":0},"t":171.645,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[49,-50.5],[49,-48.5]],"c":true}]},{"t":185.4375,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[49,-47.5],[49.5,38]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"L1","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[60.25,-4.75],"ix":2},"a":{"a":0,"k":[60.25,-4.75],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"L","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.715,"y":1},"o":{"x":0.414,"y":0},"t":159.992,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-9.5,-7.5],[-11.5,-7.5]],"c":false}]},{"t":175.75390625,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[28,-7.5],[-9.5,-7.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.715,"y":1},"o":{"x":0.414,"y":0},"t":154.08,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[0.5,-50],[0.5,-48]],"c":false}]},{"t":169.84375,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[0.5,-48],[0,37]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 3","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.715,"y":1},"o":{"x":0.414,"y":0},"t":145.266,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-10.5,-39.5],[-12,-39.5]],"c":false}]},{"t":160.693359375,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[36,-39.5],[-9,-39.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[13.25,-5.5],"ix":2},"a":{"a":0,"k":[13.25,-5.5],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"F","np":3,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.715,"y":1},"o":{"x":0.414,"y":0},"t":136.115,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-40.5,-54],[-40.5,-49.5]],"c":false}]},{"t":151.876953125,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-38.5,-45.5],[-39,38.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.715,"y":1},"o":{"x":0.414,"y":0},"t":132.174,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-62.5,-38.5],[-66,-38.5]],"c":false}]},{"t":147.9375,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-14.5,-40.5],[-63.5,-38.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[-39,-3.5],"ix":2},"a":{"a":0,"k":[-39,-3.5],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"T","np":2,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.715,"y":1},"o":{"x":0.414,"y":0},"t":127.73,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-114,32.5],[-119,32.5]],"c":false}]},{"t":147.435546875,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-67.5,29],[-112,32.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 3","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.715,"y":1},"o":{"x":0.414,"y":0},"t":121.82,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-115,-6.5],[-119.5,-6.5]],"c":true}]},{"t":141.033203125,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-74.5,-6],[-113,-6]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.715,"y":1},"o":{"x":0.414,"y":0},"t":117.881,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-103.5,-54.5],[-103.5,-49]],"c":false}]},{"t":137.58203125,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-103.5,-48.5],[-102.5,42]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 4","np":3,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.715,"y":1},"o":{"x":0.414,"y":0},"t":110,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-117,-38],[-120.5,-38]],"c":false}]},{"t":129.2109375,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-68,-38],[-114.5,-38]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[-90,-3.25],"ix":2},"a":{"a":0,"k":[-90,-3.25],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"E","np":4,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false}],"ip":101,"op":3868,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"Etflix","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"s":true,"x":{"a":1,"k":[{"i":{"x":[0.455],"y":[1]},"o":{"x":[0.684],"y":[0]},"t":104,"s":[402.75]},{"t":154.74609375,"s":[256]}],"ix":3},"y":{"a":0,"k":256,"ix":4}},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[-5.131,0],[0,0],[5.401,-0.27],[0,0],[-8.551,0.27],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[5.582,0],[0,0],[-6.392,0],[0,0],[8.462,-0.54],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-95.285,-12.333],[-76.021,-12.603],[-76.021,1.8],[-95.285,2.07],[-95.285,23.495],[-69.81,21.964],[-69.81,35.826],[-109.689,38.978],[-109.689,-46.09],[-69.81,-46.09],[-69.81,-31.687],[-95.285,-31.687]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[4.68,-0.18],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[-4.861,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-16.249,-31.686],[-31.192,-31.686],[-31.192,34.568],[-45.594,34.747],[-45.594,-31.686],[-60.537,-31.686],[-60.537,-46.09],[-16.248,-46.09]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[7.156,-13.323],[26.871,-13.323],[26.871,1.08],[7.156,1.08],[7.156,33.757],[-6.978,33.757],[-6.978,-46.09],[33.262,-46.09],[33.262,-31.687],[7.156,-31.687]],"c":true},"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ind":4,"ty":"sh","ix":5,"ks":{"a":0,"k":{"i":[[0,0],[-8.012,-0.449],[0,0],[13.143,0.271],[0,0],[0,0]],"o":[[8.192,0.18],[0,0],[-12.873,-0.811],[0,0],[0,0],[0,0]],"v":[[56.667,21.154],[81.152,22.415],[81.152,36.638],[42.264,34.747],[42.264,-46.09],[56.667,-46.09]],"c":true},"ix":2},"nm":"Path 5","mn":"ADBE Vector Shape - Group","hd":false},{"ind":5,"ty":"sh","ix":6,"ks":{"a":0,"k":{"i":[[0,0],[-4.681,-0.539],[0,0],[0,0]],"o":[[4.591,0.27],[0,0],[0,0],[0,0]],"v":[[93.304,37.628],[107.437,38.708],[107.437,-46.09],[93.304,-46.09]],"c":true},"ix":2},"nm":"Path 6","mn":"ADBE Vector Shape - Group","hd":false},{"ind":6,"ty":"sh","ix":7,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[5.401,0.9],[0,0],[0,0],[5.22,0.72],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[-5.403,-0.72],[0,0],[0,0],[-5.222,-0.901],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[170.541,-46.09],[152.267,-2.25],[170.541,46.09],[154.337,43.479],[143.985,16.834],[133.454,41.319],[117.971,39.428],[136.515,-2.791],[119.771,-46.09],[135.253,-46.09],[144.705,-21.875],[154.788,-46.09]],"c":true},"ix":2},"nm":"Path 7","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.898039215686,0.035294117647,0.078431372549,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Netflix Wordmark","np":8,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":102,"op":3868,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"Netflix N","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"s":true,"x":{"a":1,"k":[{"i":{"x":[0.455],"y":[1]},"o":{"x":[0.684],"y":[0]},"t":104,"s":[402.75]},{"t":154.74609375,"s":[256]}],"ix":3},"y":{"a":0,"k":256,"ix":4}},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[5.401,-0.719],[0,0],[0,0],[4.861,-0.72],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[-5.131,0.901],[0,0],[0,0],[-5.131,0.54],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-123.641,40.148],[-139.394,42.039],[-155.868,-6.211],[-155.868,44.11],[-170.541,46.09],[-170.541,-46.09],[-156.858,-46.09],[-138.134,6.212],[-138.134,-46.09],[-123.641,-46.09]],"c":true},"ix":2},"nm":"N","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.898039215686,0.035294117647,0.078431372549,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Netflix Wordmark","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":102,"op":3868,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/core-shared-ui/src/main/res/values-night/themes.xml b/core-shared-ui/src/main/res/values-night/themes.xml deleted file mode 100644 index 04c0b155..00000000 --- a/core-shared-ui/src/main/res/values-night/themes.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - diff --git a/core-shared-ui/src/main/res/values/colors.xml b/core-shared-ui/src/main/res/values/colors.xml deleted file mode 100644 index f8c6127d..00000000 --- a/core-shared-ui/src/main/res/values/colors.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - #FFBB86FC - #FF6200EE - #FF3700B3 - #FF03DAC5 - #FF018786 - #FF000000 - #FFFFFFFF - \ No newline at end of file diff --git a/core-shared-ui/src/main/res/values/content-description.xml b/core-shared-ui/src/main/res/values/content-description.xml deleted file mode 100644 index a3353e8e..00000000 --- a/core-shared-ui/src/main/res/values/content-description.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - Ícone Netflix - Ícone Perfil - Ícone Buscar - Ícone Fechar - Ícone Microfone - Ícone Voltar - Ícone Projetar - \ No newline at end of file diff --git a/core-shared-ui/src/main/res/values/themes.xml b/core-shared-ui/src/main/res/values/themes.xml deleted file mode 100644 index 56f74635..00000000 --- a/core-shared-ui/src/main/res/values/themes.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/core-shared/build.gradle.kts b/core-shared/build.gradle.kts index f1b45dda..692b2f9a 100644 --- a/core-shared/build.gradle.kts +++ b/core-shared/build.gradle.kts @@ -1,7 +1,12 @@ plugins { - id("com.streamplayer.android-library") + id("com.streamplayer.kmp-library") } -dependencies { - implementation(libs.bundles.koin) + +kotlin { + sourceSets { + commonMain.dependencies { + implementation(libs.koin.core) + } + } } \ No newline at end of file diff --git a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/Url.kt b/core-shared/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared/Url.kt similarity index 80% rename from core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/Url.kt rename to core-shared/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared/Url.kt index 1b0d9b77..8ea4c8e2 100644 --- a/core-networking/src/main/java/com/codandotv/streamplayerapp/core_networking/Url.kt +++ b/core-shared/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared/Url.kt @@ -1,4 +1,4 @@ -package com.codandotv.streamplayerapp.core_networking +package com.codandotv.streamplayerapp.core_shared object Url { const val IMAGE_URL_SIZE_200 = "https://image.tmdb.org/t/p/w200/" diff --git a/core-shared/src/main/java/com/codandotv/streamplayerapp/core_shared/extension/String.Ext.kt b/core-shared/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared/extension/String.Ext.kt similarity index 100% rename from core-shared/src/main/java/com/codandotv/streamplayerapp/core_shared/extension/String.Ext.kt rename to core-shared/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared/extension/String.Ext.kt diff --git a/core-shared/src/main/java/com/codandotv/streamplayerapp/core_shared/qualifier/QualifierDispatcherIO.kt b/core-shared/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared/qualifier/QualifierDispatcherIO.kt similarity index 100% rename from core-shared/src/main/java/com/codandotv/streamplayerapp/core_shared/qualifier/QualifierDispatcherIO.kt rename to core-shared/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared/qualifier/QualifierDispatcherIO.kt diff --git a/core-shared/src/main/AndroidManifest.xml b/core-shared/src/main/AndroidManifest.xml deleted file mode 100644 index a8800291..00000000 --- a/core-shared/src/main/AndroidManifest.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/core-shared/src/main/java/com/codandotv/streamplayerapp/core_shared/extension/ErrorExt.kt b/core-shared/src/main/java/com/codandotv/streamplayerapp/core_shared/extension/ErrorExt.kt deleted file mode 100644 index 606f8b9d..00000000 --- a/core-shared/src/main/java/com/codandotv/streamplayerapp/core_shared/extension/ErrorExt.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.codandotv.streamplayerapp.core_shared.extension - -import android.content.Context -import android.widget.Toast - -fun showErrorMessage(context: Context, errorMessage: String, duration: Int = Toast.LENGTH_LONG) { - Toast.makeText(context, errorMessage, duration).show() -} \ No newline at end of file diff --git a/core-shared/src/main/java/com/codandotv/streamplayerapp/core_shared/extension/UriExt.kt b/core-shared/src/main/java/com/codandotv/streamplayerapp/core_shared/extension/UriExt.kt deleted file mode 100644 index 573f734e..00000000 --- a/core-shared/src/main/java/com/codandotv/streamplayerapp/core_shared/extension/UriExt.kt +++ /dev/null @@ -1,53 +0,0 @@ -package com.codandotv.streamplayerapp.core_shared.extension - -import android.content.Context -import android.graphics.BitmapFactory -import android.net.Uri -import android.provider.MediaStore -import java.io.IOException -import java.io.InputStream -import java.net.HttpURLConnection -import java.net.MalformedURLException -import java.net.URL -import java.util.* - -@Suppress("MagicNumber", "SwallowedException") -fun getUriFromUrlImage( - contentUrl: String, - context: Context -): Uri? { - var url: URL? = null - try { - url = URL(contentUrl) - } catch (e: MalformedURLException) { - e.printStackTrace() - } - var connection: HttpURLConnection? = null - try { - assert(url != null) - connection = url!!.openConnection() as HttpURLConnection - } catch (e: IOException) { - showErrorMessage(context, "Erro ao buscar imagem") - } - assert(connection != null) - connection!!.doInput = true - try { - connection.connect() - } catch (e: IOException) { - showErrorMessage(context, "Erro ao buscar imagem") - } - var input: InputStream? = null - try { - input = connection.inputStream - } catch (e: IOException) { - showErrorMessage(context, "Erro ao buscar imagem") - } - val imgBitmap = BitmapFactory.decodeStream(input) - val rand = Random() - val randNo = rand.nextInt(100000) - val imgBitmapPath = MediaStore.Images.Media.insertImage( - context.contentResolver, imgBitmap, - "IMG:$randNo", null - ) - return Uri.parse(imgBitmapPath) -} \ No newline at end of file diff --git a/feature-favorites/.gitignore b/feature-detail/.gitignore similarity index 100% rename from feature-favorites/.gitignore rename to feature-detail/.gitignore diff --git a/feature-detail/build.gradle.kts b/feature-detail/build.gradle.kts new file mode 100644 index 00000000..0ad22fc8 --- /dev/null +++ b/feature-detail/build.gradle.kts @@ -0,0 +1,38 @@ +@file:Suppress("UnstableApiUsage") + +plugins { + id("com.streamplayer.kmp-library") + alias(libs.plugins.jetbrains.compose) + alias(libs.plugins.compose.compiler) +} + +kotlin { + sourceSets { + androidMain.dependencies { + implementation(compose.preview) + } + commonMain.dependencies { + implementation(libs.koin.core) + implementation(libs.koin.compose) + implementation(libs.koin.compose.viewmodel) + + implementation(projects.coreNetworking) + implementation(projects.coreNavigation) + implementation(projects.coreShared) + implementation(projects.coreSharedUi) + implementation(projects.coreLocalStorage) + + implementation(compose.material3) + implementation(compose.ui) + implementation(compose.components.resources) + + implementation(libs.navigation.compose) + + implementation(libs.ktor.client.content.serialization.json) + implementation(libs.ktor.client.content.negotiation) + } + androidUnitTest.dependencies { + implementation(libs.bundles.test) + } + } +} \ No newline at end of file diff --git a/feature-favorites/consumer-rules.pro b/feature-detail/consumer-rules.pro similarity index 100% rename from feature-favorites/consumer-rules.pro rename to feature-detail/consumer-rules.pro diff --git a/feature-favorites/proguard-rules.pro b/feature-detail/proguard-rules.pro similarity index 100% rename from feature-favorites/proguard-rules.pro rename to feature-detail/proguard-rules.pro diff --git a/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/DetailStreamRepositoryTest.kt b/feature-detail/src/androidUnitTest/kotlin/com/codandotv/streamplayerapp/feature_detail/DetailStreamRepositoryTest.kt similarity index 80% rename from feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/DetailStreamRepositoryTest.kt rename to feature-detail/src/androidUnitTest/kotlin/com/codandotv/streamplayerapp/feature_detail/DetailStreamRepositoryTest.kt index f2f00d88..042fb260 100644 --- a/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/DetailStreamRepositoryTest.kt +++ b/feature-detail/src/androidUnitTest/kotlin/com/codandotv/streamplayerapp/feature_detail/DetailStreamRepositoryTest.kt @@ -1,10 +1,10 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail +package com.codandotv.streamplayerapp.feature_detail import com.codandotv.streamplayerapp.core_local_storage.data.dao.FavoriteDao import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse -import com.codandotv.streamplayerapp.feature_list_streams.detail.data.DetailStreamRepository -import com.codandotv.streamplayerapp.feature_list_streams.detail.data.DetailStreamRepositoryImpl -import com.codandotv.streamplayerapp.feature_list_streams.detail.data.DetailStreamService +import com.codandotv.streamplayerapp.feature_detail.data.DetailStreamRepository +import com.codandotv.streamplayerapp.feature_detail.data.DetailStreamRepositoryImpl +import com.codandotv.streamplayerapp.feature_detail.data.DetailStreamService import io.mockk.coEvery import io.mockk.coVerifyOrder import io.mockk.mockk diff --git a/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/DetailStreamUseCaseTest.kt b/feature-detail/src/androidUnitTest/kotlin/com/codandotv/streamplayerapp/feature_detail/DetailStreamUseCaseTest.kt similarity index 66% rename from feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/DetailStreamUseCaseTest.kt rename to feature-detail/src/androidUnitTest/kotlin/com/codandotv/streamplayerapp/feature_detail/DetailStreamUseCaseTest.kt index f08442b4..37e4c128 100644 --- a/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/DetailStreamUseCaseTest.kt +++ b/feature-detail/src/androidUnitTest/kotlin/com/codandotv/streamplayerapp/feature_detail/DetailStreamUseCaseTest.kt @@ -1,15 +1,12 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail +package com.codandotv.streamplayerapp.feature_detail -import com.codandotv.streamplayerapp.feature_list_streams.detail.data.DetailStreamRepository -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.DetailStream -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.DetailStreamUseCase -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.DetailStreamUseCaseImpl +import com.codandotv.streamplayerapp.feature_detail.data.DetailStreamRepository +import com.codandotv.streamplayerapp.feature_detail.domain.DetailStreamUseCase +import com.codandotv.streamplayerapp.feature_detail.domain.DetailStreamUseCaseImpl import io.mockk.coEvery import io.mockk.coVerify import io.mockk.mockk -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.flowOf -import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test diff --git a/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/DetailStreamViewModelTest.kt b/feature-detail/src/androidUnitTest/kotlin/com/codandotv/streamplayerapp/feature_detail/DetailStreamViewModelTest.kt similarity index 78% rename from feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/DetailStreamViewModelTest.kt rename to feature-detail/src/androidUnitTest/kotlin/com/codandotv/streamplayerapp/feature_detail/DetailStreamViewModelTest.kt index 60a47271..65a2ae0d 100644 --- a/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/DetailStreamViewModelTest.kt +++ b/feature-detail/src/androidUnitTest/kotlin/com/codandotv/streamplayerapp/feature_detail/DetailStreamViewModelTest.kt @@ -1,11 +1,10 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail +package com.codandotv.streamplayerapp.feature_detail import androidx.arch.core.executor.testing.InstantTaskExecutorRule -import androidx.lifecycle.LifecycleOwner -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.DetailStreamUseCase -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.VideoStreamsUseCase -import com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.screens.DetailStreamViewModel -import com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.screens.DetailStreamsUIState +import com.codandotv.streamplayerapp.feature_detail.domain.DetailStreamUseCase +import com.codandotv.streamplayerapp.feature_detail.domain.VideoStreamsUseCase +import com.codandotv.streamplayerapp.feature_detail.presentation.screens.DetailStreamViewModel +import com.codandotv.streamplayerapp.feature_detail.presentation.screens.DetailStreamsUIState import io.mockk.coEvery import io.mockk.coVerify import io.mockk.mockk diff --git a/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/InstantTaskCoroutinesExecutorRule.kt b/feature-detail/src/androidUnitTest/kotlin/com/codandotv/streamplayerapp/feature_detail/InstantTaskCoroutinesExecutorRule.kt similarity index 91% rename from feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/InstantTaskCoroutinesExecutorRule.kt rename to feature-detail/src/androidUnitTest/kotlin/com/codandotv/streamplayerapp/feature_detail/InstantTaskCoroutinesExecutorRule.kt index f30e6ca3..f0cf84a7 100644 --- a/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/InstantTaskCoroutinesExecutorRule.kt +++ b/feature-detail/src/androidUnitTest/kotlin/com/codandotv/streamplayerapp/feature_detail/InstantTaskCoroutinesExecutorRule.kt @@ -1,4 +1,4 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail +package com.codandotv.streamplayerapp.feature_detail import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi diff --git a/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/Shared.kt b/feature-detail/src/androidUnitTest/kotlin/com/codandotv/streamplayerapp/feature_detail/Shared.kt similarity index 64% rename from feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/Shared.kt rename to feature-detail/src/androidUnitTest/kotlin/com/codandotv/streamplayerapp/feature_detail/Shared.kt index 3adda93e..095ab5dc 100644 --- a/feature-list-streams/src/test/java/com/codandotv/streamplayerapp/feature_list_streams/detail/Shared.kt +++ b/feature-detail/src/androidUnitTest/kotlin/com/codandotv/streamplayerapp/feature_detail/Shared.kt @@ -1,8 +1,8 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail +package com.codandotv.streamplayerapp.feature_detail -import com.codandotv.streamplayerapp.feature_list_streams.detail.data.model.DetailStreamResponse -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.DetailStream -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.VideoStream +import com.codandotv.streamplayerapp.feature_detail.data.model.DetailStreamResponse +import com.codandotv.streamplayerapp.feature_detail.domain.DetailStream +import com.codandotv.streamplayerapp.feature_detail.domain.VideoStream val videoStream = VideoStream( movieId = 123, @@ -22,7 +22,7 @@ val videosStreamsList = listOf( ) val detailStreamResponse = DetailStreamResponse( - id = "id", + id = 12, title = "title", overview = "overview", tagline = "tagline", diff --git a/feature-list-streams/src/main/res/drawable/netflix_detail.webp b/feature-detail/src/commonMain/composeResources/drawable/netflix_detail.webp similarity index 100% rename from feature-list-streams/src/main/res/drawable/netflix_detail.webp rename to feature-detail/src/commonMain/composeResources/drawable/netflix_detail.webp diff --git a/feature-list-streams/src/main/res/drawable/play_circle.xml b/feature-detail/src/commonMain/composeResources/drawable/play_circle.xml similarity index 100% rename from feature-list-streams/src/main/res/drawable/play_circle.xml rename to feature-detail/src/commonMain/composeResources/drawable/play_circle.xml diff --git a/feature-detail/src/commonMain/composeResources/values/strings.xml b/feature-detail/src/commonMain/composeResources/values/strings.xml new file mode 100644 index 00000000..ac85d916 --- /dev/null +++ b/feature-detail/src/commonMain/composeResources/values/strings.xml @@ -0,0 +1,12 @@ + + + Assistir + Baixar E1 + Filme + Minha Lista + Classificar + Compartilhar + Baixar completo + Pesquisar + Voltar + \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/DetailStreamRepository.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/DetailStreamRepository.kt similarity index 75% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/DetailStreamRepository.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/DetailStreamRepository.kt index 7fd6c5e1..21adf8f1 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/DetailStreamRepository.kt +++ b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/DetailStreamRepository.kt @@ -1,12 +1,12 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.data +package com.codandotv.streamplayerapp.feature_detail.data import com.codandotv.streamplayerapp.core_local_storage.data.dao.FavoriteDao import com.codandotv.streamplayerapp.core_networking.handleError.toFlow -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.DetailStream -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.VideoStream -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.toDetailStream -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.toDetailStreamLocal -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.toVideoStreams +import com.codandotv.streamplayerapp.feature_detail.domain.DetailStream +import com.codandotv.streamplayerapp.feature_detail.domain.VideoStream +import com.codandotv.streamplayerapp.feature_detail.domain.toDetailStream +import com.codandotv.streamplayerapp.feature_detail.domain.toDetailStreamLocal +import com.codandotv.streamplayerapp.feature_detail.domain.toVideoStreams import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map diff --git a/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/DetailStreamService.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/DetailStreamService.kt new file mode 100644 index 00000000..f4c69ba1 --- /dev/null +++ b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/DetailStreamService.kt @@ -0,0 +1,28 @@ +package com.codandotv.streamplayerapp.feature_detail.data + +import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse +import com.codandotv.streamplayerapp.core_networking.handleError.safeRequest +import com.codandotv.streamplayerapp.feature_detail.data.model.DetailStreamResponse +import com.codandotv.streamplayerapp.feature_detail.data.model.VideoStreamsResponse +import io.ktor.client.HttpClient +import io.ktor.client.request.url + +interface DetailStreamService { + suspend fun getMovie(movieId: String): NetworkResponse + suspend fun getVideoStreams(movieId: String): NetworkResponse +} + +class DetailStreamServiceImpl( + private val client: HttpClient +) : DetailStreamService { + + override suspend fun getMovie(movieId: String): NetworkResponse = + client.safeRequest { + url("movie/$movieId") + } + + override suspend fun getVideoStreams(movieId: String): NetworkResponse = + client.safeRequest { + url("movie/$movieId/videos") + } +} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/model/DetailStreamResponse.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/model/DetailStreamResponse.kt similarity index 60% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/model/DetailStreamResponse.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/model/DetailStreamResponse.kt index 58f66c52..27c79e86 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/model/DetailStreamResponse.kt +++ b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/model/DetailStreamResponse.kt @@ -1,8 +1,11 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.data.model +package com.codandotv.streamplayerapp.feature_detail.data.model +import kotlinx.serialization.Serializable + +@Serializable @Suppress("ConstructorParameterNaming") data class DetailStreamResponse( - val id : String, + val id : Long, val title : String, val overview : String, val tagline : String, diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/model/VideoStreamResponse.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/model/VideoStreamResponse.kt similarity index 67% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/model/VideoStreamResponse.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/model/VideoStreamResponse.kt index e6b4a696..e7fcc7eb 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/model/VideoStreamResponse.kt +++ b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/data/model/VideoStreamResponse.kt @@ -1,5 +1,8 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.data.model +package com.codandotv.streamplayerapp.feature_detail.data.model +import kotlinx.serialization.Serializable + +@Serializable data class VideoStreamResponse( val id: String, val name: String, @@ -10,6 +13,7 @@ data class VideoStreamResponse( val type: String, ) +@Serializable data class VideoStreamsResponse( val id: Long, val results: List diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/di/DetailStreamModule.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/di/DetailStreamModule.kt similarity index 53% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/di/DetailStreamModule.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/di/DetailStreamModule.kt index 30723490..2a5e35db 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/di/DetailStreamModule.kt +++ b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/di/DetailStreamModule.kt @@ -1,18 +1,19 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.di +package com.codandotv.streamplayerapp.feature_detail.di -import com.codandotv.streamplayerapp.feature_list_streams.detail.data.DetailStreamRepository -import com.codandotv.streamplayerapp.feature_list_streams.detail.data.DetailStreamRepositoryImpl -import com.codandotv.streamplayerapp.feature_list_streams.detail.data.DetailStreamService -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.DetailStreamUseCase -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.DetailStreamUseCaseImpl -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.VideoStreamsUseCase -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.VideoStreamsUseCaseImpl -import com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.screens.DetailStreamViewModel +import com.codandotv.streamplayerapp.feature_detail.data.DetailStreamRepository +import com.codandotv.streamplayerapp.feature_detail.data.DetailStreamRepositoryImpl +import com.codandotv.streamplayerapp.feature_detail.data.DetailStreamService +import com.codandotv.streamplayerapp.feature_detail.data.DetailStreamServiceImpl +import com.codandotv.streamplayerapp.feature_detail.domain.DetailStreamUseCase +import com.codandotv.streamplayerapp.feature_detail.domain.DetailStreamUseCaseImpl +import com.codandotv.streamplayerapp.feature_detail.domain.VideoStreamsUseCase +import com.codandotv.streamplayerapp.feature_detail.domain.VideoStreamsUseCaseImpl +import com.codandotv.streamplayerapp.feature_detail.presentation.screens.DetailStreamViewModel import kotlinx.coroutines.Dispatchers -import org.koin.androidx.viewmodel.dsl.viewModel +import kotlinx.coroutines.IO +import org.koin.core.module.dsl.viewModel import org.koin.core.parameter.parametersOf import org.koin.dsl.module -import retrofit2.Retrofit object DetailStreamModule { val module = module { @@ -49,6 +50,10 @@ object DetailStreamModule { ) } - factory { get().create(DetailStreamService::class.java) } + factory { + DetailStreamServiceImpl( + client = get() + ) + } } } \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/DetailStream.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/DetailStream.kt similarity index 73% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/DetailStream.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/DetailStream.kt index 0cd575a5..0d9f6689 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/DetailStream.kt +++ b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/DetailStream.kt @@ -1,4 +1,4 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.domain +package com.codandotv.streamplayerapp.feature_detail.domain data class DetailStream( val id : String, diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/DetailStreamMapper.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/DetailStreamMapper.kt similarity index 69% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/DetailStreamMapper.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/DetailStreamMapper.kt index 174f7fc1..e12cf78f 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/DetailStreamMapper.kt +++ b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/DetailStreamMapper.kt @@ -1,14 +1,13 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.domain +package com.codandotv.streamplayerapp.feature_detail.domain import com.codandotv.streamplayerapp.core_local_storage.domain.model.MovieEntity -import com.codandotv.streamplayerapp.core_networking.Url.IMAGE_URL_SIZE_500 -import com.codandotv.streamplayerapp.feature_list_streams.detail.data.model.DetailStreamResponse -import com.codandotv.streamplayerapp.feature_list_streams.detail.data.model.VideoStreamsResponse +import com.codandotv.streamplayerapp.core_shared.Url.IMAGE_URL_SIZE_500 +import com.codandotv.streamplayerapp.feature_detail.data.model.DetailStreamResponse +import com.codandotv.streamplayerapp.feature_detail.data.model.VideoStreamsResponse -@Suppress("MagicNumber") fun DetailStreamResponse.toDetailStream(isFavorite: Boolean = false): DetailStream = DetailStream( - id = this.id, + id = this.id.toString(), title = this.title, overview = this.overview, tagline = this.tagline, diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/DetailStreamUseCase.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/DetailStreamUseCase.kt similarity index 80% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/DetailStreamUseCase.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/DetailStreamUseCase.kt index 88bd4705..74c3c256 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/DetailStreamUseCase.kt +++ b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/DetailStreamUseCase.kt @@ -1,6 +1,6 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.domain +package com.codandotv.streamplayerapp.feature_detail.domain -import com.codandotv.streamplayerapp.feature_list_streams.detail.data.DetailStreamRepository +import com.codandotv.streamplayerapp.feature_detail.data.DetailStreamRepository import kotlinx.coroutines.flow.Flow interface DetailStreamUseCase { diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/VideoStream.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/VideoStream.kt similarity index 50% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/VideoStream.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/VideoStream.kt index b97c964f..39ccb50e 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/VideoStream.kt +++ b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/VideoStream.kt @@ -1,4 +1,4 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.domain +package com.codandotv.streamplayerapp.feature_detail.domain data class VideoStream( val movieId: Long, diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/VideoStreamsUseCase.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/VideoStreamsUseCase.kt similarity index 69% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/VideoStreamsUseCase.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/VideoStreamsUseCase.kt index b15bb7bd..d35544be 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/domain/VideoStreamsUseCase.kt +++ b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/domain/VideoStreamsUseCase.kt @@ -1,6 +1,6 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.domain +package com.codandotv.streamplayerapp.feature_detail.domain -import com.codandotv.streamplayerapp.feature_list_streams.detail.data.DetailStreamRepository +import com.codandotv.streamplayerapp.feature_detail.data.DetailStreamRepository import kotlinx.coroutines.flow.Flow interface VideoStreamsUseCase { diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/navigation/DetailStreamNavigation.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/navigation/DetailStreamNavigation.kt similarity index 56% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/navigation/DetailStreamNavigation.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/navigation/DetailStreamNavigation.kt index 9db0b723..a52a01fb 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/navigation/DetailStreamNavigation.kt +++ b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/navigation/DetailStreamNavigation.kt @@ -1,25 +1,25 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.navigation +package com.codandotv.streamplayerapp.feature_detail.presentation.navigation -import androidx.lifecycle.Lifecycle import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController import androidx.navigation.compose.composable import com.codandotv.streamplayerapp.core_navigation.routes.Routes import com.codandotv.streamplayerapp.core_navigation.routes.Routes.DETAIL_COMPLETE import com.codandotv.streamplayerapp.core_navigation.routes.Routes.PARAM.ID -import com.codandotv.streamplayerapp.feature_list_streams.detail.di.DetailStreamModule -import com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.screens.DetailStreamScreen -import org.koin.androidx.compose.koinViewModel -import org.koin.core.context.loadKoinModules -import org.koin.core.context.unloadKoinModules +import com.codandotv.streamplayerapp.feature_detail.di.DetailStreamModule +import com.codandotv.streamplayerapp.feature_detail.presentation.screens.DetailStreamScreen +import org.koin.compose.module.rememberKoinModules +import org.koin.compose.viewmodel.koinViewModel +import org.koin.core.annotation.KoinExperimentalAPI import org.koin.core.parameter.parametersOf internal const val DEFAULT_ID = "0" +@OptIn(KoinExperimentalAPI::class) fun NavGraphBuilder.detailStreamNavGraph(navController: NavHostController) { composable(DETAIL_COMPLETE) { nav -> - if (nav.lifecycle.currentState == Lifecycle.State.STARTED) { - loadKoinModules(DetailStreamModule.module) + rememberKoinModules { + listOf(DetailStreamModule.module) } DetailStreamScreen( viewModel = koinViewModel { @@ -29,9 +29,6 @@ fun NavGraphBuilder.detailStreamNavGraph(navController: NavHostController) { onNavigateSearchScreen = { navController.navigate(Routes.SEARCH) }, - disposable = { - unloadKoinModules(DetailStreamModule.module) - } ) } } diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/screens/DetailStreamViewModel.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamViewModel.kt similarity index 72% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/screens/DetailStreamViewModel.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamViewModel.kt index 5d3ca5ba..a9ae55f1 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/screens/DetailStreamViewModel.kt +++ b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamViewModel.kt @@ -1,13 +1,14 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.screens +package com.codandotv.streamplayerapp.feature_detail.presentation.screens import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.codandotv.streamplayerapp.core_networking.handleError.catchFailure -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.DetailStream -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.DetailStreamUseCase -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.VideoStreamsUseCase -import com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.screens.DetailStreamsUIState.DetailStreamsLoadedUIState -import com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.screens.DetailStreamsUIState.LoadingStreamUIState +import com.codandotv.streamplayerapp.core_networking.resources.StringNetworking +import com.codandotv.streamplayerapp.feature_detail.domain.DetailStream +import com.codandotv.streamplayerapp.feature_detail.domain.DetailStreamUseCase +import com.codandotv.streamplayerapp.feature_detail.domain.VideoStreamsUseCase +import com.codandotv.streamplayerapp.feature_detail.presentation.screens.DetailStreamsUIState.DetailStreamsLoadedUIState +import com.codandotv.streamplayerapp.feature_detail.presentation.screens.DetailStreamsUIState.LoadingStreamUIState import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted @@ -25,6 +26,10 @@ class DetailStreamViewModel( private val dispatcher: CoroutineDispatcher ) : ViewModel() { + init { + loadDetail() + } + private val _uiState = MutableStateFlow(LoadingStreamUIState) val uiState: StateFlow = _uiState.stateIn( viewModelScope, @@ -44,7 +49,7 @@ class DetailStreamViewModel( .flowOn(dispatcher) .onStart { onLoading() } .catchFailure { - println(">>>> ${it.errorMessage}") + println(">>>> ${StringNetworking.getStringResource(it.errorMessageResKey)}") } .collect { result -> _uiState.update { diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/screens/DetailStreamsScreen.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamsScreen.kt similarity index 75% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/screens/DetailStreamsScreen.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamsScreen.kt index d4cbc47a..df3f2bfa 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/screens/DetailStreamsScreen.kt +++ b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamsScreen.kt @@ -1,7 +1,5 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.screens +package com.codandotv.streamplayerapp.feature_detail.presentation.screens -import android.annotation.SuppressLint -import androidx.activity.compose.BackHandler import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer @@ -12,62 +10,46 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.FileDownload +import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.PlayArrow import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.CircularProgressIndicator -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.collectAsState 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.LocalLifecycleOwner -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.em import androidx.compose.ui.unit.sp -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.compose.LifecycleEventEffect -import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavController -import com.codandotv.streamplayerapp.core_shared_ui.widget.SharingStreamCustomView -import com.codandotv.streamplayerapp.feature.list.streams.R -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.DetailStream -import com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.widget.DetailStreamActionOption -import com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.widget.DetailStreamButtonAction -import com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.widget.DetailStreamImagePreview -import com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.widget.DetailStreamRowHeader -import com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.widget.DetailStreamToolbar -import org.koin.androidx.compose.koinViewModel +import com.codandotv.streamplayerapp.core_shared_ui.widget.SharingStreamPlatform +import com.codandotv.streamplayerapp.feature_detail.domain.DetailStream +import com.codandotv.streamplayerapp.feature_detail.presentation.widget.DetailStreamActionOption +import com.codandotv.streamplayerapp.feature_detail.presentation.widget.DetailStreamButtonAction +import com.codandotv.streamplayerapp.feature_detail.presentation.widget.DetailStreamImagePreview +import com.codandotv.streamplayerapp.feature_detail.presentation.widget.DetailStreamRowHeader +import com.codandotv.streamplayerapp.feature_detail.presentation.widget.DetailStreamToolbar +import org.jetbrains.compose.resources.stringResource +import org.koin.compose.viewmodel.koinViewModel +import streamplayerapp_kmp.feature_detail.generated.resources.Res +import streamplayerapp_kmp.feature_detail.generated.resources.detail_default_text_secondary_button +import streamplayerapp_kmp.feature_detail.generated.resources.detail_watch_primary_button @Composable fun DetailStreamScreen( viewModel: DetailStreamViewModel = koinViewModel(), navController: NavController, - disposable: () -> Unit = {}, onNavigateSearchScreen: () -> Unit = {}, ) { - val uiState by viewModel.uiState.collectAsStateWithLifecycle() - - val lifecycleOwner = LocalLifecycleOwner.current - - LifecycleEventEffect(Lifecycle.Event.ON_START) { - viewModel.loadDetail() - } - - DisposableEffect(lifecycleOwner) { - onDispose { - disposable.invoke() - } - } + val uiState by viewModel.uiState.collectAsState() when (uiState) { is DetailStreamsUIState.DetailStreamsLoadedUIState -> { @@ -92,9 +74,7 @@ fun DetailStreamScreen( } } -@OptIn(ExperimentalMaterial3Api::class) @Suppress("LongMethod") -@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter") @Composable private fun SetupDetailScreen( onToggleToMyList: (DetailStream) -> Unit, @@ -154,7 +134,7 @@ private fun SetupDetailScreen( ), imageVector = Icons.Filled.PlayArrow, imageVectorColor = MaterialTheme.colorScheme.onSurface, - text = stringResource(R.string.detail_watch_primary_button), + text = stringResource(Res.string.detail_watch_primary_button), textColor = MaterialTheme.colorScheme.onSurface ) Spacer(modifier = Modifier.height(4.dp)) @@ -162,9 +142,9 @@ private fun SetupDetailScreen( buttonsColors = ButtonDefaults.buttonColors( containerColor = MaterialTheme.colorScheme.onSurfaceVariant ), - imageVector = Icons.Filled.FileDownload, + imageVector = Icons.Filled.Add, imageVectorColor = MaterialTheme.colorScheme.onSurface, - text = stringResource(id = R.string.detail_default_text_secondary_button), + text = stringResource(Res.string.detail_default_text_secondary_button), textColor = MaterialTheme.colorScheme.onSurface, ) Text( @@ -185,19 +165,19 @@ private fun SetupDetailScreen( } } if (showDialog.value) { - SharingStreamCustomView( + SharingStreamPlatform( contentTitle = uiState.detailStream.title, contentUrl = uiState.detailStream.url, setShowDialog = { showDialog.value = it }) } - BackHandler { + /*BackHandler { if (showDialog.value) { showDialog.value = false } else { navController.navigateUp() } - } + }*/ }) } \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/screens/DetailStreamsUIState.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamsUIState.kt similarity index 58% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/screens/DetailStreamsUIState.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamsUIState.kt index cfc4ebb7..66c2a144 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/screens/DetailStreamsUIState.kt +++ b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/screens/DetailStreamsUIState.kt @@ -1,6 +1,6 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.screens +package com.codandotv.streamplayerapp.feature_detail.presentation.screens -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.DetailStream +import com.codandotv.streamplayerapp.feature_detail.domain.DetailStream sealed class DetailStreamsUIState { data class DetailStreamsLoadedUIState( diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/widget/DetailStreamActionOption.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamActionOption.kt similarity index 72% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/widget/DetailStreamActionOption.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamActionOption.kt index e4b92603..03b52f98 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/widget/DetailStreamActionOption.kt +++ b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamActionOption.kt @@ -1,4 +1,4 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.widget +package com.codandotv.streamplayerapp.feature_detail.presentation.widget import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row @@ -6,7 +6,6 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Check -import androidx.compose.material.icons.filled.Download import androidx.compose.material.icons.filled.Share import androidx.compose.material.icons.filled.ThumbUp import androidx.compose.runtime.Composable @@ -18,10 +17,14 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource import com.codandotv.streamplayerapp.core_shared_ui.widget.IconWithText -import com.codandotv.streamplayerapp.feature.list.streams.R -import com.codandotv.streamplayerapp.feature_list_streams.detail.domain.DetailStream +import com.codandotv.streamplayerapp.feature_detail.domain.DetailStream +import org.jetbrains.compose.resources.stringResource +import streamplayerapp_kmp.feature_detail.generated.resources.Res +import streamplayerapp_kmp.feature_detail.generated.resources.detail_classification +import streamplayerapp_kmp.feature_detail.generated.resources.detail_download +import streamplayerapp_kmp.feature_detail.generated.resources.detail_my_list +import streamplayerapp_kmp.feature_detail.generated.resources.detail_share @Composable fun DetailStreamActionOption( @@ -49,28 +52,28 @@ fun DetailStreamActionOption( }, imageVector = iconCheckList, imageColor = Color.White, - text = stringResource(id = R.string.detail_my_list), + text = stringResource(Res.string.detail_my_list), textColor = Color.Gray, ) IconWithText( onClick = { TODO("Implementar mecanismo de classificação.") }, imageVector = Icons.Filled.ThumbUp, imageColor = Color.White, - text = stringResource(id = R.string.detail_classification), + text = stringResource(Res.string.detail_classification), textColor = Color.Gray, ) IconWithText( onClick = { onShowSharingOptions.invoke() }, imageVector = Icons.Filled.Share, imageColor = Color.White, - text = stringResource(id = R.string.detail_share), + text = stringResource(Res.string.detail_share), textColor = Color.Gray, ) IconWithText( onClick = { TODO("Implementar mecanismo de download.") }, - imageVector = Icons.Filled.Download, + imageVector = Icons.Filled.Share, imageColor = Color.White, - text = stringResource(id = R.string.detail_download), + text = stringResource(Res.string.detail_download), textColor = Color.Gray, ) } diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/widget/DetailStreamButtonAction.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamButtonAction.kt similarity index 95% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/widget/DetailStreamButtonAction.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamButtonAction.kt index 0cdefd53..c97b9f1e 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/widget/DetailStreamButtonAction.kt +++ b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamButtonAction.kt @@ -1,4 +1,4 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.widget +package com.codandotv.streamplayerapp.feature_detail.presentation.widget import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/widget/DetailStreamImagePreview.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamImagePreview.kt similarity index 75% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/widget/DetailStreamImagePreview.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamImagePreview.kt index e1451f60..5d17576d 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/widget/DetailStreamImagePreview.kt +++ b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamImagePreview.kt @@ -1,4 +1,4 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.widget +package com.codandotv.streamplayerapp.feature_detail.presentation.widget import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -14,12 +14,13 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp -import coil.compose.AsyncImage -import com.codandotv.streamplayerapp.core_shared_ui.widget.PlayerComponent -import com.codandotv.streamplayerapp.feature.list.streams.R -import com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.screens.DetailStreamsUIState.DetailStreamsLoadedUIState +import com.codandotv.streamplayerapp.core_shared_ui.widget.PlayerComponentPlatform +import com.codandotv.streamplayerapp.core_shared_ui.widget.WebImage +import com.codandotv.streamplayerapp.feature_detail.presentation.screens.DetailStreamsUIState.DetailStreamsLoadedUIState +import org.jetbrains.compose.resources.painterResource +import streamplayerapp_kmp.feature_detail.generated.resources.Res +import streamplayerapp_kmp.feature_detail.generated.resources.play_circle @Suppress("MagicNumber") @Composable @@ -36,12 +37,12 @@ fun DetailStreamImagePreview( contentAlignment = Alignment.Center ) { if (showPlayer) { - PlayerComponent( + PlayerComponentPlatform( videoId = uiState.videoId ?: "" ) } else { - AsyncImage( - model = uiState.detailStream.url, + WebImage( + imageUrl = uiState.detailStream.url, contentScale = ContentScale.FillBounds, contentDescription = uiState.detailStream.tagline, modifier = Modifier @@ -56,7 +57,7 @@ fun DetailStreamImagePreview( .align(Alignment.Center), ) Icon( - painter = painterResource(id = R.drawable.play_circle), + painter = painterResource(Res.drawable.play_circle), tint = Color.White, contentDescription = null, modifier = Modifier diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/widget/DetailStreamRowHeader.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamRowHeader.kt similarity index 71% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/widget/DetailStreamRowHeader.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamRowHeader.kt index 5ef2dfa5..cf5d5c0f 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/widget/DetailStreamRowHeader.kt +++ b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamRowHeader.kt @@ -1,4 +1,4 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.widget +package com.codandotv.streamplayerapp.feature_detail.presentation.widget import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Row @@ -11,13 +11,15 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.em import androidx.compose.ui.unit.sp -import com.codandotv.streamplayerapp.feature.list.streams.R +import org.jetbrains.compose.resources.painterResource +import org.jetbrains.compose.resources.stringResource +import streamplayerapp_kmp.feature_detail.generated.resources.Res +import streamplayerapp_kmp.feature_detail.generated.resources.detail_movie +import streamplayerapp_kmp.feature_detail.generated.resources.netflix_detail @Composable fun DetailStreamRowHeader( @@ -28,7 +30,7 @@ fun DetailStreamRowHeader( modifier = modifier ) { Image( - painter = painterResource(id = R.drawable.netflix_detail), + painter = painterResource(Res.drawable.netflix_detail), contentDescription = null, modifier = Modifier .size(26.dp) @@ -36,7 +38,7 @@ fun DetailStreamRowHeader( ) Text( - text = stringResource(id = R.string.detail_movie), + text = stringResource(Res.string.detail_movie), modifier = Modifier.offset(x = (-6).dp), style = MaterialTheme.typography.headlineMedium.copy( color = Color.Gray, diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/widget/DetailStreamToolbar.kt b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamToolbar.kt similarity index 66% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/widget/DetailStreamToolbar.kt rename to feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamToolbar.kt index 152ebe46..cdf05dce 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/presentation/widget/DetailStreamToolbar.kt +++ b/feature-detail/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_detail/presentation/widget/DetailStreamToolbar.kt @@ -1,4 +1,4 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.presentation.widget +package com.codandotv.streamplayerapp.feature_detail.presentation.widget import androidx.compose.foundation.Image import androidx.compose.foundation.layout.height @@ -13,11 +13,15 @@ import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.navigation.NavController -import com.codandotv.streamplayerapp.feature.list.streams.R +import org.jetbrains.compose.resources.painterResource +import org.jetbrains.compose.resources.stringResource +import streamplayerapp_kmp.core_shared_ui.generated.resources.perfil_fake +import streamplayerapp_kmp.feature_detail.generated.resources.Res +import streamplayerapp_kmp.core_shared_ui.generated.resources.Res as SharedRes +import streamplayerapp_kmp.feature_detail.generated.resources.detail_back +import streamplayerapp_kmp.feature_detail.generated.resources.detail_search @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -32,7 +36,7 @@ fun DetailStreamToolbar( IconButton(onClick = { navController.navigateUp() }) { Icon( imageVector = Icons.Filled.ArrowBack, - contentDescription = stringResource(id = R.string.detail_back) + contentDescription = stringResource(Res.string.detail_back) ) } }, actions = { @@ -42,12 +46,12 @@ fun DetailStreamToolbar( Icon( imageVector = Icons.Default.Search, tint = Color.White, - contentDescription = stringResource(id = R.string.detail_search) + contentDescription = stringResource(Res.string.detail_search) ) } IconButton(onClick = { }) { Image( - painter = painterResource(id = com.codandotv.streamplayerapp.core.shared.ui.R.drawable.perfil_fake), + painter = painterResource(SharedRes.drawable.perfil_fake), contentDescription = null ) } diff --git a/feature-favorites/build.gradle.kts b/feature-favorites/build.gradle.kts deleted file mode 100644 index 6bf94b61..00000000 --- a/feature-favorites/build.gradle.kts +++ /dev/null @@ -1,19 +0,0 @@ -@file:Suppress("UnstableApiUsage") -plugins { - id("com.streamplayer.android-library") - id("com.streamplayer.compose") -} - -dependencies { - implementation(projects.coreNetworking) - implementation(projects.coreNavigation) - implementation(projects.coreShared) - implementation(projects.coreSharedUi) - - implementation(libs.bundles.koin) - implementation(libs.bundles.networking) - implementation(libs.bundles.androidSupport) - implementation(libs.coil) - - testImplementation(libs.bundles.test) -} \ No newline at end of file diff --git a/feature-list-streams/.gitignore b/feature-list-streams/.gitignore index 42afabfd..581f8daa 100644 --- a/feature-list-streams/.gitignore +++ b/feature-list-streams/.gitignore @@ -1 +1 @@ -/build \ No newline at end of file +**/build/** \ No newline at end of file diff --git a/feature-list-streams/build.gradle.kts b/feature-list-streams/build.gradle.kts index 7faf9beb..53b2eb8c 100644 --- a/feature-list-streams/build.gradle.kts +++ b/feature-list-streams/build.gradle.kts @@ -1,30 +1,37 @@ @file:Suppress("UnstableApiUsage") plugins { - id("com.streamplayer.android-library") - id("com.streamplayer.compose") - alias(libs.plugins.ksp) + id("com.streamplayer.kmp-library") + alias(libs.plugins.jetbrains.compose) + alias(libs.plugins.compose.compiler) } -dependencies { - implementation(projects.coreNetworking) - implementation(projects.coreNavigation) - implementation(projects.coreShared) - implementation(projects.coreSharedUi) - implementation(projects.coreLocalStorage) +kotlin { + sourceSets { + androidMain.dependencies { + implementation(compose.preview) + } - implementation(libs.bundles.koin) - implementation(libs.koin.annotations) - ksp(libs.koin.compiler) + commonMain.dependencies { + implementation(projects.coreNetworking) + implementation(projects.coreNavigation) + implementation(projects.coreShared) + implementation(projects.coreSharedUi) + implementation(projects.coreLocalStorage) - implementation(libs.bundles.networking) - implementation(libs.roomRuntime) - implementation(libs.bundles.androidSupport) - implementation(libs.coil) + implementation(compose.components.resources) + implementation(compose.material3) + implementation(compose.ui) - testImplementation(libs.bundles.test) -} + implementation(libs.paging.compose) + + implementation(libs.navigation.compose) + + implementation(libs.ktor.client.content.serialization.json) + implementation(libs.ktor.client.content.negotiation) -ksp { - arg("KOIN_CONFIG_CHECK","true") + implementation(libs.koin.compose) + implementation(libs.koin.compose.viewmodel) + } + } } \ No newline at end of file diff --git a/feature-list-streams/consumer-rules.pro b/feature-list-streams/consumer-rules.pro deleted file mode 100644 index e69de29b..00000000 diff --git a/feature-list-streams/proguard-rules.pro b/feature-list-streams/proguard-rules.pro deleted file mode 100644 index 481bb434..00000000 --- a/feature-list-streams/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screen/ListStreamsScreenPreview.kt b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screen/ListStreamsScreenPreview.kt new file mode 100644 index 00000000..0717265b --- /dev/null +++ b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screen/ListStreamsScreenPreview.kt @@ -0,0 +1,12 @@ +package com.codandotv.streamplayerapp.feature_list_streams.list.presentation.screen + +import androidx.compose.runtime.Composable +import androidx.navigation.compose.rememberNavController +import com.codandotv.streamplayerapp.core_shared_ui.theme.ThemePreviews +import com.codandotv.streamplayerapp.feature_list_streams.list.presentation.screens.ListStreamsScreen + +@ThemePreviews +@Composable +fun ListStreamsScreenPreview() { + ListStreamsScreen(navController = rememberNavController(), profilePicture = "") +} diff --git a/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/HighlightBannerPreview.kt b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/HighlightBannerPreview.kt new file mode 100644 index 00000000..b5e899a9 --- /dev/null +++ b/feature-list-streams/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/HighlightBannerPreview.kt @@ -0,0 +1,50 @@ +package com.codandotv.streamplayerapp.feature_list_streams.list.presentation.widgets + +import androidx.compose.runtime.Composable +import com.codandotv.streamplayerapp.core_shared_ui.theme.ThemePreviews +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.IconAndTextInfo +import org.jetbrains.compose.resources.stringResource +import streamplayerapp_kmp.core_shared_ui.generated.resources.Res +import streamplayerapp_kmp.core_shared_ui.generated.resources.app_name +import streamplayerapp_kmp.core_shared_ui.generated.resources.ic_add +import streamplayerapp_kmp.core_shared_ui.generated.resources.ic_info +import streamplayerapp_kmp.core_shared_ui.generated.resources.ic_play +import streamplayerapp_kmp.feature_list_streams.generated.resources.ic_top_10 +import streamplayerapp_kmp.feature_list_streams.generated.resources.list_highlight_banner_add +import streamplayerapp_kmp.feature_list_streams.generated.resources.list_highlight_banner_info +import streamplayerapp_kmp.feature_list_streams.generated.resources.list_highlight_banner_watch + +@ThemePreviews +@Composable +fun HighlightBannerPreview() { + HighlightBanner( + data = com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.HighlightBanner( + name = stringResource(Res.string.app_name), + imageUrl = String(), + contentType = com.codandotv.streamplayerapp.feature_list_streams.core.ContentType.getContentName( + com.codandotv.streamplayerapp.feature_list_streams.core.ContentType.SHOW + ), + contentTypeAsPlural = com.codandotv.streamplayerapp.feature_list_streams.core.ContentType.getContentNameAsPlural( + com.codandotv.streamplayerapp.feature_list_streams.core.ContentType.SHOW + ), + extraInfo = IconAndTextInfo( + streamplayerapp_kmp.feature_list_streams.generated.resources.Res.drawable.ic_top_10, + com.codandotv.streamplayerapp.feature_list_streams.core.ContentType.getContentName( + com.codandotv.streamplayerapp.feature_list_streams.core.ContentType.SHOW + ) + ), + leftButton = IconAndTextInfo( + Res.drawable.ic_add, + streamplayerapp_kmp.feature_list_streams.generated.resources.Res.string.list_highlight_banner_add + ), + centralButton = IconAndTextInfo( + Res.drawable.ic_play, + streamplayerapp_kmp.feature_list_streams.generated.resources.Res.string.list_highlight_banner_watch + ), + rightButton = IconAndTextInfo( + Res.drawable.ic_info, + streamplayerapp_kmp.feature_list_streams.generated.resources.Res.string.list_highlight_banner_info + ), + ) + ) +} diff --git a/feature-list-streams/src/commonMain/composeResources/drawable/ic_top_10.png b/feature-list-streams/src/commonMain/composeResources/drawable/ic_top_10.png new file mode 100644 index 00000000..03b1f3b0 Binary files /dev/null and b/feature-list-streams/src/commonMain/composeResources/drawable/ic_top_10.png differ diff --git a/feature-list-streams/src/main/res/drawable/image_placeholder.xml b/feature-list-streams/src/commonMain/composeResources/drawable/image_placeholder.xml similarity index 100% rename from feature-list-streams/src/main/res/drawable/image_placeholder.xml rename to feature-list-streams/src/commonMain/composeResources/drawable/image_placeholder.xml diff --git a/feature-list-streams/src/main/res/drawable/netflix_horizontal_logo.xml b/feature-list-streams/src/commonMain/composeResources/drawable/netflix_horizontal_logo.xml similarity index 100% rename from feature-list-streams/src/main/res/drawable/netflix_horizontal_logo.xml rename to feature-list-streams/src/commonMain/composeResources/drawable/netflix_horizontal_logo.xml diff --git a/feature-list-streams/src/commonMain/composeResources/values/strings.xml b/feature-list-streams/src/commonMain/composeResources/values/strings.xml new file mode 100644 index 00000000..2211d1eb --- /dev/null +++ b/feature-list-streams/src/commonMain/composeResources/values/strings.xml @@ -0,0 +1,20 @@ + + + + Série + Séries + Filme + Filmes + + Minha lista + Saiba mais + Assistir + Top 1 em %s hoje + + Ícone Reprodução + Ícone adicionar + Ícone informações + Poster de conteúdo em destaque + Ícone top 10 + + \ No newline at end of file diff --git a/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/core/ContentType.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/core/ContentType.kt new file mode 100644 index 00000000..38c98665 --- /dev/null +++ b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/core/ContentType.kt @@ -0,0 +1,21 @@ +package com.codandotv.streamplayerapp.feature_list_streams.core + +import org.jetbrains.compose.resources.StringResource +import streamplayerapp_kmp.feature_list_streams.generated.resources.Res +import streamplayerapp_kmp.feature_list_streams.generated.resources.list_content_type_film +import streamplayerapp_kmp.feature_list_streams.generated.resources.list_content_type_film_plural +import streamplayerapp_kmp.feature_list_streams.generated.resources.list_content_type_show +import streamplayerapp_kmp.feature_list_streams.generated.resources.list_content_type_show_plural + +enum class ContentType(val contentName: StringResource, val contentNameAsPlural: StringResource) { + SHOW(Res.string.list_content_type_show, Res.string.list_content_type_show_plural), + FILM(Res.string.list_content_type_film, Res.string.list_content_type_film_plural); + + companion object { + fun getContentName(contentType: ContentType) = + entries.first { contentType == it }.contentName + + fun getContentNameAsPlural(contentType: ContentType) = + entries.first { contentType == it }.contentNameAsPlural + } +} \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamRepository.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamRepository.kt similarity index 97% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamRepository.kt rename to feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamRepository.kt index 42a14d44..dce60971 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamRepository.kt +++ b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamRepository.kt @@ -10,7 +10,6 @@ import com.codandotv.streamplayerapp.feature_list_streams.list.domain.toGenres import com.codandotv.streamplayerapp.feature_list_streams.list.domain.toStream import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map -import org.koin.core.annotation.Factory interface ListStreamRepository { suspend fun getGenres(): Flow> @@ -20,7 +19,6 @@ interface ListStreamRepository { fun loadMovies(genre: Genre): Flow> } -@Factory class ListStreamRepositoryImpl( private val service: ListStreamService, ) : ListStreamRepository { diff --git a/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamService.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamService.kt new file mode 100644 index 00000000..e2634895 --- /dev/null +++ b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamService.kt @@ -0,0 +1,59 @@ +package com.codandotv.streamplayerapp.feature_list_streams.list.data + +import ListStreamResponse +import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse +import com.codandotv.streamplayerapp.core_networking.handleError.safeRequest +import com.codandotv.streamplayerapp.feature_list_streams.list.data.model.GenresResponse +import io.ktor.client.HttpClient +import io.ktor.client.request.parameter +import io.ktor.client.request.url + +interface ListStreamService { + suspend fun getMovies(genres: String): NetworkResponse + suspend fun getPaginatedMovies(genres: String, page: Int): NetworkResponse + suspend fun getGenres(): NetworkResponse + suspend fun getTopRatedMovies( + sortBy: String = "vote_average.desc", + page: Int = 1 + ): NetworkResponse +} + +class ListStreamServiceImpl( + private val client: HttpClient +) : ListStreamService { + + override suspend fun getMovies(genres: String): NetworkResponse { + return client.safeRequest { + url("discover/movie") + parameter("with_genres", genres) + } + } + + override suspend fun getPaginatedMovies( + genres: String, + page: Int + ): NetworkResponse { + return client.safeRequest { + url("discover/movie") + parameter("with_genres", genres) + parameter("page", page) + } + } + + override suspend fun getGenres(): NetworkResponse { + return client.safeRequest { + url("genre/movie/list") + } + } + + override suspend fun getTopRatedMovies( + sortBy: String, + page: Int + ): NetworkResponse { + return client.safeRequest { + url("discover/movie") + parameter("sort_by", sortBy) + parameter("page", page) + } + } +} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/StreamDataSource.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/StreamDataSource.kt similarity index 100% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/StreamDataSource.kt rename to feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/StreamDataSource.kt diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/GenresResponse.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/GenresResponse.kt similarity index 74% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/GenresResponse.kt rename to feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/GenresResponse.kt index 90f9bed1..3533dcdd 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/GenresResponse.kt +++ b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/GenresResponse.kt @@ -1,10 +1,14 @@ package com.codandotv.streamplayerapp.feature_list_streams.list.data.model +import kotlinx.serialization.Serializable + +@Serializable data class GenreResponse( val id: Long, val name: String ) +@Serializable data class GenresResponse( val genres: List ) \ No newline at end of file diff --git a/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/ListStreamResponse.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/ListStreamResponse.kt new file mode 100644 index 00000000..89574e2c --- /dev/null +++ b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/ListStreamResponse.kt @@ -0,0 +1,14 @@ +import kotlinx.serialization.Serializable + +@Serializable +data class StreamResponse( + val id: Int, + val title: String, + val overview: String, + val poster_path: String? = null +) + +@Serializable +data class ListStreamResponse( + val results: List +) diff --git a/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/di/ListStreamModule.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/di/ListStreamModule.kt new file mode 100644 index 00000000..ffbfb75e --- /dev/null +++ b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/di/ListStreamModule.kt @@ -0,0 +1,63 @@ +package com.codandotv.streamplayerapp.feature_list_streams.list.di + +import com.codandotv.streamplayerapp.feature_list_streams.list.data.ListStreamRepository +import com.codandotv.streamplayerapp.feature_list_streams.list.data.ListStreamRepositoryImpl +import com.codandotv.streamplayerapp.feature_list_streams.list.data.ListStreamService +import com.codandotv.streamplayerapp.feature_list_streams.list.data.ListStreamServiceImpl +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.GetGenresUseCase +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.GetGenresUseCaseImpl +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.GetTopRatedStream +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.GetTopRatedStreamImpl +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.ListStreamAnalytics +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.ListStreamAnalyticsImpl +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.ListStreamUseCase +import com.codandotv.streamplayerapp.feature_list_streams.list.domain.ListStreamUseCaseImpl +import com.codandotv.streamplayerapp.feature_list_streams.list.presentation.screens.ListStreamViewModel +import org.koin.core.module.dsl.viewModel +import org.koin.dsl.module + +object ListStreamModule { + val module = module { + viewModel { + ListStreamViewModel( + listStreams = get(), + listGenres = get(), + latestStream = get() + ) + } + + factory { + ListStreamUseCaseImpl( + repository = get() + ) + } + + factory { + GetGenresUseCaseImpl( + repository = get() + ) + } + + factory { + GetTopRatedStreamImpl( + repository = get() + ) + } + + factory { + ListStreamAnalyticsImpl() + } + + factory { + ListStreamRepositoryImpl( + service = get(), + ) + } + + factory { + ListStreamServiceImpl( + client = get() + ) + } + } +} \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetGenresUseCase.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetGenresUseCase.kt similarity index 92% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetGenresUseCase.kt rename to feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetGenresUseCase.kt index 36b2b4d9..e3da0b8c 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetGenresUseCase.kt +++ b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetGenresUseCase.kt @@ -3,13 +3,11 @@ package com.codandotv.streamplayerapp.feature_list_streams.list.domain import com.codandotv.streamplayerapp.feature_list_streams.list.data.ListStreamRepository import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Genre import kotlinx.coroutines.flow.Flow -import org.koin.core.annotation.Factory interface GetGenresUseCase { suspend operator fun invoke(): Flow> } -@Factory class GetGenresUseCaseImpl( private val repository: ListStreamRepository ) : GetGenresUseCase { diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetLatestMovieUseCase.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetLatestMovieUseCase.kt similarity index 92% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetLatestMovieUseCase.kt rename to feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetLatestMovieUseCase.kt index 7257a40c..a5300816 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetLatestMovieUseCase.kt +++ b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/GetLatestMovieUseCase.kt @@ -3,13 +3,11 @@ package com.codandotv.streamplayerapp.feature_list_streams.list.domain import com.codandotv.streamplayerapp.feature_list_streams.list.data.ListStreamRepository import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Stream import kotlinx.coroutines.flow.Flow -import org.koin.core.annotation.Factory interface GetTopRatedStream { suspend operator fun invoke(): Flow } -@Factory class GetTopRatedStreamImpl( private val repository: ListStreamRepository ) : GetTopRatedStream { diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListMovieUseCase.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListMovieUseCase.kt similarity index 93% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListMovieUseCase.kt rename to feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListMovieUseCase.kt index 367f47be..b4aff62b 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListMovieUseCase.kt +++ b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListMovieUseCase.kt @@ -5,13 +5,11 @@ import com.codandotv.streamplayerapp.feature_list_streams.list.data.ListStreamRe import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Genre import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Stream import kotlinx.coroutines.flow.Flow -import org.koin.core.annotation.Factory interface ListStreamUseCase { operator fun invoke(genre: Genre): Flow> } -@Factory class ListStreamUseCaseImpl( private val repository: ListStreamRepository ) : ListStreamUseCase { diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamAnalytics.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamAnalytics.kt similarity index 75% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamAnalytics.kt rename to feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamAnalytics.kt index e599c1fa..e2fc2866 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamAnalytics.kt +++ b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamAnalytics.kt @@ -1,8 +1,6 @@ package com.codandotv.streamplayerapp.feature_list_streams.list.domain -import org.koin.core.annotation.Factory interface ListStreamAnalytics -@Factory class ListStreamAnalyticsImpl : ListStreamAnalytics \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamMapper.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamMapper.kt similarity index 78% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamMapper.kt rename to feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamMapper.kt index 5e5d86c0..105d61a4 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamMapper.kt +++ b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/ListStreamMapper.kt @@ -1,9 +1,9 @@ package com.codandotv.streamplayerapp.feature_list_streams.list.domain -import com.codandotv.streamplayerapp.core_networking.Url +import ListStreamResponse +import StreamResponse +import com.codandotv.streamplayerapp.core_shared.Url import com.codandotv.streamplayerapp.feature_list_streams.list.data.model.GenresResponse -import com.codandotv.streamplayerapp.feature_list_streams.list.data.model.ListStreamResponse -import com.codandotv.streamplayerapp.feature_list_streams.list.data.model.StreamResponse import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Genre import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.ListStream import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Stream @@ -24,5 +24,5 @@ fun StreamResponse.toStream(): Stream = Stream( description = overview, name = title, posterPathUrl = "${Url.IMAGE_URL_SIZE_300}${poster_path}", - id = id + id = id.toString() ) \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/Genre.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/Genre.kt similarity index 100% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/Genre.kt rename to feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/Genre.kt diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/HighlightBanner.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/HighlightBanner.kt similarity index 51% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/HighlightBanner.kt rename to feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/HighlightBanner.kt index 7bdd369d..75c93595 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/HighlightBanner.kt +++ b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/HighlightBanner.kt @@ -1,24 +1,20 @@ package com.codandotv.streamplayerapp.feature_list_streams.list.domain.model -import android.os.Parcelable -import androidx.annotation.DrawableRes -import androidx.annotation.StringRes -import kotlinx.parcelize.Parcelize +import org.jetbrains.compose.resources.DrawableResource +import org.jetbrains.compose.resources.StringResource -@Parcelize data class HighlightBanner( val name: String, val imageUrl: String, - val contentType: Int, - val contentTypeAsPlural: Int, + val contentType: StringResource, + val contentTypeAsPlural: StringResource, val extraInfo: IconAndTextInfo, val leftButton: IconAndTextInfo, val centralButton: IconAndTextInfo, val rightButton: IconAndTextInfo -) : Parcelable +) -@Parcelize data class IconAndTextInfo( - @DrawableRes val icon: Int, - @StringRes val text: Int -) : Parcelable \ No newline at end of file + val icon: DrawableResource, + val text: StringResource +) \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/ListStream.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/ListStream.kt similarity index 100% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/ListStream.kt rename to feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/domain/model/ListStream.kt diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/navigation/ListStreamsNavigation.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/navigation/ListStreamsNavigation.kt similarity index 72% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/navigation/ListStreamsNavigation.kt rename to feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/navigation/ListStreamsNavigation.kt index ac58e2be..1ed73ef9 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/navigation/ListStreamsNavigation.kt +++ b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/navigation/ListStreamsNavigation.kt @@ -1,7 +1,5 @@ package com.codandotv.streamplayerapp.feature_list_streams.list.presentation.navigation -import androidx.activity.compose.BackHandler -import androidx.lifecycle.Lifecycle import androidx.navigation.NavGraphBuilder import androidx.navigation.NavHostController import androidx.navigation.compose.composable @@ -12,19 +10,22 @@ import com.codandotv.streamplayerapp.core_navigation.routes.Routes.DETAIL import com.codandotv.streamplayerapp.core_navigation.routes.Routes.PROFILE_PICKER import com.codandotv.streamplayerapp.feature_list_streams.list.di.ListStreamModule import com.codandotv.streamplayerapp.feature_list_streams.list.presentation.screens.ListStreamsScreen -import org.koin.core.context.loadKoinModules -import org.koin.core.context.unloadKoinModules -import org.koin.ksp.generated.module +import org.koin.compose.module.rememberKoinModules +import org.koin.core.annotation.KoinExperimentalAPI internal const val DEFAULT_ID = "" +@OptIn(KoinExperimentalAPI::class) fun NavGraphBuilder.listStreamsNavGraph(navController: NavHostController) { composable(HOME_COMPLETE) { nav -> - BackHandler(true) {} - if (nav.lifecycle.currentState == Lifecycle.State.STARTED) { - loadKoinModules(ListStreamModule().module) + // BackHandler(true) {} + + rememberKoinModules { + listOf(ListStreamModule.module) } - ListStreamsScreen(navController = navController, + + ListStreamsScreen( + navController = navController, onNavigateDetailList = { id -> navController.navigate("${DETAIL}${id}") }, @@ -34,9 +35,6 @@ fun NavGraphBuilder.listStreamsNavGraph(navController: NavHostController) { onNavigateSearchScreen = { navController.navigate(Routes.SEARCH) }, - disposable = { - unloadKoinModules(ListStreamModule().module) - }, profilePicture = nav.arguments?.getString(PROFILE_ID) ?: DEFAULT_ID ) } diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamViewModel.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamViewModel.kt similarity index 74% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamViewModel.kt rename to feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamViewModel.kt index f470f26f..0c6ad07f 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamViewModel.kt +++ b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamViewModel.kt @@ -5,7 +5,6 @@ import androidx.lifecycle.viewModelScope import androidx.paging.cachedIn import androidx.paging.map import com.codandotv.streamplayerapp.core_networking.handleError.catchFailure -import com.codandotv.streamplayerapp.feature.list.streams.R import com.codandotv.streamplayerapp.feature_list_streams.core.ContentType import com.codandotv.streamplayerapp.feature_list_streams.list.domain.GetGenresUseCase import com.codandotv.streamplayerapp.feature_list_streams.list.domain.GetTopRatedStream @@ -14,8 +13,8 @@ import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Genr import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.HighlightBanner import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.IconAndTextInfo import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.Stream -import com.codandotv.streamplayerapp.feature_list_streams.list.presentation.widgets.StreamsCardContent -import com.codandotv.streamplayerapp.feature_list_streams.list.presentation.widgets.StreamsCarouselContent +import com.codandotv.streamplayerapp.core_shared_ui.widget.StreamsCardContent +import com.codandotv.streamplayerapp.core_shared_ui.widget.StreamsCarouselContent import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.combine @@ -25,10 +24,17 @@ import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -import org.koin.android.annotation.KoinViewModel -import com.codandotv.streamplayerapp.core.shared.ui.R as SharedUiR +import streamplayerapp_kmp.core_shared_ui.generated.resources.ic_add +import streamplayerapp_kmp.core_shared_ui.generated.resources.ic_info +import streamplayerapp_kmp.core_shared_ui.generated.resources.ic_play +import streamplayerapp_kmp.feature_list_streams.generated.resources.Res +import streamplayerapp_kmp.feature_list_streams.generated.resources.ic_top_10 +import streamplayerapp_kmp.core_shared_ui.generated.resources.Res as SharedRes +import streamplayerapp_kmp.feature_list_streams.generated.resources.list_highlight_banner_add +import streamplayerapp_kmp.feature_list_streams.generated.resources.list_highlight_banner_info +import streamplayerapp_kmp.feature_list_streams.generated.resources.list_highlight_banner_stream_ranking +import streamplayerapp_kmp.feature_list_streams.generated.resources.list_highlight_banner_watch -@KoinViewModel class ListStreamViewModel( private val listStreams: ListStreamUseCase, private val listGenres: GetGenresUseCase, @@ -64,7 +70,6 @@ class ListStreamViewModel( } .collect { pair -> val (latest, genres) = pair - _uiState.update { it.copy( streamsCarouselContent = genres.map { genreTarget -> @@ -84,23 +89,24 @@ class ListStreamViewModel( contentType = ContentType.getContentName(ContentType.FILM), contentTypeAsPlural = ContentType.getContentNameAsPlural(ContentType.FILM), extraInfo = IconAndTextInfo( - R.drawable.ic_top_10, - R.string.list_highlight_banner_stream_ranking + Res.drawable.ic_top_10, + Res.string.list_highlight_banner_stream_ranking ), leftButton = IconAndTextInfo( - SharedUiR.drawable.ic_add, - R.string.list_highlight_banner_add + SharedRes.drawable.ic_add, + Res.string.list_highlight_banner_add ), centralButton = IconAndTextInfo( - SharedUiR.drawable.ic_play, - R.string.list_highlight_banner_watch + SharedRes.drawable.ic_play, + Res.string.list_highlight_banner_watch ), rightButton = IconAndTextInfo( - SharedUiR.drawable.ic_info, - R.string.list_highlight_banner_info + SharedRes.drawable.ic_info, + Res.string.list_highlight_banner_info ), ) + private fun getStreamsByGenre(genre: Genre): StreamsCarouselContent { return StreamsCarouselContent( genre.name, diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsScreen.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsScreen.kt similarity index 79% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsScreen.kt rename to feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsScreen.kt index 345d078b..c8691035 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsScreen.kt +++ b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsScreen.kt @@ -1,6 +1,5 @@ package com.codandotv.streamplayerapp.feature_list_streams.list.presentation.screens -import android.annotation.SuppressLint import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -17,25 +16,20 @@ import androidx.compose.material3.Scaffold import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.rememberTopAppBarState import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.input.nestedscroll.nestedScroll -import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.unit.dp -import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavController -import androidx.navigation.compose.rememberNavController import com.codandotv.streamplayerapp.core_navigation.bottomnavigation.StreamPlayerBottomNavigation -import com.codandotv.streamplayerapp.core_shared_ui.theme.ThemePreviews import com.codandotv.streamplayerapp.core_shared_ui.widget.StreamPlayerTopBar import com.codandotv.streamplayerapp.feature_list_streams.list.presentation.widgets.HighlightBanner -import com.codandotv.streamplayerapp.feature_list_streams.list.presentation.widgets.StreamsCarousel -import org.koin.androidx.compose.koinViewModel +import com.codandotv.streamplayerapp.core_shared_ui.widget.StreamsCarousel +import org.koin.compose.viewmodel.koinViewModel @Suppress("LongParameterList") -@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter") @OptIn(ExperimentalMaterial3Api::class) @Composable fun ListStreamsScreen( @@ -44,21 +38,13 @@ fun ListStreamsScreen( onNavigateDetailList: (String) -> Unit = {}, onNavigateProfilePicker: () -> Unit = {}, onNavigateSearchScreen: () -> Unit = {}, - disposable: () -> Unit = {}, profilePicture: String ) { - val uiState by viewModel.uiState.collectAsStateWithLifecycle() - val lifecycleOwner = LocalLifecycleOwner.current + val uiState by viewModel.uiState.collectAsState() val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(rememberTopAppBarState()) val baseScrollState = rememberScrollState() - DisposableEffect(lifecycleOwner) { - onDispose { - disposable.invoke() - } - } - Scaffold( modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), topBar = { @@ -108,8 +94,3 @@ fun ListStreamsScreen( } } -@ThemePreviews -@Composable -fun ListStreamsScreenPreview() { - ListStreamsScreen(navController = rememberNavController(), profilePicture = "") -} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsUIState.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsUIState.kt similarity index 76% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsUIState.kt rename to feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsUIState.kt index fba66712..5260d36c 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsUIState.kt +++ b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/screens/ListStreamsUIState.kt @@ -1,7 +1,7 @@ package com.codandotv.streamplayerapp.feature_list_streams.list.presentation.screens import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.HighlightBanner -import com.codandotv.streamplayerapp.feature_list_streams.list.presentation.widgets.StreamsCarouselContent +import com.codandotv.streamplayerapp.core_shared_ui.widget.StreamsCarouselContent data class ListStreamsUIState( val highlightBanner: HighlightBanner? = null, diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/HighlightBanner.kt b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/HighlightBanner.kt similarity index 71% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/HighlightBanner.kt rename to feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/HighlightBanner.kt index bbeb30ec..8b411424 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/HighlightBanner.kt +++ b/feature-list-streams/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_list_streams/list/presentation/widgets/HighlightBanner.kt @@ -1,6 +1,5 @@ package com.codandotv.streamplayerapp.feature_list_streams.list.presentation.widgets -import androidx.annotation.StringRes import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -27,20 +26,30 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import coil.compose.AsyncImage -import com.codandotv.streamplayerapp.core_shared_ui.theme.ThemePreviews -import com.codandotv.streamplayerapp.feature.list.streams.R -import com.codandotv.streamplayerapp.feature_list_streams.core.ContentType +import com.codandotv.streamplayerapp.core_shared_ui.widget.WebImage import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.HighlightBanner import com.codandotv.streamplayerapp.feature_list_streams.list.domain.model.IconAndTextInfo -import com.codandotv.streamplayerapp.core.shared.ui.R as RSharedUI +import org.jetbrains.compose.resources.StringResource +import org.jetbrains.compose.resources.painterResource +import org.jetbrains.compose.resources.stringResource +import streamplayerapp_kmp.core_shared_ui.generated.resources.ic_add +import streamplayerapp_kmp.core_shared_ui.generated.resources.ic_info +import streamplayerapp_kmp.core_shared_ui.generated.resources.ic_netflix +import streamplayerapp_kmp.core_shared_ui.generated.resources.ic_play +import streamplayerapp_kmp.core_shared_ui.generated.resources.icon_netflix +import streamplayerapp_kmp.feature_list_streams.generated.resources.Res +import streamplayerapp_kmp.feature_list_streams.generated.resources.list_highligh_banner_content +import streamplayerapp_kmp.feature_list_streams.generated.resources.list_highlight_banner_watch +import streamplayerapp_kmp.feature_list_streams.generated.resources.list_icon_add +import streamplayerapp_kmp.feature_list_streams.generated.resources.list_icon_highligh_banner_ranking +import streamplayerapp_kmp.feature_list_streams.generated.resources.list_icon_info +import streamplayerapp_kmp.feature_list_streams.generated.resources.list_icon_play +import streamplayerapp_kmp.core_shared_ui.generated.resources.Res as SharedRes @Suppress("MagicNumber") @Composable @@ -74,11 +83,11 @@ fun HighlightBanner(modifier: Modifier = Modifier, data: HighlightBanner?) { @Composable fun ContentImage(modifier: Modifier = Modifier, imageUrl: String) { - AsyncImage( + WebImage( modifier = modifier.fillMaxSize(), - model = imageUrl, + imageUrl = imageUrl, contentScale = ContentScale.Crop, - contentDescription = stringResource(id = R.string.list_highligh_banner_content) + contentDescription = stringResource(Res.string.list_highligh_banner_content) ) } @@ -115,20 +124,17 @@ fun ContentName(modifier: Modifier = Modifier, name: String) { fun ContentRanking( modifier: Modifier = Modifier, extraInfo: IconAndTextInfo, - @StringRes contentTypeAsPlural: Int + contentTypeAsPlural: StringResource ) { Row(modifier = modifier, verticalAlignment = Alignment.CenterVertically) { Icon( - painter = painterResource(id = extraInfo.icon), - contentDescription = stringResource(id = R.string.list_icon_highligh_banner_ranking), + painter = painterResource(extraInfo.icon), + contentDescription = stringResource(Res.string.list_icon_highligh_banner_ranking), modifier = Modifier.size(24.dp), tint = Color.Unspecified ) Text( - text = stringResource( - id = extraInfo.text, - stringResource(contentTypeAsPlural).lowercase() - ), + text = stringResource(contentTypeAsPlural).lowercase(), Modifier.padding(start = 4.dp), style = TextStyle(fontWeight = FontWeight.Bold), fontSize = 14.sp, @@ -138,11 +144,11 @@ fun ContentRanking( } @Composable -fun ContentType(modifier: Modifier = Modifier, @StringRes contentType: Int) { +fun ContentType(modifier: Modifier = Modifier, contentType: StringResource) { Row(modifier = modifier, verticalAlignment = Alignment.CenterVertically) { Icon( - painter = painterResource(id = RSharedUI.drawable.ic_netflix), - contentDescription = stringResource(id = RSharedUI.string.icon_netflix), + painter = painterResource(SharedRes.drawable.ic_netflix), + contentDescription = stringResource(SharedRes.string.icon_netflix), modifier = Modifier.size(16.dp), tint = Color.Unspecified ) @@ -189,13 +195,13 @@ fun AddToListButton( IconButton(onClick = { onClick.invoke() }, modifier = modifier) { Column(horizontalAlignment = Alignment.CenterHorizontally) { Icon( - painter = painterResource(id = RSharedUI.drawable.ic_add), - contentDescription = stringResource(id = R.string.list_icon_add), + painter = painterResource(SharedRes.drawable.ic_add), + contentDescription = stringResource(Res.string.list_icon_add), tint = Color.White, ) Text( fontSize = 10.sp, - text = stringResource(id = data.leftButton.text), + text = stringResource(data.leftButton.text), color = Color.White, ) } @@ -211,12 +217,12 @@ fun InfoButton( IconButton(onClick = { onClick.invoke() }, modifier = modifier) { Column(horizontalAlignment = Alignment.CenterHorizontally) { Icon( - painter = painterResource(id = RSharedUI.drawable.ic_info), - contentDescription = stringResource(id = R.string.list_icon_info), + painter = painterResource(SharedRes.drawable.ic_info), + contentDescription = stringResource(Res.string.list_icon_info), tint = Color.White ) Text( - text = stringResource(id = data.rightButton.text), + text = stringResource(data.rightButton.text), fontSize = 10.sp, color = Color.White ) @@ -242,14 +248,14 @@ fun PlayButton( ) ) { Icon( - painter = painterResource(RSharedUI.drawable.ic_play), - contentDescription = stringResource(id = R.string.list_icon_play), + painter = painterResource(SharedRes.drawable.ic_play), + contentDescription = stringResource(Res.string.list_icon_play), tint = Color.Black, modifier = Modifier.padding(vertical = 8.dp) ) Spacer(modifier = Modifier.width(4.dp)) Text( - text = stringResource(id = R.string.list_highlight_banner_watch), + text = stringResource(Res.string.list_highlight_banner_watch), color = Color.Black, fontSize = 14.sp, modifier = Modifier @@ -258,23 +264,3 @@ fun PlayButton( ) } } - -@ThemePreviews -@Composable -fun HighlightBannerPreview() { - HighlightBanner( - data = HighlightBanner( - name = stringResource(id = RSharedUI.string.app_name), - imageUrl = String(), - contentType = ContentType.getContentName(ContentType.SHOW), - contentTypeAsPlural = ContentType.getContentNameAsPlural(ContentType.SHOW), - extraInfo = IconAndTextInfo( - R.drawable.ic_top_10, - ContentType.getContentName(ContentType.SHOW) - ), - leftButton = IconAndTextInfo(RSharedUI.drawable.ic_add, R.string.list_highlight_banner_add), - centralButton = IconAndTextInfo(RSharedUI.drawable.ic_play, R.string.list_highlight_banner_watch), - rightButton = IconAndTextInfo(RSharedUI.drawable.ic_info, R.string.list_highlight_banner_info), - ) - ) -} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/core/ContentType.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/core/ContentType.kt deleted file mode 100644 index eef6a23b..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/core/ContentType.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.core - -import androidx.annotation.StringRes -import com.codandotv.streamplayerapp.feature.list.streams.R - -enum class ContentType(@StringRes val contentName: Int, @StringRes val contentNameAsPlural: Int) { - SHOW(R.string.list_content_type_show, R.string.list_content_type_show_plural), - FILM(R.string.list_content_type_film, R.string.list_content_type_film_plural); - - companion object { - fun getContentName(contentType: ContentType) = - values().first { contentType == it }.contentName - - fun getContentNameAsPlural(contentType: ContentType) = - values().first { contentType == it }.contentNameAsPlural - } -} \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/DetailStreamService.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/DetailStreamService.kt deleted file mode 100644 index d61f86a4..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/detail/data/DetailStreamService.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.detail.data - -import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse -import com.codandotv.streamplayerapp.feature_list_streams.detail.data.model.DetailStreamResponse -import com.codandotv.streamplayerapp.feature_list_streams.detail.data.model.VideoStreamsResponse -import retrofit2.http.GET -import retrofit2.http.Path - -interface DetailStreamService { - @GET("movie/{movie_id}") - suspend fun getMovie(@Path("movie_id") movieId: String): NetworkResponse - - @GET("movie/{movie_id}/videos") - suspend fun getVideoStreams(@Path("movie_id") movieId: String): NetworkResponse -} \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamService.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamService.kt deleted file mode 100644 index d702c49e..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/ListStreamService.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.list.data - -import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse -import com.codandotv.streamplayerapp.feature_list_streams.list.data.model.GenresResponse -import com.codandotv.streamplayerapp.feature_list_streams.list.data.model.ListStreamResponse -import com.codandotv.streamplayerapp.feature_list_streams.list.data.model.StreamResponse -import retrofit2.http.GET -import retrofit2.http.Query - -interface ListStreamService { - @GET("discover/movie") - suspend fun getMovies(@Query("with_genres") genres: String) : NetworkResponse - - @GET("discover/movie") - suspend fun getPaginatedMovies( - @Query("with_genres") genres: String, - @Query("page") page: Int - ) : NetworkResponse - - @GET("genre/movie/list") - suspend fun getGenres(): NetworkResponse - - @GET("discover/movie") - suspend fun getTopRatedMovies( - @Query("sort_by") sortBy: String = "vote_average.desc", - @Query("page") page: Int = 1 - ): NetworkResponse -} \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/ListStreamResponse.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/ListStreamResponse.kt deleted file mode 100644 index 0cd75ada..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/data/model/ListStreamResponse.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.list.data.model - -@Suppress("ConstructorParameterNaming") -data class StreamResponse( - val id : String, - val title : String, - val overview : String, - val poster_path: String? = null, -) -data class ListStreamResponse( - val results: List -) \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/di/ListStreamModule.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/di/ListStreamModule.kt deleted file mode 100644 index 9a4ea1ac..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/list/di/ListStreamModule.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.list.di - -import com.codandotv.streamplayerapp.feature_list_streams.list.data.ListStreamService -import org.koin.core.annotation.ComponentScan -import org.koin.core.annotation.Factory -import org.koin.core.annotation.Module -import org.koin.core.context.GlobalContext -import retrofit2.Retrofit - -@Module -@ComponentScan("com.codandotv.streamplayerapp.feature_list_streams.list") -class ListStreamModule { - - @Factory - fun service(): ListStreamService { - val koin = GlobalContext.get() - val retrofit = koin.get() - return retrofit.create(ListStreamService::class.java) - } -} \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/api/MostPopularMoviesService.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/api/MostPopularMoviesService.kt deleted file mode 100644 index a2d6e452..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/api/MostPopularMoviesService.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.data.api - -import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse -import com.codandotv.streamplayerapp.feature_list_streams.search.data.model.ListSearchStreamResponse -import retrofit2.http.GET - -interface MostPopularMoviesService { - @GET("movie/popular") - suspend fun getPopular(): NetworkResponse -} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/api/SearchStreamService.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/api/SearchStreamService.kt deleted file mode 100644 index c9d43b1d..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/api/SearchStreamService.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.data.api - -import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse -import com.codandotv.streamplayerapp.feature_list_streams.search.data.model.ListSearchStreamResponse -import retrofit2.http.GET -import retrofit2.http.Query - -interface SearchStreamService { - @GET("search/movie") - suspend fun getSearch(@Query("query") query: String) : NetworkResponse -} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/model/ListSearchStreamResponse.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/model/ListSearchStreamResponse.kt deleted file mode 100644 index d15bdc21..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/model/ListSearchStreamResponse.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.data.model - -import com.squareup.moshi.Json - -data class ListSearchStreamResponse( - @Json(name = "results") - val results: List -) { - data class SearchStreamResponse( - @Json(name = "id") - val id: String, - @Json(name = "title") - val title: String, - @Json(name="overview") - val overview: String, - @Json(name = "poster_path") - val posterPath: String, - ) -} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/di/SearchModule.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/di/SearchModule.kt deleted file mode 100644 index 44025733..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/di/SearchModule.kt +++ /dev/null @@ -1,42 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.di - -import com.codandotv.streamplayerapp.feature_list_streams.search.data.api.SearchStreamService -import com.codandotv.streamplayerapp.feature_list_streams.search.data.datasource.SearchStreamDataSourceImpl -import com.codandotv.streamplayerapp.feature_list_streams.search.data.datasource.MostPopularMoviesDataSource -import com.codandotv.streamplayerapp.feature_list_streams.search.data.datasource.MostPopularMoviesDataSourceImpl -import com.codandotv.streamplayerapp.feature_list_streams.search.data.repository.MostPopularMoviesRepository -import com.codandotv.streamplayerapp.feature_list_streams.search.data.repository.MostPopularMoviesRepositoryImpl -import com.codandotv.streamplayerapp.feature_list_streams.search.data.api.MostPopularMoviesService -import com.codandotv.streamplayerapp.feature_list_streams.search.data.datasource.SearchStreamDataSource -import com.codandotv.streamplayerapp.feature_list_streams.search.data.repository.SearchStreamRepository -import com.codandotv.streamplayerapp.feature_list_streams.search.data.repository.SearchStreamRepositoryImp -import com.codandotv.streamplayerapp.feature_list_streams.search.domain.MostPopularMoviesUseCase -import com.codandotv.streamplayerapp.feature_list_streams.search.domain.MostPopularMoviesUseCaseImpl -import com.codandotv.streamplayerapp.feature_list_streams.search.domain.SearchUseCase -import com.codandotv.streamplayerapp.feature_list_streams.search.domain.SearchUseCaseImpl -import com.codandotv.streamplayerapp.feature_list_streams.search.presentation.screens.SearchViewModel -import org.koin.androidx.viewmodel.dsl.viewModel -import org.koin.dsl.module -import retrofit2.Retrofit - -object SearchModule { - val module = module { - viewModel { - SearchViewModel( - searchUseCase = get(), - mostPopularMoviesUseCase = get() - ) - } - - factory { get().create(SearchStreamService::class.java) } - factory { get().create(MostPopularMoviesService::class.java) } - - factory { MostPopularMoviesUseCaseImpl(repository = get()) } - factory { MostPopularMoviesDataSourceImpl(service = get()) } - factory { MostPopularMoviesRepositoryImpl(dataSource = get()) } - - factory { SearchUseCaseImpl(repository = get()) } - factory { SearchStreamDataSourceImpl(service = get()) } - factory { SearchStreamRepositoryImp(dataSource = get()) } - } -} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/domain/mapper/SearchMapper.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/domain/mapper/SearchMapper.kt deleted file mode 100644 index 2817a44b..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/domain/mapper/SearchMapper.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.domain.mapper - -import com.codandotv.streamplayerapp.core_networking.Url -import com.codandotv.streamplayerapp.feature_list_streams.search.data.model.ListSearchStreamResponse.SearchStreamResponse -import com.codandotv.streamplayerapp.feature_list_streams.search.presentation.widgets.SearchStreamCardModel - -fun SearchStreamResponse.toSearchStreamCardModel() = SearchStreamCardModel( - id = id, - title = title, - url = "${Url.IMAGE_URL_SIZE_200}${posterPath}" -) diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/navigation/SearchStreamNavigation.kt b/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/navigation/SearchStreamNavigation.kt deleted file mode 100644 index adcec747..00000000 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/navigation/SearchStreamNavigation.kt +++ /dev/null @@ -1,30 +0,0 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.presentation.navigation - -import androidx.activity.compose.BackHandler -import androidx.lifecycle.Lifecycle -import androidx.navigation.NavGraphBuilder -import androidx.navigation.NavHostController -import androidx.navigation.compose.composable -import com.codandotv.streamplayerapp.core_navigation.routes.Routes -import com.codandotv.streamplayerapp.feature_list_streams.search.di.SearchModule -import com.codandotv.streamplayerapp.feature_list_streams.search.presentation.screens.SearchScreen -import org.koin.core.context.loadKoinModules -import org.koin.core.context.unloadKoinModules - -fun NavGraphBuilder.searchStreamsNavGraph(navController: NavHostController) { - composable(Routes.SEARCH) { nav -> - BackHandler(true) {} - if (nav.lifecycle.currentState == Lifecycle.State.STARTED) { - loadKoinModules(SearchModule.module) - } - SearchScreen( - navController = navController, - onNavigateDetailList = { id -> - navController.navigate("${Routes.DETAIL}${id}") - }, - disposable = { - unloadKoinModules(SearchModule.module) - } - ) - } -} diff --git a/feature-list-streams/src/main/res/drawable/ic_top_10.webp b/feature-list-streams/src/main/res/drawable/ic_top_10.webp deleted file mode 100644 index e165119d..00000000 Binary files a/feature-list-streams/src/main/res/drawable/ic_top_10.webp and /dev/null differ diff --git a/feature-list-streams/src/main/res/layout/activity_list_stream.xml b/feature-list-streams/src/main/res/layout/activity_list_stream.xml deleted file mode 100644 index 5377cc83..00000000 --- a/feature-list-streams/src/main/res/layout/activity_list_stream.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/feature-list-streams/src/main/res/values/content-description.xml b/feature-list-streams/src/main/res/values/content-description.xml deleted file mode 100644 index 99cae6c4..00000000 --- a/feature-list-streams/src/main/res/values/content-description.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - Ícone Reprodução - Ícone adicionar - Ícone informações - Poster de conteúdo em destaque - Ícone top 10 - \ No newline at end of file diff --git a/feature-list-streams/src/main/res/values/strings.xml b/feature-list-streams/src/main/res/values/strings.xml deleted file mode 100644 index beceb11d..00000000 --- a/feature-list-streams/src/main/res/values/strings.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - Assistir - Baixar E1 - Filme - Minha Lista - Classificar - Compartilhar - Baixar completo - Pesquisar - Voltar - - - Série - Séries - Filme - Filmes - - Minha lista - Saiba mais - Assistir - Top 1 em %s hoje - - - - Principais buscas - Principais buscas - - - Houve um problema ao conectar à Netflix. Tente novamente mais tarde. - Tente novamente - Conteúdo não encontrado - - \ No newline at end of file diff --git a/feature-profile/build.gradle.kts b/feature-profile/build.gradle.kts index 4695d8f9..c6695c53 100644 --- a/feature-profile/build.gradle.kts +++ b/feature-profile/build.gradle.kts @@ -1,28 +1,31 @@ @file:Suppress("UnstableApiUsage") plugins { - id("com.streamplayer.android-library") - id("com.streamplayer.compose") - alias(libs.plugins.ksp) + id("com.streamplayer.kmp-library") + alias(libs.plugins.jetbrains.compose) + alias(libs.plugins.compose.compiler) } -dependencies { - implementation(projects.coreNetworking) - implementation(projects.coreNavigation) - implementation(projects.coreShared) - implementation(projects.coreSharedUi) +kotlin { + sourceSets { + commonMain.dependencies { + implementation(projects.coreNetworking) + implementation(projects.coreNavigation) + implementation(projects.coreShared) + implementation(projects.coreSharedUi) - implementation(libs.bundles.koin) - implementation(libs.koin.annotations) - ksp(libs.koin.compiler) + implementation(libs.navigation.compose) - implementation(libs.bundles.networking) - implementation(libs.bundles.androidSupport) - implementation(libs.coil) + implementation(compose.material3) + implementation(compose.ui) + implementation(compose.components.resources) - testImplementation(libs.bundles.test) -} + implementation(libs.ktor.client.content.serialization.json) + implementation(libs.ktor.client.content.negotiation) -ksp { - arg("KOIN_CONFIG_CHECK","true") -} + implementation(libs.koin.core) + implementation(libs.koin.compose) + implementation(libs.koin.compose.viewmodel) + } + } +} \ No newline at end of file diff --git a/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamToolbarPreview.kt b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamToolbarPreview.kt new file mode 100644 index 00000000..f26eac1c --- /dev/null +++ b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamToolbarPreview.kt @@ -0,0 +1,14 @@ +package com.codandotv.streamplayerapp.profile.presentation.screens + +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import com.codandotv.streamplayerapp.core_shared_ui.theme.ThemePreviews +import com.codandotv.streamplayerapp.profile.presentation.widget.ProfilePickerStreamToolbar + +@ThemePreviews +@Composable +fun ProfilePickerStreamToolbarPreview() { + MaterialTheme { + ProfilePickerStreamToolbar() + } +} \ No newline at end of file diff --git a/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/SetupProfilePickerScreenPreview.kt b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/SetupProfilePickerScreenPreview.kt new file mode 100644 index 00000000..363bd326 --- /dev/null +++ b/feature-profile/src/androidMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/SetupProfilePickerScreenPreview.kt @@ -0,0 +1,18 @@ +package com.codandotv.streamplayerapp.profile.presentation.screens + +import androidx.compose.runtime.Composable +import com.codandotv.streamplayerapp.core_shared_ui.theme.ThemePreview +import com.codandotv.streamplayerapp.core_shared_ui.theme.ThemePreviews +import com.codandotv.streamplayerapp.profile.domain.ProfileStream + +@ThemePreviews +@Composable +fun SetupProfilePickerScreenPreview() { + ThemePreview { + SetupProfilePickerScreen( + uiState = ProfilePickerStreamsUIState( + selectedItem = ProfileStream("1", "Name", ""), + ) + ) + } +} \ No newline at end of file diff --git a/feature-profile/src/main/res/drawable/image_placeholder.xml b/feature-profile/src/commonMain/composeResources/drawable/image_placeholder.xml similarity index 100% rename from feature-profile/src/main/res/drawable/image_placeholder.xml rename to feature-profile/src/commonMain/composeResources/drawable/image_placeholder.xml diff --git a/feature-profile/src/main/res/drawable/netflix_horizontal_logo.xml b/feature-profile/src/commonMain/composeResources/drawable/netflix_horizontal_logo.xml similarity index 100% rename from feature-profile/src/main/res/drawable/netflix_horizontal_logo.xml rename to feature-profile/src/commonMain/composeResources/drawable/netflix_horizontal_logo.xml diff --git a/feature-profile/src/main/res/values/strings.xml b/feature-profile/src/commonMain/composeResources/values/strings.xml similarity index 100% rename from feature-profile/src/main/res/values/strings.xml rename to feature-profile/src/commonMain/composeResources/values/strings.xml diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/data/ProfilePickerStreamRepository.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/data/ProfilePickerStreamRepository.kt similarity index 84% rename from feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/data/ProfilePickerStreamRepository.kt rename to feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/data/ProfilePickerStreamRepository.kt index 7fdba887..793670c5 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/data/ProfilePickerStreamRepository.kt +++ b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/data/ProfilePickerStreamRepository.kt @@ -1,20 +1,17 @@ -package com.codandotv.streamplayerapp.feature_profile.profile.data +package com.codandotv.streamplayerapp.profile.data -import android.util.Log import com.codandotv.streamplayerapp.core_networking.handleError.toFlow import com.codandotv.streamplayerapp.core_networking.handleError.toResult -import com.codandotv.streamplayerapp.feature_profile.profile.domain.ProfileStream -import com.codandotv.streamplayerapp.feature_profile.profile.domain.toProfiles +import com.codandotv.streamplayerapp.profile.domain.ProfileStream +import com.codandotv.streamplayerapp.profile.domain.toProfiles import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map -import org.koin.core.annotation.Factory interface ProfilePickerStreamRepository { suspend fun getProfiles(): Flow> } -@Factory class ProfilePickerStreamRepositoryImpl( private val service: ProfilePickerStreamService ) : ProfilePickerStreamRepository { @@ -23,7 +20,7 @@ class ProfilePickerStreamRepositoryImpl( with(service.getProfiles()) { if (this.toResult().isFailure || this.toResult().getOrNull() == null) { - Log.i("ProfilePickerStreamRepositoryImpl", "versão off carregada") + // Log.i("ProfilePickerStreamRepositoryImpl", "versão off carregada") return flowOf(mockProfiles) } else { return this.toFlow().map { it.toProfiles() } diff --git a/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/data/ProfilePickerStreamService.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/data/ProfilePickerStreamService.kt new file mode 100644 index 00000000..e071ddf2 --- /dev/null +++ b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/data/ProfilePickerStreamService.kt @@ -0,0 +1,20 @@ +package com.codandotv.streamplayerapp.profile.data + +import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse +import com.codandotv.streamplayerapp.core_networking.handleError.safeRequest +import com.codandotv.streamplayerapp.profile.data.model.ProfilesResponse +import io.ktor.client.HttpClient +import io.ktor.client.request.url + +interface ProfilePickerStreamService { + suspend fun getProfiles(): NetworkResponse +} + +class ProfilePickerStreamServiceImpl( + private val client: HttpClient +) : ProfilePickerStreamService { + override suspend fun getProfiles(): NetworkResponse = + client.safeRequest { + url("profiles") + } +} diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/data/model/ProfileStreamResponse.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/data/model/ProfileStreamResponse.kt similarity index 63% rename from feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/data/model/ProfileStreamResponse.kt rename to feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/data/model/ProfileStreamResponse.kt index b8534939..afac8e93 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/data/model/ProfileStreamResponse.kt +++ b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/data/model/ProfileStreamResponse.kt @@ -1,5 +1,8 @@ -package com.codandotv.streamplayerapp.feature_profile.profile.data.model +package com.codandotv.streamplayerapp.profile.data.model +import kotlinx.serialization.Serializable + +@Serializable @Suppress("ConstructorParameterNaming") data class ProfileStreamResponse( val id: String, @@ -7,6 +10,7 @@ data class ProfileStreamResponse( val profile_url: String, ) +@Serializable data class ProfilesResponse( val profiles: List ) \ No newline at end of file diff --git a/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/di/ProfilePickerStreamModule.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/di/ProfilePickerStreamModule.kt new file mode 100644 index 00000000..127e6887 --- /dev/null +++ b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/di/ProfilePickerStreamModule.kt @@ -0,0 +1,39 @@ +package com.codandotv.streamplayerapp.profile.di + +import com.codandotv.streamplayerapp.profile.data.ProfilePickerStreamRepository +import com.codandotv.streamplayerapp.profile.data.ProfilePickerStreamRepositoryImpl +import com.codandotv.streamplayerapp.profile.data.ProfilePickerStreamService +import com.codandotv.streamplayerapp.profile.data.ProfilePickerStreamServiceImpl +import com.codandotv.streamplayerapp.profile.domain.ProfilePickerStreamUseCase +import com.codandotv.streamplayerapp.profile.domain.ProfilePickerStreamUseCaseImpl +import com.codandotv.streamplayerapp.profile.presentation.screens.ProfilePickerStreamViewModel +import org.koin.core.module.dsl.viewModel +import org.koin.dsl.module + +object ProfilePickerStreamModule { + val module = module { + viewModel { + ProfilePickerStreamViewModel( + useCase = get() + ) + } + + factory { + ProfilePickerStreamUseCaseImpl( + profilePickerStreamRepository = get() + ) + } + + factory { + ProfilePickerStreamRepositoryImpl( + service = get() + ) + } + + factory { + ProfilePickerStreamServiceImpl( + client = get() + ) + } + } +} \ No newline at end of file diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/domain/ProfilePickerStreamMapper.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfilePickerStreamMapper.kt similarity index 60% rename from feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/domain/ProfilePickerStreamMapper.kt rename to feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfilePickerStreamMapper.kt index 6d5ce0ac..ff732549 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/domain/ProfilePickerStreamMapper.kt +++ b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfilePickerStreamMapper.kt @@ -1,6 +1,6 @@ -package com.codandotv.streamplayerapp.feature_profile.profile.domain +package com.codandotv.streamplayerapp.profile.domain -import com.codandotv.streamplayerapp.feature_profile.profile.data.model.ProfilesResponse +import com.codandotv.streamplayerapp.profile.data.model.ProfilesResponse fun ProfilesResponse.toProfiles(): List = this.profiles.map { profileResponse -> ProfileStream( diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/domain/ProfilePickerStreamUseCase.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfilePickerStreamUseCase.kt similarity index 91% rename from feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/domain/ProfilePickerStreamUseCase.kt rename to feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfilePickerStreamUseCase.kt index 225a15be..abf1a4a6 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/domain/ProfilePickerStreamUseCase.kt +++ b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfilePickerStreamUseCase.kt @@ -1,9 +1,8 @@ @file:Suppress("MagicNumber") -package com.codandotv.streamplayerapp.feature_profile.profile.domain +package com.codandotv.streamplayerapp.profile.domain -import com.codandotv.streamplayerapp.feature_profile.profile.data.ProfilePickerStreamRepository +import com.codandotv.streamplayerapp.profile.data.ProfilePickerStreamRepository import kotlinx.coroutines.flow.Flow -import org.koin.core.annotation.Factory interface ProfilePickerStreamUseCase { suspend fun getProfile(): Flow> @@ -22,7 +21,6 @@ interface ProfilePickerStreamUseCase { ): Pair } -@Factory class ProfilePickerStreamUseCaseImpl( private val profilePickerStreamRepository: ProfilePickerStreamRepository ) : ProfilePickerStreamUseCase { diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/domain/ProfileStream.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfileStream.kt similarity index 57% rename from feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/domain/ProfileStream.kt rename to feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfileStream.kt index 7c365999..5440084a 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/domain/ProfileStream.kt +++ b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/domain/ProfileStream.kt @@ -1,4 +1,4 @@ -package com.codandotv.streamplayerapp.feature_profile.profile.domain +package com.codandotv.streamplayerapp.profile.domain data class ProfileStream( val id: String, diff --git a/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/navigation/ProfilePickerStreamNavigation.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/navigation/ProfilePickerStreamNavigation.kt new file mode 100644 index 00000000..eb885448 --- /dev/null +++ b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/navigation/ProfilePickerStreamNavigation.kt @@ -0,0 +1,26 @@ +package com.codandotv.streamplayerapp.profile.presentation.navigation + +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavHostController +import androidx.navigation.compose.composable +import com.codandotv.streamplayerapp.core_navigation.routes.BottomNavRoutes.HOME +import com.codandotv.streamplayerapp.core_navigation.routes.BottomNavRoutes.PARAM.PROFILE_ID +import com.codandotv.streamplayerapp.core_navigation.routes.Routes +import com.codandotv.streamplayerapp.profile.di.ProfilePickerStreamModule +import com.codandotv.streamplayerapp.profile.presentation.screens.ProfilePickerStreamScreen +import org.koin.compose.module.rememberKoinModules +import org.koin.core.annotation.KoinExperimentalAPI + +@OptIn(KoinExperimentalAPI::class) +fun NavGraphBuilder.profilePickerStreamNavGraph(navController: NavHostController) { + composable(Routes.PROFILE_PICKER) { + rememberKoinModules { + listOf(ProfilePickerStreamModule.module) + } + ProfilePickerStreamScreen( + onNavigateListStreams = { profilePic -> + navController.navigate("$HOME?$PROFILE_ID=$profilePic") + } + ) + } +} diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/screens/ProfilePickerStreamScreen.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamScreen.kt similarity index 65% rename from feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/screens/ProfilePickerStreamScreen.kt rename to feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamScreen.kt index e54b0442..5dfa8488 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/screens/ProfilePickerStreamScreen.kt +++ b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamScreen.kt @@ -1,47 +1,41 @@ -package com.codandotv.streamplayerapp.feature_profile.profile.presentation.screens +package com.codandotv.streamplayerapp.profile.presentation.screens -import android.annotation.SuppressLint import androidx.compose.animation.animateColorAsState import androidx.compose.animation.core.animateDpAsState import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.animateIntOffsetAsState import androidx.compose.animation.core.tween import androidx.compose.foundation.background -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalLifecycleOwner -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.dp -import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.codandotv.streamplayerapp.core_shared_ui.theme.ThemePreview -import com.codandotv.streamplayerapp.core_shared_ui.theme.ThemePreviews -import com.codandotv.streamplayerapp.feature.profile.R -import com.codandotv.streamplayerapp.feature_profile.profile.domain.ProfileStream -import com.codandotv.streamplayerapp.feature_profile.profile.presentation.widget.LoadScreen -import com.codandotv.streamplayerapp.feature_profile.profile.presentation.widget.ProfilePickerOpacityLayer -import com.codandotv.streamplayerapp.feature_profile.profile.presentation.widget.ProfilePickerProfilesGrid -import com.codandotv.streamplayerapp.feature_profile.profile.presentation.widget.ProfilePickerSelectedProfileContainer -import com.codandotv.streamplayerapp.feature_profile.profile.presentation.widget.ProfilePickerStreamToolbar -import com.codandotv.streamplayerapp.feature_profile.profile.presentation.widget.dpToPx -import org.koin.androidx.compose.koinViewModel +import com.codandotv.streamplayerapp.profile.domain.ProfileStream +import com.codandotv.streamplayerapp.profile.presentation.widget.LoadScreen +import com.codandotv.streamplayerapp.profile.presentation.widget.ProfilePickerOpacityLayer +import com.codandotv.streamplayerapp.profile.presentation.widget.ProfilePickerProfilesGrid +import com.codandotv.streamplayerapp.profile.presentation.widget.ProfilePickerSelectedProfileContainer +import com.codandotv.streamplayerapp.profile.presentation.widget.ProfilePickerStreamToolbar +import com.codandotv.streamplayerapp.profile.presentation.widget.dpToPx +import org.jetbrains.compose.resources.stringResource +import org.koin.compose.viewmodel.koinViewModel +import streamplayerapp_kmp.feature_profile.generated.resources.Res +import streamplayerapp_kmp.feature_profile.generated.resources.profile_animation_background_opacity +import streamplayerapp_kmp.feature_profile.generated.resources.profile_animation_selected_image_position +import streamplayerapp_kmp.feature_profile.generated.resources.profile_animation_selected_image_size +import streamplayerapp_kmp.feature_profile.generated.resources.profile_animation_showing_all_profiles @Composable fun ProfilePickerStreamScreen( viewModel: ProfilePickerStreamViewModel = koinViewModel(), onNavigateListStreams: (String) -> Unit = {}, - disposable: () -> Unit = {} ) { - val uiState by viewModel.uiState.collectAsStateWithLifecycle() - val lifecycleOwner = LocalLifecycleOwner.current - Lifecycle(lifecycleOwner, viewModel, disposable) + val uiState by viewModel.uiState.collectAsState() if (uiState.isLoading) { LoadScreen() @@ -62,10 +56,8 @@ fun ProfilePickerStreamScreen( } @Suppress("LongMethod", "LongParameterList") -@OptIn(ExperimentalMaterial3Api::class) -@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter") @Composable -private fun SetupProfilePickerScreen( +fun SetupProfilePickerScreen( uiState: ProfilePickerStreamsUIState, onSetCenterImageAlpha: (Float) -> Unit = {}, onSetScreenSize: (Float, Float, Int, Int) -> Unit = { _, _, _, _ -> }, @@ -81,7 +73,7 @@ private fun SetupProfilePickerScreen( } else { Color.Transparent }, - label = stringResource(R.string.profile_animation_background_opacity), + label = stringResource(Res.string.profile_animation_background_opacity), animationSpec = tween(durationMillis = 1000), finishedListener = { onSetCenterImageAlpha(0f) @@ -109,13 +101,13 @@ private fun SetupProfilePickerScreen( // Preparing animations val animatedSizeImage by animateDpAsState( targetValue = if (expandImage) expandedImageSize.dp else defaultImageSize.dp, - label = stringResource(R.string.profile_animation_selected_image_size), + label = stringResource(Res.string.profile_animation_selected_image_size), animationSpec = tween(durationMillis = 1000), ) val animatedProfileAlpha: Float by animateFloatAsState( if (lastItemPositioned) 1f else 0f, - label = stringResource(R.string.profile_animation_showing_all_profiles), + label = stringResource(Res.string.profile_animation_showing_all_profiles), ) val animatedOffsetSelectedProfileImage by animateIntOffsetAsState( @@ -130,7 +122,7 @@ private fun SetupProfilePickerScreen( IntOffset(0, 0) } }, - label = stringResource(R.string.profile_animation_selected_image_position), + label = stringResource(Res.string.profile_animation_selected_image_position), animationSpec = tween(durationMillis = if (!showCenterImage) 100 else 800) ) @@ -152,32 +144,4 @@ private fun SetupProfilePickerScreen( } } ) -} - -@Composable -private fun Lifecycle( - lifecycleOwner: LifecycleOwner, viewModel: ProfilePickerStreamViewModel, disposable: () -> Unit -) { - DisposableEffect(lifecycleOwner) { - val lifecycle = lifecycleOwner.lifecycle - - lifecycle.addObserver(viewModel) - - onDispose { - lifecycle.removeObserver(viewModel) - disposable.invoke() - } - } -} - -@ThemePreviews -@Composable -fun SetupProfilePickerScreenPreview() { - ThemePreview { - SetupProfilePickerScreen( - uiState = ProfilePickerStreamsUIState( - selectedItem = ProfileStream("1", "Name", ""), - ) - ) - } } \ No newline at end of file diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/screens/ProfilePickerStreamViewModel.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamViewModel.kt similarity index 88% rename from feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/screens/ProfilePickerStreamViewModel.kt rename to feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamViewModel.kt index 36e3aa90..1eac734f 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/screens/ProfilePickerStreamViewModel.kt +++ b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamViewModel.kt @@ -1,24 +1,20 @@ -package com.codandotv.streamplayerapp.feature_profile.profile.presentation.screens +package com.codandotv.streamplayerapp.profile.presentation.screens -import androidx.lifecycle.DefaultLifecycleObserver -import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.codandotv.streamplayerapp.core_networking.handleError.catchFailure -import com.codandotv.streamplayerapp.feature_profile.profile.domain.ProfilePickerStreamUseCase -import com.codandotv.streamplayerapp.feature_profile.profile.domain.ProfileStream +import com.codandotv.streamplayerapp.profile.domain.ProfilePickerStreamUseCase +import com.codandotv.streamplayerapp.profile.domain.ProfileStream import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -import org.koin.android.annotation.KoinViewModel -@KoinViewModel class ProfilePickerStreamViewModel( private val useCase: ProfilePickerStreamUseCase, -) : ViewModel(), DefaultLifecycleObserver { +) : ViewModel() { private val _uiState = MutableStateFlow(ProfilePickerStreamsUIState()) val uiState = _uiState.stateIn( @@ -27,9 +23,7 @@ class ProfilePickerStreamViewModel( initialValue = _uiState.value ) - override fun onCreate(owner: LifecycleOwner) { - super.onCreate(owner) - + init { viewModelScope.launch { useCase.getProfile() .catchFailure { diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/screens/ProfilePickerStreamsUIState.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamsUIState.kt similarity index 83% rename from feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/screens/ProfilePickerStreamsUIState.kt rename to feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamsUIState.kt index 414b8d83..0ca2751b 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/screens/ProfilePickerStreamsUIState.kt +++ b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/screens/ProfilePickerStreamsUIState.kt @@ -1,6 +1,6 @@ -package com.codandotv.streamplayerapp.feature_profile.profile.presentation.screens +package com.codandotv.streamplayerapp.profile.presentation.screens -import com.codandotv.streamplayerapp.feature_profile.profile.domain.ProfileStream +import com.codandotv.streamplayerapp.profile.domain.ProfileStream data class ProfilePickerStreamsUIState( diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ComposeExtensions.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ComposeExtensions.kt similarity index 72% rename from feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ComposeExtensions.kt rename to feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ComposeExtensions.kt index 2d30f8c5..109a6561 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ComposeExtensions.kt +++ b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ComposeExtensions.kt @@ -1,4 +1,4 @@ -package com.codandotv.streamplayerapp.feature_profile.profile.presentation.widget +package com.codandotv.streamplayerapp.profile.presentation.widget import androidx.compose.runtime.Composable import androidx.compose.ui.platform.LocalDensity diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ProfilePickerOpacityLayer.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerOpacityLayer.kt similarity index 84% rename from feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ProfilePickerOpacityLayer.kt rename to feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerOpacityLayer.kt index f8fb3601..efbd403f 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ProfilePickerOpacityLayer.kt +++ b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerOpacityLayer.kt @@ -1,4 +1,4 @@ -package com.codandotv.streamplayerapp.feature_profile.profile.presentation.widget +package com.codandotv.streamplayerapp.profile.presentation.widget import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ProfilePickerProfilesGrid.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerProfilesGrid.kt similarity index 79% rename from feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ProfilePickerProfilesGrid.kt rename to feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerProfilesGrid.kt index f24737a2..d207b644 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ProfilePickerProfilesGrid.kt +++ b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerProfilesGrid.kt @@ -1,4 +1,4 @@ -package com.codandotv.streamplayerapp.feature_profile.profile.presentation.widget +package com.codandotv.streamplayerapp.profile.presentation.widget import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.BoxWithConstraints @@ -18,14 +18,17 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.graphicsLayer -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.dp -import coil.compose.AsyncImage -import com.codandotv.streamplayerapp.feature.profile.R -import com.codandotv.streamplayerapp.feature_profile.profile.domain.ProfileStream -import com.codandotv.streamplayerapp.feature_profile.profile.presentation.screens.ProfilePickerStreamsUIState +import com.codandotv.streamplayerapp.core_shared_ui.widget.WebImage +import com.codandotv.streamplayerapp.profile.domain.ProfileStream +import com.codandotv.streamplayerapp.profile.presentation.screens.ProfilePickerStreamsUIState +import org.jetbrains.compose.resources.painterResource +import org.jetbrains.compose.resources.stringResource +import streamplayerapp_kmp.feature_profile.generated.resources.Res +import streamplayerapp_kmp.feature_profile.generated.resources.image_placeholder +import streamplayerapp_kmp.feature_profile.generated.resources.profile_current_profile_name @Composable fun ProfilePickerProfilesGrid( @@ -90,13 +93,14 @@ private fun ProfileItem( profileItemPosition } ) { - AsyncImage( - model = profile.imageUrl, - placeholder = painterResource(id = R.drawable.image_placeholder), + WebImage( + imageUrl = profile.imageUrl, + //placeholder = painterResource(Res.drawable.image_placeholder), contentDescription = stringResource( - id = R.string.profile_current_profile_name, + Res.string.profile_current_profile_name, profile.name ), + contentScale = ContentScale.Fit, modifier = Modifier .clip(RoundedCornerShape(5)) .alpha(if (selectedItem == profile) selectedImageAlpha else 1f) diff --git a/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerSelectedProfileContainer.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerSelectedProfileContainer.kt new file mode 100644 index 00000000..652b8181 --- /dev/null +++ b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerSelectedProfileContainer.kt @@ -0,0 +1,65 @@ +package com.codandotv.streamplayerapp.profile.presentation.widget + +import androidx.compose.foundation.layout.BoxWithConstraints +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.draw.clip +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.IntOffset +import androidx.compose.ui.unit.dp +import com.codandotv.streamplayerapp.core_shared_ui.widget.WebImage +import com.codandotv.streamplayerapp.profile.presentation.screens.ProfilePickerStreamsUIState + +@Suppress("MagicNumber") +@Composable +fun ProfilePickerSelectedProfileContainer( + state: ProfilePickerStreamsUIState, + offsetSelectedProfileImage: IntOffset, + animatedSizeImage: Dp +) { + with(state) { + BoxWithConstraints( + Modifier + .fillMaxSize() + .padding(top = 100.dp) + ) { + if (showCenterImage) { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier + .offset { offsetSelectedProfileImage } + ) { + selectedItem?.imageUrl?.let { imageUrl -> + WebImage( + imageUrl =imageUrl, /*ImageRequest.Builder(LocalPlatformContext.current) + .data(selectedItem?.imageUrl) + .crossfade(true) + .build()*/ + contentScale = ContentScale.Fit, + contentDescription = null, + //placeholder = painterResource(Res.drawable.image_placeholder), + /*contentDescription = selectedItem?.let { + stringResource( + Res.string.profile_current_profile_name, + ).format(it.name) + },*/ + modifier = Modifier + .clip(RoundedCornerShape(5)) + .size(animatedSizeImage) + .alpha(centerImageAlpha) + ) + } + } + } + } + } +} \ No newline at end of file diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ProfilePickerStreamLoad.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerStreamLoad.kt similarity index 85% rename from feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ProfilePickerStreamLoad.kt rename to feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerStreamLoad.kt index 7c2bc50d..a2746cbd 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ProfilePickerStreamLoad.kt +++ b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerStreamLoad.kt @@ -1,4 +1,4 @@ -package com.codandotv.streamplayerapp.feature_profile.profile.presentation.widget +package com.codandotv.streamplayerapp.profile.presentation.widget import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ProfilePickerStreamToolbar.kt b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerStreamToolbar.kt similarity index 76% rename from feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ProfilePickerStreamToolbar.kt rename to feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerStreamToolbar.kt index 50a2c455..32ef6ca5 100644 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ProfilePickerStreamToolbar.kt +++ b/feature-profile/src/commonMain/kotlin/com/codandotv/streamplayerapp/profile/presentation/widget/ProfilePickerStreamToolbar.kt @@ -1,4 +1,4 @@ -package com.codandotv.streamplayerapp.feature_profile.profile.presentation.widget +package com.codandotv.streamplayerapp.profile.presentation.widget import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Arrangement @@ -14,10 +14,10 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp -import com.codandotv.streamplayerapp.core_shared_ui.theme.ThemePreviews -import com.codandotv.streamplayerapp.feature.profile.R +import org.jetbrains.compose.resources.painterResource +import streamplayerapp_kmp.feature_profile.generated.resources.Res +import streamplayerapp_kmp.feature_profile.generated.resources.netflix_horizontal_logo @Composable fun ProfilePickerStreamToolbar(modifier: Modifier = Modifier) { @@ -34,7 +34,7 @@ fun ProfilePickerStreamToolbar(modifier: Modifier = Modifier) { horizontalArrangement = Arrangement.Center ) { Image( - painter = painterResource(id = R.drawable.netflix_horizontal_logo), + painter = painterResource(Res.drawable.netflix_horizontal_logo), contentDescription = null, modifier = Modifier .height(28.dp) @@ -56,12 +56,3 @@ fun ProfilePickerStreamToolbar(modifier: Modifier = Modifier) { .height(56.dp) ) } - - -@ThemePreviews -@Composable -fun ProfilePickerStreamToolbarPreview() { - MaterialTheme { - ProfilePickerStreamToolbar() - } -} \ No newline at end of file diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/data/ProfilePickerStreamService.kt b/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/data/ProfilePickerStreamService.kt deleted file mode 100644 index 6c512286..00000000 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/data/ProfilePickerStreamService.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.codandotv.streamplayerapp.feature_profile.profile.data - -import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse -import com.codandotv.streamplayerapp.feature_profile.profile.data.model.ProfilesResponse -import retrofit2.http.GET - -interface ProfilePickerStreamService { - @GET("profiles") - suspend fun getProfiles(): NetworkResponse -} \ No newline at end of file diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/di/ProfilePickerStreamModule.kt b/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/di/ProfilePickerStreamModule.kt deleted file mode 100644 index d6ae9651..00000000 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/di/ProfilePickerStreamModule.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.codandotv.streamplayerapp.feature_profile.profile.di - -import com.codandotv.streamplayerapp.core_networking.di.QualifierProfileRetrofit -import com.codandotv.streamplayerapp.feature_profile.profile.data.ProfilePickerStreamService -import org.koin.core.annotation.ComponentScan -import org.koin.core.annotation.Factory -import org.koin.core.annotation.Module -import org.koin.core.context.GlobalContext -import retrofit2.Retrofit - -@Module -@ComponentScan("com.codandotv.streamplayerapp.feature_profile") -class ProfilePickerStreamModule { - - @Factory - fun service(): ProfilePickerStreamService { - val koin = GlobalContext.get() - val retrofit = koin.get(QualifierProfileRetrofit) - return retrofit.create(ProfilePickerStreamService::class.java) - } - -} diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/navigation/ProfilePickerStreamNavigation.kt b/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/navigation/ProfilePickerStreamNavigation.kt deleted file mode 100644 index 3624f939..00000000 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/navigation/ProfilePickerStreamNavigation.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.codandotv.streamplayerapp.feature_profile.profile.presentation.navigation - -import androidx.lifecycle.Lifecycle -import androidx.navigation.NavGraphBuilder -import androidx.navigation.NavHostController -import androidx.navigation.compose.composable -import com.codandotv.streamplayerapp.core_navigation.routes.BottomNavRoutes.HOME -import com.codandotv.streamplayerapp.core_navigation.routes.BottomNavRoutes.PARAM.PROFILE_ID -import com.codandotv.streamplayerapp.core_navigation.routes.Routes -import com.codandotv.streamplayerapp.feature_profile.profile.di.ProfilePickerStreamModule -import com.codandotv.streamplayerapp.feature_profile.profile.presentation.screens.ProfilePickerStreamScreen -import org.koin.core.context.loadKoinModules -import org.koin.core.context.unloadKoinModules -import org.koin.ksp.generated.module - -fun NavGraphBuilder.profilePickerStreamNavGraph(navController: NavHostController) { - composable(Routes.PROFILE_PICKER) { nav -> - if (nav.lifecycle.currentState == Lifecycle.State.STARTED) { - loadKoinModules(ProfilePickerStreamModule().module) - } - ProfilePickerStreamScreen( - onNavigateListStreams = { profilePic -> - navController.navigate("$HOME?$PROFILE_ID=$profilePic") - } - ) { - unloadKoinModules(ProfilePickerStreamModule().module) - } - } -} diff --git a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ProfilePickerSelectedProfileContainer.kt b/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ProfilePickerSelectedProfileContainer.kt deleted file mode 100644 index beade0ac..00000000 --- a/feature-profile/src/main/java/com/codandotv/streamplayerapp/feature_profile/profile/presentation/widget/ProfilePickerSelectedProfileContainer.kt +++ /dev/null @@ -1,66 +0,0 @@ -package com.codandotv.streamplayerapp.feature_profile.profile.presentation.widget - -import androidx.compose.foundation.layout.BoxWithConstraints -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.offset -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.alpha -import androidx.compose.ui.draw.clip -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.IntOffset -import androidx.compose.ui.unit.dp -import coil.compose.AsyncImage -import coil.request.ImageRequest -import com.codandotv.streamplayerapp.feature.profile.R -import com.codandotv.streamplayerapp.feature_profile.profile.presentation.screens.ProfilePickerStreamsUIState - -@Suppress("MagicNumber") -@Composable -fun ProfilePickerSelectedProfileContainer( - state: ProfilePickerStreamsUIState, - offsetSelectedProfileImage: IntOffset, - animatedSizeImage: Dp -) { - with(state) { - BoxWithConstraints( - Modifier - .fillMaxSize() - .padding(top = 100.dp) - ) { - if (showCenterImage) { - Column( - horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier - .offset { offsetSelectedProfileImage } - ) { - AsyncImage( - model = ImageRequest.Builder(LocalContext.current) - .data(selectedItem?.imageUrl) - .crossfade(true) - .build(), - placeholder = painterResource(id = R.drawable.image_placeholder), - contentDescription = selectedItem?.let { - stringResource( - id = R.string.profile_current_profile_name, - it.name - ) - }, - modifier = Modifier - .clip(RoundedCornerShape(5)) - .size(animatedSizeImage) - .alpha(centerImageAlpha) - ) - } - } - } - } -} \ No newline at end of file diff --git a/feature-search/.gitignore b/feature-search/.gitignore new file mode 100644 index 00000000..581f8daa --- /dev/null +++ b/feature-search/.gitignore @@ -0,0 +1 @@ +**/build/** \ No newline at end of file diff --git a/feature-search/build.gradle.kts b/feature-search/build.gradle.kts new file mode 100644 index 00000000..c7562960 --- /dev/null +++ b/feature-search/build.gradle.kts @@ -0,0 +1,39 @@ +@file:Suppress("UnstableApiUsage") + +plugins { + id("com.streamplayer.kmp-library") + alias(libs.plugins.jetbrains.compose) + alias(libs.plugins.compose.compiler) +} + +kotlin { + sourceSets { + androidMain.dependencies { + implementation(compose.preview) + } + + commonMain.dependencies { + implementation(libs.paging.compose) + + implementation(projects.coreNetworking) + implementation(projects.coreNavigation) + implementation(projects.coreShared) + implementation(projects.coreSharedUi) + implementation(projects.coreLocalStorage) + + implementation(compose.components.resources) + implementation(compose.material3) + implementation(compose.ui) + + + implementation(libs.navigation.compose) + + implementation(libs.ktor.client.content.serialization.json) + implementation(libs.ktor.client.content.negotiation) + + implementation(libs.koin.core) + implementation(libs.koin.compose) + implementation(libs.koin.compose.viewmodel) + } + } +} \ No newline at end of file diff --git a/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchStreamCardPreview.kt b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchStreamCardPreview.kt new file mode 100644 index 00000000..2597746e --- /dev/null +++ b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchStreamCardPreview.kt @@ -0,0 +1,25 @@ +package com.codandotv.streamplayerapp.feature_search.presentation.widgets + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.codandotv.streamplayerapp.core_shared_ui.theme.ThemePreviews + + +@ThemePreviews +@Composable +fun SearchStreamCardPreview() { + SearchStreamCard( + content = SearchStreamCardModel( + id = "1", + title = "The Witcher", + url = "https://image.tmdb.org/t/p/w200/iwsMu0ehRPbtaSxqiaUDQB9qMWT.jpg" + ), + onSearchStreamPressed = {} + ) +} + +@ThemePreviews +@Composable +fun PlayerPreview() { + PlayerIcon(modifier = Modifier) +} \ No newline at end of file diff --git a/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchStreamsPreview.kt b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchStreamsPreview.kt new file mode 100644 index 00000000..8b37e056 --- /dev/null +++ b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchStreamsPreview.kt @@ -0,0 +1,36 @@ +package com.codandotv.streamplayerapp.feature_search.presentation.widgets + +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.Preview + +@Composable +@Preview +fun SearchBarPreview() { + StreamPlayerTopBar( + onBackPressed = {} + ) +} + +@Composable +@Preview +fun SearchTopBarEmptyPreview() { + SearchTopBar( + currentSearchText = "", + onSearchTextChanged = {}, + onSearchDispatched = {}, + onCleanTextPressed = {}, + onSearchIconPressed = {} + ) +} + +@Composable +@Preview +fun SearchTopBarPreview() { + SearchTopBar( + currentSearchText = "Texto de busca", + onSearchTextChanged = {}, + onSearchDispatched = {}, + onCleanTextPressed = {}, + onSearchIconPressed = {} + ) +} diff --git a/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/StreamsCarouselPreview.kt b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/StreamsCarouselPreview.kt new file mode 100644 index 00000000..75b34df3 --- /dev/null +++ b/feature-search/src/androidMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/StreamsCarouselPreview.kt @@ -0,0 +1,19 @@ +package com.codandotv.streamplayerapp.feature_search.presentation.widgets + +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.Preview + +@Composable +@Preview +fun StreamsErrorPreview() { + StreamsError( + onRetry = {}, + onCloseButton = {} + ) +} + +@Composable +@Preview +fun StreamEmptyPreview() { + StreamsEmpty() +} \ No newline at end of file diff --git a/feature-search/src/commonMain/composeResources/values/strings.xml b/feature-search/src/commonMain/composeResources/values/strings.xml new file mode 100644 index 00000000..e8445742 --- /dev/null +++ b/feature-search/src/commonMain/composeResources/values/strings.xml @@ -0,0 +1,12 @@ + + + + Principais buscas + Principais buscas + Voltar + + + Houve um problema ao conectar à Netflix. Tente novamente mais tarde. + Tente novamente + Conteúdo não encontrado + \ No newline at end of file diff --git a/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/api/MostPopularMoviesService.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/api/MostPopularMoviesService.kt new file mode 100644 index 00000000..aa4ac25f --- /dev/null +++ b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/api/MostPopularMoviesService.kt @@ -0,0 +1,22 @@ +package com.codandotv.streamplayerapp.feature_search.data.api + +import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse +import com.codandotv.streamplayerapp.core_networking.handleError.safeRequest +import com.codandotv.streamplayerapp.feature_search.data.model.ListSearchStreamResponse +import io.ktor.client.HttpClient +import io.ktor.client.call.body +import io.ktor.client.request.get +import io.ktor.client.request.url + +interface MostPopularMoviesService { + suspend fun getPopular(): NetworkResponse +} + +class MostPopularMoviesServiceImpl( + private val client: HttpClient +) : MostPopularMoviesService { + override suspend fun getPopular(): NetworkResponse = + client.safeRequest { + url("movie/popular") + } +} diff --git a/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/api/SearchStreamService.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/api/SearchStreamService.kt new file mode 100644 index 00000000..1020971f --- /dev/null +++ b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/api/SearchStreamService.kt @@ -0,0 +1,22 @@ +package com.codandotv.streamplayerapp.feature_search.data.api + +import com.codandotv.streamplayerapp.core_networking.handleError.NetworkResponse +import com.codandotv.streamplayerapp.core_networking.handleError.safeRequest +import com.codandotv.streamplayerapp.feature_search.data.model.ListSearchStreamResponse +import io.ktor.client.HttpClient +import io.ktor.client.request.parameter +import io.ktor.client.request.url + +interface SearchStreamService { + suspend fun getSearch(query: String): NetworkResponse +} + +class SearchStreamServiceImpl( + private val client: HttpClient +) : SearchStreamService { + override suspend fun getSearch(query: String): NetworkResponse = + client.safeRequest { + url("search/movie") + parameter("query", query) + } +} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/datasource/MostPopularMoviesDataSource.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/datasource/MostPopularMoviesDataSource.kt similarity index 62% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/datasource/MostPopularMoviesDataSource.kt rename to feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/datasource/MostPopularMoviesDataSource.kt index 82f01044..b074864d 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/datasource/MostPopularMoviesDataSource.kt +++ b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/datasource/MostPopularMoviesDataSource.kt @@ -1,8 +1,8 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.data.datasource +package com.codandotv.streamplayerapp.feature_search.data.datasource import com.codandotv.streamplayerapp.core_networking.handleError.toFlow -import com.codandotv.streamplayerapp.feature_list_streams.search.data.model.ListSearchStreamResponse -import com.codandotv.streamplayerapp.feature_list_streams.search.data.api.MostPopularMoviesService +import com.codandotv.streamplayerapp.feature_search.data.model.ListSearchStreamResponse +import com.codandotv.streamplayerapp.feature_search.data.api.MostPopularMoviesService import kotlinx.coroutines.flow.Flow interface MostPopularMoviesDataSource { diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/datasource/SearchStreamDataSource.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/datasource/SearchStreamDataSource.kt similarity index 63% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/datasource/SearchStreamDataSource.kt rename to feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/datasource/SearchStreamDataSource.kt index 77f25ce3..e3d65b3b 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/datasource/SearchStreamDataSource.kt +++ b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/datasource/SearchStreamDataSource.kt @@ -1,8 +1,8 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.data.datasource +package com.codandotv.streamplayerapp.feature_search.data.datasource import com.codandotv.streamplayerapp.core_networking.handleError.toFlow -import com.codandotv.streamplayerapp.feature_list_streams.search.data.model.ListSearchStreamResponse -import com.codandotv.streamplayerapp.feature_list_streams.search.data.api.SearchStreamService +import com.codandotv.streamplayerapp.feature_search.data.model.ListSearchStreamResponse +import com.codandotv.streamplayerapp.feature_search.data.api.SearchStreamService import kotlinx.coroutines.flow.Flow interface SearchStreamDataSource { diff --git a/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/model/ListSearchStreamResponse.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/model/ListSearchStreamResponse.kt new file mode 100644 index 00000000..88fa6d04 --- /dev/null +++ b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/model/ListSearchStreamResponse.kt @@ -0,0 +1,22 @@ +package com.codandotv.streamplayerapp.feature_search.data.model + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class ListSearchStreamResponse( + @SerialName("results") + val results: List +) { + @Serializable + data class SearchStreamResponse( + @SerialName("id") + val id: Int, + @SerialName("title") + val title: String, + @SerialName("overview") + val overview: String, + @SerialName("poster_path") + val posterPath: String? = null + ) +} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/repository/MostPopularMoviesRepository.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/repository/MostPopularMoviesRepository.kt similarity index 58% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/repository/MostPopularMoviesRepository.kt rename to feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/repository/MostPopularMoviesRepository.kt index cbf9ddb3..5fbf97e5 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/repository/MostPopularMoviesRepository.kt +++ b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/repository/MostPopularMoviesRepository.kt @@ -1,7 +1,7 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.data.repository +package com.codandotv.streamplayerapp.feature_search.data.repository -import com.codandotv.streamplayerapp.feature_list_streams.search.data.model.ListSearchStreamResponse -import com.codandotv.streamplayerapp.feature_list_streams.search.data.datasource.MostPopularMoviesDataSource +import com.codandotv.streamplayerapp.feature_search.data.model.ListSearchStreamResponse +import com.codandotv.streamplayerapp.feature_search.data.datasource.MostPopularMoviesDataSource import kotlinx.coroutines.flow.Flow interface MostPopularMoviesRepository { diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/repository/SearchStreamRepository.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/repository/SearchStreamRepository.kt similarity index 58% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/repository/SearchStreamRepository.kt rename to feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/repository/SearchStreamRepository.kt index d336d2ba..9b101176 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/data/repository/SearchStreamRepository.kt +++ b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/repository/SearchStreamRepository.kt @@ -1,7 +1,7 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.data.repository +package com.codandotv.streamplayerapp.feature_search.data.repository -import com.codandotv.streamplayerapp.feature_list_streams.search.data.datasource.SearchStreamDataSource -import com.codandotv.streamplayerapp.feature_list_streams.search.data.model.ListSearchStreamResponse +import com.codandotv.streamplayerapp.feature_search.data.datasource.SearchStreamDataSource +import com.codandotv.streamplayerapp.feature_search.data.model.ListSearchStreamResponse import kotlinx.coroutines.flow.Flow interface SearchStreamRepository { diff --git a/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/di/SearchModule.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/di/SearchModule.kt new file mode 100644 index 00000000..7848bf61 --- /dev/null +++ b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/di/SearchModule.kt @@ -0,0 +1,43 @@ +package com.codandotv.streamplayerapp.feature_search.di + +import com.codandotv.streamplayerapp.feature_search.data.api.SearchStreamService +import com.codandotv.streamplayerapp.feature_search.data.datasource.SearchStreamDataSourceImpl +import com.codandotv.streamplayerapp.feature_search.data.datasource.MostPopularMoviesDataSource +import com.codandotv.streamplayerapp.feature_search.data.datasource.MostPopularMoviesDataSourceImpl +import com.codandotv.streamplayerapp.feature_search.data.repository.MostPopularMoviesRepository +import com.codandotv.streamplayerapp.feature_search.data.repository.MostPopularMoviesRepositoryImpl +import com.codandotv.streamplayerapp.feature_search.data.api.MostPopularMoviesService +import com.codandotv.streamplayerapp.feature_search.data.api.MostPopularMoviesServiceImpl +import com.codandotv.streamplayerapp.feature_search.data.api.SearchStreamServiceImpl +import com.codandotv.streamplayerapp.feature_search.data.datasource.SearchStreamDataSource +import com.codandotv.streamplayerapp.feature_search.data.repository.SearchStreamRepository +import com.codandotv.streamplayerapp.feature_search.data.repository.SearchStreamRepositoryImp +import com.codandotv.streamplayerapp.feature_search.domain.MostPopularMoviesUseCase +import com.codandotv.streamplayerapp.feature_search.domain.MostPopularMoviesUseCaseImpl +import com.codandotv.streamplayerapp.feature_search.domain.SearchUseCase +import com.codandotv.streamplayerapp.feature_search.domain.SearchUseCaseImpl +import com.codandotv.streamplayerapp.feature_search.presentation.screens.SearchViewModel +import org.koin.core.module.dsl.viewModel +import org.koin.dsl.module + +object SearchModule { + val module = module { + viewModel { + SearchViewModel( + searchUseCase = get(), + mostPopularMoviesUseCase = get() + ) + } + + factory { SearchStreamServiceImpl(get()) } + factory { MostPopularMoviesServiceImpl(get()) } + + factory { MostPopularMoviesUseCaseImpl(repository = get()) } + factory { MostPopularMoviesDataSourceImpl(service = get()) } + factory { MostPopularMoviesRepositoryImpl(dataSource = get()) } + + factory { SearchUseCaseImpl(repository = get()) } + factory { SearchStreamDataSourceImpl(service = get()) } + factory { SearchStreamRepositoryImp(dataSource = get()) } + } +} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/domain/MostPopularMoviesUseCase.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/MostPopularMoviesUseCase.kt similarity index 58% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/domain/MostPopularMoviesUseCase.kt rename to feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/MostPopularMoviesUseCase.kt index 1ba461fc..b924c782 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/domain/MostPopularMoviesUseCase.kt +++ b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/MostPopularMoviesUseCase.kt @@ -1,7 +1,7 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.domain +package com.codandotv.streamplayerapp.feature_search.domain -import com.codandotv.streamplayerapp.feature_list_streams.search.data.model.ListSearchStreamResponse -import com.codandotv.streamplayerapp.feature_list_streams.search.data.repository.MostPopularMoviesRepository +import com.codandotv.streamplayerapp.feature_search.data.model.ListSearchStreamResponse +import com.codandotv.streamplayerapp.feature_search.data.repository.MostPopularMoviesRepository import kotlinx.coroutines.flow.Flow interface MostPopularMoviesUseCase { diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/domain/SearchUseCase.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/SearchUseCase.kt similarity index 57% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/domain/SearchUseCase.kt rename to feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/SearchUseCase.kt index 90e2e3b9..075f7bfe 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/domain/SearchUseCase.kt +++ b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/SearchUseCase.kt @@ -1,7 +1,7 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.domain +package com.codandotv.streamplayerapp.feature_search.domain -import com.codandotv.streamplayerapp.feature_list_streams.search.data.model.ListSearchStreamResponse -import com.codandotv.streamplayerapp.feature_list_streams.search.data.repository.SearchStreamRepository +import com.codandotv.streamplayerapp.feature_search.data.model.ListSearchStreamResponse +import com.codandotv.streamplayerapp.feature_search.data.repository.SearchStreamRepository import kotlinx.coroutines.flow.Flow interface SearchUseCase { diff --git a/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/mapper/SearchMapper.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/mapper/SearchMapper.kt new file mode 100644 index 00000000..a96edcb1 --- /dev/null +++ b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/mapper/SearchMapper.kt @@ -0,0 +1,11 @@ +package com.codandotv.streamplayerapp.feature_search.domain.mapper + +import com.codandotv.streamplayerapp.core_shared.Url +import com.codandotv.streamplayerapp.feature_search.data.model.ListSearchStreamResponse.SearchStreamResponse +import com.codandotv.streamplayerapp.feature_search.presentation.widgets.SearchStreamCardModel + +fun SearchStreamResponse.toSearchStreamCardModel() = SearchStreamCardModel( + id = id.toString(), + title = title, + url = "${Url.IMAGE_URL_SIZE_200}${posterPath}" +) diff --git a/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/navigation/SearchStreamNavigation.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/navigation/SearchStreamNavigation.kt new file mode 100644 index 00000000..e8aa897e --- /dev/null +++ b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/navigation/SearchStreamNavigation.kt @@ -0,0 +1,26 @@ +package com.codandotv.streamplayerapp.feature_search.presentation.navigation + +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavHostController +import androidx.navigation.compose.composable +import com.codandotv.streamplayerapp.core_navigation.routes.Routes +import com.codandotv.streamplayerapp.feature_search.di.SearchModule +import com.codandotv.streamplayerapp.feature_search.presentation.screens.SearchScreen +import org.koin.compose.module.rememberKoinModules +import org.koin.core.annotation.KoinExperimentalAPI + +@OptIn(KoinExperimentalAPI::class) +fun NavGraphBuilder.searchStreamsNavGraph(navController: NavHostController) { + composable(Routes.SEARCH) { _ -> +// BackHandler(true) {} + rememberKoinModules { + listOf(SearchModule.module) + } + SearchScreen( + navController = navController, + onNavigateDetailList = { id -> + navController.navigate("${Routes.DETAIL}${id}") + } + ) + } +} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/screens/SearchScreen.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchScreen.kt similarity index 69% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/screens/SearchScreen.kt rename to feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchScreen.kt index f3f68d21..379193e8 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/screens/SearchScreen.kt +++ b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchScreen.kt @@ -1,6 +1,5 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.presentation.screens +package com.codandotv.streamplayerapp.feature_search.presentation.screens -import androidx.activity.compose.BackHandler import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize @@ -8,48 +7,37 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.CircularProgressIndicator -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.collectAsState 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.LocalLifecycleOwner -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavController import com.codandotv.streamplayerapp.core_navigation.extensions.goBack -import com.codandotv.streamplayerapp.feature.list.streams.R -import com.codandotv.streamplayerapp.feature_list_streams.search.domain.mapper.toSearchStreamCardModel -import com.codandotv.streamplayerapp.feature_list_streams.search.presentation.widgets.SearchStreamCard -import com.codandotv.streamplayerapp.feature_list_streams.search.presentation.widgets.SearchableTopBar -import com.codandotv.streamplayerapp.feature_list_streams.search.presentation.widgets.StreamsEmpty -import com.codandotv.streamplayerapp.feature_list_streams.search.presentation.widgets.StreamsError -import org.koin.androidx.compose.koinViewModel +import com.codandotv.streamplayerapp.feature_search.domain.mapper.toSearchStreamCardModel +import com.codandotv.streamplayerapp.feature_search.presentation.widgets.SearchStreamCard +import com.codandotv.streamplayerapp.feature_search.presentation.widgets.SearchableTopBar +import com.codandotv.streamplayerapp.feature_search.presentation.widgets.StreamsEmpty +import com.codandotv.streamplayerapp.feature_search.presentation.widgets.StreamsError +import org.jetbrains.compose.resources.stringResource +import org.koin.compose.viewmodel.koinViewModel +import streamplayerapp_kmp.feature_search.generated.resources.Res +import streamplayerapp_kmp.feature_search.generated.resources.search_list_describle @Composable fun SearchScreen( viewModel: SearchViewModel = koinViewModel(), onNavigateDetailList: (String) -> Unit = {}, navController: NavController, - disposable: () -> Unit = {} ) { - val uiState by viewModel.uiState.collectAsStateWithLifecycle() - Lifecycle( - lifecycleOwner = LocalLifecycleOwner.current, - viewModel = viewModel, - disposable = disposable - ) - + val uiState by viewModel.uiState.collectAsState() when (uiState) { is SearchUIState.Success -> { SetupSearchScreen( @@ -88,7 +76,6 @@ fun SearchScreen( } } -@OptIn(ExperimentalMaterial3Api::class) @Composable private fun SetupSearchScreen( onNavigateDetailList: (String) -> Unit = {}, @@ -129,7 +116,7 @@ private fun SetupSearchScreen( .verticalScroll(rememberScrollState()), ) { Text( - text = stringResource(id = R.string.search_list_describle), + text = stringResource(Res.string.search_list_describle), color = Color.White, fontWeight = FontWeight.SemiBold, fontSize = 20.sp, @@ -150,24 +137,4 @@ private fun SetupSearchScreen( } } } - BackHandler { - navController.goBack() - } - -} - -@Composable -private fun Lifecycle( - lifecycleOwner: LifecycleOwner, viewModel: SearchViewModel, disposable: () -> Unit -) { - DisposableEffect(lifecycleOwner) { - val lifecycle = lifecycleOwner.lifecycle - - lifecycle.addObserver(viewModel) - - onDispose { - lifecycle.removeObserver(viewModel) - disposable.invoke() - } - } -} +} \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/screens/SearchUIState.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchUIState.kt similarity index 58% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/screens/SearchUIState.kt rename to feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchUIState.kt index 965ec7dd..3e716dfc 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/screens/SearchUIState.kt +++ b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchUIState.kt @@ -1,6 +1,6 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.presentation.screens +package com.codandotv.streamplayerapp.feature_search.presentation.screens -import com.codandotv.streamplayerapp.feature_list_streams.search.data.model.ListSearchStreamResponse +import com.codandotv.streamplayerapp.feature_search.data.model.ListSearchStreamResponse sealed class SearchUIState { data class Success(val listCharacters: ListSearchStreamResponse) : SearchUIState() diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/screens/SearchViewModel.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchViewModel.kt similarity index 89% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/screens/SearchViewModel.kt rename to feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchViewModel.kt index f02c07ac..8a4314b7 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/screens/SearchViewModel.kt +++ b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchViewModel.kt @@ -1,11 +1,10 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.presentation.screens +package com.codandotv.streamplayerapp.feature_search.presentation.screens -import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.codandotv.streamplayerapp.core_networking.handleError.catchFailure -import com.codandotv.streamplayerapp.feature_list_streams.search.domain.MostPopularMoviesUseCase -import com.codandotv.streamplayerapp.feature_list_streams.search.domain.SearchUseCase +import com.codandotv.streamplayerapp.feature_search.domain.MostPopularMoviesUseCase +import com.codandotv.streamplayerapp.feature_search.domain.SearchUseCase import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -18,7 +17,7 @@ import kotlinx.coroutines.launch class SearchViewModel( private val searchUseCase: SearchUseCase, private val mostPopularMoviesUseCase: MostPopularMoviesUseCase -) : ViewModel(), DefaultLifecycleObserver { +) : ViewModel() { private var tryAgain: () -> Unit = {} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/widgets/SearchCarousel.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchCarousel.kt similarity index 73% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/widgets/SearchCarousel.kt rename to feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchCarousel.kt index 0e884005..d736bac1 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/widgets/SearchCarousel.kt +++ b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchCarousel.kt @@ -1,4 +1,4 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.presentation.widgets +package com.codandotv.streamplayerapp.feature_search.presentation.widgets import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -21,21 +21,24 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.paging.PagingData -import androidx.paging.compose.collectAsLazyPagingItems -import androidx.paging.compose.itemContentType -import androidx.paging.compose.itemKey -import com.codandotv.streamplayerapp.feature.list.streams.R -import com.codandotv.streamplayerapp.feature_list_streams.list.presentation.widgets.StreamsCard -import com.codandotv.streamplayerapp.feature_list_streams.list.presentation.widgets.StreamsCardContent +import app.cash.paging.compose.collectAsLazyPagingItems +import app.cash.paging.compose.itemContentType +import app.cash.paging.compose.itemKey +import com.codandotv.streamplayerapp.core_shared_ui.widget.StreamsCard +import com.codandotv.streamplayerapp.core_shared_ui.widget.StreamsCardContent import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.emptyFlow +import org.jetbrains.compose.resources.stringResource +import streamplayerapp_kmp.feature_search.generated.resources.Res +import streamplayerapp_kmp.feature_search.generated.resources.bottom_search_list_error +import streamplayerapp_kmp.feature_search.generated.resources.empty_search_list +import streamplayerapp_kmp.feature_search.generated.resources.search_back +import streamplayerapp_kmp.feature_search.generated.resources.search_list_describle +import streamplayerapp_kmp.feature_search.generated.resources.search_list_error data class SearchCarousel( val genreTitle: String, @@ -51,7 +54,7 @@ fun SearchCarouselStream( val lazyPagingItems = content.contentList.collectAsLazyPagingItems() Text( - text = stringResource(id = R.string.search_list_describle), + text = stringResource(Res.string.search_list_describle), color = Color.Black, fontSize = 14.sp ) @@ -79,17 +82,6 @@ fun SearchCarouselStream( } } -@Composable -@Preview -fun StreamsCarouselPreview() { - SearchCarouselStream( - content = SearchCarousel( - genreTitle = "Comédia", - contentList = emptyFlow() - ) - ) -} - @Composable fun StreamsError( onRetry: () -> Unit, @@ -105,12 +97,12 @@ fun StreamsError( }) { Icon( imageVector = Icons.Filled.Close, - contentDescription = stringResource(id = R.string.detail_back), + contentDescription = stringResource(Res.string.search_back), tint = Color.White ) } Text( - text = stringResource(id = R.string.search_list_error), + text = stringResource(Res.string.search_list_error), color = Color.White, fontWeight = FontWeight.SemiBold, fontSize = 20.sp, @@ -132,18 +124,17 @@ fun StreamsError( ), shape = RoundedCornerShape(8.dp), ) { - Text(text = stringResource(id = R.string.bottom_search_list_error)) + Text(text = stringResource(Res.string.bottom_search_list_error)) } } } @Composable -@Preview fun StreamsEmpty() { Row(verticalAlignment = Alignment.CenterVertically) { Column { Text( - text = stringResource(id = R.string.empty_search_list), + text = stringResource(Res.string.empty_search_list), color = Color.White, fontWeight = FontWeight.SemiBold, fontSize = 20.sp, @@ -154,12 +145,3 @@ fun StreamsEmpty() { } } } - -@Composable -@Preview -fun StreamsErrorPreview() { - StreamsError( - onRetry = {}, - onCloseButton = {} - ) -} \ No newline at end of file diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/widgets/SearchStreamCard.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchStreamCard.kt similarity index 82% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/widgets/SearchStreamCard.kt rename to feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchStreamCard.kt index 86d1d674..f496d701 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/widgets/SearchStreamCard.kt +++ b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchStreamCard.kt @@ -1,4 +1,4 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.presentation.widgets +package com.codandotv.streamplayerapp.feature_search.presentation.widgets import androidx.compose.foundation.background import androidx.compose.foundation.border @@ -24,8 +24,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import coil.compose.AsyncImage -import com.codandotv.streamplayerapp.core_shared_ui.theme.ThemePreviews +import com.codandotv.streamplayerapp.core_shared_ui.widget.WebImage @Suppress("MagicNumber") @Composable @@ -80,8 +79,8 @@ fun ImageStream(modifier: Modifier, url: String) { shape = RoundedCornerShape(4.dp), modifier = modifier ) { - AsyncImage( - model = url, + WebImage( + imageUrl = url, contentScale = ContentScale.FillBounds, contentDescription = "", modifier = Modifier.fillMaxSize() @@ -107,22 +106,3 @@ fun PlayerIcon(modifier: Modifier) { ) } } - -@ThemePreviews -@Composable -fun SearchStreamCardPreview() { - SearchStreamCard( - content = SearchStreamCardModel( - id = "1", - title = "The Witcher", - url = "https://image.tmdb.org/t/p/w200/iwsMu0ehRPbtaSxqiaUDQB9qMWT.jpg" - ), - onSearchStreamPressed = {} - ) -} - -@ThemePreviews -@Composable -fun PlayerPreview() { - PlayerIcon(modifier = Modifier) -} diff --git a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/widgets/SearchStreams.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchStreams.kt similarity index 60% rename from feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/widgets/SearchStreams.kt rename to feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchStreams.kt index 6626e3ca..01775583 100644 --- a/feature-list-streams/src/main/java/com/codandotv/streamplayerapp/feature_list_streams/search/presentation/widgets/SearchStreams.kt +++ b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/widgets/SearchStreams.kt @@ -1,4 +1,4 @@ -package com.codandotv.streamplayerapp.feature_list_streams.search.presentation.widgets +package com.codandotv.streamplayerapp.feature_search.presentation.widgets import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box @@ -13,11 +13,7 @@ import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack -import androidx.compose.material.icons.filled.Cast -import androidx.compose.material.icons.filled.Close -import androidx.compose.material.icons.filled.MicNone -import androidx.compose.material.icons.filled.Search -import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material.icons.filled.Check import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme @@ -28,16 +24,22 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.input.ImeAction -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.codandotv.streamplayerapp.core.shared.ui.R import com.codandotv.streamplayerapp.core_shared_ui.resources.Colors -import com.codandotv.streamplayerapp.feature.list.streams.R as ResourceListStream +import com.codandotv.streamplayerapp.core_shared_ui.widget.CloseButton +import com.codandotv.streamplayerapp.core_shared_ui.widget.MicButton +import com.codandotv.streamplayerapp.core_shared_ui.widget.SearchIcon +import org.jetbrains.compose.resources.painterResource +import org.jetbrains.compose.resources.stringResource +import streamplayerapp_kmp.core_shared_ui.generated.resources.icon_back +import streamplayerapp_kmp.core_shared_ui.generated.resources.icon_cast +import streamplayerapp_kmp.core_shared_ui.generated.resources.icon_profile +import streamplayerapp_kmp.core_shared_ui.generated.resources.perfil_fake +import streamplayerapp_kmp.feature_search.generated.resources.Res +import streamplayerapp_kmp.feature_search.generated.resources.search_list_main_search +import streamplayerapp_kmp.core_shared_ui.generated.resources.Res as SharedRes @Suppress("LongParameterList") @Composable @@ -64,7 +66,7 @@ fun SearchableTopBar( } @Composable -private fun StreamPlayerTopBar( +internal fun StreamPlayerTopBar( onBackPressed: () -> Unit ) { Row( @@ -79,7 +81,7 @@ private fun StreamPlayerTopBar( ) { Icon( imageVector = Icons.AutoMirrored.Filled.ArrowBack, - contentDescription = stringResource(id = R.string.icon_back), + contentDescription = stringResource(SharedRes.string.icon_back), tint = Color.White, ) } @@ -90,8 +92,8 @@ private fun StreamPlayerTopBar( onClick = { /* todo */ } ) { Icon( - imageVector = Icons.Default.Cast, - contentDescription = stringResource(id = R.string.icon_cast), + imageVector = Icons.Default.Check, + contentDescription = stringResource(SharedRes.string.icon_cast), tint = Color.White, ) } @@ -104,15 +106,14 @@ private fun StreamPlayerTopBar( modifier = Modifier .height(24.dp) .clip(RoundedCornerShape(4.dp)), - painter = painterResource(R.drawable.perfil_fake), - contentDescription = stringResource(id = R.string.icon_profile), + painter = painterResource(SharedRes.drawable.perfil_fake), + contentDescription = stringResource(SharedRes.string.icon_profile), tint = Color.Unspecified, ) } } } -@OptIn(ExperimentalMaterial3Api::class) @Composable fun SearchTopBar( currentSearchText: String, @@ -142,7 +143,7 @@ fun SearchTopBar( }, placeholder = { Text( - text = stringResource(id = ResourceListStream.string.search_list_main_search), + text = stringResource(Res.string.search_list_main_search), color = Color.Gray ) }, @@ -167,85 +168,3 @@ fun SearchTopBar( ) } } - -@Composable -fun DefaultIcon( - modifier: Modifier = Modifier, - searchIcon: ImageVector = Icons.Default.Search, - iconColor: Color = Color.White, - contentDescription: String = "", - onIconClickAction: () -> Unit = {} -) { - IconButton( - modifier = modifier, - onClick = onIconClickAction - ) { - Icon( - imageVector = searchIcon, - contentDescription = contentDescription, - tint = iconColor - ) - } -} - -@Composable -fun SearchIcon(action: () -> Unit = {}) { - DefaultIcon( - searchIcon = Icons.Filled.Search, - contentDescription = stringResource(id = R.string.icon_search), - onIconClickAction = action, - iconColor = Color.Gray - ) -} - -@Composable -fun CloseButton(action: () -> Unit = {}) { - DefaultIcon( - searchIcon = Icons.Default.Close, - contentDescription = stringResource(id = R.string.icon_close), - onIconClickAction = action, - iconColor = Color.Gray - ) -} - -@Composable -private fun MicButton(action: () -> Unit = {}) { - DefaultIcon( - searchIcon = Icons.Default.MicNone, - contentDescription = stringResource(id = R.string.icon_mic), - onIconClickAction = action, - iconColor = Color.Gray - ) -} - -@Composable -@Preview -fun SearchBarPreview() { - StreamPlayerTopBar( - onBackPressed = {} - ) -} - -@Composable -@Preview -fun SearchTopBarEmptyPreview() { - SearchTopBar( - currentSearchText = "", - onSearchTextChanged = {}, - onSearchDispatched = {}, - onCleanTextPressed = {}, - onSearchIconPressed = {} - ) -} - -@Composable -@Preview -fun SearchTopBarPreview() { - SearchTopBar( - currentSearchText = "Texto de busca", - onSearchTextChanged = {}, - onSearchDispatched = {}, - onCleanTextPressed = {}, - onSearchIconPressed = {} - ) -} diff --git a/gradle.properties b/gradle.properties index f63f4eac..1d55b8a4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -21,5 +21,4 @@ kotlin.code.style=official # resources declared in the library itself and none from the library's dependencies, # thereby reducing the size of the R class for that library android.nonTransitiveRClass=true -android.defaults.buildfeatures.buildconfig=true android.nonFinalResIds=false \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 865020d6..11cd12dd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,55 +1,34 @@ [versions] -kotlin = "1.9.25" -android_gradle_plugin = "8.2.2" -koin = "3.4.0" -koin-annotations-bom = "1.3.0" -ksp = "1.9.25-1.0.20" +kotlin = "2.1.10" +android_gradle_plugin = "8.7.2" +koin = "4.0.1" +ksp = "2.1.10-1.0.29" + dokka = "1.9.10" kover = "0.7.5" detekt = "1.23.6" +compose_plugin_multiplataform = "1.7.3" +navigation-compose-version = "2.7.0-alpha07" +paging-compose = "3.3.0-alpha02-0.5.1" +buildkonfig = "0.15.2" #Test test_junit = "4.13.2" androidx_core_testing = "2.2.0" mockk = "1.13.7" -kotlinx-coroutines-test= "1.8.1" - -#Android Test -androidx_test_core = "1.6.1" -androidx_test_rules = "1.6.1" -androidx_test_runner = "1.6.2" -androidx_test_junit_ext = "1.2.1" -mockWebServer = "4.10.0" - -#Android Support -android_core_ktx = "1.7.0" -androidx_appcompat = "1.7.0" -material = "1.12.0" -dynamic_animation = "1.0.0" -constraint_motion = "2.1.3" -viewmodel = "2.8.6" -androidx_core_ktx = "1.13.1" +kotlinx-coroutines-test = "1.8.1" #Networking -moshi = "1.14.0" okhttp = "4.12.0" -retrofit = "2.9.0" - -#Compose -compose = "1.5.15" -compose_bom = "2024.09.02" -compose_material_3 = "1.3.0" -compose_activity = "1.5.0" -compose_icons = "1.4.3" -compose_navigation = "2.8.1" -lifecycle_version = "2.8.6" -compose_pagging="3.3.2" - -coil = "2.3.0" +ktor = "3.0.1" + +coil = "3.1.0" lottie = "5.2.0" #Room Database -room = "2.5.2" +room = "2.7.0-alpha13" +sqlite = "2.5.0-SNAPSHOT" + android_youtube_player_version = "12.0.0" @@ -57,104 +36,71 @@ android_youtube_player_version = "12.0.0" kotlin_gradle_plugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlin" } android_gradle_plugin = { group = "com.android.tools.build", name = "gradle", version.ref = "android_gradle_plugin" } detekt-gradle-plugin = { module = "io.gitlab.arturbosch.detekt:detekt-gradle-plugin", version.ref = "detekt" } +serialization = { module = "org.jetbrains.kotlin.plugin.serialization:org.jetbrains.kotlin.plugin.serialization.gradle.plugin", version.ref = "kotlin" } + +com-google-devtools-ksp-gradle-plugin = { module = "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin", version.ref = "ksp" } -#Kover kover-gradle-plugin = { module = "org.jetbrains.kotlinx:kover-gradle-plugin", version.ref = "kover" } -#Coil -coil = { group = "io.coil-kt", name = "coil-compose", version.ref = "coil" } +coil = { group = "io.coil-kt.coil3", name = "coil-compose", version.ref = "coil" } +coil-network-ktor3 = { module = "io.coil-kt.coil3:coil-network-ktor3", version.ref="coil"} -#Lottie lottie = { group = "com.airbnb.android", name = "lottie-compose", version.ref = "lottie" } -# Kotlin kotlin_stdlib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib-jdk7", version.ref = "kotlin" } -kotlin_reflect = { group = "org.jetbrains.kotlin", name = "kotlin-reflect", version.ref = "kotlin" } - -# Android Support -androidx_core = { group = "androidx.core", name = "core-ktx", version.ref = "androidx_core_ktx" } -androidx_appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "androidx_appcompat" } -androidx_dynamicanimation = { group = "androidx.dynamicanimation", name = "dynamicanimation", version.ref = "dynamic_animation" } -# Test junit = { group = "junit", name = "junit", version.ref = "test_junit" } mockk = { group = "io.mockk", name = "mockk", version.ref = "mockk" } mockk_android = { group = "io.mockk", name = "mockk-android", version.ref = "mockk" } viewmodel_test = { group = "androidx.arch.core", name = "core-testing", version.ref = "androidx_core_testing" } coroutines_test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "kotlinx-coroutines-test" } - -# AndroidX Lifecycle -androidx_viewmodel_lifecycle-extensions = { group = "androidx.lifecycle", name = "lifecycle-extensions", version.ref = "viewmodel" } -androidx_common_java = { group = "androidx.lifecycle", name = "lifecycle-reactivestreams", version.ref = "viewmodel" } - -# AndroidX test -androidx_test_core = { group = "androidx.test", name = "core-ktx", version.ref = "androidx_test_core" } -androidx_test_rules = { group = "androidx.test", name = "rules", version.ref = "androidx_test_rules" } -androidx_test_runner = { group = "androidx.test", name = "runner", version.ref = "androidx_test_runner" } -androidx_test_junit_ext = { group = "androidx.test.ext", name = "junit-ktx", version.ref = "androidx_test_junit_ext" } -android_test_mockwebserver = { group = "com.squareup.okhttp3", name = "mockwebserver", version.ref = "mockWebServer" } - -# Google -google_material = { group = "com.google.android.material", name = "material", version.ref = "material" } - -# Compose -compose_bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose_bom" } -compose_ui = { module = "androidx.compose.ui:ui" } -compose_toolingpreview = { module = "androidx.compose.ui:ui-tooling-preview" } -compose_icons = { module = "androidx.compose.material:material-icons-extended" } -compose_lifecycle = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "lifecycle_version" } -compose_material3 = { group = "androidx.compose.material3", name = "material3", version.ref = "compose_material_3" } -compose_navigation = { group = "androidx.navigation", name = "navigation-compose", version.ref = "compose_navigation" } -compose_pagging = { group = "androidx.paging", name = "paging-compose", version.ref = "compose_pagging" } -compose_activity = { module = "androidx.activity:activity-compose" } -compose_ui_tooling = { module = "androidx.compose.ui:ui-tooling" } -compose_ui_test = { module = "androidx.compose.ui:ui-test-junit4" } -compose_manifest = { module = "androidx.compose.ui:ui-test-manifest" } -compose_uitest = { module = "androidx.compose.ui:ui-test" } -compose_junit4 = { module = "androidx.compose.ui:ui-test-junit4" } +navigation-compose = { module = "org.jetbrains.androidx.navigation:navigation-compose", version.ref = "navigation-compose-version" } +paging-compose = { module = "app.cash.paging:paging-compose-common", version.ref = "paging-compose" } # Koin koin_test = { group = "io.insert-koin", name = "koin-test-junit4", version.ref = "koin" } koin_android = { group = "io.insert-koin", name = "koin-android", version.ref = "koin" } -koin_annotations = { group = "io.insert-koin", name = "koin-annotations", version.ref = "koin-annotations-bom" } -koin_compiler = { group = "io.insert-koin", name = "koin-ksp-compiler", version.ref = "koin-annotations-bom" } -koin_compose = { group = "io.insert-koin", name = "koin-androidx-compose", version.ref = "koin" } +koin_core = { group = "io.insert-koin", name = "koin-core", version.ref = "koin" } +koin_compose = { module = "io.insert-koin:koin-compose", version.ref = "koin" } +koin_compose_viewmodel = { module = "io.insert-koin:koin-compose-viewmodel", version.ref = "koin" } #Networking -retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" } -moshi = { group = "com.squareup.moshi", name = "moshi-kotlin", version.ref = "moshi" } -moshi_converter = { group = "com.squareup.retrofit2", name = "converter-moshi", version.ref = "retrofit" } okhttp = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhttp" } interceptor = { group = "com.squareup.okhttp3", name = "logging-interceptor", version.ref = "okhttp" } -compose-material = { group = "androidx.wear.compose", name = "compose-material", version = "1.2.0" } + +ktor_client_core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" } +ktor_client_okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" } +ktor_client_logger = { module = "io.ktor:ktor-client-logging", version.ref = "ktor" } +ktor_client_auth = { module = "io.ktor:ktor-client-auth", version.ref = "ktor" } +ktor_client_darwin = { group = "io.ktor", name = "ktor-client-darwin", version.ref = "ktor" } +ktor_client_content_negotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" } +ktor_client_content_serialization_json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" } #Room -roomRuntime = { group = "androidx.room", name = "room-runtime", version.ref = "room"} -roomCompiler = { group = "androidx.room", name= "room-compiler", version.ref = "room"} -roomKtx = { group = "androidx.room", name = "room-ktx", version.ref = "room"} +room_runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" } +room_compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" } +room_bundled = { group = "androidx.sqlite", name = "sqlite-bundled", version.ref = "sqlite" } android_youtube_player = { group = "com.pierfrancescosoffritti.androidyoutubeplayer", name = "core", version.ref = "android_youtube_player_version" } dokka = { group = "org.jetbrains.dokka", name = "android-documentation-plugin", version.ref = "dokka" } [bundles] -room = ["roomRuntime","roomKtx"] -compose = ["compose.ui", "compose.icons", "compose.material3","compose_pagging", "compose.lifecycle", "compose.navigation", "compose.activity", "compose.ui.tooling"] -composetest = ["compose.uitest", "compose.junit4", "compose.manifest", "compose.ui.test"] -networking = ["retrofit", "moshi", "moshi_converter", "okhttp", "interceptor"] -koin = ["koin_android", "koin_compose"] -test = ["junit", "mockk", "mockk_android", "viewmodel_test", "koin_test","coroutines_test"] -androidSupport = ["androidx_core", "androidx_appcompat", "androidx_dynamicanimation","google_material"] -kotlin = ["androidx_core", "kotlin_stdlib", "kotlin_reflect"] +test = ["junit", "mockk", "mockk_android", "viewmodel_test", "koin_test", "coroutines_test"] [plugins] android_application = { id = "com.android.application", version.ref = "android_gradle_plugin" } android_library = { id = "com.android.library", version.ref = "android_gradle_plugin" } kotlin_android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } -kotlin_kapt = { id = "org.jetbrains.kotlin.kapt", version.ref = "kotlin" } -kotlin_parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref = "kotlin" } -ksp = { id = "com.google.devtools.ksp", version.ref = "ksp"} -dokka = { id = "org.jetbrains.dokka", version.ref = "dokka"} +serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } + +jetbrains-compose = { id = "org.jetbrains.compose", version.ref = "compose_plugin_multiplataform" } +kotlin_multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } +compose_compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } +room = { id = "androidx.room", version.ref = "room" } + +ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } +dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" } kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" } -detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } \ No newline at end of file +buildkonfig_plugin = { id = "com.codingfeline.buildkonfig", version.ref = "buildkonfig" } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e708b1c0..2c352119 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 30be1904..960f6e70 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,8 @@ -#Sat Apr 08 14:40:45 BRT 2023 +#Wed Feb 19 11:41:18 BRT 2025 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip distributionPath=wrapper/dists -zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 4f906e0c..f5feea6d 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,69 +15,104 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +122,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,88 +133,120 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 107acd32..9d21a218 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,8 +13,10 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +27,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,13 +43,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -56,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -75,13 +78,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/iosApp/Configuration/Config.xcconfig b/iosApp/Configuration/Config.xcconfig new file mode 100644 index 00000000..81c20de5 --- /dev/null +++ b/iosApp/Configuration/Config.xcconfig @@ -0,0 +1,3 @@ +TEAM_ID= +BUNDLE_ID=com.codandotv.streamplayerapp.KotlinProject +APP_NAME=KotlinProject \ No newline at end of file diff --git a/iosApp/iosApp.xcodeproj/project.pbxproj b/iosApp/iosApp.xcodeproj/project.pbxproj new file mode 100644 index 00000000..25552509 --- /dev/null +++ b/iosApp/iosApp.xcodeproj/project.pbxproj @@ -0,0 +1,422 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 56; + objects = { + +/* Begin PBXBuildFile section */ + 058557BB273AAA24004C7B11 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 058557BA273AAA24004C7B11 /* Assets.xcassets */; }; + 058557D9273AAEEB004C7B11 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */; }; + 2152FB042600AC8F00CF470E /* iOSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2152FB032600AC8F00CF470E /* iOSApp.swift */; }; + 5BAD97872D7CCDDA00D93987 /* Lottie.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BAD97862D7CCDDA00D93987 /* Lottie.swift */; }; + 5BAD97892D7CCEA700D93987 /* Lottie in Frameworks */ = {isa = PBXBuildFile; productRef = 5BAD97882D7CCEA700D93987 /* Lottie */; }; + 7555FF83242A565900829871 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7555FF82242A565900829871 /* ContentView.swift */; }; +/* 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 = ""; }; + 5BAD97862D7CCDDA00D93987 /* Lottie.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Lottie.swift; sourceTree = ""; }; + 7555FF7B242A565900829871 /* KotlinProject.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = KotlinProject.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 = ( + 5BAD97892D7CCEA700D93987 /* Lottie 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 /* KotlinProject.app */, + ); + name = Products; + sourceTree = ""; + }; + 7555FF7D242A565900829871 /* iosApp */ = { + isa = PBXGroup; + children = ( + 5BAD97862D7CCDDA00D93987 /* Lottie.swift */, + 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 = ( + 5BAD97882D7CCEA700D93987 /* Lottie */, + ); + productName = iosApp; + productReference = 7555FF7B242A565900829871 /* KotlinProject.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 7555FF73242A565900829871 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 1130; + LastUpgradeCheck = 1540; + ORGANIZATIONNAME = orgName; + TargetAttributes = { + 7555FF7A242A565900829871 = { + CreatedOnToolsVersion = 11.3.1; + }; + }; + }; + buildConfigurationList = 7555FF76242A565900829871 /* Build configuration list for PBXProject "iosApp" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 7555FF72242A565900829871; + packageReferences = ( + 5BAD97852D7CCDB400D93987 /* XCRemoteSwiftPackageReference "lottie-spm" */, + ); + productRefGroup = 7555FF7C242A565900829871 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 7555FF7A242A565900829871 /* iosApp */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 7555FF79242A565900829871 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 058557D9273AAEEB004C7B11 /* Preview Assets.xcassets in Resources */, + 058557BB273AAA24004C7B11 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + F36B1CEB2AD83DDC00CB74D5 /* Compile Kotlin Framework */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Compile Kotlin Framework"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "if [ \"YES\" = \"$OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED\" ]; then\n echo \"Skipping Gradle build task invocation due to OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED environment variable set to \\\"YES\\\"\"\n exit 0\nfi\ncd \"$SRCROOT/..\"\n./gradlew :composeApp:embedAndSignAppleFrameworkForXcode\n"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 7555FF77242A565900829871 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2152FB042600AC8F00CF470E /* iOSApp.swift in Sources */, + 7555FF83242A565900829871 /* ContentView.swift in Sources */, + 5BAD97872D7CCDDA00D93987 /* Lottie.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 7555FFA3242A565B00829871 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = AB3632DC29227652001CCB65 /* Config.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.3; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 7555FFA4242A565B00829871 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = AB3632DC29227652001CCB65 /* Config.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.3; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 7555FFA6242A565B00829871 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\""; + DEVELOPMENT_TEAM = "${TEAM_ID}"; + ENABLE_PREVIEWS = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)\n$(SRCROOT)/../composeApp/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)", + ); + INFOPLIST_FILE = iosApp/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 15.3; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "${BUNDLE_ID}${TEAM_ID}"; + PRODUCT_NAME = "${APP_NAME}"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 7555FFA7242A565B00829871 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\""; + DEVELOPMENT_TEAM = "${TEAM_ID}"; + ENABLE_PREVIEWS = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)\n$(SRCROOT)/../composeApp/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)", + ); + INFOPLIST_FILE = iosApp/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 15.3; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "${BUNDLE_ID}${TEAM_ID}"; + PRODUCT_NAME = "${APP_NAME}"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 7555FF76242A565900829871 /* Build configuration list for PBXProject "iosApp" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7555FFA3242A565B00829871 /* Debug */, + 7555FFA4242A565B00829871 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 7555FFA5242A565B00829871 /* Build configuration list for PBXNativeTarget "iosApp" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7555FFA6242A565B00829871 /* Debug */, + 7555FFA7242A565B00829871 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + 5BAD97852D7CCDB400D93987 /* XCRemoteSwiftPackageReference "lottie-spm" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/airbnb/lottie-spm.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 4.5.1; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 5BAD97882D7CCEA700D93987 /* Lottie */ = { + isa = XCSwiftPackageProductDependency; + package = 5BAD97852D7CCDB400D93987 /* XCRemoteSwiftPackageReference "lottie-spm" */; + productName = Lottie; + }; +/* End XCSwiftPackageProductDependency section */ + }; + rootObject = 7555FF73242A565900829871 /* Project object */; +} diff --git a/iosApp/iosApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/iosApp/iosApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..919434a6 --- /dev/null +++ b/iosApp/iosApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/iosApp/iosApp.xcodeproj/project.xcworkspace/xcuserdata/pedroalvarez.xcuserdatad/UserInterfaceState.xcuserstate b/iosApp/iosApp.xcodeproj/project.xcworkspace/xcuserdata/pedroalvarez.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 00000000..82332d93 Binary files /dev/null and b/iosApp/iosApp.xcodeproj/project.xcworkspace/xcuserdata/pedroalvarez.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/iosApp/iosApp.xcodeproj/xcuserdata/pedroalvarez.xcuserdatad/xcschemes/xcschememanagement.plist b/iosApp/iosApp.xcodeproj/xcuserdata/pedroalvarez.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 00000000..56b5955f --- /dev/null +++ b/iosApp/iosApp.xcodeproj/xcuserdata/pedroalvarez.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SchemeUserState + + iosApp.xcscheme_^#shared#^_ + + orderHint + 0 + + + + diff --git a/iosApp/iosApp/Assets.xcassets/AccentColor.colorset/Contents.json b/iosApp/iosApp/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 00000000..ee7e3ca0 --- /dev/null +++ b/iosApp/iosApp/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} \ No newline at end of file diff --git a/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/Contents.json b/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..8edf56e7 --- /dev/null +++ b/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/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/app-icon-1024.png b/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/app-icon-1024.png new file mode 100644 index 00000000..53fc536f Binary files /dev/null and b/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/app-icon-1024.png differ diff --git a/iosApp/iosApp/Assets.xcassets/Contents.json b/iosApp/iosApp/Assets.xcassets/Contents.json new file mode 100644 index 00000000..4aa7c535 --- /dev/null +++ b/iosApp/iosApp/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} \ No newline at end of file diff --git a/iosApp/iosApp/ContentView.swift b/iosApp/iosApp/ContentView.swift new file mode 100644 index 00000000..fad7f5d8 --- /dev/null +++ b/iosApp/iosApp/ContentView.swift @@ -0,0 +1,21 @@ +import UIKit +import SwiftUI +import streamplayerapp + +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/iosApp/iosApp/Info.plist b/iosApp/iosApp/Info.plist new file mode 100644 index 00000000..412e3781 --- /dev/null +++ b/iosApp/iosApp/Info.plist @@ -0,0 +1,50 @@ + + + + + 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 + + + diff --git a/iosApp/iosApp/Lottie.swift b/iosApp/iosApp/Lottie.swift new file mode 100644 index 00000000..dbd28a6f --- /dev/null +++ b/iosApp/iosApp/Lottie.swift @@ -0,0 +1,60 @@ +import Lottie +import UIKit +import streamplayerapp + +class LottieViewProviderImpl : LottieViewProvider { + func provideLottieView(lottieAnimationJson: String,onAnimationFinish: @escaping () -> Void) -> UIView { + let lottieView = LottieView() + lottieView.setupLottieAnimationView( + animationContentJson: lottieAnimationJson, + onAnimationFinished: onAnimationFinish + ) + return lottieView + } +} +class LottieView : UIView { + + private let animationView: LottieAnimationView + var onAnimationFinished: (() -> Void)? + + override init(frame: CGRect) { + animationView = LottieAnimationView() + super.init(frame: frame) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented.") + } + + func setupLottieAnimationView(animationContentJson: String, onAnimationFinished: @escaping () -> Void) { + self.onAnimationFinished = onAnimationFinished + + animationView.contentMode = .scaleAspectFit + addSubview(animationView) + + animationView.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + animationView.leftAnchor.constraint(equalTo: leftAnchor), + animationView.rightAnchor.constraint(equalTo: rightAnchor), + animationView.topAnchor.constraint(equalTo: topAnchor), + animationView.bottomAnchor.constraint(equalTo: bottomAnchor) + ]) + + animationView.loopMode = .playOnce // Toca apenas uma vez + animationView.frame = bounds + + if let animation = loadLottieAnimation(from: animationContentJson) { + animationView.animation = animation + animationView.play { finished in + if finished { + self.onAnimationFinished?() // Chama o callback quando terminar + } + } + } + } + + func loadLottieAnimation(from jsonString: String) -> LottieAnimation? { + guard let data = jsonString.data(using: .utf8) else { return nil } + return try? JSONDecoder().decode(LottieAnimation.self, from: data) + } +} diff --git a/iosApp/iosApp/Lottie/Lottie.swift b/iosApp/iosApp/Lottie/Lottie.swift new file mode 100644 index 00000000..4f0144d0 --- /dev/null +++ b/iosApp/iosApp/Lottie/Lottie.swift @@ -0,0 +1,56 @@ +import Lottie +import UIKit +import streamplayerapp + +class LottieViewProviderImpl : LottieViewProvider { + func provideLottieView(lottieAnimationJson: String) -> UIView { + let lottieView = LottieView() + lottieView.setupLottieAnimationView( + animationContentJson: lottieAnimationJson + ) + return lottieView + } +} + +class LottieView : UIView { + + private let animationView: LottieAnimationView + + override init(frame: CGRect) { + animationView = LottieAnimationView() + + super.init(frame: frame) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented.") + } + + func setupLottieAnimationView(animationContentJson: String) { + + animationView.contentMode = .scaleAspectFit + + addSubview(animationView) + + animationView.translatesAutoresizingMaskIntoConstraints = false + + animationView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true + animationView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true + animationView.topAnchor.constraint(equalTo: topAnchor).isActive = true + animationView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true + + animationView.loopMode = .loop + animationView.frame = bounds + + if let animation = loadLottieAnimation(from: animationContentJson) { + animationView.animation = animation + animationView.loopMode = .loop + animationView.play() + } + } + + func loadLottieAnimation(from jsonString: String) -> LottieAnimation? { + guard let data = jsonString.data(using: .utf8) else { return nil } + return try? JSONDecoder().decode(LottieAnimation.self, from: data) + } +} diff --git a/iosApp/iosApp/Preview Content/Preview Assets.xcassets/Contents.json b/iosApp/iosApp/Preview Content/Preview Assets.xcassets/Contents.json new file mode 100644 index 00000000..4aa7c535 --- /dev/null +++ b/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/iosApp/iosApp/iOSApp.swift b/iosApp/iosApp/iOSApp.swift new file mode 100644 index 00000000..dec7c719 --- /dev/null +++ b/iosApp/iosApp/iOSApp.swift @@ -0,0 +1,16 @@ +import SwiftUI +import streamplayerapp + +@main +struct iOSApp: App { + + init() { + KoinIosHelper().doInitKoin(lottieViewProvider: LottieViewProviderImpl()) + } + + var body: some Scene { + WindowGroup { + ContentView() + } + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 2e3a17f0..7bbc2720 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,4 +1,5 @@ -@file:Suppress("UnstableApiUsage") +rootProject.name = "StreamPlayerApp-KMP" + pluginManagement { includeBuild("build-logic") repositories { @@ -14,11 +15,12 @@ dependencyResolutionManagement { mavenCentral() maven { setUrl("https://jitpack.io") } maven(url = uri("https://oss.sonatype.org/content/repositories/snapshots/")) + } } -include(":app") +include(":composeApp") include(":feature-list-streams") include(":core-shared") include(":core-networking") @@ -26,6 +28,8 @@ include(":core-shared-ui") include(":core-navigation") include(":feature-profile") include(":core-local-storage") -include(":feature-favorites") +include(":feature-detail") +include(":feature-search") + -enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") \ No newline at end of file +enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")