mirror of
https://github.com/Shabinder/SpotiFlyer.git
synced 2024-11-22 01:04:31 +01:00
Android Network Connectivity
This commit is contained in:
parent
81a0b9a85c
commit
bf6463a3e1
@ -4,6 +4,9 @@ plugins {
|
||||
id("com.android.application")
|
||||
kotlin("android")
|
||||
id("org.jetbrains.compose")
|
||||
id("com.google.gms.google-services")
|
||||
id("com.google.firebase.crashlytics")
|
||||
id("com.google.firebase.firebase-perf")
|
||||
}
|
||||
|
||||
group = "com.shabinder"
|
||||
@ -75,6 +78,12 @@ dependencies {
|
||||
implementation(Decompose.decompose)
|
||||
implementation(Decompose.extensionsCompose)
|
||||
|
||||
//Firebase
|
||||
implementation(platform("com.google.firebase:firebase-bom:26.5.0"))
|
||||
implementation("com.google.firebase:firebase-analytics-ktx")
|
||||
implementation("com.google.firebase:firebase-crashlytics-ktx")
|
||||
implementation("com.google.firebase:firebase-perf-ktx")
|
||||
|
||||
/*
|
||||
//Lifecycle
|
||||
Versions.androidLifecycle.let{
|
||||
@ -85,6 +94,7 @@ dependencies {
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
Extras.Android.apply {
|
||||
implementation(appUpdator)
|
||||
implementation(razorpay)
|
||||
|
13
android/proguard-rules.pro
vendored
13
android/proguard-rules.pro
vendored
@ -21,6 +21,8 @@
|
||||
#-renamesourcefileattribute SourceFile
|
||||
-keepattributes *Annotation*, InnerClasses
|
||||
-dontnote kotlinx.serialization.AnnotationsKt # core serialization annotations
|
||||
-keepattributes SourceFile,LineNumberTable # Keep file names and line numbers.
|
||||
-keep public class * extends java.lang.Exception # Optional: Keep custom exceptions.
|
||||
|
||||
# kotlinx-serialization-json specific. Add this if you have java.lang.NoClassDefFoundError kotlinx.serialization.json.JsonObjectSerializer
|
||||
-keepclassmembers class kotlinx.serialization.json.** {
|
||||
@ -29,11 +31,14 @@
|
||||
-keepclasseswithmembers class kotlinx.serialization.json.** {
|
||||
kotlinx.serialization.KSerializer serializer(...);
|
||||
}
|
||||
|
||||
-keep,includedescriptorclasses class com.shabinder.spotiflyer.**$$serializer { *; } # <-- change package name to your app's
|
||||
-keepclassmembers class com.shabinder.spotiflyer.** { # <-- change package name to your app's
|
||||
-keep class com.shabinder.** { *; }
|
||||
-keep,includedescriptorclasses class com.shabinder.**$$serializer { *; } # <-- change package name to your app's
|
||||
-keepclassmembers class com.shabinder.** { # <-- change package name to your app's
|
||||
*** Companion;
|
||||
}
|
||||
-keepclasseswithmembers class com.shabinder.spotiflyer.** { # <-- change package name to your app's
|
||||
-keepclasseswithmembers class com.shabinder.** { # <-- change package name to your app's
|
||||
kotlinx.serialization.KSerializer serializer(...);
|
||||
}
|
||||
# Ktor
|
||||
-keep class io.ktor.** { *; }
|
||||
-keep class kotlinx.coroutines.** { *; }
|
@ -12,6 +12,7 @@
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
|
||||
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
|
@ -45,9 +45,7 @@ import com.shabinder.common.root.SpotiFlyerRoot
|
||||
import com.shabinder.common.root.callbacks.SpotiFlyerRootCallBacks
|
||||
import com.shabinder.common.uikit.*
|
||||
import com.shabinder.database.Database
|
||||
import com.shabinder.spotiflyer.utils.checkIfLatestVersion
|
||||
import com.shabinder.spotiflyer.utils.disableDozeMode
|
||||
import com.shabinder.spotiflyer.utils.requestStoragePermission
|
||||
import com.shabinder.spotiflyer.utils.*
|
||||
import com.tonyodev.fetch2.Status
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.*
|
||||
@ -100,6 +98,7 @@ class MainActivity : ComponentActivity(), PaymentResultListener {
|
||||
|
||||
if(askForPermission && !permissionGranted.value) permissionDialog()
|
||||
|
||||
NetworkDialog()
|
||||
root = SpotiFlyerRootContent(rememberRootComponent(::spotiFlyerRoot),statusBarHeight)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,73 @@
|
||||
package com.shabinder.spotiflyer.utils
|
||||
|
||||
import androidx.compose.animation.Crossfade
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.AlertDialog
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.CloudOff
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.shabinder.common.di.isInternetAvailable
|
||||
import com.shabinder.common.di.isInternetAvailableState
|
||||
import com.shabinder.common.uikit.SpotiFlyerShapes
|
||||
import com.shabinder.common.uikit.SpotiFlyerTypography
|
||||
import com.shabinder.common.uikit.colorOffWhite
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
@Composable
|
||||
fun NetworkDialog(
|
||||
networkAvailability: State<Boolean?> = isInternetAvailableState()
|
||||
){
|
||||
var visible by remember { mutableStateOf(false) }
|
||||
|
||||
LaunchedEffect(Unit){
|
||||
delay(2600)
|
||||
visible = true
|
||||
}
|
||||
if(networkAvailability.value == false){
|
||||
Crossfade(visible){
|
||||
if(it){
|
||||
AlertDialog(
|
||||
onDismissRequest = {},
|
||||
buttons = {
|
||||
/* TextButton({
|
||||
//Retry Network Connection
|
||||
},
|
||||
Modifier.padding(bottom = 16.dp,start = 16.dp,end = 16.dp).fillMaxWidth().background(Color(0xFFFC5C7D),shape = RoundedCornerShape(size = 8.dp)).padding(horizontal = 8.dp),
|
||||
){
|
||||
Text("Retry",color = Color.Black,fontSize = 18.sp,textAlign = TextAlign.Center)
|
||||
Icon(Icons.Rounded.SyncProblem,"Check Network Connection Again")
|
||||
}
|
||||
*/},
|
||||
title = { Text("No Internet Connection!",
|
||||
style = SpotiFlyerTypography.h5,
|
||||
textAlign = TextAlign.Center) },
|
||||
backgroundColor = Color.DarkGray,
|
||||
text = {
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally,verticalArrangement = Arrangement.Center){
|
||||
Spacer(modifier = Modifier.padding(8.dp))
|
||||
Row(verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.fillMaxWidth().padding(vertical = 6.dp)
|
||||
) {
|
||||
Image(Icons.Rounded.CloudOff,"No Internet.",Modifier.size(42.dp),colorFilter = ColorFilter.tint(
|
||||
colorOffWhite))
|
||||
Spacer(modifier = Modifier.padding(start = 16.dp))
|
||||
Text(
|
||||
text = "Please Check Your Network Connection.",
|
||||
style = SpotiFlyerTypography.subtitle1
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
,shape = SpotiFlyerShapes.medium)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -16,6 +16,9 @@ repositories {
|
||||
|
||||
dependencies {
|
||||
implementation("com.android.tools.build:gradle:4.0.1")
|
||||
implementation("com.google.gms:google-services:4.3.5")
|
||||
implementation("com.google.firebase:perf-plugin:1.3.4")
|
||||
implementation("com.google.firebase:firebase-crashlytics-gradle:2.5.0")
|
||||
implementation(JetBrains.Compose.gradlePlugin)
|
||||
implementation(JetBrains.Kotlin.gradlePlugin)
|
||||
implementation(JetBrains.Kotlin.serialization)
|
||||
|
@ -27,7 +27,7 @@ object Versions {
|
||||
//Android
|
||||
const val versionCode = 15
|
||||
const val minSdkVersion = 24
|
||||
const val compileSdkVersion = 30
|
||||
const val compileSdkVersion = 29
|
||||
const val targetSdkVersion = 29
|
||||
const val androidLifecycle = "2.3.0"
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.shabinder.common.ui"/>
|
||||
<manifest package="com.shabinder.common.uikit"/>
|
||||
|
@ -1,2 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.shabinder.common.ui"/>
|
||||
<manifest package="com.shabinder.common.models"/>
|
||||
|
@ -1,3 +1,5 @@
|
||||
import org.jetbrains.compose.compose
|
||||
|
||||
plugins {
|
||||
id("multiplatform-compose-setup")
|
||||
id("android-setup")
|
||||
@ -8,6 +10,7 @@ kotlin {
|
||||
sourceSets {
|
||||
commonMain {
|
||||
dependencies {
|
||||
implementation(compose.materialIconsExtended)
|
||||
implementation(project(":common:data-models"))
|
||||
implementation(project(":common:database"))
|
||||
implementation(project(":fuzzywuzzy:app"))
|
||||
|
@ -1,2 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.shabinder.common.ui"/>
|
||||
<manifest package="com.shabinder.common.di" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
</manifest>
|
||||
|
@ -4,8 +4,13 @@ import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.contentColorFor
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.github.kiulian.downloader.model.YoutubeVideo
|
||||
import com.github.kiulian.downloader.model.formats.Format
|
||||
|
@ -0,0 +1,122 @@
|
||||
package com.shabinder.common.di
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Context.CONNECTIVITY_SERVICE
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.Network
|
||||
import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
|
||||
import android.net.NetworkRequest
|
||||
import android.util.Log
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.lifecycle.LiveData
|
||||
import com.shabinder.common.database.appContext
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.IOException
|
||||
import java.net.InetSocketAddress
|
||||
import javax.net.SocketFactory
|
||||
|
||||
const val TAG = "C-Manager"
|
||||
|
||||
val isInternetAvailable by lazy { ConnectionLiveData(appContext) }
|
||||
|
||||
@Composable
|
||||
fun isInternetAvailableState(): State<Boolean?>{
|
||||
return isInternetAvailable.observeAsState()
|
||||
}
|
||||
|
||||
/**
|
||||
* Save all available networks with an internet connection to a set (@validNetworks).
|
||||
* As long as the size of the set > 0, this LiveData emits true.
|
||||
* MinSdk = 21.
|
||||
*
|
||||
* Inspired by:
|
||||
* https://github.com/AlexSheva-mason/Rick-Morty-Database/blob/master/app/src/main/java/com/shevaalex/android/rickmortydatabase/utils/networking/ConnectionLiveData.kt
|
||||
*/
|
||||
class ConnectionLiveData(context: Context = appContext) : LiveData<Boolean>() {
|
||||
|
||||
private lateinit var networkCallback: ConnectivityManager.NetworkCallback
|
||||
private val cm = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||
private val validNetworks: MutableSet<Network> = HashSet()
|
||||
|
||||
private fun checkValidNetworks() {
|
||||
postValue(validNetworks.size > 0)
|
||||
}
|
||||
|
||||
override fun onActive() {
|
||||
checkValidNetworks()
|
||||
networkCallback = createNetworkCallback()
|
||||
val networkRequest = NetworkRequest.Builder()
|
||||
.addCapability(NET_CAPABILITY_INTERNET)
|
||||
.build()
|
||||
cm.registerNetworkCallback(networkRequest, networkCallback)
|
||||
}
|
||||
|
||||
override fun onInactive() {
|
||||
cm.unregisterNetworkCallback(networkCallback)
|
||||
}
|
||||
|
||||
private fun createNetworkCallback() = object : ConnectivityManager.NetworkCallback() {
|
||||
|
||||
/*
|
||||
Called when a network is detected. If that network has internet, save it in the Set.
|
||||
Source: https://developer.android.com/reference/android/net/ConnectivityManager.NetworkCallback#onAvailable(android.net.Network)
|
||||
*/
|
||||
override fun onAvailable(network: Network) {
|
||||
Log.d(TAG, "onAvailable: ${network}")
|
||||
val networkCapabilities = cm.getNetworkCapabilities(network)
|
||||
val hasInternetCapability = networkCapabilities?.hasCapability(NET_CAPABILITY_INTERNET)
|
||||
Log.d(TAG, "onAvailable: ${network}, $hasInternetCapability")
|
||||
if (hasInternetCapability == true) {
|
||||
// check if this network actually has internet
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val hasInternet = DoesNetworkHaveInternet.execute(network.socketFactory)
|
||||
if(hasInternet){
|
||||
withContext(Dispatchers.Main){
|
||||
Log.d(TAG, "onAvailable: adding network. ${network}")
|
||||
validNetworks.add(network)
|
||||
checkValidNetworks()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
If the callback was registered with registerNetworkCallback() it will be called for each network which no longer satisfies the criteria of the callback.
|
||||
Source: https://developer.android.com/reference/android/net/ConnectivityManager.NetworkCallback#onLost(android.net.Network)
|
||||
*/
|
||||
override fun onLost(network: Network) {
|
||||
Log.d(TAG, "onLost: ${network}")
|
||||
validNetworks.remove(network)
|
||||
checkValidNetworks()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a ping to googles primary DNS.
|
||||
* If successful, that means we have internet.
|
||||
*/
|
||||
object DoesNetworkHaveInternet {
|
||||
|
||||
// Make sure to execute this on a background thread.
|
||||
fun execute(socketFactory: SocketFactory): Boolean {
|
||||
return try{
|
||||
Log.d(TAG, "PINGING google.")
|
||||
val socket = socketFactory.createSocket() ?: throw IOException("Socket is null.")
|
||||
socket.connect(InetSocketAddress("8.8.8.8", 53), 1500)
|
||||
socket.close()
|
||||
Log.d(TAG, "PING success.")
|
||||
true
|
||||
}catch (e: IOException){
|
||||
Log.e(TAG, "No internet connection. $e")
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package com.shabinder.common.di
|
||||
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.Observer
|
||||
|
||||
@Composable
|
||||
fun <T> LiveData<T>.observeAsState(): State<T?> = observeAsState(value)
|
||||
|
||||
/**
|
||||
* Starts observing this [LiveData] and represents its values via [State]. Every time there would
|
||||
* be new value posted into the [LiveData] the returned [State] will be updated causing
|
||||
* recomposition of every [State.value] usage.
|
||||
*
|
||||
* The inner observer will automatically be removed when this composable disposes or the current
|
||||
* [LifecycleOwner] moves to the [Lifecycle.State.DESTROYED] state.
|
||||
*
|
||||
* @sample androidx.compose.runtime.livedata.samples.LiveDataWithInitialSample
|
||||
*/
|
||||
@Composable
|
||||
fun <R, T : R> LiveData<T>.observeAsState(initial: R): State<R> {
|
||||
val lifecycleOwner = LocalLifecycleOwner.current
|
||||
val state = remember { mutableStateOf(initial) }
|
||||
DisposableEffect(this, lifecycleOwner) {
|
||||
val observer = Observer<T> { state.value = it }
|
||||
observe(lifecycleOwner, observer)
|
||||
onDispose { removeObserver(observer) }
|
||||
}
|
||||
return state
|
||||
}
|
@ -14,6 +14,7 @@ import io.ktor.client.features.logging.*
|
||||
import io.ktor.client.request.*
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.koin.core.context.startKoin
|
||||
import org.koin.dsl.KoinAppDeclaration
|
||||
@ -46,20 +47,18 @@ val kotlinxSerializer = KotlinxSerializer( Json {
|
||||
/*
|
||||
* Refactor This
|
||||
* */
|
||||
fun isInternetAvailable(): Boolean {
|
||||
var result = false
|
||||
val job = GlobalScope.launch {
|
||||
suspend fun isInternetAvailable(): Boolean {
|
||||
return withContext(dispatcherIO) {
|
||||
try {
|
||||
ktorHttpClient.head<String>("http://google.com")
|
||||
result = true
|
||||
true
|
||||
} catch (e: Exception) {
|
||||
println(e.message)
|
||||
result = false
|
||||
false
|
||||
}
|
||||
}
|
||||
while (job.isActive){}
|
||||
return result
|
||||
}
|
||||
|
||||
fun createHttpClient(enableNetworkLogs: Boolean = false,serializer: KotlinxSerializer = kotlinxSerializer) = HttpClient {
|
||||
install(JsonFeature) {
|
||||
this.serializer = serializer
|
||||
|
@ -0,0 +1,6 @@
|
||||
package com.shabinder.common.di
|
||||
|
||||
sealed class NetworkResponse<out T> {
|
||||
data class Success<T>(val value:T):NetworkResponse<T>()
|
||||
data class Error(val message:String):NetworkResponse<Nothing>()
|
||||
}
|
@ -21,7 +21,7 @@ class TokenStore(
|
||||
db.add(token.access_token!!, token.expiry!! + Clock.System.now().epochSeconds)
|
||||
}
|
||||
|
||||
suspend fun getToken(): TokenData {
|
||||
suspend fun getToken(): TokenData? {
|
||||
var token: TokenData? = db.select().executeAsOneOrNull()?.let {
|
||||
TokenData(it.accessToken,null,it.expiry)
|
||||
}
|
||||
@ -29,7 +29,7 @@ class TokenStore(
|
||||
if(Clock.System.now().epochSeconds > token?.expiry ?:0 || token == null){
|
||||
logger.d{"Requesting New Token"}
|
||||
token = authenticateSpotify()
|
||||
GlobalScope.launch { token.access_token?.let { save(token) } }
|
||||
GlobalScope.launch { token?.access_token?.let { save(token) } }
|
||||
}
|
||||
return token
|
||||
}
|
||||
|
@ -18,10 +18,7 @@ package com.shabinder.common.di.providers
|
||||
|
||||
import co.touchlab.kermit.Kermit
|
||||
import com.shabinder.common.database.DownloadRecordDatabaseQueries
|
||||
import com.shabinder.common.di.Dir
|
||||
import com.shabinder.common.di.TokenStore
|
||||
import com.shabinder.common.di.finalOutputDir
|
||||
import com.shabinder.common.di.kotlinxSerializer
|
||||
import com.shabinder.common.di.*
|
||||
import com.shabinder.common.di.spotify.SpotifyRequests
|
||||
import com.shabinder.common.models.PlatformQueryResult
|
||||
import com.shabinder.common.models.TrackDetails
|
||||
@ -48,8 +45,17 @@ class SpotifyProvider(
|
||||
|
||||
init {
|
||||
logger.d { "Creating Spotify Provider" }
|
||||
GlobalScope.launch(Dispatchers.Default) {
|
||||
val token = tokenStore.getToken()
|
||||
GlobalScope.launch(Dispatchers.Default) {authenticateSpotify()}
|
||||
}
|
||||
|
||||
override suspend fun authenticateSpotify(): HttpClient?{
|
||||
val token = tokenStore.getToken()
|
||||
return if(token == null) {
|
||||
showPopUpMessage("Please Check your Network Connection")
|
||||
null
|
||||
}
|
||||
else{
|
||||
logger.d { "Spotify Provider Created with $token" }
|
||||
httpClient = HttpClient {
|
||||
defaultRequest {
|
||||
header("Authorization","Bearer ${token.access_token}")
|
||||
@ -58,7 +64,7 @@ class SpotifyProvider(
|
||||
serializer = kotlinxSerializer
|
||||
}
|
||||
}
|
||||
logger.d { "Spotify Provider Created with $token" }
|
||||
httpClient
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,6 +74,11 @@ class SpotifyProvider(
|
||||
get() = database.downloadRecordDatabaseQueries
|
||||
|
||||
suspend fun query(fullLink: String): PlatformQueryResult?{
|
||||
|
||||
if(!this::httpClient.isInitialized){
|
||||
authenticateSpotify()
|
||||
}
|
||||
|
||||
var spotifyLink =
|
||||
"https://" + fullLink.substringAfterLast("https://").substringBefore(" ").trim()
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.shabinder.common.di.spotify
|
||||
|
||||
import com.shabinder.common.di.isInternetAvailable
|
||||
import com.shabinder.common.di.kotlinxSerializer
|
||||
import com.shabinder.common.models.spotify.TokenData
|
||||
import io.ktor.client.*
|
||||
@ -10,10 +11,10 @@ import io.ktor.client.request.*
|
||||
import io.ktor.client.request.forms.*
|
||||
import io.ktor.http.*
|
||||
|
||||
suspend fun authenticateSpotify(): TokenData {
|
||||
return spotifyAuthClient.post("https://accounts.spotify.com/api/token"){
|
||||
suspend fun authenticateSpotify(): TokenData? {
|
||||
return if(isInternetAvailable()) spotifyAuthClient.post("https://accounts.spotify.com/api/token"){
|
||||
body = FormDataContent(Parameters.build { append("grant_type","client_credentials") })
|
||||
}
|
||||
} else null
|
||||
}
|
||||
|
||||
private val spotifyAuthClient by lazy {
|
||||
|
@ -13,6 +13,8 @@ interface SpotifyRequests {
|
||||
|
||||
val httpClient:HttpClient
|
||||
|
||||
suspend fun authenticateSpotify():HttpClient?
|
||||
|
||||
suspend fun getPlaylist(playlistID: String): Playlist {
|
||||
return httpClient.get("$BASE_URL/playlists/$playlistID")
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
package com.shabinder.common.di
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import com.github.kiulian.downloader.YoutubeDownloader
|
||||
import com.github.kiulian.downloader.model.YoutubeVideo
|
||||
import com.github.kiulian.downloader.model.formats.Format
|
||||
@ -22,6 +26,19 @@ actual fun giveDonation(){
|
||||
//TODO
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
actual fun AlertDialog(
|
||||
onDismissRequest: () -> Unit,
|
||||
buttons: @Composable () -> Unit,
|
||||
modifier: Modifier,
|
||||
title: (@Composable () -> Unit)?,
|
||||
text: @Composable (() -> Unit)?,
|
||||
shape: Shape,
|
||||
backgroundColor: Color,
|
||||
contentColor: Color,
|
||||
){}
|
||||
|
||||
actual fun queryActiveTracks(){}
|
||||
|
||||
val DownloadProgressFlow: MutableSharedFlow<HashMap<String,DownloadStatus>> = MutableSharedFlow(1)
|
||||
|
@ -1,2 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.shabinder.common.ui"/>
|
||||
<manifest package="com.shabinder.common.list"/>
|
||||
|
@ -1,2 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.shabinder.common.ui"/>
|
||||
<manifest package="com.shabinder.common.main"/>
|
||||
|
@ -1,2 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.shabinder.common.ui"/>
|
||||
<manifest package="com.shabinder.common.root"/>
|
||||
|
@ -22,6 +22,7 @@ kotlin {
|
||||
implementation(project(":common:database"))
|
||||
implementation(project(":common:dependency-injection"))
|
||||
implementation(project(":common:compose"))
|
||||
implementation(project(":common:root"))
|
||||
implementation(Decompose.decompose)
|
||||
implementation(Decompose.extensionsCompose)
|
||||
implementation(MVIKotlin.mvikotlin)
|
||||
|
Loading…
Reference in New Issue
Block a user