mirror of
https://github.com/Shabinder/SpotiFlyer.git
synced 2024-11-26 02:24:31 +01:00
Fixes & Refactors
This commit is contained in:
parent
85a8dfec68
commit
f9120a1fb4
@ -9,6 +9,7 @@ import com.arkivanov.mvikotlin.logging.store.LoggingStoreFactory
|
|||||||
import com.arkivanov.mvikotlin.main.store.DefaultStoreFactory
|
import com.arkivanov.mvikotlin.main.store.DefaultStoreFactory
|
||||||
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.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.SpotiFlyerTheme
|
import com.shabinder.common.ui.SpotiFlyerTheme
|
||||||
@ -28,6 +29,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
SpotiFlyerRootContent(rootComponent(::spotiFlyerRoot))
|
SpotiFlyerRootContent(rootComponent(::spotiFlyerRoot))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
dir.createDirectories()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ kotlin {
|
|||||||
implementation(compose.materialIconsExtended)
|
implementation(compose.materialIconsExtended)
|
||||||
//implementation("org.jetbrains.compose.material:material-icons-extended:0.3.0-build150")
|
//implementation("org.jetbrains.compose.material:material-icons-extended:0.3.0-build150")
|
||||||
implementation(project(":common:dependency-injection"))
|
implementation(project(":common:dependency-injection"))
|
||||||
|
//implementation("com.alialbaali.kamel:kamel-image:0.0.7")
|
||||||
implementation(project(":common:data-models"))
|
implementation(project(":common:data-models"))
|
||||||
implementation(project(":common:database"))
|
implementation(project(":common:database"))
|
||||||
implementation(SqlDelight.coroutineExtensions)
|
implementation(SqlDelight.coroutineExtensions)
|
||||||
|
@ -1,48 +1,9 @@
|
|||||||
package com.shabinder.common.ui
|
package com.shabinder.common.ui
|
||||||
|
|
||||||
import androidx.compose.foundation.Image
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.graphics.ImageBitmap
|
|
||||||
import androidx.compose.ui.graphics.asImageBitmap
|
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
|
||||||
import androidx.compose.ui.res.vectorResource
|
|
||||||
import com.shabinder.common.di.Picture
|
|
||||||
import com.shabinder.common.database.appContext
|
import com.shabinder.common.database.appContext
|
||||||
|
|
||||||
@Composable
|
|
||||||
actual fun ImageLoad(
|
|
||||||
pic: Picture?,
|
|
||||||
modifier: Modifier
|
|
||||||
){
|
|
||||||
Image(pic?.image?.asImageBitmap(), vectorResource(R.drawable.music) ,"Image",modifier)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun Image(pic: ImageBitmap?, placeholder:ImageVector, desc: String,modifier:Modifier = Modifier) {
|
|
||||||
if(pic == null) Image(placeholder,desc,modifier) else Image(pic,desc,modifier)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
@Composable
|
|
||||||
actual fun ImageLoad(
|
|
||||||
url:String,
|
|
||||||
loadingResource:ImageBitmap?,
|
|
||||||
errorResource:ImageBitmap?,
|
|
||||||
modifier: Modifier
|
|
||||||
){
|
|
||||||
val imgUri = url.toUri().buildUpon().scheme("https").build()
|
|
||||||
CoilImage(
|
|
||||||
data = imgUri,
|
|
||||||
contentScale = ContentScale.Crop,
|
|
||||||
loading = { loadingResource?.let { Image(it,"loading image") } },
|
|
||||||
error = { errorResource?.let { it1 -> Image(it1,"Error Image") } },
|
|
||||||
modifier = modifier
|
|
||||||
)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun Toast(
|
actual fun Toast(
|
||||||
text: String,
|
text: String,
|
||||||
|
@ -34,6 +34,9 @@ actual fun DownloadImageArrow(modifier: Modifier){
|
|||||||
@Composable
|
@Composable
|
||||||
actual fun DownloadAllImage() = vectorResource(R.drawable.ic_download_arrow)
|
actual fun DownloadAllImage() = vectorResource(R.drawable.ic_download_arrow)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
actual fun PlaceHolderImage() = vectorResource(R.drawable.music)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun SpotiFlyerLogo() = vectorResource(R.drawable.ic_spotiflyer_logo)
|
actual fun SpotiFlyerLogo() = vectorResource(R.drawable.ic_spotiflyer_logo)
|
||||||
|
|
||||||
@ -51,5 +54,6 @@ actual fun YoutubeLogo() = vectorResource(R.drawable.ic_youtube)
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun YoutubeMusicLogo() = vectorResource(R.drawable.ic_youtube_music_logo)
|
actual fun YoutubeMusicLogo() = vectorResource(R.drawable.ic_youtube_music_logo)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun GithubLogo() = vectorResource(R.drawable.ic_github)
|
actual fun GithubLogo() = vectorResource(R.drawable.ic_github)
|
@ -1,10 +1,10 @@
|
|||||||
package com.shabinder.common.list
|
package com.shabinder.common.list
|
||||||
|
|
||||||
|
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.di.Picture
|
|
||||||
import com.shabinder.common.list.integration.SpotiFlyerListImpl
|
import com.shabinder.common.list.integration.SpotiFlyerListImpl
|
||||||
import com.shabinder.common.models.spotify.Source
|
import com.shabinder.common.models.spotify.Source
|
||||||
import com.shabinder.common.utils.Consumer
|
import com.shabinder.common.utils.Consumer
|
||||||
@ -33,14 +33,14 @@ interface SpotiFlyerList {
|
|||||||
/*
|
/*
|
||||||
* Load Image from cache/Internet and cache it
|
* Load Image from cache/Internet and cache it
|
||||||
* */
|
* */
|
||||||
fun loadImage(url:String): Picture?
|
suspend fun loadImage(url:String): ImageBitmap?
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
val storeFactory: StoreFactory
|
val storeFactory: StoreFactory
|
||||||
val fetchQuery: FetchPlatformQueryResult
|
val fetchQuery: FetchPlatformQueryResult
|
||||||
val dir: Dir
|
val dir: Dir
|
||||||
val link: String
|
val link: String
|
||||||
fun listOutput(finished: Output.Finished): Consumer<Output>
|
val listOutput: Consumer<Output>
|
||||||
}
|
}
|
||||||
sealed class Output {
|
sealed class Output {
|
||||||
object Finished : Output()
|
object Finished : Output()
|
||||||
|
@ -5,25 +5,23 @@ import androidx.compose.foundation.layout.*
|
|||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.material.*
|
import androidx.compose.material.*
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.runtime.collectAsState
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
|
||||||
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.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.ImageBitmap
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
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.models.DownloadStatus
|
import com.shabinder.common.models.DownloadStatus
|
||||||
import com.shabinder.common.di.Picture
|
|
||||||
import com.shabinder.common.models.TrackDetails
|
import com.shabinder.common.models.TrackDetails
|
||||||
import com.shabinder.common.ui.*
|
import com.shabinder.common.ui.*
|
||||||
import com.shabinder.common.ui.SpotiFlyerTypography
|
import com.shabinder.common.ui.SpotiFlyerTypography
|
||||||
import com.shabinder.common.ui.colorAccent
|
import com.shabinder.common.ui.colorAccent
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SpotiFlyerListContent(
|
fun SpotiFlyerListContent(
|
||||||
@ -64,12 +62,17 @@ fun SpotiFlyerListContent(
|
|||||||
fun TrackCard(
|
fun TrackCard(
|
||||||
track: TrackDetails,
|
track: TrackDetails,
|
||||||
downloadTrack:()->Unit,
|
downloadTrack:()->Unit,
|
||||||
loadImage:(String)-> Picture?
|
loadImage:suspend (String)-> ImageBitmap?
|
||||||
) {
|
) {
|
||||||
Row(verticalAlignment = Alignment.CenterVertically,modifier = Modifier.fillMaxWidth().padding(horizontal = 8.dp)) {
|
Row(verticalAlignment = Alignment.CenterVertically,modifier = Modifier.fillMaxWidth().padding(horizontal = 8.dp)) {
|
||||||
val pic: Picture? = loadImage(track.albumArtURL)
|
var pic by mutableStateOf<ImageBitmap?>(null)
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
scope.launch {
|
||||||
|
pic = loadImage(track.albumArtURL)
|
||||||
|
}
|
||||||
ImageLoad(
|
ImageLoad(
|
||||||
pic = pic,
|
pic = pic,
|
||||||
|
"Album Art",
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.preferredWidth(75.dp)
|
.preferredWidth(75.dp)
|
||||||
.preferredHeight(90.dp)
|
.preferredHeight(90.dp)
|
||||||
@ -116,16 +119,20 @@ fun CoverImage(
|
|||||||
title: String,
|
title: String,
|
||||||
coverURL: String,
|
coverURL: String,
|
||||||
scope: CoroutineScope,
|
scope: CoroutineScope,
|
||||||
loadImage: (String) -> Picture?,
|
loadImage: suspend (String) -> ImageBitmap?,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier.padding(vertical = 8.dp).fillMaxWidth(),
|
modifier.padding(vertical = 8.dp).fillMaxWidth(),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
val pic = loadImage(coverURL)
|
var pic by mutableStateOf<ImageBitmap?>(null)
|
||||||
|
scope.launch {
|
||||||
|
pic = loadImage(coverURL)
|
||||||
|
}
|
||||||
ImageLoad(
|
ImageLoad(
|
||||||
pic,
|
pic,
|
||||||
|
"Cover Image",
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.preferredWidth(210.dp)
|
.preferredWidth(210.dp)
|
||||||
.preferredHeight(230.dp)
|
.preferredHeight(230.dp)
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package com.shabinder.common.list.integration
|
package com.shabinder.common.list.integration
|
||||||
|
|
||||||
|
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.di.Picture
|
|
||||||
import com.shabinder.common.models.TrackDetails
|
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
|
||||||
@ -37,8 +37,8 @@ internal class SpotiFlyerListImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onBackPressed(){
|
override fun onBackPressed(){
|
||||||
listOutput(SpotiFlyerList.Output.Finished)
|
listOutput.callback(SpotiFlyerList.Output.Finished)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadImage(url: String): Picture? = dir.loadImage(url)
|
override suspend fun loadImage(url: String): ImageBitmap? = dir.loadImage(url)
|
||||||
}
|
}
|
@ -1,10 +1,10 @@
|
|||||||
package com.shabinder.common.main
|
package com.shabinder.common.main
|
||||||
|
|
||||||
|
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.models.DownloadRecord
|
||||||
import com.shabinder.common.di.Picture
|
|
||||||
import com.shabinder.common.main.integration.SpotiFlyerMainImpl
|
import com.shabinder.common.main.integration.SpotiFlyerMainImpl
|
||||||
import com.shabinder.common.utils.Consumer
|
import com.shabinder.common.utils.Consumer
|
||||||
import com.shabinder.database.Database
|
import com.shabinder.database.Database
|
||||||
@ -33,10 +33,10 @@ interface SpotiFlyerMain {
|
|||||||
/*
|
/*
|
||||||
* Load Image from cache/Internet and cache it
|
* Load Image from cache/Internet and cache it
|
||||||
* */
|
* */
|
||||||
fun loadImage(url:String): Picture?
|
suspend fun loadImage(url:String): ImageBitmap?
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
fun mainOutput(searched: Output): Consumer<Output>
|
val mainOutput: Consumer<Output>
|
||||||
val storeFactory: StoreFactory
|
val storeFactory: StoreFactory
|
||||||
val database: Database
|
val database: Database
|
||||||
val dir: Dir
|
val dir: Dir
|
||||||
|
@ -14,23 +14,24 @@ import androidx.compose.material.icons.Icons
|
|||||||
import androidx.compose.material.icons.outlined.History
|
import androidx.compose.material.icons.outlined.History
|
||||||
import androidx.compose.material.icons.outlined.Info
|
import androidx.compose.material.icons.outlined.Info
|
||||||
import androidx.compose.material.icons.rounded.*
|
import androidx.compose.material.icons.rounded.*
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.runtime.collectAsState
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Brush
|
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.text.TextStyle
|
||||||
import androidx.compose.ui.text.input.KeyboardType
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
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.models.DownloadRecord
|
import com.shabinder.common.models.DownloadRecord
|
||||||
import com.shabinder.common.di.Picture
|
|
||||||
import com.shabinder.common.main.SpotiFlyerMain.HomeCategory
|
import com.shabinder.common.main.SpotiFlyerMain.HomeCategory
|
||||||
import com.shabinder.common.di.openPlatform
|
import com.shabinder.common.di.openPlatform
|
||||||
import com.shabinder.common.ui.*
|
import com.shabinder.common.ui.*
|
||||||
import com.shabinder.common.ui.SpotiFlyerTypography
|
import com.shabinder.common.ui.SpotiFlyerTypography
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SpotiFlyerMainContent(component: SpotiFlyerMain){
|
fun SpotiFlyerMainContent(component: SpotiFlyerMain){
|
||||||
@ -120,18 +121,18 @@ fun SearchPanel(
|
|||||||
value = link,
|
value = link,
|
||||||
onValueChange = updateLink ,
|
onValueChange = updateLink ,
|
||||||
leadingIcon = {
|
leadingIcon = {
|
||||||
Icon(Icons.Rounded.Edit,"Link Text Box",tint = Color(0xFFCCCCCC))//LightGray
|
Icon(Icons.Rounded.Edit,"Link Text Box",tint = Color.LightGray)
|
||||||
},
|
},
|
||||||
label = { Text(text = "Paste Link Here...",color = Color(0xFFCCCCCC)) },
|
label = { Text(text = "Paste Link Here...",color = Color.LightGray) },
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
//textStyle = LocalTextStyle.current.merge(TextStyle(fontSize = 18.sp,color = Color.White)),
|
textStyle = TextStyle.Default.merge(TextStyle(fontSize = 18.sp,color = Color.White)),
|
||||||
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)
|
||||||
),
|
),
|
||||||
backgroundColor = Color(0xFF000000),
|
backgroundColor = Color.Black,
|
||||||
shape = RoundedCornerShape(size = 30.dp),
|
shape = RoundedCornerShape(size = 30.dp),
|
||||||
activeColor = transparent,
|
activeColor = transparent,
|
||||||
inactiveColor = transparent,
|
inactiveColor = transparent,
|
||||||
@ -158,7 +159,7 @@ fun AboutColumn(modifier: Modifier = Modifier) {
|
|||||||
Column(modifier.fillMaxSize().verticalScroll(rememberScrollState())) {
|
Column(modifier.fillMaxSize().verticalScroll(rememberScrollState())) {
|
||||||
Card(
|
Card(
|
||||||
modifier = modifier.fillMaxWidth(),
|
modifier = modifier.fillMaxWidth(),
|
||||||
border = BorderStroke(1.dp,Color(0xFF888888))//Gray
|
border = BorderStroke(1.dp,Color.Gray)
|
||||||
) {
|
) {
|
||||||
Column(modifier.padding(12.dp)) {
|
Column(modifier.padding(12.dp)) {
|
||||||
Text(
|
Text(
|
||||||
@ -171,28 +172,28 @@ fun AboutColumn(modifier: Modifier = Modifier) {
|
|||||||
Icon(
|
Icon(
|
||||||
imageVector = SpotifyLogo(),
|
imageVector = SpotifyLogo(),
|
||||||
"Open Spotify",
|
"Open Spotify",
|
||||||
tint = unspecifiedColor,
|
tint = Color.Unspecified,
|
||||||
modifier = Modifier.clickable(
|
modifier = Modifier.clickable(
|
||||||
onClick = { openPlatform("com.spotify.music","http://open.spotify.com") })
|
onClick = { openPlatform("com.spotify.music","http://open.spotify.com") })
|
||||||
)
|
)
|
||||||
Spacer(modifier = modifier.padding(start = 16.dp))
|
Spacer(modifier = modifier.padding(start = 16.dp))
|
||||||
Icon(imageVector = GaanaLogo(),
|
Icon(imageVector = GaanaLogo(),
|
||||||
"Open Gaana",
|
"Open Gaana",
|
||||||
tint = unspecifiedColor,
|
tint = Color.Unspecified,
|
||||||
modifier = Modifier.clickable(
|
modifier = Modifier.clickable(
|
||||||
onClick = { openPlatform("com.gaana","http://gaana.com") })
|
onClick = { openPlatform("com.gaana","http://gaana.com") })
|
||||||
)
|
)
|
||||||
Spacer(modifier = modifier.padding(start = 16.dp))
|
Spacer(modifier = modifier.padding(start = 16.dp))
|
||||||
Icon(imageVector = YoutubeLogo(),
|
Icon(imageVector = YoutubeLogo(),
|
||||||
"Open Youtube",
|
"Open Youtube",
|
||||||
tint = unspecifiedColor,
|
tint = Color.Unspecified,
|
||||||
modifier = Modifier.clickable(
|
modifier = Modifier.clickable(
|
||||||
onClick = { openPlatform("com.google.android.youtube","http://m.youtube.com") })
|
onClick = { openPlatform("com.google.android.youtube","http://m.youtube.com") })
|
||||||
)
|
)
|
||||||
Spacer(modifier = modifier.padding(start = 12.dp))
|
Spacer(modifier = modifier.padding(start = 12.dp))
|
||||||
Icon(imageVector = YoutubeMusicLogo(),
|
Icon(imageVector = YoutubeMusicLogo(),
|
||||||
"Open Youtube Music",
|
"Open Youtube Music",
|
||||||
tint = unspecifiedColor,
|
tint = Color.Unspecified,
|
||||||
modifier = Modifier.clickable(
|
modifier = Modifier.clickable(
|
||||||
onClick = { openPlatform("com.google.android.apps.youtube.music","https://music.youtube.com/") })
|
onClick = { openPlatform("com.google.android.apps.youtube.music","https://music.youtube.com/") })
|
||||||
)
|
)
|
||||||
@ -202,7 +203,7 @@ fun AboutColumn(modifier: Modifier = Modifier) {
|
|||||||
Spacer(modifier = Modifier.padding(top = 8.dp))
|
Spacer(modifier = Modifier.padding(top = 8.dp))
|
||||||
Card(
|
Card(
|
||||||
modifier = modifier.fillMaxWidth(),
|
modifier = modifier.fillMaxWidth(),
|
||||||
border = BorderStroke(1.dp,Color(0xFF888888))//Gray
|
border = BorderStroke(1.dp,Color.Gray)//Gray
|
||||||
) {
|
) {
|
||||||
Column(modifier.padding(12.dp)) {
|
Column(modifier.padding(12.dp)) {
|
||||||
Text(
|
Text(
|
||||||
@ -300,7 +301,7 @@ fun AboutColumn(modifier: Modifier = Modifier) {
|
|||||||
@Composable
|
@Composable
|
||||||
fun HistoryColumn(
|
fun HistoryColumn(
|
||||||
list: List<DownloadRecord>,
|
list: List<DownloadRecord>,
|
||||||
loadImage:(String)-> Picture?,
|
loadImage:suspend (String)-> ImageBitmap?,
|
||||||
onItemClicked: (String) -> Unit
|
onItemClicked: (String) -> Unit
|
||||||
) {
|
) {
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
@ -321,13 +322,18 @@ fun HistoryColumn(
|
|||||||
@Composable
|
@Composable
|
||||||
fun DownloadRecordItem(
|
fun DownloadRecordItem(
|
||||||
item: DownloadRecord,
|
item: DownloadRecord,
|
||||||
loadImage:(String)-> Picture?,
|
loadImage:suspend (String)-> ImageBitmap?,
|
||||||
onItemClicked:(String)->Unit
|
onItemClicked:(String)->Unit
|
||||||
) {
|
) {
|
||||||
Row(verticalAlignment = Alignment.CenterVertically,modifier = Modifier.fillMaxWidth().padding(end = 8.dp)) {
|
Row(verticalAlignment = Alignment.CenterVertically,modifier = Modifier.fillMaxWidth().padding(end = 8.dp)) {
|
||||||
val pic = loadImage(item.coverUrl)
|
val scope = rememberCoroutineScope()
|
||||||
|
var pic by mutableStateOf<ImageBitmap?>(null)
|
||||||
|
scope.launch(Dispatchers.Unconfined) {
|
||||||
|
pic = loadImage(item.coverUrl)
|
||||||
|
}
|
||||||
ImageLoad(
|
ImageLoad(
|
||||||
pic,
|
pic,
|
||||||
|
"Album Art",
|
||||||
modifier = Modifier.preferredHeight(75.dp).preferredWidth(90.dp)
|
modifier = Modifier.preferredHeight(75.dp).preferredWidth(90.dp)
|
||||||
)
|
)
|
||||||
Column(modifier = Modifier.padding(horizontal = 8.dp).preferredHeight(60.dp).weight(1f),verticalArrangement = Arrangement.SpaceEvenly) {
|
Column(modifier = Modifier.padding(horizontal = 8.dp).preferredHeight(60.dp).weight(1f),verticalArrangement = Arrangement.SpaceEvenly) {
|
||||||
@ -343,7 +349,7 @@ fun DownloadRecordItem(
|
|||||||
}
|
}
|
||||||
Image(
|
Image(
|
||||||
imageVector = Icons.Rounded.Share,
|
imageVector = Icons.Rounded.Share,
|
||||||
"Share App",
|
"Research",
|
||||||
modifier = Modifier.clickable(onClick = {
|
modifier = Modifier.clickable(onClick = {
|
||||||
//if(!isOnline(ctx)) showDialog("Check Your Internet Connection") else
|
//if(!isOnline(ctx)) showDialog("Check Your Internet Connection") else
|
||||||
onItemClicked(item.link)
|
onItemClicked(item.link)
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package com.shabinder.common.main.integration
|
package com.shabinder.common.main.integration
|
||||||
|
|
||||||
|
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.di.Picture
|
|
||||||
import com.shabinder.common.main.SpotiFlyerMain
|
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
|
||||||
@ -26,7 +26,7 @@ internal class SpotiFlyerMainImpl(
|
|||||||
override val models: Flow<State> = store.states
|
override val models: Flow<State> = store.states
|
||||||
|
|
||||||
override fun onLinkSearch(link: String) {
|
override fun onLinkSearch(link: String) {
|
||||||
mainOutput(Output.Search(link = link))
|
mainOutput.callback(Output.Search(link = link))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onInputLinkChanged(link: String) {
|
override fun onInputLinkChanged(link: String) {
|
||||||
@ -37,5 +37,5 @@ internal class SpotiFlyerMainImpl(
|
|||||||
store.accept(Intent.SelectCategory(category))
|
store.accept(Intent.SelectCategory(category))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadImage(url: String): Picture? = dir.loadImage(url)
|
override suspend fun loadImage(url: String): ImageBitmap? = dir.loadImage(url)
|
||||||
}
|
}
|
@ -14,6 +14,7 @@ import com.shabinder.common.main.SpotiFlyerMain
|
|||||||
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.ui.showPopUpMessage
|
||||||
import com.shabinder.common.utils.Consumer
|
import com.shabinder.common.utils.Consumer
|
||||||
|
|
||||||
internal class SpotiFlyerRootImpl(
|
internal class SpotiFlyerRootImpl(
|
||||||
@ -40,7 +41,7 @@ internal class SpotiFlyerRootImpl(
|
|||||||
SpotiFlyerMain(
|
SpotiFlyerMain(
|
||||||
componentContext = componentContext,
|
componentContext = componentContext,
|
||||||
dependencies = object : SpotiFlyerMain.Dependencies, Dependencies by this {
|
dependencies = object : SpotiFlyerMain.Dependencies, Dependencies by this {
|
||||||
override fun mainOutput(searched: SpotiFlyerMain.Output): Consumer<SpotiFlyerMain.Output> = Consumer(::onMainOutput)
|
override val mainOutput: Consumer<SpotiFlyerMain.Output> = Consumer(::onMainOutput)
|
||||||
override val dir: Dir = directories
|
override val dir: Dir = directories
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -52,16 +53,16 @@ internal class SpotiFlyerRootImpl(
|
|||||||
override val fetchQuery = fetchPlatformQueryResult
|
override val fetchQuery = fetchPlatformQueryResult
|
||||||
override val dir: Dir = directories
|
override val dir: Dir = directories
|
||||||
override val link: String = link
|
override val link: String = link
|
||||||
|
override val listOutput : Consumer<SpotiFlyerList.Output> = Consumer(::onListOutput)
|
||||||
override fun listOutput(finished: SpotiFlyerList.Output.Finished): Consumer<SpotiFlyerList.Output> =
|
|
||||||
Consumer(::onListOutput)
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun onMainOutput(output: SpotiFlyerMain.Output): Unit =
|
private fun onMainOutput(output: SpotiFlyerMain.Output){
|
||||||
|
showPopUpMessage("Button Pressed")
|
||||||
when (output) {
|
when (output) {
|
||||||
is SpotiFlyerMain.Output.Search -> router.push(Configuration.List(link = output.link))
|
is SpotiFlyerMain.Output.Search -> router.push(Configuration.List(link = output.link))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun onListOutput(output: SpotiFlyerList.Output): Unit =
|
private fun onListOutput(output: SpotiFlyerList.Output): Unit =
|
||||||
when (output) {
|
when (output) {
|
||||||
|
@ -27,7 +27,6 @@ val colorSuccessGreen = Color(0xFF59C351)
|
|||||||
val darkBackgroundColor = Color(0xFF000000)
|
val darkBackgroundColor = Color(0xFF000000)
|
||||||
val colorOffWhite = Color(0xFFE7E7E7)
|
val colorOffWhite = Color(0xFFE7E7E7)
|
||||||
val transparent = Color(0x00000000)
|
val transparent = Color(0x00000000)
|
||||||
val unspecifiedColor =Color(0f, 0f, 0f, 0f)
|
|
||||||
val black = Color(0xFF000000)
|
val black = Color(0xFF000000)
|
||||||
val lightGray = Color(0xFFCCCCCC)
|
val lightGray = Color(0xFFCCCCCC)
|
||||||
|
|
||||||
|
@ -1,13 +1,3 @@
|
|||||||
package com.shabinder.common.ui
|
package com.shabinder.common.ui
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import com.shabinder.common.di.Picture
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
expect fun ImageLoad(
|
|
||||||
pic: Picture?,
|
|
||||||
modifier: Modifier = Modifier
|
|
||||||
)
|
|
||||||
|
|
||||||
expect fun showPopUpMessage(text: String)
|
expect fun showPopUpMessage(text: String)
|
@ -1,15 +1,25 @@
|
|||||||
package com.shabinder.common.ui
|
package com.shabinder.common.ui
|
||||||
|
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.ImageBitmap
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ImageLoad(pic: ImageBitmap?, desc: String, modifier:Modifier = Modifier, placeholder:ImageVector = PlaceHolderImage()) {
|
||||||
|
if(pic == null) Image(placeholder, desc, modifier) else Image(pic, desc, modifier)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
expect fun DownloadImageTick()
|
expect fun DownloadImageTick()
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
expect fun DownloadAllImage():ImageVector
|
expect fun DownloadAllImage():ImageVector
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
expect fun PlaceHolderImage():ImageVector
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
expect fun SpotiFlyerLogo():ImageVector
|
expect fun SpotiFlyerLogo():ImageVector
|
||||||
|
|
||||||
|
@ -20,12 +20,15 @@ import androidx.compose.foundation.Image
|
|||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.material.Icon
|
import androidx.compose.material.Icon
|
||||||
import androidx.compose.material.Text
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.BrokenImage
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.rememberUpdatedState
|
import androidx.compose.runtime.rememberUpdatedState
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
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.ui.*
|
||||||
@ -43,7 +46,7 @@ fun Splash(modifier: Modifier = Modifier, onTimeout: () -> Unit) {
|
|||||||
delay(SplashWaitTime)
|
delay(SplashWaitTime)
|
||||||
currentOnTimeout()
|
currentOnTimeout()
|
||||||
}
|
}
|
||||||
Image(imageVector = SpotiFlyerLogo(),"SpotiFlyer Logo")
|
Image(imageVector = Icons.Default.BrokenImage/*SpotiFlyerLogo()*/,"SpotiFlyer Logo")
|
||||||
MadeInIndia(Modifier.align(Alignment.BottomCenter))
|
MadeInIndia(Modifier.align(Alignment.BottomCenter))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,7 +69,7 @@ fun MadeInIndia(
|
|||||||
fontSize = 22.sp
|
fontSize = 22.sp
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.padding(start = 4.dp))
|
Spacer(modifier = Modifier.padding(start = 4.dp))
|
||||||
Icon(HeartIcon(),"Love",tint = unspecifiedColor)
|
//Icon(HeartIcon(),"Love",tint = Color.Unspecified)
|
||||||
Spacer(modifier = Modifier.padding(start = 4.dp))
|
Spacer(modifier = Modifier.padding(start = 4.dp))
|
||||||
Text(
|
Text(
|
||||||
text = " in India",
|
text = " in India",
|
||||||
|
@ -4,13 +4,13 @@ package com.shabinder.common.utils
|
|||||||
* Callback Utility
|
* Callback Utility
|
||||||
* */
|
* */
|
||||||
interface Consumer<in T> {
|
interface Consumer<in T> {
|
||||||
fun onCall(value: T)
|
fun callback(value: T)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("FunctionName") // Factory function
|
@Suppress("FunctionName") // Factory function
|
||||||
inline fun <T> Consumer(crossinline block: (T) -> Unit): Consumer<T> =
|
inline fun <T> Consumer(crossinline block: (T) -> Unit): Consumer<T> =
|
||||||
object : Consumer<T> {
|
object : Consumer<T> {
|
||||||
override fun onCall(value: T) {
|
override fun callback(value: T) {
|
||||||
block(value)
|
block(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,31 +9,3 @@ import com.shabinder.common.di.Picture
|
|||||||
import java.awt.image.BufferedImage
|
import java.awt.image.BufferedImage
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import javax.imageio.ImageIO
|
import javax.imageio.ImageIO
|
||||||
|
|
||||||
@Composable
|
|
||||||
actual fun ImageLoad(
|
|
||||||
pic: Picture?,
|
|
||||||
modifier: Modifier
|
|
||||||
){
|
|
||||||
if(pic == null) {
|
|
||||||
Image(
|
|
||||||
vectorXmlResource("common/compose-ui/src/main/res/drawable/music.xml"),
|
|
||||||
"",
|
|
||||||
modifier
|
|
||||||
)
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
Image(
|
|
||||||
org.jetbrains.skija.Image.makeFromEncoded(
|
|
||||||
toByteArray(pic.image)
|
|
||||||
).asImageBitmap(),
|
|
||||||
"Image",
|
|
||||||
modifier = modifier
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fun toByteArray(bitmap: BufferedImage) : ByteArray {
|
|
||||||
val baOs = ByteArrayOutputStream()
|
|
||||||
ImageIO.write(bitmap, "png", baOs)
|
|
||||||
return baOs.toByteArray()
|
|
||||||
}
|
|
@ -34,6 +34,10 @@ actual fun DownloadImageArrow(modifier: Modifier){
|
|||||||
@Composable
|
@Composable
|
||||||
actual fun DownloadAllImage():ImageVector = vectorXmlResource("common/compose-ui/src/main/res/drawable/ic_download_arrow.xml")
|
actual fun DownloadAllImage():ImageVector = vectorXmlResource("common/compose-ui/src/main/res/drawable/ic_download_arrow.xml")
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
actual fun PlaceHolderImage():ImageVector = vectorXmlResource("common/compose-ui/src/main/res/drawable/music.xml")
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun SpotiFlyerLogo():ImageVector = vectorXmlResource("common/compose-ui/src/main/res/drawable/ic_spotiflyer_logo.xml")
|
actual fun SpotiFlyerLogo():ImageVector = vectorXmlResource("common/compose-ui/src/main/res/drawable/ic_spotiflyer_logo.xml")
|
||||||
|
|
||||||
|
@ -24,5 +24,5 @@ data class Artist (
|
|||||||
val popularity : Int,
|
val popularity : Int,
|
||||||
val seokey : String,
|
val seokey : String,
|
||||||
val name : String,
|
val name : String,
|
||||||
@SerialName("artwork_175x175")var artworkLink :String?
|
@SerialName("artwork_175x175")var artworkLink :String? = null
|
||||||
)
|
)
|
@ -18,6 +18,9 @@ package com.shabinder.common.models.gaana
|
|||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class CustomArtworks (
|
data class CustomArtworks (
|
||||||
@SerialName("40x40") val size_40p : String,
|
@SerialName("40x40") val size_40p : String,
|
||||||
@SerialName("80x80") val size_80p : String,
|
@SerialName("80x80") val size_80p : String,
|
||||||
|
@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
package com.shabinder.common.models.gaana
|
package com.shabinder.common.models.gaana
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class GaanaAlbum (
|
data class GaanaAlbum (
|
||||||
val tracks : List<GaanaTrack>,
|
val tracks : List<GaanaTrack>,
|
||||||
val count : Int,
|
val count : Int,
|
||||||
|
@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
package com.shabinder.common.models.gaana
|
package com.shabinder.common.models.gaana
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class GaanaArtistDetails(
|
data class GaanaArtistDetails(
|
||||||
val artist : List<Artist>,
|
val artist : List<Artist>,
|
||||||
val count : Int,
|
val count : Int,
|
||||||
|
@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
package com.shabinder.common.models.gaana
|
package com.shabinder.common.models.gaana
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class GaanaArtistTracks(
|
data class GaanaArtistTracks(
|
||||||
val count : Int,
|
val count : Int,
|
||||||
val tracks : List<GaanaTrack>
|
val tracks : List<GaanaTrack>
|
||||||
|
@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
package com.shabinder.common.models.gaana
|
package com.shabinder.common.models.gaana
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class GaanaPlaylist (
|
data class GaanaPlaylist (
|
||||||
val modified_on : String,
|
val modified_on : String,
|
||||||
val count : Int,
|
val count : Int,
|
||||||
|
@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
package com.shabinder.common.models.gaana
|
package com.shabinder.common.models.gaana
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class GaanaSong(
|
data class GaanaSong(
|
||||||
val tracks : List<GaanaTrack>
|
val tracks : List<GaanaTrack>
|
||||||
)
|
)
|
@ -22,21 +22,21 @@ import kotlinx.serialization.Serializable
|
|||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class GaanaTrack (
|
data class GaanaTrack (
|
||||||
val tags : List<Tags?>?,
|
val tags : List<Tags?>? = null,
|
||||||
val seokey : String,
|
val seokey : String,
|
||||||
val albumseokey : String?,
|
val albumseokey : String? = null,
|
||||||
val track_title : String,
|
val track_title : String,
|
||||||
val album_title : String?,
|
val album_title : String? = null,
|
||||||
val language : String?,
|
val language : String? = null,
|
||||||
val duration: Int,
|
val duration: Int,
|
||||||
@SerialName("artwork_large") val artworkLink : String,
|
@SerialName("artwork_large") val artworkLink : String,
|
||||||
val artist : List<Artist?>,
|
val artist : List<Artist?> = emptyList(),
|
||||||
@SerialName("gener") val genre : List<Genre?>?,
|
@SerialName("gener") val genre : List<Genre?>? = null,
|
||||||
val lyrics_url : String?,
|
val lyrics_url : String? = null,
|
||||||
val youtube_id : String?,
|
val youtube_id : String? = null,
|
||||||
val total_favourite_count : Int?,
|
val total_favourite_count : Int? = null,
|
||||||
val release_date : String?,
|
val release_date : String? = null,
|
||||||
val play_ct : String?,
|
val play_ct : String? = null,
|
||||||
val secondary_language : String?,
|
val secondary_language : String? = null,
|
||||||
var downloaded: DownloadStatus? = DownloadStatus.NotDownloaded
|
var downloaded: DownloadStatus? = DownloadStatus.NotDownloaded
|
||||||
)
|
)
|
@ -4,6 +4,8 @@ import android.content.Context
|
|||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
|
import androidx.compose.ui.graphics.ImageBitmap
|
||||||
|
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.models.TrackDetails
|
||||||
@ -57,25 +59,11 @@ actual class Dir actual constructor(
|
|||||||
File(imageCacheDir()).deleteRecursively()
|
File(imageCacheDir()).deleteRecursively()
|
||||||
}
|
}
|
||||||
|
|
||||||
actual suspend fun cacheImage(picture: Picture) {
|
actual suspend fun cacheImage(image: Any,path:String) {
|
||||||
try {
|
try {
|
||||||
val path = imageCacheDir() + picture.name
|
|
||||||
FileOutputStream(path).use { out ->
|
FileOutputStream(path).use { out ->
|
||||||
picture.image.compress(Bitmap.CompressFormat.JPEG, 100, out)
|
(image as? Bitmap)?.compress(Bitmap.CompressFormat.JPEG, 100, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
val bw =
|
|
||||||
BufferedWriter(
|
|
||||||
OutputStreamWriter(
|
|
||||||
FileOutputStream(path + cacheImagePostfix()), StandardCharsets.UTF_8
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
bw.write(picture.source)
|
|
||||||
bw.write("\r\n${picture.width}")
|
|
||||||
bw.write("\r\n${picture.height}")
|
|
||||||
bw.close()
|
|
||||||
|
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
@ -96,45 +84,20 @@ actual class Dir actual constructor(
|
|||||||
.setId3v2TagsAndSaveFile(trackDetails,path)
|
.setId3v2TagsAndSaveFile(trackDetails,path)
|
||||||
}
|
}
|
||||||
|
|
||||||
actual fun loadImage(url: String): Picture? {
|
actual suspend fun loadImage(url: String): ImageBitmap? {
|
||||||
val cachePath = imageCacheDir() + getNameURL(url)
|
val cachePath = imageCacheDir() + getNameURL(url)
|
||||||
var picture: Picture? = loadCachedImage(cachePath)
|
return (loadCachedImage(cachePath) ?: freshImage(url))?.asImageBitmap()
|
||||||
if (picture == null) picture = freshImage(url)
|
|
||||||
return picture
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadCachedImage(cachePath: String): Picture? {
|
private fun loadCachedImage(cachePath: String): Bitmap? {
|
||||||
return try {
|
return try {
|
||||||
val read = BufferedReader(
|
BitmapFactory.decodeFile(cachePath)
|
||||||
InputStreamReader(
|
|
||||||
FileInputStream(cachePath + cacheImagePostfix()),
|
|
||||||
StandardCharsets.UTF_8
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
val source = read.readLine()
|
|
||||||
val width = read.readLine().toInt()
|
|
||||||
val height = read.readLine().toInt()
|
|
||||||
|
|
||||||
read.close()
|
|
||||||
|
|
||||||
val result: Bitmap? = BitmapFactory.decodeFile(cachePath)
|
|
||||||
|
|
||||||
if (result != null) {
|
|
||||||
com.shabinder.common.di.Picture(
|
|
||||||
source,
|
|
||||||
getNameURL(source),
|
|
||||||
result,
|
|
||||||
width,
|
|
||||||
height
|
|
||||||
)
|
|
||||||
}else null
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private fun freshImage(url:String): Picture?{
|
private suspend fun freshImage(url:String): Bitmap?{
|
||||||
return try {
|
return try {
|
||||||
val source = URL(url)
|
val source = URL(url)
|
||||||
val connection: HttpURLConnection = source.openConnection() as HttpURLConnection
|
val connection: HttpURLConnection = source.openConnection() as HttpURLConnection
|
||||||
@ -145,17 +108,10 @@ actual class Dir actual constructor(
|
|||||||
val result: Bitmap? = BitmapFactory.decodeStream(input)
|
val result: Bitmap? = BitmapFactory.decodeStream(input)
|
||||||
|
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
val picture = com.shabinder.common.di.Picture(
|
|
||||||
url,
|
|
||||||
getNameURL(url),
|
|
||||||
result,
|
|
||||||
result.width,
|
|
||||||
result.height
|
|
||||||
)
|
|
||||||
GlobalScope.launch(Dispatchers.IO) {
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
cacheImage(picture)
|
cacheImage(result,imageCacheDir() + getNameURL(url))
|
||||||
}
|
}
|
||||||
picture
|
result
|
||||||
} else null
|
} else null
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
package com.shabinder.common.di
|
|
||||||
|
|
||||||
import android.graphics.Bitmap
|
|
||||||
|
|
||||||
actual data class Picture(
|
|
||||||
var source: String = "",
|
|
||||||
var name: String = "",
|
|
||||||
var image: Bitmap,
|
|
||||||
var width: Int = 0,
|
|
||||||
var height: Int = 0,
|
|
||||||
var id: Int = 0
|
|
||||||
)
|
|
@ -1,5 +1,6 @@
|
|||||||
package com.shabinder.common.di
|
package com.shabinder.common.di
|
||||||
|
|
||||||
|
import androidx.compose.ui.graphics.ImageBitmap
|
||||||
import co.touchlab.kermit.Kermit
|
import co.touchlab.kermit.Kermit
|
||||||
import com.shabinder.common.models.DownloadResult
|
import com.shabinder.common.models.DownloadResult
|
||||||
import com.shabinder.common.models.TrackDetails
|
import com.shabinder.common.models.TrackDetails
|
||||||
@ -18,8 +19,8 @@ expect class Dir(
|
|||||||
fun defaultDir(): String
|
fun defaultDir(): String
|
||||||
fun imageCacheDir(): String
|
fun imageCacheDir(): String
|
||||||
fun createDirectory(dirPath:String)
|
fun createDirectory(dirPath:String)
|
||||||
suspend fun cacheImage(picture: Picture)
|
suspend fun cacheImage(image: Any,path: String) // in Android = ImageBitmap, Desktop = BufferedImage
|
||||||
fun loadImage(url:String): Picture?
|
suspend fun loadImage(url:String): ImageBitmap?
|
||||||
suspend fun clearCache()
|
suspend fun clearCache()
|
||||||
suspend fun saveFileWithMetadata(mp3ByteArray: ByteArray, path: String, trackDetails: TrackDetails)
|
suspend fun saveFileWithMetadata(mp3ByteArray: ByteArray, path: String, trackDetails: TrackDetails)
|
||||||
}
|
}
|
||||||
@ -44,8 +45,6 @@ suspend fun downloadFile(url: String): Flow<DownloadResult> {
|
|||||||
client.close()
|
client.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Dir.cacheImagePostfix():String = "info"
|
|
||||||
fun getNameURL(url: String): String {
|
fun getNameURL(url: String): String {
|
||||||
return url.substring(url.lastIndexOf('/') + 1, url.length)
|
return url.substring(url.lastIndexOf('/') + 1, url.length)
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,6 @@ package com.shabinder.common.di
|
|||||||
|
|
||||||
import com.shabinder.common.models.TrackDetails
|
import com.shabinder.common.models.TrackDetails
|
||||||
|
|
||||||
expect class Picture
|
|
||||||
|
|
||||||
expect fun openPlatform(platformID:String ,platformLink:String)
|
expect fun openPlatform(platformID:String ,platformLink:String)
|
||||||
|
|
||||||
expect fun shareApp()
|
expect fun shareApp()
|
||||||
|
@ -1,16 +1,18 @@
|
|||||||
package com.shabinder.common.di
|
package com.shabinder.common.di
|
||||||
|
|
||||||
|
import androidx.compose.ui.graphics.ImageBitmap
|
||||||
|
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.models.TrackDetails
|
||||||
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 org.jetbrains.skija.Image
|
||||||
import java.awt.image.BufferedImage
|
import java.awt.image.BufferedImage
|
||||||
import java.io.*
|
import java.io.*
|
||||||
import java.net.HttpURLConnection
|
import java.net.HttpURLConnection
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.nio.charset.StandardCharsets
|
|
||||||
import javax.imageio.ImageIO
|
import javax.imageio.ImageIO
|
||||||
|
|
||||||
actual class Dir actual constructor(private val logger: Kermit) {
|
actual class Dir actual constructor(private val logger: Kermit) {
|
||||||
@ -46,25 +48,11 @@ actual class Dir actual constructor(private val logger: Kermit) {
|
|||||||
File(imageCacheDir()).deleteRecursively()
|
File(imageCacheDir()).deleteRecursively()
|
||||||
}
|
}
|
||||||
|
|
||||||
actual suspend fun cacheImage(picture: Picture) {
|
actual suspend fun cacheImage(image: Any,path:String) {
|
||||||
try {
|
try {
|
||||||
val path = imageCacheDir() + picture.name
|
(image as? BufferedImage)?.let {
|
||||||
|
ImageIO.write(it,"jpeg", File(path))
|
||||||
ImageIO.write(picture.image, "jpeg", File(path))
|
}
|
||||||
|
|
||||||
val bw =
|
|
||||||
BufferedWriter(
|
|
||||||
OutputStreamWriter(
|
|
||||||
FileOutputStream(path + cacheImagePostfix()),
|
|
||||||
StandardCharsets.UTF_8
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
bw.write(picture.source)
|
|
||||||
bw.write("\r\n${picture.width}")
|
|
||||||
bw.write("\r\n${picture.height}")
|
|
||||||
bw.close()
|
|
||||||
|
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
@ -85,45 +73,23 @@ actual class Dir actual constructor(private val logger: Kermit) {
|
|||||||
.setId3v2TagsAndSaveFile(trackDetails,path)
|
.setId3v2TagsAndSaveFile(trackDetails,path)
|
||||||
}
|
}
|
||||||
|
|
||||||
actual fun loadImage(url: String): Picture? {
|
actual suspend fun loadImage(url: String): ImageBitmap? {
|
||||||
val cachePath = imageCacheDir() + getNameURL(url)
|
val cachePath = imageCacheDir() + getNameURL(url)
|
||||||
var picture: Picture? = loadCachedImage(cachePath)
|
var picture: ImageBitmap? = loadCachedImage(cachePath)
|
||||||
if (picture == null) picture = freshImage(url,cachePath)
|
if (picture == null) picture = freshImage(url)
|
||||||
return picture
|
return picture
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadCachedImage(cachePath: String): Picture? {
|
private fun loadCachedImage(cachePath: String): ImageBitmap? {
|
||||||
return try {
|
return try {
|
||||||
val read = BufferedReader(
|
ImageIO.read(File(cachePath))?.toImageBitmap()
|
||||||
InputStreamReader(
|
|
||||||
FileInputStream(cachePath + cacheImagePostfix()),
|
|
||||||
StandardCharsets.UTF_8
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
val source = read.readLine()
|
|
||||||
val width = read.readLine().toInt()
|
|
||||||
val height = read.readLine().toInt()
|
|
||||||
|
|
||||||
read.close()
|
|
||||||
|
|
||||||
val result: BufferedImage? = ImageIO.read(File(cachePath))
|
|
||||||
|
|
||||||
if (result != null) {
|
|
||||||
com.shabinder.common.di.Picture(
|
|
||||||
source,
|
|
||||||
getNameURL(source),
|
|
||||||
result,
|
|
||||||
width,
|
|
||||||
height
|
|
||||||
)
|
|
||||||
}else null
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
//e.printStackTrace()
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private fun freshImage(url:String,cachePath: String): Picture?{
|
|
||||||
|
private suspend fun freshImage(url:String): ImageBitmap?{
|
||||||
return try {
|
return try {
|
||||||
val source = URL(url)
|
val source = URL(url)
|
||||||
val connection: HttpURLConnection = source.openConnection() as HttpURLConnection
|
val connection: HttpURLConnection = source.openConnection() as HttpURLConnection
|
||||||
@ -134,17 +100,10 @@ actual class Dir actual constructor(private val logger: Kermit) {
|
|||||||
val result: BufferedImage? = ImageIO.read(input)
|
val result: BufferedImage? = ImageIO.read(input)
|
||||||
|
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
val picture = com.shabinder.common.di.Picture(
|
|
||||||
url,
|
|
||||||
getNameURL(url),
|
|
||||||
result,
|
|
||||||
result.width,
|
|
||||||
result.height
|
|
||||||
)
|
|
||||||
GlobalScope.launch(Dispatchers.IO) { //TODO Refactor
|
GlobalScope.launch(Dispatchers.IO) { //TODO Refactor
|
||||||
cacheImage(picture)
|
cacheImage(result,imageCacheDir() + getNameURL(url))
|
||||||
}
|
}
|
||||||
picture
|
result.toImageBitmap()
|
||||||
} else null
|
} else null
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
@ -152,3 +111,12 @@ actual class Dir actual constructor(private val logger: Kermit) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fun BufferedImage.toImageBitmap() = Image.makeFromEncoded(
|
||||||
|
toByteArray(this)
|
||||||
|
).asImageBitmap()
|
||||||
|
|
||||||
|
private fun toByteArray(bitmap: BufferedImage) : ByteArray {
|
||||||
|
val baOs = ByteArrayOutputStream()
|
||||||
|
ImageIO.write(bitmap, "png", baOs)
|
||||||
|
return baOs.toByteArray()
|
||||||
|
}
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
package com.shabinder.common.di
|
|
||||||
|
|
||||||
import java.awt.image.BufferedImage
|
|
||||||
|
|
||||||
actual data class Picture(
|
|
||||||
var source: String = "",
|
|
||||||
var name: String = "",
|
|
||||||
var image: BufferedImage,
|
|
||||||
var width: Int = 0,
|
|
||||||
var height: Int = 0,
|
|
||||||
var id: Int = 0
|
|
||||||
)
|
|
Loading…
Reference in New Issue
Block a user