diff --git a/build-logic/src/main/java/Config.kt b/build-logic/src/main/java/Config.kt index 0ca766ba..0617bf47 100644 --- a/build-logic/src/main/java/Config.kt +++ b/build-logic/src/main/java/Config.kt @@ -6,9 +6,9 @@ object Config { const val applicationId = "com.codandotv.$appName" val jvmTarget = JvmTarget.JVM_21 val javaVersion = JavaVersion.VERSION_21 - const val compileSdkVersion = 35 + const val compileSdkVersion = 36 const val minSdkVersion = 28 - const val targetSdkVersion = 35 + const val targetSdkVersion = 36 const val versionName = "1.2" const val versionCode = 1 const val testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" diff --git a/build-logic/src/main/java/com.streamplayer.koin-annotations-setup.gradle.kts b/build-logic/src/main/java/com.streamplayer.koin-annotations-setup.gradle.kts new file mode 100644 index 00000000..1a688d6d --- /dev/null +++ b/build-logic/src/main/java/com.streamplayer.koin-annotations-setup.gradle.kts @@ -0,0 +1,53 @@ +import extensions.koinAnnotationsDependency +import extensions.koinCompiler +import extensions.koinCoreDependency +import org.gradle.api.artifacts.VersionCatalog +import org.gradle.api.artifacts.VersionCatalogsExtension +import org.gradle.kotlin.dsl.getByType +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +val libs: VersionCatalog = extensions.getByType().named("libs") +plugins { + id("org.jetbrains.kotlin.multiplatform") + id("com.google.devtools.ksp") +} + +kotlin { + sourceSets { + commonMain.dependencies { + implementation(libs.koinCoreDependency()) + api(libs.koinAnnotationsDependency()) + } + } + + // KSP Common sourceSet + sourceSets.named("commonMain").configure { + kotlin.srcDir("build/generated/ksp/metadata/commonMain/kotlin") + } +} + +// KSP Tasks +dependencies { + add("kspCommonMainMetadata", libs.koinCompiler()) +} + + +// WORKAROUND: ADD this dependsOn("kspCommonMainKotlinMetadata") instead of above dependencies +tasks.withType().configureEach { + if (name != "kspCommonMainKotlinMetadata") { + dependsOn("kspCommonMainKotlinMetadata") + } +} + +afterEvaluate { + tasks.filter { + it.name.contains("SourcesJar", true) + }.forEach { + println("SourceJarTask====>${it.name}") + it.dependsOn("kspCommonMainKotlinMetadata") + } +} + +ksp { + arg("KOIN_CONFIG_CHECK", "true") +} \ No newline at end of file diff --git a/build-logic/src/main/java/extensions/VersionCatalog.kt b/build-logic/src/main/java/extensions/VersionCatalog.kt index fcfdaf10..8437cea6 100644 --- a/build-logic/src/main/java/extensions/VersionCatalog.kt +++ b/build-logic/src/main/java/extensions/VersionCatalog.kt @@ -12,5 +12,5 @@ internal fun VersionCatalog.koinAnnotationsDependency() = findLibrary("koin_anno internal fun VersionCatalog.koinComposeDependency() = findLibrary("koin_compose").get() -internal fun VersionCatalog.koinCompiler() = findLibrary("koin_ksp_compiler").get() +internal fun VersionCatalog.koinCompiler() = findLibrary("koin-ksp-compiler").get() diff --git a/composeApp/src/androidMain/kotlin/com.codandotv.streamplayerapp/presentation/MainActivity.kt b/composeApp/src/androidMain/kotlin/com.codandotv.streamplayerapp/presentation/MainActivity.kt index 40c2663c..679bd2b6 100644 --- a/composeApp/src/androidMain/kotlin/com.codandotv.streamplayerapp/presentation/MainActivity.kt +++ b/composeApp/src/androidMain/kotlin/com.codandotv.streamplayerapp/presentation/MainActivity.kt @@ -3,6 +3,7 @@ package com.codandotv.streamplayerapp.presentation import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent +import androidx.core.view.WindowCompat import com.codandotv.streamplayerapp.StreamPlayerApp import com.google.firebase.Firebase import com.google.firebase.initialize @@ -14,6 +15,7 @@ class MainActivity : ComponentActivity() { super.onCreate(savedInstanceState) Firebase.initialize(this) requestNotificationPermission() + setContent { StreamPlayerApp() } diff --git a/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCarousel.kt b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCarousel.kt index fb47bacd..1e6e1b76 100644 --- a/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCarousel.kt +++ b/core-shared-ui/src/commonMain/kotlin/com/codandotv/streamplayerapp/core_shared_ui/widget/StreamsCarousel.kt @@ -15,11 +15,10 @@ import androidx.compose.ui.text.font.FontWeight 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 app.cash.paging.compose.collectAsLazyPagingItems +import app.cash.paging.compose.itemContentType +import app.cash.paging.compose.itemKey import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.emptyFlow @Composable fun StreamsCarousel( diff --git a/feature-list-streams/src/commonMain/kotlin/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 index c8691035..55154c58 100644 --- a/feature-list-streams/src/commonMain/kotlin/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 @@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.CircularProgressIndicator @@ -46,7 +47,9 @@ fun ListStreamsScreen( val baseScrollState = rememberScrollState() Scaffold( - modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), + modifier = Modifier + .statusBarsPadding() + .nestedScroll(scrollBehavior.nestedScrollConnection), topBar = { StreamPlayerTopBar( scrollBehavior = scrollBehavior, diff --git a/feature-search/build.gradle.kts b/feature-search/build.gradle.kts index f6e6662f..91d24b35 100644 --- a/feature-search/build.gradle.kts +++ b/feature-search/build.gradle.kts @@ -4,6 +4,7 @@ plugins { id("com.streamplayer.kmp-library") alias(libs.plugins.jetbrains.compose) alias(libs.plugins.compose.compiler) + id("com.streamplayer.koin-annotations-setup") } kotlin { 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 index aa4ac25f..ea68be71 100644 --- 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 @@ -7,13 +7,16 @@ import io.ktor.client.HttpClient import io.ktor.client.call.body import io.ktor.client.request.get import io.ktor.client.request.url +import org.koin.core.annotation.Factory +import org.koin.core.annotation.Provided interface MostPopularMoviesService { suspend fun getPopular(): NetworkResponse } +@Factory(binds = [MostPopularMoviesService::class]) class MostPopularMoviesServiceImpl( - private val client: HttpClient + @Provided private val client: HttpClient ) : MostPopularMoviesService { override suspend fun getPopular(): NetworkResponse = client.safeRequest { 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 index 1020971f..8bff2425 100644 --- 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 @@ -6,13 +6,17 @@ import com.codandotv.streamplayerapp.feature_search.data.model.ListSearchStreamR import io.ktor.client.HttpClient import io.ktor.client.request.parameter import io.ktor.client.request.url +import org.koin.core.annotation.Factory +import org.koin.core.annotation.Provided +import org.koin.meta.annotations.ExternalDefinition interface SearchStreamService { suspend fun getSearch(query: String): NetworkResponse } +@Factory(binds = [SearchStreamService::class]) class SearchStreamServiceImpl( - private val client: HttpClient + @Provided private val client: HttpClient ) : SearchStreamService { override suspend fun getSearch(query: String): NetworkResponse = client.safeRequest { diff --git a/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/datasource/MostPopularMoviesDataSource.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/datasource/MostPopularMoviesDataSource.kt index b074864d..556be8c9 100644 --- a/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/datasource/MostPopularMoviesDataSource.kt +++ b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/datasource/MostPopularMoviesDataSource.kt @@ -4,11 +4,13 @@ import com.codandotv.streamplayerapp.core_networking.handleError.toFlow import com.codandotv.streamplayerapp.feature_search.data.model.ListSearchStreamResponse import com.codandotv.streamplayerapp.feature_search.data.api.MostPopularMoviesService import kotlinx.coroutines.flow.Flow +import org.koin.core.annotation.Factory interface MostPopularMoviesDataSource { suspend fun getMostPopularMovies(): Flow } +@Factory(binds = [MostPopularMoviesDataSource::class]) class MostPopularMoviesDataSourceImpl( private val service: MostPopularMoviesService ) : MostPopularMoviesDataSource { diff --git a/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/datasource/SearchStreamDataSource.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/datasource/SearchStreamDataSource.kt index e3d65b3b..bb0606f2 100644 --- a/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/datasource/SearchStreamDataSource.kt +++ b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/datasource/SearchStreamDataSource.kt @@ -4,10 +4,13 @@ import com.codandotv.streamplayerapp.core_networking.handleError.toFlow import com.codandotv.streamplayerapp.feature_search.data.model.ListSearchStreamResponse import com.codandotv.streamplayerapp.feature_search.data.api.SearchStreamService import kotlinx.coroutines.flow.Flow +import org.koin.core.annotation.Factory interface SearchStreamDataSource { suspend fun getMovieSearch(query: String): Flow } + +@Factory(binds = [SearchStreamDataSource::class]) class SearchStreamDataSourceImpl( private val service: SearchStreamService ): SearchStreamDataSource { diff --git a/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/repository/MostPopularMoviesRepository.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/repository/MostPopularMoviesRepository.kt index 5fbf97e5..7a630a48 100644 --- a/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/repository/MostPopularMoviesRepository.kt +++ b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/repository/MostPopularMoviesRepository.kt @@ -3,11 +3,13 @@ package com.codandotv.streamplayerapp.feature_search.data.repository import com.codandotv.streamplayerapp.feature_search.data.model.ListSearchStreamResponse import com.codandotv.streamplayerapp.feature_search.data.datasource.MostPopularMoviesDataSource import kotlinx.coroutines.flow.Flow +import org.koin.core.annotation.Factory interface MostPopularMoviesRepository { suspend fun getMostPopularMovies(): Flow } +@Factory(binds = [MostPopularMoviesRepository::class]) class MostPopularMoviesRepositoryImpl( private val dataSource: MostPopularMoviesDataSource ) : MostPopularMoviesRepository { diff --git a/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/repository/SearchStreamRepository.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/repository/SearchStreamRepository.kt index 9b101176..6358c928 100644 --- a/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/repository/SearchStreamRepository.kt +++ b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/data/repository/SearchStreamRepository.kt @@ -3,11 +3,14 @@ package com.codandotv.streamplayerapp.feature_search.data.repository import com.codandotv.streamplayerapp.feature_search.data.datasource.SearchStreamDataSource import com.codandotv.streamplayerapp.feature_search.data.model.ListSearchStreamResponse import kotlinx.coroutines.flow.Flow +import org.koin.core.annotation.Factory interface SearchStreamRepository { - suspend fun getMovieSearch(query: String) : Flow + suspend fun getMovieSearch(query: String): Flow } + +@Factory(binds = [SearchStreamRepository::class]) class SearchStreamRepositoryImp( private val dataSource: SearchStreamDataSource ) : 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 index 7848bf61..f6741e4e 100644 --- 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 @@ -1,43 +1,8 @@ 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 +import org.koin.core.annotation.ComponentScan +import org.koin.core.annotation.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()) } - } -} +@Module +@ComponentScan("com.codandotv.streamplayerapp.feature_search") +class SearchModule diff --git a/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/MostPopularMoviesUseCase.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/MostPopularMoviesUseCase.kt index b924c782..4afdd79f 100644 --- a/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/MostPopularMoviesUseCase.kt +++ b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/MostPopularMoviesUseCase.kt @@ -3,11 +3,13 @@ package com.codandotv.streamplayerapp.feature_search.domain import com.codandotv.streamplayerapp.feature_search.data.model.ListSearchStreamResponse import com.codandotv.streamplayerapp.feature_search.data.repository.MostPopularMoviesRepository import kotlinx.coroutines.flow.Flow +import org.koin.core.annotation.Factory interface MostPopularMoviesUseCase { suspend operator fun invoke(): Flow } +@Factory(binds = [MostPopularMoviesUseCase::class]) class MostPopularMoviesUseCaseImpl( val repository: MostPopularMoviesRepository ) : MostPopularMoviesUseCase { diff --git a/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/SearchUseCase.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/SearchUseCase.kt index 075f7bfe..28b77f76 100644 --- a/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/SearchUseCase.kt +++ b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/domain/SearchUseCase.kt @@ -3,11 +3,13 @@ package com.codandotv.streamplayerapp.feature_search.domain import com.codandotv.streamplayerapp.feature_search.data.model.ListSearchStreamResponse import com.codandotv.streamplayerapp.feature_search.data.repository.SearchStreamRepository import kotlinx.coroutines.flow.Flow +import org.koin.core.annotation.Factory interface SearchUseCase { suspend operator fun invoke(query:String): Flow } +@Factory(binds = [SearchUseCase::class]) class SearchUseCaseImpl(val repository: SearchStreamRepository) : SearchUseCase { override suspend operator fun invoke(query:String): Flow { return repository.getMovieSearch(query = query) 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 index f7a36db7..a46a09fd 100644 --- 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 @@ -8,12 +8,15 @@ 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 +import org.koin.ksp.generated.module @OptIn(KoinExperimentalAPI::class) fun NavGraphBuilder.searchStreamsNavGraph(navController: NavHostController) { composable(Routes.SEARCH) { _ -> rememberKoinModules { - listOf(SearchModule.module) + listOf( + SearchModule().module + ) } SearchScreen( navController = navController, diff --git a/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchViewModel.kt b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchViewModel.kt index 8a4314b7..964a49d4 100644 --- a/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchViewModel.kt +++ b/feature-search/src/commonMain/kotlin/com/codandotv/streamplayerapp/feature_search/presentation/screens/SearchViewModel.kt @@ -13,7 +13,9 @@ 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 +@KoinViewModel class SearchViewModel( private val searchUseCase: SearchUseCase, private val mostPopularMoviesUseCase: MostPopularMoviesUseCase diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0896faa0..e75e8b2c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,8 @@ [versions] kotlin = "2.3.10" -android_gradle_plugin = "8.7.3" -koin = "4.1.1" +android_gradle_plugin = "8.9.1" +koin = "4.2.0" +koin-annotations = "2.3.1" ksp = "2.3.5" kotzilla = "2.0.8" lifecycle-viewmodel-compose-version = "2.9.6" @@ -85,6 +86,8 @@ androidx-camera-view = { module = "androidx.camera:camera-view", version.ref = " 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_core = { group = "io.insert-koin", name = "koin-core", version.ref = "koin" } +koin-annotations = { module = "io.insert-koin:koin-annotations", version.ref = "koin-annotations" } +koin-ksp-compiler = { module = "io.insert-koin:koin-ksp-compiler", version.ref = "koin-annotations" } koin_compose = { module = "io.insert-koin:koin-compose", version.ref = "koin" } koin_compose_viewmodel = { module = "io.insert-koin:koin-compose-viewmodel", version.ref = "koin" }