Web App Dep Updation and Moving to IR backend

This commit is contained in:
shabinder 2021-06-19 23:27:38 +05:30
parent 034aa246d8
commit 2cdb764430
31 changed files with 180 additions and 427 deletions

View File

@ -129,7 +129,7 @@ dependencies {
}
//implementation("com.jakewharton.timber:timber:4.7.1")
implementation("dev.icerock.moko:parcelize:0.6.1")
implementation("dev.icerock.moko:parcelize:0.7.0")
implementation("com.github.shabinder:storage-chooser:2.0.4.45")
implementation("com.google.accompanist:accompanist-insets:0.11.1")

View File

@ -41,7 +41,7 @@ class App: Application(), KoinComponent {
val tracker: Tracker by lazy {
TrackerBuilder.createDefault(
"https://kind-grasshopper-73.telebit.io/matomo/matomo.php", 1)
"https://matomo.spotiflyer.ml/matomo.php", 1)
.build(Matomo.getInstance(this)).apply {
if (BuildConfig.DEBUG) {
/*Timber.plant(DebugTree())
@ -85,7 +85,7 @@ class App: Application(), KoinComponent {
}
// Send Crash Report to self hosted Acrarium (FOSS)
httpSender {
uri = "https://kind-grasshopper-73.telebit.io/acrarium/report"
uri = "https://acrarium.spotiflyer.ml/report"
basicAuthLogin = "sDj2xCKQIxw0dujf"
basicAuthPassword = "O83du0TsgsDJ69zN"
httpMethod = HttpSender.Method.POST

View File

@ -42,7 +42,7 @@ kotlin {
implementation(compose.animation)
implementation(Extras.kermit)
implementation("dev.icerock.moko:parcelize:0.6.1")
implementation("dev.icerock.moko:parcelize:0.7.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0-native-mt") {
@Suppress("DEPRECATION")
isForce = true

View File

@ -34,7 +34,7 @@ kotlin {
jvm("desktop")
android()
js(/*BOTH*/) {
js(BOTH) {
browser()
// nodejs()
}

View File

@ -37,7 +37,7 @@ kotlin {
jvm("desktop")
android()
js(/*BOTH*/) {
js(BOTH) {
browser()
// nodejs()
}
@ -65,7 +65,7 @@ kotlin {
implementation(Extras.kermit)
implementation(Serialization.json)
implementation("co.touchlab:stately-common:1.1.7")
implementation("dev.icerock.moko:parcelize:0.6.1")
implementation("dev.icerock.moko:parcelize:0.7.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0-native-mt") {
@Suppress("DEPRECATION")
isForce = true
@ -102,9 +102,9 @@ kotlin {
named("jsMain") {
dependencies {
implementation(Ktor.clientJs)
implementation("org.jetbrains:kotlin-react:17.0.1-pre.148-kotlin-1.4.30")
implementation("org.jetbrains:kotlin-styled:1.0.0-pre.115-kotlin-1.4.10")
implementation("org.jetbrains:kotlin-react-dom:17.0.1-pre.148-kotlin-1.4.30")
implementation("org.jetbrains.kotlin-wrappers:kotlin-react:17.0.2-pre.213-kotlin-1.5.10")
implementation("org.jetbrains.kotlin-wrappers:kotlin-react-dom:17.0.2-pre.213-kotlin-1.5.10")
implementation("org.jetbrains.kotlin-wrappers:kotlin-styled:5.3.0-pre.213-kotlin-1.5.10")
}
}
if(HostOS.isMac){

View File

@ -17,32 +17,12 @@
package com.shabinder.common.uikit
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.ExtendedFloatingActionButton
import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
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.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
@ -51,7 +31,7 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.arkivanov.decompose.extensions.compose.jetbrains.asState
import com.arkivanov.decompose.extensions.compose.jetbrains.subscribeAsState
import com.shabinder.common.di.Picture
import com.shabinder.common.list.SpotiFlyerList
import com.shabinder.common.models.DownloadStatus
@ -64,7 +44,7 @@ fun SpotiFlyerListContent(
component: SpotiFlyerList,
modifier: Modifier = Modifier
) {
val model by component.models.asState()
val model by component.model.subscribeAsState()
LaunchedEffect(model.errorOccurred) {
/*Handle if Any Exception Occurred*/

View File

@ -17,57 +17,21 @@
package com.shabinder.common.uikit
import androidx.compose.animation.Crossfade
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Card
import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme
import androidx.compose.material.OutlinedButton
import androidx.compose.material.Switch
import androidx.compose.material.SwitchDefaults
import androidx.compose.material.Tab
import androidx.compose.material.TabPosition
import androidx.compose.material.TabRow
import androidx.compose.material.*
import androidx.compose.material.TabRowDefaults.tabIndicatorOffset
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.material.TextFieldDefaults.textFieldColors
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.History
import androidx.compose.material.icons.outlined.Info
import androidx.compose.material.icons.rounded.CardGiftcard
import androidx.compose.material.icons.rounded.Edit
import androidx.compose.material.icons.rounded.Flag
import androidx.compose.material.icons.rounded.Insights
import androidx.compose.material.icons.rounded.Share
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.material.icons.rounded.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
@ -80,7 +44,7 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.arkivanov.decompose.extensions.compose.jetbrains.asState
import com.arkivanov.decompose.extensions.compose.jetbrains.subscribeAsState
import com.shabinder.common.di.Picture
import com.shabinder.common.main.SpotiFlyerMain
import com.shabinder.common.main.SpotiFlyerMain.HomeCategory
@ -89,7 +53,7 @@ import com.shabinder.common.models.methods
@Composable
fun SpotiFlyerMainContent(component: SpotiFlyerMain) {
val model by component.models.asState()
val model by component.model.subscribeAsState()
Column {
SearchPanel(

View File

@ -17,7 +17,7 @@
package com.shabinder.common.models
sealed class CorsProxy(open val url: String) {
data class SelfHostedCorsProxy(override val url: String = "https://kind-grasshopper-73.telebit.io/cors/" /*"https://spotiflyer.azurewebsites.net/"*/) : CorsProxy(url)
data class SelfHostedCorsProxy(override val url: String = "https://cors.spotiflyer.ml/cors/" /*"https://spotiflyer.azurewebsites.net/"*/) : CorsProxy(url)
data class PublicProxyWithExtension(override val url: String = "https://cors.bridged.cc/") : CorsProxy(url)
fun toggle(mode: CorsProxy? = null): CorsProxy {

View File

@ -21,7 +21,7 @@ import com.shabinder.common.di.Dir
import com.shabinder.common.di.currentPlatform
import com.shabinder.common.di.youtubeMp3.Yt1sMp3
import com.shabinder.common.models.AllPlatforms
import io.ktor.client.HttpClient
import io.ktor.client.*
class YoutubeMp3(
override val httpClient: HttpClient,
@ -33,7 +33,7 @@ class YoutubeMp3(
getLinkFromYt1sMp3(videoID)?.let {
logger.i { "Download Link: $it" }
if (currentPlatform is AllPlatforms.Js/* && corsProxy !is CorsProxy.PublicProxyWithExtension*/)
"https://kind-grasshopper-73.telebit.io/cors/$it"
"https://cors.spotiflyer.ml/cors/$it"
// "https://spotiflyer.azurewebsites.net/$it" // Data OUT Limit issue
else it
}

View File

@ -28,7 +28,7 @@ import io.github.shabinder.YoutubeDownloader
import io.github.shabinder.models.YoutubeVideo
import io.github.shabinder.models.formats.Format
import io.github.shabinder.models.quality.AudioQuality
import io.ktor.client.HttpClient
import io.ktor.client.*
class YoutubeProvider(
private val httpClient: HttpClient,
@ -37,7 +37,7 @@ class YoutubeProvider(
) {
val ytDownloader: YoutubeDownloader = YoutubeDownloader(
enableCORSProxy = true,
CORSProxyAddress = "https://kind-grasshopper-73.telebit.io/cors/"
CORSProxyAddress = "https://cors.spotiflyer.ml/cors/"
)
/*
@ -157,7 +157,7 @@ class YoutubeProvider(
val video = ytDownloader.getVideo(searchId)
coverUrl = "https://i.ytimg.com/vi/$searchId/hqdefault.jpg"
val detail = video.videoDetails
val name = detail.title?.replace(detail.author?.toUpperCase() ?: "", "", true)
val name = detail.title?.replace(detail.author?.uppercase() ?: "", "", true)
?: detail.title ?: ""
// logger.i{ detail.toString() }
trackList = listOf(

View File

@ -16,6 +16,8 @@
package com.shabinder.common.di.utils
import io.github.shabinder.TargetPlatforms
import io.github.shabinder.activePlatform
import kotlinx.serialization.json.Json
import kotlin.native.concurrent.ThreadLocal
@ -31,6 +33,7 @@ val json by lazy {
* Removing Illegal Chars from File Name
* **/
fun removeIllegalChars(fileName: String): String {
if (activePlatform is TargetPlatforms.Js) return fileName
val illegalCharArray = charArrayOf(
'/',
'\n',

View File

@ -31,7 +31,7 @@ import kotlinx.coroutines.flow.MutableSharedFlow
interface SpotiFlyerList {
val models: Value<State>
val model: Value<State>
/*
* Download All Tracks(after filtering already Downloaded)

View File

@ -56,7 +56,7 @@ internal class SpotiFlyerListImpl(
.maximumCacheSize(75)
.build<String, Picture>()
override val models: Value<State> = store.asValue()
override val model: Value<State> = store.asValue()
override fun onDownloadAllClicked(trackList: List<TrackDetails>) {
store.accept(Intent.StartDownloadAll(trackList))

View File

@ -28,7 +28,7 @@ import com.shabinder.database.Database
interface SpotiFlyerMain {
val models: Value<State>
val model: Value<State>
val analytics: Analytics

View File

@ -23,10 +23,7 @@ import com.shabinder.common.caching.Cache
import com.shabinder.common.di.Picture
import com.shabinder.common.di.utils.asValue
import com.shabinder.common.main.SpotiFlyerMain
import com.shabinder.common.main.SpotiFlyerMain.Dependencies
import com.shabinder.common.main.SpotiFlyerMain.HomeCategory
import com.shabinder.common.main.SpotiFlyerMain.Output
import com.shabinder.common.main.SpotiFlyerMain.State
import com.shabinder.common.main.SpotiFlyerMain.*
import com.shabinder.common.main.store.SpotiFlyerMainStore.Intent
import com.shabinder.common.main.store.SpotiFlyerMainStoreProvider
import com.shabinder.common.main.store.getStore
@ -55,7 +52,7 @@ internal class SpotiFlyerMainImpl(
.maximumCacheSize(25)
.build<String, Picture>()
override val models: Value<State> = store.asValue()
override val model: Value<State> = store.asValue()
override val analytics = mainAnalytics

View File

@ -27,24 +27,12 @@ import com.arkivanov.decompose.extensions.compose.jetbrains.rememberRootComponen
import com.arkivanov.mvikotlin.core.lifecycle.LifecycleRegistry
import com.arkivanov.mvikotlin.core.lifecycle.resume
import com.arkivanov.mvikotlin.main.store.DefaultStoreFactory
import com.shabinder.common.di.Dir
import com.shabinder.common.di.DownloadProgressFlow
import com.shabinder.common.di.FetchPlatformQueryResult
import com.shabinder.common.di.firstLaunchDone
import com.shabinder.common.di.initKoin
import com.shabinder.common.di.isFirstLaunch
import com.shabinder.common.di.isInternetAccessible
import com.shabinder.common.di.setDownloadDirectory
import com.shabinder.common.di.toggleAnalytics
import com.shabinder.common.di.*
import com.shabinder.common.models.Actions
import com.shabinder.common.models.PlatformActions
import com.shabinder.common.models.TrackDetails
import com.shabinder.common.root.SpotiFlyerRoot
import com.shabinder.common.uikit.SpotiFlyerColors
import com.shabinder.common.uikit.SpotiFlyerRootContent
import com.shabinder.common.uikit.SpotiFlyerShapes
import com.shabinder.common.uikit.SpotiFlyerTypography
import com.shabinder.common.uikit.colorOffWhite
import com.shabinder.common.uikit.*
import com.shabinder.database.Database
import kotlinx.coroutines.runBlocking
import org.piwik.java.tracking.PiwikTracker
@ -58,7 +46,7 @@ import javax.swing.JFileChooser.APPROVE_OPTION
private val koin = initKoin(enableNetworkLogs = true).koin
private lateinit var showToast: (String)->Unit
private val tracker: PiwikTracker by lazy {
PiwikTracker("https://kind-grasshopper-73.telebit.io/matomo/matomo.php")
PiwikTracker("https://matomo.spotiflyer.ml/matomo.php")
}
fun main() {

View File

@ -35,12 +35,6 @@ dependencies {
implementation(MVIKotlin.coroutines)
implementation(MVIKotlin.mvikotlinMain)
implementation(MVIKotlin.mvikotlinLogging)
implementation(Ktor.auth)
implementation(Ktor.clientJs)
implementation(Ktor.clientJson)
implementation(Ktor.clientCore)
implementation(Ktor.clientLogging)
implementation(Ktor.clientSerialization)
implementation(project(":common:root"))
implementation(project(":common:main"))
implementation(project(":common:list"))
@ -48,20 +42,23 @@ dependencies {
implementation(project(":common:data-models"))
implementation(project(":common:dependency-injection"))
implementation("co.touchlab:stately-common:1.1.7")
implementation("dev.icerock.moko:parcelize:0.6.1")
implementation("dev.icerock.moko:parcelize:0.7.0")
// implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.1")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.1.0") {
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.1") {
// https://youtrack.jetbrains.com/issue/KTOR-2670
isForce = true
}
implementation("org.jetbrains:kotlin-react:17.0.1-pre.148-kotlin-1.4.30")
implementation("org.jetbrains:kotlin-react-dom:17.0.1-pre.148-kotlin-1.4.30")
implementation("org.jetbrains:kotlin-styled:1.0.0-pre.115-kotlin-1.4.10")
implementation("org.jetbrains:kotlin-react-router-dom:5.2.0-pre.148-kotlin-1.4.30")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0-native-mt") {
@Suppress("DEPRECATION")
isForce = true
}
implementation("org.jetbrains.kotlin-wrappers:kotlin-react:17.0.2-pre.213-kotlin-1.5.10")
implementation("org.jetbrains.kotlin-wrappers:kotlin-react-dom:17.0.2-pre.213-kotlin-1.5.10")
implementation("org.jetbrains.kotlin-wrappers:kotlin-styled:5.3.0-pre.213-kotlin-1.5.10")
}
kotlin {
js {
js(IR) {
//useCommonJs()
browser {
webpackTask {
@ -77,5 +74,6 @@ kotlin {
}
}
}
binaries.executable()
}
}

View File

@ -28,11 +28,7 @@ import com.shabinder.common.models.TrackDetails
import com.shabinder.common.root.SpotiFlyerRoot
import com.shabinder.database.Database
import extras.renderableChild
import react.RBuilder
import react.RComponent
import react.RProps
import react.RState
import react.ReactElement
import react.*
import root.RootR
external interface AppProps : RProps {
@ -46,6 +42,10 @@ fun RBuilder.App(attrs: AppProps.() -> Unit): ReactElement {
}
}
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED", "NON_EXPORTABLE_TYPE")
@OptIn(ExperimentalJsExport::class)
@JsExport
class App(props: AppProps): RComponent<AppProps, RState>(props) {
private val lifecycle = LifecycleRegistry()

View File

@ -17,53 +17,63 @@
package extras
import com.arkivanov.decompose.value.Value
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import com.arkivanov.decompose.value.ValueObserver
import react.RComponent
import react.RProps
import react.RState
import react.setState
abstract class RenderableComponent<
T : Any,
S : Any
>(
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED", "NON_EXPORTABLE_TYPE")
@OptIn(ExperimentalJsExport::class)
@JsExport
abstract class RenderableComponent<T: Any, S: RState>(
props: Props<T>,
initialState: S
) : RComponent<RenderableComponent.Props<T>, RenderableComponent.State<S>>(props) {
) : RComponent<Props<T>, S>(props) {
protected abstract val stateFlow: Value<S>
protected val model: T get() = props.model
protected var scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
private val subscriptions = ArrayList<Subscription<*>>()
protected val component: T get() = props.component
init {
state = State(data = initialState)
state = initialState
}
override fun componentDidMount() {
if(!scope.isActive)
scope = CoroutineScope(Dispatchers.Default)
scope.launch {
stateFlow.subscribe {
setState { data = it }
}
subscriptions.forEach { subscribe(it) }
}
private fun <T : Any> subscribe(subscription: Subscription<T>) {
subscription.value.subscribe(subscription.observer)
}
override fun componentWillUnmount() {
scope.cancel("Component Unmounted")
subscriptions.forEach { unsubscribe(it) }
}
interface Props<T : Any> : RProps {
var model: T
private fun <T : Any> unsubscribe(subscription: Subscription<T>) {
subscription.value.unsubscribe(subscription.observer)
}
class State<S>(
var data: S
):RState
protected fun <T : Any> Value<T>.bindToState(buildState: S.(T) -> Unit) {
subscriptions += Subscription(this) { data -> setState { buildState(data) } }
}
protected class Subscription<T : Any>(
val value: Value<T>,
val observer: ValueObserver<T>
)
}
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED", "NON_EXPORTABLE_TYPE")
@OptIn(ExperimentalJsExport::class)
@JsExport
class RStateWrapper<T>(
var model: T
) : RState
external interface Props<T : Any> : RProps {
var component: T
}

View File

@ -1,78 +0,0 @@
/*
* * Copyright (c) 2021 Shabinder Singh
* * This program is free software: you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation, either version 3 of the License, or
* * (at your option) any later version.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
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.isActive
import react.RComponent
import react.RProps
import react.RState
import react.setState
abstract class RenderableRootComponent<
T : Any,
S : RState
>(
props: Props<T>,
initialState: S
) : RComponent<Props<T>, S>(props) {
protected val model: T get() = props.model
private val subscriptions = ArrayList<Subscription<*>>()
protected var scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
init {
this.state = initialState
}
override fun componentDidMount() {
subscriptions.forEach { subscribe(it) }
if(!scope.isActive)
scope = CoroutineScope(Dispatchers.Default)
}
private fun <T : Any> subscribe(subscription: Subscription<T>) {
subscription.value.subscribe(subscription.observer)
}
override fun componentWillUnmount() {
subscriptions.forEach { unsubscribe(it) }
scope.cancel("Component Unmounted")
}
private fun <T : Any> unsubscribe(subscription: Subscription<T>) {
subscription.value.unsubscribe(subscription.observer)
}
protected fun <T : Any> Value<T>.bindToState(buildState: S.(T) -> Unit) {
subscriptions += Subscription(this) { data -> setState { buildState(data) } }
}
interface Props<T : Any> : RProps {
var model: T
}
protected class Subscription<T : Any>(
val value: Value<T>,
val observer: ValueObserver<T>
)
}

View File

@ -19,15 +19,9 @@ package extras
import react.RBuilder
import kotlin.reflect.KClass
fun <M : Any, T : RenderableRootComponent<M, *>> RBuilder.renderableChild(clazz: KClass<out T>, model: M) {
child(clazz) {
key = model.uniqueId().toString()
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
attrs.component = model
}
}

View File

@ -16,21 +16,12 @@
package home
import com.arkivanov.decompose.value.Value
import com.shabinder.common.main.SpotiFlyerMain
import com.shabinder.common.main.SpotiFlyerMain.State
import extras.Props
import extras.RStateWrapper
import extras.RenderableComponent
import kotlinx.browser.document
import kotlinx.coroutines.flow.Flow
import kotlinx.css.Align
import kotlinx.css.Display
import kotlinx.css.FlexDirection
import kotlinx.css.JustifyContent
import kotlinx.css.alignItems
import kotlinx.css.display
import kotlinx.css.flexDirection
import kotlinx.css.flexGrow
import kotlinx.css.justifyContent
import kotlinx.css.*
import kotlinx.dom.appendElement
import react.RBuilder
import styled.css
@ -38,12 +29,20 @@ import styled.styledDiv
class HomeScreen(
props: Props<SpotiFlyerMain>,
) : RenderableComponent<SpotiFlyerMain, State>(
) : RenderableComponent<SpotiFlyerMain, RStateWrapper<SpotiFlyerMain.State>>(
props,
initialState = State()
initialState = RStateWrapper(props.component.model.value)
) {
init {
component.model.bindToState {
model = it
}
}
override fun componentDidMount() {
super.componentDidMount()
// RazorPay Button
val form = document.getElementById("razorpay-form")!!
repeat(form.childNodes.length){
form.childNodes.item(0)?.let { it1 -> form.removeChild(it1) }
@ -56,8 +55,6 @@ class HomeScreen(
}
}
override val stateFlow: Value<SpotiFlyerMain.State> = model.models
override fun RBuilder.render() {
styledDiv{
css {
@ -73,9 +70,9 @@ class HomeScreen(
}
SearchBar {
link = state.data.link
search = model::onLinkSearch
onLinkChange = model::onInputLinkChanged
link = state.model.link
search = component::onLinkSearch
onLinkChange = component::onInputLinkChanged
}
IconList {

View File

@ -17,22 +17,11 @@
package home
import Styles
import kotlinx.css.borderRadius
import kotlinx.css.height
import kotlinx.css.margin
import kotlinx.css.px
import kotlinx.css.width
import kotlinx.css.*
import kotlinx.html.id
import react.RBuilder
import react.RProps
import react.ReactElement
import react.child
import react.functionalComponent
import styled.css
import styled.styledA
import styled.styledDiv
import styled.styledForm
import styled.styledImg
import react.*
import react.dom.attrs
import styled.*
external interface IconListProps : RProps {
var iconsAndPlatforms: Map<String,String>
@ -63,7 +52,7 @@ private val iconList = functionalComponent<IconListProps>("IconList") { props ->
if(icon == firstElem && props.isBadge){
//<form><script src="https://checkout.razorpay.com/v1/payment-button.js" data-payment_button_id="pl_GnKuuDBdBu0ank" async> </script> </form>
styledForm {
attrs{
attrs {
id = "razorpay-form"
}
}

View File

@ -25,12 +25,9 @@ import org.w3c.dom.HTMLInputElement
import react.RBuilder
import react.RProps
import react.child
import react.dom.attrs
import react.functionalComponent
import styled.css
import styled.styledButton
import styled.styledDiv
import styled.styledImg
import styled.styledInput
import styled.*
external interface SearchbarProps : RProps {
var link: String
@ -45,8 +42,6 @@ fun RBuilder.SearchBar(handler:SearchbarProps.() -> Unit) = child(searchbar){
}
}
val searchbar = functionalComponent<SearchbarProps>("SearchBar"){ props ->
styledDiv{
css {

View File

@ -16,24 +16,10 @@
package list
import kotlinx.css.Align
import kotlinx.css.Display
import kotlinx.css.FlexDirection
import kotlinx.css.TextAlign
import kotlinx.css.alignItems
import kotlinx.css.display
import kotlinx.css.flexDirection
import kotlinx.css.height
import kotlinx.css.marginTop
import kotlinx.css.px
import kotlinx.css.textAlign
import kotlinx.css.width
import kotlinx.css.*
import kotlinx.html.id
import react.RBuilder
import react.RProps
import react.ReactElement
import react.child
import react.functionalComponent
import react.*
import react.dom.attrs
import styled.css
import styled.styledDiv
import styled.styledH1

View File

@ -16,26 +16,11 @@
package list
import kotlinx.css.Align
import kotlinx.css.Display
import kotlinx.css.JustifyContent
import kotlinx.css.WhiteSpace
import kotlinx.css.alignItems
import kotlinx.css.display
import kotlinx.css.fontSize
import kotlinx.css.height
import kotlinx.css.justifyContent
import kotlinx.css.px
import kotlinx.css.whiteSpace
import kotlinx.css.*
import kotlinx.html.id
import kotlinx.html.js.onClickFunction
import react.RBuilder
import react.RProps
import react.ReactElement
import react.child
import react.functionalComponent
import react.useEffect
import react.useState
import react.*
import react.dom.attrs
import styled.css
import styled.styledDiv
import styled.styledH5

View File

@ -17,17 +17,10 @@
package list
import com.shabinder.common.models.DownloadStatus
import kotlinx.css.borderRadius
import kotlinx.css.em
import kotlinx.css.margin
import kotlinx.css.px
import kotlinx.css.width
import kotlinx.css.*
import kotlinx.html.js.onClickFunction
import react.RBuilder
import react.RProps
import react.ReactElement
import react.child
import react.functionalComponent
import react.*
import react.dom.attrs
import styled.css
import styled.styledDiv
import styled.styledImg

View File

@ -16,55 +16,55 @@
package list
import com.arkivanov.decompose.value.Value
import com.shabinder.common.list.SpotiFlyerList
import com.shabinder.common.list.SpotiFlyerList.State
import extras.Props
import extras.RStateWrapper
import extras.RenderableComponent
import kotlinx.coroutines.flow.Flow
import kotlinx.css.Color
import kotlinx.css.Display
import kotlinx.css.FlexDirection
import kotlinx.css.color
import kotlinx.css.display
import kotlinx.css.flexDirection
import kotlinx.css.flexGrow
import kotlinx.css.padding
import kotlinx.css.px
import kotlinx.css.*
import kotlinx.html.id
import react.RBuilder
import react.dom.attrs
import styled.css
import styled.styledDiv
import styled.styledSection
class ListScreen(
props: Props<SpotiFlyerList>,
) : RenderableComponent<SpotiFlyerList, State>(props,initialState = State()) {
override val stateFlow: Value<SpotiFlyerList.State> = model.models
) : RenderableComponent<SpotiFlyerList, RStateWrapper<State>>(
props,
initialState = RStateWrapper(props.component.model.value)
) {
init {
component.model.bindToState {
model = it
}
}
override fun RBuilder.render() {
val result = state.data.queryResult
val queryResult = state.model.queryResult
styledSection {
attrs {
id = "list-screen"
}
if(result == null) {
if(queryResult == null) {
LoadingAnim { }
}else {
CoverImage {
coverImageURL = result.coverUrl
coverName = result.title
coverImageURL = queryResult.coverUrl
coverName = queryResult.title
}
DownloadAllButton {
isActive = state.data.trackList.size > 1
isActive = state.model.trackList.size > 1
downloadAll = {
model.onDownloadAllClicked(state.data.trackList)
component.onDownloadAllClicked(state.model.trackList)
}
link = state.data.link
link = state.model.link
}
styledDiv {
@ -74,10 +74,10 @@ class ListScreen(
flexDirection = FlexDirection.column
color = Color.white
}
state.data.trackList.forEachIndexed{ _, trackDetails ->
state.model.trackList.forEachIndexed{ _, trackDetails ->
TrackItem {
details = trackDetails
downloadTrack = model::onDownloadClicked
downloadTrack = component::onDownloadClicked
}
}
}

View File

@ -18,43 +18,11 @@ package list
import com.shabinder.common.models.DownloadStatus
import com.shabinder.common.models.TrackDetails
import kotlinx.css.Align
import kotlinx.css.Display
import kotlinx.css.FlexDirection
import kotlinx.css.Overflow
import kotlinx.css.TextAlign
import kotlinx.css.TextOverflow
import kotlinx.css.WhiteSpace
import kotlinx.css.alignItems
import kotlinx.css.display
import kotlinx.css.em
import kotlinx.css.flexDirection
import kotlinx.css.flexGrow
import kotlinx.css.fontSize
import kotlinx.css.height
import kotlinx.css.margin
import kotlinx.css.minWidth
import kotlinx.css.overflow
import kotlinx.css.padding
import kotlinx.css.paddingRight
import kotlinx.css.px
import kotlinx.css.textAlign
import kotlinx.css.textOverflow
import kotlinx.css.whiteSpace
import kotlinx.css.width
import kotlinx.css.*
import kotlinx.html.id
import react.RBuilder
import react.RProps
import react.ReactElement
import react.child
import react.functionalComponent
import react.useEffect
import react.useState
import styled.css
import styled.styledDiv
import styled.styledH3
import styled.styledH4
import styled.styledImg
import react.*
import react.dom.attrs
import styled.*
external interface TrackItemProps : RProps {
var details:TrackDetails

View File

@ -16,33 +16,13 @@
package navbar
import kotlinx.css.Align
import kotlinx.css.Display
import kotlinx.css.LinearDimension
import kotlinx.css.alignItems
import kotlinx.css.display
import kotlinx.css.filter
import kotlinx.css.fontSize
import kotlinx.css.height
import kotlinx.css.margin
import kotlinx.css.marginLeft
import kotlinx.css.marginRight
import kotlinx.css.px
import kotlinx.css.width
import kotlinx.css.*
import kotlinx.html.id
import kotlinx.html.js.onBlurFunction
import kotlinx.html.js.onClickFunction
import react.RBuilder
import react.RProps
import react.ReactElement
import react.child
import react.functionalComponent
import styled.css
import styled.styledA
import styled.styledDiv
import styled.styledH1
import styled.styledImg
import styled.styledNav
import react.*
import react.dom.attrs
import styled.*
@Suppress("FunctionName")
fun RBuilder.NavBar(handler: NavBarProps.() -> Unit): ReactElement{

View File

@ -19,7 +19,8 @@ package root
import com.arkivanov.decompose.RouterState
import com.shabinder.common.root.SpotiFlyerRoot
import com.shabinder.common.root.SpotiFlyerRoot.Child
import extras.RenderableRootComponent
import extras.Props
import extras.RenderableComponent
import extras.renderableChild
import home.HomeScreen
import list.ListScreen
@ -27,31 +28,34 @@ import navbar.NavBar
import react.RBuilder
import react.RState
class RootR(props: Props<SpotiFlyerRoot>) : RenderableRootComponent<SpotiFlyerRoot, RootR.State>(
class RootR(props: Props<SpotiFlyerRoot>) : RenderableComponent<SpotiFlyerRoot, State>(
props = props,
initialState = State(routerState = props.model.routerState.value)
initialState = State(routerState = props.component.routerState.value)
) {
private val component: Child
get() = model.routerState.value.activeChild.instance
private val child: Child
get() = component.routerState.value.activeChild.instance
private val callBacks get() = model.callBacks
private val callBacks get() = component.callBacks
init {
component.routerState.bindToState { routerState = it }
}
override fun RBuilder.render() {
NavBar {
isBackVisible = (component is Child.List)
isBackVisible = (child is Child.List)
popBackToHomeScreen = callBacks::popBackToHomeScreen
}
when(component){
is Child.Main -> renderableChild(HomeScreen::class, (component as Child.Main).component)
is Child.List -> renderableChild(ListScreen::class, (component as Child.List).component)
when(child){
is Child.Main -> renderableChild(HomeScreen::class, (child as Child.Main).component)
is Child.List -> renderableChild(ListScreen::class, (child as Child.List).component)
}
}
init {
model.routerState.bindToState { routerState = it }
}
class State(
var routerState: RouterState<*, Child>
) : RState
}
@Suppress("NON_EXPORTABLE_TYPE", "EXPERIMENTAL_IS_NOT_ENABLED")
@OptIn(ExperimentalJsExport::class)
@JsExport
class State(
var routerState: RouterState<*, Child>
) : RState