diff --git a/app/src/main/java/org/jellyfin/mobile/ui/utils/DownloadSettingsDialog.kt b/app/src/main/java/org/jellyfin/mobile/ui/utils/DownloadSettingsDialog.kt new file mode 100644 index 00000000..43545df2 --- /dev/null +++ b/app/src/main/java/org/jellyfin/mobile/ui/utils/DownloadSettingsDialog.kt @@ -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() + 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() } + } + } +} diff --git a/app/src/main/java/org/jellyfin/mobile/utils/SystemUtils.kt b/app/src/main/java/org/jellyfin/mobile/utils/SystemUtils.kt index c8a9945b..902b84f2 100644 --- a/app/src/main/java/org/jellyfin/mobile/utils/SystemUtils.kt +++ b/app/src/main/java/org/jellyfin/mobile/utils/SystemUtils.kt @@ -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) { 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) { } } - // 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) } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3eb11a34..a629e3d9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -162,4 +162,7 @@ Keep local file(s) Do you want to remove "%1$s" from your downloads? Download incomplete + Choose download location + Please choose where downloaded media should be saved. Downloads use WiFi only by default. + Select folder