Show download settings dialog on first download

This commit is contained in:
Niels van Velzen authored and Niels van Velzen committed 2026-06-18 16:41:03 +02:00
1 parent f90b3e543b
commit 57b4aac586
3 files changed
+128 -37

No files matched your search

@@ -0,0 +1,110 @@
package org.jellyfin.mobile.ui.utils
import androidx.activity.ComponentActivity
import androidx.activity.ComponentDialog
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Button
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.suspendCancellableCoroutine
import org.jellyfin.mobile.R
import org.jellyfin.mobile.app.StorageManager
import org.koin.android.ext.android.get
import org.koin.compose.koinInject
import kotlin.coroutines.resume
@Composable
fun DownloadSettingsDialogContent(onClose: () -> Unit) {
val storageManager: StorageManager = koinInject()
var storageLocation by remember { mutableStateOf(storageManager.getStorageLocation()) }
val storageLocationPicker = rememberLauncherForActivityResult(ActivityResultContracts.OpenDocumentTree()) { uri ->
if (uri != null) {
storageManager.changeStorageLocation(uri)
storageLocation = storageManager.getStorageLocation()
onClose()
}
}
Surface(
shape = MaterialTheme.shapes.medium,
color = MaterialTheme.colors.surface,
contentColor = MaterialTheme.colors.onSurface,
) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(24.dp)
.verticalScroll(rememberScrollState()),
verticalArrangement = Arrangement.spacedBy(16.dp),
) {
Text(
text = stringResource(R.string.download_settings_dialog_title),
style = MaterialTheme.typography.h6,
)
Text(
text = stringResource(R.string.download_settings_dialog_message),
style = MaterialTheme.typography.body2,
)
Button(
onClick = {
storageLocationPicker.launch(storageLocation?.uri ?: storageManager.defaultStorageLocation)
},
modifier = Modifier.fillMaxWidth(),
) {
Text(text = stringResource(R.string.select_folder))
}
}
}
}
fun ComponentActivity.shouldShowDownloadSettingsDialog(): Boolean {
val storageManager = get<StorageManager>()
return storageManager.getStorageLocation() == null
}
suspend fun ComponentActivity.showDownloadSettingsDialog() {
suspendCancellableCoroutine { continuation ->
ComponentDialog(this).apply {
setContentView(
ComposeView(this@showDownloadSettingsDialog).apply {
setContent {
AppTheme {
DownloadSettingsDialogContent(
onClose = { dismiss() },
)
}
}
},
)
setOnDismissListener {
if (continuation.isActive) {
continuation.resume(Unit)
}
}
show()
continuation.invokeOnCancellation { dismiss() }
}
}
}
@@ -13,7 +13,6 @@ import android.net.Uri
import android.os.PowerManager
import android.provider.Settings
import android.provider.Settings.System.ACCELEROMETER_ROTATION
import androidx.appcompat.app.AlertDialog
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.content.getSystemService
import com.google.android.material.snackbar.Snackbar
@@ -23,8 +22,9 @@ import org.jellyfin.mobile.MainActivity
import org.jellyfin.mobile.R
import org.jellyfin.mobile.app.AppPreferences
import org.jellyfin.mobile.downloads.DownloadManager
import org.jellyfin.mobile.downloads.DownloadMethod
import org.jellyfin.mobile.settings.ExternalPlayerPackage
import org.jellyfin.mobile.ui.utils.shouldShowDownloadSettingsDialog
import org.jellyfin.mobile.ui.utils.showDownloadSettingsDialog
import org.jellyfin.mobile.webapp.WebViewFragment
import org.jellyfin.sdk.model.serializer.toUUID
import org.koin.android.ext.android.get
@@ -63,7 +63,17 @@ suspend fun MainActivity.requestDownload(itemIds: Collection<UUID>) {
val appPreferences: AppPreferences = get()
val downloadManager: DownloadManager = get()
val permissionResult: Boolean = suspendCancellableCoroutine { continuation ->
// Show dialog to choose download location for first download
if (shouldShowDownloadSettingsDialog()) {
showDownloadSettingsDialog()
}
// If no storage location is set the request for choosing a download folder
// so we'll cancel the download too
if (appPreferences.storageLocation == null) return
// Request permissions to send notifications about download progress
suspendCancellableCoroutine { continuation ->
requestPermission("android.permission.POST_NOTIFICATIONS") { permissionsMap ->
if (permissionsMap[Manifest.permission.POST_NOTIFICATIONS] == PackageManager.PERMISSION_GRANTED) {
continuation.resume(true)
@@ -73,42 +83,10 @@ suspend fun MainActivity.requestDownload(itemIds: Collection<UUID>) {
}
}
// First time download, ask for network constraint preference
if (appPreferences.downloadMethod == null) {
suspendCancellableCoroutine { continuation ->
AlertDialog.Builder(this)
.setTitle(R.string.network_title)
.setMessage(R.string.network_message)
.setPositiveButton(R.string.wifi_only) { _, _ ->
val selectedDownloadMethod = DownloadMethod.WIFI_ONLY
appPreferences.downloadMethod = selectedDownloadMethod
continuation.resume(selectedDownloadMethod)
}
.setNegativeButton(R.string.mobile_data) { _, _ ->
val selectedDownloadMethod = DownloadMethod.MOBILE_DATA
appPreferences.downloadMethod = selectedDownloadMethod
continuation.resume(selectedDownloadMethod)
}
.setNeutralButton(R.string.mobile_data_and_roaming) { _, _ ->
val selectedDownloadMethod = DownloadMethod.MOBILE_AND_ROAMING
appPreferences.downloadMethod = selectedDownloadMethod
continuation.resume(selectedDownloadMethod)
}
.setOnDismissListener {
continuation.cancel(null)
}
.setCancelable(false)
.show()
}
}
// Automatically use a default download location
if (appPreferences.storageLocation == null) {
}
// Add actual download
val server = mainViewModel.serverState.value.server ?: return
val user = mainViewModel.userState.value.user ?: return
downloadManager.enqueueItems(server, user, itemIds)
}
+3
View File
@@ -162,4 +162,7 @@
<string name="download_remove_keep_local">Keep local file(s)</string>
<string name="download_remove_description">Do you want to remove "%1$s" from your downloads?</string>
<string name="download_incomplete">Download incomplete</string>
<string name="download_settings_dialog_title">Choose download location</string>
<string name="download_settings_dialog_message">Please choose where downloaded media should be saved. Downloads use WiFi only by default.</string>
<string name="select_folder">Select folder</string>
</resources>