mirror of
https://github.com/Shabinder/SpotiFlyer.git
synced 2024-12-22 20:57:54 +01:00
Error Handling
This commit is contained in:
parent
a0797bd891
commit
318c673cea
@ -33,7 +33,7 @@ class App: Application(), KoinComponent {
|
||||
val loggingEnabled = true
|
||||
|
||||
initKoin(loggingEnabled) {
|
||||
androidLogger(Level.NONE)
|
||||
androidLogger(Level.NONE) // No virtual method elapsedNow
|
||||
androidContext(this@App)
|
||||
modules(appModule(loggingEnabled))
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ import androidx.compose.material.Icon
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
@ -49,6 +50,7 @@ import com.shabinder.common.di.Picture
|
||||
import com.shabinder.common.list.SpotiFlyerList
|
||||
import com.shabinder.common.models.DownloadStatus
|
||||
import com.shabinder.common.models.TrackDetails
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
@Composable
|
||||
fun SpotiFlyerListContent(
|
||||
@ -61,11 +63,20 @@ fun SpotiFlyerListContent(
|
||||
// TODO Better Null Handling
|
||||
val result = model.queryResult
|
||||
if (result == null) {
|
||||
/* Loading Bar */
|
||||
Column(Modifier.fillMaxSize(), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
CircularProgressIndicator()
|
||||
Spacer(modifier.padding(8.dp))
|
||||
Text("Loading..", style = appNameStyle, color = colorPrimary)
|
||||
}
|
||||
LaunchedEffect(Unit) {
|
||||
delay(350)
|
||||
/*Handle if Any Exception Occurred*/
|
||||
model.errorOccurred?.let {
|
||||
showPopUpMessage(it.message ?: "An Error Occurred, Check your Link / Connection")
|
||||
component.onBackPressed()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LazyColumn(
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp),
|
||||
|
@ -150,8 +150,9 @@ actual class Dir actual constructor(
|
||||
}
|
||||
}catch (e:Exception){
|
||||
withContext(Dispatchers.Main){
|
||||
Toast.makeText(appContext,"Could Not Create File:\n${songFile.absolutePath}",Toast.LENGTH_SHORT).show()
|
||||
//Toast.makeText(appContext,"Could Not Create File:\n${songFile.absolutePath}",Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
if(songFile.exists()) songFile.delete()
|
||||
logger.e { "${songFile.absolutePath} could not be created" }
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,6 @@ import com.shabinder.common.di.utils.ParallelExecutor
|
||||
import com.shabinder.common.models.DownloadResult
|
||||
import com.shabinder.common.models.DownloadStatus
|
||||
import com.shabinder.common.models.TrackDetails
|
||||
import com.shabinder.downloader.YoutubeDownloader
|
||||
import com.shabinder.downloader.models.formats.Format
|
||||
import com.shabinder.common.models.Status
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@ -57,6 +56,7 @@ import java.io.File
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class ForegroundService : Service(), CoroutineScope {
|
||||
|
||||
private val tag: String = "Foreground Service"
|
||||
private val channelId = "ForegroundDownloaderService"
|
||||
private val notificationId = 101
|
||||
@ -64,26 +64,25 @@ class ForegroundService : Service(), CoroutineScope {
|
||||
private var converted = 0 // Total Files Converted
|
||||
private var downloaded = 0 // Total Files downloaded
|
||||
private var failed = 0 // Total Files failed
|
||||
private val isFinished: Boolean
|
||||
get() = converted + failed == total
|
||||
private var isSingleDownload: Boolean = false
|
||||
private val isFinished get() = converted + failed == total
|
||||
private var isSingleDownload = false
|
||||
|
||||
private lateinit var serviceJob: Job
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = serviceJob + Dispatchers.IO
|
||||
|
||||
private val allTracksStatus = hashMapOf<String, DownloadStatus>()
|
||||
private var messageList = mutableListOf("", "", "", "", "")
|
||||
private var wakeLock: PowerManager.WakeLock? = null
|
||||
private var isServiceStarted = false
|
||||
private var messageList = mutableListOf("", "", "", "", "")
|
||||
private lateinit var cancelIntent: PendingIntent
|
||||
|
||||
private lateinit var downloadManager: DownloadManager
|
||||
private lateinit var downloadService: ParallelExecutor
|
||||
private val ytDownloader get() = fetcher.youtubeProvider.ytDownloader
|
||||
private val fetcher: FetchPlatformQueryResult by inject()
|
||||
private val logger: Kermit by inject()
|
||||
private val dir: Dir by inject()
|
||||
private val ytDownloader: YoutubeDownloader
|
||||
get() = fetcher.youtubeProvider.ytDownloader
|
||||
|
||||
override fun onBind(intent: Intent): IBinder? = null
|
||||
|
||||
|
@ -24,6 +24,7 @@ import com.shabinder.common.di.providers.SpotifyProvider
|
||||
import com.shabinder.common.di.providers.YoutubeMp3
|
||||
import com.shabinder.common.di.providers.YoutubeMusic
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.features.HttpTimeout
|
||||
import io.ktor.client.features.json.JsonFeature
|
||||
import io.ktor.client.features.json.serializer.KotlinxSerializer
|
||||
import io.ktor.client.features.logging.DEFAULT
|
||||
@ -65,6 +66,12 @@ fun createHttpClient(enableNetworkLogs: Boolean = false, serializer: KotlinxSeri
|
||||
install(JsonFeature) {
|
||||
this.serializer = serializer
|
||||
}
|
||||
// Timeout
|
||||
install(HttpTimeout) {
|
||||
requestTimeoutMillis = 15000L
|
||||
connectTimeoutMillis = 15000L
|
||||
socketTimeoutMillis = 15000L
|
||||
}
|
||||
if (enableNetworkLogs) {
|
||||
install(Logging) {
|
||||
logger = Logger.DEFAULT
|
||||
@ -72,4 +79,5 @@ fun createHttpClient(enableNetworkLogs: Boolean = false, serializer: KotlinxSeri
|
||||
}
|
||||
}
|
||||
}
|
||||
/*Client Active Throughout App's Lifetime*/
|
||||
val ktorHttpClient = HttpClient {}
|
||||
|
@ -53,23 +53,27 @@ expect class Dir (
|
||||
|
||||
suspend fun downloadFile(url: String): Flow<DownloadResult> {
|
||||
return flow {
|
||||
val client = createHttpClient()
|
||||
val response = client.get<HttpStatement>(url).execute()
|
||||
val data = ByteArray(response.contentLength()!!.toInt())
|
||||
var offset = 0
|
||||
do {
|
||||
// Set Length optimally, after how many kb you want a progress update, now it 0.25mb
|
||||
val currentRead = response.content.readAvailable(data, offset, 250000)
|
||||
offset += currentRead
|
||||
val progress = (offset * 100f / data.size).roundToInt()
|
||||
emit(DownloadResult.Progress(progress))
|
||||
} while (currentRead > 0)
|
||||
if (response.status.isSuccess()) {
|
||||
emit(DownloadResult.Success(data))
|
||||
} else {
|
||||
emit(DownloadResult.Error("File not downloaded"))
|
||||
try {
|
||||
val client = createHttpClient()
|
||||
val response = client.get<HttpStatement>(url).execute()
|
||||
val data = ByteArray(response.contentLength()!!.toInt())
|
||||
var offset = 0
|
||||
do {
|
||||
// Set Length optimally, after how many kb you want a progress update, now it 0.25mb
|
||||
val currentRead = response.content.readAvailable(data, offset, 250000)
|
||||
offset += currentRead
|
||||
val progress = (offset * 100f / data.size).roundToInt()
|
||||
emit(DownloadResult.Progress(progress))
|
||||
} while (currentRead > 0)
|
||||
if (response.status.isSuccess()) {
|
||||
emit(DownloadResult.Success(data))
|
||||
} else {
|
||||
emit(DownloadResult.Error("File not downloaded"))
|
||||
}
|
||||
client.close()
|
||||
} catch (e:Exception) {
|
||||
emit(DownloadResult.Error(e.message ?: "File not downloaded"))
|
||||
}
|
||||
client.close()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,10 +63,6 @@ private suspend fun isInternetAvailable(): Boolean {
|
||||
actual val isInternetAvailable: Boolean
|
||||
get() {
|
||||
return true
|
||||
/*var result = false
|
||||
val job = GlobalScope.launch { result = isInternetAvailable() }
|
||||
while(job.isActive){}
|
||||
return result*/
|
||||
}
|
||||
|
||||
val DownloadProgressFlow: MutableSharedFlow<HashMap<String, DownloadStatus>> = MutableSharedFlow(1)
|
||||
|
@ -73,7 +73,8 @@ interface SpotiFlyerList {
|
||||
data class State(
|
||||
val queryResult: PlatformQueryResult? = null,
|
||||
val link: String = "",
|
||||
val trackList: List<TrackDetails> = emptyList()
|
||||
val trackList: List<TrackDetails> = emptyList(),
|
||||
val errorOccurred: Exception? = null
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -58,6 +58,7 @@ internal class SpotiFlyerListStoreProvider(
|
||||
data class ResultFetched(val result: PlatformQueryResult, val trackList: List<TrackDetails>) : Result()
|
||||
data class UpdateTrackList(val list: List<TrackDetails>) : Result()
|
||||
data class UpdateTrackItem(val item: TrackDetails) : Result()
|
||||
data class ErrorOccurred(val error: Exception) : Result()
|
||||
}
|
||||
|
||||
private inner class ExecutorImpl : SuspendExecutor<Intent, Unit, State, Result, Nothing>() {
|
||||
@ -74,10 +75,19 @@ internal class SpotiFlyerListStoreProvider(
|
||||
|
||||
override suspend fun executeIntent(intent: Intent, getState: () -> State) {
|
||||
when (intent) {
|
||||
is Intent.SearchLink -> fetchQuery.query(link)?.let { result ->
|
||||
result.trackList = result.trackList.toMutableList()
|
||||
dispatch((Result.ResultFetched(result, result.trackList.updateTracksStatuses(downloadProgressFlow.replayCache.getOrElse(0) { hashMapOf() }))))
|
||||
executeIntent(Intent.RefreshTracksStatuses, getState)
|
||||
is Intent.SearchLink -> {
|
||||
try {
|
||||
val result = fetchQuery.query(link)
|
||||
if( result != null) {
|
||||
result.trackList = result.trackList.toMutableList()
|
||||
dispatch((Result.ResultFetched(result, result.trackList.updateTracksStatuses(downloadProgressFlow.replayCache.getOrElse(0) { hashMapOf() }))))
|
||||
executeIntent(Intent.RefreshTracksStatuses, getState)
|
||||
} else {
|
||||
throw Exception("An Error Occurred, Check your Link / Connection")
|
||||
}
|
||||
} catch (e:Exception) {
|
||||
dispatch(Result.ErrorOccurred(e))
|
||||
}
|
||||
}
|
||||
|
||||
is Intent.StartDownloadAll -> {
|
||||
@ -107,6 +117,7 @@ internal class SpotiFlyerListStoreProvider(
|
||||
is Result.ResultFetched -> copy(queryResult = result.result, trackList = result.trackList, link = link)
|
||||
is Result.UpdateTrackList -> copy(trackList = result.list)
|
||||
is Result.UpdateTrackItem -> updateTrackItem(result.item)
|
||||
is Result.ErrorOccurred -> copy(errorOccurred = result.error)
|
||||
}
|
||||
|
||||
private fun State.updateTrackItem(item: TrackDetails): State {
|
||||
|
Loading…
Reference in New Issue
Block a user