Modular Structure

This commit is contained in:
shabinder 2021-02-25 18:58:33 +05:30
parent ec1402ef2e
commit 475a64cad5
104 changed files with 299 additions and 360 deletions

View File

@ -16,7 +16,7 @@ repositories {
android { android {
compileSdkVersion(29) compileSdkVersion(29)
defaultConfig { defaultConfig {
applicationId = "com.shabinder.android" applicationId = "com.shabinder.spotiflyer"
minSdkVersion(Versions.minSdkVersion) minSdkVersion(Versions.minSdkVersion)
targetSdkVersion(Versions.targetSdkVersion) targetSdkVersion(Versions.targetSdkVersion)
versionCode = Versions.versionCode versionCode = Versions.versionCode
@ -25,8 +25,8 @@ android {
buildTypes { buildTypes {
getByName("release") { getByName("release") {
isMinifyEnabled = false isMinifyEnabled = true
//isShrinkResources = true isShrinkResources = true
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
} }
} }
@ -63,7 +63,8 @@ dependencies {
implementation(Androidx.androidxActivity) implementation(Androidx.androidxActivity)
implementation(project(":common:database")) implementation(project(":common:database"))
implementation(project(":common:compose-ui")) implementation(project(":common:compose"))
implementation(project(":common:root"))
implementation(project(":common:dependency-injection")) implementation(project(":common:dependency-injection"))
implementation(project(":common:data-models")) implementation(project(":common:data-models"))
@ -82,12 +83,6 @@ dependencies {
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:$it") implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:$it")
implementation("androidx.lifecycle:lifecycle-viewmodel-savedstate:$it") implementation("androidx.lifecycle:lifecycle-viewmodel-savedstate:$it")
} }
//Coil-Image Loading
Versions.coilVersion.let{
implementation("dev.chrisbanes.accompanist:accompanist-coil:$it")
implementation("dev.chrisbanes.accompanist:accompanist-insets:$it")
}
*/ */
Extras.Android.apply { Extras.Android.apply {
@ -103,7 +98,7 @@ dependencies {
implementation(Decompose.extensionsCompose) implementation(Decompose.extensionsCompose)
//Test //Test
testImplementation("junit:junit:4.13.1") testImplementation("junit:junit:4.13.2")
androidTestImplementation(Androidx.junit) androidTestImplementation(Androidx.junit)
androidTestImplementation(Androidx.expresso) androidTestImplementation(Androidx.expresso)

View File

@ -19,3 +19,21 @@
# If you keep the line number information, uncomment this to # If you keep the line number information, uncomment this to
# hide the original source file name. # hide the original source file name.
#-renamesourcefileattribute SourceFile #-renamesourcefileattribute SourceFile
-keepattributes *Annotation*, InnerClasses
-dontnote kotlinx.serialization.AnnotationsKt # core serialization annotations
# kotlinx-serialization-json specific. Add this if you have java.lang.NoClassDefFoundError kotlinx.serialization.json.JsonObjectSerializer
-keepclassmembers class kotlinx.serialization.json.** {
*** Companion;
}
-keepclasseswithmembers class kotlinx.serialization.json.** {
kotlinx.serialization.KSerializer serializer(...);
}
-keep,includedescriptorclasses class com.shabinder.spotiflyer.**$$serializer { *; } # <-- change package name to your app's
-keepclassmembers class com.shabinder.spotiflyer.** { # <-- change package name to your app's
*** Companion;
}
-keepclasseswithmembers class com.shabinder.spotiflyer.** { # <-- change package name to your app's
kotlinx.serialization.KSerializer serializer(...);
}

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
package="com.shabinder.android"> package="com.shabinder.spotiflyer">
<queries> <queries>
<package android:name="com.gaana" /> <package android:name="com.gaana" />

View File

@ -14,12 +14,12 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.shabinder.android package com.shabinder.spotiflyer
import android.app.Application import android.app.Application
import com.shabinder.android.di.appModule
import com.shabinder.common.database.appContext import com.shabinder.common.database.appContext
import com.shabinder.common.di.initKoin import com.shabinder.common.di.initKoin
import com.shabinder.spotiflyer.di.appModule
import org.koin.android.ext.koin.androidContext import org.koin.android.ext.koin.androidContext
import org.koin.android.ext.koin.androidLogger import org.koin.android.ext.koin.androidLogger
import org.koin.core.KoinComponent import org.koin.core.KoinComponent

View File

@ -1,4 +1,4 @@
package com.shabinder.android package com.shabinder.spotiflyer
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
@ -12,37 +12,33 @@ import android.util.Log
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.compose.material.Surface import androidx.compose.material.Surface
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.*
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalView import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.arkivanov.decompose.ComponentContext import com.arkivanov.decompose.ComponentContext
import com.arkivanov.decompose.extensions.compose.jetbrains.rootComponent import com.arkivanov.decompose.extensions.compose.jetbrains.rememberRootComponent
import com.arkivanov.mvikotlin.logging.store.LoggingStoreFactory import com.arkivanov.mvikotlin.logging.store.LoggingStoreFactory
import com.arkivanov.mvikotlin.main.store.DefaultStoreFactory import com.arkivanov.mvikotlin.main.store.DefaultStoreFactory
import com.razorpay.Checkout import com.razorpay.Checkout
import com.razorpay.PaymentResultListener import com.razorpay.PaymentResultListener
import com.shabinder.android.utils.checkIfLatestVersion
import com.shabinder.android.utils.disableDozeMode
import com.shabinder.android.utils.requestStoragePermission
import com.shabinder.common.database.activityContext import com.shabinder.common.database.activityContext
import com.shabinder.common.di.Dir import com.shabinder.common.di.Dir
import com.shabinder.common.di.FetchPlatformQueryResult import com.shabinder.common.di.FetchPlatformQueryResult
import com.shabinder.common.di.createDirectories import com.shabinder.common.di.createDirectories
import com.shabinder.common.di.showPopUpMessage
import com.shabinder.common.models.DownloadStatus import com.shabinder.common.models.DownloadStatus
import com.shabinder.common.models.TrackDetails import com.shabinder.common.models.TrackDetails
import com.shabinder.common.root.SpotiFlyerRoot import com.shabinder.common.root.SpotiFlyerRoot
import com.shabinder.common.root.SpotiFlyerRootContent
import com.shabinder.common.root.callbacks.SpotiFlyerRootCallBacks import com.shabinder.common.root.callbacks.SpotiFlyerRootCallBacks
import com.shabinder.common.ui.SpotiFlyerTheme import com.shabinder.common.uikit.SpotiFlyerRootContent
import com.shabinder.common.ui.colorOffWhite import com.shabinder.common.uikit.SpotiFlyerTheme
import com.shabinder.common.ui.showPopUpMessage import com.shabinder.common.uikit.colorOffWhite
import com.shabinder.database.Database import com.shabinder.database.Database
import com.shabinder.spotiflyer.utils.checkIfLatestVersion
import com.shabinder.spotiflyer.utils.disableDozeMode
import com.shabinder.spotiflyer.utils.requestStoragePermission
import com.tonyodev.fetch2.Status import com.tonyodev.fetch2.Status
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.*
@ -81,7 +77,7 @@ class MainActivity : ComponentActivity(), PaymentResultListener {
insets insets
} }
} }
root = SpotiFlyerRootContent(rootComponent(::spotiFlyerRoot),statusBarHeight) root = SpotiFlyerRootContent(rememberRootComponent(::spotiFlyerRoot),statusBarHeight)
} }
} }
} }

