diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index b6798d6..f5d77a3 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -52,6 +52,9 @@
+
+ smartDeleteEnabled = enabled
+ userDataManager.smartDeleteEnabled = enabled
+ },
+ label = {
+ Text("Smart Delete")
+ },
+ toggleControl = {
+ Switch(
+ checked = smartDeleteEnabled,
+ onCheckedChange = null
+ )
+ },
+ modifier = Modifier.fillMaxWidth()
+ )
+ }
+
+ if (smartDeleteEnabled) {
+ item {
+ Text(
+ text = "Old audiobooks will be deleted once this amount is reached:",
+ style = MaterialTheme.typography.body2,
+ modifier = Modifier.padding(vertical = 8.dp)
+ )
+ }
+
+ item {
+ Text(
+ text = "Maximum Downloads",
+ style = MaterialTheme.typography.body1,
+ modifier = Modifier.padding(vertical = 8.dp)
+ )
+ }
+
+ item {
+ Row(
+ horizontalArrangement = Arrangement.spacedBy(16.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ modifier = Modifier.padding(horizontal = 16.dp)
+ ) {
+ // Minus button
+ Button(
+ onClick = {
+ if (maxDownloads > 1) {
+ maxDownloads--
+ userDataManager.smartDeleteMaxDownloads = maxDownloads
+ }
+ },
+ modifier = Modifier.size(40.dp),
+ enabled = maxDownloads > 1
+ ) {
+ Text("-")
+ }
+
+ // Current value
+ Text(
+ text = "$maxDownloads",
+ style = MaterialTheme.typography.title1,
+ modifier = Modifier.width(40.dp),
+ textAlign = TextAlign.Center
+ )
+
+ // Plus button
+ Button(
+ onClick = {
+ if (maxDownloads < 20) {
+ maxDownloads++
+ userDataManager.smartDeleteMaxDownloads = maxDownloads
+ }
+ },
+ modifier = Modifier.size(40.dp),
+ enabled = maxDownloads < 20
+ ) {
+ Text("+")
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/kaf/audiobookshelfwearos/app/data/SmartDeleteSettings.kt b/app/src/main/java/kaf/audiobookshelfwearos/app/data/SmartDeleteSettings.kt
new file mode 100644
index 0000000..06693a6
--- /dev/null
+++ b/app/src/main/java/kaf/audiobookshelfwearos/app/data/SmartDeleteSettings.kt
@@ -0,0 +1,6 @@
+package kaf.audiobookshelfwearos.app.data
+
+data class SmartDeleteSettings(
+ val isEnabled: Boolean = true,
+ val maxDownloads: Int = 5
+)
diff --git a/app/src/main/java/kaf/audiobookshelfwearos/app/services/MyDownloadService.kt b/app/src/main/java/kaf/audiobookshelfwearos/app/services/MyDownloadService.kt
index 90a1c09..83c9239 100644
--- a/app/src/main/java/kaf/audiobookshelfwearos/app/services/MyDownloadService.kt
+++ b/app/src/main/java/kaf/audiobookshelfwearos/app/services/MyDownloadService.kt
@@ -27,6 +27,7 @@ import kaf.audiobookshelfwearos.app.data.DownloadState
import kaf.audiobookshelfwearos.app.data.Track
import kaf.audiobookshelfwearos.app.userdata.UserDataManager
import kaf.audiobookshelfwearos.app.utils.DownloadProgressCalculator
+import kaf.audiobookshelfwearos.app.utils.SmartDeleteManager
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.asSharedFlow
@@ -205,6 +206,10 @@ class MyDownloadService : DownloadService(
Timber.i("Download completed: " + download.request.id)
// Clear speed history for completed downloads
DownloadProgressCalculator.clearSpeedHistory(download.request.id)
+
+ // Trigger smart delete after download completion
+ val smartDeleteManager = SmartDeleteManager(context)
+ smartDeleteManager.triggerSmartDeleteAfterDownload()
}
Timber.d("onDownloadChanged ${download.state}")
diff --git a/app/src/main/java/kaf/audiobookshelfwearos/app/userdata/UserDataManager.kt b/app/src/main/java/kaf/audiobookshelfwearos/app/userdata/UserDataManager.kt
index 92b2a0b..ae54b26 100644
--- a/app/src/main/java/kaf/audiobookshelfwearos/app/userdata/UserDataManager.kt
+++ b/app/src/main/java/kaf/audiobookshelfwearos/app/userdata/UserDataManager.kt
@@ -17,6 +17,8 @@ class UserDataManager(context: Context) {
private const val KEY_TOKEN = "token"
private const val KEY_USERID = "userid"
private const val KEY_OFFLINEMODE = "offlinemode"
+ private const val KEY_SMART_DELETE_ENABLED = "smart_delete_enabled"
+ private const val KEY_SMART_DELETE_MAX_DOWNLOADS = "smart_delete_max_downloads"
}
private val masterKey = MasterKey.Builder(context)
@@ -63,6 +65,14 @@ class UserDataManager(context: Context) {
get() = sharedPreferences.getBoolean(KEY_OFFLINEMODE, false)
set(value) = sharedPreferences.edit().putBoolean(KEY_OFFLINEMODE, value).apply()
+ var smartDeleteEnabled: Boolean
+ get() = sharedPreferences.getBoolean(KEY_SMART_DELETE_ENABLED, true)
+ set(value) = sharedPreferences.edit().putBoolean(KEY_SMART_DELETE_ENABLED, value).apply()
+
+ var smartDeleteMaxDownloads: Int
+ get() = sharedPreferences.getInt(KEY_SMART_DELETE_MAX_DOWNLOADS, 5)
+ set(value) = sharedPreferences.edit().putInt(KEY_SMART_DELETE_MAX_DOWNLOADS, value).apply()
+
fun clearUserData() {
sharedPreferences.edit().clear().apply()
}
diff --git a/app/src/main/java/kaf/audiobookshelfwearos/app/utils/SmartDeleteManager.kt b/app/src/main/java/kaf/audiobookshelfwearos/app/utils/SmartDeleteManager.kt
new file mode 100644
index 0000000..b226565
--- /dev/null
+++ b/app/src/main/java/kaf/audiobookshelfwearos/app/utils/SmartDeleteManager.kt
@@ -0,0 +1,81 @@
+package kaf.audiobookshelfwearos.app.utils
+
+import androidx.annotation.OptIn
+import androidx.media3.common.util.UnstableApi
+import android.content.Context
+import android.widget.Toast
+import androidx.media3.common.util.Log
+import kaf.audiobookshelfwearos.app.MainApp
+import kaf.audiobookshelfwearos.app.data.LibraryItem
+import kaf.audiobookshelfwearos.app.services.MyDownloadService
+import kaf.audiobookshelfwearos.app.userdata.UserDataManager
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+import timber.log.Timber
+
+class SmartDeleteManager(private val context: Context) {
+ private val userDataManager = UserDataManager(context)
+ private val database = (context.applicationContext as MainApp).database
+
+ fun triggerSmartDeleteAfterDownload() {
+ if (!userDataManager.smartDeleteEnabled) return
+
+ CoroutineScope(Dispatchers.IO).launch {
+ delay(3_000) // 3 second delay
+ performSmartDelete()
+ }
+ }
+
+ @OptIn(UnstableApi::class)
+ private suspend fun performSmartDelete() {
+ try {
+ val downloadManager = MyDownloadService.getDownloadManager(context)
+ val downloadedItems = database.libraryItemDao().getAllLibraryItems()
+ .filter { it.isDownloaded(context) }
+
+ // Get download completion order by checking download index
+ val itemsWithDownloadInfo = downloadedItems.mapNotNull { item ->
+ val firstTrack = item.media.tracks.firstOrNull()
+ if (firstTrack != null) {
+ val download = downloadManager.downloadIndex.getDownload(firstTrack.contentUrl)
+ if (download != null) {
+ item to download.updateTimeMs
+ } else null
+ } else null
+ }.sortedBy { it.second } // Sort by download update time (oldest first)
+
+ val maxDownloads = userDataManager.smartDeleteMaxDownloads
+ Timber.d("Smart delete max count: ${maxDownloads}")
+ val excessCount = itemsWithDownloadInfo.size - maxDownloads
+ Timber.d("Smart delete excess count: ${excessCount}")
+
+ if (excessCount > 0) {
+ val itemsToDelete = itemsWithDownloadInfo.take(excessCount).map { it.first }
+
+ for (item in itemsToDelete) {
+ // Remove downloads using the existing service
+ for (track in item.media.tracks) {
+ MyDownloadService.sendRemoveDownload(context, track)
+ }
+
+ // Remove from database
+ database.libraryItemDao().deleteLibraryItem(item)
+
+ CoroutineScope(Dispatchers.Main).launch {
+ Toast.makeText(
+ context,
+ "Removed ${item.title} to make space",
+ Toast.LENGTH_SHORT
+ ).show()
+ }
+
+ Timber.d("Smart delete removed: ${item.title}")
+ }
+ }
+ } catch (e: Exception) {
+ Timber.e(e, "Error during smart delete")
+ }
+ }
+}