From 15a4ecf092bd3552db55eefe86ae3a16459b70c4 Mon Sep 17 00:00:00 2001 From: zaednasr <75589932+zaednasr@users.noreply.github.com> Date: Mon, 1 Jul 2024 20:20:58 +0200 Subject: [PATCH] 1.7.8 --- app/build.gradle | 9 +- .../18.json | 732 +++++++++++++++++ .../19.json | 739 ++++++++++++++++++ .../java/com/deniscerri/ytdl/MainActivity.kt | 55 +- .../com/deniscerri/ytdl/database/DBManager.kt | 6 +- .../deniscerri/ytdl/database/Migrations.kt | 7 +- .../ytdl/database/dao/CommandTemplateDao.kt | 3 + .../ytdl/database/dao/DownloadDao.kt | 21 +- .../ytdl/database/models/DownloadItem.kt | 4 +- .../database/models/DownloadItemSimple.kt | 1 + .../database/models/RestoreAppDataItem.kt | 19 + .../observeSources/ObserveSourcesItem.kt | 4 +- .../repository/CommandTemplateRepository.kt | 4 + .../database/repository/DownloadRepository.kt | 32 +- .../database/repository/ResultRepository.kt | 7 +- .../viewmodel/CommandTemplateViewModel.kt | 4 + .../database/viewmodel/DownloadViewModel.kt | 98 +-- .../viewmodel/SharedDownloadViewModel.kt | 60 +- .../PauseDownloadNotificationReceiver.kt | 46 +- .../ytdl/ui/adapter/ActiveDownloadAdapter.kt | 27 +- .../adapter/ActiveDownloadMinifiedAdapter.kt | 41 +- .../ConfigureMultipleDownloadsAdapter.kt | 7 +- .../ytdl/ui/adapter/GenericDownloadAdapter.kt | 3 + .../ytdl/ui/adapter/NavBarOptionsAdapter.kt | 73 ++ .../ConfigureDownloadBottomSheetDialog.kt | 41 +- .../downloadcard/DownloadBottomSheetDialog.kt | 24 +- .../downloadcard/DownloadCommandFragment.kt | 7 +- .../downloadcard/DownloadFragmentAdapter.kt | 6 +- .../DownloadMultipleBottomSheetDialog.kt | 60 +- .../DownloadsAlreadyExistDialog.kt | 4 +- .../FormatSelectionBottomSheetDialog.kt | 52 +- .../ObserveSourcesBottomSheetDialog.kt | 9 + .../downloadcard/ResultCardDetailsDialog.kt | 47 -- .../ui/downloads/ActiveDownloadsFragment.kt | 594 +++++++++++++- .../ui/downloads/DownloadQueueMainFragment.kt | 59 +- .../ytdl/ui/downloads/HistoryFragment.kt | 9 +- .../downloads/ScheduledDownloadsFragment.kt | 5 +- .../deniscerri/ytdl/ui/more/MoreFragment.kt | 8 + .../more/settings/GeneralSettingsFragment.kt | 122 ++- .../ui/more/settings/MainSettingsFragment.kt | 564 ++++++------- .../more/settings/UpdateSettingsFragment.kt | 7 - .../com/deniscerri/ytdl/util/Extensions.kt | 8 + .../com/deniscerri/ytdl/util/FormatSorter.kt | 155 ++++ .../java/com/deniscerri/ytdl/util/InfoUtil.kt | 92 ++- .../com/deniscerri/ytdl/util/NavbarUtil.kt | 136 ++++ .../deniscerri/ytdl/util/NotificationUtil.kt | 7 +- .../java/com/deniscerri/ytdl/util/UiUtil.kt | 16 +- .../deniscerri/ytdl/work/DownloadWorker.kt | 10 +- .../ytdl/work/ObserveSourceWorker.kt | 30 +- .../ytdl/work/TerminalDownloadWorker.kt | 2 +- .../drawable/baseline_disabled_visible_24.xml | 5 + .../res/drawable/baseline_home_filled_24.xml | 5 + .../baseline_library_add_check_24.xml | 5 + app/src/main/res/drawable/ic_history.xml | 5 + .../main/res/drawable/ic_home_outlined.xml | 10 + .../main/res/layout/active_download_card.xml | 31 +- .../configure_download_bottom_sheet.xml | 43 +- app/src/main/res/layout/cut_video_sheet.xml | 1 + .../main/res/layout/download_bottom_sheet.xml | 45 +- app/src/main/res/layout/download_card.xml | 20 +- .../res/layout/format_select_bottom_sheet.xml | 40 + app/src/main/res/layout/fragment_active.xml | 109 ++- .../fragment_download_queue_main_screen.xml | 2 +- app/src/main/res/layout/nav_options_item.xml | 59 ++ .../layout/observe_sources_bottom_sheet.xml | 7 + .../main/res/layout/result_card_details.xml | 1 + .../res/layout/simple_options_recycler.xml | 12 + app/src/main/res/menu/bottom_nav_menu.xml | 12 + .../main/res/menu/download_multiple_menu.xml | 6 + app/src/main/res/menu/queued_menu_context.xml | 7 - app/src/main/res/navigation/nav_graph.xml | 3 + app/src/main/res/values-in/strings.xml | 3 +- app/src/main/res/values-sq-rAL/strings.xml | 1 + .../main/res/values-sw600dp-land/attrs.xml | 1 + app/src/main/res/values/arrays.xml | 12 + app/src/main/res/values/attrs.xml | 1 + app/src/main/res/values/strings.xml | 7 + .../main/res/xml/downloading_preferences.xml | 2 +- app/src/main/res/xml/general_preferences.xml | 40 +- app/src/main/res/xml/updating_preferences.xml | 18 +- build.gradle | 2 +- 81 files changed, 3827 insertions(+), 764 deletions(-) create mode 100644 app/schemas/com.deniscerri.ytdl.database.DBManager/18.json create mode 100644 app/schemas/com.deniscerri.ytdl.database.DBManager/19.json create mode 100644 app/src/main/java/com/deniscerri/ytdl/database/models/RestoreAppDataItem.kt create mode 100644 app/src/main/java/com/deniscerri/ytdl/ui/adapter/NavBarOptionsAdapter.kt create mode 100644 app/src/main/java/com/deniscerri/ytdl/util/FormatSorter.kt create mode 100644 app/src/main/java/com/deniscerri/ytdl/util/NavbarUtil.kt create mode 100644 app/src/main/res/drawable/baseline_disabled_visible_24.xml create mode 100644 app/src/main/res/drawable/baseline_home_filled_24.xml create mode 100644 app/src/main/res/drawable/baseline_library_add_check_24.xml create mode 100644 app/src/main/res/drawable/ic_history.xml create mode 100644 app/src/main/res/drawable/ic_home_outlined.xml create mode 100644 app/src/main/res/layout/nav_options_item.xml create mode 100644 app/src/main/res/layout/simple_options_recycler.xml diff --git a/app/build.gradle b/app/build.gradle index 20b84cc7..092840c4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,7 +10,7 @@ plugins { def properties = new Properties() def versionMajor = 1 def versionMinor = 7 -def versionPatch = 7 +def versionPatch = 8 def versionBuild = 0 // bump for dogfood builds, public betas, etc. def isBeta = false def versionExt = isBeta ? ".${versionBuild}-beta" : "" @@ -130,6 +130,10 @@ dependencies { implementation "com.github.yausername.youtubedl-android:library:$youtubedlAndroidVer" implementation "com.github.yausername.youtubedl-android:ffmpeg:$youtubedlAndroidVer" implementation "com.github.yausername.youtubedl-android:aria2c:$youtubedlAndroidVer" +// +// implementation "io.github.junkfood02.youtubedl-android:library:0.16.0" +// implementation "io.github.junkfood02.youtubedl-android:ffmpeg:0.16.0" +// implementation "io.github.junkfood02.youtubedl-android:aria2c:0.16.0" implementation "androidx.appcompat:appcompat:$appCompatVer" implementation "androidx.constraintlayout:constraintlayout:2.1.4" @@ -142,6 +146,7 @@ dependencies { implementation 'androidx.core:core-ktx:1.12.0' implementation 'androidx.test.ext:junit-ktx:1.1.5' implementation 'androidx.compose.ui:ui-android:1.6.5' + implementation 'androidx.preference:preference:1.2.1' testImplementation "junit:junit:$junitVer" androidTestImplementation "junit:junit:$junitVer" androidTestImplementation "androidx.test.ext:junit:$androidJunitVer" @@ -177,7 +182,7 @@ dependencies { implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0' implementation 'it.xabaras.android:recyclerview-swipedecorator:1.4' - implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.7.0" + implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.8.2" implementation "com.github.Irineu333:Highlight-KT:1.0.4" // For media playback using ExoPlayer diff --git a/app/schemas/com.deniscerri.ytdl.database.DBManager/18.json b/app/schemas/com.deniscerri.ytdl.database.DBManager/18.json new file mode 100644 index 00000000..39e4da73 --- /dev/null +++ b/app/schemas/com.deniscerri.ytdl.database.DBManager/18.json @@ -0,0 +1,732 @@ +{ + "formatVersion": 1, + "database": { + "version": 18, + "identityHash": "0e5e77e8657b2b151e63613f8d6f8110", + "entities": [ + { + "tableName": "results", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `title` TEXT NOT NULL, `author` TEXT NOT NULL, `duration` TEXT NOT NULL, `thumb` TEXT NOT NULL, `website` TEXT NOT NULL, `playlistTitle` TEXT NOT NULL, `formats` TEXT NOT NULL, `urls` TEXT NOT NULL DEFAULT '', `chapters` TEXT, `playlistURL` TEXT DEFAULT '', `playlistIndex` INTEGER, `creationTime` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "author", + "columnName": "author", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "duration", + "columnName": "duration", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "thumb", + "columnName": "thumb", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "website", + "columnName": "website", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "playlistTitle", + "columnName": "playlistTitle", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "formats", + "columnName": "formats", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "urls", + "columnName": "urls", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "chapters", + "columnName": "chapters", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "playlistURL", + "columnName": "playlistURL", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "''" + }, + { + "fieldPath": "playlistIndex", + "columnName": "playlistIndex", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "creationTime", + "columnName": "creationTime", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "history", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `title` TEXT NOT NULL, `author` TEXT NOT NULL, `duration` TEXT NOT NULL, `thumb` TEXT NOT NULL, `type` TEXT NOT NULL, `time` INTEGER NOT NULL, `downloadPath` TEXT NOT NULL, `website` TEXT NOT NULL, `format` TEXT NOT NULL, `downloadId` INTEGER NOT NULL DEFAULT 0, `command` TEXT NOT NULL DEFAULT '')", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "author", + "columnName": "author", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "duration", + "columnName": "duration", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "thumb", + "columnName": "thumb", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "time", + "columnName": "time", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "downloadPath", + "columnName": "downloadPath", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "website", + "columnName": "website", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "format", + "columnName": "format", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "downloadId", + "columnName": "downloadId", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "command", + "columnName": "command", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "downloads", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `title` TEXT NOT NULL, `author` TEXT NOT NULL, `thumb` TEXT NOT NULL, `duration` TEXT NOT NULL, `type` TEXT NOT NULL, `format` TEXT NOT NULL, `container` TEXT NOT NULL DEFAULT 'Default', `downloadSections` TEXT NOT NULL DEFAULT '', `allFormats` TEXT NOT NULL, `downloadPath` TEXT NOT NULL, `website` TEXT NOT NULL, `downloadSize` TEXT NOT NULL, `playlistTitle` TEXT NOT NULL, `audioPreferences` TEXT NOT NULL, `videoPreferences` TEXT NOT NULL, `extraCommands` TEXT NOT NULL DEFAULT '', `customFileNameTemplate` TEXT NOT NULL, `SaveThumb` INTEGER NOT NULL, `status` TEXT NOT NULL DEFAULT 'Queued', `downloadStartTime` INTEGER NOT NULL DEFAULT 0, `logID` INTEGER, `playlistURL` TEXT DEFAULT '', `playlistIndex` INTEGER)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "author", + "columnName": "author", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "thumb", + "columnName": "thumb", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "duration", + "columnName": "duration", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "format", + "columnName": "format", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "container", + "columnName": "container", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "'Default'" + }, + { + "fieldPath": "downloadSections", + "columnName": "downloadSections", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "allFormats", + "columnName": "allFormats", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "downloadPath", + "columnName": "downloadPath", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "website", + "columnName": "website", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "downloadSize", + "columnName": "downloadSize", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "playlistTitle", + "columnName": "playlistTitle", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "audioPreferences", + "columnName": "audioPreferences", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "videoPreferences", + "columnName": "videoPreferences", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "extraCommands", + "columnName": "extraCommands", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "customFileNameTemplate", + "columnName": "customFileNameTemplate", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "SaveThumb", + "columnName": "SaveThumb", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "'Queued'" + }, + { + "fieldPath": "downloadStartTime", + "columnName": "downloadStartTime", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "logID", + "columnName": "logID", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "playlistURL", + "columnName": "playlistURL", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "''" + }, + { + "fieldPath": "playlistIndex", + "columnName": "playlistIndex", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "commandTemplates", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `useAsExtraCommand` INTEGER NOT NULL DEFAULT 0, `useAsExtraCommandAudio` INTEGER NOT NULL DEFAULT 1, `useAsExtraCommandVideo` INTEGER NOT NULL DEFAULT 1)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "useAsExtraCommand", + "columnName": "useAsExtraCommand", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "useAsExtraCommandAudio", + "columnName": "useAsExtraCommandAudio", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "1" + }, + { + "fieldPath": "useAsExtraCommandVideo", + "columnName": "useAsExtraCommandVideo", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "1" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "searchHistory", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `query` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "query", + "columnName": "query", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "templateShortcuts", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `content` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "cookies", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `content` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "logs", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `format` TEXT NOT NULL, `downloadType` TEXT NOT NULL, `downloadTime` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "format", + "columnName": "format", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "downloadType", + "columnName": "downloadType", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "downloadTime", + "columnName": "downloadTime", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "terminalDownloads", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `command` TEXT NOT NULL, `log` TEXT DEFAULT '')", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "command", + "columnName": "command", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "log", + "columnName": "log", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "''" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "sources", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `url` TEXT NOT NULL, `downloadItemTemplate` TEXT NOT NULL, `everyNr` INTEGER NOT NULL, `everyCategory` TEXT NOT NULL, `everyTime` INTEGER NOT NULL, `weeklyConfig` TEXT, `monthlyConfig` TEXT, `status` TEXT NOT NULL, `startsTime` INTEGER NOT NULL, `endsDate` INTEGER NOT NULL DEFAULT 0, `endsAfterCount` INTEGER NOT NULL DEFAULT 0, `runCount` INTEGER NOT NULL DEFAULT 0, `getOnlyNewUploads` INTEGER NOT NULL DEFAULT 0, `retryMissingDownloads` INTEGER NOT NULL, `ignoredLinks` TEXT NOT NULL DEFAULT '[]', `alreadyProcessedLinks` TEXT NOT NULL, `syncWithSource` INTEGER NOT NULL DEFAULT 0)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "downloadItemTemplate", + "columnName": "downloadItemTemplate", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "everyNr", + "columnName": "everyNr", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "everyCategory", + "columnName": "everyCategory", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "everyTime", + "columnName": "everyTime", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "weeklyConfig", + "columnName": "weeklyConfig", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "monthlyConfig", + "columnName": "monthlyConfig", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "startsTime", + "columnName": "startsTime", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "endsDate", + "columnName": "endsDate", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "endsAfterCount", + "columnName": "endsAfterCount", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "runCount", + "columnName": "runCount", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "getOnlyNewUploads", + "columnName": "getOnlyNewUploads", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "retryMissingDownloads", + "columnName": "retryMissingDownloads", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "ignoredLinks", + "columnName": "ignoredLinks", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "'[]'" + }, + { + "fieldPath": "alreadyProcessedLinks", + "columnName": "alreadyProcessedLinks", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "syncWithSource", + "columnName": "syncWithSource", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '0e5e77e8657b2b151e63613f8d6f8110')" + ] + } +} \ No newline at end of file diff --git a/app/schemas/com.deniscerri.ytdl.database.DBManager/19.json b/app/schemas/com.deniscerri.ytdl.database.DBManager/19.json new file mode 100644 index 00000000..8aeb1d08 --- /dev/null +++ b/app/schemas/com.deniscerri.ytdl.database.DBManager/19.json @@ -0,0 +1,739 @@ +{ + "formatVersion": 1, + "database": { + "version": 19, + "identityHash": "348500cc087b2ef2e8f43470db15069e", + "entities": [ + { + "tableName": "results", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `title` TEXT NOT NULL, `author` TEXT NOT NULL, `duration` TEXT NOT NULL, `thumb` TEXT NOT NULL, `website` TEXT NOT NULL, `playlistTitle` TEXT NOT NULL, `formats` TEXT NOT NULL, `urls` TEXT NOT NULL DEFAULT '', `chapters` TEXT, `playlistURL` TEXT DEFAULT '', `playlistIndex` INTEGER, `creationTime` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "author", + "columnName": "author", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "duration", + "columnName": "duration", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "thumb", + "columnName": "thumb", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "website", + "columnName": "website", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "playlistTitle", + "columnName": "playlistTitle", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "formats", + "columnName": "formats", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "urls", + "columnName": "urls", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "chapters", + "columnName": "chapters", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "playlistURL", + "columnName": "playlistURL", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "''" + }, + { + "fieldPath": "playlistIndex", + "columnName": "playlistIndex", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "creationTime", + "columnName": "creationTime", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "history", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `title` TEXT NOT NULL, `author` TEXT NOT NULL, `duration` TEXT NOT NULL, `thumb` TEXT NOT NULL, `type` TEXT NOT NULL, `time` INTEGER NOT NULL, `downloadPath` TEXT NOT NULL, `website` TEXT NOT NULL, `format` TEXT NOT NULL, `downloadId` INTEGER NOT NULL DEFAULT 0, `command` TEXT NOT NULL DEFAULT '')", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "author", + "columnName": "author", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "duration", + "columnName": "duration", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "thumb", + "columnName": "thumb", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "time", + "columnName": "time", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "downloadPath", + "columnName": "downloadPath", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "website", + "columnName": "website", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "format", + "columnName": "format", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "downloadId", + "columnName": "downloadId", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "command", + "columnName": "command", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "downloads", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `title` TEXT NOT NULL, `author` TEXT NOT NULL, `thumb` TEXT NOT NULL, `duration` TEXT NOT NULL, `type` TEXT NOT NULL, `format` TEXT NOT NULL, `container` TEXT NOT NULL DEFAULT 'Default', `downloadSections` TEXT NOT NULL DEFAULT '', `allFormats` TEXT NOT NULL, `downloadPath` TEXT NOT NULL, `website` TEXT NOT NULL, `downloadSize` TEXT NOT NULL, `playlistTitle` TEXT NOT NULL, `audioPreferences` TEXT NOT NULL, `videoPreferences` TEXT NOT NULL, `extraCommands` TEXT NOT NULL DEFAULT '', `customFileNameTemplate` TEXT NOT NULL, `SaveThumb` INTEGER NOT NULL, `status` TEXT NOT NULL DEFAULT 'Queued', `downloadStartTime` INTEGER NOT NULL DEFAULT 0, `logID` INTEGER, `playlistURL` TEXT DEFAULT '', `playlistIndex` INTEGER, `incognito` INTEGER NOT NULL DEFAULT 0)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "author", + "columnName": "author", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "thumb", + "columnName": "thumb", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "duration", + "columnName": "duration", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "format", + "columnName": "format", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "container", + "columnName": "container", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "'Default'" + }, + { + "fieldPath": "downloadSections", + "columnName": "downloadSections", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "allFormats", + "columnName": "allFormats", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "downloadPath", + "columnName": "downloadPath", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "website", + "columnName": "website", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "downloadSize", + "columnName": "downloadSize", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "playlistTitle", + "columnName": "playlistTitle", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "audioPreferences", + "columnName": "audioPreferences", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "videoPreferences", + "columnName": "videoPreferences", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "extraCommands", + "columnName": "extraCommands", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "''" + }, + { + "fieldPath": "customFileNameTemplate", + "columnName": "customFileNameTemplate", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "SaveThumb", + "columnName": "SaveThumb", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "'Queued'" + }, + { + "fieldPath": "downloadStartTime", + "columnName": "downloadStartTime", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "logID", + "columnName": "logID", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "playlistURL", + "columnName": "playlistURL", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "''" + }, + { + "fieldPath": "playlistIndex", + "columnName": "playlistIndex", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "incognito", + "columnName": "incognito", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "commandTemplates", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `useAsExtraCommand` INTEGER NOT NULL DEFAULT 0, `useAsExtraCommandAudio` INTEGER NOT NULL DEFAULT 1, `useAsExtraCommandVideo` INTEGER NOT NULL DEFAULT 1)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "useAsExtraCommand", + "columnName": "useAsExtraCommand", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "useAsExtraCommandAudio", + "columnName": "useAsExtraCommandAudio", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "1" + }, + { + "fieldPath": "useAsExtraCommandVideo", + "columnName": "useAsExtraCommandVideo", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "1" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "searchHistory", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `query` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "query", + "columnName": "query", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "templateShortcuts", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `content` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "cookies", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `content` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "logs", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT NOT NULL, `content` TEXT NOT NULL, `format` TEXT NOT NULL, `downloadType` TEXT NOT NULL, `downloadTime` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "format", + "columnName": "format", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "downloadType", + "columnName": "downloadType", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "downloadTime", + "columnName": "downloadTime", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "terminalDownloads", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `command` TEXT NOT NULL, `log` TEXT DEFAULT '')", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "command", + "columnName": "command", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "log", + "columnName": "log", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "''" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "sources", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `url` TEXT NOT NULL, `downloadItemTemplate` TEXT NOT NULL, `everyNr` INTEGER NOT NULL, `everyCategory` TEXT NOT NULL, `everyTime` INTEGER NOT NULL, `weeklyConfig` TEXT, `monthlyConfig` TEXT, `status` TEXT NOT NULL, `startsTime` INTEGER NOT NULL, `endsDate` INTEGER NOT NULL DEFAULT 0, `endsAfterCount` INTEGER NOT NULL DEFAULT 0, `runCount` INTEGER NOT NULL DEFAULT 0, `getOnlyNewUploads` INTEGER NOT NULL DEFAULT 0, `retryMissingDownloads` INTEGER NOT NULL, `ignoredLinks` TEXT NOT NULL DEFAULT '[]', `alreadyProcessedLinks` TEXT NOT NULL, `syncWithSource` INTEGER NOT NULL DEFAULT 0)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "downloadItemTemplate", + "columnName": "downloadItemTemplate", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "everyNr", + "columnName": "everyNr", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "everyCategory", + "columnName": "everyCategory", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "everyTime", + "columnName": "everyTime", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "weeklyConfig", + "columnName": "weeklyConfig", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "monthlyConfig", + "columnName": "monthlyConfig", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "status", + "columnName": "status", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "startsTime", + "columnName": "startsTime", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "endsDate", + "columnName": "endsDate", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "endsAfterCount", + "columnName": "endsAfterCount", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "runCount", + "columnName": "runCount", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "getOnlyNewUploads", + "columnName": "getOnlyNewUploads", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "retryMissingDownloads", + "columnName": "retryMissingDownloads", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "ignoredLinks", + "columnName": "ignoredLinks", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "'[]'" + }, + { + "fieldPath": "alreadyProcessedLinks", + "columnName": "alreadyProcessedLinks", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "syncWithSource", + "columnName": "syncWithSource", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '348500cc087b2ef2e8f43470db15069e')" + ] + } +} \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdl/MainActivity.kt b/app/src/main/java/com/deniscerri/ytdl/MainActivity.kt index 851e43d4..d9ca49a9 100644 --- a/app/src/main/java/com/deniscerri/ytdl/MainActivity.kt +++ b/app/src/main/java/com/deniscerri/ytdl/MainActivity.kt @@ -42,9 +42,13 @@ import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel import com.deniscerri.ytdl.database.viewmodel.ResultViewModel import com.deniscerri.ytdl.ui.BaseActivity import com.deniscerri.ytdl.ui.HomeFragment +import com.deniscerri.ytdl.ui.downloads.DownloadQueueMainFragment +import com.deniscerri.ytdl.ui.downloads.HistoryFragment import com.deniscerri.ytdl.ui.more.settings.SettingsActivity import com.deniscerri.ytdl.util.CrashListener import com.deniscerri.ytdl.util.FileUtil +import com.deniscerri.ytdl.util.NavbarUtil +import com.deniscerri.ytdl.util.NavbarUtil.applyNavBarStyle import com.deniscerri.ytdl.util.ThemeUtil import com.deniscerri.ytdl.util.UpdateUtil import com.google.android.material.bottomnavigation.BottomNavigationView @@ -125,26 +129,39 @@ class MainActivity : BaseActivity() { } } - if (savedInstanceState == null){ - val graph = navController.navInflater.inflate(R.navigation.nav_graph) - graph.setStartDestination(R.id.homeFragment) - when(preferences.getString("start_destination", "")) { - "History" -> graph.setStartDestination(R.id.historyFragment) - "More" -> if (navigationView is NavigationBarView) graph.setStartDestination(R.id.moreFragment) - } - - navController.graph = graph - } + NavbarUtil.init(this) if (navigationView is NavigationBarView){ + if (savedInstanceState == null){ + val graph = navController.navInflater.inflate(R.navigation.nav_graph) + graph.setStartDestination(NavbarUtil.getStartFragmentId(this)) + navController.graph = graph + } + (navigationView as NavigationBarView).applyNavBarStyle() + + val showingDownloadQueue = NavbarUtil.getNavBarItems(this).any { n -> n.itemId == R.id.downloadQueueMainFragment && n.isVisible } + (navigationView as NavigationBarView).setupWithNavController(navController) (navigationView as NavigationBarView).setOnItemReselectedListener { when (it.itemId) { R.id.homeFragment -> { - (navHostFragment.childFragmentManager.primaryNavigationFragment!! as HomeFragment).scrollToTop() + kotlin.runCatching { + (navHostFragment.childFragmentManager.primaryNavigationFragment!! as HomeFragment).scrollToTop() + } } R.id.historyFragment -> { - navController.navigate(R.id.downloadQueueMainFragment) + if(!showingDownloadQueue) { + navController.navigate(R.id.downloadQueueMainFragment) + }else{ + kotlin.runCatching { + (navHostFragment.childFragmentManager.primaryNavigationFragment!! as HistoryFragment).scrollToTop() + } + } + } + R.id.downloadQueueMainFragment -> { + kotlin.runCatching { + (navHostFragment.childFragmentManager.primaryNavigationFragment!! as DownloadQueueMainFragment).scrollToActive() + } } R.id.moreFragment -> { val intent = Intent(context, SettingsActivity::class.java) @@ -153,7 +170,11 @@ class MainActivity : BaseActivity() { } } - val activeDownloadsBadge = (navigationView as NavigationBarView).getOrCreateBadge(R.id.historyFragment) + val activeDownloadsBadge = if (showingDownloadQueue) { + (navigationView as NavigationBarView).getOrCreateBadge(R.id.downloadQueueMainFragment) + }else{ + (navigationView as NavigationBarView).getOrCreateBadge(R.id.historyFragment) + } lifecycleScope.launch { downloadViewModel.activeDownloadsCount.collectLatest { if (it == 0) { @@ -220,12 +241,14 @@ class MainActivity : BaseActivity() { (navigationView as NavigationView).getHeaderView(0).findViewById(R.id.title).text = ThemeUtil.getStyledAppName(this) } + val showingNavbarItems = NavbarUtil.getNavBarItems(this).filter { it.isVisible }.map { it.itemId } navController.addOnDestinationChangedListener { _, destination, _ -> Handler(Looper.getMainLooper()).post { if (navigationView is NavigationBarView){ - when(destination.id){ - R.id.homeFragment, R.id.historyFragment, R.id.moreFragment -> showBottomNavigation() - else -> hideBottomNavigation() + if (showingNavbarItems.contains(destination.id)) { + showBottomNavigation() + }else{ + hideBottomNavigation() } } } diff --git a/app/src/main/java/com/deniscerri/ytdl/database/DBManager.kt b/app/src/main/java/com/deniscerri/ytdl/database/DBManager.kt index 4ebb5b85..53273d66 100644 --- a/app/src/main/java/com/deniscerri/ytdl/database/DBManager.kt +++ b/app/src/main/java/com/deniscerri/ytdl/database/DBManager.kt @@ -41,7 +41,7 @@ import com.deniscerri.ytdl.database.models.TerminalItem TerminalItem::class, ObserveSourcesItem::class ], - version = 17, + version = 19, autoMigrations = [ AutoMigration (from = 1, to = 2), AutoMigration (from = 2, to = 3), @@ -58,7 +58,9 @@ import com.deniscerri.ytdl.database.models.TerminalItem // AutoMigration (from = 13, to = 14) MANUALLY HANDLED AutoMigration (from = 14, to = 15), AutoMigration (from = 15, to = 16, spec = Migrations.resetObserveSources::class), - AutoMigration (from = 16, to = 17) + AutoMigration (from = 16, to = 17), + AutoMigration (from = 17, to = 18), + AutoMigration (from = 18, to = 19), ] ) abstract class DBManager : RoomDatabase(){ diff --git a/app/src/main/java/com/deniscerri/ytdl/database/Migrations.kt b/app/src/main/java/com/deniscerri/ytdl/database/Migrations.kt index caf17595..cf702ef6 100644 --- a/app/src/main/java/com/deniscerri/ytdl/database/Migrations.kt +++ b/app/src/main/java/com/deniscerri/ytdl/database/Migrations.kt @@ -23,7 +23,11 @@ object Migrations { } database.execSQL("CREATE TABLE IF NOT EXISTS `observeSources` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `url` TEXT NOT NULL, `downloadItemTemplate` TEXT NOT NULL, `status` TEXT NOT NULL, `everyNr` INTEGER NOT NULL, `everyCategory` TEXT NOT NULL, `everyWeekDay` TEXT NOT NULL, `everyMonthDay` INTEGER NOT NULL, `everyTime` INTEGER NOT NULL, `startsTime` INTEGER NOT NULL, `startsMonth` TEXT NOT NULL, `endsDate` INTEGER NOT NULL DEFAULT 0, `endsAfterCount` INTEGER NOT NULL DEFAULT 0, `runCount` INTEGER NOT NULL DEFAULT 0, `retryMissingDownloads` INTEGER NOT NULL, `alreadyProcessedLinks` TEXT NOT NULL)") - } + }, + +// Migration(17, 18 ){ database -> +// database.execSQL("ALTER TABLE `sources` ADD COLUMN `syncWithSource` INTEGER NOT NULL DEFAULT 0") +// } ) @DeleteTable.Entries( @@ -39,5 +43,4 @@ object Migrations { } - } \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdl/database/dao/CommandTemplateDao.kt b/app/src/main/java/com/deniscerri/ytdl/database/dao/CommandTemplateDao.kt index 81b77dde..39393434 100644 --- a/app/src/main/java/com/deniscerri/ytdl/database/dao/CommandTemplateDao.kt +++ b/app/src/main/java/com/deniscerri/ytdl/database/dao/CommandTemplateDao.kt @@ -83,6 +83,9 @@ interface CommandTemplateDao { @Query("DELETE FROM templateShortcuts WHERE id=:itemId") suspend fun deleteShortcut(itemId: Long) + @Query("DELETE FROM templateShortcuts") + suspend fun deleteAllShortcuts() + @Update suspend fun update(item: CommandTemplate) } \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdl/database/dao/DownloadDao.kt b/app/src/main/java/com/deniscerri/ytdl/database/dao/DownloadDao.kt index 37ec6984..7590968a 100644 --- a/app/src/main/java/com/deniscerri/ytdl/database/dao/DownloadDao.kt +++ b/app/src/main/java/com/deniscerri/ytdl/database/dao/DownloadDao.kt @@ -50,8 +50,6 @@ interface DownloadDao { @Query("SELECT * FROM downloads WHERE status = 'Processing' ORDER BY id LIMIT 1") fun getFirstProcessingDownload() : DownloadItem - @Query("SELECT * FROM downloads WHERE status='Active'") - fun getActiveAndPausedDownloadsList() : List @Query("SELECT * FROM downloads WHERE status = 'Processing'") fun getProcessingDownloadsList() : List @@ -63,12 +61,12 @@ interface DownloadDao { suspend fun updateProcessingDownloadPath(path: String) @Query("SELECT * FROM downloads WHERE status='Active'") - suspend fun getActiveDownloadsList() : List + fun getActiveDownloadsList() : List @Query("SELECT * FROM downloads WHERE status in('Active','Queued', 'Scheduled')") fun getActiveAndQueuedDownloadsList() : List - @Query("UPDATE downloads SET status='Queued' where status in ('Active', 'QueuedPaused', 'ActivePaused')") - suspend fun resetActivePausedItems() + @Query("UPDATE downloads SET status='Queued' where status = 'Active'") + suspend fun resetActiveToQueued() @Query("SELECT id FROM downloads WHERE status in('Active','Queued')") fun getActiveAndQueuedDownloadIDs() : List @@ -102,8 +100,6 @@ interface DownloadDao { @Query("SELECT * FROM downloads WHERE status='Cancelled' ORDER BY id DESC") fun getCancelledDownloadsList() : List - @Query("SELECT * FROM downloads WHERE status LIKE '%Paused%'") - fun getPausedDownloadsList() : List @RewriteQueriesToDropUnusedColumns @Query("SELECT * FROM downloads WHERE status='Error' ORDER BY id DESC") fun getErroredDownloads() : PagingSource @@ -159,6 +155,9 @@ interface DownloadDao { @Query("DELETE FROM downloads WHERE status='Error'") suspend fun deleteErrored() + @Query("DELETE FROM downloads WHERE status='Queued'") + suspend fun deleteQueued() + @Query("DELETE FROM downloads WHERE status='Saved'") suspend fun deleteSaved() @@ -269,10 +268,16 @@ interface DownloadDao { @Query("Update downloads set id=:newId where id=:id") suspend fun updateDownloadID(id: Long, newId: Long) - @Query("SELECT id from downloads WHERE id > :item1 AND id < :item2 AND status in (:statuses) ORDER BY id DESC") fun getIDsBetweenTwoItems(item1: Long, item2: Long, statuses: List) : List @Query("SELECT id from downloads WHERE id > :item1 AND id < :item2 AND status in('Scheduled') ORDER BY downloadStartTime, id") fun getScheduledIDsBetweenTwoItems(item1: Long, item2: Long) : List + + + @Query("UPDATE downloads set incognito=:incognito WHERE status='Processing'") + suspend fun updateProcessingIncognito(incognito: Boolean) + + @Query("SELECT COUNT(id) FROM downloads WHERE status='Processing' AND incognito='1'") + fun getProcessingAsIncognitoCount(): Int } \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdl/database/models/DownloadItem.kt b/app/src/main/java/com/deniscerri/ytdl/database/models/DownloadItem.kt index 30f393e1..20615019 100644 --- a/app/src/main/java/com/deniscerri/ytdl/database/models/DownloadItem.kt +++ b/app/src/main/java/com/deniscerri/ytdl/database/models/DownloadItem.kt @@ -42,5 +42,7 @@ data class DownloadItem( @ColumnInfo(defaultValue = "") var playlistURL: String? = "", @ColumnInfo(defaultValue = "") - var playlistIndex: Int? = null + var playlistIndex: Int? = null, + @ColumnInfo(defaultValue = "0") + var incognito: Boolean = false ) : Parcelable \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdl/database/models/DownloadItemSimple.kt b/app/src/main/java/com/deniscerri/ytdl/database/models/DownloadItemSimple.kt index 1eecf203..ad1989c1 100644 --- a/app/src/main/java/com/deniscerri/ytdl/database/models/DownloadItemSimple.kt +++ b/app/src/main/java/com/deniscerri/ytdl/database/models/DownloadItemSimple.kt @@ -22,4 +22,5 @@ data class DownloadItemSimple( var type: DownloadViewModel.Type, @ColumnInfo(defaultValue = "0") var downloadStartTime: Long, + var incognito: Boolean = false ) \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdl/database/models/RestoreAppDataItem.kt b/app/src/main/java/com/deniscerri/ytdl/database/models/RestoreAppDataItem.kt new file mode 100644 index 00000000..f9272049 --- /dev/null +++ b/app/src/main/java/com/deniscerri/ytdl/database/models/RestoreAppDataItem.kt @@ -0,0 +1,19 @@ +package com.deniscerri.ytdl.database.models + +import com.deniscerri.ytdl.database.models.observeSources.ObserveSourcesItem +import com.google.gson.JsonArray + +data class RestoreAppDataItem( + var settings : JsonArray? = null, + var downloads: List? = null, + var queued: List? = null, + var scheduled: List? = null, + var cancelled: List? = null, + var errored: List? = null, + var saved: List? = null, + var cookies: List? = null, + var templates: List? = null, + var shortcuts: List? = null, + var searchHistory: List? = null, + var observeSources: List? = null, +) \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdl/database/models/observeSources/ObserveSourcesItem.kt b/app/src/main/java/com/deniscerri/ytdl/database/models/observeSources/ObserveSourcesItem.kt index 0ba6f44e..e6e3aec1 100644 --- a/app/src/main/java/com/deniscerri/ytdl/database/models/observeSources/ObserveSourcesItem.kt +++ b/app/src/main/java/com/deniscerri/ytdl/database/models/observeSources/ObserveSourcesItem.kt @@ -37,5 +37,7 @@ data class ObserveSourcesItem( var retryMissingDownloads: Boolean, @ColumnInfo(defaultValue = "[]") var ignoredLinks: MutableList, - var alreadyProcessedLinks : MutableList + var alreadyProcessedLinks : MutableList, + @ColumnInfo(defaultValue = "0") + var syncWithSource: Boolean ) : Parcelable diff --git a/app/src/main/java/com/deniscerri/ytdl/database/repository/CommandTemplateRepository.kt b/app/src/main/java/com/deniscerri/ytdl/database/repository/CommandTemplateRepository.kt index 06b28cd1..b067272c 100644 --- a/app/src/main/java/com/deniscerri/ytdl/database/repository/CommandTemplateRepository.kt +++ b/app/src/main/java/com/deniscerri/ytdl/database/repository/CommandTemplateRepository.kt @@ -60,6 +60,10 @@ class CommandTemplateRepository(private val commandDao: CommandTemplateDao) { commandDao.deleteShortcut(item.id) } + suspend fun deleteAllShortcuts() { + commandDao.deleteAllShortcuts() + } + suspend fun deleteAll(){ commandDao.deleteAll() } diff --git a/app/src/main/java/com/deniscerri/ytdl/database/repository/DownloadRepository.kt b/app/src/main/java/com/deniscerri/ytdl/database/repository/DownloadRepository.kt index 2b73b38e..1aee5834 100644 --- a/app/src/main/java/com/deniscerri/ytdl/database/repository/DownloadRepository.kt +++ b/app/src/main/java/com/deniscerri/ytdl/database/repository/DownloadRepository.kt @@ -73,7 +73,7 @@ class DownloadRepository(private val downloadDao: DownloadDao) { val scheduledDownloadsCount : Flow = downloadDao.getDownloadsCountByStatusFlow(listOf(Status.Scheduled).toListString()) enum class Status { - Active, ActivePaused, Queued, Error, Cancelled, Saved, Processing, Scheduled + Active, Queued, Error, Cancelled, Saved, Processing, Scheduled } suspend fun insert(item: DownloadItem) : Long { @@ -118,12 +118,8 @@ class DownloadRepository(private val downloadDao: DownloadDao) { return downloadDao.getDownloadsByIds(ids) } - fun getAllItemsByIDsFlow(ids: List) : Flow> { - return downloadDao.getDownloadsByIdsFlow(ids) - } - fun getActiveDownloads() : List { - return downloadDao.getActiveAndPausedDownloadsList() + return downloadDao.getActiveDownloadsList() } fun getProcessingDownloads() : List { @@ -154,10 +150,6 @@ class DownloadRepository(private val downloadDao: DownloadDao) { return downloadDao.getCancelledDownloadsList() } - fun getPausedDownloads() : List { - return downloadDao.getPausedDownloadsList() - } - fun getErroredDownloads() : List { return downloadDao.getErroredDownloadsList() } @@ -182,6 +174,10 @@ class DownloadRepository(private val downloadDao: DownloadDao) { deleteCache(errored) } + suspend fun deleteQueued() { + downloadDao.deleteQueued() + } + suspend fun deleteSaved(){ downloadDao.deleteSaved() } @@ -238,7 +234,7 @@ class DownloadRepository(private val downloadDao: DownloadDao) { val workConstraints = Constraints.Builder() if (!allowMeteredNetworks) workConstraints.setRequiredNetworkType(NetworkType.UNMETERED) else { - workConstraints.setRequiredNetworkType(NetworkType.CONNECTED) + //workConstraints.setRequiredNetworkType(NetworkType.CONNECTED) } val workRequest = OneTimeWorkRequestBuilder() @@ -268,12 +264,14 @@ class DownloadRepository(private val downloadDao: DownloadDao) { }, 0) } - val first = queuedItems.first() - if (first.downloadStartTime > 0L) { - val date = SimpleDateFormat(DateFormat.getBestDateTimePattern(Locale.getDefault(), "ddMMMyyyy - HHmm"), Locale.getDefault()).format(queuedItems.first().downloadStartTime) - handler.postDelayed({ - Toast.makeText(context, context.getString(R.string.download_rescheduled_to) + " " + date, Toast.LENGTH_LONG).show() - }, 0) + if (queuedItems.isNotEmpty()) { + val first = queuedItems.first() + if (first.downloadStartTime > 0L) { + val date = SimpleDateFormat(DateFormat.getBestDateTimePattern(Locale.getDefault(), "ddMMMyyyy - HHmm"), Locale.getDefault()).format(queuedItems.first().downloadStartTime) + handler.postDelayed({ + Toast.makeText(context, context.getString(R.string.download_rescheduled_to) + " " + date, Toast.LENGTH_LONG).show() + }, 0) + } } } diff --git a/app/src/main/java/com/deniscerri/ytdl/database/repository/ResultRepository.kt b/app/src/main/java/com/deniscerri/ytdl/database/repository/ResultRepository.kt index a28bc12e..1b9d4332 100644 --- a/app/src/main/java/com/deniscerri/ytdl/database/repository/ResultRepository.kt +++ b/app/src/main/java/com/deniscerri/ytdl/database/repository/ResultRepository.kt @@ -12,6 +12,7 @@ import java.util.regex.Pattern class ResultRepository(private val resultDao: ResultDao, private val context: Context) { private val tag: String = "ResultRepository" + val YTDLNIS_SEARCH = "YTDLNIS_SEARCH" val allResults : Flow> = resultDao.getResults() var itemCount = MutableStateFlow(-1) @@ -56,7 +57,7 @@ class ResultRepository(private val resultDao: ResultDao, private val context: Co deleteAll() itemCount.value = v.size }else{ - v.filter { it.playlistTitle.isBlank() }.forEach { it.playlistTitle = "ytdlnis-Search" } + v.filter { it.playlistTitle.isBlank() }.forEach { it.playlistTitle = YTDLNIS_SEARCH } } if (addToResults){ val ids = resultDao.insertMultiple(v) @@ -99,7 +100,7 @@ class ResultRepository(private val resultDao: ResultDao, private val context: Co deleteAll() itemCount.value = items.size }else{ - items.filter { it.playlistTitle.isNullOrBlank() }.forEach { it.playlistTitle = "ytdlnis-Search" } + items.filter { it.playlistTitle.isBlank() }.forEach { it.playlistTitle = YTDLNIS_SEARCH } } if (addToResults){ @@ -182,7 +183,7 @@ class ResultRepository(private val resultDao: ResultDao, private val context: Co val info = getResultsFromSource(downloadItem.url, resetResults = false, addToResults = false, singleItem = true).first() if (downloadItem.title.isEmpty()) downloadItem.title = info.title if (downloadItem.author.isEmpty()) downloadItem.author = info.author - if (downloadItem.playlistTitle.isEmpty() && downloadItem.playlistTitle != "ytdlnis-Search") downloadItem.playlistTitle = info.playlistTitle + if (downloadItem.playlistTitle.isNotBlank() && downloadItem.playlistTitle != YTDLNIS_SEARCH) downloadItem.playlistTitle = info.playlistTitle downloadItem.duration = info.duration downloadItem.website = info.website if (downloadItem.thumb.isEmpty()) downloadItem.thumb = info.thumb diff --git a/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/CommandTemplateViewModel.kt b/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/CommandTemplateViewModel.kt index 7f43d50b..6acf3caf 100644 --- a/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/CommandTemplateViewModel.kt +++ b/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/CommandTemplateViewModel.kt @@ -111,6 +111,10 @@ class CommandTemplateViewModel(private val application: Application) : AndroidVi repository.deleteShortcut(item) } + fun deleteAllShortcuts() = viewModelScope.launch(Dispatchers.IO) { + repository.deleteAllShortcuts() + } + fun deleteAll() = viewModelScope.launch(Dispatchers.IO) { repository.deleteAll() } diff --git a/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/DownloadViewModel.kt b/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/DownloadViewModel.kt index 9d1882e6..a6970203 100644 --- a/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/DownloadViewModel.kt +++ b/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/DownloadViewModel.kt @@ -76,21 +76,9 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel val alreadyExistsUiState: MutableStateFlow> - private var bestVideoFormat : Format - private var bestAudioFormat : Format - private var defaultVideoFormats : MutableList - - private val videoQualityPreference: String - private val formatIDPreference: List - private val audioFormatIDPreference: List - private val resources : Resources private var extraCommandsForAudio: String = "" private var extraCommandsForVideo: String = "" - private var audioContainer: String? - private var videoContainer: String? - private var videoCodec: String? - private var audioCodec: String? private val dao: DownloadDao private val historyRepository: HistoryRepository private val resultRepository: ResultRepository @@ -137,37 +125,6 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel } } - videoQualityPreference = sharedPreferences.getString("video_quality", application.getString(R.string.best_quality)).toString() - formatIDPreference = sharedPreferences.getString("format_id", "").toString().split(",").filter { it.isNotEmpty() } - audioFormatIDPreference = sharedPreferences.getString("format_id_audio", "").toString().split(",").filter { it.isNotEmpty() } - - val confTmp = Configuration(application.resources.configuration) - confTmp.setLocale(Locale(sharedPreferences.getString("app_language", "en")!!)) - val metrics = DisplayMetrics() - resources = Resources(application.assets, metrics, confTmp) - - - videoContainer = sharedPreferences.getString("video_format", "Default") - defaultVideoFormats = infoUtil.getGenericVideoFormats(resources) - bestVideoFormat = defaultVideoFormats.first() - - audioContainer = sharedPreferences.getString("audio_format", "mp3") - bestAudioFormat = if (audioFormatIDPreference.isEmpty()){ - infoUtil.getGenericAudioFormats(resources).first() - }else{ - Format( - audioFormatIDPreference.first().split("+").first(), - audioContainer!!, - "", - "", - "", - 0, - audioFormatIDPreference.first().split("+").first() - ) - } - - videoCodec = sharedPreferences.getString("video_codec", "") - audioCodec = sharedPreferences.getString("audio_codec", "") } fun deleteDownload(id: Long) = viewModelScope.launch(Dispatchers.IO) { @@ -325,14 +282,26 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel container, "", ArrayList(), - path, historyItem.website, "", "", audioPreferences, videoPreferences, extraCommands, customFileNameTemplate!!, saveThumb, DownloadRepository.Status.Queued.toString(), 0, null + path, + historyItem.website, + "", + "", + audioPreferences, + videoPreferences, + extraCommands, + customFileNameTemplate!!, + saveThumb, + DownloadRepository.Status.Queued.toString(), + 0, + null, + incognito = sharedPreferences.getBoolean("incognito", false) ) } fun getPreferredAudioRequirements(): MutableList<(Format) -> Int> { - return sharedDownloadViewModel.getPreferredVideoRequirements() + return sharedDownloadViewModel.getPreferredAudioRequirements() } //requirement and importance @@ -371,7 +340,7 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel try { itemIDs.forEachIndexed { idx, it -> val item = repository.getItemByID(it) - if (!isActive) throw CancellationException() + if (processingItemsFlow?.job?.isCancelled == true) throw CancellationException() item.id = 0 item.status = DownloadRepository.Status.Processing.toString() @@ -383,11 +352,7 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel } processingItems.emit(false) } catch (e: Exception) { - processingItemsFlow?.apply { - this.processingDownloadItemIDs.chunked(100).forEach { - repository.deleteAllWithIDs(it) - } - } + deleteProcessing() updateProcessingJobData(null) processingItems.emit(false) } @@ -399,6 +364,7 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel fun turnResultItemsToProcessingDownloads(itemIDs: List, downloadNow: Boolean = false) = viewModelScope.launch(Dispatchers.IO) { updateProcessingJobData(ProcessingItemsJob(null, ResultItem::class.java.toString(), itemIDs)) val job = viewModelScope.launch(Dispatchers.IO) { + repository.deleteProcessing() processingItems.emit(true) try { itemIDs.forEach { id -> @@ -409,7 +375,7 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel )) downloadItem.status = DownloadRepository.Status.Processing.toString() - if (!isActive) { + if (processingItemsFlow?.job?.isCancelled == true) { throw CancellationException() } @@ -425,11 +391,7 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel } processingItems.emit(false) }catch (e: Exception) { - processingItemsFlow?.apply { - this.processingDownloadItemIDs.chunked(100).forEach { - repository.deleteAllWithIDs(it) - } - } + deleteProcessing() updateProcessingJobData(null) processingItems.emit(false) } @@ -472,6 +434,10 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel repository.deleteErrored() } + fun deleteQueued() = viewModelScope.launch(Dispatchers.IO) { + repository.deleteQueued() + } + fun deleteSaved() = viewModelScope.launch(Dispatchers.IO) { repository.deleteSaved() } @@ -513,7 +479,11 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel } fun getActiveDownloadsCount() : Int { - return dao.getDownloadsCountByStatus(listOf(DownloadRepository.Status.Active, DownloadRepository.Status.ActivePaused).toListString()) + return dao.getDownloadsCountByStatus(listOf(DownloadRepository.Status.Active).toListString()) + } + + fun getActiveQueuedDownloadsCount() : Int { + return dao.getDownloadsCountByStatus(listOf(DownloadRepository.Status.Active, DownloadRepository.Status.Queued).toListString()) } fun getQueuedDownloadsCount() : Int { @@ -529,8 +499,8 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel repository.startDownloadWorker(emptyList(), application) } - suspend fun resetActivePaused() { - dbManager.downloadDao.resetActivePausedItems() + suspend fun resetActiveToQueued() { + dbManager.downloadDao.resetActiveToQueued() } suspend fun startDownloadWorker(list: List){ @@ -751,5 +721,13 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel return dao.getScheduledIDsBetweenTwoItems(item1, item2) } + suspend fun updateProcessingIncognito(incognito: Boolean) { + dao.updateProcessingIncognito(incognito) + } + + fun areAllProcessingIncognito() : Boolean { + return dao.getProcessingAsIncognitoCount() > 0 + } + } \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/SharedDownloadViewModel.kt b/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/SharedDownloadViewModel.kt index 907ae073..37138c49 100644 --- a/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/SharedDownloadViewModel.kt +++ b/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/SharedDownloadViewModel.kt @@ -29,6 +29,7 @@ import com.deniscerri.ytdl.database.repository.ResultRepository import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel.Type import com.deniscerri.ytdl.util.Extensions.toListString import com.deniscerri.ytdl.util.FileUtil +import com.deniscerri.ytdl.util.FormatSorter import com.deniscerri.ytdl.util.InfoUtil import com.deniscerri.ytdl.work.AlarmScheduler import com.google.gson.Gson @@ -230,13 +231,18 @@ class SharedDownloadViewModel(private val context: Context) { resultItem.formats, downloadPath!!, resultItem.website, "", - resultItem.playlistTitle, + if (resultItem.playlistTitle == resultRepository.YTDLNIS_SEARCH) "" else resultItem.playlistTitle, audioPreferences, videoPreferences, extraCommands, customFileNameTemplate!!, saveThumb, - DownloadRepository.Status.Queued.toString(), 0, null, playlistURL = resultItem.playlistURL, playlistIndex = resultItem.playlistIndex + DownloadRepository.Status.Queued.toString(), + 0, + null, + playlistURL = resultItem.playlistURL, + playlistIndex = resultItem.playlistIndex, + incognito = sharedPreferences.getBoolean("incognito", false) ) } @@ -281,7 +287,7 @@ class SharedDownloadViewModel(private val context: Context) { } - private fun getPreferredAudioRequirements(): MutableList<(Format) -> Int> { + fun getPreferredAudioRequirements(): MutableList<(Format) -> Int> { val requirements: MutableList<(Format) -> Int> = mutableListOf() val itemValues = resources.getStringArray(R.array.format_importance_audio_values).toSet() @@ -345,9 +351,8 @@ class SharedDownloadViewModel(private val context: Context) { for(i in 0..preferenceIndex){ removeAt(0) } - requirements.add { it: Format -> if (it.format_note.contains(preference, ignoreCase = true)) importance else 0 } + add(0, preference) forEachIndexed { index, res -> - if (index >= 2) importance = 0 requirements.add { it: Format -> if (it.format_note.contains(res, ignoreCase = true)) (importance - index - 1) else 0 } } } @@ -381,8 +386,10 @@ class SharedDownloadViewModel(private val context: Context) { return cloneFormat ( try { val theFormats = formats.filter { it.vcodec.isBlank() || it.vcodec == "none" } - val requirements = getPreferredAudioRequirements() - theFormats.maxByOrNull { f -> requirements.sumOf{ req -> req(f)} } ?: throw Exception() + FormatSorter(context).sortAudioFormats(theFormats).first() +// +// val requirements = getPreferredAudioRequirements() +// theFormats.maxByOrNull { f -> requirements.sumOf{ req -> req(f)} } ?: throw Exception() }catch (e: Exception){ bestAudioFormat } @@ -395,24 +402,27 @@ class SharedDownloadViewModel(private val context: Context) { val theFormats = formats.filter { it.vcodec.isNotBlank() && it.vcodec != "none" }.ifEmpty { defaultVideoFormats.sortedByDescending { it.filesize } } - when (videoQualityPreference) { - "worst" -> { - theFormats.last() - } - else /*best*/ -> { - val requirements = getPreferredVideoRequirements() - theFormats.run { - if (sharedPreferences.getBoolean("prefer_smaller_formats", false)){ - sortedBy { it.filesize }.maxByOrNull { f -> requirements.sumOf { req -> req(f) } } ?: throw Exception() - }else{ - sortedByDescending { it.filesize }.maxByOrNull { f -> - val summ = requirements.sumOf { req -> req(f) } - summ - } ?: throw Exception() - } - } - } - } + + FormatSorter(context).sortVideoFormats(theFormats).first() +// +// when (videoQualityPreference) { +// "worst" -> { +// theFormats.last() +// } +// else /*best*/ -> { +// val requirements = getPreferredVideoRequirements() +// theFormats.run { +// if (sharedPreferences.getBoolean("prefer_smaller_formats", false)){ +// sortedBy { it.filesize }.maxByOrNull { f -> requirements.sumOf { req -> req(f) } } ?: throw Exception() +// }else{ +// sortedByDescending { it.filesize }.maxByOrNull { f -> +// val summ = requirements.sumOf { req -> req(f) } +// summ +// } ?: throw Exception() +// } +// } +// } +// } }catch (e: Exception){ bestVideoFormat } diff --git a/app/src/main/java/com/deniscerri/ytdl/receiver/PauseDownloadNotificationReceiver.kt b/app/src/main/java/com/deniscerri/ytdl/receiver/PauseDownloadNotificationReceiver.kt index f51239a5..3cf248e1 100644 --- a/app/src/main/java/com/deniscerri/ytdl/receiver/PauseDownloadNotificationReceiver.kt +++ b/app/src/main/java/com/deniscerri/ytdl/receiver/PauseDownloadNotificationReceiver.kt @@ -14,28 +14,28 @@ import kotlinx.coroutines.withContext class PauseDownloadNotificationReceiver : BroadcastReceiver() { override fun onReceive(c: Context, intent: Intent) { - val result = goAsync() - val id = intent.getIntExtra("itemID", 0) - if (id != 0) { - runCatching { - val title = intent.getStringExtra("title") - val notificationUtil = NotificationUtil(c) - notificationUtil.cancelDownloadNotification(id) - YoutubeDL.getInstance().destroyProcessById(id.toString()) - val dbManager = DBManager.getInstance(c) - CoroutineScope(Dispatchers.IO).launch{ - try { - val item = dbManager.downloadDao.getDownloadById(id.toLong()) - item.status = DownloadRepository.Status.ActivePaused.toString() - dbManager.downloadDao.update(item) - }finally { - withContext(Dispatchers.Main){ - notificationUtil.createResumeDownload(id, title) - result.finish() - } - } - } - } - } +// val result = goAsync() +// val id = intent.getIntExtra("itemID", 0) +// if (id != 0) { +// runCatching { +// val title = intent.getStringExtra("title") +// val notificationUtil = NotificationUtil(c) +// notificationUtil.cancelDownloadNotification(id) +// YoutubeDL.getInstance().destroyProcessById(id.toString()) +// val dbManager = DBManager.getInstance(c) +// CoroutineScope(Dispatchers.IO).launch{ +// try { +// val item = dbManager.downloadDao.getDownloadById(id.toLong()) +// item.status = DownloadRepository.Status.ActivePaused.toString() +// dbManager.downloadDao.update(item) +// }finally { +// withContext(Dispatchers.Main){ +// notificationUtil.createResumeDownload(id, title) +// result.finish() +// } +// } +// } +// } +// } } } \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/adapter/ActiveDownloadAdapter.kt b/app/src/main/java/com/deniscerri/ytdl/ui/adapter/ActiveDownloadAdapter.kt index 4c0791a1..effbbb5e 100644 --- a/app/src/main/java/com/deniscerri/ytdl/ui/adapter/ActiveDownloadAdapter.kt +++ b/app/src/main/java/com/deniscerri/ytdl/ui/adapter/ActiveDownloadAdapter.kt @@ -122,16 +122,24 @@ class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity: if (cancelButton.hasOnClickListeners()) cancelButton.setOnClickListener(null) cancelButton.setOnClickListener {onItemClickListener.onCancelClick(item.id)} - val activePaused = item.status == DownloadRepository.Status.ActivePaused.toString() - val resumeButton = card.findViewById(R.id.active_download_resume) - resumeButton.isVisible = activePaused - if (resumeButton.hasOnClickListeners()) resumeButton.setOnClickListener(null) - resumeButton.setOnClickListener { - resumeButton.isVisible = false - onItemClickListener.onResumeClick(item.id) - } +// val resumeButton = card.findViewById(R.id.active_download_resume) +// resumeButton.isEnabled = true +// if (resumeButton.hasOnClickListeners()) resumeButton.setOnClickListener(null) +// if (activePaused) { +// resumeButton.setIconResource(R.drawable.exomedia_ic_play_arrow_white) +// resumeButton.setOnClickListener { +// resumeButton.isEnabled = false +// onItemClickListener.onResumeClick(item.id) +// } +// }else { +// resumeButton.setIconResource(R.drawable.exomedia_ic_pause_white) +// resumeButton.setOnClickListener { +// resumeButton.isEnabled = false +// onItemClickListener.onPauseClick(item.id) +// } +// } - if (sharedPreferences.getBoolean("paused_downloads", false) || activePaused) { + if (sharedPreferences.getBoolean("paused_downloads", false)) { progressBar.isIndeterminate = false cancelButton.isEnabled = true output.text = activity.getString(R.string.exo_download_paused) @@ -142,7 +150,6 @@ class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity: } interface OnItemClickListener { fun onCancelClick(itemID: Long) - fun onResumeClick(itemID: Long) fun onOutputClick(item: DownloadItem) } diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/adapter/ActiveDownloadMinifiedAdapter.kt b/app/src/main/java/com/deniscerri/ytdl/ui/adapter/ActiveDownloadMinifiedAdapter.kt index a31362cd..540a7fc9 100644 --- a/app/src/main/java/com/deniscerri/ytdl/ui/adapter/ActiveDownloadMinifiedAdapter.kt +++ b/app/src/main/java/com/deniscerri/ytdl/ui/adapter/ActiveDownloadMinifiedAdapter.kt @@ -125,7 +125,7 @@ class ActiveDownloadMinifiedAdapter(onItemClickListener: OnItemClickListener, ac else fileSize.text = fileSizeReadable val menu = card.findViewById(R.id.options) - val paused = sharedPreferences.getBoolean("paused_downloads", false) || item.status == DownloadRepository.Status.ActivePaused.toString() + //val paused = sharedPreferences.getBoolean("paused_downloads", false) || item.status == DownloadRepository.Status.ActivePaused.toString() menu.setOnClickListener { val popup = PopupMenu(activity, it) popup.menuInflater.inflate(R.menu.active_downloads_minified, popup.menu) @@ -133,27 +133,27 @@ class ActiveDownloadMinifiedAdapter(onItemClickListener: OnItemClickListener, ac val pause = popup.menu[0] val resume = popup.menu[1] - - if (paused){ - pause.isVisible = false - resume.isVisible = true - }else{ - pause.isVisible = true - resume.isVisible = false - } +// +// if (paused){ +// pause.isVisible = false +// resume.isVisible = true +// }else{ +// pause.isVisible = true +// resume.isVisible = false +// } popup.setOnMenuItemClickListener { m -> when(m.itemId){ - R.id.pause -> { - onItemClickListener.onPauseClick(item.id, ActiveDownloadAdapter.ActiveDownloadAction.Pause, position) - if (progressBar.progress == 0) progressBar.isIndeterminate = false - popup.dismiss() - } - R.id.resume -> { - onItemClickListener.onPauseClick(item.id, ActiveDownloadAdapter.ActiveDownloadAction.Resume, position) - progressBar.isIndeterminate = true - popup.dismiss() - } +// R.id.pause -> { +// onItemClickListener.onPauseClick(item.id, ActiveDownloadAdapter.ActiveDownloadAction.Pause, position) +// if (progressBar.progress == 0) progressBar.isIndeterminate = false +// popup.dismiss() +// } +// R.id.resume -> { +// onItemClickListener.onPauseClick(item.id, ActiveDownloadAdapter.ActiveDownloadAction.Resume, position) +// progressBar.isIndeterminate = true +// popup.dismiss() +// } R.id.cancel -> { onItemClickListener.onCancelClick(item.id) popup.dismiss() @@ -166,7 +166,7 @@ class ActiveDownloadMinifiedAdapter(onItemClickListener: OnItemClickListener, ac } - progressBar.isIndeterminate = !paused + progressBar.isIndeterminate = !sharedPreferences.getBoolean("paused_downloads", false) card.setOnClickListener { onItemClickListener.onCardClick() @@ -174,7 +174,6 @@ class ActiveDownloadMinifiedAdapter(onItemClickListener: OnItemClickListener, ac } interface OnItemClickListener { fun onCancelClick(itemID: Long) - fun onPauseClick(itemID: Long, action: ActiveDownloadAdapter.ActiveDownloadAction, position: Int) fun onCardClick() } diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/adapter/ConfigureMultipleDownloadsAdapter.kt b/app/src/main/java/com/deniscerri/ytdl/ui/adapter/ConfigureMultipleDownloadsAdapter.kt index 2365b834..1fdfaa30 100644 --- a/app/src/main/java/com/deniscerri/ytdl/ui/adapter/ConfigureMultipleDownloadsAdapter.kt +++ b/app/src/main/java/com/deniscerri/ytdl/ui/adapter/ConfigureMultipleDownloadsAdapter.kt @@ -88,6 +88,10 @@ class ConfigureMultipleDownloadsAdapter(onItemClickListener: OnItemClickListener formatNote.visibility = View.GONE } + + val incognitoLabel = card.findViewById(R.id.incognitoLabel) + incognitoLabel.isVisible = item.incognito + val codec = card.findViewById(R.id.codec) val codecText = if (item.format.encoding != "") { @@ -160,7 +164,8 @@ class ConfigureMultipleDownloadsAdapter(onItemClickListener: OnItemClickListener return oldItem.title == newItem.title && oldItem.author == newItem.author && oldItem.type == newItem.type && - oldItem.format == newItem.format + oldItem.format == newItem.format && + oldItem.incognito == newItem.incognito } } } diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/adapter/GenericDownloadAdapter.kt b/app/src/main/java/com/deniscerri/ytdl/ui/adapter/GenericDownloadAdapter.kt index 62506d53..81ca0db0 100644 --- a/app/src/main/java/com/deniscerri/ytdl/ui/adapter/GenericDownloadAdapter.kt +++ b/app/src/main/java/com/deniscerri/ytdl/ui/adapter/GenericDownloadAdapter.kt @@ -96,6 +96,9 @@ class GenericDownloadAdapter(onItemClickListener: OnItemClickListener, activity: ) } + val incognitoLabel = card.findViewById(R.id.incognitoLabel) + incognitoLabel.isVisible = item.incognito + val formatNote = card.findViewById(R.id.format_note) if (item.format.format_note == "?" || item.format.format_note == "") formatNote!!.visibility = View.GONE diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/adapter/NavBarOptionsAdapter.kt b/app/src/main/java/com/deniscerri/ytdl/ui/adapter/NavBarOptionsAdapter.kt new file mode 100644 index 00000000..61603ff4 --- /dev/null +++ b/app/src/main/java/com/deniscerri/ytdl/ui/adapter/NavBarOptionsAdapter.kt @@ -0,0 +1,73 @@ +package com.deniscerri.ytdl.ui.adapter + +import android.view.LayoutInflater +import android.view.Menu +import android.view.MenuItem +import android.view.ViewGroup +import androidx.core.view.isVisible +import androidx.recyclerview.widget.RecyclerView +import com.deniscerri.ytdl.R +import com.deniscerri.ytdl.databinding.NavOptionsItemBinding + +class NavBarOptionsAdapter( + val items: MutableList, + var selectedHomeTabId: Int, + onItemClickListener: OnItemClickListener, +) : RecyclerView.Adapter() { + + private val onItemClickListener: OnItemClickListener + + init { + this.onItemClickListener = onItemClickListener + } + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NavBarOptionsViewHolder { + val binding = NavOptionsItemBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ) + return NavBarOptionsViewHolder(binding) + } + + override fun getItemCount() = items.size + + class NavBarOptionsViewHolder( + val binding: NavOptionsItemBinding + ) : RecyclerView.ViewHolder(binding.root) + + override fun onBindViewHolder(holder: NavBarOptionsViewHolder, position: Int) { + val item = items[position] + val essential = listOf(R.id.homeFragment, R.id.moreFragment) + val noHome = listOf(R.id.terminalActivity) + holder.binding.apply { + title.text = item.title + checkbox.isChecked = item.isVisible || essential.contains(item.itemId) + checkbox.isEnabled = !essential.contains(item.itemId) + home.setImageResource( + if (item.itemId == selectedHomeTabId) + R.drawable.baseline_home_filled_24 else R.drawable.ic_home_outlined + ) + home.isVisible = !noHome.contains(item.itemId) + home.setOnClickListener { + if (!checkbox.isChecked || selectedHomeTabId == item.itemId) { + return@setOnClickListener + } + val oldSelection = items.indexOfFirst { it.itemId == selectedHomeTabId } + selectedHomeTabId = item.itemId + listOf(position, oldSelection).forEach { + notifyItemChanged(it) + } + } + checkbox.setOnClickListener { + item.isVisible = checkbox.isChecked + if (!checkbox.isChecked){ + onItemClickListener.onNavBarOptionDeselected(this) + } + } + } + } + + interface OnItemClickListener { + fun onNavBarOptionDeselected(item: NavOptionsItemBinding) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/downloadcard/ConfigureDownloadBottomSheetDialog.kt b/app/src/main/java/com/deniscerri/ytdl/ui/downloadcard/ConfigureDownloadBottomSheetDialog.kt index 876caa38..b30101ab 100644 --- a/app/src/main/java/com/deniscerri/ytdl/ui/downloadcard/ConfigureDownloadBottomSheetDialog.kt +++ b/app/src/main/java/com/deniscerri/ytdl/ui/downloadcard/ConfigureDownloadBottomSheetDialog.kt @@ -21,11 +21,9 @@ import androidx.recyclerview.widget.RecyclerView import androidx.viewpager2.widget.ViewPager2 import com.deniscerri.ytdl.R import com.deniscerri.ytdl.database.models.DownloadItem -import com.deniscerri.ytdl.database.models.ResultItem import com.deniscerri.ytdl.database.viewmodel.CommandTemplateViewModel import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel.Type -import com.deniscerri.ytdl.database.viewmodel.ResultViewModel import com.deniscerri.ytdl.util.UiUtil import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialogFragment @@ -36,21 +34,19 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -class ConfigureDownloadBottomSheetDialog(private var result: ResultItem, private val currentDownloadItem: DownloadItem, private val listener: OnDownloadItemUpdateListener) : BottomSheetDialogFragment() { +class ConfigureDownloadBottomSheetDialog(private val currentDownloadItem: DownloadItem, private val listener: OnDownloadItemUpdateListener) : BottomSheetDialogFragment() { private lateinit var tabLayout: TabLayout private lateinit var viewPager2: ViewPager2 private lateinit var fragmentAdapter : DownloadFragmentAdapter private lateinit var downloadViewModel: DownloadViewModel - private lateinit var resultViewModel: ResultViewModel private lateinit var commandTemplateViewModel: CommandTemplateViewModel private lateinit var behavior: BottomSheetBehavior private lateinit var onDownloadItemUpdateListener: OnDownloadItemUpdateListener private lateinit var sharedPreferences : SharedPreferences - + private var incognito: Boolean = currentDownloadItem.incognito override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java] - resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java] commandTemplateViewModel = ViewModelProvider(requireActivity())[CommandTemplateViewModel::class.java] onDownloadItemUpdateListener = listener sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext()) @@ -100,7 +96,7 @@ class ConfigureDownloadBottomSheetDialog(private var result: ResultItem, private } //check if the item has formats and its audio-only - val isAudioOnly = result.formats.isNotEmpty() && result.formats.none { !it.format_note.contains("audio") } + val isAudioOnly = currentDownloadItem.allFormats.isNotEmpty() && currentDownloadItem.allFormats.none { !it.format_note.contains("audio") } if (isAudioOnly){ (tabLayout.getChildAt(0) as? ViewGroup)?.getChildAt(1)?.isClickable = true (tabLayout.getChildAt(0) as? ViewGroup)?.getChildAt(1)?.alpha = 0.3f @@ -111,7 +107,7 @@ class ConfigureDownloadBottomSheetDialog(private var result: ResultItem, private fragmentAdapter = DownloadFragmentAdapter( fragmentManager, lifecycle, - result, + null, currentDownloadItem ) viewPager2.adapter = fragmentAdapter @@ -194,24 +190,39 @@ class ConfigureDownloadBottomSheetDialog(private var result: ResultItem, private val ok = view.findViewById