web-app bug fixes

This commit is contained in:
shabinder 2021-03-09 17:45:22 +05:30
parent 0d42ea545c
commit 601d8135db
16 changed files with 181 additions and 36 deletions

View File

@ -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)
}
}

View File

@ -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")
}
}
}

View File

@ -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
)

View File

@ -0,0 +1,7 @@
package com.shabinder.common.models.wynk
data class HtDataWynk(
val cutName: String,
val previewUrl: String,
val vcode: String
)

View File

@ -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<String>,
val downloadPrice: String,
val downloadUrl: String,
val duration: Int, //in Seconds
val exclusive: Boolean,
val formats: List<String>,
val htData: List<HtDataWynk>,
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
)

View File

@ -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<String>,
val itemTypes: List<String>, //Songs , etc
val items: List<ItemWynk>,
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<SingerWynk>,
val smallImage: String,
val title: String,
val total: Int,
val type: String
)

View File

@ -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
)

View File

@ -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 {

View File

@ -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"))

View File

@ -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<AppProps, RState>(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

View File

@ -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<T>,
initialState: S
) : RenderableRootComponent<T, S>(props,initialState) {
) : RComponent<RenderableComponent.Props<T>, RenderableComponent.State<S>>(props) {
protected abstract val stateFlow: Flow<S>
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<T : Any> : RProps {
var model: T
}
class State<S>(
var data: S
):RState
}

View File

@ -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<Subscription<*>>()
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 <T : Any> subscribe(subscription: Subscription<T>) {

View File

@ -9,3 +9,9 @@ fun <M : Any, T : RenderableRootComponent<M, *>> RBuilder.renderableChild(clazz:
attrs.model = model
}
}
fun <M : Any, T : RenderableComponent<M, *>> RBuilder.renderableChild(clazz: KClass<out T>, model: M) {
child(clazz) {
key = model.uniqueId().toString()
attrs.model = model
}
}

View File

@ -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<SpotiFlyerMain>,
override val stateFlow: Flow<State> = props.model.models.map { State(it) }
) : RenderableComponent<SpotiFlyerMain, HomeScreen.State>(
) : RenderableComponent<SpotiFlyerMain, State>(
props,
initialState = State(data = SpotiFlyerMain.State())
initialState = State()
) {
override val stateFlow: Flow<SpotiFlyerMain.State> = 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
}

View File

@ -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<SearchbarProps>("SearchBar"){ props ->
val (link,setLink) = useState(props.link)
styledDiv{
css {
classes = mutableListOf("searchBox")
@ -33,9 +32,10 @@ val searchbar = functionalComponent<SearchbarProps>("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<SearchbarProps>("SearchBar"){ props ->
styledButton {
attrs {
onClickFunction = {
props.search(link)
props.search(props.link)
}
}
css {

View File

@ -13,9 +13,10 @@ import styled.styledDiv
class ListScreen(
props: Props<SpotiFlyerList>,
override val stateFlow: Flow<State> = props.model.models.map { State(it) }
) : RenderableComponent<SpotiFlyerList, ListScreen.State>(props,initialState = State(SpotiFlyerList.State())) {
override val stateFlow: Flow<State> = model.models.map { State(it) }
override fun RBuilder.render() {
styledDiv {
attrs {