history revamp paginated wip
This commit is contained in:
parent
0c00ab350d
commit
8ae2a4d8a3
24 changed files with 2249 additions and 322 deletions
753
app/schemas/com.deniscerri.ytdl.database.DBManager/20.json
Normal file
753
app/schemas/com.deniscerri.ytdl.database.DBManager/20.json
Normal file
|
|
@ -0,0 +1,753 @@
|
|||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 20,
|
||||
"identityHash": "3be2d00eeed0d077b84c352d10f6628f",
|
||||
"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, `filesize` INTEGER NOT NULL DEFAULT 0, `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": "filesize",
|
||||
"columnName": "filesize",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true,
|
||||
"defaultValue": "0"
|
||||
},
|
||||
{
|
||||
"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, `useAsExtraCommandDataFetching` INTEGER NOT NULL DEFAULT 0)",
|
||||
"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"
|
||||
},
|
||||
{
|
||||
"fieldPath": "useAsExtraCommandDataFetching",
|
||||
"columnName": "useAsExtraCommandDataFetching",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true,
|
||||
"defaultValue": "0"
|
||||
}
|
||||
],
|
||||
"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, '3be2d00eeed0d077b84c352d10f6628f')"
|
||||
]
|
||||
}
|
||||
}
|
||||
753
app/schemas/com.deniscerri.ytdl.database.DBManager/21.json
Normal file
753
app/schemas/com.deniscerri.ytdl.database.DBManager/21.json
Normal file
|
|
@ -0,0 +1,753 @@
|
|||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 21,
|
||||
"identityHash": "3be2d00eeed0d077b84c352d10f6628f",
|
||||
"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, `filesize` INTEGER NOT NULL DEFAULT 0, `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": "filesize",
|
||||
"columnName": "filesize",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true,
|
||||
"defaultValue": "0"
|
||||
},
|
||||
{
|
||||
"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, `useAsExtraCommandDataFetching` INTEGER NOT NULL DEFAULT 0)",
|
||||
"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"
|
||||
},
|
||||
{
|
||||
"fieldPath": "useAsExtraCommandDataFetching",
|
||||
"columnName": "useAsExtraCommandDataFetching",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true,
|
||||
"defaultValue": "0"
|
||||
}
|
||||
],
|
||||
"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, '3be2d00eeed0d077b84c352d10f6628f')"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -52,8 +52,6 @@ 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.Extensions.extractURL
|
||||
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
|
||||
|
|
@ -440,7 +438,7 @@ class MainActivity : BaseActivity() {
|
|||
textBuilder.append(c.toChar())
|
||||
}
|
||||
val bundle = Bundle()
|
||||
bundle.putString("url", textBuilder.toString().extractURL())
|
||||
bundle.putString("url", textBuilder.toString())
|
||||
navController.popBackStack(R.id.homeFragment, true)
|
||||
navController.navigate(
|
||||
R.id.homeFragment,
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ import com.deniscerri.ytdl.database.models.TerminalItem
|
|||
TerminalItem::class,
|
||||
ObserveSourcesItem::class
|
||||
],
|
||||
version = 19,
|
||||
version = 21,
|
||||
autoMigrations = [
|
||||
AutoMigration (from = 1, to = 2),
|
||||
AutoMigration (from = 2, to = 3),
|
||||
|
|
@ -61,6 +61,8 @@ import com.deniscerri.ytdl.database.models.TerminalItem
|
|||
AutoMigration (from = 16, to = 17),
|
||||
AutoMigration (from = 17, to = 18),
|
||||
AutoMigration (from = 18, to = 19),
|
||||
AutoMigration (from = 19, to = 20),
|
||||
//AutoMigration (from = 20, to = 21) MANUALLY HANDLED
|
||||
]
|
||||
)
|
||||
abstract class DBManager : RoomDatabase(){
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import androidx.room.DeleteTable
|
|||
import androidx.room.migration.AutoMigrationSpec
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import com.deniscerri.ytdl.database.models.Format
|
||||
import com.google.gson.Gson
|
||||
|
||||
|
||||
object Migrations {
|
||||
|
|
@ -28,6 +30,19 @@ object Migrations {
|
|||
// Migration(17, 18 ){ database ->
|
||||
// database.execSQL("ALTER TABLE `sources` ADD COLUMN `syncWithSource` INTEGER NOT NULL DEFAULT 0")
|
||||
// }
|
||||
|
||||
//add filesizes to history
|
||||
Migration(20, 21) { database ->
|
||||
val cursor = database.query("SELECT * FROM history")
|
||||
while(cursor.moveToNext()) {
|
||||
kotlin.runCatching {
|
||||
val id = cursor.getLong(cursor.getColumnIndex("id"))
|
||||
val format = cursor.getString(cursor.getColumnIndex("format"))
|
||||
val parsed = Gson().fromJson(format, Format::class.java)
|
||||
database.execSQL("UPDATE history SET filesize = ${parsed.filesize} WHERE id = $id")
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@DeleteTable.Entries(
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
package com.deniscerri.ytdl.database.dao
|
||||
|
||||
import androidx.paging.PagingSource
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import androidx.room.Update
|
||||
import com.deniscerri.ytdl.database.models.DownloadItem
|
||||
import com.deniscerri.ytdl.database.models.HistoryItem
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
|
|
@ -30,9 +32,44 @@ interface HistoryDao {
|
|||
fun getHistorySortedByAuthor(query : String, type : String, site : String, sort : String) : List<HistoryItem>
|
||||
|
||||
|
||||
|
||||
@Query("SELECT * FROM history WHERE (title LIKE '%'||:query||'%' OR author LIKE '%'||:query||'%') AND type LIKE '%'||:type||'%' AND website LIKE '%'||:site||'%' ORDER BY " +
|
||||
"CASE WHEN :sort = 'ASC' THEN id END ASC," +
|
||||
"CASE WHEN :sort = 'DESC' THEN id END DESC," +
|
||||
"CASE WHEN :sort = '' THEN id END DESC ")
|
||||
fun getHistorySortedByIDPaginated(query : String, type : String, site : String, sort : String) : PagingSource<Int, HistoryItem>
|
||||
|
||||
@Query("SELECT * FROM history WHERE (title LIKE '%'||:query||'%' OR author LIKE '%'||:query||'%') AND type LIKE '%'||:type||'%' AND website LIKE '%'||:site||'%' ORDER BY " +
|
||||
"CASE WHEN :sort = 'ASC' THEN title END ASC," +
|
||||
"CASE WHEN :sort = 'DESC' THEN title END DESC," +
|
||||
"CASE WHEN :sort = '' THEN title END DESC ")
|
||||
fun getHistorySortedByTitlePaginated(query : String, type : String, site : String, sort : String) : PagingSource<Int, HistoryItem>
|
||||
|
||||
@Query("SELECT * FROM history WHERE (title LIKE '%'||:query||'%' OR author LIKE '%'||:query||'%') AND type LIKE '%'||:type||'%' AND website LIKE '%'||:site||'%' ORDER BY " +
|
||||
"CASE WHEN :sort = 'ASC' THEN author END ASC," +
|
||||
"CASE WHEN :sort = 'DESC' THEN author END DESC," +
|
||||
"CASE WHEN :sort = '' THEN author END DESC ")
|
||||
fun getHistorySortedByAuthorPaginated(query : String, type : String, site : String, sort : String) : PagingSource<Int, HistoryItem>
|
||||
|
||||
@Query("SELECT * FROM history WHERE (title LIKE '%'||:query||'%' OR author LIKE '%'||:query||'%') AND type LIKE '%'||:type||'%' AND website LIKE '%'||:site||'%' ORDER BY " +
|
||||
"CASE WHEN :sort = 'ASC' THEN filesize END ASC," +
|
||||
"CASE WHEN :sort = 'DESC' THEN filesize END DESC," +
|
||||
"CASE WHEN :sort = '' THEN filesize END DESC ")
|
||||
fun getHistorySortedByFilesizePaginated(query : String, type : String, site : String, sort : String) : PagingSource<Int, HistoryItem>
|
||||
|
||||
|
||||
@Query("SELECT * FROM history")
|
||||
fun getAllHistory() : Flow<List<HistoryItem>>
|
||||
|
||||
@Query("SELECT DISTINCT website FROM history")
|
||||
fun getWebsites() : Flow<List<String>>
|
||||
|
||||
@Query("SELECT COUNT(*) FROM history")
|
||||
fun getCount() : Flow<Int>
|
||||
|
||||
@Query("SELECT * FROM history")
|
||||
fun getAllHistoryPaginated() : PagingSource<Int, HistoryItem>
|
||||
|
||||
@Query("SELECT * FROM history")
|
||||
fun getAllHistoryList() : List<HistoryItem>
|
||||
|
||||
|
|
|
|||
|
|
@ -17,5 +17,7 @@ data class CommandTemplate(
|
|||
@ColumnInfo(defaultValue = "1")
|
||||
var useAsExtraCommandAudio: Boolean,
|
||||
@ColumnInfo(defaultValue = "1")
|
||||
var useAsExtraCommandVideo: Boolean
|
||||
var useAsExtraCommandVideo: Boolean,
|
||||
@ColumnInfo(defaultValue = "0")
|
||||
var useAsExtraCommandDataFetching: Boolean
|
||||
)
|
||||
|
|
@ -20,6 +20,8 @@ data class HistoryItem(
|
|||
val website: String,
|
||||
val format: Format,
|
||||
@ColumnInfo(defaultValue = "0")
|
||||
val filesize: Long = 0,
|
||||
@ColumnInfo(defaultValue = "0")
|
||||
val downloadId: Long,
|
||||
@ColumnInfo(defaultValue = "")
|
||||
val command: String = ""
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
package com.deniscerri.ytdl.database.repository
|
||||
|
||||
import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import androidx.paging.PagingData
|
||||
import androidx.paging.PagingSource
|
||||
import androidx.paging.filter
|
||||
import com.deniscerri.ytdl.database.DBManager.SORTING
|
||||
import com.deniscerri.ytdl.database.dao.HistoryDao
|
||||
import com.deniscerri.ytdl.database.models.HistoryItem
|
||||
|
|
@ -7,9 +12,12 @@ import com.deniscerri.ytdl.database.viewmodel.HistoryViewModel
|
|||
import com.deniscerri.ytdl.util.FileUtil
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
class HistoryRepository(private val historyDao: HistoryDao) {
|
||||
val items : Flow<List<HistoryItem>> = historyDao.getAllHistory()
|
||||
val websites : Flow<List<String>> = historyDao.getWebsites()
|
||||
val count : Flow<Int> = historyDao.getCount()
|
||||
|
||||
enum class HistorySortType {
|
||||
DATE, TITLE, AUTHOR, FILESIZE
|
||||
|
|
@ -27,6 +35,7 @@ class HistoryRepository(private val historyDao: HistoryDao) {
|
|||
return historyDao.getAllHistoryByURL(url)
|
||||
}
|
||||
|
||||
|
||||
fun getFiltered(query : String, type : String, site : String, sortType: HistorySortType, sort: SORTING, statusFilter: HistoryViewModel.HistoryStatus) : List<HistoryItem> {
|
||||
var filtered = when(sortType){
|
||||
HistorySortType.DATE -> historyDao.getHistorySortedByID(query, type, site, sort.toString())
|
||||
|
|
@ -54,6 +63,20 @@ class HistoryRepository(private val historyDao: HistoryDao) {
|
|||
return filtered
|
||||
}
|
||||
|
||||
fun getPaginatedSource(query : String, type : String, site : String, sortType: HistorySortType, sort: SORTING) : PagingSource<Int, HistoryItem> {
|
||||
val source = when(sortType){
|
||||
HistorySortType.DATE -> historyDao.getHistorySortedByIDPaginated(query, type, site, sort.toString())
|
||||
HistorySortType.TITLE -> historyDao.getHistorySortedByTitlePaginated(query, type, site, sort.toString())
|
||||
HistorySortType.AUTHOR -> historyDao.getHistorySortedByAuthorPaginated(query, type, site, sort.toString())
|
||||
HistorySortType.FILESIZE -> {
|
||||
historyDao.getHistorySortedByFilesizePaginated(query, type, site, sort.toString())
|
||||
}
|
||||
}
|
||||
|
||||
return source
|
||||
}
|
||||
|
||||
|
||||
suspend fun insert(item: HistoryItem){
|
||||
historyDao.insert(item)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -550,7 +550,7 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
|||
}
|
||||
|
||||
return generateCommandFormat(
|
||||
c ?: CommandTemplate(0, "", preferredTemplateContent, useAsExtraCommand = false, useAsExtraCommandAudio = false, useAsExtraCommandVideo = false)
|
||||
c ?: CommandTemplate(0, "", preferredTemplateContent, useAsExtraCommand = false, useAsExtraCommandAudio = false, useAsExtraCommandVideo = false, useAsExtraCommandDataFetching = false)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,68 +6,109 @@ import androidx.lifecycle.LiveData
|
|||
import androidx.lifecycle.MediatorLiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.switchMap
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import androidx.paging.PagingData
|
||||
import androidx.paging.cachedIn
|
||||
import androidx.paging.filter
|
||||
import com.deniscerri.ytdl.database.DBManager
|
||||
import com.deniscerri.ytdl.database.DBManager.SORTING
|
||||
import com.deniscerri.ytdl.database.models.HistoryItem
|
||||
import com.deniscerri.ytdl.database.repository.DownloadRepository
|
||||
import com.deniscerri.ytdl.database.repository.HistoryRepository
|
||||
import com.deniscerri.ytdl.database.repository.HistoryRepository.HistorySortType
|
||||
import com.deniscerri.ytdl.util.Extensions
|
||||
import com.deniscerri.ytdl.util.FileUtil
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.buffer
|
||||
import kotlinx.coroutines.flow.cache
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.flattenMerge
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.merge
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class HistoryViewModel(application: Application) : AndroidViewModel(application) {
|
||||
private val repository : HistoryRepository
|
||||
val sortOrder = MutableLiveData(SORTING.DESC)
|
||||
val sortType = MutableLiveData(HistorySortType.DATE)
|
||||
val websiteFilter = MutableLiveData("")
|
||||
val statusFilter = MutableLiveData(HistoryStatus.ALL)
|
||||
private val queryFilter = MutableLiveData("")
|
||||
private val typeFilter = MutableLiveData("")
|
||||
val sortOrder = MutableStateFlow(SORTING.DESC)
|
||||
val sortType = MutableStateFlow(HistorySortType.DATE)
|
||||
val websiteFilter = MutableStateFlow("")
|
||||
val statusFilter = MutableStateFlow(HistoryStatus.ALL)
|
||||
private val queryFilter = MutableStateFlow("")
|
||||
private val typeFilter = MutableStateFlow("")
|
||||
|
||||
enum class HistoryStatus {
|
||||
UNSET, DELETED, NOT_DELETED, ALL
|
||||
}
|
||||
|
||||
val allItems : LiveData<List<HistoryItem>>
|
||||
private var _items = MediatorLiveData<List<HistoryItem>>()
|
||||
|
||||
var paginatedItems : Flow<PagingData<HistoryItem>>
|
||||
var websites : Flow<List<String>>
|
||||
var totalCount : Flow<Int>
|
||||
|
||||
data class HistoryFilters(
|
||||
var type: String = "",
|
||||
var sortType: HistorySortType = HistorySortType.DATE,
|
||||
var sortOrder: SORTING = SORTING.DESC,
|
||||
var query: String = "",
|
||||
var status: HistoryStatus = HistoryStatus.ALL,
|
||||
var website: String = ""
|
||||
)
|
||||
|
||||
init {
|
||||
val dao = DBManager.getInstance(application).historyDao
|
||||
repository = HistoryRepository(dao)
|
||||
allItems = repository.items.asLiveData()
|
||||
_items.addSource(allItems){
|
||||
filter(queryFilter.value!!, typeFilter.value!!, websiteFilter.value!!, sortType.value!!, sortOrder.value!!, statusFilter.value!!)
|
||||
}
|
||||
_items.addSource(typeFilter){
|
||||
filter(queryFilter.value!!, typeFilter.value!!, websiteFilter.value!!, sortType.value!!, sortOrder.value!!, statusFilter.value!!)
|
||||
}
|
||||
_items.addSource(sortType){
|
||||
filter(queryFilter.value!!, typeFilter.value!!, websiteFilter.value!!, sortType.value!!, sortOrder.value!!, statusFilter.value!!)
|
||||
}
|
||||
_items.addSource(websiteFilter){
|
||||
filter(queryFilter.value!!, typeFilter.value!!, websiteFilter.value!!, sortType.value!!, sortOrder.value!!, statusFilter.value!!)
|
||||
}
|
||||
_items.addSource(queryFilter){
|
||||
filter(queryFilter.value!!, typeFilter.value!!, websiteFilter.value!!, sortType.value!!, sortOrder.value!!, statusFilter.value!!)
|
||||
}
|
||||
websites = repository.websites
|
||||
totalCount = repository.count
|
||||
|
||||
_items.addSource(statusFilter){
|
||||
filter(queryFilter.value!!, typeFilter.value!!, websiteFilter.value!!, sortType.value!!, sortOrder.value!!, statusFilter.value!!)
|
||||
}
|
||||
val filters = listOf(dao.getAllHistory(), sortOrder, sortType, websiteFilter, statusFilter, queryFilter, typeFilter)
|
||||
paginatedItems = combine(filters) { f ->
|
||||
val sortOrder = f[1] as SORTING
|
||||
val sortType = f[2] as HistorySortType
|
||||
val website = f[3] as String
|
||||
val status = f[4] as HistoryStatus
|
||||
val query = f[5] as String
|
||||
val type = f[6] as String
|
||||
|
||||
}
|
||||
var pager = Pager(
|
||||
config = PagingConfig(pageSize = 20, initialLoadSize = 20, prefetchDistance = 1),
|
||||
pagingSourceFactory = {
|
||||
repository.getPaginatedSource(query, type, website, sortType, sortOrder)
|
||||
}
|
||||
).flow
|
||||
|
||||
fun getFilteredList() : LiveData<List<HistoryItem>>{
|
||||
return _items
|
||||
when(status) {
|
||||
HistoryStatus.DELETED -> {
|
||||
pager = pager.map {
|
||||
it.filter { it2 ->
|
||||
it2.downloadPath.any { it3 ->
|
||||
!FileUtil.exists(it3)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
HistoryStatus.NOT_DELETED -> {
|
||||
pager = pager.map {
|
||||
it.filter { it2 ->
|
||||
it2.downloadPath.any { it3 ->
|
||||
FileUtil.exists(it3)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
|
||||
pager
|
||||
}.flatMapLatest { it }
|
||||
}
|
||||
|
||||
fun setSorting(sort: HistorySortType){
|
||||
|
|
@ -98,7 +139,8 @@ class HistoryViewModel(application: Application) : AndroidViewModel(application)
|
|||
}
|
||||
|
||||
private fun filter(query : String, format : String, site : String, sortType: HistorySortType, sort: SORTING, statusFilter: HistoryStatus) = viewModelScope.launch(Dispatchers.IO){
|
||||
_items.postValue(repository.getFiltered(query, format, site, sortType, sort, statusFilter))
|
||||
|
||||
|
||||
}
|
||||
|
||||
fun getAll() : List<HistoryItem> {
|
||||
|
|
|
|||
|
|
@ -41,8 +41,6 @@ import com.deniscerri.ytdl.database.viewmodel.ResultViewModel
|
|||
import com.deniscerri.ytdl.ui.BaseActivity
|
||||
import com.deniscerri.ytdl.util.Extensions.extractURL
|
||||
import com.deniscerri.ytdl.util.ThemeUtil
|
||||
import com.deniscerri.ytdl.util.UiUtil
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
|
|
@ -50,7 +48,6 @@ import kotlinx.coroutines.flow.collectLatest
|
|||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlin.properties.Delegates
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
|
||||
class ShareActivity : BaseActivity() {
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ import com.deniscerri.ytdl.ui.adapter.SearchSuggestionsAdapter
|
|||
import com.deniscerri.ytdl.ui.downloads.HistoryFragment
|
||||
import com.deniscerri.ytdl.ui.downloads.HistoryFragment.Companion
|
||||
import com.deniscerri.ytdl.util.Extensions.enableFastScroll
|
||||
import com.deniscerri.ytdl.util.Extensions.isURL
|
||||
import com.deniscerri.ytdl.util.NotificationUtil
|
||||
import com.deniscerri.ytdl.util.ThemeUtil
|
||||
import com.deniscerri.ytdl.util.UiUtil
|
||||
|
|
@ -231,7 +232,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, SearchSuggesti
|
|||
val url = requireArguments().getString("url")
|
||||
if (inputQueries == null) inputQueries = mutableListOf()
|
||||
searchBar?.setText(url)
|
||||
val argList = url!!.split("\n").toMutableList()
|
||||
val argList = url!!.split("\n").filter { it.isURL() }.toMutableList()
|
||||
argList.removeAll(listOf("", null))
|
||||
inputQueries!!.addAll(argList)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,243 @@
|
|||
package com.deniscerri.ytdl.ui.adapter
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.SharedPreferences
|
||||
import android.graphics.ColorMatrix
|
||||
import android.graphics.ColorMatrixColorFilter
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.paging.PagingDataAdapter
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.AsyncDifferConfig
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.deniscerri.ytdl.R
|
||||
import com.deniscerri.ytdl.database.models.HistoryItem
|
||||
import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdl.util.Extensions.loadThumbnail
|
||||
import com.deniscerri.ytdl.util.Extensions.popup
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
import com.google.android.material.color.MaterialColors
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
import java.io.File
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
|
||||
class HistoryPaginatedAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : PagingDataAdapter<HistoryItem, HistoryPaginatedAdapter.ViewHolder>(
|
||||
DIFF_CALLBACK
|
||||
) {
|
||||
val checkedItems: MutableSet<Long>
|
||||
var inverted: Boolean
|
||||
private val onItemClickListener: OnItemClickListener
|
||||
private val activity: Activity
|
||||
private val sharedPreferences: SharedPreferences
|
||||
|
||||
init {
|
||||
checkedItems = mutableSetOf()
|
||||
this.inverted = false
|
||||
this.onItemClickListener = onItemClickListener
|
||||
this.activity = activity
|
||||
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(activity)
|
||||
}
|
||||
|
||||
class ViewHolder(itemView: View, onItemClickListener: OnItemClickListener?) : RecyclerView.ViewHolder(itemView) {
|
||||
val cardView: MaterialCardView
|
||||
|
||||
init {
|
||||
cardView = itemView.findViewById(R.id.downloads_card_view)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HistoryPaginatedAdapter.ViewHolder {
|
||||
return if (viewType == 0){
|
||||
val cardView = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.history_card, parent, false)
|
||||
ViewHolder(cardView, onItemClickListener)
|
||||
}else{
|
||||
val cardView = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.history_card_multiple, parent, false)
|
||||
ViewHolder(cardView, onItemClickListener)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
getItem(position)?.apply {
|
||||
return if(this.downloadPath.size == 1){
|
||||
0
|
||||
}else{
|
||||
1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val item = getItem(position) ?: return
|
||||
val card = holder.cardView
|
||||
card.tag = item.id.toString()
|
||||
card.popup()
|
||||
|
||||
|
||||
val uiHandler = Handler(Looper.getMainLooper())
|
||||
val thumbnail = card.findViewById<ImageView>(R.id.downloads_image_view)
|
||||
|
||||
// THUMBNAIL ----------------------------------
|
||||
val hideThumb = sharedPreferences.getStringSet("hide_thumbnails", emptySet())!!.contains("downloads")
|
||||
uiHandler.post { thumbnail.loadThumbnail(hideThumb, item!!.thumb) }
|
||||
|
||||
// TITLE ----------------------------------
|
||||
val itemTitle = card.findViewById<TextView>(R.id.downloads_title)
|
||||
var title = item!!.title.ifEmpty { item.url }
|
||||
if (title.length > 100) {
|
||||
title = title.substring(0, 40) + "..."
|
||||
}
|
||||
itemTitle.text = title
|
||||
|
||||
// Bottom Info ----------------------------------
|
||||
val author = card.findViewById<TextView>(R.id.downloads_info_bottom)
|
||||
author.text = item.author
|
||||
|
||||
val length = card.findViewById<TextView>(R.id.length)
|
||||
length.text = if(item.downloadPath.size == 1) item.duration else ""
|
||||
|
||||
|
||||
// TIME DOWNLOADED ----------------------------------
|
||||
val datetime = card.findViewById<TextView>(R.id.downloads_info_time)
|
||||
datetime.text = SimpleDateFormat(android.text.format.DateFormat.getBestDateTimePattern(Locale.getDefault(), "ddMMMyyyy - HHmm"), Locale.getDefault()).format(item.time * 1000L)
|
||||
|
||||
// BUTTON ----------------------------------
|
||||
val btn = card.findViewById<FloatingActionButton>(R.id.downloads_download_button_type)
|
||||
var filesPresent = true
|
||||
|
||||
//IS IN THE FILE SYSTEM?
|
||||
if (item.downloadPath.all { !File(it).exists() && it.isNotBlank()}) {
|
||||
filesPresent = false
|
||||
thumbnail.colorFilter = ColorMatrixColorFilter(object : ColorMatrix() {
|
||||
init {
|
||||
setSaturation(0f)
|
||||
}
|
||||
})
|
||||
thumbnail.alpha = 0.7f
|
||||
btn.backgroundTintList = MaterialColors.getColorStateList(activity, R.attr.colorSurface, ContextCompat.getColorStateList(activity, android.R.color.transparent)!!)
|
||||
}else{
|
||||
thumbnail.alpha = 1f
|
||||
thumbnail.colorFilter = null
|
||||
btn.backgroundTintList = MaterialColors.getColorStateList(activity, R.attr.colorPrimaryContainer, ContextCompat.getColorStateList(activity, android.R.color.transparent)!!)
|
||||
}
|
||||
|
||||
if (item.type == DownloadViewModel.Type.audio) {
|
||||
if (filesPresent) btn.setImageResource(R.drawable.ic_music_downloaded) else {
|
||||
btn.setImageResource(R.drawable.ic_music)
|
||||
}
|
||||
} else if (item.type == DownloadViewModel.Type.video) {
|
||||
if (filesPresent) btn.setImageResource(R.drawable.ic_video_downloaded) else btn.setImageResource(R.drawable.ic_video)
|
||||
}else{
|
||||
if (filesPresent) btn.setImageResource(R.drawable.ic_terminal) else btn.setImageResource(R.drawable.baseline_code_off_24)
|
||||
}
|
||||
if (btn.hasOnClickListeners()) btn.setOnClickListener(null)
|
||||
btn.isClickable = filesPresent
|
||||
|
||||
if (checkedItems.contains(item.id)) {
|
||||
card.isChecked = true
|
||||
card.strokeWidth = 5
|
||||
} else {
|
||||
card.isChecked = false
|
||||
card.strokeWidth = 0
|
||||
}
|
||||
val finalFilePresent = filesPresent
|
||||
card.setOnLongClickListener {
|
||||
checkCard(card, item.id)
|
||||
true
|
||||
}
|
||||
card.setOnClickListener {
|
||||
if (checkedItems.size > 0) {
|
||||
checkCard(card, item.id)
|
||||
} else {
|
||||
onItemClickListener.onCardClick(item.id, finalFilePresent)
|
||||
}
|
||||
}
|
||||
|
||||
btn.setOnClickListener {
|
||||
onItemClickListener.onButtonClick(item.id, finalFilePresent)
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
fun clearCheckedItems() {
|
||||
inverted = false
|
||||
checkedItems.clear()
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
fun checkAll() {
|
||||
checkedItems.clear()
|
||||
inverted = true
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
fun checkMultipleItems(list: List<Long>){
|
||||
checkedItems.clear()
|
||||
inverted = false
|
||||
checkedItems.addAll(list)
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
fun invertSelected() {
|
||||
inverted = !inverted
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
fun getSelectedObjectsCount(totalSize: Int) : Int{
|
||||
return if (inverted){
|
||||
totalSize - checkedItems.size
|
||||
}else{
|
||||
checkedItems.size
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkCard(card: MaterialCardView, itemID: Long) {
|
||||
if (card.isChecked) {
|
||||
card.strokeWidth = 0
|
||||
if (inverted) checkedItems.add(itemID)
|
||||
else checkedItems.remove(itemID)
|
||||
} else {
|
||||
card.strokeWidth = 5
|
||||
if (inverted) checkedItems.remove(itemID)
|
||||
else checkedItems.add(itemID)
|
||||
}
|
||||
card.isChecked = !card.isChecked
|
||||
onItemClickListener.onCardSelect(itemID, card.isChecked)
|
||||
}
|
||||
|
||||
interface OnItemClickListener {
|
||||
fun onCardClick(itemID: Long, isPresent: Boolean)
|
||||
fun onButtonClick(itemID: Long, isPresent: Boolean)
|
||||
fun onCardSelect(itemID: Long, isChecked: Boolean)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val DIFF_CALLBACK: DiffUtil.ItemCallback<HistoryItem> = object : DiffUtil.ItemCallback<HistoryItem>() {
|
||||
override fun areItemsTheSame(oldItem: HistoryItem, newItem: HistoryItem): Boolean {
|
||||
val ranged = arrayListOf(oldItem.id, newItem.id)
|
||||
return ranged[0] == ranged[1]
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: HistoryItem, newItem: HistoryItem): Boolean {
|
||||
return oldItem.time == newItem.time
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -93,7 +93,7 @@ class DownloadCommandFragment(private val resultItem: ResultItem? = null, privat
|
|||
preferences.edit().putString("lastCommandTemplateUsed", downloadItem.format.format_note).apply()
|
||||
|
||||
if (!Patterns.WEB_URL.matcher(downloadItem.url).matches() && downloadItem.url.endsWith(".txt")){
|
||||
downloadItem.format = downloadViewModel.generateCommandFormat(CommandTemplate(0,"txt", "-a \"${downloadItem.url}\"", useAsExtraCommand = false, useAsExtraCommandAudio = false, useAsExtraCommandVideo = false))
|
||||
downloadItem.format = downloadViewModel.generateCommandFormat(CommandTemplate(0,"txt", "-a \"${downloadItem.url}\"", useAsExtraCommand = false, useAsExtraCommandAudio = false, useAsExtraCommandVideo = false, useAsExtraCommandDataFetching = false))
|
||||
downloadItem.url = ""
|
||||
}
|
||||
|
||||
|
|
@ -249,7 +249,7 @@ class DownloadCommandFragment(private val resultItem: ResultItem? = null, privat
|
|||
0,
|
||||
"",
|
||||
chosenCommandView.editText!!.text.toString(),
|
||||
useAsExtraCommand = false, useAsExtraCommandAudio = false, useAsExtraCommandVideo = false
|
||||
useAsExtraCommand = false, useAsExtraCommandAudio = false, useAsExtraCommandVideo = false, useAsExtraCommandDataFetching = false
|
||||
)
|
||||
UiUtil.showCommandTemplateCreationOrUpdatingSheet(
|
||||
current, requireActivity(), viewLifecycleOwner, commandTemplateViewModel,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.deniscerri.ytdl.ui.downloads
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.graphics.Canvas
|
||||
|
|
@ -16,8 +15,6 @@ import android.view.LayoutInflater
|
|||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.View.GONE
|
||||
import android.view.View.VISIBLE
|
||||
import android.view.ViewGroup
|
||||
import android.view.Window
|
||||
import android.widget.LinearLayout
|
||||
|
|
@ -45,13 +42,12 @@ import com.deniscerri.ytdl.MainActivity
|
|||
import com.deniscerri.ytdl.R
|
||||
import com.deniscerri.ytdl.database.DBManager.SORTING
|
||||
import com.deniscerri.ytdl.database.models.HistoryItem
|
||||
import com.deniscerri.ytdl.database.repository.DownloadRepository
|
||||
import com.deniscerri.ytdl.database.repository.HistoryRepository
|
||||
import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdl.database.viewmodel.HistoryViewModel
|
||||
import com.deniscerri.ytdl.ui.adapter.HistoryAdapter
|
||||
import com.deniscerri.ytdl.ui.downloadcard.FormatSelectionBottomSheetDialog.FormatCategory
|
||||
import com.deniscerri.ytdl.ui.adapter.HistoryPaginatedAdapter
|
||||
import com.deniscerri.ytdl.util.Extensions.enableFastScroll
|
||||
import com.deniscerri.ytdl.util.Extensions.isYoutubeURL
|
||||
import com.deniscerri.ytdl.util.FileUtil
|
||||
import com.deniscerri.ytdl.util.NavbarUtil
|
||||
import com.deniscerri.ytdl.util.UiUtil
|
||||
|
|
@ -73,26 +69,23 @@ import kotlinx.coroutines.withContext
|
|||
/**
|
||||
* A fragment representing a list of Items.
|
||||
*/
|
||||
class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
||||
class HistoryFragment : Fragment(), HistoryPaginatedAdapter.OnItemClickListener{
|
||||
private lateinit var historyViewModel : HistoryViewModel
|
||||
private lateinit var downloadViewModel : DownloadViewModel
|
||||
|
||||
private var fragmentView: View? = null
|
||||
private var activity: Activity? = null
|
||||
private lateinit var fragmentView: View
|
||||
private var mainActivity: MainActivity? = null
|
||||
private var fragmentContext: Context? = null
|
||||
private var layoutinflater: LayoutInflater? = null
|
||||
private var topAppBar: MaterialToolbar? = null
|
||||
private lateinit var layoutinflater: LayoutInflater
|
||||
private lateinit var topAppBar: MaterialToolbar
|
||||
private lateinit var recyclerView: RecyclerView
|
||||
private var historyAdapter: HistoryAdapter? = null
|
||||
private var sortSheet: BottomSheetDialog? = null
|
||||
private var uiHandler: Handler? = null
|
||||
private var noResults: RelativeLayout? = null
|
||||
private var selectionChips: LinearLayout? = null
|
||||
private var historyList: List<HistoryItem?>? = null
|
||||
private var allhistoryList: List<HistoryItem?>? = null
|
||||
private lateinit var historyAdapter: HistoryPaginatedAdapter
|
||||
private lateinit var sortSheet: BottomSheetDialog
|
||||
private lateinit var uiHandler: Handler
|
||||
private lateinit var noResults: RelativeLayout
|
||||
private lateinit var selectionChips: LinearLayout
|
||||
private var websiteList: MutableList<String> = mutableListOf()
|
||||
private lateinit var selectedObjects: ArrayList<HistoryItem>
|
||||
private var totalCount = 0
|
||||
private var actionMode : ActionMode? = null
|
||||
|
||||
private lateinit var sortChip: Chip
|
||||
|
|
@ -100,9 +93,8 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
): View {
|
||||
fragmentView = inflater.inflate(R.layout.fragment_history, container, false)
|
||||
activity = getActivity()
|
||||
mainActivity = activity as MainActivity?
|
||||
return fragmentView
|
||||
}
|
||||
|
|
@ -118,24 +110,15 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
selectionChips = view.findViewById(R.id.history_selection_chips)
|
||||
uiHandler = Handler(Looper.getMainLooper())
|
||||
sortChip = view.findViewById(R.id.sortChip)
|
||||
selectedObjects = arrayListOf()
|
||||
|
||||
val isInNavBar = NavbarUtil.getNavBarItems(requireActivity()).any { n -> n.itemId == R.id.historyFragment && n.isVisible }
|
||||
if (isInNavBar) {
|
||||
topAppBar?.navigationIcon = null
|
||||
topAppBar.navigationIcon = null
|
||||
}else{
|
||||
mainActivity?.hideBottomNavigation()
|
||||
}
|
||||
topAppBar?.setNavigationOnClickListener { mainActivity?.onBackPressedDispatcher?.onBackPressed() }
|
||||
|
||||
|
||||
historyList = mutableListOf()
|
||||
|
||||
historyAdapter =
|
||||
HistoryAdapter(
|
||||
this,
|
||||
requireActivity()
|
||||
)
|
||||
topAppBar.setNavigationOnClickListener { mainActivity?.onBackPressedDispatcher?.onBackPressed() }
|
||||
historyAdapter = HistoryPaginatedAdapter(this, requireActivity())
|
||||
recyclerView = view.findViewById(R.id.recyclerviewhistorys)
|
||||
recyclerView.enableFastScroll()
|
||||
|
||||
|
|
@ -146,37 +129,44 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
}
|
||||
|
||||
recyclerView.layoutManager = GridLayoutManager(context, resources.getInteger(R.integer.grid_size))
|
||||
noResults?.visibility = GONE
|
||||
|
||||
|
||||
noResults.isVisible = false
|
||||
historyViewModel = ViewModelProvider(this)[HistoryViewModel::class.java]
|
||||
historyViewModel.allItems.observe(viewLifecycleOwner) {
|
||||
allhistoryList = it
|
||||
if(it.isEmpty()){
|
||||
noResults!!.visibility = VISIBLE
|
||||
selectionChips!!.visibility = GONE
|
||||
topAppBar!!.menu.children.firstOrNull { m -> m.itemId == R.id.filters }?.isVisible = false
|
||||
}else{
|
||||
noResults!!.visibility = GONE
|
||||
selectionChips!!.visibility = VISIBLE
|
||||
topAppBar!!.menu.children.firstOrNull { m -> m.itemId == R.id.filters }?.isVisible = true
|
||||
updateWebsiteChips(it)
|
||||
recyclerView.adapter = historyAdapter
|
||||
lifecycleScope.launch {
|
||||
historyViewModel.paginatedItems.collectLatest {
|
||||
withContext(Dispatchers.IO){
|
||||
historyAdapter.submitData(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
lifecycleScope.launch {
|
||||
historyViewModel.websites.collectLatest {
|
||||
if(it.isEmpty()) {
|
||||
noResults.isVisible = true
|
||||
selectionChips.isVisible = false
|
||||
topAppBar.menu.children.firstOrNull { m -> m.itemId == R.id.filters }?.isVisible = false
|
||||
}else{
|
||||
noResults.isVisible = false
|
||||
selectionChips.isVisible = true
|
||||
topAppBar.menu.children.firstOrNull { m -> m.itemId == R.id.filters }?.isVisible = true
|
||||
|
||||
websiteList = mutableListOf()
|
||||
for (item in it){
|
||||
if (item == "null" || item.isEmpty()) continue
|
||||
if (!websiteList.any { it.contentEquals(item, true) }) websiteList.add(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
historyViewModel.getFilteredList().observe(viewLifecycleOwner) {
|
||||
historyAdapter!!.submitList(it)
|
||||
historyList = it
|
||||
|
||||
if (recyclerView.adapter == null){
|
||||
recyclerView.adapter = historyAdapter
|
||||
}else{
|
||||
scrollToTop()
|
||||
lifecycleScope.launch {
|
||||
historyViewModel.totalCount.collectLatest {
|
||||
totalCount = it
|
||||
}
|
||||
}
|
||||
|
||||
historyViewModel.sortOrder.observe(viewLifecycleOwner){
|
||||
if (it != null){
|
||||
lifecycleScope.launch {
|
||||
historyViewModel.sortOrder.collectLatest {
|
||||
when(it){
|
||||
SORTING.ASC -> sortChip.chipIcon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_down)
|
||||
SORTING.DESC -> sortChip.chipIcon = ContextCompat.getDrawable(requireContext(), R.drawable.ic_up)
|
||||
|
|
@ -184,20 +174,18 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
}
|
||||
}
|
||||
|
||||
historyViewModel.sortType.observe(viewLifecycleOwner){
|
||||
if(it != null){
|
||||
when(it){
|
||||
lifecycleScope.launch {
|
||||
historyViewModel.sortType.collectLatest {
|
||||
when(it){
|
||||
HistoryRepository.HistorySortType.AUTHOR -> sortChip.text = getString(R.string.author)
|
||||
HistoryRepository.HistorySortType.DATE -> sortChip.text = getString(R.string.date_added)
|
||||
HistoryRepository.HistorySortType.TITLE -> sortChip.text = getString(R.string.title)
|
||||
HistoryRepository.HistorySortType.FILESIZE -> sortChip.text = getString(R.string.file_size)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
|
||||
|
||||
lifecycleScope.launch{
|
||||
downloadViewModel.alreadyExistsUiState.collectLatest { res ->
|
||||
if (res.isNotEmpty()){
|
||||
|
|
@ -212,7 +200,6 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
initMenu()
|
||||
initChips()
|
||||
}
|
||||
|
|
@ -220,7 +207,7 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
fun scrollToTop() {
|
||||
recyclerView.scrollToPosition(0)
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
(topAppBar!!.parent as AppBarLayout).setExpanded(
|
||||
(topAppBar.parent as AppBarLayout).setExpanded(
|
||||
true,
|
||||
true
|
||||
)
|
||||
|
|
@ -238,14 +225,14 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
return true
|
||||
}
|
||||
}
|
||||
topAppBar!!.menu.findItem(R.id.search_history)
|
||||
topAppBar.menu.findItem(R.id.search_history)
|
||||
.setOnActionExpandListener(onActionExpandListener)
|
||||
val searchView = topAppBar!!.menu.findItem(R.id.search_history).actionView as SearchView?
|
||||
val searchView = topAppBar.menu.findItem(R.id.search_history).actionView as SearchView?
|
||||
searchView!!.inputType = InputType.TYPE_CLASS_TEXT
|
||||
searchView.queryHint = getString(R.string.search_history_hint)
|
||||
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
||||
override fun onQueryTextSubmit(query: String): Boolean {
|
||||
topAppBar!!.menu.findItem(R.id.search_history).collapseActionView()
|
||||
topAppBar.menu.findItem(R.id.search_history).collapseActionView()
|
||||
historyViewModel.setQueryFilter(query)
|
||||
return true
|
||||
}
|
||||
|
|
@ -255,13 +242,13 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
return true
|
||||
}
|
||||
})
|
||||
topAppBar!!.setOnClickListener { scrollToTop() }
|
||||
topAppBar.setOnClickListener { scrollToTop() }
|
||||
val showingDownloadQueue = NavbarUtil.getNavBarItems(requireContext()).any { n -> n.itemId == R.id.downloadQueueMainFragment && n.isVisible }
|
||||
topAppBar!!.menu.findItem(R.id.download_queue).isVisible = !showingDownloadQueue
|
||||
topAppBar!!.setOnMenuItemClickListener { m: MenuItem ->
|
||||
topAppBar.menu.findItem(R.id.download_queue).isVisible = !showingDownloadQueue
|
||||
topAppBar.setOnMenuItemClickListener { m: MenuItem ->
|
||||
when (m.itemId) {
|
||||
R.id.remove_history -> {
|
||||
if(allhistoryList!!.isEmpty()){
|
||||
if(websiteList.isEmpty()){
|
||||
Toast.makeText(context, R.string.history_is_empty, Toast.LENGTH_SHORT).show()
|
||||
}else{
|
||||
val deleteFile = booleanArrayOf(false)
|
||||
|
|
@ -282,7 +269,7 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
findNavController().navigate(R.id.downloadQueueMainFragment)
|
||||
}
|
||||
R.id.remove_deleted_history -> {
|
||||
if(allhistoryList!!.isEmpty()){
|
||||
if(websiteList.isEmpty()){
|
||||
Toast.makeText(context, R.string.history_is_empty, Toast.LENGTH_SHORT).show()
|
||||
}else{
|
||||
val deleteDialog = MaterialAlertDialogBuilder(fragmentContext!!)
|
||||
|
|
@ -296,7 +283,7 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
}
|
||||
}
|
||||
R.id.remove_duplicates -> {
|
||||
if(allhistoryList!!.isEmpty()){
|
||||
if(websiteList.isEmpty()){
|
||||
Toast.makeText(context, R.string.history_is_empty, Toast.LENGTH_SHORT).show()
|
||||
}else{
|
||||
val deleteDialog = MaterialAlertDialogBuilder(fragmentContext!!)
|
||||
|
|
@ -384,7 +371,7 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
|
||||
for (i in websiteList.indices) {
|
||||
val w = websiteList[i]
|
||||
val tmp = layoutinflater!!.inflate(R.layout.filter_chip, websiteGroup, false) as Chip
|
||||
val tmp = layoutinflater.inflate(R.layout.filter_chip, websiteGroup, false) as Chip
|
||||
tmp.text = w
|
||||
tmp.id = i
|
||||
tmp.setOnClickListener {
|
||||
|
|
@ -427,16 +414,16 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
|
||||
|
||||
private fun initChips() {
|
||||
val sortChip = fragmentView!!.findViewById<Chip>(R.id.sortChip)
|
||||
val sortChip = fragmentView.findViewById<Chip>(R.id.sortChip)
|
||||
sortChip.setOnClickListener {
|
||||
sortSheet = BottomSheetDialog(requireContext())
|
||||
sortSheet!!.requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
sortSheet!!.setContentView(R.layout.history_sort_sheet)
|
||||
sortSheet.requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
sortSheet.setContentView(R.layout.history_sort_sheet)
|
||||
|
||||
val date = sortSheet!!.findViewById<TextView>(R.id.date)
|
||||
val title = sortSheet!!.findViewById<TextView>(R.id.title)
|
||||
val author = sortSheet!!.findViewById<TextView>(R.id.author)
|
||||
val filesize = sortSheet!!.findViewById<TextView>(R.id.filesize)
|
||||
val date = sortSheet.findViewById<TextView>(R.id.date)
|
||||
val title = sortSheet.findViewById<TextView>(R.id.title)
|
||||
val author = sortSheet.findViewById<TextView>(R.id.author)
|
||||
val filesize = sortSheet.findViewById<TextView>(R.id.filesize)
|
||||
|
||||
val sortOptions = listOf(date!!, title!!, author!!, filesize!!)
|
||||
sortOptions.forEach { it.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.empty,0,0,0) }
|
||||
|
|
@ -469,12 +456,12 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
}
|
||||
val displayMetrics = DisplayMetrics()
|
||||
requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics)
|
||||
sortSheet!!.behavior.peekHeight = displayMetrics.heightPixels
|
||||
sortSheet!!.show()
|
||||
sortSheet.behavior.peekHeight = displayMetrics.heightPixels
|
||||
sortSheet.show()
|
||||
}
|
||||
|
||||
//format
|
||||
val audio = fragmentView!!.findViewById<Chip>(R.id.audio_chip)
|
||||
val audio = fragmentView.findViewById<Chip>(R.id.audio_chip)
|
||||
audio.setOnClickListener {
|
||||
if (audio.isChecked) {
|
||||
historyViewModel.setTypeFilter(DownloadViewModel.Type.audio.toString())
|
||||
|
|
@ -484,7 +471,7 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
audio.isChecked = false
|
||||
}
|
||||
}
|
||||
val video = fragmentView!!.findViewById<Chip>(R.id.video_chip)
|
||||
val video = fragmentView.findViewById<Chip>(R.id.video_chip)
|
||||
video.setOnClickListener {
|
||||
if (video.isChecked) {
|
||||
historyViewModel.setTypeFilter(DownloadViewModel.Type.video.toString())
|
||||
|
|
@ -494,7 +481,7 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
video.isChecked = false
|
||||
}
|
||||
}
|
||||
val command = fragmentView!!.findViewById<Chip>(R.id.command_chip)
|
||||
val command = fragmentView.findViewById<Chip>(R.id.command_chip)
|
||||
command.setOnClickListener {
|
||||
if (command.isChecked) {
|
||||
historyViewModel.setTypeFilter(DownloadViewModel.Type.command.toString())
|
||||
|
|
@ -508,71 +495,68 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
|
||||
}
|
||||
|
||||
private fun updateWebsiteChips(list : List<HistoryItem>) {
|
||||
websiteList = mutableListOf()
|
||||
for (item in list){
|
||||
if (item.website == "null" || item.website.isEmpty()) continue
|
||||
if (!websiteList.any { it.contentEquals(item.website, true) }) websiteList.add(item.website)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCardClick(itemID: Long, isPresent: Boolean) {
|
||||
val item = findItem(itemID)
|
||||
UiUtil.showHistoryItemDetailsCard(item, requireActivity(), isPresent,
|
||||
removeItem = { it, deleteFile ->
|
||||
historyViewModel.delete(it, deleteFile)
|
||||
},
|
||||
redownloadItem = {
|
||||
val downloadItem = downloadViewModel.createDownloadItemFromHistory(it)
|
||||
runBlocking{
|
||||
downloadViewModel.queueDownloads(listOf(downloadItem))
|
||||
}
|
||||
historyViewModel.delete(it, false)
|
||||
},
|
||||
redownloadShowDownloadCard = {
|
||||
findNavController().navigate(R.id.downloadBottomSheetDialog, bundleOf(
|
||||
Pair("result", downloadViewModel.createResultItemFromHistory(it)),
|
||||
Pair("type", it.type),
|
||||
))
|
||||
lifecycleScope.launch {
|
||||
val item = withContext(Dispatchers.IO){
|
||||
historyViewModel.getByID(itemID)
|
||||
}
|
||||
)
|
||||
|
||||
UiUtil.showHistoryItemDetailsCard(item, requireActivity(), isPresent,
|
||||
removeItem = { it, deleteFile ->
|
||||
historyViewModel.delete(it, deleteFile)
|
||||
},
|
||||
redownloadItem = {
|
||||
val downloadItem = downloadViewModel.createDownloadItemFromHistory(it)
|
||||
runBlocking{
|
||||
downloadViewModel.queueDownloads(listOf(downloadItem))
|
||||
}
|
||||
historyViewModel.delete(it, false)
|
||||
},
|
||||
redownloadShowDownloadCard = {
|
||||
findNavController().navigate(R.id.downloadBottomSheetDialog, bundleOf(
|
||||
Pair("result", downloadViewModel.createResultItemFromHistory(it)),
|
||||
Pair("type", it.type),
|
||||
))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCardSelect(itemID: Long, isChecked: Boolean) {
|
||||
lifecycleScope.launch {
|
||||
val item = findItem(itemID)
|
||||
if (actionMode == null) actionMode = (getActivity() as AppCompatActivity?)!!.startSupportActionMode(contextualActionBar)
|
||||
actionMode?.apply {
|
||||
if (isChecked) selectedObjects.add(item!!)
|
||||
else selectedObjects.remove(item!!)
|
||||
val item = withContext(Dispatchers.IO) {
|
||||
historyViewModel.getByID(itemID)
|
||||
}
|
||||
|
||||
if (selectedObjects.size == 0){
|
||||
if (actionMode == null) actionMode = (activity as AppCompatActivity?)!!.startSupportActionMode(contextualActionBar)
|
||||
val selectedObjects = historyAdapter.getSelectedObjectsCount(totalCount)
|
||||
actionMode?.apply {
|
||||
if (selectedObjects == 0){
|
||||
this.finish()
|
||||
}else{
|
||||
actionMode?.title = "${selectedObjects.size} ${getString(R.string.selected)}"
|
||||
actionMode?.title = "$selectedObjects ${getString(R.string.selected)}"
|
||||
this.menu.findItem(R.id.select_between).isVisible = false
|
||||
if(selectedObjects.size == 2){
|
||||
val selectedIDs = selectedObjects.sortedBy { it.id }
|
||||
val resultsInMiddle = withContext(Dispatchers.IO){
|
||||
historyViewModel.getRecordsBetweenTwoItems(selectedIDs.first().id, selectedIDs.last().id)
|
||||
}.toMutableList()
|
||||
this.menu.findItem(R.id.select_between).isVisible = resultsInMiddle.isNotEmpty()
|
||||
if(selectedObjects == 2){
|
||||
//TODO
|
||||
// val selectedIDs = contextualActionBar.getSelectedIDs().sortedBy { it }
|
||||
// val resultsInMiddle = withContext(Dispatchers.IO){
|
||||
// historyViewModel.getRecordsBetweenTwoItems(selectedIDs.first().id, selectedIDs.last().id)
|
||||
// }.toMutableList()
|
||||
// this.menu.findItem(R.id.select_between).isVisible = resultsInMiddle.isNotEmpty()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun findItem(id : Long): HistoryItem? {
|
||||
return historyList?.find { it?.id == id }
|
||||
}
|
||||
|
||||
private val contextualActionBar = object : ActionMode.Callback {
|
||||
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
|
||||
mode!!.menuInflater.inflate(R.menu.history_menu_context, menu)
|
||||
mode.title = "${selectedObjects.size} ${getString(R.string.selected)}"
|
||||
mode.title = "${historyAdapter.getSelectedObjectsCount(totalCount)} ${getString(R.string.selected)}"
|
||||
(activity as MainActivity).disableBottomNavigation()
|
||||
topAppBar!!.menu.forEach { it.isEnabled = false }
|
||||
topAppBar.menu.forEach { it.isEnabled = false }
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
@ -589,62 +573,66 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
): Boolean {
|
||||
return when (item!!.itemId) {
|
||||
R.id.select_between -> {
|
||||
lifecycleScope.launch {
|
||||
val selectedIDs = selectedObjects.sortedBy { it.id }
|
||||
val resultsInMiddle = withContext(Dispatchers.IO){
|
||||
historyViewModel.getRecordsBetweenTwoItems(selectedIDs.first().id, selectedIDs.last().id)
|
||||
}.toMutableList()
|
||||
if (resultsInMiddle.isNotEmpty()){
|
||||
selectedObjects.addAll(resultsInMiddle)
|
||||
historyAdapter?.checkMultipleItems(selectedObjects.map { it.id })
|
||||
actionMode?.title = "${selectedObjects.count()} ${getString(R.string.selected)}"
|
||||
}
|
||||
mode?.menu?.findItem(R.id.select_between)?.isVisible = false
|
||||
}
|
||||
//TODO
|
||||
// lifecycleScope.launch {
|
||||
// val selectedIDs = selectedObjects.sortedBy { it.id }
|
||||
// val resultsInMiddle = withContext(Dispatchers.IO){
|
||||
// historyViewModel.getRecordsBetweenTwoItems(selectedIDs.first().id, selectedIDs.last().id)
|
||||
// }.toMutableList()
|
||||
// if (resultsInMiddle.isNotEmpty()){
|
||||
// selectedObjects.addAll(resultsInMiddle)
|
||||
// historyAdapter.checkMultipleItems(selectedObjects.map { it.id })
|
||||
// actionMode?.title = "${selectedObjects.count()} ${getString(R.string.selected)}"
|
||||
// }
|
||||
// mode?.menu?.findItem(R.id.select_between)?.isVisible = false
|
||||
// }
|
||||
true
|
||||
}
|
||||
R.id.delete_results -> {
|
||||
val deleteFile = booleanArrayOf(false)
|
||||
val deleteDialog = MaterialAlertDialogBuilder(fragmentContext!!)
|
||||
deleteDialog.setTitle(getString(R.string.you_are_going_to_delete_multiple_items))
|
||||
deleteDialog.setMultiChoiceItems(
|
||||
arrayOf(getString(R.string.delete_files_too)),
|
||||
booleanArrayOf(false)
|
||||
) { _: DialogInterface?, _: Int, b: Boolean -> deleteFile[0] = b }
|
||||
deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
|
||||
deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
|
||||
for (obj in selectedObjects){
|
||||
historyViewModel.delete(obj, deleteFile[0])
|
||||
}
|
||||
clearCheckedItems()
|
||||
actionMode?.finish()
|
||||
}
|
||||
deleteDialog.show()
|
||||
//TODO
|
||||
// val deleteFile = booleanArrayOf(false)
|
||||
// val deleteDialog = MaterialAlertDialogBuilder(fragmentContext!!)
|
||||
// deleteDialog.setTitle(getString(R.string.you_are_going_to_delete_multiple_items))
|
||||
// deleteDialog.setMultiChoiceItems(
|
||||
// arrayOf(getString(R.string.delete_files_too)),
|
||||
// booleanArrayOf(false)
|
||||
// ) { _: DialogInterface?, _: Int, b: Boolean -> deleteFile[0] = b }
|
||||
// deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
|
||||
// deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
|
||||
// for (obj in selectedObjects){
|
||||
// historyViewModel.delete(obj, deleteFile[0])
|
||||
// }
|
||||
// clearCheckedItems()
|
||||
// actionMode?.finish()
|
||||
// }
|
||||
// deleteDialog.show()
|
||||
true
|
||||
}
|
||||
R.id.share -> {
|
||||
FileUtil.shareFileIntent(requireContext(), selectedObjects.map { it.downloadPath }.flatten())
|
||||
clearCheckedItems()
|
||||
actionMode?.finish()
|
||||
//TODO
|
||||
// FileUtil.shareFileIntent(requireContext(), selectedObjects.map { it.downloadPath }.flatten())
|
||||
// clearCheckedItems()
|
||||
// actionMode?.finish()
|
||||
true
|
||||
}
|
||||
R.id.select_all -> {
|
||||
historyAdapter?.checkAll(historyList)
|
||||
selectedObjects.clear()
|
||||
historyList?.forEach { selectedObjects.add(it!!) }
|
||||
mode?.title = "(${selectedObjects.size}) ${resources.getString(R.string.all_items_selected)}"
|
||||
//TODO
|
||||
// historyAdapter.checkAll()
|
||||
// historyList?.forEach { selectedObjects.add(it!!) }
|
||||
// mode?.title = "(${selectedObjects.size}) ${resources.getString(R.string.all_items_selected)}"
|
||||
true
|
||||
}
|
||||
R.id.invert_selected -> {
|
||||
historyAdapter?.invertSelected(historyList)
|
||||
val invertedList = arrayListOf<HistoryItem>()
|
||||
historyList?.forEach {
|
||||
if (!selectedObjects.contains(it)!!) invertedList.add(it!!)
|
||||
}
|
||||
selectedObjects.clear()
|
||||
selectedObjects.addAll(invertedList)
|
||||
actionMode!!.title = "${selectedObjects.size} ${getString(R.string.selected)}"
|
||||
if (invertedList.isEmpty()) actionMode?.finish()
|
||||
//TODO
|
||||
// historyAdapter.invertSelected()
|
||||
// val invertedList = arrayListOf<HistoryItem>()
|
||||
// historyList?.forEach {
|
||||
// if (!selectedObjects.contains(it)!!) invertedList.add(it!!)
|
||||
// }
|
||||
// selectedObjects.clear()
|
||||
// selectedObjects.addAll(invertedList)
|
||||
// actionMode!!.title = "${selectedObjects.size} ${getString(R.string.selected)}"
|
||||
// if (invertedList.isEmpty()) actionMode?.finish()
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
|
|
@ -654,15 +642,23 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
override fun onDestroyActionMode(mode: ActionMode?) {
|
||||
actionMode = null
|
||||
(activity as MainActivity).enableBottomNavigation()
|
||||
clearCheckedItems()
|
||||
topAppBar!!.menu.forEach { it.isEnabled = true }
|
||||
historyAdapter.clearCheckedItems()
|
||||
topAppBar.menu.forEach { it.isEnabled = true }
|
||||
}
|
||||
|
||||
suspend fun getSelectedIDs() : List<Long>{
|
||||
//TODO
|
||||
// return if (historyAdapter.inverted || historyAdapter.checkedItems.isEmpty()) {
|
||||
// withContext(Dispatchers.IO){
|
||||
// historyViewModel.getItemIDsNotPresentIn(historyAdapter.checkedItems.toList())
|
||||
// }
|
||||
// }else{
|
||||
// historyAdapter.checkedItems.toList()
|
||||
// }
|
||||
return listOf()
|
||||
}
|
||||
}
|
||||
|
||||
private fun clearCheckedItems(){
|
||||
historyAdapter?.clearCheckeditems()
|
||||
selectedObjects.clear()
|
||||
}
|
||||
|
||||
private var simpleCallback: ItemTouchHelper.SimpleCallback =
|
||||
object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) {
|
||||
|
|
@ -672,34 +668,44 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
}
|
||||
|
||||
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
|
||||
val itemID = viewHolder.itemView.tag.toString().toLong()
|
||||
val position = viewHolder.bindingAdapterPosition
|
||||
when (direction) {
|
||||
ItemTouchHelper.LEFT -> {
|
||||
val deletedItem = historyList!![position]
|
||||
historyAdapter!!.notifyItemChanged(position)
|
||||
UiUtil.showRemoveHistoryItemDialog(deletedItem!!, requireActivity(),
|
||||
delete = { item, deleteFile ->
|
||||
lifecycleScope.launch {
|
||||
withContext(Dispatchers.IO){
|
||||
historyViewModel.delete(item, deleteFile)
|
||||
}
|
||||
lifecycleScope.launch {
|
||||
val deletedItem = withContext(Dispatchers.IO) {
|
||||
historyViewModel.getByID(itemID)
|
||||
}
|
||||
historyAdapter.notifyItemChanged(position)
|
||||
UiUtil.showRemoveHistoryItemDialog(deletedItem, requireActivity(),
|
||||
delete = { item, deleteFile ->
|
||||
lifecycleScope.launch {
|
||||
withContext(Dispatchers.IO){
|
||||
historyViewModel.delete(item, deleteFile)
|
||||
}
|
||||
|
||||
if (!deleteFile){
|
||||
Snackbar.make(recyclerView, getString(R.string.you_are_going_to_delete) + ": " + deletedItem.title, Snackbar.LENGTH_INDEFINITE)
|
||||
.setAction(getString(R.string.undo)) {
|
||||
historyViewModel.insert(deletedItem)
|
||||
}.show()
|
||||
if (!deleteFile){
|
||||
Snackbar.make(recyclerView, getString(R.string.you_are_going_to_delete) + ": " + deletedItem.title, Snackbar.LENGTH_INDEFINITE)
|
||||
.setAction(getString(R.string.undo)) {
|
||||
historyViewModel.insert(deletedItem)
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
ItemTouchHelper.RIGHT -> {
|
||||
val item = historyList!![position]!!
|
||||
historyAdapter!!.notifyItemChanged(position)
|
||||
findNavController().navigate(R.id.downloadBottomSheetDialog, bundleOf(
|
||||
Pair("result", downloadViewModel.createResultItemFromHistory(item)),
|
||||
Pair("type", item.type)
|
||||
))
|
||||
lifecycleScope.launch {
|
||||
val item = withContext(Dispatchers.IO) {
|
||||
historyViewModel.getByID(itemID)
|
||||
}
|
||||
historyAdapter.notifyItemChanged(position)
|
||||
findNavController().navigate(R.id.downloadBottomSheetDialog, bundleOf(
|
||||
Pair("result", downloadViewModel.createResultItemFromHistory(item)),
|
||||
Pair("type", item.type)
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -737,7 +743,7 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
super.onChildDraw(
|
||||
c,
|
||||
recyclerView,
|
||||
viewHolder!!,
|
||||
viewHolder,
|
||||
dX,
|
||||
dY,
|
||||
actionState,
|
||||
|
|
@ -748,7 +754,13 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
|
||||
override fun onButtonClick(itemID: Long, isPresent: Boolean) {
|
||||
if (isPresent){
|
||||
FileUtil.shareFileIntent(requireContext(), historyList!!.first { it!!.id == itemID }!!.downloadPath)
|
||||
lifecycleScope.launch {
|
||||
val item = withContext(Dispatchers.IO){
|
||||
historyViewModel.getByID(itemID)
|
||||
}
|
||||
FileUtil.shareFileIntent(requireContext(), item.downloadPath)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
companion object {
|
||||
|
|
|
|||
|
|
@ -49,6 +49,12 @@ class UpdateSettingsFragment : BaseSettingsFragment() {
|
|||
true
|
||||
}
|
||||
|
||||
|
||||
ytdlVersion!!.setOnPreferenceClickListener {
|
||||
initYTDLUpdate(editor)
|
||||
true
|
||||
}
|
||||
|
||||
updateYTDL!!.onPreferenceClickListener =
|
||||
Preference.OnPreferenceClickListener {
|
||||
initYTDLUpdate(editor)
|
||||
|
|
|
|||
|
|
@ -46,9 +46,6 @@ import com.deniscerri.ytdl.database.models.Format
|
|||
import com.deniscerri.ytdl.database.models.observeSources.ObserveSourcesItem
|
||||
import com.deniscerri.ytdl.database.repository.DownloadRepository
|
||||
import com.deniscerri.ytdl.database.repository.ObserveSourcesRepository.EveryCategory
|
||||
import com.deniscerri.ytdl.util.Extensions.isYoutubeChannelURL
|
||||
import com.deniscerri.ytdl.util.Extensions.isYoutubeURL
|
||||
import com.deniscerri.ytdl.util.Extensions.toTimePeriodsArray
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
|
|
@ -59,6 +56,7 @@ import com.neo.highlight.util.listener.HighlightTextWatcher
|
|||
import com.neo.highlight.util.scheme.ColorScheme
|
||||
import com.squareup.picasso.Picasso
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.FlowCollector
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.serialization.json.Json
|
||||
|
|
@ -526,11 +524,43 @@ object Extensions {
|
|||
}
|
||||
|
||||
fun String.extractURL() : String {
|
||||
val res = Pattern.compile("(http|ftp|https)://([\\w_-]+(?:\\.[\\w_-]+)+)([\\w.,@?^=%&:/~+#-]*[\\w@?^=%&/~+#-])").matcher(this)
|
||||
return if (res.find()){
|
||||
val res =
|
||||
Pattern.compile("(http|ftp|https)://([\\w_-]+(?:\\.[\\w_-]+)+)([\\w.,@?^=%&:/~+#-]*[\\w@?^=%&/~+#-])")
|
||||
.matcher(this)
|
||||
return if (res.find()) {
|
||||
res.group()
|
||||
}else{
|
||||
} else {
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
fun String.isURL(): Boolean {
|
||||
return Pattern.compile("(http|ftp|https)://([\\w_-]+(?:\\.[\\w_-]+)+)([\\w.,@?^=%&:/~+#-]*[\\w@?^=%&/~+#-])").matcher(this).find()
|
||||
}
|
||||
|
||||
fun <T1, T2, T3, T4, T5, T6, T7, R> combine(
|
||||
flow: Flow<T1>,
|
||||
flow2: Flow<T2>,
|
||||
flow3: Flow<T3>,
|
||||
flow4: Flow<T4>,
|
||||
flow5: Flow<T5>,
|
||||
flow6: Flow<T6>,
|
||||
flow7: Flow<T7>,
|
||||
transform: suspend (T1, T2, T3, T4, T5, T6, T7) -> R
|
||||
): Flow<R> = combine(
|
||||
flow,
|
||||
combine(flow2, flow3, ::Pair),
|
||||
combine(flow4, flow5, ::Pair),
|
||||
combine(flow6, flow7, ::Pair),
|
||||
) { t1, t2, t3, t4, ->
|
||||
transform(
|
||||
t1,
|
||||
t2.first,
|
||||
t2.second,
|
||||
t3.first,
|
||||
t3.second,
|
||||
t4.first,
|
||||
t4.second
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -191,6 +191,7 @@ object UiUtil {
|
|||
val extraCommandsSwitch : MaterialSwitch = bottomSheet.findViewById(R.id.extraCommandsSwitch)!!
|
||||
val extraCommandsAudio : CheckBox = bottomSheet.findViewById(R.id.checkbox_audio)!!
|
||||
val extraCommandsVideo : CheckBox = bottomSheet.findViewById(R.id.checkbox_video)!!
|
||||
val extraCommandsDataFetchingSwitch : MaterialSwitch = bottomSheet.findViewById(R.id.extraCommandDataFetching)!!
|
||||
val shortcutsChipGroup : ChipGroup = bottomSheet.findViewById(R.id.shortcutsChipGroup)!!
|
||||
val editShortcuts : Button = bottomSheet.findViewById(R.id.edit_shortcuts)!!
|
||||
|
||||
|
|
@ -252,6 +253,7 @@ object UiUtil {
|
|||
|
||||
if (item != null){
|
||||
preferredCommandSwitch.isChecked = item.content == sharedPreferences.getString("preferred_command_template", "")
|
||||
extraCommandsDataFetchingSwitch.isChecked = item.useAsExtraCommandDataFetching
|
||||
|
||||
extraCommandsSwitch.isChecked = item.useAsExtraCommand
|
||||
if (item.useAsExtraCommand){
|
||||
|
|
@ -307,7 +309,7 @@ object UiUtil {
|
|||
|
||||
|
||||
if (item == null){
|
||||
val t = CommandTemplate(0, title.editText!!.text.toString(), content.editText!!.text.toString(), extraCommandsSwitch.isChecked, extraCommandsAudio.isChecked, extraCommandsVideo.isChecked)
|
||||
val t = CommandTemplate(0, title.editText!!.text.toString(), content.editText!!.text.toString(), extraCommandsSwitch.isChecked, extraCommandsAudio.isChecked, extraCommandsVideo.isChecked, extraCommandsDataFetchingSwitch.isChecked)
|
||||
commandTemplateViewModel.insert(t)
|
||||
newTemplate(t)
|
||||
}else{
|
||||
|
|
@ -316,6 +318,7 @@ object UiUtil {
|
|||
item.useAsExtraCommand = extraCommandsSwitch.isChecked
|
||||
item.useAsExtraCommandAudio = extraCommandsAudio.isChecked
|
||||
item.useAsExtraCommandVideo = extraCommandsVideo.isChecked
|
||||
item.useAsExtraCommandDataFetching = extraCommandsDataFetchingSwitch.isChecked
|
||||
commandTemplateViewModel.update(item)
|
||||
newTemplate(item)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,8 +113,8 @@ class DownloadWorker(
|
|||
setForegroundAsync(ForegroundInfo(notificationID, workNotif))
|
||||
}
|
||||
|
||||
queuedItems.collectLatest { items ->
|
||||
if (this@DownloadWorker.isStopped) return@collectLatest
|
||||
queuedItems.collect { items ->
|
||||
if (this@DownloadWorker.isStopped) return@collect
|
||||
|
||||
runningYTDLInstances.clear()
|
||||
val activeDownloads = dao.getActiveDownloadsList()
|
||||
|
|
@ -126,19 +126,19 @@ class DownloadWorker(
|
|||
val useScheduler = sharedPreferences.getBoolean("use_scheduler", false)
|
||||
if (items.isEmpty() && running.isEmpty()) {
|
||||
WorkManager.getInstance(context).cancelWorkById(this@DownloadWorker.id)
|
||||
return@collectLatest
|
||||
return@collect
|
||||
}
|
||||
|
||||
if (useScheduler){
|
||||
if (items.none{it.downloadStartTime > 0L} && running.isEmpty() && !alarmScheduler.isDuringTheScheduledTime()) {
|
||||
WorkManager.getInstance(context).cancelWorkById(this@DownloadWorker.id)
|
||||
return@collectLatest
|
||||
return@collect
|
||||
}
|
||||
}
|
||||
|
||||
if (priorityItemIDs.isEmpty() && !continueAfterPriorityIds) {
|
||||
WorkManager.getInstance(context).cancelWorkById(this@DownloadWorker.id)
|
||||
return@collectLatest
|
||||
return@collect
|
||||
}
|
||||
|
||||
val concurrentDownloads = sharedPreferences.getInt("concurrent_downloads", 1) - running.size
|
||||
|
|
@ -312,6 +312,7 @@ class DownloadWorker(
|
|||
finalPaths,
|
||||
downloadItem.website,
|
||||
downloadItem.format,
|
||||
downloadItem.format.filesize,
|
||||
downloadItem.id,
|
||||
commandString)
|
||||
historyDao.insert(historyItem)
|
||||
|
|
|
|||
|
|
@ -157,6 +157,20 @@
|
|||
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
style="@style/Divider.Horizontal"
|
||||
android:layout_marginVertical="10dp" />
|
||||
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/extraCommandDataFetching"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginHorizontal="10dp"
|
||||
android:checked="false"
|
||||
android:text="@string/data_fetching_extra_command"
|
||||
android:textSize="15sp"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<View
|
||||
style="@style/Divider.Horizontal"
|
||||
android:layout_marginVertical="10dp" />
|
||||
|
|
|
|||
|
|
@ -434,6 +434,6 @@
|
|||
<string name="socket_timeout">Socket Timeout</string>
|
||||
<string name="socket_timeout_description">Time to wait before giving up, in seconds</string>
|
||||
<string name="advanced">Advanced</string>
|
||||
<string name="data_fetching_extra_commands">Data Fetching Extra Commands</string>
|
||||
<string name="data_fetching_extra_command">Data Fetching Extra Command</string>
|
||||
<string name="thumbnail">Thumbnail</string>
|
||||
</resources>
|
||||
|
|
@ -2,32 +2,27 @@
|
|||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<EditTextPreference
|
||||
android:defaultValue="default,mediaconnect"
|
||||
android:icon="@drawable/ic_code"
|
||||
android:key="youtube_player_client"
|
||||
app:useSimpleSummaryProvider="true"
|
||||
android:title="Player Client" />
|
||||
<PreferenceCategory android:title="YouTube">
|
||||
<EditTextPreference
|
||||
android:defaultValue="default,mediaconnect"
|
||||
android:icon="@drawable/ic_code"
|
||||
android:key="youtube_player_client"
|
||||
app:useSimpleSummaryProvider="true"
|
||||
android:title="Player Client" />
|
||||
|
||||
<EditTextPreference
|
||||
android:defaultValue=""
|
||||
android:icon="@drawable/ic_code"
|
||||
android:key="youtube_po_token"
|
||||
app:useSimpleSummaryProvider="true"
|
||||
android:title="PO Token" />
|
||||
<EditTextPreference
|
||||
android:defaultValue=""
|
||||
android:icon="@drawable/ic_code"
|
||||
android:key="youtube_po_token"
|
||||
app:useSimpleSummaryProvider="true"
|
||||
android:title="PO Token" />
|
||||
|
||||
<EditTextPreference
|
||||
android:defaultValue=""
|
||||
android:icon="@drawable/ic_code"
|
||||
android:key="youtube_other_extractor_args"
|
||||
app:useSimpleSummaryProvider="true"
|
||||
android:title="@string/other_youtube_extractor_args" />
|
||||
|
||||
<EditTextPreference
|
||||
android:defaultValue=""
|
||||
android:icon="@drawable/ic_terminal"
|
||||
android:key="data_fetching_extra_commands"
|
||||
app:useSimpleSummaryProvider="true"
|
||||
android:title="@string/data_fetching_extra_commands" />
|
||||
<EditTextPreference
|
||||
android:defaultValue=""
|
||||
android:icon="@drawable/ic_code"
|
||||
android:key="youtube_other_extractor_args"
|
||||
app:useSimpleSummaryProvider="true"
|
||||
android:title="@string/other_youtube_extractor_args" />
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
|
@ -2,6 +2,11 @@
|
|||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<Preference
|
||||
app:icon="@drawable/ic_info"
|
||||
app:key="version"
|
||||
app:title="@string/version"/>
|
||||
|
||||
<PreferenceCategory android:title="@string/source">
|
||||
|
||||
<Preference
|
||||
|
|
@ -35,6 +40,36 @@
|
|||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:title="@string/app">
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="true"
|
||||
android:icon="@drawable/ic_update_app"
|
||||
android:key="update_app"
|
||||
app:summary="@string/update_app_summary"
|
||||
app:title="@string/update_app" />
|
||||
|
||||
<EditTextPreference
|
||||
app:isPreferenceVisible="false"
|
||||
app:key="skip_updates"
|
||||
app:defaultValue="" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="false"
|
||||
android:icon="@drawable/ic_experiment"
|
||||
android:key="update_beta"
|
||||
app:summary="@string/update_app_beta_summary"
|
||||
app:title="@string/update_app_beta" />
|
||||
|
||||
<Preference
|
||||
app:icon="@drawable/ic_chapters"
|
||||
app:key="changelog"
|
||||
app:title="@string/changelog" />
|
||||
</PreferenceCategory>
|
||||
|
||||
|
||||
<PreferenceCategory android:title="@string/format">
|
||||
<ListPreference
|
||||
android:defaultValue="filesize"
|
||||
|
|
@ -63,41 +98,4 @@
|
|||
app:title="@string/update_formats" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:title="@string/app">
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="true"
|
||||
android:icon="@drawable/ic_update_app"
|
||||
android:key="update_app"
|
||||
app:summary="@string/update_app_summary"
|
||||
app:title="@string/update_app" />
|
||||
|
||||
<EditTextPreference
|
||||
app:isPreferenceVisible="false"
|
||||
app:key="skip_updates"
|
||||
app:defaultValue="" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:widgetLayout="@layout/preferece_material_switch"
|
||||
app:defaultValue="false"
|
||||
android:icon="@drawable/ic_experiment"
|
||||
android:key="update_beta"
|
||||
app:summary="@string/update_app_beta_summary"
|
||||
app:title="@string/update_app_beta" />
|
||||
|
||||
<Preference
|
||||
app:icon="@drawable/ic_chapters"
|
||||
app:key="changelog"
|
||||
app:title="@string/changelog" />
|
||||
|
||||
|
||||
<Preference
|
||||
app:icon="@drawable/ic_info"
|
||||
app:key="version"
|
||||
app:title="@string/version"/>
|
||||
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
||||
Loading…
Reference in a new issue