View File

@ -1,4 +1,4 @@
package com.shabinder.android.di package com.shabinder.spotiflyer.di
import com.shabinder.common.database.appContext import com.shabinder.common.database.appContext
import com.tonyodev.fetch2.Fetch import com.tonyodev.fetch2.Fetch

View File

@ -1,4 +1,4 @@
package com.shabinder.android.utils package com.shabinder.spotiflyer.utils
import android.Manifest import android.Manifest
import android.annotation.SuppressLint import android.annotation.SuppressLint
@ -12,7 +12,6 @@ import android.provider.Settings
import com.github.javiersantos.appupdater.AppUpdater import com.github.javiersantos.appupdater.AppUpdater
import com.github.javiersantos.appupdater.enums.Display import com.github.javiersantos.appupdater.enums.Display
import com.github.javiersantos.appupdater.enums.UpdateFrom import com.github.javiersantos.appupdater.enums.UpdateFrom
import com.tonyodev.fetch2.Fetch
fun Activity.checkIfLatestVersion() { fun Activity.checkIfLatestVersion() {
AppUpdater(this,0).run { AppUpdater(this,0).run {

View File

@ -67,12 +67,12 @@ object JetBrains {
object Compose { object Compose {
// __LATEST_COMPOSE_RELEASE_VERSION__ // __LATEST_COMPOSE_RELEASE_VERSION__
const val VERSION = "0.3.0" const val VERSION = "0.4.0-build168"
const val gradlePlugin = "org.jetbrains.compose:compose-gradle-plugin:$VERSION" const val gradlePlugin = "org.jetbrains.compose:compose-gradle-plugin:$VERSION"
} }
} }
object Decompose { object Decompose {
private const val VERSION = "0.1.8" private const val VERSION = "0.1.9"
const val decompose = "com.arkivanov.decompose:decompose:$VERSION" const val decompose = "com.arkivanov.decompose:decompose:$VERSION"
const val decomposeIosX64 = "com.arkivanov.decompose:decompose-iosx64:$VERSION" const val decomposeIosX64 = "com.arkivanov.decompose:decompose-iosx64:$VERSION"
const val decomposeIosArm64 = "com.arkivanov.decompose:decompose-iosarm64:$VERSION" const val decomposeIosArm64 = "com.arkivanov.decompose:decompose-iosarm64:$VERSION"

View File

@ -1,5 +1,3 @@
import org.jetbrains.compose.compose
plugins { plugins {
id("com.android.library") id("com.android.library")
id("kotlin-multiplatform") id("kotlin-multiplatform")

View File

@ -1,21 +0,0 @@
package com.shabinder.common.ui
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import com.shabinder.common.database.appContext
import kotlinx.coroutines.Dispatchers
actual val dispatcherIO = Dispatchers.IO
@Composable
actual fun Toast(
text: String,
visibility: MutableState<Boolean>,
duration: ToastDuration
){
//We Have Android's Implementation of Toast so its just Empty
}
actual fun showPopUpMessage(text: String){
android.widget.Toast.makeText(appContext,text, android.widget.Toast.LENGTH_SHORT).show()
}

View File

@ -1,7 +0,0 @@
package com.shabinder.common.ui
import kotlinx.coroutines.CoroutineDispatcher
expect fun showPopUpMessage(text: String)
expect val dispatcherIO: CoroutineDispatcher

View File

@ -1,72 +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 com.shabinder.common.ui.utils
/**
* Draws a vertical gradient scrim in the foreground.
*
* @param color The color of the gradient scrim.
* @param startYPercentage The start y value, in percentage of the layout's height (0f to 1f)
* @param endYPercentage The end y value, in percentage of the layout's height (0f to 1f)
* @param decay The exponential decay to apply to the gradient. Defaults to `1.0f` which is
* a linear gradient.
* @param numStops The number of color stops to draw in the gradient. Higher numbers result in
* the higher visual quality at the cost of draw performance. Defaults to `16`.
*/
/*
fun Modifier.verticalGradientScrim(
color: Color,
//@FloatRange(from = 0.0, to = 1.0)
startYPercentage: Float = 0f,
//@FloatRange(from = 0.0, to = 1.0)
endYPercentage: Float = 1f,
decay: Float = 1.0f,
numStops: Int = 16,
fixedHeight: Float? = null
): Modifier = composed {
val colors = remember(color, numStops) {
if (decay != 1f) {
// If we have a non-linear decay, we need to create the color gradient steps
// manually
val baseAlpha = color.alpha
List(numStops) { i ->
val x = i * 1f / (numStops - 1)
val opacity = x.pow(decay)
color.copy(alpha = baseAlpha * opacity)
}
} else {
// If we have a linear decay, we just create a simple list of start + end colors
listOf(color.copy(alpha = 0f), color)
}
}
var height by remember { mutableStateOf(fixedHeight ?: 0f) }
val brush = remember(color, numStops, startYPercentage, endYPercentage, height) {
Brush.verticalGradient(
colors = colors,
startY = height * startYPercentage,
endY = height * endYPercentage
)
}
drawBehind {
height = fixedHeight ?: size.height
// log("Height",size.height.toString())
drawRect(brush = brush)
}
}
*/

View File

@ -0,0 +1,26 @@
import org.jetbrains.compose.compose
plugins {
id("multiplatform-compose-setup")
id("android-setup")
id("kotlin-parcelize")
}
kotlin {
sourceSets {
commonMain {
dependencies {
implementation(compose.materialIconsExtended)
implementation(project(":common:root"))
implementation(project(":common:main"))
implementation(project(":common:list"))
implementation(project(":common:database"))
implementation(project(":common:data-models"))
implementation(project(":common:dependency-injection"))
//DECOMPOSE
implementation(Decompose.decompose)
implementation(Decompose.extensionsCompose)
}
}
}
}

View File

@ -1,6 +1,6 @@
@file:Suppress("FunctionName") @file:Suppress("FunctionName")
package com.shabinder.common.ui package com.shabinder.common.uikit
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
@ -12,6 +12,7 @@ import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.text.font.Font import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import com.shabinder.common.database.R
actual fun montserratFont() = FontFamily( actual fun montserratFont() = FontFamily(
Font(R.font.montserrat_light, FontWeight.Light), Font(R.font.montserrat_light, FontWeight.Light),

View File

@ -14,7 +14,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.shabinder.common.ui package com.shabinder.common.uikit
import androidx.compose.material.darkColors import androidx.compose.material.darkColors
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color

View File

@ -1,15 +1,14 @@
@file:Suppress("FunctionName") @file:Suppress("FunctionName")
package com.shabinder.common.ui package com.shabinder.common.uikit
import androidx.compose.animation.Crossfade import androidx.compose.animation.Crossfade
import androidx.compose.animation.core.snap
import androidx.compose.animation.core.tween
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import com.shabinder.common.di.dispatcherIO
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@Composable @Composable

View File

@ -14,7 +14,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.shabinder.common.ui package com.shabinder.common.uikit
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Shapes import androidx.compose.material.Shapes

View File

@ -1,4 +1,4 @@
package com.shabinder.common.list package com.shabinder.common.uikit
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
@ -15,11 +15,9 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.shabinder.common.list.SpotiFlyerList
import com.shabinder.common.models.DownloadStatus import com.shabinder.common.models.DownloadStatus
import com.shabinder.common.models.TrackDetails import com.shabinder.common.models.TrackDetails
import com.shabinder.common.ui.*
import com.shabinder.common.ui.SpotiFlyerTypography
import com.shabinder.common.ui.colorAccent
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@Composable @Composable

View File

@ -1,5 +1,6 @@
package com.shabinder.common.main package com.shabinder.common.uikit
import androidx.compose.animation.Crossfade
import androidx.compose.foundation.* import androidx.compose.foundation.*
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
@ -7,9 +8,7 @@ import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.* import androidx.compose.material.*
import androidx.compose.material.Icon
import androidx.compose.material.TabRowDefaults.tabIndicatorOffset import androidx.compose.material.TabRowDefaults.tabIndicatorOffset
import androidx.compose.material.Text
import androidx.compose.material.TextFieldDefaults.textFieldColors import androidx.compose.material.TextFieldDefaults.textFieldColors
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.History import androidx.compose.material.icons.outlined.History
@ -23,17 +22,19 @@ import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.shabinder.common.di.giveDonation import com.shabinder.common.di.giveDonation
import com.shabinder.common.models.DownloadRecord
import com.shabinder.common.main.SpotiFlyerMain.HomeCategory
import com.shabinder.common.di.openPlatform import com.shabinder.common.di.openPlatform
import com.shabinder.common.di.shareApp import com.shabinder.common.di.shareApp
import com.shabinder.common.ui.* import com.shabinder.common.di.showPopUpMessage
import com.shabinder.common.ui.SpotiFlyerTypography import com.shabinder.common.main.SpotiFlyerMain
import com.shabinder.common.main.SpotiFlyerMain.HomeCategory
import com.shabinder.common.models.DownloadRecord
@Composable @Composable
fun SpotiFlyerMainContent(component: SpotiFlyerMain){ fun SpotiFlyerMainContent(component: SpotiFlyerMain){
@ -129,7 +130,10 @@ fun SearchPanel(
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Uri), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Uri),
modifier = modifier.padding(12.dp).fillMaxWidth() modifier = modifier.padding(12.dp).fillMaxWidth()
.border( .border(
BorderStroke(2.dp, Brush.horizontalGradient(listOf(colorPrimary, colorAccent))), BorderStroke(2.dp, Brush.horizontalGradient(listOf(
colorPrimary,
colorAccent
))),
RoundedCornerShape(30.dp) RoundedCornerShape(30.dp)
), ),
shape = RoundedCornerShape(size = 30.dp), shape = RoundedCornerShape(size = 30.dp),
@ -148,7 +152,10 @@ fun SearchPanel(
onSearch(link) onSearch(link)
} }
}, },
border = BorderStroke(1.dp, Brush.horizontalGradient(listOf(colorPrimary, colorAccent))) border = BorderStroke(1.dp, Brush.horizontalGradient(listOf(
colorPrimary,
colorAccent
)))
){ ){
Text(text = "Search",style = SpotiFlyerTypography.h6,modifier = Modifier.padding(4.dp)) Text(text = "Search",style = SpotiFlyerTypography.h6,modifier = Modifier.padding(4.dp))
} }
@ -299,19 +306,30 @@ fun HistoryColumn(
loadImage:suspend (String)-> ImageBitmap?, loadImage:suspend (String)-> ImageBitmap?,
onItemClicked: (String) -> Unit onItemClicked: (String) -> Unit
) { ) {
LazyColumn( Crossfade(list){
verticalArrangement = Arrangement.spacedBy(12.dp), if(it.isEmpty()){
content = { Column(Modifier.padding(bottom = 32.dp).fillMaxSize(),verticalArrangement = Arrangement.Center,horizontalAlignment = Alignment.CenterHorizontally) {
items(list.distinctBy { it.coverUrl }) { Icon(Icons.Outlined.Info,"No History Available Yet",modifier = Modifier.size(80.dp),
DownloadRecordItem( colorOffWhite
item = it,
loadImage,
onItemClicked
) )
Text("No History Available",style = SpotiFlyerTypography.h4.copy(fontWeight = FontWeight.Light),textAlign = TextAlign.Center)
} }
}, }else{
modifier = Modifier.padding(top = 8.dp).fillMaxSize() LazyColumn(
) verticalArrangement = Arrangement.spacedBy(12.dp),
content = {
items(it.distinctBy {record -> record.coverUrl }) { record ->
DownloadRecordItem(
item = record,
loadImage,
onItemClicked
)
}
},
modifier = Modifier.padding(top = 8.dp).fillMaxSize()
)
}
}
} }
@Composable @Composable
@ -334,8 +352,8 @@ fun DownloadRecordItem(
verticalAlignment = Alignment.Bottom, verticalAlignment = Alignment.Bottom,
modifier = Modifier.padding(horizontal = 8.dp).fillMaxSize() modifier = Modifier.padding(horizontal = 8.dp).fillMaxSize()
){ ){
Text(item.type,fontSize = 13.sp) Text(item.type,fontSize = 13.sp,color = colorOffWhite)
Text("Tracks: ${item.totalFiles}",fontSize = 13.sp) Text("Tracks: ${item.totalFiles}",fontSize = 13.sp,color = colorOffWhite)
} }
} }
Image( Image(

View File

@ -1,14 +1,16 @@
package com.shabinder.common.root package com.shabinder.common.uikit
import androidx.compose.animation.core.* import androidx.compose.animation.core.*
import androidx.compose.animation.core.Spring.StiffnessLow import androidx.compose.animation.core.Spring.StiffnessLow
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.material.* import androidx.compose.material.MaterialTheme
import androidx.compose.material.icons.Icons import androidx.compose.material.Text
import androidx.compose.material.icons.filled.Settings import androidx.compose.material.TopAppBar
import androidx.compose.runtime.* import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.alpha
@ -17,17 +19,14 @@ import androidx.compose.ui.platform.LocalViewConfiguration
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.arkivanov.decompose.extensions.compose.jetbrains.Children import com.arkivanov.decompose.extensions.compose.jetbrains.Children
import com.shabinder.common.list.SpotiFlyerListContent import com.shabinder.common.root.SpotiFlyerRoot
import com.shabinder.common.main.SpotiFlyerMainContent
import com.shabinder.common.root.SpotiFlyerRoot.Child import com.shabinder.common.root.SpotiFlyerRoot.Child
import com.shabinder.common.ui.SpotiFlyerLogo import com.shabinder.common.uikit.splash.Splash
import com.shabinder.common.ui.appNameStyle import com.shabinder.common.uikit.splash.SplashState
import com.shabinder.common.ui.colorPrimaryDark import com.shabinder.common.uikit.utils.verticalGradientScrim
import com.shabinder.common.ui.splash.*
import com.shabinder.common.utils.verticalGradientScrim
@Composable @Composable
fun SpotiFlyerRootContent(component: SpotiFlyerRoot,statusBarHeight:Dp = 0.dp):SpotiFlyerRoot { fun SpotiFlyerRootContent(component: SpotiFlyerRoot, statusBarHeight:Dp = 0.dp): SpotiFlyerRoot {
val transitionState = remember { MutableTransitionState(SplashState.Shown) } val transitionState = remember { MutableTransitionState(SplashState.Shown) }
val transition = updateTransition(transitionState) val transition = updateTransition(transitionState)

View File

@ -14,7 +14,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.shabinder.common.ui package com.shabinder.common.uikit
import androidx.compose.material.MaterialTheme import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable

View File

@ -14,7 +14,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.shabinder.common.ui package com.shabinder.common.uikit
import androidx.compose.material.Typography import androidx.compose.material.Typography
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color

View File

@ -14,7 +14,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.shabinder.common.ui.splash package com.shabinder.common.uikit.splash
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
@ -29,7 +29,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.shabinder.common.ui.* import com.shabinder.common.uikit.*
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
private const val SplashWaitTime: Long = 2000 private const val SplashWaitTime: Long = 2000

View File

@ -14,7 +14,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.shabinder.common.ui.utils package com.shabinder.common.uikit.utils
/* /*

View File

@ -14,7 +14,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package com.shabinder.common.utils package com.shabinder.common.uikit.utils
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf

View File

@ -1,5 +1,5 @@
@file:Suppress("FunctionName") @file:Suppress("FunctionName")
package com.shabinder.common.ui package com.shabinder.common.uikit
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable

View File

@ -1,4 +1,4 @@
package com.shabinder.common.utils package com.shabinder.common.models
/* /*
* Callback Utility * Callback Utility

View File

@ -4,15 +4,19 @@ import android.app.Activity
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.net.Uri import android.net.Uri
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import com.github.kiulian.downloader.model.YoutubeVideo import com.github.kiulian.downloader.model.YoutubeVideo
import com.github.kiulian.downloader.model.formats.Format import com.github.kiulian.downloader.model.formats.Format
import com.github.kiulian.downloader.model.quality.AudioQuality import com.github.kiulian.downloader.model.quality.AudioQuality
import com.razorpay.Checkout import com.razorpay.Checkout
import com.shabinder.common.database.R
import com.shabinder.common.database.activityContext import com.shabinder.common.database.activityContext
import com.shabinder.common.database.appContext
import com.shabinder.common.di.worker.ForegroundService import com.shabinder.common.di.worker.ForegroundService
import com.shabinder.common.models.TrackDetails import com.shabinder.common.models.TrackDetails
import com.shabinder.common.ui.R import kotlinx.coroutines.Dispatchers
import org.json.JSONObject import org.json.JSONObject
actual fun openPlatform(packageID:String, platformLink:String){ actual fun openPlatform(packageID:String, platformLink:String){
@ -29,7 +33,20 @@ actual fun openPlatform(packageID:String, platformLink:String){
activityContext.startActivity(intent) activityContext.startActivity(intent)
} }
} }
actual val dispatcherIO = Dispatchers.IO
@Composable
actual fun Toast(
text: String,
visibility: MutableState<Boolean>,
duration: ToastDuration
){
//We Have Android's Implementation of Toast so its just Empty
}
actual fun showPopUpMessage(text: String){
android.widget.Toast.makeText(appContext,text, android.widget.Toast.LENGTH_SHORT).show()
}
actual fun shareApp(){ actual fun shareApp(){
val sendIntent: Intent = Intent().apply { val sendIntent: Intent = Intent().apply {
action = Intent.ACTION_SEND action = Intent.ACTION_SEND

View File

@ -9,14 +9,16 @@ import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.graphics.asImageBitmap
import co.touchlab.kermit.Kermit import co.touchlab.kermit.Kermit
import com.mpatric.mp3agic.Mp3File import com.mpatric.mp3agic.Mp3File
import com.shabinder.common.models.TrackDetails
import com.shabinder.common.database.appContext import com.shabinder.common.database.appContext
import com.shabinder.common.models.TrackDetails
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.io.* import java.io.File
import java.lang.Exception import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
import java.net.HttpURLConnection import java.net.HttpURLConnection
import java.net.URL import java.net.URL

View File

@ -18,10 +18,10 @@ package com.shabinder.common.di
import co.touchlab.kermit.Kermit import co.touchlab.kermit.Kermit
import com.github.kiulian.downloader.YoutubeDownloader import com.github.kiulian.downloader.YoutubeDownloader
import com.shabinder.common.database.DownloadRecordDatabaseQueries
import com.shabinder.common.models.DownloadStatus import com.shabinder.common.models.DownloadStatus
import com.shabinder.common.models.PlatformQueryResult import com.shabinder.common.models.PlatformQueryResult
import com.shabinder.common.models.TrackDetails import com.shabinder.common.models.TrackDetails
import com.shabinder.common.database.DownloadRecordDatabaseQueries
import com.shabinder.common.models.spotify.Source import com.shabinder.common.models.spotify.Source
import com.shabinder.database.Database import com.shabinder.database.Database
import io.ktor.client.* import io.ktor.client.*

View File

@ -33,12 +33,12 @@ import androidx.core.net.toUri
import co.touchlab.kermit.Kermit import co.touchlab.kermit.Kermit
import com.github.kiulian.downloader.YoutubeDownloader import com.github.kiulian.downloader.YoutubeDownloader
import com.github.kiulian.downloader.model.formats.Format import com.github.kiulian.downloader.model.formats.Format
import com.shabinder.common.database.R.*
import com.shabinder.common.di.Dir import com.shabinder.common.di.Dir
import com.shabinder.common.di.FetchPlatformQueryResult import com.shabinder.common.di.FetchPlatformQueryResult
import com.shabinder.common.di.getData import com.shabinder.common.di.getData
import com.shabinder.common.models.DownloadStatus import com.shabinder.common.models.DownloadStatus
import com.shabinder.common.models.TrackDetails import com.shabinder.common.models.TrackDetails
import com.shabinder.common.ui.R.*
import com.tonyodev.fetch2.* import com.tonyodev.fetch2.*
import com.tonyodev.fetch2core.DownloadBlock import com.tonyodev.fetch2core.DownloadBlock
import kotlinx.coroutines.* import kotlinx.coroutines.*

View File

@ -2,13 +2,11 @@ package com.shabinder.common.di
import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.ImageBitmap
import co.touchlab.kermit.Kermit import co.touchlab.kermit.Kermit
import com.shabinder.common.di.providers.YoutubeMusic
import com.shabinder.common.models.DownloadResult import com.shabinder.common.models.DownloadResult
import com.shabinder.common.models.TrackDetails import com.shabinder.common.models.TrackDetails
import io.ktor.client.request.* import io.ktor.client.request.*
import io.ktor.client.statement.* import io.ktor.client.statement.*
import io.ktor.http.* import io.ktor.http.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flow
import kotlin.math.roundToInt import kotlin.math.roundToInt

View File

@ -1,6 +1,7 @@
package com.shabinder.common.di package com.shabinder.common.di
import com.shabinder.common.models.TrackDetails import com.shabinder.common.models.TrackDetails
import kotlinx.coroutines.CoroutineDispatcher
expect fun openPlatform(packageID:String, platformLink:String) expect fun openPlatform(packageID:String, platformLink:String)
@ -8,6 +9,10 @@ expect fun shareApp()
expect fun giveDonation() expect fun giveDonation()
expect fun showPopUpMessage(text: String)
expect val dispatcherIO: CoroutineDispatcher
expect suspend fun downloadTracks( expect suspend fun downloadTracks(
list: List<TrackDetails>, list: List<TrackDetails>,
getYTIDBestMatch:suspend (String,TrackDetails)->String?, getYTIDBestMatch:suspend (String,TrackDetails)->String?,

View File

@ -1,11 +1,11 @@
package com.shabinder.common.di package com.shabinder.common.di
import com.shabinder.common.models.PlatformQueryResult
import com.shabinder.common.database.DownloadRecordDatabaseQueries import com.shabinder.common.database.DownloadRecordDatabaseQueries
import com.shabinder.common.di.providers.GaanaProvider import com.shabinder.common.di.providers.GaanaProvider
import com.shabinder.common.di.providers.SpotifyProvider import com.shabinder.common.di.providers.SpotifyProvider
import com.shabinder.common.di.providers.YoutubeMp3 import com.shabinder.common.di.providers.YoutubeMp3
import com.shabinder.common.di.providers.YoutubeMusic import com.shabinder.common.di.providers.YoutubeMusic
import com.shabinder.common.models.PlatformQueryResult
import com.shabinder.database.Database import com.shabinder.database.Database
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext

View File

@ -1,4 +1,4 @@
package com.shabinder.common.ui package com.shabinder.common.di
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState import androidx.compose.runtime.MutableState

View File

@ -2,8 +2,8 @@ package com.shabinder.common.di
import co.touchlab.kermit.Kermit import co.touchlab.kermit.Kermit
import com.shabinder.common.database.TokenDBQueries import com.shabinder.common.database.TokenDBQueries
import com.shabinder.common.models.spotify.TokenData
import com.shabinder.common.di.spotify.authenticateSpotify import com.shabinder.common.di.spotify.authenticateSpotify
import com.shabinder.common.models.spotify.TokenData
import com.shabinder.database.Database import com.shabinder.database.Database
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch

View File

@ -21,10 +21,10 @@ import com.shabinder.common.database.DownloadRecordDatabaseQueries
import com.shabinder.common.di.Dir import com.shabinder.common.di.Dir
import com.shabinder.common.di.finalOutputDir import com.shabinder.common.di.finalOutputDir
import com.shabinder.common.di.gaana.GaanaRequests import com.shabinder.common.di.gaana.GaanaRequests
import com.shabinder.common.models.gaana.GaanaTrack
import com.shabinder.common.models.DownloadStatus import com.shabinder.common.models.DownloadStatus
import com.shabinder.common.models.PlatformQueryResult import com.shabinder.common.models.PlatformQueryResult
import com.shabinder.common.models.TrackDetails import com.shabinder.common.models.TrackDetails
import com.shabinder.common.models.gaana.GaanaTrack
import com.shabinder.common.models.spotify.Source import com.shabinder.common.models.spotify.Source
import com.shabinder.database.Database import com.shabinder.database.Database
import io.ktor.client.* import io.ktor.client.*
@ -169,7 +169,7 @@ class GaanaProvider(
subFolder = link subFolder = link
coverUrl = gaanaPlaceholderImageUrl coverUrl = gaanaPlaceholderImageUrl
val artistDetails = val artistDetails =
getGaanaArtistDetails(seokey = link).artist?.firstOrNull() getGaanaArtistDetails(seokey = link).artist.firstOrNull()
?.also { ?.also {
title = it.name title = it.name
coverUrl = it.artworkLink ?: gaanaPlaceholderImageUrl coverUrl = it.artworkLink ?: gaanaPlaceholderImageUrl

View File

@ -1,7 +1,6 @@
package com.shabinder.common.di.providers package com.shabinder.common.di.providers
import co.touchlab.kermit.Kermit import co.touchlab.kermit.Kermit
import co.touchlab.kermit.Logger
import com.shabinder.common.models.TrackDetails import com.shabinder.common.models.TrackDetails
import com.shabinder.common.models.YoutubeTrack import com.shabinder.common.models.YoutubeTrack
import com.willowtreeapps.fuzzywuzzy.diffutils.FuzzySearch import com.willowtreeapps.fuzzywuzzy.diffutils.FuzzySearch

View File

@ -2,7 +2,6 @@ package com.shabinder.common.di.spotify
import com.shabinder.common.di.kotlinxSerializer import com.shabinder.common.di.kotlinxSerializer
import com.shabinder.common.models.spotify.TokenData import com.shabinder.common.models.spotify.TokenData
import com.shabinder.database.Database
import io.ktor.client.* import io.ktor.client.*
import io.ktor.client.features.auth.* import io.ktor.client.features.auth.*
import io.ktor.client.features.auth.providers.* import io.ktor.client.features.auth.providers.*
@ -10,7 +9,6 @@ import io.ktor.client.features.json.*
import io.ktor.client.request.* import io.ktor.client.request.*
import io.ktor.client.request.forms.* import io.ktor.client.request.forms.*
import io.ktor.http.* import io.ktor.http.*
import kotlinx.datetime.Clock
suspend fun authenticateSpotify(): TokenData { suspend fun authenticateSpotify(): TokenData {
return spotifyAuthClient.post("https://accounts.spotify.com/api/token"){ return spotifyAuthClient.post("https://accounts.spotify.com/api/token"){

View File

@ -7,8 +7,8 @@ import com.github.kiulian.downloader.model.quality.AudioQuality
import com.shabinder.common.models.DownloadResult import com.shabinder.common.models.DownloadResult
import com.shabinder.common.models.DownloadStatus import com.shabinder.common.models.DownloadStatus
import com.shabinder.common.models.TrackDetails import com.shabinder.common.models.TrackDetails
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.flow.collect
actual fun openPlatform(packageID:String, platformLink:String){ actual fun openPlatform(packageID:String, platformLink:String){
//TODO //TODO

View File

@ -10,7 +10,10 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.jetbrains.skija.Image import org.jetbrains.skija.Image
import java.awt.image.BufferedImage import java.awt.image.BufferedImage
import java.io.* import java.io.ByteArrayOutputStream
import java.io.File
import java.io.IOException
import java.io.InputStream
import java.net.HttpURLConnection import java.net.HttpURLConnection
import java.net.URL import java.net.URL
import javax.imageio.ImageIO import javax.imageio.ImageIO

View File

@ -1,6 +1,9 @@
package com.shabinder.common.ui package com.shabinder.common.di
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Surface import androidx.compose.material.Surface
import androidx.compose.material.Text import androidx.compose.material.Text

View File

@ -18,10 +18,10 @@ package com.shabinder.common.di
import co.touchlab.kermit.Kermit import co.touchlab.kermit.Kermit
import com.github.kiulian.downloader.YoutubeDownloader import com.github.kiulian.downloader.YoutubeDownloader
import com.shabinder.common.database.DownloadRecordDatabaseQueries
import com.shabinder.common.models.DownloadStatus import com.shabinder.common.models.DownloadStatus
import com.shabinder.common.models.PlatformQueryResult import com.shabinder.common.models.PlatformQueryResult
import com.shabinder.common.models.TrackDetails import com.shabinder.common.models.TrackDetails
import com.shabinder.common.database.DownloadRecordDatabaseQueries
import com.shabinder.common.models.spotify.Source import com.shabinder.common.models.spotify.Source
import com.shabinder.database.Database import com.shabinder.database.Database
import io.ktor.client.* import io.ktor.client.*

View File

@ -1,26 +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/>.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M12,4c4.41,0 8,3.59 8,8s-3.59,8 -8,8s-8,-3.59 -8,-8S7.59,4 12,4M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10c5.52,0 10,-4.48 10,-10C22,6.48 17.52,2 12,2L12,2zM13,12l0,-4h-2l0,4H8l4,4l4,-4H13z"/>
</vector>

View File

@ -1,26 +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/>.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M12,2C6.47,2 2,6.47 2,12s4.47,10 10,10 10,-4.47 10,-10S17.53,2 12,2zM16.3,16.3c-0.39,0.39 -1.02,0.39 -1.41,0L12,13.41 9.11,16.3c-0.39,0.39 -1.02,0.39 -1.41,0 -0.39,-0.39 -0.39,-1.02 0,-1.41L10.59,12 7.7,9.11c-0.39,-0.39 -0.39,-1.02 0,-1.41 0.39,-0.39 1.02,-0.39 1.41,0L12,10.59l2.89,-2.89c0.39,-0.39 1.02,-0.39 1.41,0 0.39,0.39 0.39,1.02 0,1.41L13.41,12l2.89,2.89c0.38,0.38 0.38,1.02 0,1.41z"/>
</vector>

View File

@ -1,47 +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/>.
-->
<vector android:height="150dp" android:viewportHeight="512"
android:viewportWidth="512" android:width="150dp"
xmlns:aapt="http://schemas.android.com/aapt" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:pathData="M256,256m-256,0a256,256 0,1 1,512 0a256,256 0,1 1,-512 0">
<aapt:attr name="android:fillColor">
<gradient android:endX="437.019" android:endY="74.981"
android:startX="74.981" android:startY="437.019" android:type="linear">
<item android:color="#FF736BFD" android:offset="0"/>
<item android:color="#FFF54187" android:offset="1"/>
</gradient>
</aapt:attr>
</path>
<path android:fillColor="#FF000000" android:pathData="M377,356.7c-68.9,-45.4 -155.6,-56.4 -257.6,-32.7c-20.5,4.8 -13.6,35.8 7.3,31.2C290.7,317 351.6,386 368.2,386C384,386 390.2,365.4 377,356.7z"/>
<path android:fillColor="#FF000000" android:pathData="M112.1,275.1C203.9,253.4 308.1,266 384,308c18.5,10.2 34,-17.8 15.5,-28c-82.7,-45.7 -195.6,-59.5 -294.7,-36C84.2,248.8 91.5,280 112.1,275.1L112.1,275.1z"/>
<path android:fillColor="#FF000000" android:pathData="M100,191.9c96.6,-29.6 232.2,-13.4 308.7,36.9c17.6,11.5 35.3,-15.1 17.6,-26.7c-84.9,-55.8 -229.2,-73.3 -335.6,-40.8C70.4,167.5 79.9,198.1 100,191.9L100,191.9z"/>
<path android:pathData="M507.8,438.2c-1.6,97.2 -141.9,97.1 -143.5,0C365.9,341 506.2,341 507.8,438.2z">
<aapt:attr name="android:fillColor">
<gradient android:endX="384.197" android:endY="490.009"
android:startX="487.832" android:startY="386.374" android:type="linear">
<item android:color="#FF736BFD" android:offset="0"/>
<item android:color="#FFF54187" android:offset="1"/>
</gradient>
</aapt:attr>
</path>
<path android:fillColor="#FF000000"
android:pathData="M486.8,456.8c-0.6,-2.4 -6.9,-1 -8.5,-1.4c11.5,-82 -82.4,-86.7 -87.1,-22.2c0.3,1.8 -1,6.7 2.2,6.6c0,0 8.6,0 8.6,0c3.1,0.1 2,-4.7 2.2,-6.6c0.1,-23.3 35,-23.3 35.2,0c0,0 0,6.9 0,6.9c-0.1,2.8 4.4,2.8 4.3,0c5,-35.2 -43.8,-40.1 -43.8,-4.7h-4.3c-1.6,-53.7 77.2,-55.9 78.4,-2.2c0,0 0,24.4 0,24.4c-0.1,2.9 3.8,2.1 5.6,2.2l-20.7,21l-20.7,-21c1.8,-0.1 5.6,0.7 5.6,-2.2c0,0 0,-8.8 0,-8.8c0,-2.8 -4.4,-2.8 -4.3,0c0,0 0,6.6 0,6.6c-2.2,0.2 -11.3,-1.3 -8,3.7c0,0 25.9,26.3 25.9,26.3c0.8,0.9 2.2,0.9 3.1,0C460.6,484.4 489.4,458.3 486.8,456.8z"
android:strokeColor="#000" android:strokeWidth=".75"/>
<path android:fillColor="#00000000"
android:pathData="M510,437.5c-1.7,96.2 -142.1,96.2 -143.8,0C367.9,341.3 508.4,341.3 510,437.5z"
android:strokeColor="#000" android:strokeWidth="6"/>
</vector>

View File

@ -0,0 +1,22 @@
plugins {
id("multiplatform-compose-setup")
id("android-setup")
id("kotlin-parcelize")
}
kotlin {
sourceSets {
commonMain {
dependencies {
implementation(project(":common:dependency-injection"))
implementation(project(":common:data-models"))
implementation(project(":common:database"))
implementation(SqlDelight.coroutineExtensions)
implementation(MVIKotlin.coroutines)
implementation(MVIKotlin.mvikotlin)
implementation(Decompose.decompose)
implementation(Decompose.extensionsCompose)
}
}
}
}

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.shabinder.common.ui"/>

View File

@ -1,21 +1,17 @@
package com.shabinder.common.list package com.shabinder.common.list
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.snapshots.SnapshotStateList
import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.ImageBitmap
import com.arkivanov.decompose.ComponentContext import com.arkivanov.decompose.ComponentContext
import com.arkivanov.mvikotlin.core.store.StoreFactory import com.arkivanov.mvikotlin.core.store.StoreFactory
import com.shabinder.common.di.Dir import com.shabinder.common.di.Dir
import com.shabinder.common.di.FetchPlatformQueryResult import com.shabinder.common.di.FetchPlatformQueryResult
import com.shabinder.common.list.integration.SpotiFlyerListImpl import com.shabinder.common.list.integration.SpotiFlyerListImpl
import com.shabinder.common.models.Consumer
import com.shabinder.common.models.DownloadStatus import com.shabinder.common.models.DownloadStatus
import com.shabinder.common.models.spotify.Source
import com.shabinder.common.utils.Consumer
import com.shabinder.common.models.PlatformQueryResult import com.shabinder.common.models.PlatformQueryResult
import com.shabinder.common.models.TrackDetails import com.shabinder.common.models.TrackDetails
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.StateFlow
interface SpotiFlyerList { interface SpotiFlyerList {

View File

@ -3,13 +3,13 @@ package com.shabinder.common.list.integration
import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.ImageBitmap
import com.arkivanov.decompose.ComponentContext import com.arkivanov.decompose.ComponentContext
import com.arkivanov.mvikotlin.extensions.coroutines.states import com.arkivanov.mvikotlin.extensions.coroutines.states
import com.shabinder.common.models.TrackDetails
import com.shabinder.common.list.SpotiFlyerList import com.shabinder.common.list.SpotiFlyerList
import com.shabinder.common.list.SpotiFlyerList.Dependencies import com.shabinder.common.list.SpotiFlyerList.Dependencies
import com.shabinder.common.list.SpotiFlyerList.State import com.shabinder.common.list.SpotiFlyerList.State
import com.shabinder.common.list.store.SpotiFlyerListStore.Intent import com.shabinder.common.list.store.SpotiFlyerListStore.Intent
import com.shabinder.common.list.store.SpotiFlyerListStoreProvider import com.shabinder.common.list.store.SpotiFlyerListStoreProvider
import com.shabinder.common.utils.getStore import com.shabinder.common.list.store.getStore
import com.shabinder.common.models.TrackDetails
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
internal class SpotiFlyerListImpl( internal class SpotiFlyerListImpl(

View File

@ -1,4 +1,4 @@
package com.shabinder.common.utils package com.shabinder.common.list.store
import com.arkivanov.decompose.instancekeeper.InstanceKeeper import com.arkivanov.decompose.instancekeeper.InstanceKeeper
import com.arkivanov.decompose.instancekeeper.getOrCreate import com.arkivanov.decompose.instancekeeper.getOrCreate
@ -8,7 +8,9 @@ fun <T : Store<*, *, *>> InstanceKeeper.getStore(key: Any, factory: () -> T): T
getOrCreate(key) { StoreHolder(factory()) } getOrCreate(key) { StoreHolder(factory()) }
.store .store
inline fun <reified T : Store<*, *, *>> InstanceKeeper.getStore(noinline factory: () -> T): T = inline fun <reified T
: Store<*, *, *>> InstanceKeeper.getStore(noinline factory: () -> T): T =
getStore(T::class, factory) getStore(T::class, factory)
private class StoreHolder<T : Store<*, *, *>>( private class StoreHolder<T : Store<*, *, *>>(

View File

@ -1,9 +1,9 @@
package com.shabinder.common.list.store package com.shabinder.common.list.store
import com.arkivanov.mvikotlin.core.store.Store import com.arkivanov.mvikotlin.core.store.Store
import com.shabinder.common.models.TrackDetails
import com.shabinder.common.list.SpotiFlyerList.State import com.shabinder.common.list.SpotiFlyerList.State
import com.shabinder.common.list.store.SpotiFlyerListStore.* import com.shabinder.common.list.store.SpotiFlyerListStore.Intent
import com.shabinder.common.models.TrackDetails
internal interface SpotiFlyerListStore: Store<Intent, State, Nothing> { internal interface SpotiFlyerListStore: Store<Intent, State, Nothing> {
sealed class Intent { sealed class Intent {

View File

@ -3,16 +3,12 @@ package com.shabinder.common.list.store
import com.arkivanov.mvikotlin.core.store.* import com.arkivanov.mvikotlin.core.store.*
import com.arkivanov.mvikotlin.extensions.coroutines.SuspendExecutor import com.arkivanov.mvikotlin.extensions.coroutines.SuspendExecutor
import com.shabinder.common.database.getLogger import com.shabinder.common.database.getLogger
import com.shabinder.common.di.Dir import com.shabinder.common.di.*
import com.shabinder.common.di.FetchPlatformQueryResult
import com.shabinder.common.di.downloadTracks
import com.shabinder.common.di.queryActiveTracks
import com.shabinder.common.list.SpotiFlyerList.State import com.shabinder.common.list.SpotiFlyerList.State
import com.shabinder.common.list.store.SpotiFlyerListStore.Intent import com.shabinder.common.list.store.SpotiFlyerListStore.Intent
import com.shabinder.common.models.DownloadStatus import com.shabinder.common.models.DownloadStatus
import com.shabinder.common.models.PlatformQueryResult import com.shabinder.common.models.PlatformQueryResult
import com.shabinder.common.models.TrackDetails import com.shabinder.common.models.TrackDetails
import com.shabinder.common.ui.showPopUpMessage
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.shabinder.common.ui"/>

View File

@ -4,9 +4,9 @@ import androidx.compose.ui.graphics.ImageBitmap
import com.arkivanov.decompose.ComponentContext import com.arkivanov.decompose.ComponentContext
import com.arkivanov.mvikotlin.core.store.StoreFactory import com.arkivanov.mvikotlin.core.store.StoreFactory
import com.shabinder.common.di.Dir import com.shabinder.common.di.Dir
import com.shabinder.common.models.DownloadRecord
import com.shabinder.common.main.integration.SpotiFlyerMainImpl import com.shabinder.common.main.integration.SpotiFlyerMainImpl
import com.shabinder.common.utils.Consumer import com.shabinder.common.models.Consumer
import com.shabinder.common.models.DownloadRecord
import com.shabinder.database.Database import com.shabinder.database.Database
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow

View File

@ -7,7 +7,7 @@ import com.shabinder.common.main.SpotiFlyerMain
import com.shabinder.common.main.SpotiFlyerMain.* import com.shabinder.common.main.SpotiFlyerMain.*
import com.shabinder.common.main.store.SpotiFlyerMainStore.Intent import com.shabinder.common.main.store.SpotiFlyerMainStore.Intent
import com.shabinder.common.main.store.SpotiFlyerMainStoreProvider import com.shabinder.common.main.store.SpotiFlyerMainStoreProvider
import com.shabinder.common.utils.getStore import com.shabinder.common.main.store.getStore
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
internal class SpotiFlyerMainImpl( internal class SpotiFlyerMainImpl(

View File

@ -0,0 +1,22 @@
package com.shabinder.common.main.store
import com.arkivanov.decompose.instancekeeper.InstanceKeeper
import com.arkivanov.decompose.instancekeeper.getOrCreate
import com.arkivanov.mvikotlin.core.store.Store
fun <T : Store<*, *, *>> InstanceKeeper.getStore(key: Any, factory: () -> T): T =
getOrCreate(key) { StoreHolder(factory()) }
.store
inline fun <reified T
: Store<*, *, *>> InstanceKeeper.getStore(noinline factory: () -> T): T =
getStore(T::class, factory)
private class StoreHolder<T : Store<*, *, *>>(
val store: T
) : InstanceKeeper.Instance {
override fun onDestroy() {
store.dispose()
}
}

View File

@ -2,7 +2,7 @@ package com.shabinder.common.main.store
import com.arkivanov.mvikotlin.core.store.Store import com.arkivanov.mvikotlin.core.store.Store
import com.shabinder.common.main.SpotiFlyerMain import com.shabinder.common.main.SpotiFlyerMain
import com.shabinder.common.main.store.SpotiFlyerMainStore.* import com.shabinder.common.main.store.SpotiFlyerMainStore.Intent
internal interface SpotiFlyerMainStore: Store<Intent, SpotiFlyerMain.State, Nothing> { internal interface SpotiFlyerMainStore: Store<Intent, SpotiFlyerMain.State, Nothing> {
sealed class Intent { sealed class Intent {

View File

@ -5,13 +5,13 @@ import com.arkivanov.mvikotlin.core.store.SimpleBootstrapper
import com.arkivanov.mvikotlin.core.store.Store import com.arkivanov.mvikotlin.core.store.Store
import com.arkivanov.mvikotlin.core.store.StoreFactory import com.arkivanov.mvikotlin.core.store.StoreFactory
import com.arkivanov.mvikotlin.extensions.coroutines.SuspendExecutor import com.arkivanov.mvikotlin.extensions.coroutines.SuspendExecutor
import com.shabinder.common.models.DownloadRecord
import com.shabinder.common.di.giveDonation import com.shabinder.common.di.giveDonation
import com.shabinder.common.di.openPlatform
import com.shabinder.common.di.shareApp
import com.shabinder.common.main.SpotiFlyerMain import com.shabinder.common.main.SpotiFlyerMain
import com.shabinder.common.main.SpotiFlyerMain.State import com.shabinder.common.main.SpotiFlyerMain.State
import com.shabinder.common.main.store.SpotiFlyerMainStore.Intent import com.shabinder.common.main.store.SpotiFlyerMainStore.Intent
import com.shabinder.common.di.openPlatform import com.shabinder.common.models.DownloadRecord
import com.shabinder.common.di.shareApp
import com.shabinder.database.Database import com.shabinder.database.Database
import com.squareup.sqldelight.runtime.coroutines.asFlow import com.squareup.sqldelight.runtime.coroutines.asFlow
import com.squareup.sqldelight.runtime.coroutines.mapToList import com.squareup.sqldelight.runtime.coroutines.mapToList

View File

@ -0,0 +1,28 @@
import org.jetbrains.compose.compose
plugins {
id("multiplatform-compose-setup")
id("android-setup")
id("kotlin-parcelize")
}
kotlin {
sourceSets {
commonMain {
dependencies {
implementation(compose.materialIconsExtended)
implementation(project(":common:dependency-injection"))
//implementation("com.alialbaali.kamel:kamel-image:0.1.0")
implementation(project(":common:data-models"))
implementation(project(":common:database"))
implementation(project(":common:list"))
implementation(project(":common:main"))
implementation(SqlDelight.coroutineExtensions)
implementation(MVIKotlin.coroutines)
implementation(MVIKotlin.mvikotlin)
implementation(Decompose.decompose)
implementation(Decompose.extensionsCompose)
}
}
}
}

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.shabinder.common.ui"/>

View File

@ -11,11 +11,9 @@ import com.shabinder.common.main.SpotiFlyerMain
import com.shabinder.common.models.DownloadStatus import com.shabinder.common.models.DownloadStatus
import com.shabinder.common.root.SpotiFlyerRoot.Dependencies import com.shabinder.common.root.SpotiFlyerRoot.Dependencies
import com.shabinder.common.root.callbacks.SpotiFlyerRootCallBacks import com.shabinder.common.root.callbacks.SpotiFlyerRootCallBacks
import com.shabinder.database.Database
import com.shabinder.common.root.integration.SpotiFlyerRootImpl import com.shabinder.common.root.integration.SpotiFlyerRootImpl
import com.shabinder.common.utils.Consumer import com.shabinder.database.Database
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.StateFlow
interface SpotiFlyerRoot { interface SpotiFlyerRoot {

View File

@ -1,25 +1,17 @@
package com.shabinder.common.root.integration package com.shabinder.common.root.integration
import co.touchlab.kermit.Kermit import com.arkivanov.decompose.*
import com.arkivanov.decompose.ComponentContext
import com.arkivanov.decompose.RouterState
import com.arkivanov.decompose.pop
import com.arkivanov.decompose.push
import com.arkivanov.decompose.router
import com.arkivanov.decompose.statekeeper.Parcelable import com.arkivanov.decompose.statekeeper.Parcelable
import com.arkivanov.decompose.statekeeper.Parcelize import com.arkivanov.decompose.statekeeper.Parcelize
import com.arkivanov.decompose.value.Value import com.arkivanov.decompose.value.Value
import com.shabinder.common.database.getLogger
import com.shabinder.common.di.Dir import com.shabinder.common.di.Dir
import com.shabinder.common.list.SpotiFlyerList import com.shabinder.common.list.SpotiFlyerList
import com.shabinder.common.main.SpotiFlyerMain import com.shabinder.common.main.SpotiFlyerMain
import com.shabinder.common.models.DownloadStatus import com.shabinder.common.models.Consumer
import com.shabinder.common.root.SpotiFlyerRoot import com.shabinder.common.root.SpotiFlyerRoot
import com.shabinder.common.root.SpotiFlyerRoot.Child import com.shabinder.common.root.SpotiFlyerRoot.Child
import com.shabinder.common.root.SpotiFlyerRoot.Dependencies import com.shabinder.common.root.SpotiFlyerRoot.Dependencies
import com.shabinder.common.root.callbacks.SpotiFlyerRootCallBacks import com.shabinder.common.root.callbacks.SpotiFlyerRootCallBacks
import com.shabinder.common.utils.Consumer
import kotlinx.coroutines.flow.StateFlow
internal class SpotiFlyerRootImpl( internal class SpotiFlyerRootImpl(
componentContext: ComponentContext, componentContext: ComponentContext,

View File

@ -21,7 +21,7 @@ kotlin {
implementation(compose.desktop.currentOs) implementation(compose.desktop.currentOs)
implementation(project(":common:database")) implementation(project(":common:database"))
implementation(project(":common:dependency-injection")) implementation(project(":common:dependency-injection"))
implementation(project(":common:compose-ui")) implementation(project(":common:compose"))
implementation(Decompose.decompose) implementation(Decompose.decompose)
implementation(Decompose.extensionsCompose) implementation(Decompose.extensionsCompose)
implementation(MVIKotlin.mvikotlin) implementation(MVIKotlin.mvikotlin)

View File

@ -16,12 +16,11 @@ import com.shabinder.common.di.FetchPlatformQueryResult
import com.shabinder.common.di.initKoin import com.shabinder.common.di.initKoin
import com.shabinder.common.root.SpotiFlyerRoot import com.shabinder.common.root.SpotiFlyerRoot
import com.shabinder.common.root.SpotiFlyerRootContent import com.shabinder.common.root.SpotiFlyerRootContent
import com.shabinder.common.ui.SpotiFlyerColors import com.shabinder.common.uikit.SpotiFlyerColors
import com.shabinder.common.ui.SpotiFlyerShapes import com.shabinder.common.uikit.SpotiFlyerShapes
import com.shabinder.common.ui.SpotiFlyerTypography import com.shabinder.common.uikit.SpotiFlyerTypography
import com.shabinder.common.ui.colorOffWhite import com.shabinder.common.uikit.colorOffWhite
import com.shabinder.database.Database import com.shabinder.database.Database
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch import kotlinx.coroutines.launch

View File

@ -78,7 +78,7 @@ class Extractor(private var cutoff: Int = 0) {
fun extractOne(query: String, choices: Collection<String>, func: Applicable): ExtractedResult { fun extractOne(query: String, choices: Collection<String>, func: Applicable): ExtractedResult {
val extracted = extractWithoutOrder(query, choices, func) val extracted = extractWithoutOrder(query, choices, func)
return extracted.max()!! return extracted.maxOrNull()!!
} }
/** /**
@ -95,7 +95,7 @@ class Extractor(private var cutoff: Int = 0) {
val extracted = extractWithoutOrder(query, choices, toStringFunction, func) val extracted = extractWithoutOrder(query, choices, toStringFunction, func)
return extracted.max()!! return extracted.maxOrNull()!!
} }

View File

@ -1,3 +1,5 @@
@file:Suppress("UNCHECKED_CAST")
package com.willowtreeapps.fuzzywuzzy.diffutils package com.willowtreeapps.fuzzywuzzy.diffutils
/* /*
* Copyright (c) 2017 Kotlin Algorithm Club * Copyright (c) 2017 Kotlin Algorithm Club

Some files were not shown because too many files have changed in this diff Show More