Fixes & Refactors

This commit is contained in:
shabinder 2021-02-10 01:12:01 +05:30
parent 85a8dfec68
commit f9120a1fb4
32 changed files with 157 additions and 282 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -16,6 +16,9 @@
package com.shabinder.common.models.gaana
import kotlinx.serialization.Serializable
@Serializable
data class GaanaSong(
val tracks : List<GaanaTrack>
)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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