mirror of
https://github.com/Shabinder/SpotiFlyer.git
synced 2024-11-22 17:14:32 +01:00
Ui Fixes and ImageLoading fun improvised.
This commit is contained in:
parent
a186a1a1e7
commit
7602fa3f23
@ -8,6 +8,7 @@ import android.os.Bundle
|
|||||||
import android.os.PowerManager
|
import android.os.PowerManager
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
|
import androidx.compose.material.Surface
|
||||||
import com.arkivanov.decompose.ComponentContext
|
import com.arkivanov.decompose.ComponentContext
|
||||||
import com.arkivanov.decompose.extensions.compose.jetbrains.rootComponent
|
import com.arkivanov.decompose.extensions.compose.jetbrains.rootComponent
|
||||||
import com.arkivanov.mvikotlin.logging.store.LoggingStoreFactory
|
import com.arkivanov.mvikotlin.logging.store.LoggingStoreFactory
|
||||||
@ -22,6 +23,7 @@ import com.shabinder.common.root.SpotiFlyerRoot
|
|||||||
import com.shabinder.common.root.SpotiFlyerRootContent
|
import com.shabinder.common.root.SpotiFlyerRootContent
|
||||||
import com.shabinder.common.root.callbacks.SpotiFlyerRootCallBacks
|
import com.shabinder.common.root.callbacks.SpotiFlyerRootCallBacks
|
||||||
import com.shabinder.common.ui.SpotiFlyerTheme
|
import com.shabinder.common.ui.SpotiFlyerTheme
|
||||||
|
import com.shabinder.common.ui.colorOffWhite
|
||||||
import com.shabinder.database.Database
|
import com.shabinder.database.Database
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
@ -41,7 +43,9 @@ class MainActivity : ComponentActivity() {
|
|||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContent {
|
setContent {
|
||||||
SpotiFlyerTheme {
|
SpotiFlyerTheme {
|
||||||
|
Surface(contentColor = colorOffWhite) {
|
||||||
root = SpotiFlyerRootContent(rootComponent(::spotiFlyerRoot))
|
root = SpotiFlyerRootContent(rootComponent(::spotiFlyerRoot))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
initialise()
|
initialise()
|
||||||
|
@ -24,6 +24,7 @@ import kotlinx.coroutines.CoroutineScope
|
|||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.channelFlow
|
import kotlinx.coroutines.flow.channelFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SpotiFlyerListContent(
|
fun SpotiFlyerListContent(
|
||||||
@ -67,13 +68,8 @@ fun TrackCard(
|
|||||||
loadImage:suspend (String)-> ImageBitmap?
|
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)) {
|
||||||
var pic by mutableStateOf<ImageBitmap?>(null)
|
|
||||||
val scope = rememberCoroutineScope()
|
|
||||||
LaunchedEffect((1..10).random()){
|
|
||||||
pic = loadImage(track.albumArtURL)
|
|
||||||
}
|
|
||||||
ImageLoad(
|
ImageLoad(
|
||||||
pic = pic,
|
{loadImage(track.albumArtURL)},
|
||||||
"Album Art",
|
"Album Art",
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.width(75.dp)
|
.width(75.dp)
|
||||||
@ -128,14 +124,8 @@ fun CoverImage(
|
|||||||
modifier.padding(vertical = 8.dp).fillMaxWidth(),
|
modifier.padding(vertical = 8.dp).fillMaxWidth(),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
var pic by mutableStateOf<ImageBitmap?>(null)
|
|
||||||
LaunchedEffect(true){
|
|
||||||
scope.launch(dispatcherIO) {
|
|
||||||
pic = loadImage(coverURL)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ImageLoad(
|
ImageLoad(
|
||||||
pic,
|
{ loadImage(coverURL) },
|
||||||
"Cover Image",
|
"Cover Image",
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.width(210.dp)
|
.width(210.dp)
|
||||||
|
@ -30,8 +30,6 @@ 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){
|
||||||
@ -326,13 +324,15 @@ fun DownloadRecordItem(
|
|||||||
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 scope = rememberCoroutineScope()
|
/*KamelImage(
|
||||||
var pic by mutableStateOf<ImageBitmap?>(null)
|
lazyImageResource(item.coverUrl),
|
||||||
scope.launch(dispatcherIO) {
|
"Album Art",
|
||||||
pic = loadImage(item.coverUrl)
|
modifier = Modifier.height(75.dp).width(90.dp),
|
||||||
}
|
crossfade = true,
|
||||||
|
onLoading = { PlaceHolderImage() }
|
||||||
|
)*/
|
||||||
ImageLoad(
|
ImageLoad(
|
||||||
pic,
|
{ loadImage(item.coverUrl) },
|
||||||
"Album Art",
|
"Album Art",
|
||||||
modifier = Modifier.height(75.dp).width(90.dp)
|
modifier = Modifier.height(75.dp).width(90.dp)
|
||||||
)
|
)
|
||||||
|
@ -1,15 +1,25 @@
|
|||||||
@file:Suppress("FunctionName")
|
@file:Suppress("FunctionName")
|
||||||
package com.shabinder.common.ui
|
package com.shabinder.common.ui
|
||||||
|
|
||||||
|
import androidx.compose.animation.Crossfade
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.ImageBitmap
|
import androidx.compose.ui.graphics.ImageBitmap
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ImageLoad(pic: ImageBitmap?, desc: String, modifier:Modifier = Modifier, placeholder:ImageVector = PlaceHolderImage()) {
|
fun ImageLoad(loader: suspend () -> ImageBitmap?, desc: String = "Album Art", modifier:Modifier = Modifier, placeholder:ImageVector = PlaceHolderImage()) {
|
||||||
if(pic == null) Image(placeholder, desc, modifier) else Image(pic, desc, modifier)
|
var pic by remember { mutableStateOf<ImageBitmap?>(null) }
|
||||||
|
Crossfade(pic){
|
||||||
|
if(pic == null) Image(placeholder, desc, modifier) else Image(pic!!, desc, modifier)
|
||||||
|
}
|
||||||
|
LaunchedEffect(loader){
|
||||||
|
withContext(dispatcherIO) {
|
||||||
|
pic = loader()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
@ -21,5 +21,5 @@ import kotlinx.serialization.Serializable
|
|||||||
@Serializable
|
@Serializable
|
||||||
data class GaanaArtistTracks(
|
data class GaanaArtistTracks(
|
||||||
val count : Int,
|
val count : Int,
|
||||||
val tracks : List<GaanaTrack>
|
val tracks : List<GaanaTrack>? = null
|
||||||
)
|
)
|
@ -16,7 +16,7 @@ class TokenStore(
|
|||||||
private val db: TokenDBQueries
|
private val db: TokenDBQueries
|
||||||
get() = tokenDB.tokenDBQueries
|
get() = tokenDB.tokenDBQueries
|
||||||
|
|
||||||
private suspend fun save(token: TokenData){
|
private fun save(token: TokenData){
|
||||||
if(!token.access_token.isNullOrBlank() && token.expiry != null)
|
if(!token.access_token.isNullOrBlank() && token.expiry != null)
|
||||||
db.add(token.access_token!!, token.expiry!! + Clock.System.now().epochSeconds)
|
db.add(token.access_token!!, token.expiry!! + Clock.System.now().epochSeconds)
|
||||||
}
|
}
|
||||||
@ -25,6 +25,7 @@ class TokenStore(
|
|||||||
var token: TokenData? = db.select().executeAsOneOrNull()?.let {
|
var token: TokenData? = db.select().executeAsOneOrNull()?.let {
|
||||||
TokenData(it.accessToken,null,it.expiry)
|
TokenData(it.accessToken,null,it.expiry)
|
||||||
}
|
}
|
||||||
|
logger.d{"System Time:${Clock.System.now().epochSeconds} , Token Expiry:${token?.expiry}"}
|
||||||
if(Clock.System.now().epochSeconds > token?.expiry ?:0 || token == null){
|
if(Clock.System.now().epochSeconds > token?.expiry ?:0 || token == null){
|
||||||
logger.d{"Requesting New Token"}
|
logger.d{"Requesting New Token"}
|
||||||
token = authenticateSpotify()
|
token = authenticateSpotify()
|
||||||
|
@ -85,7 +85,7 @@ class GaanaProvider(
|
|||||||
dir.defaultDir()
|
dir.defaultDir()
|
||||||
)
|
)
|
||||||
)) {//Download Already Present!!
|
)) {//Download Already Present!!
|
||||||
it.downloaded = com.shabinder.common.models.DownloadStatus.Downloaded
|
it.downloaded = DownloadStatus.Downloaded
|
||||||
}
|
}
|
||||||
trackList = listOf(it).toTrackDetailsList(folderType, subFolder)
|
trackList = listOf(it).toTrackDetailsList(folderType, subFolder)
|
||||||
title = it.track_title
|
title = it.track_title
|
||||||
@ -115,7 +115,7 @@ class GaanaProvider(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
) {//Download Already Present!!
|
) {//Download Already Present!!
|
||||||
track.downloaded = com.shabinder.common.models.DownloadStatus.Downloaded
|
track.downloaded = DownloadStatus.Downloaded
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
trackList = it.tracks.toTrackDetailsList(folderType, subFolder)
|
trackList = it.tracks.toTrackDetailsList(folderType, subFolder)
|
||||||
@ -146,7 +146,7 @@ class GaanaProvider(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
) {//Download Already Present!!
|
) {//Download Already Present!!
|
||||||
track.downloaded = com.shabinder.common.models.DownloadStatus.Downloaded
|
track.downloaded = DownloadStatus.Downloaded
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
trackList = it.tracks.toTrackDetailsList(folderType, subFolder)
|
trackList = it.tracks.toTrackDetailsList(folderType, subFolder)
|
||||||
@ -175,7 +175,7 @@ class GaanaProvider(
|
|||||||
coverUrl = it.artworkLink ?: gaanaPlaceholderImageUrl
|
coverUrl = it.artworkLink ?: gaanaPlaceholderImageUrl
|
||||||
}
|
}
|
||||||
getGaanaArtistTracks(seokey = link).also {
|
getGaanaArtistTracks(seokey = link).also {
|
||||||
it.tracks.forEach { track ->
|
it.tracks?.forEach { track ->
|
||||||
if (dir.isPresent(
|
if (dir.isPresent(
|
||||||
dir.finalOutputDir(
|
dir.finalOutputDir(
|
||||||
track.track_title,
|
track.track_title,
|
||||||
@ -185,10 +185,10 @@ class GaanaProvider(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
) {//Download Already Present!!
|
) {//Download Already Present!!
|
||||||
track.downloaded = com.shabinder.common.models.DownloadStatus.Downloaded
|
track.downloaded = DownloadStatus.Downloaded
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
trackList = it.tracks.toTrackDetailsList(folderType, subFolder)
|
trackList = it.tracks?.toTrackDetailsList(folderType, subFolder) ?: emptyList()
|
||||||
withContext(Dispatchers.Default) {
|
withContext(Dispatchers.Default) {
|
||||||
db.add(
|
db.add(
|
||||||
type = "Artist",
|
type = "Artist",
|
||||||
|
@ -19,8 +19,11 @@ package com.shabinder.common.di.providers
|
|||||||
import co.touchlab.kermit.Kermit
|
import co.touchlab.kermit.Kermit
|
||||||
import com.shabinder.common.database.DownloadRecordDatabaseQueries
|
import com.shabinder.common.database.DownloadRecordDatabaseQueries
|
||||||
import com.shabinder.common.di.Dir
|
import com.shabinder.common.di.Dir
|
||||||
|
import com.shabinder.common.di.TokenStore
|
||||||
import com.shabinder.common.di.finalOutputDir
|
import com.shabinder.common.di.finalOutputDir
|
||||||
|
import com.shabinder.common.di.kotlinxSerializer
|
||||||
import com.shabinder.common.di.spotify.SpotifyRequests
|
import com.shabinder.common.di.spotify.SpotifyRequests
|
||||||
|
import com.shabinder.common.di.spotify.authenticateSpotify
|
||||||
import com.shabinder.common.models.PlatformQueryResult
|
import com.shabinder.common.models.PlatformQueryResult
|
||||||
import com.shabinder.common.models.TrackDetails
|
import com.shabinder.common.models.TrackDetails
|
||||||
import com.shabinder.common.models.spotify.Album
|
import com.shabinder.common.models.spotify.Album
|
||||||
@ -29,16 +32,40 @@ import com.shabinder.common.models.spotify.Source
|
|||||||
import com.shabinder.common.models.spotify.Track
|
import com.shabinder.common.models.spotify.Track
|
||||||
import com.shabinder.database.Database
|
import com.shabinder.database.Database
|
||||||
import io.ktor.client.*
|
import io.ktor.client.*
|
||||||
|
import io.ktor.client.features.*
|
||||||
|
import io.ktor.client.features.json.*
|
||||||
|
import io.ktor.client.request.*
|
||||||
|
import io.ktor.http.*
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
class SpotifyProvider(
|
class SpotifyProvider(
|
||||||
override val httpClient: HttpClient,
|
private val tokenStore: TokenStore,
|
||||||
private val database: Database,
|
private val database: Database,
|
||||||
private val logger: Kermit,
|
private val logger: Kermit,
|
||||||
private val dir: Dir,
|
private val dir: Dir,
|
||||||
) : SpotifyRequests {
|
) : SpotifyRequests {
|
||||||
|
|
||||||
|
init {
|
||||||
|
logger.d { "Creating Spotify Provider" }
|
||||||
|
GlobalScope.launch(Dispatchers.Default) {
|
||||||
|
val token = tokenStore.getToken()
|
||||||
|
httpClient = HttpClient {
|
||||||
|
defaultRequest {
|
||||||
|
header("Authorization","Bearer ${token.access_token}")
|
||||||
|
}
|
||||||
|
install(JsonFeature) {
|
||||||
|
serializer = kotlinxSerializer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.d { "Spotify Provider Created with $token" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override lateinit var httpClient: HttpClient
|
||||||
|
|
||||||
private val db:DownloadRecordDatabaseQueries
|
private val db:DownloadRecordDatabaseQueries
|
||||||
get() = database.downloadRecordDatabaseQueries
|
get() = database.downloadRecordDatabaseQueries
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package com.shabinder.common.di.spotify
|
|||||||
|
|
||||||
import com.shabinder.common.di.kotlinxSerializer
|
import com.shabinder.common.di.kotlinxSerializer
|
||||||
import com.shabinder.common.models.spotify.TokenData
|
import com.shabinder.common.models.spotify.TokenData
|
||||||
|
import com.shabinder.database.Database
|
||||||
import io.ktor.client.*
|
import io.ktor.client.*
|
||||||
import io.ktor.client.features.auth.*
|
import io.ktor.client.features.auth.*
|
||||||
import io.ktor.client.features.auth.providers.*
|
import io.ktor.client.features.auth.providers.*
|
||||||
@ -9,6 +10,7 @@ import io.ktor.client.features.json.*
|
|||||||
import io.ktor.client.request.*
|
import io.ktor.client.request.*
|
||||||
import io.ktor.client.request.forms.*
|
import io.ktor.client.request.forms.*
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
|
import kotlinx.datetime.Clock
|
||||||
|
|
||||||
suspend fun authenticateSpotify(): TokenData {
|
suspend fun authenticateSpotify(): TokenData {
|
||||||
return spotifyAuthClient.post("https://accounts.spotify.com/api/token"){
|
return spotifyAuthClient.post("https://accounts.spotify.com/api/token"){
|
||||||
|
@ -17,6 +17,7 @@ import com.shabinder.common.root.SpotiFlyerRootContent
|
|||||||
import com.shabinder.common.ui.SpotiFlyerColors
|
import com.shabinder.common.ui.SpotiFlyerColors
|
||||||
import com.shabinder.common.ui.SpotiFlyerShapes
|
import com.shabinder.common.ui.SpotiFlyerShapes
|
||||||
import com.shabinder.common.ui.SpotiFlyerTypography
|
import com.shabinder.common.ui.SpotiFlyerTypography
|
||||||
|
import com.shabinder.common.ui.colorOffWhite
|
||||||
import com.shabinder.database.Database
|
import com.shabinder.database.Database
|
||||||
|
|
||||||
private val koin = initKoin(enableNetworkLogs = true).koin
|
private val koin = initKoin(enableNetworkLogs = true).koin
|
||||||
@ -29,7 +30,8 @@ fun main(){
|
|||||||
Window("SpotiFlyer") {
|
Window("SpotiFlyer") {
|
||||||
Surface(
|
Surface(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
color = Color.Black
|
color = Color.Black,
|
||||||
|
contentColor = colorOffWhite
|
||||||
) {
|
) {
|
||||||
DesktopMaterialTheme(
|
DesktopMaterialTheme(
|
||||||
colors = SpotiFlyerColors,
|
colors = SpotiFlyerColors,
|
||||||
|
Loading…
Reference in New Issue
Block a user