From 601d8135dbeee92936291610dc03e1ae827d7502 Mon Sep 17 00:00:00 2001 From: shabinder Date: Tue, 9 Mar 2021 17:45:22 +0530 Subject: [PATCH] web-app bug fixes --- .../kotlin/multiplatform-setup.gradle.kts | 4 ++- common/data-models/build.gradle.kts | 1 + .../common/models/wynk/AlbumRefWynk.kt | 9 +++++ .../common/models/wynk/HtDataWynk.kt | 7 ++++ .../shabinder/common/models/wynk/ItemWynk.kt | 36 +++++++++++++++++++ .../common/models/wynk/ShortURLWynk.kt | 36 +++++++++++++++++++ .../common/models/wynk/SingerWynk.kt | 10 ++++++ common/dependency-injection/build.gradle.kts | 9 ++--- web-app/build.gradle.kts | 2 ++ web-app/src/main/kotlin/App.kt | 3 +- .../main/kotlin/extras/RenderableComponent.kt | 35 ++++++++++++++---- .../kotlin/extras/RenderableRootComponent.kt | 14 +++----- web-app/src/main/kotlin/extras/Utils.kt | 6 ++++ web-app/src/main/kotlin/home/HomeScreen.kt | 32 ++++++++++++----- web-app/src/main/kotlin/home/Searchbar.kt | 10 +++--- web-app/src/main/kotlin/list/ListScreen.kt | 3 +- 16 files changed, 181 insertions(+), 36 deletions(-) create mode 100644 common/data-models/src/commonMain/kotlin/com/shabinder/common/models/wynk/AlbumRefWynk.kt create mode 100644 common/data-models/src/commonMain/kotlin/com/shabinder/common/models/wynk/HtDataWynk.kt create mode 100644 common/data-models/src/commonMain/kotlin/com/shabinder/common/models/wynk/ItemWynk.kt create mode 100644 common/data-models/src/commonMain/kotlin/com/shabinder/common/models/wynk/ShortURLWynk.kt create mode 100644 common/data-models/src/commonMain/kotlin/com/shabinder/common/models/wynk/SingerWynk.kt diff --git a/buildSrc/src/main/kotlin/multiplatform-setup.gradle.kts b/buildSrc/src/main/kotlin/multiplatform-setup.gradle.kts index 6c610f15..68d7a67d 100644 --- a/buildSrc/src/main/kotlin/multiplatform-setup.gradle.kts +++ b/buildSrc/src/main/kotlin/multiplatform-setup.gradle.kts @@ -21,7 +21,7 @@ kotlin { sourceSets { named("commonMain") { dependencies { - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2") + } } @@ -33,6 +33,7 @@ kotlin { implementation(compose.material) implementation(compose.foundation) implementation(compose.materialIconsExtended) + implementation(Decompose.decompose) implementation(Decompose.extensionsCompose) } } @@ -44,6 +45,7 @@ kotlin { implementation(compose.material) implementation(compose.desktop.common) implementation(compose.materialIconsExtended) + implementation(Decompose.decompose) implementation(Decompose.extensionsCompose) } } diff --git a/common/data-models/build.gradle.kts b/common/data-models/build.gradle.kts index 54c39f78..f17414c4 100644 --- a/common/data-models/build.gradle.kts +++ b/common/data-models/build.gradle.kts @@ -11,6 +11,7 @@ kotlin { dependencies { api("dev.icerock.moko:parcelize:0.6.0") api("org.jetbrains.kotlinx:kotlinx-serialization-json:1.1.0") + api("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.3") } } } diff --git a/common/data-models/src/commonMain/kotlin/com/shabinder/common/models/wynk/AlbumRefWynk.kt b/common/data-models/src/commonMain/kotlin/com/shabinder/common/models/wynk/AlbumRefWynk.kt new file mode 100644 index 00000000..7b46e3db --- /dev/null +++ b/common/data-models/src/commonMain/kotlin/com/shabinder/common/models/wynk/AlbumRefWynk.kt @@ -0,0 +1,9 @@ +package com.shabinder.common.models.wynk + +data class AlbumRefWynk( + val id: String, + val largeImage: String, + val smallImage: String, + val title: String, + val type: String +) \ No newline at end of file diff --git a/common/data-models/src/commonMain/kotlin/com/shabinder/common/models/wynk/HtDataWynk.kt b/common/data-models/src/commonMain/kotlin/com/shabinder/common/models/wynk/HtDataWynk.kt new file mode 100644 index 00000000..dd406287 --- /dev/null +++ b/common/data-models/src/commonMain/kotlin/com/shabinder/common/models/wynk/HtDataWynk.kt @@ -0,0 +1,7 @@ +package com.shabinder.common.models.wynk + +data class HtDataWynk( + val cutName: String, + val previewUrl: String, + val vcode: String +) \ No newline at end of file diff --git a/common/data-models/src/commonMain/kotlin/com/shabinder/common/models/wynk/ItemWynk.kt b/common/data-models/src/commonMain/kotlin/com/shabinder/common/models/wynk/ItemWynk.kt new file mode 100644 index 00000000..43f23203 --- /dev/null +++ b/common/data-models/src/commonMain/kotlin/com/shabinder/common/models/wynk/ItemWynk.kt @@ -0,0 +1,36 @@ +package com.shabinder.common.models.wynk + +data class ItemWynk( + val album: String, + val albumRef: AlbumRefWynk, + val basicShortUrl: String, + val branchUrl: String, + val contentLang: String, + val contentState: String, + val count: Int, + val cues: List, + val downloadPrice: String, + val downloadUrl: String, + val duration: Int, //in Seconds + val exclusive: Boolean, + val formats: List, + val htData: List, + val id: String, + val isHt: Boolean, + val itemContentLang: String, + val keywords: String, + val largeImage: String, + val lyrics_avl: String, + val ostreamingUrl: String, + val purchaseUrl: String, + val rentUrl: String, + val serverEtag: String, + val shortUrl: String, + val smallImage: String, //Cover Image after Replacing 120x120 with 720x720 + val subtitle: String, // String : `ArtistName - TrackName` + val subtitleId: String, //ARTIST NAME,artist-id , etc //USE SUBTITLE INSTEAD + val subtitleType: String, // ARTIST etc + val title: String, + val type: String, //Song ,etc + val videoPresent: Boolean +) \ No newline at end of file diff --git a/common/data-models/src/commonMain/kotlin/com/shabinder/common/models/wynk/ShortURLWynk.kt b/common/data-models/src/commonMain/kotlin/com/shabinder/common/models/wynk/ShortURLWynk.kt new file mode 100644 index 00000000..990669c9 --- /dev/null +++ b/common/data-models/src/commonMain/kotlin/com/shabinder/common/models/wynk/ShortURLWynk.kt @@ -0,0 +1,36 @@ +package com.shabinder.common.models.wynk + + + +// Use Kotlinx JSON Parsing as in YT Music +data class ShortURLWynk( + val actualTotal: Int, + val basicShortUrl: String, + val branchUrl: String, + val count: Int, + val downloadUrl: String, + val duration: Int, + val exclusive: Boolean, + val followCount: String, + val id: String, + val isCurated: Boolean, + val isFollowable: Boolean, + val isHt: Boolean, + val itemIds: List, + val itemTypes: List, //Songs , etc + val items: List, + val lang: String, + val largeImage: String, //Cover Image Alternate + val lastUpdated: Long, + val offset: Int, + val owner: String, + val playIcon: Boolean, + val playlistImage: String, //Cover Image + val redesignFeaturedImage: String, + val shortUrl: String, + val singers: List, + val smallImage: String, + val title: String, + val total: Int, + val type: String +) \ No newline at end of file diff --git a/common/data-models/src/commonMain/kotlin/com/shabinder/common/models/wynk/SingerWynk.kt b/common/data-models/src/commonMain/kotlin/com/shabinder/common/models/wynk/SingerWynk.kt new file mode 100644 index 00000000..ef439d51 --- /dev/null +++ b/common/data-models/src/commonMain/kotlin/com/shabinder/common/models/wynk/SingerWynk.kt @@ -0,0 +1,10 @@ +package com.shabinder.common.models.wynk + +data class SingerWynk( + val id: String, + val isCurated: Boolean, + val packageId: String, + val smallImage: String, + val title: String, + val type: String +) \ No newline at end of file diff --git a/common/dependency-injection/build.gradle.kts b/common/dependency-injection/build.gradle.kts index 957729bc..d34854e1 100644 --- a/common/dependency-injection/build.gradle.kts +++ b/common/dependency-injection/build.gradle.kts @@ -13,7 +13,6 @@ kotlin { implementation(project(":common:data-models")) implementation(project(":common:database")) implementation(project(":fuzzywuzzy:app")) - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.1.0") implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.1.1") implementation(Ktor.clientCore) @@ -26,17 +25,17 @@ kotlin { api(Koin.test) api(Extras.kermit) - api(Extras.youtubeDownloader) - api(Extras.mp3agic) } } androidMain { dependencies{ implementation(compose.materialIconsExtended) + implementation(Koin.android) implementation(Ktor.clientAndroid) implementation(Extras.Android.fetch) - implementation(Koin.android) implementation(Extras.Android.razorpay) + api(Extras.youtubeDownloader) + api(Extras.mp3agic) //api(files("$rootDir/libs/mobile-ffmpeg.aar")) } } @@ -45,6 +44,8 @@ kotlin { implementation(compose.materialIconsExtended) implementation(Ktor.clientApache) implementation(Ktor.slf4j) + api(Extras.youtubeDownloader) + api(Extras.mp3agic) } } jsMain { diff --git a/web-app/build.gradle.kts b/web-app/build.gradle.kts index ac0baecf..cb001435 100644 --- a/web-app/build.gradle.kts +++ b/web-app/build.gradle.kts @@ -17,7 +17,9 @@ dependencies { implementation(Decompose.decompose) implementation(Koin.core) implementation(MVIKotlin.mvikotlin) + implementation(MVIKotlin.coroutines) implementation(MVIKotlin.mvikotlinMain) + implementation(MVIKotlin.mvikotlinLogging) implementation(project(":common:root")) implementation(project(":common:main")) implementation(project(":common:list")) diff --git a/web-app/src/main/kotlin/App.kt b/web-app/src/main/kotlin/App.kt index 8f44ccff..08ce4c41 100644 --- a/web-app/src/main/kotlin/App.kt +++ b/web-app/src/main/kotlin/App.kt @@ -4,6 +4,7 @@ import com.arkivanov.decompose.lifecycle.LifecycleRegistry import com.arkivanov.decompose.lifecycle.destroy import com.arkivanov.decompose.lifecycle.resume import com.arkivanov.mvikotlin.core.store.StoreFactory +import com.arkivanov.mvikotlin.logging.store.LoggingStoreFactory import com.arkivanov.mvikotlin.main.store.DefaultStoreFactory import com.shabinder.common.models.DownloadStatus import com.shabinder.common.root.SpotiFlyerRoot @@ -33,7 +34,7 @@ class App(props: AppProps): RComponent(props) { private val root = SpotiFlyerRoot(ctx, object : SpotiFlyerRoot.Dependencies{ - override val storeFactory: StoreFactory = DefaultStoreFactory + override val storeFactory: StoreFactory = LoggingStoreFactory(DefaultStoreFactory) override val fetchPlatformQueryResult = dependencies.fetchPlatformQueryResult override val directories = dependencies.directories override val database: Database? = directories.db diff --git a/web-app/src/main/kotlin/extras/RenderableComponent.kt b/web-app/src/main/kotlin/extras/RenderableComponent.kt index 0c9aea86..1b0fb87d 100644 --- a/web-app/src/main/kotlin/extras/RenderableComponent.kt +++ b/web-app/src/main/kotlin/extras/RenderableComponent.kt @@ -1,27 +1,48 @@ package extras +import kotlinx.coroutines.* import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.launch +import kotlinx.coroutines.flow.collect +import react.RComponent +import react.RProps import react.RState import react.setState abstract class RenderableComponent< T : Any, - S : RState + S : Any >( props: Props, initialState: S -) : RenderableRootComponent(props,initialState) { +) : RComponent, RenderableComponent.State>(props) { protected abstract val stateFlow: Flow + protected val model: T get() = props.model + protected var scope: CoroutineScope = CoroutineScope(Dispatchers.Default) + + init { + state = State(data = initialState) + } override fun componentDidMount() { - super.componentDidMount() + if(!scope.isActive) + scope = CoroutineScope(Dispatchers.Default) scope.launch { - stateFlow.collectLatest { - setState { state = it } + stateFlow.collect { + setState { data = it } } } } + + override fun componentWillUnmount() { + scope.cancel("Component Unmounted") + } + + interface Props : RProps { + var model: T + } + + class State( + var data: S + ):RState } \ No newline at end of file diff --git a/web-app/src/main/kotlin/extras/RenderableRootComponent.kt b/web-app/src/main/kotlin/extras/RenderableRootComponent.kt index f26542c4..58642d24 100644 --- a/web-app/src/main/kotlin/extras/RenderableRootComponent.kt +++ b/web-app/src/main/kotlin/extras/RenderableRootComponent.kt @@ -3,12 +3,7 @@ package extras import com.arkivanov.decompose.value.Value import com.arkivanov.decompose.value.ValueObserver import extras.RenderableRootComponent.Props -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.cancel -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.launch +import kotlinx.coroutines.* import react.RComponent import react.RProps import react.RState @@ -24,15 +19,16 @@ abstract class RenderableRootComponent< protected val model: T get() = props.model private val subscriptions = ArrayList>() - protected lateinit var scope: CoroutineScope + protected var scope: CoroutineScope = CoroutineScope(Dispatchers.Default) init { - state = initialState + this.state = initialState } override fun componentDidMount() { subscriptions.forEach { subscribe(it) } - scope = CoroutineScope(Dispatchers.Default) + if(!scope.isActive) + scope = CoroutineScope(Dispatchers.Default) } private fun subscribe(subscription: Subscription) { diff --git a/web-app/src/main/kotlin/extras/Utils.kt b/web-app/src/main/kotlin/extras/Utils.kt index ba6cb5c5..16a639ea 100644 --- a/web-app/src/main/kotlin/extras/Utils.kt +++ b/web-app/src/main/kotlin/extras/Utils.kt @@ -9,3 +9,9 @@ fun > RBuilder.renderableChild(clazz: attrs.model = model } } +fun > RBuilder.renderableChild(clazz: KClass, model: M) { + child(clazz) { + key = model.uniqueId().toString() + attrs.model = model + } +} diff --git a/web-app/src/main/kotlin/home/HomeScreen.kt b/web-app/src/main/kotlin/home/HomeScreen.kt index 1c40b2b2..012c09a8 100644 --- a/web-app/src/main/kotlin/home/HomeScreen.kt +++ b/web-app/src/main/kotlin/home/HomeScreen.kt @@ -1,9 +1,14 @@ package home import com.shabinder.common.main.SpotiFlyerMain +import com.shabinder.common.main.SpotiFlyerMain.State import extras.RenderableComponent +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.isActive +import kotlinx.coroutines.launch import kotlinx.css.* import react.* import styled.css @@ -11,13 +16,26 @@ import styled.styledDiv class HomeScreen( props: Props, - override val stateFlow: Flow = props.model.models.map { State(it) } -) : RenderableComponent( +) : RenderableComponent( props, - initialState = State(data = SpotiFlyerMain.State()) + initialState = State() ) { + override val stateFlow: Flow = model.models + + override fun componentDidMount() { + if(!scope.isActive) + scope = CoroutineScope(Dispatchers.Default) + scope.launch { + stateFlow.collect { + println("Updating State = $it") + setState { data = it } + } + } + } + override fun RBuilder.render() { + println("Rendering New State = \"${state.data}\" ") styledDiv{ css { display = Display.flex @@ -32,8 +50,10 @@ class HomeScreen( } SearchBar { + println("Search Props ${state.data.link}") link = state.data.link search = model::onLinkSearch + onLinkChange = model::onInputLinkChanged } IconList { @@ -46,10 +66,6 @@ class HomeScreen( isBadge = true } } - - class State( - var data: SpotiFlyerMain.State - ):RState } diff --git a/web-app/src/main/kotlin/home/Searchbar.kt b/web-app/src/main/kotlin/home/Searchbar.kt index d064cc8c..8d31ed62 100644 --- a/web-app/src/main/kotlin/home/Searchbar.kt +++ b/web-app/src/main/kotlin/home/Searchbar.kt @@ -10,6 +10,7 @@ import styled.* external interface SearchbarProps : RProps { var link: String var search:(String)->Unit + var onLinkChange:(String)->Unit } @Suppress("FunctionName") @@ -22,8 +23,6 @@ fun RBuilder.SearchBar(handler:SearchbarProps.() -> Unit) = child(searchbar){ val searchbar = functionalComponent("SearchBar"){ props -> - val (link,setLink) = useState(props.link) - styledDiv{ css { classes = mutableListOf("searchBox") @@ -33,9 +32,10 @@ val searchbar = functionalComponent("SearchBar"){ props -> placeholder = "Search" onChangeFunction = { val target = it.target as HTMLInputElement - setLink(target.value) + props.onLinkChange(target.value) + println(target.value) } - value = link + value = props.link } css { classes = mutableListOf("searchInput") @@ -44,7 +44,7 @@ val searchbar = functionalComponent("SearchBar"){ props -> styledButton { attrs { onClickFunction = { - props.search(link) + props.search(props.link) } } css { diff --git a/web-app/src/main/kotlin/list/ListScreen.kt b/web-app/src/main/kotlin/list/ListScreen.kt index c74d4815..34ae286c 100644 --- a/web-app/src/main/kotlin/list/ListScreen.kt +++ b/web-app/src/main/kotlin/list/ListScreen.kt @@ -13,9 +13,10 @@ import styled.styledDiv class ListScreen( props: Props, - override val stateFlow: Flow = props.model.models.map { State(it) } ) : RenderableComponent(props,initialState = State(SpotiFlyerList.State())) { + override val stateFlow: Flow = model.models.map { State(it) } + override fun RBuilder.render() { styledDiv { attrs {