mirror of
https://github.com/Shabinder/SpotiFlyer.git
synced 2024-11-22 09:04:32 +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.shabinder.common.di.Dir
|
||||
import com.shabinder.common.di.FetchPlatformQueryResult
|
||||
import com.shabinder.common.di.createDirectories
|
||||
import com.shabinder.common.root.SpotiFlyerRoot
|
||||
import com.shabinder.common.root.SpotiFlyerRootContent
|
||||
import com.shabinder.common.ui.SpotiFlyerTheme
|
||||
@ -28,6 +29,7 @@ class MainActivity : AppCompatActivity() {
|
||||
SpotiFlyerRootContent(rootComponent(::spotiFlyerRoot))
|
||||
}
|
||||
}
|
||||
dir.createDirectories()
|
||||
}
|
||||
|
||||
|
||||
|
@ -13,6 +13,7 @@ kotlin {
|
||||
implementation(compose.materialIconsExtended)
|
||||
//implementation("org.jetbrains.compose.material:material-icons-extended:0.3.0-build150")
|
||||
implementation(project(":common:dependency-injection"))
|
||||
//implementation("com.alialbaali.kamel:kamel-image:0.0.7")
|
||||
implementation(project(":common:data-models"))
|
||||
implementation(project(":common:database"))
|
||||
implementation(SqlDelight.coroutineExtensions)
|
||||
|
@ -1,48 +1,9 @@
|
||||
package com.shabinder.common.ui
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.runtime.Composable
|
||||
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
|
||||
|
||||
@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
|
||||
actual fun Toast(
|
||||
text: String,
|
||||
|
@ -34,6 +34,9 @@ actual fun DownloadImageArrow(modifier: Modifier){
|
||||
@Composable
|
||||
actual fun DownloadAllImage() = vectorResource(R.drawable.ic_download_arrow)
|
||||
|
||||
@Composable
|
||||
actual fun PlaceHolderImage() = vectorResource(R.drawable.music)
|
||||
|
||||
@Composable
|
||||
actual fun SpotiFlyerLogo() = vectorResource(R.drawable.ic_spotiflyer_logo)
|
||||
|
||||
@ -51,5 +54,6 @@ actual fun YoutubeLogo() = vectorResource(R.drawable.ic_youtube)
|
||||
|
||||
@Composable
|
||||
actual fun YoutubeMusicLogo() = vectorResource(R.drawable.ic_youtube_music_logo)
|
||||
|
||||
@Composable
|
||||
actual fun GithubLogo() = vectorResource(R.drawable.ic_github)
|
@ -1,10 +1,10 @@
|
||||
package com.shabinder.common.list
|
||||
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
import com.arkivanov.decompose.ComponentContext
|
||||
import com.arkivanov.mvikotlin.core.store.StoreFactory
|
||||
import com.shabinder.common.di.Dir
|
||||
import com.shabinder.common.di.FetchPlatformQueryResult
|
||||
import com.shabinder.common.di.Picture
|
||||
import com.shabinder.common.list.integration.SpotiFlyerListImpl
|
||||
import com.shabinder.common.models.spotify.Source
|
||||
import com.shabinder.common.utils.Consumer
|
||||
@ -33,14 +33,14 @@ interface SpotiFlyerList {
|
||||
/*
|
||||
* Load Image from cache/Internet and cache it
|
||||
* */
|
||||
fun loadImage(url:String): Picture?
|
||||
suspend fun loadImage(url:String): ImageBitmap?
|
||||
|
||||
interface Dependencies {
|
||||
val storeFactory: StoreFactory
|
||||
val fetchQuery: FetchPlatformQueryResult
|
||||
val dir: Dir
|
||||
val link: String
|
||||
fun listOutput(finished: Output.Finished): Consumer<Output>
|
||||
val listOutput: Consumer<Output>
|
||||
}
|
||||
sealed class Output {
|
||||
object Finished : Output()
|
||||
|
@ -5,25 +5,23 @@ import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
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.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.shabinder.common.models.DownloadStatus
|
||||
import com.shabinder.common.di.Picture
|
||||
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.launch
|
||||
|
||||
@Composable
|
||||
fun SpotiFlyerListContent(
|
||||
@ -64,12 +62,17 @@ fun SpotiFlyerListContent(
|
||||
fun TrackCard(
|
||||
track: TrackDetails,
|
||||
downloadTrack:()->Unit,
|
||||
loadImage:(String)-> Picture?
|
||||
loadImage:suspend (String)-> ImageBitmap?
|
||||
) {
|
||||
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(
|
||||
pic = pic,
|
||||
"Album Art",
|
||||
modifier = Modifier
|
||||
.preferredWidth(75.dp)
|
||||
.preferredHeight(90.dp)
|
||||
@ -116,16 +119,20 @@ fun CoverImage(
|
||||
title: String,
|
||||
coverURL: String,
|
||||
scope: CoroutineScope,
|
||||
loadImage: (String) -> Picture?,
|
||||
loadImage: suspend (String) -> ImageBitmap?,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(
|
||||
modifier.padding(vertical = 8.dp).fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
val pic = loadImage(coverURL)
|
||||
var pic by mutableStateOf<ImageBitmap?>(null)
|
||||
scope.launch {
|
||||
pic = loadImage(coverURL)
|
||||
}
|
||||
ImageLoad(
|
||||
pic,
|
||||
"Cover Image",
|
||||
modifier = Modifier
|
||||
.preferredWidth(210.dp)
|
||||
.preferredHeight(230.dp)
|
||||
|
@ -1,8 +1,8 @@
|
||||
package com.shabinder.common.list.integration
|
||||
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
import com.arkivanov.decompose.ComponentContext
|
||||
import com.arkivanov.mvikotlin.extensions.coroutines.states
|
||||
import com.shabinder.common.di.Picture
|
||||
import com.shabinder.common.models.TrackDetails
|
||||
import com.shabinder.common.list.SpotiFlyerList
|
||||
import com.shabinder.common.list.SpotiFlyerList.Dependencies
|
||||
@ -37,8 +37,8 @@ internal class SpotiFlyerListImpl(
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
import com.arkivanov.decompose.ComponentContext
|
||||
import com.arkivanov.mvikotlin.core.store.StoreFactory
|
||||
import com.shabinder.common.di.Dir
|
||||
import com.shabinder.common.models.DownloadRecord
|
||||
import com.shabinder.common.di.Picture
|
||||
import com.shabinder.common.main.integration.SpotiFlyerMainImpl
|
||||
import com.shabinder.common.utils.Consumer
|
||||
import com.shabinder.database.Database
|
||||
@ -33,10 +33,10 @@ interface SpotiFlyerMain {
|
||||
/*
|
||||
* Load Image from cache/Internet and cache it
|
||||
* */
|
||||
fun loadImage(url:String): Picture?
|
||||
suspend fun loadImage(url:String): ImageBitmap?
|
||||
|
||||
interface Dependencies {
|
||||
fun mainOutput(searched: Output): Consumer<Output>
|
||||
val mainOutput: Consumer<Output>
|
||||
val storeFactory: StoreFactory
|
||||
val database: Database
|
||||
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.Info
|
||||
import androidx.compose.material.icons.rounded.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
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.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.shabinder.common.models.DownloadRecord
|
||||
import com.shabinder.common.di.Picture
|
||||
import com.shabinder.common.main.SpotiFlyerMain.HomeCategory
|
||||
import com.shabinder.common.di.openPlatform
|
||||
import com.shabinder.common.ui.*
|
||||
import com.shabinder.common.ui.SpotiFlyerTypography
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
fun SpotiFlyerMainContent(component: SpotiFlyerMain){
|
||||
@ -120,18 +121,18 @@ fun SearchPanel(
|
||||
value = link,
|
||||
onValueChange = updateLink ,
|
||||
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,
|
||||
//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),
|
||||
modifier = modifier.padding(12.dp).fillMaxWidth()
|
||||
.border(
|
||||
BorderStroke(2.dp, Brush.horizontalGradient(listOf(colorPrimary, colorAccent))),
|
||||
RoundedCornerShape(30.dp)
|
||||
),
|
||||
backgroundColor = Color(0xFF000000),
|
||||
backgroundColor = Color.Black,
|
||||
shape = RoundedCornerShape(size = 30.dp),
|
||||
activeColor = transparent,
|
||||
inactiveColor = transparent,
|
||||
@ -158,7 +159,7 @@ fun AboutColumn(modifier: Modifier = Modifier) {
|
||||
Column(modifier.fillMaxSize().verticalScroll(rememberScrollState())) {
|
||||
Card(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
border = BorderStroke(1.dp,Color(0xFF888888))//Gray
|
||||
border = BorderStroke(1.dp,Color.Gray)
|
||||
) {
|
||||
Column(modifier.padding(12.dp)) {
|
||||
Text(
|
||||
@ -171,28 +172,28 @@ fun AboutColumn(modifier: Modifier = Modifier) {
|
||||
Icon(
|
||||
imageVector = SpotifyLogo(),
|
||||
"Open Spotify",
|
||||
tint = unspecifiedColor,
|
||||
tint = Color.Unspecified,
|
||||
modifier = Modifier.clickable(
|
||||
onClick = { openPlatform("com.spotify.music","http://open.spotify.com") })
|
||||
)
|
||||
Spacer(modifier = modifier.padding(start = 16.dp))
|
||||
Icon(imageVector = GaanaLogo(),
|
||||
"Open Gaana",
|
||||
tint = unspecifiedColor,
|
||||
tint = Color.Unspecified,
|
||||
modifier = Modifier.clickable(
|
||||
onClick = { openPlatform("com.gaana","http://gaana.com") })
|
||||
)
|
||||
Spacer(modifier = modifier.padding(start = 16.dp))
|
||||
Icon(imageVector = YoutubeLogo(),
|
||||
"Open Youtube",
|
||||
tint = unspecifiedColor,
|
||||
tint = Color.Unspecified,
|
||||
modifier = Modifier.clickable(
|
||||
onClick = { openPlatform("com.google.android.youtube","http://m.youtube.com") })
|
||||
)
|
||||
Spacer(modifier = modifier.padding(start = 12.dp))
|
||||
Icon(imageVector = YoutubeMusicLogo(),
|
||||
"Open Youtube Music",
|
||||
tint = unspecifiedColor,
|
||||
tint = Color.Unspecified,
|
||||
modifier = Modifier.clickable(
|
||||
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))
|
||||
Card(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
border = BorderStroke(1.dp,Color(0xFF888888))//Gray
|
||||
border = BorderStroke(1.dp,Color.Gray)//Gray
|
||||
) {
|
||||
Column(modifier.padding(12.dp)) {
|
||||
Text(
|
||||
@ -300,7 +301,7 @@ fun AboutColumn(modifier: Modifier = Modifier) {
|
||||
@Composable
|
||||
fun HistoryColumn(
|
||||
list: List<DownloadRecord>,
|
||||
loadImage:(String)-> Picture?,
|
||||
loadImage:suspend (String)-> ImageBitmap?,
|
||||
onItemClicked: (String) -> Unit
|
||||
) {
|
||||
LazyColumn(
|
||||
@ -321,13 +322,18 @@ fun HistoryColumn(
|
||||
@Composable
|
||||
fun DownloadRecordItem(
|
||||
item: DownloadRecord,
|
||||
loadImage:(String)-> Picture?,
|
||||
loadImage:suspend (String)-> ImageBitmap?,
|
||||
onItemClicked:(String)->Unit
|
||||
) {
|
||||
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(
|
||||
pic,
|
||||
"Album Art",
|
||||
modifier = Modifier.preferredHeight(75.dp).preferredWidth(90.dp)
|
||||
)
|
||||
Column(modifier = Modifier.padding(horizontal = 8.dp).preferredHeight(60.dp).weight(1f),verticalArrangement = Arrangement.SpaceEvenly) {
|
||||
@ -343,7 +349,7 @@ fun DownloadRecordItem(
|
||||
}
|
||||
Image(
|
||||
imageVector = Icons.Rounded.Share,
|
||||
"Share App",
|
||||
"Research",
|
||||
modifier = Modifier.clickable(onClick = {
|
||||
//if(!isOnline(ctx)) showDialog("Check Your Internet Connection") else
|
||||
onItemClicked(item.link)
|
||||
|
@ -1,8 +1,8 @@
|
||||
package com.shabinder.common.main.integration
|
||||
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
import com.arkivanov.decompose.ComponentContext
|
||||
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.store.SpotiFlyerMainStore.Intent
|
||||
@ -26,7 +26,7 @@ internal class SpotiFlyerMainImpl(
|
||||
override val models: Flow<State> = store.states
|
||||
|
||||
override fun onLinkSearch(link: String) {
|
||||
mainOutput(Output.Search(link = link))
|
||||
mainOutput.callback(Output.Search(link = link))
|
||||
}
|
||||
|
||||
override fun onInputLinkChanged(link: String) {
|
||||
@ -37,5 +37,5 @@ internal class SpotiFlyerMainImpl(
|
||||
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.Child
|
||||
import com.shabinder.common.root.SpotiFlyerRoot.Dependencies
|
||||
import com.shabinder.common.ui.showPopUpMessage
|
||||
import com.shabinder.common.utils.Consumer
|
||||
|
||||
internal class SpotiFlyerRootImpl(
|
||||
@ -40,7 +41,7 @@ internal class SpotiFlyerRootImpl(
|
||||
SpotiFlyerMain(
|
||||
componentContext = componentContext,
|
||||
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
|
||||
}
|
||||
)
|
||||
@ -52,16 +53,16 @@ internal class SpotiFlyerRootImpl(
|
||||
override val fetchQuery = fetchPlatformQueryResult
|
||||
override val dir: Dir = directories
|
||||
override val link: String = link
|
||||
|
||||
override fun listOutput(finished: SpotiFlyerList.Output.Finished): Consumer<SpotiFlyerList.Output> =
|
||||
Consumer(::onListOutput)
|
||||
override val listOutput : Consumer<SpotiFlyerList.Output> = Consumer(::onListOutput)
|
||||
}
|
||||
)
|
||||
|
||||
private fun onMainOutput(output: SpotiFlyerMain.Output): Unit =
|
||||
private fun onMainOutput(output: SpotiFlyerMain.Output){
|
||||
showPopUpMessage("Button Pressed")
|
||||
when (output) {
|
||||
is SpotiFlyerMain.Output.Search -> router.push(Configuration.List(link = output.link))
|
||||
}
|
||||
}
|
||||
|
||||
private fun onListOutput(output: SpotiFlyerList.Output): Unit =
|
||||
when (output) {
|
||||
|
@ -27,7 +27,6 @@ val colorSuccessGreen = Color(0xFF59C351)
|
||||
val darkBackgroundColor = Color(0xFF000000)
|
||||
val colorOffWhite = Color(0xFFE7E7E7)
|
||||
val transparent = Color(0x00000000)
|
||||
val unspecifiedColor =Color(0f, 0f, 0f, 0f)
|
||||
val black = Color(0xFF000000)
|
||||
val lightGray = Color(0xFFCCCCCC)
|
||||
|
||||
|
@ -1,13 +1,3 @@
|
||||
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)
|
@ -1,15 +1,25 @@
|
||||
package com.shabinder.common.ui
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
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
|
||||
expect fun DownloadImageTick()
|
||||
|
||||
@Composable
|
||||
expect fun DownloadAllImage():ImageVector
|
||||
|
||||
@Composable
|
||||
expect fun PlaceHolderImage():ImageVector
|
||||
|
||||
@Composable
|
||||
expect fun SpotiFlyerLogo():ImageVector
|
||||
|
||||
|
@ -20,12 +20,15 @@ import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.Icon
|
||||
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.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.shabinder.common.ui.*
|
||||
@ -43,7 +46,7 @@ fun Splash(modifier: Modifier = Modifier, onTimeout: () -> Unit) {
|
||||
delay(SplashWaitTime)
|
||||
currentOnTimeout()
|
||||
}
|
||||
Image(imageVector = SpotiFlyerLogo(),"SpotiFlyer Logo")
|
||||
Image(imageVector = Icons.Default.BrokenImage/*SpotiFlyerLogo()*/,"SpotiFlyer Logo")
|
||||
MadeInIndia(Modifier.align(Alignment.BottomCenter))
|
||||
}
|
||||
}
|
||||
@ -66,7 +69,7 @@ fun MadeInIndia(
|
||||
fontSize = 22.sp
|
||||
)
|
||||
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))
|
||||
Text(
|
||||
text = " in India",
|
||||
|
@ -4,13 +4,13 @@ package com.shabinder.common.utils
|
||||
* Callback Utility
|
||||
* */
|
||||
interface Consumer<in T> {
|
||||
fun onCall(value: T)
|
||||
fun callback(value: T)
|
||||
}
|
||||
|
||||
@Suppress("FunctionName") // Factory function
|
||||
inline fun <T> Consumer(crossinline block: (T) -> Unit): Consumer<T> =
|
||||
object : Consumer<T> {
|
||||
override fun onCall(value: T) {
|
||||
override fun callback(value: T) {
|
||||
block(value)
|
||||
}
|
||||
}
|
||||
|
@ -9,31 +9,3 @@ import com.shabinder.common.di.Picture
|
||||
import java.awt.image.BufferedImage
|
||||
import java.io.ByteArrayOutputStream
|
||||
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
|
||||
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
|
||||
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 seokey : 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.Serializable
|
||||
|
||||
@Serializable
|
||||
data class CustomArtworks (
|
||||
@SerialName("40x40") val size_40p : String,
|
||||
@SerialName("80x80") val size_80p : String,
|
||||
|
@ -16,6 +16,9 @@
|
||||
|
||||
package com.shabinder.common.models.gaana
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class GaanaAlbum (
|
||||
val tracks : List<GaanaTrack>,
|
||||
val count : Int,
|
||||
|
@ -16,6 +16,9 @@
|
||||
|
||||
package com.shabinder.common.models.gaana
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class GaanaArtistDetails(
|
||||
val artist : List<Artist>,
|
||||
val count : Int,
|
||||
|
@ -16,6 +16,9 @@
|
||||
|
||||
package com.shabinder.common.models.gaana
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class GaanaArtistTracks(
|
||||
val count : Int,
|
||||
val tracks : List<GaanaTrack>
|
||||
|
@ -16,6 +16,9 @@
|
||||
|
||||
package com.shabinder.common.models.gaana
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class GaanaPlaylist (
|
||||
val modified_on : String,
|
||||
val count : Int,
|
||||
|
@ -16,6 +16,9 @@
|
||||
|
||||
package com.shabinder.common.models.gaana
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class GaanaSong(
|
||||
val tracks : List<GaanaTrack>
|
||||
)
|
@ -22,21 +22,21 @@ import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class GaanaTrack (
|
||||
val tags : List<Tags?>?,
|
||||
val tags : List<Tags?>? = null,
|
||||
val seokey : String,
|
||||
val albumseokey : String?,
|
||||
val albumseokey : String? = null,
|
||||
val track_title : String,
|
||||
val album_title : String?,
|
||||
val language : String?,
|
||||
val album_title : String? = null,
|
||||
val language : String? = null,
|
||||
val duration: Int,
|
||||
@SerialName("artwork_large") val artworkLink : String,
|
||||
val artist : List<Artist?>,
|
||||
@SerialName("gener") val genre : List<Genre?>?,
|
||||
val lyrics_url : String?,
|
||||
val youtube_id : String?,
|
||||
val total_favourite_count : Int?,
|
||||
val release_date : String?,
|
||||
val play_ct : String?,
|
||||
val secondary_language : String?,
|
||||
val artist : List<Artist?> = emptyList(),
|
||||
@SerialName("gener") val genre : List<Genre?>? = null,
|
||||
val lyrics_url : String? = null,
|
||||
val youtube_id : String? = null,
|
||||
val total_favourite_count : Int? = null,
|
||||
val release_date : String? = null,
|
||||
val play_ct : String? = null,
|
||||
val secondary_language : String? = null,
|
||||
var downloaded: DownloadStatus? = DownloadStatus.NotDownloaded
|
||||
)
|
@ -4,6 +4,8 @@ import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.os.Environment
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
import androidx.compose.ui.graphics.asImageBitmap
|
||||
import co.touchlab.kermit.Kermit
|
||||
import com.mpatric.mp3agic.Mp3File
|
||||
import com.shabinder.common.models.TrackDetails
|
||||
@ -57,25 +59,11 @@ actual class Dir actual constructor(
|
||||
File(imageCacheDir()).deleteRecursively()
|
||||
}
|
||||
|
||||
actual suspend fun cacheImage(picture: Picture) {
|
||||
actual suspend fun cacheImage(image: Any,path:String) {
|
||||
try {
|
||||
val path = imageCacheDir() + picture.name
|
||||
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) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
@ -96,45 +84,20 @@ actual class Dir actual constructor(
|
||||
.setId3v2TagsAndSaveFile(trackDetails,path)
|
||||
}
|
||||
|
||||
actual fun loadImage(url: String): Picture? {
|
||||
actual suspend fun loadImage(url: String): ImageBitmap? {
|
||||
val cachePath = imageCacheDir() + getNameURL(url)
|
||||
var picture: Picture? = loadCachedImage(cachePath)
|
||||
if (picture == null) picture = freshImage(url)
|
||||
return picture
|
||||
return (loadCachedImage(cachePath) ?: freshImage(url))?.asImageBitmap()
|
||||
}
|
||||
|
||||
private fun loadCachedImage(cachePath: String): Picture? {
|
||||
private fun loadCachedImage(cachePath: String): Bitmap? {
|
||||
return try {
|
||||
val read = BufferedReader(
|
||||
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
|
||||
BitmapFactory.decodeFile(cachePath)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
null
|
||||
}
|
||||
}
|
||||
private fun freshImage(url:String): Picture?{
|
||||
private suspend fun freshImage(url:String): Bitmap?{
|
||||
return try {
|
||||
val source = URL(url)
|
||||
val connection: HttpURLConnection = source.openConnection() as HttpURLConnection
|
||||
@ -145,17 +108,10 @@ actual class Dir actual constructor(
|
||||
val result: Bitmap? = BitmapFactory.decodeStream(input)
|
||||
|
||||
if (result != null) {
|
||||
val picture = com.shabinder.common.di.Picture(
|
||||
url,
|
||||
getNameURL(url),
|
||||
result,
|
||||
result.width,
|
||||
result.height
|
||||
)
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
cacheImage(picture)
|
||||
cacheImage(result,imageCacheDir() + getNameURL(url))
|
||||
}
|
||||
picture
|
||||
result
|
||||
} else null
|
||||
} catch (e: Exception) {
|
||||
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
|
||||
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
import co.touchlab.kermit.Kermit
|
||||
import com.shabinder.common.models.DownloadResult
|
||||
import com.shabinder.common.models.TrackDetails
|
||||
@ -18,8 +19,8 @@ expect class Dir(
|
||||
fun defaultDir(): String
|
||||
fun imageCacheDir(): String
|
||||
fun createDirectory(dirPath:String)
|
||||
suspend fun cacheImage(picture: Picture)
|
||||
fun loadImage(url:String): Picture?
|
||||
suspend fun cacheImage(image: Any,path: String) // in Android = ImageBitmap, Desktop = BufferedImage
|
||||
suspend fun loadImage(url:String): ImageBitmap?
|
||||
suspend fun clearCache()
|
||||
suspend fun saveFileWithMetadata(mp3ByteArray: ByteArray, path: String, trackDetails: TrackDetails)
|
||||
}
|
||||
@ -44,8 +45,6 @@ suspend fun downloadFile(url: String): Flow<DownloadResult> {
|
||||
client.close()
|
||||
}
|
||||
}
|
||||
|
||||
fun Dir.cacheImagePostfix():String = "info"
|
||||
fun getNameURL(url: String): String {
|
||||
return url.substring(url.lastIndexOf('/') + 1, url.length)
|
||||
}
|
||||
|
@ -2,8 +2,6 @@ package com.shabinder.common.di
|
||||
|
||||
import com.shabinder.common.models.TrackDetails
|
||||
|
||||
expect class Picture
|
||||
|
||||
expect fun openPlatform(platformID:String ,platformLink:String)
|
||||
|
||||
expect fun shareApp()
|
||||
|
@ -1,16 +1,18 @@
|
||||
package com.shabinder.common.di
|
||||
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
import androidx.compose.ui.graphics.asImageBitmap
|
||||
import co.touchlab.kermit.Kermit
|
||||
import com.mpatric.mp3agic.Mp3File
|
||||
import com.shabinder.common.models.TrackDetails
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jetbrains.skija.Image
|
||||
import java.awt.image.BufferedImage
|
||||
import java.io.*
|
||||
import java.net.HttpURLConnection
|
||||
import java.net.URL
|
||||
import java.nio.charset.StandardCharsets
|
||||
import javax.imageio.ImageIO
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
actual suspend fun cacheImage(picture: Picture) {
|
||||
actual suspend fun cacheImage(image: Any,path:String) {
|
||||
try {
|
||||
val path = imageCacheDir() + picture.name
|
||||
|
||||
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()
|
||||
|
||||
(image as? BufferedImage)?.let {
|
||||
ImageIO.write(it,"jpeg", File(path))
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
@ -85,45 +73,23 @@ actual class Dir actual constructor(private val logger: Kermit) {
|
||||
.setId3v2TagsAndSaveFile(trackDetails,path)
|
||||
}
|
||||
|
||||
actual fun loadImage(url: String): Picture? {
|
||||
actual suspend fun loadImage(url: String): ImageBitmap? {
|
||||
val cachePath = imageCacheDir() + getNameURL(url)
|
||||
var picture: Picture? = loadCachedImage(cachePath)
|
||||
if (picture == null) picture = freshImage(url,cachePath)
|
||||
var picture: ImageBitmap? = loadCachedImage(cachePath)
|
||||
if (picture == null) picture = freshImage(url)
|
||||
return picture
|
||||
}
|
||||
|
||||
private fun loadCachedImage(cachePath: String): Picture? {
|
||||
private fun loadCachedImage(cachePath: String): ImageBitmap? {
|
||||
return try {
|
||||
val read = BufferedReader(
|
||||
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
|
||||
ImageIO.read(File(cachePath))?.toImageBitmap()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
//e.printStackTrace()
|
||||
null
|
||||
}
|
||||
}
|
||||
private fun freshImage(url:String,cachePath: String): Picture?{
|
||||
|
||||
private suspend fun freshImage(url:String): ImageBitmap?{
|
||||
return try {
|
||||
val source = URL(url)
|
||||
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)
|
||||
|
||||
if (result != null) {
|
||||
val picture = com.shabinder.common.di.Picture(
|
||||
url,
|
||||
getNameURL(url),
|
||||
result,
|
||||
result.width,
|
||||
result.height
|
||||
)
|
||||
GlobalScope.launch(Dispatchers.IO) { //TODO Refactor
|
||||
cacheImage(picture)
|
||||
cacheImage(result,imageCacheDir() + getNameURL(url))
|
||||
}
|
||||
picture
|
||||
result.toImageBitmap()
|
||||
} else null
|
||||
} catch (e: Exception) {
|
||||
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