changes
- added extractor args lang when searching in yt-dlp - removed webarchive search engine since its not supported anymore - fixed terminal prematurely closing - made format auto-update on by default for new users - fixed main activity getting removed from recents when using the app with rvx - added ability to have the last used command template for the next download - fixed app crashing in landscape logs - fixed app constantly going back to home in landscape or config change. now it keeps state - add subtitle language suggestions in the subtitle dialog - made command template scroll state hold even if fragment is destroyed - added slovak sk language - fixed terminal icon being blank in white mode, and now its red - fixed share files from notification showing 2 files even though its 1 - fixed history item not being deleted from the bottom sheet - cleared outdated player urls for stale result items - added export cookies as file - added export command templates for selected templates - added icons for history details sheet chips - added markdown in the update dialog
This commit is contained in:
parent
9353e08ee9
commit
f335bbddf5
111 changed files with 1811 additions and 682 deletions
|
|
@ -4,7 +4,7 @@
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<a href="https://github.com/deniscerri/ytdlnis/blob/main/README.MD">English</a>
|
<a href="https://github.com/deniscerri/ytdlnis/blob/main/README.md">English</a>
|
||||||
|
|
|
|
||||||
Azərbaycanca
|
Azərbaycanca
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<a href="https://github.com/deniscerri/ytdlnis/blob/main/README.MD">English</a>
|
<a href="https://github.com/deniscerri/ytdlnis/blob/main/README.md">English</a>
|
||||||
|
|
|
|
||||||
Indonesia
|
Indonesia
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<a href="https://github.com/deniscerri/ytdlnis/blob/main/README.MD">English</a>
|
<a href="https://github.com/deniscerri/ytdlnis/blob/main/README.md">English</a>
|
||||||
|
|
|
|
||||||
Português
|
Português
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<a href="https://github.com/deniscerri/ytdlnis/blob/main/README.MD">English</a>
|
<a href="https://github.com/deniscerri/ytdlnis/blob/main/README.md">English</a>
|
||||||
|
|
|
|
||||||
Shqip
|
Shqip
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
|
|
||||||
<a href="https://github.com/deniscerri/ytdlnis/blob/main/README-az.md">Azərbaycanca</a>
|
<a href="https://github.com/deniscerri/ytdlnis/blob/main/README-az.md">Azərbaycanca</a>
|
||||||
|
|
|
|
||||||
<a href="https://github.com/deniscerri/ytdlnis/blob/main/README-id.MD">Indonesia</a>
|
<a href="https://github.com/deniscerri/ytdlnis/blob/main/README-id.md">Indonesia</a>
|
||||||
|
|
|
|
||||||
<a href="https://github.com/deniscerri/ytdlnis/blob/main/README-pt.md">Português</a>
|
<a href="https://github.com/deniscerri/ytdlnis/blob/main/README-pt.md">Português</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -34,7 +34,7 @@
|
||||||
[](https://t.me/ytdlnisupdates)
|
[](https://t.me/ytdlnisupdates)
|
||||||
|
|
||||||
|
|
||||||
|
### The links above are the only trusted sources of YTDLnis. Everything else is not related to me.
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -10,7 +10,7 @@ def properties = new Properties()
|
||||||
def versionMajor = 1
|
def versionMajor = 1
|
||||||
def versionMinor = 6
|
def versionMinor = 6
|
||||||
def versionPatch = 8
|
def versionPatch = 8
|
||||||
def versionBuild = 3 // bump for dogfood builds, public betas, etc.
|
def versionBuild = 4 // bump for dogfood builds, public betas, etc.
|
||||||
def versionExt = ""
|
def versionExt = ""
|
||||||
|
|
||||||
if (versionBuild > 0){
|
if (versionBuild > 0){
|
||||||
|
|
@ -188,5 +188,6 @@ dependencies {
|
||||||
implementation "com.anggrayudi:storage:1.5.5"
|
implementation "com.anggrayudi:storage:1.5.5"
|
||||||
implementation 'me.zhanghai.android.fastscroll:library:1.3.0'
|
implementation 'me.zhanghai.android.fastscroll:library:1.3.0'
|
||||||
implementation 'com.google.accompanist:accompanist-webview:0.30.1'
|
implementation 'com.google.accompanist:accompanist-webview:0.30.1'
|
||||||
implementation 'androidx.compose.material3:material3-android:1.2.0-alpha09'
|
implementation 'androidx.compose.material3:material3-android:1.2.0-alpha10'
|
||||||
|
implementation "io.noties.markwon:core:4.6.2"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
558
app/schemas/com.deniscerri.ytdlnis.data.DBManager/11.json
Normal file
558
app/schemas/com.deniscerri.ytdlnis.data.DBManager/11.json
Normal file
|
|
@ -0,0 +1,558 @@
|
||||||
|
{
|
||||||
|
"formatVersion": 1,
|
||||||
|
"database": {
|
||||||
|
"version": 11,
|
||||||
|
"identityHash": "09798517d2b7ce96999c879bcd381c7f",
|
||||||
|
"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, `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": "creationTime",
|
||||||
|
"columnName": "creationTime",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": true,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "history",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `title` TEXT NOT NULL, `author` TEXT NOT NULL, `duration` TEXT NOT NULL, `thumb` TEXT NOT NULL, `type` TEXT NOT NULL, `time` INTEGER NOT NULL, `downloadPath` TEXT NOT NULL, `website` TEXT NOT NULL, `format` TEXT NOT NULL, `downloadId` INTEGER NOT NULL DEFAULT 0, `command` TEXT NOT NULL DEFAULT '')",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "url",
|
||||||
|
"columnName": "url",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "title",
|
||||||
|
"columnName": "title",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "author",
|
||||||
|
"columnName": "author",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "duration",
|
||||||
|
"columnName": "duration",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "thumb",
|
||||||
|
"columnName": "thumb",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "type",
|
||||||
|
"columnName": "type",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "time",
|
||||||
|
"columnName": "time",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "downloadPath",
|
||||||
|
"columnName": "downloadPath",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "website",
|
||||||
|
"columnName": "website",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "format",
|
||||||
|
"columnName": "format",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "downloadId",
|
||||||
|
"columnName": "downloadId",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true,
|
||||||
|
"defaultValue": "0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "command",
|
||||||
|
"columnName": "command",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true,
|
||||||
|
"defaultValue": "''"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": true,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "downloads",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `title` TEXT NOT NULL, `author` TEXT NOT NULL, `thumb` TEXT NOT NULL, `duration` TEXT NOT NULL, `type` TEXT NOT NULL, `format` TEXT NOT NULL, `container` TEXT NOT NULL DEFAULT 'Default', `downloadSections` TEXT NOT NULL DEFAULT '', `allFormats` TEXT NOT NULL, `downloadPath` TEXT NOT NULL, `website` TEXT NOT NULL, `downloadSize` TEXT NOT NULL, `playlistTitle` TEXT NOT NULL, `audioPreferences` TEXT NOT NULL, `videoPreferences` TEXT NOT NULL, `extraCommands` TEXT NOT NULL DEFAULT '', `customFileNameTemplate` TEXT NOT NULL, `SaveThumb` INTEGER NOT NULL, `status` TEXT NOT NULL DEFAULT 'Queued', `downloadStartTime` INTEGER NOT NULL DEFAULT 0, `logID` INTEGER)",
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"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)",
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"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": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"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, '09798517d2b7ce96999c879bcd381c7f')"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -43,7 +43,7 @@
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:configChanges="smallestScreenSize|layoutDirection|locale|orientation|screenSize"
|
android:configChanges="locale"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:windowSoftInputMode="adjustPan">
|
android:windowSoftInputMode="adjustPan">
|
||||||
|
|
||||||
|
|
@ -53,7 +53,6 @@
|
||||||
android:configChanges="smallestScreenSize|layoutDirection|locale|orientation|screenSize"
|
android:configChanges="smallestScreenSize|layoutDirection|locale|orientation|screenSize"
|
||||||
android:excludeFromRecents="true"
|
android:excludeFromRecents="true"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:launchMode="singleInstance"
|
|
||||||
android:theme="@style/Theme.BottomSheet">
|
android:theme="@style/Theme.BottomSheet">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.SEND" />
|
<action android:name="android.intent.action.SEND" />
|
||||||
|
|
@ -125,7 +124,7 @@
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:configChanges="smallestScreenSize|layoutDirection|locale|orientation|screenSize"
|
android:configChanges="locale"
|
||||||
android:targetActivity=".MainActivity"
|
android:targetActivity=".MainActivity"
|
||||||
android:windowSoftInputMode="adjustPan"
|
android:windowSoftInputMode="adjustPan"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
|
|
@ -147,7 +146,7 @@
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:icon="@mipmap/ic_launcher_dark"
|
android:icon="@mipmap/ic_launcher_dark"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round_dark"
|
android:roundIcon="@mipmap/ic_launcher_round_dark"
|
||||||
android:configChanges="smallestScreenSize|layoutDirection|locale|orientation|screenSize"
|
android:configChanges="locale"
|
||||||
android:targetActivity=".MainActivity"
|
android:targetActivity=".MainActivity"
|
||||||
android:windowSoftInputMode="adjustPan">
|
android:windowSoftInputMode="adjustPan">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
|
|
@ -167,7 +166,7 @@
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:icon="@mipmap/ic_launcher_light"
|
android:icon="@mipmap/ic_launcher_light"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round_light"
|
android:roundIcon="@mipmap/ic_launcher_round_light"
|
||||||
android:configChanges="smallestScreenSize|layoutDirection|locale|orientation|screenSize"
|
android:configChanges="locale"
|
||||||
android:targetActivity=".MainActivity"
|
android:targetActivity=".MainActivity"
|
||||||
android:windowSoftInputMode="adjustPan">
|
android:windowSoftInputMode="adjustPan">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
|
|
@ -183,7 +182,7 @@
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.more.WebViewActivity"
|
android:name=".ui.more.WebViewActivity"
|
||||||
android:configChanges="smallestScreenSize|layoutDirection|locale|orientation|screenSize"
|
android:configChanges="locale"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:parentActivityName=".MainActivity"
|
android:parentActivityName=".MainActivity"
|
||||||
android:windowSoftInputMode="adjustResize">
|
android:windowSoftInputMode="adjustResize">
|
||||||
|
|
|
||||||
|
|
@ -45,11 +45,9 @@ import com.deniscerri.ytdlnis.ui.downloadcard.DownloadBottomSheetDialog
|
||||||
import com.deniscerri.ytdlnis.ui.more.settings.SettingsActivity
|
import com.deniscerri.ytdlnis.ui.more.settings.SettingsActivity
|
||||||
import com.deniscerri.ytdlnis.util.FileUtil
|
import com.deniscerri.ytdlnis.util.FileUtil
|
||||||
import com.deniscerri.ytdlnis.util.ThemeUtil
|
import com.deniscerri.ytdlnis.util.ThemeUtil
|
||||||
import com.deniscerri.ytdlnis.util.UiUtil
|
|
||||||
import com.deniscerri.ytdlnis.util.UpdateUtil
|
import com.deniscerri.ytdlnis.util.UpdateUtil
|
||||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.elevation.SurfaceColors
|
|
||||||
import com.google.android.material.navigation.NavigationBarView
|
import com.google.android.material.navigation.NavigationBarView
|
||||||
import com.google.android.material.navigation.NavigationView
|
import com.google.android.material.navigation.NavigationView
|
||||||
import com.google.android.material.navigationrail.NavigationRailView
|
import com.google.android.material.navigationrail.NavigationRailView
|
||||||
|
|
@ -65,7 +63,6 @@ import java.io.BufferedReader
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.InputStreamReader
|
import java.io.InputStreamReader
|
||||||
import java.io.Reader
|
import java.io.Reader
|
||||||
import java.net.URI
|
|
||||||
import java.nio.charset.Charset
|
import java.nio.charset.Charset
|
||||||
import java.nio.charset.StandardCharsets
|
import java.nio.charset.StandardCharsets
|
||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
|
|
@ -81,7 +78,6 @@ class MainActivity : BaseActivity() {
|
||||||
private lateinit var navigationView: View
|
private lateinit var navigationView: View
|
||||||
private lateinit var navHostFragment : NavHostFragment
|
private lateinit var navHostFragment : NavHostFragment
|
||||||
private lateinit var navController : NavController
|
private lateinit var navController : NavController
|
||||||
private lateinit var sharedPreferences: SharedPreferences
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
@ -93,9 +89,7 @@ class MainActivity : BaseActivity() {
|
||||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||||
preferences = PreferenceManager.getDefaultSharedPreferences(context)
|
preferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
|
||||||
if (preferences.getBoolean("incognito", false)){
|
if (preferences.getBoolean("incognito", false)) resultViewModel.deleteAll()
|
||||||
resultViewModel.deleteAll()
|
|
||||||
}
|
|
||||||
|
|
||||||
askPermissions()
|
askPermissions()
|
||||||
checkUpdate()
|
checkUpdate()
|
||||||
|
|
@ -120,17 +114,17 @@ class MainActivity : BaseActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
|
if (savedInstanceState == null){
|
||||||
|
val graph = navController.navInflater.inflate(R.navigation.nav_graph)
|
||||||
|
graph.setStartDestination(R.id.homeFragment)
|
||||||
|
when(preferences.getString("start_destination", "")) {
|
||||||
|
"History" -> graph.setStartDestination(R.id.historyFragment)
|
||||||
|
"More" -> if (navigationView is NavigationBarView) graph.setStartDestination(R.id.moreFragment)
|
||||||
|
}
|
||||||
|
|
||||||
val graph = navController.navInflater.inflate(R.navigation.nav_graph)
|
navController.graph = graph
|
||||||
graph.setStartDestination(R.id.homeFragment)
|
|
||||||
when(sharedPreferences.getString("start_destination", "")) {
|
|
||||||
"History" -> graph.setStartDestination(R.id.historyFragment)
|
|
||||||
"More" -> if (navigationView is NavigationBarView) graph.setStartDestination(R.id.moreFragment)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
navController.graph = graph
|
|
||||||
|
|
||||||
if (navigationView is NavigationBarView){
|
if (navigationView is NavigationBarView){
|
||||||
(navigationView as NavigationBarView).setupWithNavController(navController)
|
(navigationView as NavigationBarView).setupWithNavController(navController)
|
||||||
(navigationView as NavigationBarView).setOnItemReselectedListener {
|
(navigationView as NavigationBarView).setOnItemReselectedListener {
|
||||||
|
|
@ -164,7 +158,7 @@ class MainActivity : BaseActivity() {
|
||||||
(navigationView as NavigationView).setupWithNavController(navController)
|
(navigationView as NavigationView).setupWithNavController(navController)
|
||||||
//terminate button
|
//terminate button
|
||||||
(navigationView as NavigationView).menu.getItem(7).setOnMenuItemClickListener {
|
(navigationView as NavigationView).menu.getItem(7).setOnMenuItemClickListener {
|
||||||
if (sharedPreferences.getBoolean("ask_terminate_app", true)){
|
if (preferences.getBoolean("ask_terminate_app", true)){
|
||||||
var doNotShowAgain = false
|
var doNotShowAgain = false
|
||||||
val terminateDialog = MaterialAlertDialogBuilder(this)
|
val terminateDialog = MaterialAlertDialogBuilder(this)
|
||||||
terminateDialog.setTitle(getString(R.string.confirm_delete_history))
|
terminateDialog.setTitle(getString(R.string.confirm_delete_history))
|
||||||
|
|
@ -188,7 +182,7 @@ class MainActivity : BaseActivity() {
|
||||||
runBlocking {
|
runBlocking {
|
||||||
job.join()
|
job.join()
|
||||||
if (doNotShowAgain){
|
if (doNotShowAgain){
|
||||||
sharedPreferences.edit().putBoolean("ask_terminate_app", false).apply()
|
preferences.edit().putBoolean("ask_terminate_app", false).apply()
|
||||||
}
|
}
|
||||||
finishAndRemoveTask()
|
finishAndRemoveTask()
|
||||||
finishAffinity()
|
finishAffinity()
|
||||||
|
|
@ -212,9 +206,6 @@ class MainActivity : BaseActivity() {
|
||||||
|
|
||||||
(navigationView as NavigationView).getHeaderView(0).findViewById<TextView>(R.id.title).text = ThemeUtil.getStyledAppName(this)
|
(navigationView as NavigationView).getHeaderView(0).findViewById<TextView>(R.id.title).text = ThemeUtil.getStyledAppName(this)
|
||||||
}
|
}
|
||||||
cookieViewModel.updateCookiesFile()
|
|
||||||
val intent = intent
|
|
||||||
handleIntents(intent)
|
|
||||||
|
|
||||||
navController.addOnDestinationChangedListener { _, destination, _ ->
|
navController.addOnDestinationChangedListener { _, destination, _ ->
|
||||||
if (navigationView is NavigationBarView){
|
if (navigationView is NavigationBarView){
|
||||||
|
|
@ -233,12 +224,15 @@ class MainActivity : BaseActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
when(preferences.getString("start_destination", "")) {
|
||||||
when(sharedPreferences.getString("start_destination", "")) {
|
"Queue" -> if (savedInstanceState == null) navController.navigate(R.id.downloadQueueMainFragment)
|
||||||
"Queue" -> navController.navigate(R.id.downloadQueueMainFragment)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sharedPreferences.getBoolean("auto_update_ytdlp", false)){
|
cookieViewModel.updateCookiesFile()
|
||||||
|
val intent = intent
|
||||||
|
handleIntents(intent)
|
||||||
|
|
||||||
|
if (preferences.getBoolean("auto_update_ytdlp", false)){
|
||||||
CoroutineScope(SupervisorJob()).launch(Dispatchers.IO) {
|
CoroutineScope(SupervisorJob()).launch(Dispatchers.IO) {
|
||||||
if(DBManager.getInstance(this@MainActivity).downloadDao.getDownloadsCountByStatus(listOf("Active", "Queued")) == 0){
|
if(DBManager.getInstance(this@MainActivity).downloadDao.getDownloadsCountByStatus(listOf("Active", "Queued")) == 0){
|
||||||
if (UpdateUtil(this@MainActivity).updateYoutubeDL() == YoutubeDL.UpdateStatus.DONE) {
|
if (UpdateUtil(this@MainActivity).updateYoutubeDL() == YoutubeDL.UpdateStatus.DONE) {
|
||||||
|
|
@ -251,8 +245,8 @@ class MainActivity : BaseActivity() {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
override fun onSaveInstanceState(savedInstanceState: Bundle) {
|
override fun onSaveInstanceState(savedInstanceState: Bundle) {
|
||||||
super.onSaveInstanceState(savedInstanceState)
|
super.onSaveInstanceState(savedInstanceState)
|
||||||
savedInstanceState.putBundle("nav_state", navController.saveState())
|
savedInstanceState.putBundle("nav_state", navController.saveState())
|
||||||
|
|
@ -489,10 +483,6 @@ class MainActivity : BaseActivity() {
|
||||||
}
|
}
|
||||||
dialog.show()
|
dialog.show()
|
||||||
}
|
}
|
||||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
|
||||||
startActivity(Intent(this, MainActivity::class.java))
|
|
||||||
super.onConfigurationChanged(newConfig)
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "MainActivity"
|
private const val TAG = "MainActivity"
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,6 @@ import com.deniscerri.ytdlnis.database.models.Format
|
||||||
import com.deniscerri.ytdlnis.database.models.VideoPreferences
|
import com.deniscerri.ytdlnis.database.models.VideoPreferences
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import com.google.gson.reflect.TypeToken
|
|
||||||
import java.lang.reflect.Type
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.Calendar
|
|
||||||
import java.util.Locale
|
|
||||||
|
|
||||||
|
|
||||||
class Converters {
|
class Converters {
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,9 @@
|
||||||
package com.deniscerri.ytdlnis.database
|
package com.deniscerri.ytdlnis.database
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.paging.Pager
|
|
||||||
import androidx.paging.PagingConfig
|
|
||||||
import androidx.paging.PagingData
|
|
||||||
import androidx.paging.PagingSource
|
|
||||||
import androidx.room.*
|
import androidx.room.*
|
||||||
import com.deniscerri.ytdlnis.database.dao.*
|
import com.deniscerri.ytdlnis.database.dao.*
|
||||||
import com.deniscerri.ytdlnis.database.models.*
|
import com.deniscerri.ytdlnis.database.models.*
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
|
|
||||||
@TypeConverters(Converters::class)
|
@TypeConverters(Converters::class)
|
||||||
@Database(
|
@Database(
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ package com.deniscerri.ytdlnis.database.dao
|
||||||
|
|
||||||
import androidx.room.*
|
import androidx.room.*
|
||||||
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
||||||
import com.deniscerri.ytdlnis.database.models.HistoryItem
|
|
||||||
import com.deniscerri.ytdlnis.database.models.TemplateShortcut
|
import com.deniscerri.ytdlnis.database.models.TemplateShortcut
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
|
@ -48,10 +47,13 @@ interface CommandTemplateDao {
|
||||||
fun getTotalShortcutNumber() : Int
|
fun getTotalShortcutNumber() : Int
|
||||||
|
|
||||||
@Query("SELECT * FROM commandTemplates WHERE id=:id LIMIT 1")
|
@Query("SELECT * FROM commandTemplates WHERE id=:id LIMIT 1")
|
||||||
fun getTemplate(id: Long) : CommandTemplate
|
fun getTemplate(id: Long) : CommandTemplate?
|
||||||
|
|
||||||
|
@Query("SELECT * FROM commandTemplates WHERE content=:content LIMIT 1")
|
||||||
|
fun getTemplateByContent(content: String) : CommandTemplate?
|
||||||
|
|
||||||
@Query("SELECT * FROM commandTemplates ORDER BY id DESC LIMIT 1")
|
@Query("SELECT * FROM commandTemplates ORDER BY id DESC LIMIT 1")
|
||||||
fun getFirst() : CommandTemplate
|
fun getFirst() : CommandTemplate?
|
||||||
|
|
||||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||||
suspend fun insert(item: CommandTemplate)
|
suspend fun insert(item: CommandTemplate)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package com.deniscerri.ytdlnis.database.dao
|
package com.deniscerri.ytdlnis.database.dao
|
||||||
|
|
||||||
import androidx.room.*
|
import androidx.room.*
|
||||||
import com.deniscerri.ytdlnis.database.models.CookieItem
|
|
||||||
import com.deniscerri.ytdlnis.database.models.LogItem
|
import com.deniscerri.ytdlnis.database.models.LogItem
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,6 @@
|
||||||
package com.deniscerri.ytdlnis.database.dao
|
package com.deniscerri.ytdlnis.database.dao
|
||||||
|
|
||||||
import androidx.paging.PagingSource
|
|
||||||
import androidx.room.*
|
import androidx.room.*
|
||||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
|
||||||
import com.deniscerri.ytdlnis.database.models.DownloadItemSimple
|
|
||||||
import com.deniscerri.ytdlnis.database.models.Format
|
|
||||||
import com.deniscerri.ytdlnis.database.models.TerminalItem
|
import com.deniscerri.ytdlnis.database.models.TerminalItem
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
|
@ -34,11 +30,12 @@ interface TerminalDao {
|
||||||
val log = t.log ?: ""
|
val log = t.log ?: ""
|
||||||
val lines = log.split("\n")
|
val lines = log.split("\n")
|
||||||
//clean dublicate progress + add newline
|
//clean dublicate progress + add newline
|
||||||
val l = if (listOf(line, lines.last()).all { it.contains("[download")}){
|
var newLine = line
|
||||||
lines.dropLast(1).joinToString("\n")
|
if (newLine.contains("[download")){
|
||||||
}else{
|
newLine = "[download]" + line.split("[download]").last()
|
||||||
log
|
}
|
||||||
} + "\n${line}"
|
|
||||||
|
val l = lines.dropLastWhile { it.contains("[download") }.joinToString("\n") + "\n${newLine}"
|
||||||
|
|
||||||
updateTerminalLog(l, id)
|
updateTerminalLog(l, id)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ package com.deniscerri.ytdlnis.database.models
|
||||||
import androidx.room.ColumnInfo
|
import androidx.room.ColumnInfo
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
|
||||||
|
|
||||||
@Entity(tableName = "downloads")
|
@Entity(tableName = "downloads")
|
||||||
data class DownloadItemSimple(
|
data class DownloadItemSimple(
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ package com.deniscerri.ytdlnis.database.models
|
||||||
import com.google.gson.annotations.SerializedName
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
data class GithubRelease(
|
data class GithubRelease(
|
||||||
|
@SerializedName(value = "html_url")
|
||||||
|
val html_url: String,
|
||||||
@SerializedName(value = "tag_name")
|
@SerializedName(value = "tag_name")
|
||||||
var tag_name: String,
|
var tag_name: String,
|
||||||
@SerializedName(value = "body")
|
@SerializedName(value = "body")
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
package com.deniscerri.ytdlnis.database.models
|
package com.deniscerri.ytdlnis.database.models
|
||||||
|
|
||||||
import androidx.room.ColumnInfo
|
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ package com.deniscerri.ytdlnis.database.models
|
||||||
import androidx.room.ColumnInfo
|
import androidx.room.ColumnInfo
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
|
||||||
|
|
||||||
@Entity(tableName = "terminalDownloads")
|
@Entity(tableName = "terminalDownloads")
|
||||||
data class TerminalItem(
|
data class TerminalItem(
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
package com.deniscerri.ytdlnis.database.repository
|
package com.deniscerri.ytdlnis.database.repository
|
||||||
|
|
||||||
import androidx.lifecycle.LiveData
|
|
||||||
import com.deniscerri.ytdlnis.database.DBManager
|
import com.deniscerri.ytdlnis.database.DBManager
|
||||||
import com.deniscerri.ytdlnis.database.dao.CommandTemplateDao
|
import com.deniscerri.ytdlnis.database.dao.CommandTemplateDao
|
||||||
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
||||||
import com.deniscerri.ytdlnis.database.models.HistoryItem
|
|
||||||
import com.deniscerri.ytdlnis.database.models.TemplateShortcut
|
import com.deniscerri.ytdlnis.database.models.TemplateShortcut
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
|
@ -37,7 +35,7 @@ class CommandTemplateRepository(private val commandDao: CommandTemplateDao) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getItem(id: Long) : CommandTemplate {
|
fun getItem(id: Long) : CommandTemplate {
|
||||||
return commandDao.getTemplate(id)
|
return commandDao.getTemplate(id)!!
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun insert(item: CommandTemplate){
|
suspend fun insert(item: CommandTemplate){
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
package com.deniscerri.ytdlnis.database.repository
|
package com.deniscerri.ytdlnis.database.repository
|
||||||
|
|
||||||
import androidx.lifecycle.LiveData
|
|
||||||
import com.deniscerri.ytdlnis.database.dao.CookieDao
|
import com.deniscerri.ytdlnis.database.dao.CookieDao
|
||||||
import com.deniscerri.ytdlnis.database.models.CookieItem
|
import com.deniscerri.ytdlnis.database.models.CookieItem
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package com.deniscerri.ytdlnis.database.repository
|
package com.deniscerri.ytdlnis.database.repository
|
||||||
|
|
||||||
import com.deniscerri.ytdlnis.database.dao.LogDao
|
import com.deniscerri.ytdlnis.database.dao.LogDao
|
||||||
import com.deniscerri.ytdlnis.database.models.CookieItem
|
|
||||||
import com.deniscerri.ytdlnis.database.models.LogItem
|
import com.deniscerri.ytdlnis.database.models.LogItem
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
|
@ -16,6 +15,10 @@ class LogRepository(private val logDao: LogDao) {
|
||||||
return logDao.getLogFlowByID(id)
|
return logDao.getLogFlowByID(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getLogByID(id: Long) : LogItem? {
|
||||||
|
return logDao.getByID(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
suspend fun insert(item: LogItem) : Long{
|
suspend fun insert(item: LogItem) : Long{
|
||||||
return logDao.insert(item)
|
return logDao.insert(item)
|
||||||
|
|
@ -31,13 +34,17 @@ class LogRepository(private val logDao: LogDao) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getItem(id: Long) : LogItem{
|
fun getItem(id: Long) : LogItem{
|
||||||
return logDao.getByID(id);
|
return logDao.getByID(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun update(newLine: String, id: Long){
|
suspend fun update(line: String, id: Long){
|
||||||
val item = getItem(id)
|
runCatching {
|
||||||
item.content += "${newLine}\n"
|
val item = getItem(id)
|
||||||
logDao.update(item)
|
val log = item.content
|
||||||
|
//clean duplicate progress + add newline
|
||||||
|
//item.content = log.replace("(?s:.*\\n)?\\K\\[download\\]( *?)(\\d)(.*?)\\n(?!.*\\[download\\]( *?)(\\d)(.*?)\\n)".toRegex()).replac { it.contains("[download") }.joinToString("\n") + "\n${line}"
|
||||||
|
logDao.update(item)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package com.deniscerri.ytdlnis.database.repository
|
package com.deniscerri.ytdlnis.database.repository
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.Log
|
|
||||||
import com.deniscerri.ytdlnis.database.dao.ResultDao
|
import com.deniscerri.ytdlnis.database.dao.ResultDao
|
||||||
import com.deniscerri.ytdlnis.database.models.ResultItem
|
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||||
import com.deniscerri.ytdlnis.util.InfoUtil
|
import com.deniscerri.ytdlnis.util.InfoUtil
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,8 @@ import androidx.lifecycle.viewModelScope
|
||||||
import com.deniscerri.ytdlnis.database.DBManager
|
import com.deniscerri.ytdlnis.database.DBManager
|
||||||
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
||||||
import com.deniscerri.ytdlnis.database.models.CommandTemplateExport
|
import com.deniscerri.ytdlnis.database.models.CommandTemplateExport
|
||||||
import com.deniscerri.ytdlnis.database.models.HistoryItem
|
|
||||||
import com.deniscerri.ytdlnis.database.models.TemplateShortcut
|
import com.deniscerri.ytdlnis.database.models.TemplateShortcut
|
||||||
import com.deniscerri.ytdlnis.database.repository.CommandTemplateRepository
|
import com.deniscerri.ytdlnis.database.repository.CommandTemplateRepository
|
||||||
import com.deniscerri.ytdlnis.database.repository.HistoryRepository
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
@ -28,8 +26,9 @@ class CommandTemplateViewModel(private val application: Application) : AndroidVi
|
||||||
val sortOrder = MutableLiveData(DBManager.SORTING.DESC)
|
val sortOrder = MutableLiveData(DBManager.SORTING.DESC)
|
||||||
val sortType = MutableLiveData(CommandTemplateRepository.CommandTemplateSortType.DATE)
|
val sortType = MutableLiveData(CommandTemplateRepository.CommandTemplateSortType.DATE)
|
||||||
private val queryFilter = MutableLiveData("")
|
private val queryFilter = MutableLiveData("")
|
||||||
private var _items = MediatorLiveData<List<CommandTemplate>>()
|
|
||||||
val allItems: LiveData<List<CommandTemplate>>
|
val allItems: LiveData<List<CommandTemplate>>
|
||||||
|
private var _items = MediatorLiveData<List<CommandTemplate>>()
|
||||||
|
|
||||||
val shortcuts : LiveData<List<TemplateShortcut>>
|
val shortcuts : LiveData<List<TemplateShortcut>>
|
||||||
private val jsonFormat = Json { prettyPrint = true }
|
private val jsonFormat = Json { prettyPrint = true }
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import android.content.ClipboardManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.database.sqlite.SQLiteDatabase
|
import android.database.sqlite.SQLiteDatabase
|
||||||
import android.database.sqlite.SQLiteDatabase.OPEN_READONLY
|
import android.database.sqlite.SQLiteDatabase.OPEN_READONLY
|
||||||
|
import android.os.Environment
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.webkit.CookieManager
|
import android.webkit.CookieManager
|
||||||
import androidx.lifecycle.AndroidViewModel
|
import androidx.lifecycle.AndroidViewModel
|
||||||
|
|
@ -17,6 +18,7 @@ import com.deniscerri.ytdlnis.database.DBManager
|
||||||
import com.deniscerri.ytdlnis.database.models.CookieItem
|
import com.deniscerri.ytdlnis.database.models.CookieItem
|
||||||
import com.deniscerri.ytdlnis.database.repository.CookieRepository
|
import com.deniscerri.ytdlnis.database.repository.CookieRepository
|
||||||
import com.deniscerri.ytdlnis.ui.more.WebViewActivity
|
import com.deniscerri.ytdlnis.ui.more.WebViewActivity
|
||||||
|
import com.deniscerri.ytdlnis.util.FileUtil
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
@ -169,4 +171,18 @@ class CookieViewModel(private val application: Application) : AndroidViewModel(a
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun exportToFile(exported: (File?) -> Unit) {
|
||||||
|
try{
|
||||||
|
val cookieFile = File(application.cacheDir, "cookies.txt")
|
||||||
|
if (!cookieFile.exists()) updateCookiesFile()
|
||||||
|
|
||||||
|
val downloads = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).absolutePath + File.separator + "YTDLnis_Cookies.txt")
|
||||||
|
val file = cookieFile.copyTo(downloads, true)
|
||||||
|
exported(file)
|
||||||
|
}catch (e: Exception){
|
||||||
|
e.printStackTrace()
|
||||||
|
exported(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -6,13 +6,11 @@ import android.content.SharedPreferences
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.net.ConnectivityManager
|
import android.net.ConnectivityManager
|
||||||
import android.os.Bundle
|
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.util.DisplayMetrics
|
import android.util.DisplayMetrics
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.lifecycle.AndroidViewModel
|
import androidx.lifecycle.AndroidViewModel
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
|
||||||
import androidx.lifecycle.asLiveData
|
import androidx.lifecycle.asLiveData
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import androidx.paging.PagingData
|
import androidx.paging.PagingData
|
||||||
|
|
@ -29,7 +27,6 @@ import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.database.DBManager
|
import com.deniscerri.ytdlnis.database.DBManager
|
||||||
import com.deniscerri.ytdlnis.database.dao.CommandTemplateDao
|
import com.deniscerri.ytdlnis.database.dao.CommandTemplateDao
|
||||||
import com.deniscerri.ytdlnis.database.dao.DownloadDao
|
import com.deniscerri.ytdlnis.database.dao.DownloadDao
|
||||||
import com.deniscerri.ytdlnis.database.dao.HistoryDao
|
|
||||||
import com.deniscerri.ytdlnis.database.dao.ResultDao
|
import com.deniscerri.ytdlnis.database.dao.ResultDao
|
||||||
import com.deniscerri.ytdlnis.database.models.AudioPreferences
|
import com.deniscerri.ytdlnis.database.models.AudioPreferences
|
||||||
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
||||||
|
|
@ -272,7 +269,10 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
||||||
}
|
}
|
||||||
|
|
||||||
if (preferredAudioFormats.isEmpty()){
|
if (preferredAudioFormats.isEmpty()){
|
||||||
preferredAudioFormats.add(getFormat(resultItem.formats, Type.audio).format_id)
|
val audioF = getFormat(resultItem.formats, Type.audio)
|
||||||
|
if (!infoUtil.getGenericAudioFormats(resources).contains(audioF)){
|
||||||
|
preferredAudioFormats.add(audioF.format_id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val videoPreferences = VideoPreferences(
|
val videoPreferences = VideoPreferences(
|
||||||
|
|
@ -465,7 +465,12 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
val c = commandTemplateDao.getFirst()
|
val lastUsedCommandTemplate = sharedPreferences.getString("lastCommandTemplateUsed", "")!!
|
||||||
|
val c = if (lastUsedCommandTemplate.isBlank()){
|
||||||
|
commandTemplateDao.getFirst() ?: CommandTemplate(0,"","", false)
|
||||||
|
}else{
|
||||||
|
commandTemplateDao.getTemplateByContent(lastUsedCommandTemplate) ?: CommandTemplate(0, "", lastUsedCommandTemplate, false)
|
||||||
|
}
|
||||||
return generateCommandFormat(c)
|
return generateCommandFormat(c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -474,7 +479,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
||||||
fun generateCommandFormat(c: CommandTemplate) : Format {
|
fun generateCommandFormat(c: CommandTemplate) : Format {
|
||||||
return Format(
|
return Format(
|
||||||
c.title,
|
c.title,
|
||||||
"",
|
c.id.toString(),
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
|
|
@ -486,7 +491,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
||||||
|
|
||||||
|
|
||||||
fun getLatestCommandTemplateAsFormat() : Format {
|
fun getLatestCommandTemplateAsFormat() : Format {
|
||||||
val t = commandTemplateDao.getFirst()
|
val t = commandTemplateDao.getFirst()!!
|
||||||
return Format(t.title, "", "", "", "", 0, t.content)
|
return Format(t.title, "", "", "", "", 0, t.content)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -591,7 +596,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
||||||
startDownloadWorker(emptyList())
|
startDownloadWorker(emptyList())
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun queueDownloads(items: List<DownloadItem>, ignoreDuplicate : Boolean = false) {
|
suspend fun queueDownloads(items: List<DownloadItem>, ignoreDuplicate : Boolean = false) = CoroutineScope(Dispatchers.IO).launch {
|
||||||
val context = App.instance
|
val context = App.instance
|
||||||
val alarmScheduler = AlarmScheduler(context)
|
val alarmScheduler = AlarmScheduler(context)
|
||||||
val activeAndQueuedDownloads = withContext(Dispatchers.IO){
|
val activeAndQueuedDownloads = withContext(Dispatchers.IO){
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ import com.deniscerri.ytdlnis.database.models.HistoryItem
|
||||||
import com.deniscerri.ytdlnis.database.repository.HistoryRepository
|
import com.deniscerri.ytdlnis.database.repository.HistoryRepository
|
||||||
import com.deniscerri.ytdlnis.database.DBManager.SORTING
|
import com.deniscerri.ytdlnis.database.DBManager.SORTING
|
||||||
import com.deniscerri.ytdlnis.database.repository.HistoryRepository.HistorySortType
|
import com.deniscerri.ytdlnis.database.repository.HistoryRepository.HistorySortType
|
||||||
import com.deniscerri.ytdlnis.util.FileUtil
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
|
@ -23,6 +22,7 @@ class HistoryViewModel(application: Application) : AndroidViewModel(application)
|
||||||
val websiteFilter = MutableLiveData("")
|
val websiteFilter = MutableLiveData("")
|
||||||
private val queryFilter = MutableLiveData("")
|
private val queryFilter = MutableLiveData("")
|
||||||
private val formatFilter = MutableLiveData("")
|
private val formatFilter = MutableLiveData("")
|
||||||
|
|
||||||
val allItems : LiveData<List<HistoryItem>>
|
val allItems : LiveData<List<HistoryItem>>
|
||||||
private var _items = MediatorLiveData<List<HistoryItem>>()
|
private var _items = MediatorLiveData<List<HistoryItem>>()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package com.deniscerri.ytdlnis.database.viewmodel
|
package com.deniscerri.ytdlnis.database.viewmodel
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.util.Log
|
|
||||||
import androidx.lifecycle.AndroidViewModel
|
import androidx.lifecycle.AndroidViewModel
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.asLiveData
|
import androidx.lifecycle.asLiveData
|
||||||
|
|
@ -11,7 +10,6 @@ import com.deniscerri.ytdlnis.database.models.LogItem
|
||||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||||
import com.deniscerri.ytdlnis.database.repository.LogRepository
|
import com.deniscerri.ytdlnis.database.repository.LogRepository
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class LogViewModel(private val application: Application) : AndroidViewModel(application) {
|
class LogViewModel(private val application: Application) : AndroidViewModel(application) {
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import android.util.Log
|
||||||
import android.util.Patterns
|
import android.util.Patterns
|
||||||
import androidx.lifecycle.AndroidViewModel
|
import androidx.lifecycle.AndroidViewModel
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
|
||||||
import androidx.lifecycle.asLiveData
|
import androidx.lifecycle.asLiveData
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
|
|
@ -17,10 +16,8 @@ import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||||
import com.deniscerri.ytdlnis.database.models.SearchHistoryItem
|
import com.deniscerri.ytdlnis.database.models.SearchHistoryItem
|
||||||
import com.deniscerri.ytdlnis.database.repository.ResultRepository
|
import com.deniscerri.ytdlnis.database.repository.ResultRepository
|
||||||
import com.deniscerri.ytdlnis.database.repository.SearchHistoryRepository
|
import com.deniscerri.ytdlnis.database.repository.SearchHistoryRepository
|
||||||
import com.deniscerri.ytdlnis.util.UiUtil
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
|
||||||
|
|
@ -1,62 +1,21 @@
|
||||||
package com.deniscerri.ytdlnis.database.viewmodel
|
package com.deniscerri.ytdlnis.database.viewmodel
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.content.Context
|
|
||||||
import android.content.SharedPreferences
|
|
||||||
import android.content.res.Configuration
|
|
||||||
import android.content.res.Resources
|
|
||||||
import android.net.ConnectivityManager
|
|
||||||
import android.os.Looper
|
|
||||||
import android.util.DisplayMetrics
|
|
||||||
import android.util.Log
|
|
||||||
import android.widget.Toast
|
|
||||||
import androidx.lifecycle.AndroidViewModel
|
import androidx.lifecycle.AndroidViewModel
|
||||||
import androidx.lifecycle.LiveData
|
|
||||||
import androidx.lifecycle.asLiveData
|
|
||||||
import androidx.lifecycle.viewModelScope
|
|
||||||
import androidx.paging.PagingData
|
|
||||||
import androidx.preference.PreferenceManager
|
|
||||||
import androidx.work.Constraints
|
|
||||||
import androidx.work.Data
|
import androidx.work.Data
|
||||||
import androidx.work.ExistingWorkPolicy
|
import androidx.work.ExistingWorkPolicy
|
||||||
import androidx.work.NetworkType
|
|
||||||
import androidx.work.OneTimeWorkRequestBuilder
|
import androidx.work.OneTimeWorkRequestBuilder
|
||||||
import androidx.work.WorkInfo
|
|
||||||
import androidx.work.WorkManager
|
import androidx.work.WorkManager
|
||||||
import androidx.work.await
|
|
||||||
import com.deniscerri.ytdlnis.App
|
|
||||||
import com.deniscerri.ytdlnis.R
|
|
||||||
import com.deniscerri.ytdlnis.database.DBManager
|
import com.deniscerri.ytdlnis.database.DBManager
|
||||||
import com.deniscerri.ytdlnis.database.dao.CommandTemplateDao
|
|
||||||
import com.deniscerri.ytdlnis.database.dao.DownloadDao
|
|
||||||
import com.deniscerri.ytdlnis.database.dao.ResultDao
|
|
||||||
import com.deniscerri.ytdlnis.database.dao.TerminalDao
|
import com.deniscerri.ytdlnis.database.dao.TerminalDao
|
||||||
import com.deniscerri.ytdlnis.database.models.AudioPreferences
|
|
||||||
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
|
||||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
|
||||||
import com.deniscerri.ytdlnis.database.models.DownloadItemSimple
|
|
||||||
import com.deniscerri.ytdlnis.database.models.Format
|
|
||||||
import com.deniscerri.ytdlnis.database.models.HistoryItem
|
|
||||||
import com.deniscerri.ytdlnis.database.models.ResultItem
|
|
||||||
import com.deniscerri.ytdlnis.database.models.TerminalItem
|
import com.deniscerri.ytdlnis.database.models.TerminalItem
|
||||||
import com.deniscerri.ytdlnis.database.models.VideoPreferences
|
|
||||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
|
||||||
import com.deniscerri.ytdlnis.util.FileUtil
|
|
||||||
import com.deniscerri.ytdlnis.util.InfoUtil
|
|
||||||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
import com.deniscerri.ytdlnis.util.NotificationUtil
|
||||||
import com.deniscerri.ytdlnis.work.AlarmScheduler
|
|
||||||
import com.deniscerri.ytdlnis.work.DownloadWorker
|
|
||||||
import com.deniscerri.ytdlnis.work.TerminalDownloadWorker
|
import com.deniscerri.ytdlnis.work.TerminalDownloadWorker
|
||||||
import com.google.gson.Gson
|
|
||||||
import com.yausername.youtubedl_android.YoutubeDL
|
import com.yausername.youtubedl_android.YoutubeDL
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import java.io.File
|
|
||||||
import java.util.Locale
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
|
|
||||||
|
|
||||||
class TerminalViewModel(private val application: Application) : AndroidViewModel(application) {
|
class TerminalViewModel(private val application: Application) : AndroidViewModel(application) {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ package com.deniscerri.ytdlnis.receiver
|
||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.util.Log
|
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import com.deniscerri.ytdlnis.database.DBManager
|
import com.deniscerri.ytdlnis.database.DBManager
|
||||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||||
|
|
@ -13,9 +12,7 @@ import com.yausername.youtubedl_android.YoutubeDL
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
import java.util.Locale
|
|
||||||
|
|
||||||
class AlarmStopReceiver : BroadcastReceiver() {
|
class AlarmStopReceiver : BroadcastReceiver() {
|
||||||
override fun onReceive(p0: Context?, p1: Intent?) {
|
override fun onReceive(p0: Context?, p1: Intent?) {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.work.WorkManager
|
|
||||||
import com.deniscerri.ytdlnis.database.DBManager
|
import com.deniscerri.ytdlnis.database.DBManager
|
||||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
import com.deniscerri.ytdlnis.util.NotificationUtil
|
||||||
|
|
@ -12,7 +11,6 @@ import com.yausername.youtubedl_android.YoutubeDL
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
|
|
||||||
class CancelDownloadNotificationReceiver : BroadcastReceiver() {
|
class CancelDownloadNotificationReceiver : BroadcastReceiver() {
|
||||||
override fun onReceive(c: Context, intent: Intent) {
|
override fun onReceive(c: Context, intent: Intent) {
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,7 @@ package com.deniscerri.ytdlnis.receiver
|
||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.util.Log
|
|
||||||
import androidx.work.WorkManager
|
import androidx.work.WorkManager
|
||||||
import com.deniscerri.ytdlnis.database.DBManager
|
|
||||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
|
||||||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
|
||||||
import com.yausername.youtubedl_android.YoutubeDL
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
|
|
||||||
class CancelWorkReceiver : BroadcastReceiver() {
|
class CancelWorkReceiver : BroadcastReceiver() {
|
||||||
override fun onReceive(c: Context, intent: Intent) {
|
override fun onReceive(c: Context, intent: Intent) {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ package com.deniscerri.ytdlnis.receiver
|
||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.util.Log
|
|
||||||
import com.deniscerri.ytdlnis.database.DBManager
|
import com.deniscerri.ytdlnis.database.DBManager
|
||||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
import com.deniscerri.ytdlnis.util.NotificationUtil
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,11 @@ import android.content.Context
|
||||||
import android.graphics.drawable.ColorDrawable
|
import android.graphics.drawable.ColorDrawable
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.ui.BaseActivity
|
import com.deniscerri.ytdlnis.ui.BaseActivity
|
||||||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
import com.deniscerri.ytdlnis.util.NotificationUtil
|
||||||
import com.deniscerri.ytdlnis.util.ThemeUtil
|
import com.deniscerri.ytdlnis.util.ThemeUtil
|
||||||
|
|
@ -36,10 +38,13 @@ class ShareFileActivity : BaseActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setContentView(R.layout.activity_share)
|
||||||
|
|
||||||
val paths = intent.getStringArrayExtra("path")
|
val paths = intent.getStringArrayExtra("path")
|
||||||
val notificationId = intent.getIntExtra("notificationID", 0)
|
val notificationId = intent.getIntExtra("notificationID", 0)
|
||||||
NotificationUtil(this).cancelDownloadNotification(notificationId)
|
NotificationUtil(this).cancelDownloadNotification(notificationId)
|
||||||
UiUtil.shareFileIntent(this, paths!!.toList())
|
Log.e("SHAREE", paths.toString())
|
||||||
|
UiUtil.shareFileIntent(this, paths!!.toList().filter { it.isNotBlank() }.distinct())
|
||||||
finishAffinity()
|
finishAffinity()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -11,6 +11,7 @@ import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.text.Editable
|
import android.text.Editable
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import android.util.Patterns
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import android.view.View.*
|
import android.view.View.*
|
||||||
import android.widget.*
|
import android.widget.*
|
||||||
|
|
@ -30,7 +31,7 @@ import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.deniscerri.ytdlnis.MainActivity
|
import com.deniscerri.ytdlnis.MainActivity
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.adapter.HomeAdapter
|
import com.deniscerri.ytdlnis.ui.adapter.HomeAdapter
|
||||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||||
import com.deniscerri.ytdlnis.database.models.ResultItem
|
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||||
|
|
@ -227,7 +228,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, OnClickListene
|
||||||
launch{
|
launch{
|
||||||
resultViewModel.uiState.collectLatest { res ->
|
resultViewModel.uiState.collectLatest { res ->
|
||||||
if (res.errorMessage != null){
|
if (res.errorMessage != null){
|
||||||
kotlin.runCatching { UiUtil.handleResultResponse(requireActivity(), res) }
|
kotlin.runCatching { UiUtil.handleResultResponse(requireActivity(), res, closed ={}) }
|
||||||
resultViewModel.uiState.update {it.copy(errorMessage = null, actions = null) }
|
resultViewModel.uiState.update {it.copy(errorMessage = null, actions = null) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -557,7 +558,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, OnClickListene
|
||||||
lifecycleScope.launch(Dispatchers.IO){
|
lifecycleScope.launch(Dispatchers.IO){
|
||||||
Thread.sleep(300)
|
Thread.sleep(300)
|
||||||
if(sharedPreferences!!.getBoolean("quick_download", false) || sharedPreferences!!.getString("preferred_download_type", "video") == "command"){
|
if(sharedPreferences!!.getBoolean("quick_download", false) || sharedPreferences!!.getString("preferred_download_type", "video") == "command"){
|
||||||
if (queryList.size == 1 && queryList.first().matches("(https?://(?:www\\.|(?!www))[a-zA-Z\\d][a-zA-Z\\d-]+[a-zA-Z\\d]\\.\\S{2,}|www\\.[a-zA-Z\\d][a-zA-Z\\d-]+[a-zA-Z\\d]\\.\\S{2,}|https?://(?:www\\.|(?!www))[a-zA-Z\\d]+\\.\\S{2,}|www\\.[a-zA-Z\\d]+\\.\\S{2,})".toRegex())){
|
if (queryList.size == 1 && Patterns.WEB_URL.matcher(queryList.first()).matches()){
|
||||||
if (sharedPreferences!!.getBoolean("download_card", true)) {
|
if (sharedPreferences!!.getBoolean("download_card", true)) {
|
||||||
showSingleDownloadSheet(
|
showSingleDownloadSheet(
|
||||||
resultItem = downloadViewModel.createEmptyResultItem(queryList.first()),
|
resultItem = downloadViewModel.createEmptyResultItem(queryList.first()),
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
package com.deniscerri.ytdlnis.adapter
|
package com.deniscerri.ytdlnis.ui.adapter
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.util.Log
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
|
@ -26,12 +25,11 @@ import com.google.android.material.button.MaterialButton
|
||||||
import com.google.android.material.card.MaterialCardView
|
import com.google.android.material.card.MaterialCardView
|
||||||
import com.google.android.material.chip.Chip
|
import com.google.android.material.chip.Chip
|
||||||
import com.google.android.material.progressindicator.LinearProgressIndicator
|
import com.google.android.material.progressindicator.LinearProgressIndicator
|
||||||
import com.google.android.material.shape.CornerFamily
|
|
||||||
import com.google.android.material.shape.ShapeAppearanceModel
|
|
||||||
import com.squareup.picasso.Picasso
|
import com.squareup.picasso.Picasso
|
||||||
import java.lang.StringBuilder
|
|
||||||
|
|
||||||
class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<DownloadItem?, ActiveDownloadAdapter.ViewHolder>(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) {
|
class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<DownloadItem?, ActiveDownloadAdapter.ViewHolder>(AsyncDifferConfig.Builder(
|
||||||
|
DIFF_CALLBACK
|
||||||
|
).build()) {
|
||||||
private val onItemClickListener: OnItemClickListener
|
private val onItemClickListener: OnItemClickListener
|
||||||
private val activity: Activity
|
private val activity: Activity
|
||||||
private val sharedPreferences: SharedPreferences
|
private val sharedPreferences: SharedPreferences
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.deniscerri.ytdlnis.adapter
|
package com.deniscerri.ytdlnis.ui.adapter
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
|
|
@ -19,18 +19,16 @@ import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
|
||||||
import com.deniscerri.ytdlnis.util.FileUtil
|
import com.deniscerri.ytdlnis.util.FileUtil
|
||||||
import com.google.android.material.button.MaterialButton
|
import com.google.android.material.button.MaterialButton
|
||||||
import com.google.android.material.card.MaterialCardView
|
import com.google.android.material.card.MaterialCardView
|
||||||
import com.google.android.material.chip.Chip
|
|
||||||
import com.google.android.material.progressindicator.LinearProgressIndicator
|
import com.google.android.material.progressindicator.LinearProgressIndicator
|
||||||
import com.google.android.material.shape.CornerFamily
|
|
||||||
import com.google.android.material.shape.ShapeAppearanceModel
|
|
||||||
import com.squareup.picasso.Picasso
|
import com.squareup.picasso.Picasso
|
||||||
import java.lang.StringBuilder
|
import java.lang.StringBuilder
|
||||||
|
|
||||||
class ActiveDownloadMinifiedAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<DownloadItem?, ActiveDownloadMinifiedAdapter.ViewHolder>(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) {
|
class ActiveDownloadMinifiedAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<DownloadItem?, ActiveDownloadMinifiedAdapter.ViewHolder>(AsyncDifferConfig.Builder(
|
||||||
|
DIFF_CALLBACK
|
||||||
|
).build()) {
|
||||||
private val onItemClickListener: OnItemClickListener
|
private val onItemClickListener: OnItemClickListener
|
||||||
private val activity: Activity
|
private val activity: Activity
|
||||||
private val sharedPreferences: SharedPreferences
|
private val sharedPreferences: SharedPreferences
|
||||||
|
|
@ -132,13 +130,15 @@ class ActiveDownloadMinifiedAdapter(onItemClickListener: OnItemClickListener, ac
|
||||||
|
|
||||||
pauseButton.setOnClickListener {
|
pauseButton.setOnClickListener {
|
||||||
if (pauseButton.tag == ActiveDownloadAdapter.ActiveDownloadAction.Pause){
|
if (pauseButton.tag == ActiveDownloadAdapter.ActiveDownloadAction.Pause){
|
||||||
onItemClickListener.onPauseClick(item.id, ActiveDownloadAdapter.ActiveDownloadAction.Pause, position)
|
onItemClickListener.onPauseClick(item.id,
|
||||||
|
ActiveDownloadAdapter.ActiveDownloadAction.Pause, position)
|
||||||
pauseButton.icon = ContextCompat.getDrawable(activity, R.drawable.exomedia_ic_play_arrow_white)
|
pauseButton.icon = ContextCompat.getDrawable(activity, R.drawable.exomedia_ic_play_arrow_white)
|
||||||
if (progressBar.progress == 0) progressBar.isIndeterminate = false
|
if (progressBar.progress == 0) progressBar.isIndeterminate = false
|
||||||
cancelButton.visibility = View.VISIBLE
|
cancelButton.visibility = View.VISIBLE
|
||||||
pauseButton.tag = ActiveDownloadAdapter.ActiveDownloadAction.Resume
|
pauseButton.tag = ActiveDownloadAdapter.ActiveDownloadAction.Resume
|
||||||
}else{
|
}else{
|
||||||
onItemClickListener.onPauseClick(item.id, ActiveDownloadAdapter.ActiveDownloadAction.Resume, position)
|
onItemClickListener.onPauseClick(item.id,
|
||||||
|
ActiveDownloadAdapter.ActiveDownloadAction.Resume, position)
|
||||||
pauseButton.icon = ContextCompat.getDrawable(activity, R.drawable.exomedia_ic_pause_white)
|
pauseButton.icon = ContextCompat.getDrawable(activity, R.drawable.exomedia_ic_pause_white)
|
||||||
progressBar.isIndeterminate = true
|
progressBar.isIndeterminate = true
|
||||||
cancelButton.visibility = View.GONE
|
cancelButton.visibility = View.GONE
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.deniscerri.ytdlnis.adapter
|
package com.deniscerri.ytdlnis.ui.adapter
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
|
|
@ -24,7 +24,9 @@ import com.google.android.material.button.MaterialButton
|
||||||
import com.squareup.picasso.Picasso
|
import com.squareup.picasso.Picasso
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
class ConfigureMultipleDownloadsAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<DownloadItem?, ConfigureMultipleDownloadsAdapter.ViewHolder>(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) {
|
class ConfigureMultipleDownloadsAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<DownloadItem?, ConfigureMultipleDownloadsAdapter.ViewHolder>(AsyncDifferConfig.Builder(
|
||||||
|
DIFF_CALLBACK
|
||||||
|
).build()) {
|
||||||
private val onItemClickListener: OnItemClickListener
|
private val onItemClickListener: OnItemClickListener
|
||||||
private val activity: Activity
|
private val activity: Activity
|
||||||
private val sharedPreferences : SharedPreferences
|
private val sharedPreferences : SharedPreferences
|
||||||
|
|
@ -35,7 +37,7 @@ class ConfigureMultipleDownloadsAdapter(onItemClickListener: OnItemClickListener
|
||||||
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(activity)
|
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(activity)
|
||||||
}
|
}
|
||||||
|
|
||||||
class ViewHolder(itemView: View, onItemClickListener: OnItemClickListener?) : RecyclerView.ViewHolder(itemView) {
|
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||||
val cardView: FrameLayout
|
val cardView: FrameLayout
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
|
@ -46,7 +48,7 @@ class ConfigureMultipleDownloadsAdapter(onItemClickListener: OnItemClickListener
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
val cardView = LayoutInflater.from(parent.context)
|
val cardView = LayoutInflater.from(parent.context)
|
||||||
.inflate(R.layout.download_card, parent, false)
|
.inflate(R.layout.download_card, parent, false)
|
||||||
return ViewHolder(cardView, onItemClickListener)
|
return ViewHolder(cardView)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
|
|
@ -136,11 +138,16 @@ class ConfigureMultipleDownloadsAdapter(onItemClickListener: OnItemClickListener
|
||||||
card.setOnClickListener {
|
card.setOnClickListener {
|
||||||
onItemClickListener.onCardClick(item.url)
|
onItemClickListener.onCardClick(item.url)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
card.setOnLongClickListener {
|
||||||
|
onItemClickListener.onDelete(item.url); true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface OnItemClickListener {
|
interface OnItemClickListener {
|
||||||
fun onButtonClick(itemURL: String)
|
fun onButtonClick(itemURL: String)
|
||||||
fun onCardClick(itemURL: String)
|
fun onCardClick(itemURL: String)
|
||||||
|
fun onDelete(itemURL: String)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
package com.deniscerri.ytdlnis.adapter
|
package com.deniscerri.ytdlnis.ui.adapter
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
import androidx.recyclerview.widget.AsyncDifferConfig
|
import androidx.recyclerview.widget.AsyncDifferConfig
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.ListAdapter
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
|
|
@ -14,7 +13,9 @@ import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.database.models.CookieItem
|
import com.deniscerri.ytdlnis.database.models.CookieItem
|
||||||
import com.google.android.material.card.MaterialCardView
|
import com.google.android.material.card.MaterialCardView
|
||||||
|
|
||||||
class CookieAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<CookieItem?, CookieAdapter.ViewHolder>(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) {
|
class CookieAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<CookieItem?, CookieAdapter.ViewHolder>(AsyncDifferConfig.Builder(
|
||||||
|
DIFF_CALLBACK
|
||||||
|
).build()) {
|
||||||
private val onItemClickListener: OnItemClickListener
|
private val onItemClickListener: OnItemClickListener
|
||||||
private val activity: Activity
|
private val activity: Activity
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.deniscerri.ytdlnis.adapter
|
package com.deniscerri.ytdlnis.ui.adapter
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
|
|
@ -6,25 +6,23 @@ import android.text.format.DateFormat
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.Button
|
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
import androidx.recyclerview.widget.AsyncDifferConfig
|
import androidx.recyclerview.widget.AsyncDifferConfig
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.ListAdapter
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
|
||||||
import com.deniscerri.ytdlnis.database.models.LogItem
|
import com.deniscerri.ytdlnis.database.models.LogItem
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||||
import com.deniscerri.ytdlnis.util.FileUtil
|
import com.deniscerri.ytdlnis.util.FileUtil
|
||||||
import com.google.android.material.button.MaterialButton
|
import com.google.android.material.button.MaterialButton
|
||||||
import com.google.android.material.card.MaterialCardView
|
import com.google.android.material.card.MaterialCardView
|
||||||
import java.io.File
|
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
class DownloadLogsAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<LogItem?, DownloadLogsAdapter.ViewHolder>(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) {
|
class DownloadLogsAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<LogItem?, DownloadLogsAdapter.ViewHolder>(AsyncDifferConfig.Builder(
|
||||||
|
DIFF_CALLBACK
|
||||||
|
).build()) {
|
||||||
private val onItemClickListener: OnItemClickListener
|
private val onItemClickListener: OnItemClickListener
|
||||||
private val activity: Activity
|
private val activity: Activity
|
||||||
private val checkedItems: ArrayList<Long>
|
private val checkedItems: ArrayList<Long>
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.deniscerri.ytdlnis.adapter
|
package com.deniscerri.ytdlnis.ui.adapter
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
|
|
@ -10,13 +10,11 @@ import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import androidx.paging.PagingDataAdapter
|
import androidx.paging.PagingDataAdapter
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
|
||||||
import com.deniscerri.ytdlnis.database.models.DownloadItemSimple
|
import com.deniscerri.ytdlnis.database.models.DownloadItemSimple
|
||||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||||
import com.deniscerri.ytdlnis.util.FileUtil
|
import com.deniscerri.ytdlnis.util.FileUtil
|
||||||
|
|
@ -24,7 +22,9 @@ import com.google.android.material.button.MaterialButton
|
||||||
import com.google.android.material.card.MaterialCardView
|
import com.google.android.material.card.MaterialCardView
|
||||||
import com.squareup.picasso.Picasso
|
import com.squareup.picasso.Picasso
|
||||||
|
|
||||||
class GenericDownloadAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : PagingDataAdapter<DownloadItemSimple, GenericDownloadAdapter.ViewHolder>(DIFF_CALLBACK) {
|
class GenericDownloadAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : PagingDataAdapter<DownloadItemSimple, GenericDownloadAdapter.ViewHolder>(
|
||||||
|
DIFF_CALLBACK
|
||||||
|
) {
|
||||||
private val onItemClickListener: OnItemClickListener
|
private val onItemClickListener: OnItemClickListener
|
||||||
private val activity: Activity
|
private val activity: Activity
|
||||||
val checkedItems: ArrayList<Long>
|
val checkedItems: ArrayList<Long>
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.deniscerri.ytdlnis.adapter
|
package com.deniscerri.ytdlnis.ui.adapter
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
|
|
@ -24,13 +24,16 @@ import com.deniscerri.ytdlnis.database.models.HistoryItem
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||||
import com.google.android.material.button.MaterialButton
|
import com.google.android.material.button.MaterialButton
|
||||||
import com.google.android.material.card.MaterialCardView
|
import com.google.android.material.card.MaterialCardView
|
||||||
|
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
import com.squareup.picasso.Picasso
|
import com.squareup.picasso.Picasso
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
class HistoryAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<HistoryItem?, HistoryAdapter.ViewHolder>(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) {
|
class HistoryAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<HistoryItem?, HistoryAdapter.ViewHolder>(AsyncDifferConfig.Builder(
|
||||||
|
DIFF_CALLBACK
|
||||||
|
).build()) {
|
||||||
private val checkedItems: ArrayList<Long>
|
private val checkedItems: ArrayList<Long>
|
||||||
private val onItemClickListener: OnItemClickListener
|
private val onItemClickListener: OnItemClickListener
|
||||||
private val activity: Activity
|
private val activity: Activity
|
||||||
|
|
@ -105,7 +108,7 @@ class HistoryAdapter(onItemClickListener: OnItemClickListener, activity: Activit
|
||||||
datetime.text = SimpleDateFormat(android.text.format.DateFormat.getBestDateTimePattern(Locale.getDefault(), "ddMMMyyyy - HHmm"), Locale.getDefault()).format(item.time * 1000L)
|
datetime.text = SimpleDateFormat(android.text.format.DateFormat.getBestDateTimePattern(Locale.getDefault(), "ddMMMyyyy - HHmm"), Locale.getDefault()).format(item.time * 1000L)
|
||||||
|
|
||||||
// BUTTON ----------------------------------
|
// BUTTON ----------------------------------
|
||||||
val btn = card.findViewById<MaterialButton>(R.id.downloads_download_button_type)
|
val btn = card.findViewById<FloatingActionButton>(R.id.downloads_download_button_type)
|
||||||
var filePresent = true
|
var filePresent = true
|
||||||
|
|
||||||
//IS IN THE FILE SYSTEM?
|
//IS IN THE FILE SYSTEM?
|
||||||
|
|
@ -121,11 +124,11 @@ class HistoryAdapter(onItemClickListener: OnItemClickListener, activity: Activit
|
||||||
thumbnail.alpha = 0.7f
|
thumbnail.alpha = 0.7f
|
||||||
}
|
}
|
||||||
if (item.type == DownloadViewModel.Type.audio) {
|
if (item.type == DownloadViewModel.Type.audio) {
|
||||||
if (filePresent) btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_music_downloaded) else btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_music)
|
if (filePresent) btn.setImageResource(R.drawable.ic_music_downloaded) else btn.setImageResource(R.drawable.ic_music)
|
||||||
} else if (item.type == DownloadViewModel.Type.video) {
|
} else if (item.type == DownloadViewModel.Type.video) {
|
||||||
if (filePresent) btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_video_downloaded) else btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_video)
|
if (filePresent) btn.setImageResource(R.drawable.ic_video_downloaded) else btn.setImageResource(R.drawable.ic_video)
|
||||||
}else{
|
}else{
|
||||||
btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_terminal)
|
btn.setImageResource(R.drawable.ic_terminal)
|
||||||
}
|
}
|
||||||
if (btn.hasOnClickListeners()) btn.setOnClickListener(null)
|
if (btn.hasOnClickListeners()) btn.setOnClickListener(null)
|
||||||
btn.isClickable = filePresent
|
btn.isClickable = filePresent
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.deniscerri.ytdlnis.adapter
|
package com.deniscerri.ytdlnis.ui.adapter
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
|
|
@ -9,9 +9,7 @@ import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.LinearLayout
|
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.preference.Preference
|
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import androidx.recyclerview.widget.AsyncDifferConfig
|
import androidx.recyclerview.widget.AsyncDifferConfig
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
|
@ -25,7 +23,9 @@ import com.google.android.material.card.MaterialCardView
|
||||||
import com.google.android.material.progressindicator.LinearProgressIndicator
|
import com.google.android.material.progressindicator.LinearProgressIndicator
|
||||||
import com.squareup.picasso.Picasso
|
import com.squareup.picasso.Picasso
|
||||||
|
|
||||||
class HomeAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<ResultItem?, HomeAdapter.ViewHolder>(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) {
|
class HomeAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<ResultItem?, HomeAdapter.ViewHolder>(AsyncDifferConfig.Builder(
|
||||||
|
DIFF_CALLBACK
|
||||||
|
).build()) {
|
||||||
private val checkedVideos: ArrayList<String>
|
private val checkedVideos: ArrayList<String>
|
||||||
private val onItemClickListener: OnItemClickListener
|
private val onItemClickListener: OnItemClickListener
|
||||||
private val activity: Activity
|
private val activity: Activity
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.deniscerri.ytdlnis.adapter
|
package com.deniscerri.ytdlnis.ui.adapter
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
|
|
@ -21,11 +21,12 @@ import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.database.models.ResultItem
|
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||||
import com.squareup.picasso.Picasso
|
import com.squareup.picasso.Picasso
|
||||||
import org.w3c.dom.Text
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
class PlaylistAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<ResultItem?, PlaylistAdapter.ViewHolder>(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) {
|
class PlaylistAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<ResultItem?, PlaylistAdapter.ViewHolder>(AsyncDifferConfig.Builder(
|
||||||
|
DIFF_CALLBACK
|
||||||
|
).build()) {
|
||||||
private val checkedItems: ArrayList<String>
|
private val checkedItems: ArrayList<String>
|
||||||
private val onItemClickListener: OnItemClickListener
|
private val onItemClickListener: OnItemClickListener
|
||||||
private val activity: Activity
|
private val activity: Activity
|
||||||
|
|
@ -1,23 +1,26 @@
|
||||||
package com.deniscerri.ytdlnis.adapter
|
package com.deniscerri.ytdlnis.ui.adapter
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.opengl.Visibility
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
import androidx.recyclerview.widget.AsyncDifferConfig
|
import androidx.recyclerview.widget.AsyncDifferConfig
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.ListAdapter
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
||||||
|
import com.deniscerri.ytdlnis.database.models.LogItem
|
||||||
import com.google.android.material.card.MaterialCardView
|
import com.google.android.material.card.MaterialCardView
|
||||||
|
|
||||||
class TemplatesAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<CommandTemplate?, TemplatesAdapter.ViewHolder>(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) {
|
class TemplatesAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<CommandTemplate?, TemplatesAdapter.ViewHolder>(AsyncDifferConfig.Builder(
|
||||||
|
DIFF_CALLBACK
|
||||||
|
).build()) {
|
||||||
private val onItemClickListener: OnItemClickListener
|
private val onItemClickListener: OnItemClickListener
|
||||||
private val activity: Activity
|
private val activity: Activity
|
||||||
|
private val checkedItems: ArrayList<Long> = ArrayList()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
this.onItemClickListener = onItemClickListener
|
this.onItemClickListener = onItemClickListener
|
||||||
|
|
@ -52,19 +55,74 @@ class TemplatesAdapter(onItemClickListener: OnItemClickListener, activity: Activ
|
||||||
if (item!!.useAsExtraCommand) useInExtraCommands.visibility = View.VISIBLE
|
if (item!!.useAsExtraCommand) useInExtraCommands.visibility = View.VISIBLE
|
||||||
else useInExtraCommands.visibility = View.GONE
|
else useInExtraCommands.visibility = View.GONE
|
||||||
|
|
||||||
|
if (checkedItems.contains(item.id)) {
|
||||||
|
card.isChecked = true
|
||||||
|
card.strokeWidth = 5
|
||||||
|
} else {
|
||||||
|
card.isChecked = false
|
||||||
|
card.strokeWidth = 0
|
||||||
|
}
|
||||||
card.setOnClickListener {
|
card.setOnClickListener {
|
||||||
onItemClickListener.onItemClick(item, position)
|
if (checkedItems.size > 0) {
|
||||||
|
checkCard(card, item.id)
|
||||||
|
} else {
|
||||||
|
onItemClickListener.onItemClick(item, position)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
card.setOnLongClickListener {
|
card.setOnLongClickListener {
|
||||||
onItemClickListener.onDelete(item); true
|
checkCard(card, item.id)
|
||||||
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
|
fun clearCheckeditems() {
|
||||||
|
for (i in 0 until itemCount){
|
||||||
|
val item = getItem(i)
|
||||||
|
if (checkedItems.find { it == item?.id } != null){
|
||||||
|
checkedItems.remove(item?.id)
|
||||||
|
notifyItemChanged(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkedItems.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
|
fun checkAll(items: List<CommandTemplate?>?){
|
||||||
|
checkedItems.clear()
|
||||||
|
checkedItems.addAll(items!!.map { it!!.id })
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
|
fun invertSelected(items: List<CommandTemplate?>?){
|
||||||
|
val invertedList = mutableListOf<Long>()
|
||||||
|
items?.forEach {
|
||||||
|
if (!checkedItems.contains(it!!.id)) invertedList.add(it.id)
|
||||||
|
}
|
||||||
|
checkedItems.clear()
|
||||||
|
checkedItems.addAll(invertedList)
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkCard(card: MaterialCardView, itemID: Long) {
|
||||||
|
if (card.isChecked) {
|
||||||
|
card.strokeWidth = 0
|
||||||
|
checkedItems.remove(itemID)
|
||||||
|
} else {
|
||||||
|
card.strokeWidth = 5
|
||||||
|
checkedItems.add(itemID)
|
||||||
|
}
|
||||||
|
card.isChecked = !card.isChecked
|
||||||
|
onItemClickListener.onCardSelect(itemID, card.isChecked)
|
||||||
|
}
|
||||||
|
|
||||||
interface OnItemClickListener {
|
interface OnItemClickListener {
|
||||||
fun onItemClick(commandTemplate: CommandTemplate, index: Int)
|
fun onItemClick(commandTemplate: CommandTemplate, index: Int)
|
||||||
fun onSelected(commandTemplate: CommandTemplate)
|
fun onSelected(commandTemplate: CommandTemplate)
|
||||||
fun onDelete(commandTemplate: CommandTemplate)
|
fun onCardSelect(itemID: Long, isChecked: Boolean)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package com.deniscerri.ytdlnis.adapter
|
package com.deniscerri.ytdlnis.ui.adapter
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
|
|
@ -17,7 +17,9 @@ import com.google.android.material.button.MaterialButton
|
||||||
import com.google.android.material.card.MaterialCardView
|
import com.google.android.material.card.MaterialCardView
|
||||||
import com.google.android.material.progressindicator.LinearProgressIndicator
|
import com.google.android.material.progressindicator.LinearProgressIndicator
|
||||||
|
|
||||||
class TerminalDownloadsAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<TerminalItem?, TerminalDownloadsAdapter.ViewHolder>(AsyncDifferConfig.Builder(DIFF_CALLBACK).build()) {
|
class TerminalDownloadsAdapter(onItemClickListener: OnItemClickListener, activity: Activity) : ListAdapter<TerminalItem?, TerminalDownloadsAdapter.ViewHolder>(AsyncDifferConfig.Builder(
|
||||||
|
DIFF_CALLBACK
|
||||||
|
).build()) {
|
||||||
private val onItemClickListener: OnItemClickListener
|
private val onItemClickListener: OnItemClickListener
|
||||||
private val activity: Activity
|
private val activity: Activity
|
||||||
private val sharedPreferences: SharedPreferences
|
private val sharedPreferences: SharedPreferences
|
||||||
|
|
@ -4,11 +4,8 @@ import android.annotation.SuppressLint
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
import android.content.Intent
|
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.graphics.Color
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.DisplayMetrics
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
|
@ -25,17 +22,12 @@ import com.deniscerri.ytdlnis.database.viewmodel.CommandTemplateViewModel
|
||||||
import com.deniscerri.ytdlnis.util.InfoUtil
|
import com.deniscerri.ytdlnis.util.InfoUtil
|
||||||
import com.deniscerri.ytdlnis.util.UiUtil
|
import com.deniscerri.ytdlnis.util.UiUtil
|
||||||
import com.deniscerri.ytdlnis.util.UiUtil.enableTextHighlight
|
import com.deniscerri.ytdlnis.util.UiUtil.enableTextHighlight
|
||||||
import com.google.android.material.bottomappbar.BottomAppBar
|
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
import com.neo.highlight.core.Highlight
|
|
||||||
import com.neo.highlight.util.listener.HighlightTextWatcher
|
|
||||||
import com.neo.highlight.util.scheme.ColorScheme
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.regex.Pattern
|
|
||||||
|
|
||||||
|
|
||||||
class AddExtraCommandsDialog(private val item: DownloadItem?, private val callback: ExtraCommandsListener) : BottomSheetDialogFragment() {
|
class AddExtraCommandsDialog(private val item: DownloadItem?, private val callback: ExtraCommandsListener) : BottomSheetDialogFragment() {
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ import android.view.ViewGroup
|
||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
|
|
@ -179,10 +178,10 @@ class ConfigureDownloadBottomSheetDialog(private var result: ResultItem, private
|
||||||
val link = view.findViewById<Button>(R.id.bottom_sheet_link)
|
val link = view.findViewById<Button>(R.id.bottom_sheet_link)
|
||||||
link.text = result.url
|
link.text = result.url
|
||||||
link.setOnClickListener{
|
link.setOnClickListener{
|
||||||
UiUtil.openLinkIntent(requireContext(), result.url, null)
|
UiUtil.openLinkIntent(requireContext(), result.url)
|
||||||
}
|
}
|
||||||
link.setOnLongClickListener{
|
link.setOnLongClickListener{
|
||||||
UiUtil.copyLinkToClipBoard(requireContext(), result.url, null)
|
UiUtil.copyLinkToClipBoard(requireContext(), result.url)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ package com.deniscerri.ytdlnis.ui.downloadcard
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
import android.content.SharedPreferences
|
|
||||||
import android.content.res.ColorStateList
|
import android.content.res.ColorStateList
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
|
|
||||||
|
|
@ -14,15 +14,14 @@ import android.widget.ArrayAdapter
|
||||||
import android.widget.AutoCompleteTextView
|
import android.widget.AutoCompleteTextView
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import android.widget.Toast
|
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.appcompat.content.res.AppCompatResources
|
import androidx.appcompat.content.res.AppCompatResources
|
||||||
import androidx.core.view.isEmpty
|
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
|
import com.afollestad.materialdialogs.utils.MDUtil.getStringArray
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||||
import com.deniscerri.ytdlnis.database.models.Format
|
import com.deniscerri.ytdlnis.database.models.Format
|
||||||
|
|
@ -35,6 +34,7 @@ import com.deniscerri.ytdlnis.util.InfoUtil
|
||||||
import com.deniscerri.ytdlnis.util.UiUtil
|
import com.deniscerri.ytdlnis.util.UiUtil
|
||||||
import com.google.android.material.card.MaterialCardView
|
import com.google.android.material.card.MaterialCardView
|
||||||
import com.google.android.material.textfield.TextInputLayout
|
import com.google.android.material.textfield.TextInputLayout
|
||||||
|
import com.google.android.material.textfield.TextInputLayout.END_ICON_NONE
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
@ -69,7 +69,7 @@ class DownloadAudioFragment(private var resultItem: ResultItem? = null, private
|
||||||
infoUtil = InfoUtil(requireContext())
|
infoUtil = InfoUtil(requireContext())
|
||||||
genericAudioFormats = infoUtil.getGenericAudioFormats(requireContext().resources)
|
genericAudioFormats = infoUtil.getGenericAudioFormats(requireContext().resources)
|
||||||
preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||||
shownFields = preferences.getStringSet("modify_download_card", setOf())!!.toList()
|
shownFields = preferences.getStringSet("modify_download_card", setOf())!!.toList().ifEmpty { requireContext().getStringArray(R.array.modify_download_card_values).toList() }
|
||||||
return fragmentView
|
return fragmentView
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -92,6 +92,7 @@ class DownloadAudioFragment(private var resultItem: ResultItem? = null, private
|
||||||
title.visibility = if (shownFields.contains("title")) View.VISIBLE else View.GONE
|
title.visibility = if (shownFields.contains("title")) View.VISIBLE else View.GONE
|
||||||
if (title.editText?.text?.isEmpty() == true){
|
if (title.editText?.text?.isEmpty() == true){
|
||||||
title.editText!!.setText(downloadItem.title)
|
title.editText!!.setText(downloadItem.title)
|
||||||
|
title.endIconMode = END_ICON_NONE
|
||||||
}
|
}
|
||||||
title.editText!!.addTextChangedListener(object : TextWatcher {
|
title.editText!!.addTextChangedListener(object : TextWatcher {
|
||||||
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
|
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
|
||||||
|
|
@ -100,17 +101,12 @@ class DownloadAudioFragment(private var resultItem: ResultItem? = null, private
|
||||||
downloadItem.title = p0.toString()
|
downloadItem.title = p0.toString()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
title.setEndIconOnClickListener {
|
|
||||||
if (resultItem != null){
|
|
||||||
title.editText?.setText(resultItem?.title)
|
|
||||||
}
|
|
||||||
title.endIconDrawable = null
|
|
||||||
}
|
|
||||||
|
|
||||||
author = view.findViewById(R.id.author_textinput)
|
author = view.findViewById(R.id.author_textinput)
|
||||||
author.visibility = if (shownFields.contains("author")) View.VISIBLE else View.GONE
|
author.visibility = if (shownFields.contains("author")) View.VISIBLE else View.GONE
|
||||||
if (author.editText?.text?.isEmpty() == true){
|
if (author.editText?.text?.isEmpty() == true){
|
||||||
author.editText!!.setText(downloadItem.author)
|
author.editText!!.setText(downloadItem.author)
|
||||||
|
author.endIconMode = END_ICON_NONE
|
||||||
}
|
}
|
||||||
author.editText!!.addTextChangedListener(object : TextWatcher {
|
author.editText!!.addTextChangedListener(object : TextWatcher {
|
||||||
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
|
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
|
||||||
|
|
@ -119,25 +115,35 @@ class DownloadAudioFragment(private var resultItem: ResultItem? = null, private
|
||||||
downloadItem.author = p0.toString()
|
downloadItem.author = p0.toString()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
author.setEndIconOnClickListener {
|
|
||||||
if (resultItem != null){
|
|
||||||
author.editText?.setText(resultItem?.author)
|
|
||||||
}
|
|
||||||
author.endIconDrawable = null
|
|
||||||
}
|
|
||||||
|
|
||||||
if (savedInstanceState?.containsKey("updated") == true){
|
if (savedInstanceState?.containsKey("updated") == true){
|
||||||
if (!listOf(resultItem?.title, downloadItem.title).contains(title.editText?.text.toString())){
|
if (!listOf(resultItem?.title, downloadItem.title).contains(title.editText?.text.toString())){
|
||||||
|
title.endIconMode = TextInputLayout.END_ICON_CUSTOM
|
||||||
title.endIconDrawable = AppCompatResources.getDrawable(requireContext(), R.drawable.ic_refresh)
|
title.endIconDrawable = AppCompatResources.getDrawable(requireContext(), R.drawable.ic_refresh)
|
||||||
downloadItem.title = title.editText?.text.toString()
|
downloadItem.title = title.editText?.text.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!listOf(resultItem?.author, downloadItem.author).contains(author.editText?.text.toString())){
|
if (!listOf(resultItem?.author, downloadItem.author).contains(author.editText?.text.toString())){
|
||||||
|
author.endIconMode = TextInputLayout.END_ICON_CUSTOM
|
||||||
author.endIconDrawable = AppCompatResources.getDrawable(requireContext(), R.drawable.ic_refresh)
|
author.endIconDrawable = AppCompatResources.getDrawable(requireContext(), R.drawable.ic_refresh)
|
||||||
downloadItem.author = author.editText?.text.toString()
|
downloadItem.author = author.editText?.text.toString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
title.setEndIconOnClickListener {
|
||||||
|
if (resultItem != null){
|
||||||
|
title.editText?.setText(resultItem?.title)
|
||||||
|
}
|
||||||
|
title.endIconMode = END_ICON_NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
author.setEndIconOnClickListener {
|
||||||
|
if (resultItem != null){
|
||||||
|
author.editText?.setText(resultItem?.author)
|
||||||
|
}
|
||||||
|
author.endIconMode = END_ICON_NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
saveDir = view.findViewById(R.id.outputPath)
|
saveDir = view.findViewById(R.id.outputPath)
|
||||||
saveDir.editText!!.setText(
|
saveDir.editText!!.setText(
|
||||||
|
|
@ -295,9 +301,9 @@ class DownloadAudioFragment(private var resultItem: ResultItem? = null, private
|
||||||
downloadItem.title = t
|
downloadItem.title = t
|
||||||
downloadItem.author = a
|
downloadItem.author = a
|
||||||
title.editText?.setText(t)
|
title.editText?.setText(t)
|
||||||
title.endIconDrawable = null
|
title.endIconMode = END_ICON_NONE
|
||||||
author.editText?.setText(a)
|
author.editText?.setText(a)
|
||||||
title.endIconDrawable = null
|
author.endIconMode = END_ICON_NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateUI(res: ResultItem?){
|
override fun updateUI(res: ResultItem?){
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import androidx.viewpager2.widget.ViewPager2
|
import androidx.viewpager2.widget.ViewPager2
|
||||||
|
import com.afollestad.materialdialogs.utils.MDUtil.getStringArray
|
||||||
import com.deniscerri.ytdlnis.MainActivity
|
import com.deniscerri.ytdlnis.MainActivity
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.database.DBManager
|
import com.deniscerri.ytdlnis.database.DBManager
|
||||||
|
|
@ -31,6 +32,7 @@ import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type
|
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel.Type
|
||||||
|
import com.deniscerri.ytdlnis.database.viewmodel.HistoryViewModel
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
|
||||||
import com.deniscerri.ytdlnis.receiver.ShareActivity
|
import com.deniscerri.ytdlnis.receiver.ShareActivity
|
||||||
import com.deniscerri.ytdlnis.util.InfoUtil
|
import com.deniscerri.ytdlnis.util.InfoUtil
|
||||||
|
|
@ -44,6 +46,7 @@ import com.google.android.material.progressindicator.LinearProgressIndicator
|
||||||
import com.google.android.material.tabs.TabLayout
|
import com.google.android.material.tabs.TabLayout
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
|
import kotlinx.coroutines.flow.update
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
|
@ -53,16 +56,19 @@ class DownloadBottomSheetDialog(private var result: ResultItem, private val type
|
||||||
private lateinit var viewPager2: ViewPager2
|
private lateinit var viewPager2: ViewPager2
|
||||||
private lateinit var fragmentAdapter : DownloadFragmentAdapter
|
private lateinit var fragmentAdapter : DownloadFragmentAdapter
|
||||||
private lateinit var downloadViewModel: DownloadViewModel
|
private lateinit var downloadViewModel: DownloadViewModel
|
||||||
|
private lateinit var historyViewModel: HistoryViewModel
|
||||||
private lateinit var resultViewModel: ResultViewModel
|
private lateinit var resultViewModel: ResultViewModel
|
||||||
private lateinit var behavior: BottomSheetBehavior<View>
|
private lateinit var behavior: BottomSheetBehavior<View>
|
||||||
private lateinit var commandTemplateDao : CommandTemplateDao
|
private lateinit var commandTemplateDao : CommandTemplateDao
|
||||||
private lateinit var infoUtil: InfoUtil
|
private lateinit var infoUtil: InfoUtil
|
||||||
private lateinit var sharedPreferences : SharedPreferences
|
private lateinit var sharedPreferences : SharedPreferences
|
||||||
|
private lateinit var updateItem : Button
|
||||||
private lateinit var view: View
|
private lateinit var view: View
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||||
|
historyViewModel = ViewModelProvider(this)[HistoryViewModel::class.java]
|
||||||
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
|
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
|
||||||
commandTemplateDao = DBManager.getInstance(requireContext()).commandTemplateDao
|
commandTemplateDao = DBManager.getInstance(requireContext()).commandTemplateDao
|
||||||
infoUtil = InfoUtil(requireContext())
|
infoUtil = InfoUtil(requireContext())
|
||||||
|
|
@ -87,6 +93,7 @@ class DownloadBottomSheetDialog(private var result: ResultItem, private val type
|
||||||
|
|
||||||
tabLayout = view.findViewById(R.id.download_tablayout)
|
tabLayout = view.findViewById(R.id.download_tablayout)
|
||||||
viewPager2 = view.findViewById(R.id.download_viewpager)
|
viewPager2 = view.findViewById(R.id.download_viewpager)
|
||||||
|
updateItem = view.findViewById(R.id.update_item)
|
||||||
|
|
||||||
(viewPager2.getChildAt(0) as? RecyclerView)?.apply {
|
(viewPager2.getChildAt(0) as? RecyclerView)?.apply {
|
||||||
isNestedScrollingEnabled = false
|
isNestedScrollingEnabled = false
|
||||||
|
|
@ -121,8 +128,12 @@ class DownloadBottomSheetDialog(private var result: ResultItem, private val type
|
||||||
|
|
||||||
(tabLayout.getChildAt(0) as? ViewGroup)?.getChildAt(1)?.isClickable = false
|
(tabLayout.getChildAt(0) as? ViewGroup)?.getChildAt(1)?.isClickable = false
|
||||||
(tabLayout.getChildAt(0) as? ViewGroup)?.getChildAt(1)?.alpha = 0.3f
|
(tabLayout.getChildAt(0) as? ViewGroup)?.getChildAt(1)?.alpha = 0.3f
|
||||||
|
|
||||||
|
updateItem.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//remove outdated player url of 1hr so it can refetch it in the cut player
|
||||||
|
if (result.creationTime > System.currentTimeMillis() - 3600000) result.urls = ""
|
||||||
|
|
||||||
val fragmentManager = parentFragmentManager
|
val fragmentManager = parentFragmentManager
|
||||||
fragmentAdapter = DownloadFragmentAdapter(
|
fragmentAdapter = DownloadFragmentAdapter(
|
||||||
|
|
@ -200,8 +211,10 @@ class DownloadBottomSheetDialog(private var result: ResultItem, private val type
|
||||||
|
|
||||||
viewPager2.setPageTransformer(BackgroundToForegroundPageTransformer())
|
viewPager2.setPageTransformer(BackgroundToForegroundPageTransformer())
|
||||||
|
|
||||||
|
val shownFields = sharedPreferences.getStringSet("modify_download_card", setOf())!!.toList().ifEmpty { requireContext().getStringArray(R.array.modify_download_card_values).toList() }
|
||||||
|
|
||||||
val scheduleBtn = view.findViewById<MaterialButton>(R.id.bottomsheet_schedule_button)
|
val scheduleBtn = view.findViewById<MaterialButton>(R.id.bottomsheet_schedule_button)
|
||||||
scheduleBtn.visibility = if(sharedPreferences.getStringSet("modify_download_card", setOf())!!.contains("schedule")){
|
scheduleBtn.visibility = if(shownFields.contains("schedule")){
|
||||||
View.VISIBLE
|
View.VISIBLE
|
||||||
}else{
|
}else{
|
||||||
View.GONE
|
View.GONE
|
||||||
|
|
@ -250,19 +263,19 @@ class DownloadBottomSheetDialog(private var result: ResultItem, private val type
|
||||||
}
|
}
|
||||||
|
|
||||||
val link = view.findViewById<Button>(R.id.bottom_sheet_link)
|
val link = view.findViewById<Button>(R.id.bottom_sheet_link)
|
||||||
link.visibility = if(sharedPreferences.getStringSet("modify_download_card", setOf())!!.contains("url")){
|
link.visibility = if(shownFields.contains("url")){
|
||||||
View.VISIBLE
|
View.VISIBLE
|
||||||
}else{
|
}else{
|
||||||
View.GONE
|
View.GONE
|
||||||
}
|
}
|
||||||
val updateItem = view.findViewById<Button>(R.id.update_item)
|
|
||||||
if (Patterns.WEB_URL.matcher(result.url).matches()){
|
if (Patterns.WEB_URL.matcher(result.url).matches()){
|
||||||
link.text = result.url
|
link.text = result.url
|
||||||
link.setOnClickListener{
|
link.setOnClickListener{
|
||||||
UiUtil.openLinkIntent(requireContext(), result.url, null)
|
UiUtil.openLinkIntent(requireContext(), result.url)
|
||||||
}
|
}
|
||||||
link.setOnLongClickListener{
|
link.setOnLongClickListener{
|
||||||
UiUtil.copyLinkToClipBoard(requireContext(), result.url, null)
|
UiUtil.copyLinkToClipBoard(requireContext(), result.url)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -281,12 +294,12 @@ class DownloadBottomSheetDialog(private var result: ResultItem, private val type
|
||||||
|
|
||||||
}else{
|
}else{
|
||||||
link.visibility = View.GONE
|
link.visibility = View.GONE
|
||||||
updateItem.visibility = View.GONE
|
(updateItem.parent as LinearLayout).visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//update in the background if there is no data
|
//update in the background if there is no data
|
||||||
if(result.title.isEmpty() && currentDownloadItem == null && !sharedPreferences.getBoolean("quick_download", false)){
|
if(result.title.isEmpty() && currentDownloadItem == null && !sharedPreferences.getBoolean("quick_download", false) && type != Type.command){
|
||||||
initUpdateData(view)
|
initUpdateData(view)
|
||||||
}else {
|
}else {
|
||||||
val usingGenericFormatsOrEmpty = result.formats.isEmpty() || result.formats.any { it.format_note.contains("ytdlnisgeneric") }
|
val usingGenericFormatsOrEmpty = result.formats.isEmpty() || result.formats.any { it.format_note.contains("ytdlnisgeneric") }
|
||||||
|
|
@ -295,10 +308,10 @@ class DownloadBottomSheetDialog(private var result: ResultItem, private val type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lifecycleScope.launch {
|
CoroutineScope(Dispatchers.IO).launch{
|
||||||
downloadViewModel.uiState.collectLatest { res ->
|
downloadViewModel.uiState.collectLatest { res ->
|
||||||
if (res.errorMessage != null) {
|
if (res.errorMessage != null) {
|
||||||
UiUtil.handleDownloadsResponse(requireActivity() as MainActivity, res, downloadViewModel)
|
UiUtil.handleDownloadsResponse(requireActivity() as MainActivity, res, downloadViewModel, historyViewModel)
|
||||||
downloadViewModel.uiState.value = DownloadViewModel.DownloadsUiState(
|
downloadViewModel.uiState.value = DownloadViewModel.DownloadsUiState(
|
||||||
errorMessage = null,
|
errorMessage = null,
|
||||||
actions = null
|
actions = null
|
||||||
|
|
@ -306,6 +319,17 @@ class DownloadBottomSheetDialog(private var result: ResultItem, private val type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lifecycleScope.launch {
|
||||||
|
resultViewModel.uiState.collectLatest { res ->
|
||||||
|
if (res.errorMessage != null){
|
||||||
|
kotlin.runCatching { UiUtil.handleResultResponse(requireActivity(), res, closed = {
|
||||||
|
dismiss()
|
||||||
|
}) }
|
||||||
|
resultViewModel.uiState.update {it.copy(errorMessage = null, actions = null) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
private fun getDownloadItem(selectedTabPosition: Int = tabLayout.selectedTabPosition) : DownloadItem{
|
private fun getDownloadItem(selectedTabPosition: Int = tabLayout.selectedTabPosition) : DownloadItem{
|
||||||
return when(selectedTabPosition){
|
return when(selectedTabPosition){
|
||||||
|
|
@ -344,12 +368,12 @@ class DownloadBottomSheetDialog(private var result: ResultItem, private val type
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initUpdateData(v: View){
|
private fun initUpdateData(v: View){
|
||||||
CoroutineScope(SupervisorJob()).launch(Dispatchers.IO){
|
val shimmerLoading = v.findViewById<ShimmerFrameLayout>(R.id.shimmer_loading_title)
|
||||||
val shimmerLoading = v.findViewById<ShimmerFrameLayout>(R.id.shimmer_loading_title)
|
val title = v.findViewById<View>(R.id.bottom_sheet_title)
|
||||||
val title = v.findViewById<View>(R.id.bottom_sheet_title)
|
val shimmerLoadingSubtitle = v.findViewById<ShimmerFrameLayout>(R.id.shimmer_loading_subtitle)
|
||||||
|
val subtitle = v.findViewById<View>(R.id.bottom_sheet_subtitle)
|
||||||
|
|
||||||
val shimmerLoadingSubtitle = v.findViewById<ShimmerFrameLayout>(R.id.shimmer_loading_subtitle)
|
val updateJob = CoroutineScope(SupervisorJob()).launch(Dispatchers.IO){
|
||||||
val subtitle = v.findViewById<View>(R.id.bottom_sheet_subtitle)
|
|
||||||
withContext(Dispatchers.Main){
|
withContext(Dispatchers.Main){
|
||||||
title.visibility = View.GONE
|
title.visibility = View.GONE
|
||||||
subtitle.visibility = View.GONE
|
subtitle.visibility = View.GONE
|
||||||
|
|
@ -367,12 +391,6 @@ class DownloadBottomSheetDialog(private var result: ResultItem, private val type
|
||||||
|
|
||||||
val result = resultViewModel.parseQueries(listOf(result.url))
|
val result = resultViewModel.parseQueries(listOf(result.url))
|
||||||
if (result.isEmpty()){
|
if (result.isEmpty()){
|
||||||
withContext(Dispatchers.Main){
|
|
||||||
Looper.prepare().run {
|
|
||||||
Toast.makeText(requireContext(), "No Results Found!", Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
|
||||||
dismiss()
|
|
||||||
}
|
|
||||||
return@launch
|
return@launch
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -421,6 +439,21 @@ class DownloadBottomSheetDialog(private var result: ResultItem, private val type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
shimmerLoading.setOnClickListener {
|
||||||
|
updateJob.cancel()
|
||||||
|
}
|
||||||
|
updateJob.invokeOnCompletion {
|
||||||
|
requireActivity().runOnUiThread {
|
||||||
|
title.visibility = View.VISIBLE
|
||||||
|
subtitle.visibility = View.VISIBLE
|
||||||
|
shimmerLoading.visibility = View.GONE
|
||||||
|
shimmerLoadingSubtitle.visibility = View.GONE
|
||||||
|
shimmerLoading.stopShimmer()
|
||||||
|
shimmerLoadingSubtitle.stopShimmer()
|
||||||
|
(updateItem.parent as LinearLayout).visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateJob.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initUpdateFormats(url: String){
|
private fun initUpdateFormats(url: String){
|
||||||
|
|
@ -436,7 +469,11 @@ class DownloadBottomSheetDialog(private var result: ResultItem, private val type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val formats = infoUtil.getFormats(url).toMutableList()
|
val formats = runCatching {
|
||||||
|
infoUtil.getFormats(url).toMutableList()
|
||||||
|
}.getOrElse {
|
||||||
|
mutableListOf()
|
||||||
|
}
|
||||||
|
|
||||||
withContext(Dispatchers.Main){
|
withContext(Dispatchers.Main){
|
||||||
runCatching {
|
runCatching {
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,8 @@ import android.content.SharedPreferences
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.Editable
|
import android.text.Editable
|
||||||
import android.text.TextWatcher
|
import android.text.TextWatcher
|
||||||
import android.util.Log
|
|
||||||
import android.util.Patterns
|
import android.util.Patterns
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.MotionEvent
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.*
|
import android.widget.*
|
||||||
|
|
@ -23,6 +21,7 @@ import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
|
import com.afollestad.materialdialogs.utils.MDUtil.getStringArray
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
||||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||||
|
|
@ -30,7 +29,6 @@ import com.deniscerri.ytdlnis.database.models.Format
|
||||||
import com.deniscerri.ytdlnis.database.models.ResultItem
|
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.CommandTemplateViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.CommandTemplateViewModel
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||||
import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding
|
|
||||||
import com.deniscerri.ytdlnis.util.FileUtil
|
import com.deniscerri.ytdlnis.util.FileUtil
|
||||||
import com.deniscerri.ytdlnis.util.UiUtil
|
import com.deniscerri.ytdlnis.util.UiUtil
|
||||||
import com.deniscerri.ytdlnis.util.UiUtil.enableTextHighlight
|
import com.deniscerri.ytdlnis.util.UiUtil.enableTextHighlight
|
||||||
|
|
@ -39,7 +37,9 @@ import com.google.android.material.card.MaterialCardView
|
||||||
import com.google.android.material.chip.Chip
|
import com.google.android.material.chip.Chip
|
||||||
import com.google.android.material.textfield.TextInputLayout
|
import com.google.android.material.textfield.TextInputLayout
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
@ -66,7 +66,7 @@ class DownloadCommandFragment(private val resultItem: ResultItem? = null, privat
|
||||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||||
commandTemplateViewModel = ViewModelProvider(this)[CommandTemplateViewModel::class.java]
|
commandTemplateViewModel = ViewModelProvider(this)[CommandTemplateViewModel::class.java]
|
||||||
preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||||
shownFields = preferences.getStringSet("modify_download_card", setOf())!!.toList()
|
shownFields = preferences.getStringSet("modify_download_card", setOf())!!.toList().ifEmpty { requireContext().getStringArray(R.array.modify_download_card_values).toList() }
|
||||||
return fragmentView
|
return fragmentView
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -84,6 +84,8 @@ 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()){
|
if (!Patterns.WEB_URL.matcher(downloadItem.url).matches()){
|
||||||
downloadItem.format = downloadViewModel.generateCommandFormat(CommandTemplate(0,"txt", "-a \"${downloadItem.url}\"", false))
|
downloadItem.format = downloadViewModel.generateCommandFormat(CommandTemplate(0,"txt", "-a \"${downloadItem.url}\"", false))
|
||||||
downloadItem.url = ""
|
downloadItem.url = ""
|
||||||
|
|
@ -117,6 +119,7 @@ class DownloadCommandFragment(private val resultItem: ResultItem? = null, privat
|
||||||
0,
|
0,
|
||||||
p0.toString()
|
p0.toString()
|
||||||
)
|
)
|
||||||
|
preferences.edit().putString("lastCommandTemplateUsed", p0.toString()).apply()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -132,7 +135,6 @@ class DownloadCommandFragment(private val resultItem: ResultItem? = null, privat
|
||||||
|
|
||||||
val commandTemplateCard = view.findViewById<MaterialCardView>(R.id.command_card)
|
val commandTemplateCard = view.findViewById<MaterialCardView>(R.id.command_card)
|
||||||
runCatching {
|
runCatching {
|
||||||
populateCommandCard(commandTemplateCard, templates.first())
|
|
||||||
commandTemplateCard.setOnClickListener {
|
commandTemplateCard.setOnClickListener {
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
UiUtil.showCommandTemplates(requireActivity(), commandTemplateViewModel){
|
UiUtil.showCommandTemplates(requireActivity(), commandTemplateViewModel){
|
||||||
|
|
@ -141,6 +143,7 @@ class DownloadCommandFragment(private val resultItem: ResultItem? = null, privat
|
||||||
chosenCommandView.editText!!.text.insert(chosenCommandView.editText!!.selectionStart, "${c.content} ")
|
chosenCommandView.editText!!.text.insert(chosenCommandView.editText!!.selectionStart, "${c.content} ")
|
||||||
}
|
}
|
||||||
populateCommandCard(commandTemplateCard, it.first())
|
populateCommandCard(commandTemplateCard, it.first())
|
||||||
|
|
||||||
downloadItem.format = Format(
|
downloadItem.format = Format(
|
||||||
it.first().title,
|
it.first().title,
|
||||||
"",
|
"",
|
||||||
|
|
@ -148,15 +151,20 @@ class DownloadCommandFragment(private val resultItem: ResultItem? = null, privat
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
0,
|
0,
|
||||||
it.map { c -> c.content }.joinToString { " " }
|
it.joinToString(" ") { c -> c.content }
|
||||||
)
|
)
|
||||||
|
preferences.edit().putString("lastCommandTemplateUsed", downloadItem.format.format_note).apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
if (downloadItem.url.isEmpty()){
|
val existingTemplate = withContext(Dispatchers.IO){
|
||||||
view.findViewById<MaterialCardView>(R.id.command_card).alpha = 0.3f
|
templates.firstOrNull { it.content.replace("^ +|\n| +$".toRegex(), " ") == downloadItem.format.format_note.trim() }
|
||||||
|
}
|
||||||
|
populateCommandCard(commandTemplateCard,existingTemplate ?: templates.first())
|
||||||
|
if (downloadItem.url.isEmpty() || existingTemplate == null){
|
||||||
|
commandTemplateCard.alpha = 0.3f
|
||||||
}
|
}
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
commandTemplateCard.visibility = View.GONE
|
commandTemplateCard.visibility = View.GONE
|
||||||
|
|
@ -189,7 +197,7 @@ class DownloadCommandFragment(private val resultItem: ResultItem? = null, privat
|
||||||
|
|
||||||
|
|
||||||
view.findViewById<LinearLayout>(R.id.adjust).apply {
|
view.findViewById<LinearLayout>(R.id.adjust).apply {
|
||||||
visibility = if (shownFields.contains("adjust_command")) View.VISIBLE else View.GONE
|
visibility = if (shownFields.contains("adjust_templates")) View.VISIBLE else View.GONE
|
||||||
if (isVisible){
|
if (isVisible){
|
||||||
UiUtil.configureCommand(
|
UiUtil.configureCommand(
|
||||||
view,
|
view,
|
||||||
|
|
@ -208,6 +216,7 @@ class DownloadCommandFragment(private val resultItem: ResultItem? = null, privat
|
||||||
0,
|
0,
|
||||||
it.content
|
it.content
|
||||||
)
|
)
|
||||||
|
preferences.edit().putString("lastCommandTemplateUsed", it.content).apply()
|
||||||
commandTemplateCard.visibility = View.VISIBLE
|
commandTemplateCard.visibility = View.VISIBLE
|
||||||
view.findViewById<TextView>(R.id.command_txt).visibility = View.VISIBLE
|
view.findViewById<TextView>(R.id.command_txt).visibility = View.VISIBLE
|
||||||
view.findViewById<Chip>(R.id.editSelected).isEnabled = true
|
view.findViewById<Chip>(R.id.editSelected).isEnabled = true
|
||||||
|
|
@ -237,6 +246,7 @@ class DownloadCommandFragment(private val resultItem: ResultItem? = null, privat
|
||||||
0,
|
0,
|
||||||
it.content
|
it.content
|
||||||
)
|
)
|
||||||
|
preferences.edit().putString("lastCommandTemplateUsed", it.content).apply()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
shortcutClicked = {
|
shortcutClicked = {
|
||||||
|
|
@ -244,6 +254,7 @@ class DownloadCommandFragment(private val resultItem: ResultItem? = null, privat
|
||||||
itemSelected = {
|
itemSelected = {
|
||||||
chosenCommandView.editText!!.setText("${chosenCommandView.editText!!.text} $it")
|
chosenCommandView.editText!!.setText("${chosenCommandView.editText!!.text} $it")
|
||||||
downloadItem.format.format_note = chosenCommandView.editText!!.text.toString()
|
downloadItem.format.format_note = chosenCommandView.editText!!.text.toString()
|
||||||
|
preferences.edit().putString("lastCommandTemplateUsed", downloadItem.format.format_note).apply()
|
||||||
},
|
},
|
||||||
itemRemoved = {removed ->
|
itemRemoved = {removed ->
|
||||||
chosenCommandView.editText!!.setText(chosenCommandView.editText!!.text.replace("(${
|
chosenCommandView.editText!!.setText(chosenCommandView.editText!!.text.replace("(${
|
||||||
|
|
@ -252,6 +263,8 @@ class DownloadCommandFragment(private val resultItem: ResultItem? = null, privat
|
||||||
)
|
)
|
||||||
})(?!.*\\1)".toRegex(), "").trimEnd())
|
})(?!.*\\1)".toRegex(), "").trimEnd())
|
||||||
downloadItem.format.format_note = chosenCommandView.editText!!.text.toString().trimEnd()
|
downloadItem.format.format_note = chosenCommandView.editText!!.text.toString().trimEnd()
|
||||||
|
preferences.edit().putString("lastCommandTemplateUsed",
|
||||||
|
chosenCommandView.editText!!.text.toString().trimEnd()).apply()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -34,12 +34,13 @@ import androidx.work.OneTimeWorkRequestBuilder
|
||||||
import androidx.work.WorkManager
|
import androidx.work.WorkManager
|
||||||
import com.deniscerri.ytdlnis.MainActivity
|
import com.deniscerri.ytdlnis.MainActivity
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.adapter.ConfigureMultipleDownloadsAdapter
|
import com.deniscerri.ytdlnis.ui.adapter.ConfigureMultipleDownloadsAdapter
|
||||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||||
import com.deniscerri.ytdlnis.database.models.Format
|
import com.deniscerri.ytdlnis.database.models.Format
|
||||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.CommandTemplateViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.CommandTemplateViewModel
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||||
|
import com.deniscerri.ytdlnis.database.viewmodel.HistoryViewModel
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
|
||||||
import com.deniscerri.ytdlnis.receiver.ShareActivity
|
import com.deniscerri.ytdlnis.receiver.ShareActivity
|
||||||
import com.deniscerri.ytdlnis.util.FileUtil
|
import com.deniscerri.ytdlnis.util.FileUtil
|
||||||
|
|
@ -67,6 +68,7 @@ import java.util.Locale
|
||||||
class DownloadMultipleBottomSheetDialog(private var items: MutableList<DownloadItem>) : BottomSheetDialogFragment(), ConfigureMultipleDownloadsAdapter.OnItemClickListener, View.OnClickListener,
|
class DownloadMultipleBottomSheetDialog(private var items: MutableList<DownloadItem>) : BottomSheetDialogFragment(), ConfigureMultipleDownloadsAdapter.OnItemClickListener, View.OnClickListener,
|
||||||
ConfigureDownloadBottomSheetDialog.OnDownloadItemUpdateListener {
|
ConfigureDownloadBottomSheetDialog.OnDownloadItemUpdateListener {
|
||||||
private lateinit var downloadViewModel: DownloadViewModel
|
private lateinit var downloadViewModel: DownloadViewModel
|
||||||
|
private lateinit var historyViewModel: HistoryViewModel
|
||||||
private lateinit var commandTemplateViewModel: CommandTemplateViewModel
|
private lateinit var commandTemplateViewModel: CommandTemplateViewModel
|
||||||
private lateinit var resultViewModel: ResultViewModel
|
private lateinit var resultViewModel: ResultViewModel
|
||||||
private lateinit var listAdapter : ConfigureMultipleDownloadsAdapter
|
private lateinit var listAdapter : ConfigureMultipleDownloadsAdapter
|
||||||
|
|
@ -81,6 +83,7 @@ class DownloadMultipleBottomSheetDialog(private var items: MutableList<DownloadI
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
downloadViewModel = ViewModelProvider(requireActivity())[DownloadViewModel::class.java]
|
downloadViewModel = ViewModelProvider(requireActivity())[DownloadViewModel::class.java]
|
||||||
|
historyViewModel = ViewModelProvider(requireActivity())[HistoryViewModel::class.java]
|
||||||
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
|
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
|
||||||
commandTemplateViewModel = ViewModelProvider(this)[CommandTemplateViewModel::class.java]
|
commandTemplateViewModel = ViewModelProvider(this)[CommandTemplateViewModel::class.java]
|
||||||
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||||
|
|
@ -472,10 +475,8 @@ class DownloadMultipleBottomSheetDialog(private var items: MutableList<DownloadI
|
||||||
saveSubtitlesClicked = {checked ->
|
saveSubtitlesClicked = {checked ->
|
||||||
items.forEach { it.videoPreferences.writeSubs = checked }
|
items.forEach { it.videoPreferences.writeSubs = checked }
|
||||||
},
|
},
|
||||||
subtitleLanguagesClicked = {
|
subtitleLanguagesSet = {value ->
|
||||||
UiUtil.showSubtitleLanguagesDialog(requireActivity(), ""){ value ->
|
items.forEach { it.videoPreferences.subsLanguages = value }
|
||||||
items.forEach { it.videoPreferences.subsLanguages = value }
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
removeAudioClicked = {checked ->
|
removeAudioClicked = {checked ->
|
||||||
items.forEach { it.videoPreferences.removeAudio = checked }
|
items.forEach { it.videoPreferences.removeAudio = checked }
|
||||||
|
|
@ -509,7 +510,7 @@ class DownloadMultipleBottomSheetDialog(private var items: MutableList<DownloadI
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
downloadViewModel.uiState.collectLatest { res ->
|
downloadViewModel.uiState.collectLatest { res ->
|
||||||
if (res.errorMessage != null) {
|
if (res.errorMessage != null) {
|
||||||
UiUtil.handleDownloadsResponse(requireActivity() as MainActivity, res, downloadViewModel)
|
UiUtil.handleDownloadsResponse(requireActivity() as MainActivity, res, downloadViewModel, historyViewModel)
|
||||||
downloadViewModel.uiState.value = DownloadViewModel.DownloadsUiState(
|
downloadViewModel.uiState.value = DownloadViewModel.DownloadsUiState(
|
||||||
errorMessage = null,
|
errorMessage = null,
|
||||||
actions = null
|
actions = null
|
||||||
|
|
@ -638,6 +639,24 @@ class DownloadMultipleBottomSheetDialog(private var items: MutableList<DownloadI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onDelete(itemURL: String) {
|
||||||
|
val deletedItem = items.find { it.url == itemURL } ?: return
|
||||||
|
val position = items.indexOf(deletedItem)
|
||||||
|
UiUtil.showGenericDeleteDialog(requireContext(), deletedItem.title){
|
||||||
|
items.remove(deletedItem)
|
||||||
|
listAdapter.submitList(items.toList())
|
||||||
|
if (items.isNotEmpty()){
|
||||||
|
Snackbar.make(recyclerView, getString(R.string.you_are_going_to_delete) + ": " + deletedItem.title, Snackbar.LENGTH_LONG)
|
||||||
|
.setAction(getString(R.string.undo)) {
|
||||||
|
items.add(position, deletedItem)
|
||||||
|
listAdapter.submitList(items.toList())
|
||||||
|
}.show()
|
||||||
|
}else{
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onClick(p0: View?) {
|
override fun onClick(p0: View?) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ import android.content.SharedPreferences
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.Editable
|
import android.text.Editable
|
||||||
import android.text.TextWatcher
|
import android.text.TextWatcher
|
||||||
import android.util.Log
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
|
@ -23,6 +22,7 @@ import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
|
import com.afollestad.materialdialogs.utils.MDUtil.getStringArray
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||||
import com.deniscerri.ytdlnis.database.models.Format
|
import com.deniscerri.ytdlnis.database.models.Format
|
||||||
|
|
@ -35,6 +35,9 @@ import com.deniscerri.ytdlnis.util.InfoUtil
|
||||||
import com.deniscerri.ytdlnis.util.UiUtil
|
import com.deniscerri.ytdlnis.util.UiUtil
|
||||||
import com.google.android.material.card.MaterialCardView
|
import com.google.android.material.card.MaterialCardView
|
||||||
import com.google.android.material.textfield.TextInputLayout
|
import com.google.android.material.textfield.TextInputLayout
|
||||||
|
import com.google.android.material.textfield.TextInputLayout.END_ICON_CUSTOM
|
||||||
|
import com.google.android.material.textfield.TextInputLayout.END_ICON_NONE
|
||||||
|
import com.google.android.material.textfield.TextInputLayout.EndIconMode
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
@ -71,7 +74,7 @@ class DownloadVideoFragment(private var resultItem: ResultItem? = null, private
|
||||||
infoUtil = InfoUtil(requireContext())
|
infoUtil = InfoUtil(requireContext())
|
||||||
genericVideoFormats = infoUtil.getGenericVideoFormats(requireContext().resources)
|
genericVideoFormats = infoUtil.getGenericVideoFormats(requireContext().resources)
|
||||||
preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||||
shownFields = preferences.getStringSet("modify_download_card", setOf())!!.toList()
|
shownFields = preferences.getStringSet("modify_download_card", setOf())!!.toList().ifEmpty { requireContext().getStringArray(R.array.modify_download_card_values).toList() }
|
||||||
return fragmentView
|
return fragmentView
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -95,6 +98,7 @@ class DownloadVideoFragment(private var resultItem: ResultItem? = null, private
|
||||||
title.visibility = if (shownFields.contains("title")) View.VISIBLE else View.GONE
|
title.visibility = if (shownFields.contains("title")) View.VISIBLE else View.GONE
|
||||||
if (title.editText?.text?.isEmpty() == true){
|
if (title.editText?.text?.isEmpty() == true){
|
||||||
title.editText!!.setText(downloadItem.title)
|
title.editText!!.setText(downloadItem.title)
|
||||||
|
title.endIconMode = END_ICON_NONE
|
||||||
}
|
}
|
||||||
title.editText!!.addTextChangedListener(object : TextWatcher {
|
title.editText!!.addTextChangedListener(object : TextWatcher {
|
||||||
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
|
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
|
||||||
|
|
@ -108,6 +112,7 @@ class DownloadVideoFragment(private var resultItem: ResultItem? = null, private
|
||||||
author.visibility = if (shownFields.contains("author")) View.VISIBLE else View.GONE
|
author.visibility = if (shownFields.contains("author")) View.VISIBLE else View.GONE
|
||||||
if (author.editText?.text?.isEmpty() == true){
|
if (author.editText?.text?.isEmpty() == true){
|
||||||
author.editText!!.setText(downloadItem.author)
|
author.editText!!.setText(downloadItem.author)
|
||||||
|
author.endIconMode = END_ICON_NONE
|
||||||
}
|
}
|
||||||
author.editText!!.addTextChangedListener(object : TextWatcher {
|
author.editText!!.addTextChangedListener(object : TextWatcher {
|
||||||
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
|
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
|
||||||
|
|
@ -119,16 +124,32 @@ class DownloadVideoFragment(private var resultItem: ResultItem? = null, private
|
||||||
|
|
||||||
if (savedInstanceState?.containsKey("updated") == true){
|
if (savedInstanceState?.containsKey("updated") == true){
|
||||||
if (!listOf(resultItem?.title, downloadItem.title).contains(title.editText?.text.toString())){
|
if (!listOf(resultItem?.title, downloadItem.title).contains(title.editText?.text.toString())){
|
||||||
|
title.endIconMode = END_ICON_CUSTOM
|
||||||
title.endIconDrawable = AppCompatResources.getDrawable(requireContext(), R.drawable.ic_refresh)
|
title.endIconDrawable = AppCompatResources.getDrawable(requireContext(), R.drawable.ic_refresh)
|
||||||
downloadItem.title = title.editText?.text.toString()
|
downloadItem.title = title.editText?.text.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!listOf(resultItem?.author, downloadItem.author).contains(author.editText?.text.toString())){
|
if (!listOf(resultItem?.author, downloadItem.author).contains(author.editText?.text.toString())){
|
||||||
|
author.endIconMode = END_ICON_CUSTOM
|
||||||
author.endIconDrawable = AppCompatResources.getDrawable(requireContext(), R.drawable.ic_refresh)
|
author.endIconDrawable = AppCompatResources.getDrawable(requireContext(), R.drawable.ic_refresh)
|
||||||
downloadItem.author = author.editText?.text.toString()
|
downloadItem.author = author.editText?.text.toString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
title.setEndIconOnClickListener {
|
||||||
|
if (resultItem != null){
|
||||||
|
title.editText?.setText(resultItem?.title)
|
||||||
|
}
|
||||||
|
title.endIconMode = END_ICON_NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
author.setEndIconOnClickListener {
|
||||||
|
if (resultItem != null){
|
||||||
|
author.editText?.setText(resultItem?.author)
|
||||||
|
}
|
||||||
|
author.endIconMode = END_ICON_NONE
|
||||||
|
}
|
||||||
|
|
||||||
saveDir = view.findViewById(R.id.outputPath)
|
saveDir = view.findViewById(R.id.outputPath)
|
||||||
saveDir.editText!!.setText(
|
saveDir.editText!!.setText(
|
||||||
FileUtil.formatPath(downloadItem.downloadPath)
|
FileUtil.formatPath(downloadItem.downloadPath)
|
||||||
|
|
@ -282,10 +303,8 @@ class DownloadVideoFragment(private var resultItem: ResultItem? = null, private
|
||||||
saveSubtitlesClicked = {
|
saveSubtitlesClicked = {
|
||||||
downloadItem.videoPreferences.writeSubs = it
|
downloadItem.videoPreferences.writeSubs = it
|
||||||
},
|
},
|
||||||
subtitleLanguagesClicked = {
|
subtitleLanguagesSet = {
|
||||||
UiUtil.showSubtitleLanguagesDialog(requireActivity(), downloadItem.videoPreferences.subsLanguages){
|
downloadItem.videoPreferences.subsLanguages = it
|
||||||
downloadItem.videoPreferences.subsLanguages = it
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
removeAudioClicked = {
|
removeAudioClicked = {
|
||||||
downloadItem.videoPreferences.removeAudio = it
|
downloadItem.videoPreferences.removeAudio = it
|
||||||
|
|
@ -313,9 +332,9 @@ class DownloadVideoFragment(private var resultItem: ResultItem? = null, private
|
||||||
downloadItem.title = t
|
downloadItem.title = t
|
||||||
downloadItem.author = a
|
downloadItem.author = a
|
||||||
title.editText?.setText(t)
|
title.editText?.setText(t)
|
||||||
title.endIconDrawable = null
|
title.endIconMode = END_ICON_NONE
|
||||||
author.editText?.setText(a)
|
author.editText?.setText(a)
|
||||||
title.endIconDrawable = null
|
title.endIconMode = END_ICON_NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateUI(res: ResultItem?) {
|
override fun updateUI(res: ResultItem?) {
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ import android.util.DisplayMetrics
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.*
|
import android.widget.*
|
||||||
import androidx.compose.runtime.invalidateGroupsWithKey
|
|
||||||
import androidx.core.view.forEach
|
import androidx.core.view.forEach
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
|
@ -27,7 +26,6 @@ import com.google.android.material.snackbar.Snackbar
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import okhttp3.internal.format
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -217,9 +215,9 @@ class FormatSelectionBottomSheetDialog(private val items: List<DownloadItem?>, p
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sharedPreferences.getBoolean("update_formats", false) && refreshBtn.isVisible && items.size == 1){
|
// if (sharedPreferences.getBoolean("update_formats", false) && refreshBtn.isVisible && items.size == 1){
|
||||||
refreshBtn.performClick()
|
// refreshBtn.performClick()
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun returnFormats(){
|
private fun returnFormats(){
|
||||||
|
|
|
||||||
|
|
@ -37,9 +37,9 @@ import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import androidx.work.WorkManager
|
import androidx.work.WorkManager
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.adapter.ActiveDownloadAdapter
|
import com.deniscerri.ytdlnis.ui.adapter.ActiveDownloadAdapter
|
||||||
import com.deniscerri.ytdlnis.adapter.ActiveDownloadMinifiedAdapter
|
import com.deniscerri.ytdlnis.ui.adapter.ActiveDownloadMinifiedAdapter
|
||||||
import com.deniscerri.ytdlnis.adapter.GenericDownloadAdapter
|
import com.deniscerri.ytdlnis.ui.adapter.GenericDownloadAdapter
|
||||||
import com.deniscerri.ytdlnis.database.models.ResultItem
|
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||||
|
|
@ -136,6 +136,9 @@ class ResultCardDetailsDialog(private val item: ResultItem) : BottomSheetDialogF
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
//remove outdated player url of 1hr so it can refetch it in the player
|
||||||
|
if (item.creationTime > System.currentTimeMillis() - 3600000) item.urls = ""
|
||||||
|
|
||||||
activeAdapter = ActiveDownloadMinifiedAdapter(this,requireActivity())
|
activeAdapter = ActiveDownloadMinifiedAdapter(this,requireActivity())
|
||||||
queuedAdapter = GenericDownloadAdapter(this,requireActivity())
|
queuedAdapter = GenericDownloadAdapter(this,requireActivity())
|
||||||
|
|
||||||
|
|
@ -220,10 +223,10 @@ class ResultCardDetailsDialog(private val item: ResultItem) : BottomSheetDialogF
|
||||||
|
|
||||||
bottomSheetLink.text = item.url
|
bottomSheetLink.text = item.url
|
||||||
bottomSheetLink.setOnClickListener{
|
bottomSheetLink.setOnClickListener{
|
||||||
UiUtil.openLinkIntent(requireContext(), item.url, null)
|
UiUtil.openLinkIntent(requireContext(), item.url)
|
||||||
}
|
}
|
||||||
bottomSheetLink.setOnLongClickListener{
|
bottomSheetLink.setOnLongClickListener{
|
||||||
UiUtil.copyLinkToClipBoard(requireContext(), item.url, null)
|
UiUtil.copyLinkToClipBoard(requireContext(), item.url)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -505,10 +508,12 @@ class ResultCardDetailsDialog(private val item: ResultItem) : BottomSheetDialogF
|
||||||
link!!.text = url
|
link!!.text = url
|
||||||
link.tag = itemID
|
link.tag = itemID
|
||||||
link.setOnClickListener{
|
link.setOnClickListener{
|
||||||
UiUtil.openLinkIntent(requireContext(), item.url, bottomSheet)
|
bottomSheet.dismiss()
|
||||||
|
UiUtil.openLinkIntent(requireContext(), item.url)
|
||||||
}
|
}
|
||||||
link.setOnLongClickListener{
|
link.setOnLongClickListener{
|
||||||
UiUtil.copyLinkToClipBoard(requireContext(), item.url, bottomSheet)
|
bottomSheet.dismiss()
|
||||||
|
UiUtil.copyLinkToClipBoard(requireContext(), item.url)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
val remove = bottomSheet.findViewById<Button>(R.id.bottomsheet_remove_button)
|
val remove = bottomSheet.findViewById<Button>(R.id.bottomsheet_remove_button)
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,14 @@
|
||||||
package com.deniscerri.ytdlnis.ui.downloadcard
|
package com.deniscerri.ytdlnis.ui.downloadcard
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.app.ActionBar.LayoutParams
|
import android.app.ActionBar.LayoutParams
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.DisplayMetrics
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.Window
|
import android.view.Window
|
||||||
import android.widget.Button
|
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.core.widget.doAfterTextChanged
|
import androidx.core.widget.doAfterTextChanged
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
|
@ -20,7 +16,7 @@ import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.adapter.PlaylistAdapter
|
import com.deniscerri.ytdlnis.ui.adapter.PlaylistAdapter
|
||||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||||
import com.deniscerri.ytdlnis.database.models.ResultItem
|
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||||
|
|
@ -30,14 +26,10 @@ import com.deniscerri.ytdlnis.util.UiUtil.enableFastScroll
|
||||||
import com.deniscerri.ytdlnis.util.UiUtil.setTextAndRecalculateWidth
|
import com.deniscerri.ytdlnis.util.UiUtil.setTextAndRecalculateWidth
|
||||||
import com.google.android.material.appbar.MaterialToolbar
|
import com.google.android.material.appbar.MaterialToolbar
|
||||||
import com.google.android.material.bottomappbar.BottomAppBar
|
import com.google.android.material.bottomappbar.BottomAppBar
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|
||||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||||
import com.google.android.material.textfield.TextInputLayout
|
import com.google.android.material.textfield.TextInputLayout
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
class SelectPlaylistItemsDialog(private val items: List<ResultItem?>, private val type: DownloadViewModel.Type) : DialogFragment(), PlaylistAdapter.OnItemClickListener {
|
class SelectPlaylistItemsDialog(private val items: List<ResultItem?>, private val type: DownloadViewModel.Type) : DialogFragment(), PlaylistAdapter.OnItemClickListener {
|
||||||
private lateinit var downloadViewModel: DownloadViewModel
|
private lateinit var downloadViewModel: DownloadViewModel
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.View.OnClickListener
|
import android.view.View.OnClickListener
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.widget.RelativeLayout
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
|
@ -17,7 +18,7 @@ import androidx.work.WorkInfo
|
||||||
import androidx.work.WorkManager
|
import androidx.work.WorkManager
|
||||||
import androidx.work.WorkQuery
|
import androidx.work.WorkQuery
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.adapter.ActiveDownloadAdapter
|
import com.deniscerri.ytdlnis.ui.adapter.ActiveDownloadAdapter
|
||||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||||
|
|
@ -41,6 +42,7 @@ class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickLis
|
||||||
lateinit var downloadItem: DownloadItem
|
lateinit var downloadItem: DownloadItem
|
||||||
private lateinit var notificationUtil: NotificationUtil
|
private lateinit var notificationUtil: NotificationUtil
|
||||||
private lateinit var pauseResume: MaterialButton
|
private lateinit var pauseResume: MaterialButton
|
||||||
|
private lateinit var noResults: RelativeLayout
|
||||||
private lateinit var workManager: WorkManager
|
private lateinit var workManager: WorkManager
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -71,6 +73,7 @@ class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickLis
|
||||||
activeRecyclerView.adapter = activeDownloads
|
activeRecyclerView.adapter = activeDownloads
|
||||||
activeRecyclerView.layoutManager = GridLayoutManager(context, resources.getInteger(R.integer.grid_size))
|
activeRecyclerView.layoutManager = GridLayoutManager(context, resources.getInteger(R.integer.grid_size))
|
||||||
pauseResume = view.findViewById(R.id.pause_resume)
|
pauseResume = view.findViewById(R.id.pause_resume)
|
||||||
|
noResults = view.findViewById(R.id.no_results)
|
||||||
|
|
||||||
pauseResume.setOnClickListener {
|
pauseResume.setOnClickListener {
|
||||||
if (pauseResume.text == requireContext().getString(R.string.pause)){
|
if (pauseResume.text == requireContext().getString(R.string.pause)){
|
||||||
|
|
@ -168,6 +171,7 @@ class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickLis
|
||||||
activeDownloads.notifyDataSetChanged()
|
activeDownloads.notifyDataSetChanged()
|
||||||
pauseResume.visibility = View.GONE
|
pauseResume.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
noResults.visibility = if (it.isEmpty()) View.VISIBLE else View.GONE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.widget.RelativeLayout
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.view.ActionMode
|
import androidx.appcompat.view.ActionMode
|
||||||
|
|
@ -21,7 +22,7 @@ import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.adapter.GenericDownloadAdapter
|
import com.deniscerri.ytdlnis.ui.adapter.GenericDownloadAdapter
|
||||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||||
|
|
@ -47,6 +48,7 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic
|
||||||
private lateinit var downloadViewModel : DownloadViewModel
|
private lateinit var downloadViewModel : DownloadViewModel
|
||||||
private lateinit var cancelledRecyclerView : RecyclerView
|
private lateinit var cancelledRecyclerView : RecyclerView
|
||||||
private lateinit var adapter : GenericDownloadAdapter
|
private lateinit var adapter : GenericDownloadAdapter
|
||||||
|
private lateinit var noResults : RelativeLayout
|
||||||
private var actionMode : ActionMode? = null
|
private var actionMode : ActionMode? = null
|
||||||
private var totalSize = 0
|
private var totalSize = 0
|
||||||
|
|
||||||
|
|
@ -55,7 +57,7 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): View? {
|
): View? {
|
||||||
fragmentView = inflater.inflate(R.layout.generic_recyclerview, container, false)
|
fragmentView = inflater.inflate(R.layout.generic_list, container, false)
|
||||||
activity = getActivity()
|
activity = getActivity()
|
||||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||||
return fragmentView
|
return fragmentView
|
||||||
|
|
@ -70,6 +72,7 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic
|
||||||
requireActivity()
|
requireActivity()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
noResults = view.findViewById(R.id.no_results)
|
||||||
cancelledRecyclerView = view.findViewById(R.id.download_recyclerview)
|
cancelledRecyclerView = view.findViewById(R.id.download_recyclerview)
|
||||||
cancelledRecyclerView.forceFastScrollMode()
|
cancelledRecyclerView.forceFastScrollMode()
|
||||||
cancelledRecyclerView.adapter = adapter
|
cancelledRecyclerView.adapter = adapter
|
||||||
|
|
@ -90,6 +93,7 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic
|
||||||
|
|
||||||
downloadViewModel.getTotalSize(listOf(DownloadRepository.Status.Cancelled)).observe(viewLifecycleOwner){
|
downloadViewModel.getTotalSize(listOf(DownloadRepository.Status.Cancelled)).observe(viewLifecycleOwner){
|
||||||
totalSize = it
|
totalSize = it
|
||||||
|
noResults.visibility = if (it == 0) View.VISIBLE else View.GONE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,8 @@ import androidx.viewpager2.widget.ViewPager2
|
||||||
import androidx.work.WorkManager
|
import androidx.work.WorkManager
|
||||||
import com.deniscerri.ytdlnis.MainActivity
|
import com.deniscerri.ytdlnis.MainActivity
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
import com.deniscerri.ytdlnis.util.NotificationUtil
|
||||||
import com.deniscerri.ytdlnis.work.DownloadWorker
|
|
||||||
import com.google.android.material.appbar.MaterialToolbar
|
import com.google.android.material.appbar.MaterialToolbar
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.tabs.TabLayout
|
import com.google.android.material.tabs.TabLayout
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.AdapterView
|
import android.widget.AdapterView
|
||||||
import android.widget.AdapterView.OnItemClickListener
|
import android.widget.AdapterView.OnItemClickListener
|
||||||
|
import android.widget.RelativeLayout
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.view.ActionMode
|
import androidx.appcompat.view.ActionMode
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
|
|
@ -23,7 +24,7 @@ import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.adapter.GenericDownloadAdapter
|
import com.deniscerri.ytdlnis.ui.adapter.GenericDownloadAdapter
|
||||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||||
|
|
@ -48,6 +49,7 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
|
||||||
private var activity: Activity? = null
|
private var activity: Activity? = null
|
||||||
private lateinit var downloadViewModel : DownloadViewModel
|
private lateinit var downloadViewModel : DownloadViewModel
|
||||||
private lateinit var erroredRecyclerView : RecyclerView
|
private lateinit var erroredRecyclerView : RecyclerView
|
||||||
|
private lateinit var noResults : RelativeLayout
|
||||||
private lateinit var adapter : GenericDownloadAdapter
|
private lateinit var adapter : GenericDownloadAdapter
|
||||||
private var actionMode : ActionMode? = null
|
private var actionMode : ActionMode? = null
|
||||||
private var totalSize: Int = 0
|
private var totalSize: Int = 0
|
||||||
|
|
@ -56,7 +58,7 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): View? {
|
): View? {
|
||||||
fragmentView = inflater.inflate(R.layout.generic_recyclerview, container, false)
|
fragmentView = inflater.inflate(R.layout.generic_list, container, false)
|
||||||
activity = getActivity()
|
activity = getActivity()
|
||||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||||
return fragmentView
|
return fragmentView
|
||||||
|
|
@ -71,6 +73,7 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
|
||||||
requireActivity()
|
requireActivity()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
noResults = view.findViewById(R.id.no_results)
|
||||||
erroredRecyclerView = view.findViewById(R.id.download_recyclerview)
|
erroredRecyclerView = view.findViewById(R.id.download_recyclerview)
|
||||||
erroredRecyclerView.forceFastScrollMode()
|
erroredRecyclerView.forceFastScrollMode()
|
||||||
erroredRecyclerView.adapter = adapter
|
erroredRecyclerView.adapter = adapter
|
||||||
|
|
@ -90,6 +93,7 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
|
||||||
|
|
||||||
downloadViewModel.getTotalSize(listOf(DownloadRepository.Status.Error)).observe(viewLifecycleOwner){
|
downloadViewModel.getTotalSize(listOf(DownloadRepository.Status.Error)).observe(viewLifecycleOwner){
|
||||||
totalSize = it
|
totalSize = it
|
||||||
|
noResults.visibility = if (it == 0) View.VISIBLE else View.GONE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.deniscerri.ytdlnis.MainActivity
|
import com.deniscerri.ytdlnis.MainActivity
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.adapter.HistoryAdapter
|
import com.deniscerri.ytdlnis.ui.adapter.HistoryAdapter
|
||||||
import com.deniscerri.ytdlnis.database.models.HistoryItem
|
import com.deniscerri.ytdlnis.database.models.HistoryItem
|
||||||
import com.deniscerri.ytdlnis.database.repository.HistoryRepository
|
import com.deniscerri.ytdlnis.database.repository.HistoryRepository
|
||||||
import com.deniscerri.ytdlnis.database.DBManager.SORTING
|
import com.deniscerri.ytdlnis.database.DBManager.SORTING
|
||||||
|
|
@ -72,7 +72,6 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
||||||
private var topAppBar: MaterialToolbar? = null
|
private var topAppBar: MaterialToolbar? = null
|
||||||
private var recyclerView: RecyclerView? = null
|
private var recyclerView: RecyclerView? = null
|
||||||
private var historyAdapter: HistoryAdapter? = null
|
private var historyAdapter: HistoryAdapter? = null
|
||||||
private var bottomSheet: BottomSheetDialog? = null
|
|
||||||
private var sortSheet: BottomSheetDialog? = null
|
private var sortSheet: BottomSheetDialog? = null
|
||||||
private var uiHandler: Handler? = null
|
private var uiHandler: Handler? = null
|
||||||
private var noResults: RelativeLayout? = null
|
private var noResults: RelativeLayout? = null
|
||||||
|
|
@ -401,20 +400,24 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
||||||
override fun onCardClick(itemID: Long, isPresent: Boolean) {
|
override fun onCardClick(itemID: Long, isPresent: Boolean) {
|
||||||
val item = findItem(itemID)
|
val item = findItem(itemID)
|
||||||
UiUtil.showHistoryItemDetailsCard(item, requireActivity(), isPresent,
|
UiUtil.showHistoryItemDetailsCard(item, requireActivity(), isPresent,
|
||||||
|
removeItem = { it, deleteFile ->
|
||||||
|
historyViewModel.delete(it, deleteFile)
|
||||||
|
},
|
||||||
redownloadItem = {
|
redownloadItem = {
|
||||||
val downloadItem = downloadViewModel.createDownloadItemFromHistory(it)
|
val downloadItem = downloadViewModel.createDownloadItemFromHistory(it)
|
||||||
runBlocking{
|
runBlocking{
|
||||||
downloadViewModel.queueDownloads(listOf(downloadItem))
|
downloadViewModel.queueDownloads(listOf(downloadItem))
|
||||||
}
|
}
|
||||||
historyViewModel.delete(it, false)
|
historyViewModel.delete(it, false)
|
||||||
|
},
|
||||||
|
redownloadShowDownloadCard = {
|
||||||
|
val sheet = DownloadBottomSheetDialog(
|
||||||
|
result = downloadViewModel.createResultItemFromHistory(it),
|
||||||
|
type = it.type
|
||||||
|
)
|
||||||
|
sheet.show(parentFragmentManager, "downloadSingleSheet")
|
||||||
}
|
}
|
||||||
) {
|
)
|
||||||
val sheet = DownloadBottomSheetDialog(
|
|
||||||
result = downloadViewModel.createResultItemFromHistory(it),
|
|
||||||
type = it.type
|
|
||||||
)
|
|
||||||
sheet.show(parentFragmentManager, "downloadSingleSheet")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCardSelect(itemID: Long, isChecked: Boolean) {
|
override fun onCardSelect(itemID: Long, isChecked: Boolean) {
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.widget.RelativeLayout
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
|
@ -24,7 +25,7 @@ import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import androidx.work.WorkManager
|
import androidx.work.WorkManager
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.adapter.GenericDownloadAdapter
|
import com.deniscerri.ytdlnis.ui.adapter.GenericDownloadAdapter
|
||||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||||
|
|
@ -53,6 +54,7 @@ class QueuedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLi
|
||||||
private lateinit var downloadViewModel : DownloadViewModel
|
private lateinit var downloadViewModel : DownloadViewModel
|
||||||
private lateinit var queuedRecyclerView : RecyclerView
|
private lateinit var queuedRecyclerView : RecyclerView
|
||||||
private lateinit var adapter : GenericDownloadAdapter
|
private lateinit var adapter : GenericDownloadAdapter
|
||||||
|
private lateinit var noResults : RelativeLayout
|
||||||
private lateinit var notificationUtil: NotificationUtil
|
private lateinit var notificationUtil: NotificationUtil
|
||||||
private lateinit var fileSize: TextView
|
private lateinit var fileSize: TextView
|
||||||
private var totalSize: Int = 0
|
private var totalSize: Int = 0
|
||||||
|
|
@ -80,6 +82,7 @@ class QueuedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLi
|
||||||
requireActivity()
|
requireActivity()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
noResults = view.findViewById(R.id.no_results)
|
||||||
queuedRecyclerView = view.findViewById(R.id.download_recyclerview)
|
queuedRecyclerView = view.findViewById(R.id.download_recyclerview)
|
||||||
queuedRecyclerView.forceFastScrollMode()
|
queuedRecyclerView.forceFastScrollMode()
|
||||||
queuedRecyclerView.adapter = adapter
|
queuedRecyclerView.adapter = adapter
|
||||||
|
|
@ -120,6 +123,7 @@ class QueuedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLi
|
||||||
|
|
||||||
downloadViewModel.getTotalSize(listOf(DownloadRepository.Status.Queued, DownloadRepository.Status.QueuedPaused)).observe(viewLifecycleOwner){
|
downloadViewModel.getTotalSize(listOf(DownloadRepository.Status.Queued, DownloadRepository.Status.QueuedPaused)).observe(viewLifecycleOwner){
|
||||||
totalSize = it
|
totalSize = it
|
||||||
|
noResults.visibility = if (it == 0) View.VISIBLE else View.GONE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.widget.RelativeLayout
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.view.ActionMode
|
import androidx.appcompat.view.ActionMode
|
||||||
|
|
@ -21,7 +22,7 @@ import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.adapter.GenericDownloadAdapter
|
import com.deniscerri.ytdlnis.ui.adapter.GenericDownloadAdapter
|
||||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||||
|
|
@ -47,6 +48,7 @@ class SavedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLis
|
||||||
private lateinit var downloadViewModel : DownloadViewModel
|
private lateinit var downloadViewModel : DownloadViewModel
|
||||||
private lateinit var savedRecyclerView: RecyclerView
|
private lateinit var savedRecyclerView: RecyclerView
|
||||||
private lateinit var adapter: GenericDownloadAdapter
|
private lateinit var adapter: GenericDownloadAdapter
|
||||||
|
private lateinit var noResults: RelativeLayout
|
||||||
private var actionMode : ActionMode? = null
|
private var actionMode : ActionMode? = null
|
||||||
private var totalSize : Int = 0
|
private var totalSize : Int = 0
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
|
|
@ -54,7 +56,7 @@ class SavedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLis
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): View? {
|
): View? {
|
||||||
fragmentView = inflater.inflate(R.layout.generic_recyclerview, container, false)
|
fragmentView = inflater.inflate(R.layout.generic_list, container, false)
|
||||||
activity = getActivity()
|
activity = getActivity()
|
||||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||||
return fragmentView
|
return fragmentView
|
||||||
|
|
@ -69,6 +71,7 @@ class SavedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLis
|
||||||
requireActivity()
|
requireActivity()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
noResults = view.findViewById(R.id.no_results)
|
||||||
savedRecyclerView = view.findViewById(R.id.download_recyclerview)
|
savedRecyclerView = view.findViewById(R.id.download_recyclerview)
|
||||||
savedRecyclerView.forceFastScrollMode()
|
savedRecyclerView.forceFastScrollMode()
|
||||||
savedRecyclerView.enableFastScroll()
|
savedRecyclerView.enableFastScroll()
|
||||||
|
|
@ -89,6 +92,7 @@ class SavedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLis
|
||||||
|
|
||||||
downloadViewModel.getTotalSize(listOf(DownloadRepository.Status.Saved)).observe(viewLifecycleOwner){
|
downloadViewModel.getTotalSize(listOf(DownloadRepository.Status.Saved)).observe(viewLifecycleOwner){
|
||||||
totalSize = it
|
totalSize = it
|
||||||
|
noResults.visibility = if (it == 0) View.VISIBLE else View.GONE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
package com.deniscerri.ytdlnis.ui.more
|
package com.deniscerri.ytdlnis.ui.more
|
||||||
|
|
||||||
|
import android.content.ClipboardManager
|
||||||
|
import android.content.Context
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
import android.graphics.Canvas
|
import android.graphics.Canvas
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
|
|
@ -9,12 +11,15 @@ import android.os.Looper
|
||||||
import android.text.InputType
|
import android.text.InputType
|
||||||
import android.util.DisplayMetrics
|
import android.util.DisplayMetrics
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.Window
|
import android.view.Window
|
||||||
import android.widget.RelativeLayout
|
import android.widget.RelativeLayout
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.appcompat.view.ActionMode
|
||||||
import androidx.appcompat.widget.SearchView
|
import androidx.appcompat.widget.SearchView
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
|
|
@ -26,11 +31,13 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.deniscerri.ytdlnis.MainActivity
|
import com.deniscerri.ytdlnis.MainActivity
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.adapter.TemplatesAdapter
|
import com.deniscerri.ytdlnis.ui.adapter.TemplatesAdapter
|
||||||
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.CommandTemplateViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.CommandTemplateViewModel
|
||||||
import com.deniscerri.ytdlnis.database.repository.CommandTemplateRepository.CommandTemplateSortType
|
import com.deniscerri.ytdlnis.database.repository.CommandTemplateRepository.CommandTemplateSortType
|
||||||
import com.deniscerri.ytdlnis.database.DBManager.SORTING
|
import com.deniscerri.ytdlnis.database.DBManager.SORTING
|
||||||
|
import com.deniscerri.ytdlnis.database.models.CommandTemplateExport
|
||||||
|
import com.deniscerri.ytdlnis.database.models.LogItem
|
||||||
import com.deniscerri.ytdlnis.util.UiUtil
|
import com.deniscerri.ytdlnis.util.UiUtil
|
||||||
import com.google.android.material.appbar.AppBarLayout
|
import com.google.android.material.appbar.AppBarLayout
|
||||||
import com.google.android.material.appbar.MaterialToolbar
|
import com.google.android.material.appbar.MaterialToolbar
|
||||||
|
|
@ -42,6 +49,8 @@ import it.xabaras.android.recyclerview.swipedecorator.RecyclerViewSwipeDecorator
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
|
||||||
|
|
||||||
class CommandTemplatesFragment : Fragment(), TemplatesAdapter.OnItemClickListener {
|
class CommandTemplatesFragment : Fragment(), TemplatesAdapter.OnItemClickListener {
|
||||||
|
|
@ -53,6 +62,9 @@ class CommandTemplatesFragment : Fragment(), TemplatesAdapter.OnItemClickListene
|
||||||
private lateinit var noResults: RelativeLayout
|
private lateinit var noResults: RelativeLayout
|
||||||
private lateinit var mainActivity: MainActivity
|
private lateinit var mainActivity: MainActivity
|
||||||
private lateinit var sortChip: Chip
|
private lateinit var sortChip: Chip
|
||||||
|
private var selectedObjects: ArrayList<CommandTemplate>? = null
|
||||||
|
private var actionMode : ActionMode? = null
|
||||||
|
private val jsonFormat = Json { prettyPrint = true }
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
|
|
@ -60,6 +72,7 @@ class CommandTemplatesFragment : Fragment(), TemplatesAdapter.OnItemClickListene
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): View? {
|
): View? {
|
||||||
mainActivity = activity as MainActivity
|
mainActivity = activity as MainActivity
|
||||||
|
selectedObjects = arrayListOf()
|
||||||
return inflater.inflate(R.layout.fragment_command_templates, container, false)
|
return inflater.inflate(R.layout.fragment_command_templates, container, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -87,7 +100,7 @@ class CommandTemplatesFragment : Fragment(), TemplatesAdapter.OnItemClickListene
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
commandTemplateViewModel = ViewModelProvider(this)[CommandTemplateViewModel::class.java]
|
commandTemplateViewModel = ViewModelProvider(requireActivity())[CommandTemplateViewModel::class.java]
|
||||||
commandTemplateViewModel.allItems.observe(viewLifecycleOwner) {
|
commandTemplateViewModel.allItems.observe(viewLifecycleOwner) {
|
||||||
if (it.isEmpty()) noResults.visibility = View.VISIBLE
|
if (it.isEmpty()) noResults.visibility = View.VISIBLE
|
||||||
else noResults.visibility = View.GONE
|
else noResults.visibility = View.GONE
|
||||||
|
|
@ -259,14 +272,109 @@ class CommandTemplatesFragment : Fragment(), TemplatesAdapter.OnItemClickListene
|
||||||
override fun onSelected(commandTemplate: CommandTemplate) {
|
override fun onSelected(commandTemplate: CommandTemplate) {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDelete(commandTemplate: CommandTemplate) {
|
override fun onCardSelect(itemID: Long, isChecked: Boolean) {
|
||||||
val deleteDialog = MaterialAlertDialogBuilder(requireContext())
|
val item = templatesList.find { it.id == itemID }
|
||||||
deleteDialog.setTitle(getString(R.string.you_are_going_to_delete) + " \"" + commandTemplate.title + "\"!")
|
if (isChecked) {
|
||||||
deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
|
selectedObjects!!.add(item!!)
|
||||||
deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
|
if (actionMode == null){
|
||||||
commandTemplateViewModel.delete(commandTemplate)
|
actionMode = (activity as AppCompatActivity?)!!.startSupportActionMode(contextualActionBar)
|
||||||
|
|
||||||
|
}else{
|
||||||
|
actionMode!!.title = "${selectedObjects!!.size} ${getString(R.string.selected)}"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
deleteDialog.show()
|
else {
|
||||||
|
selectedObjects!!.remove(item)
|
||||||
|
actionMode?.title = "${selectedObjects!!.size} ${getString(R.string.selected)}"
|
||||||
|
if (selectedObjects!!.isEmpty()){
|
||||||
|
actionMode?.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val contextualActionBar = object : ActionMode.Callback {
|
||||||
|
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
|
||||||
|
mode!!.menuInflater.inflate(R.menu.templates_menu_context, menu)
|
||||||
|
mode.title = "${selectedObjects!!.size} ${getString(R.string.selected)}"
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPrepareActionMode(
|
||||||
|
mode: ActionMode?,
|
||||||
|
menu: Menu?
|
||||||
|
): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActionItemClicked(
|
||||||
|
mode: ActionMode?,
|
||||||
|
item: MenuItem?
|
||||||
|
): Boolean {
|
||||||
|
return when (item!!.itemId) {
|
||||||
|
R.id.delete_results -> {
|
||||||
|
val deleteDialog = MaterialAlertDialogBuilder(requireContext())
|
||||||
|
deleteDialog.setTitle(getString(R.string.you_are_going_to_delete_multiple_items))
|
||||||
|
deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
|
||||||
|
deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
|
||||||
|
for (obj in selectedObjects!!){
|
||||||
|
commandTemplateViewModel.delete(obj)
|
||||||
|
}
|
||||||
|
clearCheckedItems()
|
||||||
|
actionMode?.finish()
|
||||||
|
}
|
||||||
|
deleteDialog.show()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
R.id.select_all -> {
|
||||||
|
templatesAdapter.checkAll(templatesList)
|
||||||
|
selectedObjects?.clear()
|
||||||
|
templatesList.forEach { selectedObjects?.add(it) }
|
||||||
|
mode?.title = getString(R.string.all_items_selected)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
R.id.invert_selected -> {
|
||||||
|
templatesAdapter.invertSelected(templatesList)
|
||||||
|
val invertedList = arrayListOf<CommandTemplate>()
|
||||||
|
templatesList.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
|
||||||
|
}
|
||||||
|
R.id.export_clipboard -> {
|
||||||
|
lifecycleScope.launch{
|
||||||
|
val output = jsonFormat.encodeToString(
|
||||||
|
CommandTemplateExport(
|
||||||
|
templates = selectedObjects!!.toList(),
|
||||||
|
shortcuts = listOf()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val clipboard: ClipboardManager =
|
||||||
|
requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||||
|
clipboard.setText(output)
|
||||||
|
Snackbar.make(recyclerView, getString(R.string.copied_to_clipboard), Snackbar.LENGTH_LONG).show()
|
||||||
|
clearCheckedItems()
|
||||||
|
actionMode?.finish()
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyActionMode(mode: ActionMode?) {
|
||||||
|
actionMode = null
|
||||||
|
clearCheckedItems()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun clearCheckedItems(){
|
||||||
|
templatesAdapter.clearCheckeditems()
|
||||||
|
selectedObjects?.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
private var simpleCallback: ItemTouchHelper.SimpleCallback =
|
private var simpleCallback: ItemTouchHelper.SimpleCallback =
|
||||||
|
|
@ -282,7 +390,9 @@ class CommandTemplatesFragment : Fragment(), TemplatesAdapter.OnItemClickListene
|
||||||
ItemTouchHelper.LEFT -> {
|
ItemTouchHelper.LEFT -> {
|
||||||
val deletedItem = templatesList[position]
|
val deletedItem = templatesList[position]
|
||||||
templatesAdapter.notifyItemChanged(position)
|
templatesAdapter.notifyItemChanged(position)
|
||||||
onDelete(deletedItem)
|
UiUtil.showGenericDeleteDialog(requireContext(), deletedItem.title){
|
||||||
|
commandTemplateViewModel.delete(deletedItem)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ import android.view.inputmethod.InputMethodManager
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
import android.widget.RelativeLayout
|
import android.widget.RelativeLayout
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.view.children
|
|
||||||
import androidx.core.widget.doOnTextChanged
|
import androidx.core.widget.doOnTextChanged
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
|
@ -26,10 +25,10 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.deniscerri.ytdlnis.MainActivity
|
import com.deniscerri.ytdlnis.MainActivity
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.adapter.CookieAdapter
|
import com.deniscerri.ytdlnis.ui.adapter.CookieAdapter
|
||||||
import com.deniscerri.ytdlnis.database.models.CookieItem
|
import com.deniscerri.ytdlnis.database.models.CookieItem
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.CookieViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.CookieViewModel
|
||||||
import com.deniscerri.ytdlnis.util.UiUtil.enableFastScroll
|
import com.deniscerri.ytdlnis.util.UiUtil
|
||||||
import com.google.android.material.appbar.MaterialToolbar
|
import com.google.android.material.appbar.MaterialToolbar
|
||||||
import com.google.android.material.chip.Chip
|
import com.google.android.material.chip.Chip
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
|
@ -130,6 +129,10 @@ class CookiesFragment : Fragment(), CookieAdapter.OnItemClickListener {
|
||||||
}
|
}
|
||||||
deleteDialog.show()
|
deleteDialog.show()
|
||||||
}
|
}
|
||||||
|
R.id.use_header -> {
|
||||||
|
m.isChecked = !m.isChecked
|
||||||
|
preferences.edit().putBoolean("use_header", m.isChecked).apply()
|
||||||
|
}
|
||||||
R.id.import_clipboard -> {
|
R.id.import_clipboard -> {
|
||||||
lifecycleScope.launch(Dispatchers.IO){
|
lifecycleScope.launch(Dispatchers.IO){
|
||||||
cookiesViewModel.importFromClipboard()
|
cookiesViewModel.importFromClipboard()
|
||||||
|
|
@ -139,9 +142,18 @@ class CookiesFragment : Fragment(), CookieAdapter.OnItemClickListener {
|
||||||
cookiesViewModel.exportToClipboard()
|
cookiesViewModel.exportToClipboard()
|
||||||
Snackbar.make(recyclerView, getString(R.string.copied_to_clipboard), Snackbar.LENGTH_LONG).show()
|
Snackbar.make(recyclerView, getString(R.string.copied_to_clipboard), Snackbar.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
R.id.use_header -> {
|
R.id.export_file -> {
|
||||||
m.isChecked = !m.isChecked
|
cookiesViewModel.exportToFile {f ->
|
||||||
preferences.edit().putBoolean("use_header", m.isChecked).apply()
|
if (f == null){
|
||||||
|
Snackbar.make(recyclerView, getString(R.string.couldnt_parse_file), Snackbar.LENGTH_LONG).show()
|
||||||
|
}else{
|
||||||
|
val snack = Snackbar.make(recyclerView, getString(R.string.backup_created_successfully), Snackbar.LENGTH_LONG)
|
||||||
|
snack.setAction(R.string.share) {
|
||||||
|
UiUtil.shareFileIntent(requireContext(), listOf(f.absolutePath))
|
||||||
|
}
|
||||||
|
snack.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,6 @@ class MoreFragment : Fragment() {
|
||||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||||
return inflater.inflate(R.layout.fragment_more, container, false)
|
return inflater.inflate(R.layout.fragment_more, container, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,30 @@
|
||||||
package com.deniscerri.ytdlnis.ui.more.downloadLogs
|
package com.deniscerri.ytdlnis.ui.more.downloadLogs
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.content.ClipboardManager
|
import android.content.ClipboardManager
|
||||||
import android.content.Context.CLIPBOARD_SERVICE
|
import android.content.Context.CLIPBOARD_SERVICE
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.FileObserver
|
import android.text.method.LinkMovementMethod
|
||||||
|
import android.text.method.MovementMethod
|
||||||
|
import android.text.method.ScrollingMovementMethod
|
||||||
|
import android.util.Log
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.HorizontalScrollView
|
import android.widget.HorizontalScrollView
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import android.widget.ScrollView
|
import android.widget.ScrollView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import androidx.core.view.children
|
||||||
|
import androidx.core.view.get
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.lifecycle.map
|
|
||||||
import com.deniscerri.ytdlnis.MainActivity
|
import com.deniscerri.ytdlnis.MainActivity
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.database.models.LogItem
|
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.LogViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.LogViewModel
|
||||||
import com.google.android.material.appbar.MaterialToolbar
|
import com.google.android.material.appbar.MaterialToolbar
|
||||||
import com.google.android.material.bottomappbar.BottomAppBar
|
import com.google.android.material.bottomappbar.BottomAppBar
|
||||||
|
|
@ -30,11 +35,9 @@ import com.neo.highlight.util.listener.HighlightTextWatcher
|
||||||
import com.neo.highlight.util.scheme.ColorScheme
|
import com.neo.highlight.util.scheme.ColorScheme
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.withContext
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
import kotlin.math.log
|
|
||||||
|
|
||||||
|
|
||||||
class DownloadLogFragment : Fragment() {
|
class DownloadLogFragment : Fragment() {
|
||||||
|
|
@ -56,6 +59,7 @@ class DownloadLogFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
|
@ -65,11 +69,17 @@ class DownloadLogFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
content = view.findViewById(R.id.content)
|
content = view.findViewById(R.id.content)
|
||||||
|
content.movementMethod = ScrollingMovementMethod()
|
||||||
content.setTextIsSelectable(true)
|
content.setTextIsSelectable(true)
|
||||||
contentScrollView = view.findViewById(R.id.content_scrollview)
|
contentScrollView = view.findViewById(R.id.content_scrollview)
|
||||||
|
|
||||||
val bottomAppBar = view.findViewById<BottomAppBar>(R.id.bottomAppBar)
|
val bottomAppBar = view.findViewById<BottomAppBar>(R.id.bottomAppBar)
|
||||||
|
|
||||||
|
topAppBar.setOnClickListener {
|
||||||
|
contentScrollView.scrollTo(0,0)
|
||||||
|
bottomAppBar?.menu?.get(1)?.isVisible = true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
copyLog = view.findViewById(R.id.copy_log)
|
copyLog = view.findViewById(R.id.copy_log)
|
||||||
copyLog.setOnClickListener {
|
copyLog.setOnClickListener {
|
||||||
val clipboard: ClipboardManager =
|
val clipboard: ClipboardManager =
|
||||||
|
|
@ -81,22 +91,13 @@ class DownloadLogFragment : Fragment() {
|
||||||
val id = arguments?.getLong("logID")
|
val id = arguments?.getLong("logID")
|
||||||
if (id == null) {
|
if (id == null) {
|
||||||
mainActivity.onBackPressedDispatcher.onBackPressed()
|
mainActivity.onBackPressedDispatcher.onBackPressed()
|
||||||
}else{
|
|
||||||
arguments?.remove("logID")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
logViewModel = ViewModelProvider(this)[LogViewModel::class.java]
|
logViewModel = ViewModelProvider(this)[LogViewModel::class.java]
|
||||||
logViewModel.getLogFlowByID(id!!).observe(viewLifecycleOwner){logItem ->
|
|
||||||
mainActivity.runOnUiThread{
|
|
||||||
content.text = logItem?.content
|
|
||||||
content.scrollTo(0, content.height)
|
|
||||||
contentScrollView.fullScroll(View.FOCUS_DOWN)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
val logItem = logViewModel.getItemById(id)
|
val logItem = logViewModel.getItemById(id!!)
|
||||||
topAppBar.title = logItem.title
|
topAppBar.title = logItem.title
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -118,6 +119,7 @@ class DownloadLogFragment : Fragment() {
|
||||||
*schemes.map { it }.toTypedArray()
|
*schemes.map { it }.toTypedArray()
|
||||||
)
|
)
|
||||||
highlight.setSpan(content)
|
highlight.setSpan(content)
|
||||||
|
content.isFocusable = true
|
||||||
content.addTextChangedListener(highlightWatcher)
|
content.addTextChangedListener(highlightWatcher)
|
||||||
content.setHorizontallyScrolling(false)
|
content.setHorizontallyScrolling(false)
|
||||||
|
|
||||||
|
|
@ -144,9 +146,37 @@ class DownloadLogFragment : Fragment() {
|
||||||
}
|
}
|
||||||
content.setHorizontallyScrolling(!content.canScrollHorizontally(1))
|
content.setHorizontallyScrolling(!content.canScrollHorizontally(1))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
R.id.scroll_down -> {
|
||||||
|
m.isVisible = false
|
||||||
|
contentScrollView.fullScroll(View.FOCUS_DOWN)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// contentScrollView.setOnScrollChangeListener { view, sx, sy, osx, osy ->
|
||||||
|
// if (sy < osy){
|
||||||
|
// if (contentScrollView.canScrollVertically(1)){
|
||||||
|
// shouldScroll = false
|
||||||
|
// content.movementMethod = LinkMovementMethod.getInstance()
|
||||||
|
// bottomAppBar?.menu?.get(1)?.isVisible = true
|
||||||
|
// }else{
|
||||||
|
// shouldScroll = true
|
||||||
|
// content.movementMethod = ScrollingMovementMethod()
|
||||||
|
// bottomAppBar?.menu?.get(1)?.isVisible = false
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
logViewModel.getLogFlowByID(id!!).observe(viewLifecycleOwner){logItem ->
|
||||||
|
lifecycleScope.launch {
|
||||||
|
content.text = logItem.content
|
||||||
|
content.scrollTo(content.scrollX, content.height)
|
||||||
|
contentScrollView.fullScroll(View.FOCUS_DOWN)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.deniscerri.ytdlnis.MainActivity
|
import com.deniscerri.ytdlnis.MainActivity
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.adapter.DownloadLogsAdapter
|
import com.deniscerri.ytdlnis.ui.adapter.DownloadLogsAdapter
|
||||||
import com.deniscerri.ytdlnis.database.models.LogItem
|
import com.deniscerri.ytdlnis.database.models.LogItem
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.LogViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.LogViewModel
|
||||||
import com.deniscerri.ytdlnis.util.UiUtil.enableFastScroll
|
import com.deniscerri.ytdlnis.util.UiUtil.enableFastScroll
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package com.deniscerri.ytdlnis.ui.more.settings
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.SharedPreferences
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build.VERSION
|
import android.os.Build.VERSION
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
|
@ -35,14 +36,16 @@ class FolderSettingsFragment : BaseSettingsFragment() {
|
||||||
private var videoFilenameTemplate : Preference? = null
|
private var videoFilenameTemplate : Preference? = null
|
||||||
private var clearCache: Preference? = null
|
private var clearCache: Preference? = null
|
||||||
private var moveCache: Preference? = null
|
private var moveCache: Preference? = null
|
||||||
|
private lateinit var preferences: SharedPreferences
|
||||||
|
private lateinit var editor: SharedPreferences.Editor
|
||||||
|
|
||||||
private var activeDownloadCount = 0
|
private var activeDownloadCount = 0
|
||||||
|
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
setPreferencesFromResource(R.xml.folders_preference, rootKey)
|
setPreferencesFromResource(R.xml.folders_preference, rootKey)
|
||||||
|
|
||||||
val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||||
val editor = preferences.edit()
|
editor = preferences.edit()
|
||||||
|
|
||||||
musicPath = findPreference("music_path")
|
musicPath = findPreference("music_path")
|
||||||
videoPath = findPreference("video_path")
|
videoPath = findPreference("video_path")
|
||||||
|
|
@ -110,7 +113,7 @@ class FolderSettingsFragment : BaseSettingsFragment() {
|
||||||
val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
|
val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
|
||||||
val uri = Uri.parse("package:" + requireContext().packageName)
|
val uri = Uri.parse("package:" + requireContext().packageName)
|
||||||
intent.data = uri
|
intent.data = uri
|
||||||
accessAllFilesLauncher.launch(intent)
|
startActivity(intent)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -180,6 +183,18 @@ class FolderSettingsFragment : BaseSettingsFragment() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
if((VERSION.SDK_INT >= 30 && Environment.isExternalStorageManager()) ||
|
||||||
|
VERSION.SDK_INT < 30) {
|
||||||
|
accessAllFiles!!.isVisible = false
|
||||||
|
cacheDownloads!!.isEnabled = true
|
||||||
|
}else{
|
||||||
|
editor.putBoolean("cache_downloads", true).apply()
|
||||||
|
cacheDownloads!!.isEnabled = false
|
||||||
|
}
|
||||||
|
super.onResume()
|
||||||
|
}
|
||||||
|
|
||||||
private var musicPathResultLauncher = registerForActivityResult(
|
private var musicPathResultLauncher = registerForActivityResult(
|
||||||
ActivityResultContracts.StartActivityForResult()
|
ActivityResultContracts.StartActivityForResult()
|
||||||
) { result ->
|
) { result ->
|
||||||
|
|
@ -223,15 +238,6 @@ class FolderSettingsFragment : BaseSettingsFragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var accessAllFilesLauncher = registerForActivityResult(
|
|
||||||
ActivityResultContracts.StartActivityForResult()
|
|
||||||
) { result ->
|
|
||||||
if (result.resultCode == Activity.RESULT_OK) {
|
|
||||||
accessAllFiles?.isVisible = false
|
|
||||||
cacheDownloads?.isEnabled = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun changePath(p: Preference?, data: Intent?, requestCode: Int) {
|
private fun changePath(p: Preference?, data: Intent?, requestCode: Int) {
|
||||||
val path = data!!.data.toString()
|
val path = data!!.data.toString()
|
||||||
p!!.summary = FileUtil.formatPath(data.data.toString())
|
p!!.summary = FileUtil.formatPath(data.data.toString())
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import android.provider.Settings
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
|
import androidx.core.app.ActivityCompat
|
||||||
import androidx.core.os.LocaleListCompat
|
import androidx.core.os.LocaleListCompat
|
||||||
import androidx.preference.ListPreference
|
import androidx.preference.ListPreference
|
||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
|
|
@ -130,29 +131,24 @@ class GeneralSettingsFragment : BaseSettingsFragment() {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
ignoreBatteryOptimization = findPreference<Preference>("ignore_battery")
|
|
||||||
val packageName: String = requireContext().packageName
|
|
||||||
val pm = requireContext().applicationContext.getSystemService(Context.POWER_SERVICE) as PowerManager
|
|
||||||
if (pm.isIgnoringBatteryOptimizations(packageName)) {
|
|
||||||
ignoreBatteryOptimization!!.isVisible = false
|
|
||||||
}
|
|
||||||
|
|
||||||
ignoreBatteryOptimization = findPreference("ignore_battery")
|
ignoreBatteryOptimization = findPreference("ignore_battery")
|
||||||
ignoreBatteryOptimization!!.onPreferenceClickListener =
|
ignoreBatteryOptimization!!.onPreferenceClickListener =
|
||||||
Preference.OnPreferenceClickListener {
|
Preference.OnPreferenceClickListener {
|
||||||
val intent = Intent()
|
val intent = Intent()
|
||||||
intent.action = Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
|
intent.action = Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
|
||||||
intent.data = Uri.parse("package:" + requireContext().packageName)
|
intent.data = Uri.parse("package:" + requireContext().packageName)
|
||||||
ignoreBatteryLauncher.launch(intent)
|
startActivity(intent)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var ignoreBatteryLauncher = registerForActivityResult(
|
override fun onResume() {
|
||||||
ActivityResultContracts.StartActivityForResult()
|
val packageName: String = requireContext().packageName
|
||||||
) { result ->
|
val pm = requireContext().applicationContext.getSystemService(Context.POWER_SERVICE) as PowerManager
|
||||||
if (result.resultCode == Activity.RESULT_OK) {
|
if (pm.isIgnoringBatteryOptimizations(packageName)) {
|
||||||
ignoreBatteryOptimization?.isVisible = false
|
ignoreBatteryOptimization!!.isVisible = false
|
||||||
}
|
}
|
||||||
|
super.onResume()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -43,7 +43,7 @@ class SettingsActivity : BaseActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
navController.navigate(R.id.mainSettingsFragment)
|
if (savedInstanceState == null) navController.navigate(R.id.mainSettingsFragment)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun changeTopAppbarTitle(text: String) {
|
fun changeTopAppbarTitle(text: String) {
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,21 @@
|
||||||
package com.deniscerri.ytdlnis.ui.more.terminal
|
package com.deniscerri.ytdlnis.ui.more.terminal
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.Activity
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.MediaStore
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
|
||||||
import androidx.core.os.bundleOf
|
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.navigation.NavArgument
|
import androidx.navigation.NavArgument
|
||||||
import androidx.navigation.NavGraph
|
import androidx.navigation.NavGraph
|
||||||
import androidx.navigation.NavType
|
import androidx.navigation.NavType
|
||||||
import androidx.navigation.fragment.NavHostFragment
|
import androidx.navigation.fragment.NavHostFragment
|
||||||
import androidx.navigation.navArgument
|
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.TerminalViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.TerminalViewModel
|
||||||
import com.deniscerri.ytdlnis.ui.BaseActivity
|
import com.deniscerri.ytdlnis.ui.BaseActivity
|
||||||
import com.deniscerri.ytdlnis.util.FileUtil
|
import com.deniscerri.ytdlnis.util.FileUtil
|
||||||
import com.google.android.material.appbar.MaterialToolbar
|
|
||||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,12 @@
|
||||||
package com.deniscerri.ytdlnis.ui.more.terminal
|
package com.deniscerri.ytdlnis.ui.more.terminal
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.content.ClipboardManager
|
|
||||||
import android.content.Context
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.HorizontalScrollView
|
|
||||||
import android.widget.LinearLayout
|
|
||||||
import android.widget.RelativeLayout
|
import android.widget.RelativeLayout
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.activity.addCallback
|
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
import androidx.core.view.forEach
|
import androidx.core.view.forEach
|
||||||
import androidx.core.view.get
|
import androidx.core.view.get
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
|
|
@ -23,17 +15,14 @@ import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import androidx.work.WorkInfo
|
|
||||||
import androidx.work.WorkManager
|
import androidx.work.WorkManager
|
||||||
import androidx.work.WorkQuery
|
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.adapter.TerminalDownloadsAdapter
|
import com.deniscerri.ytdlnis.ui.adapter.TerminalDownloadsAdapter
|
||||||
import com.deniscerri.ytdlnis.database.models.TerminalItem
|
import com.deniscerri.ytdlnis.database.models.TerminalItem
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.TerminalViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.TerminalViewModel
|
||||||
import com.deniscerri.ytdlnis.util.UiUtil.enableFastScroll
|
import com.deniscerri.ytdlnis.util.UiUtil.enableFastScroll
|
||||||
import com.google.android.material.appbar.MaterialToolbar
|
import com.google.android.material.appbar.MaterialToolbar
|
||||||
import com.google.android.material.progressindicator.LinearProgressIndicator
|
import com.google.android.material.progressindicator.LinearProgressIndicator
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,8 @@ import android.content.Context.INPUT_METHOD_SERVICE
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.PersistableBundle
|
import android.text.method.ScrollingMovementMethod
|
||||||
import android.util.DisplayMetrics
|
import android.util.DisplayMetrics
|
||||||
import android.util.Log
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
|
@ -23,19 +22,14 @@ import android.widget.ScrollView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
import androidx.core.view.forEach
|
|
||||||
import androidx.core.view.get
|
import androidx.core.view.get
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.LifecycleOwner
|
|
||||||
import androidx.lifecycle.LiveData
|
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import androidx.work.WorkInfo
|
import androidx.work.WorkInfo
|
||||||
import androidx.work.WorkManager
|
import androidx.work.WorkManager
|
||||||
import androidx.work.workDataOf
|
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.database.models.TerminalItem
|
import com.deniscerri.ytdlnis.database.models.TerminalItem
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.CommandTemplateViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.CommandTemplateViewModel
|
||||||
|
|
@ -47,13 +41,12 @@ import com.deniscerri.ytdlnis.util.UiUtil.enableTextHighlight
|
||||||
import com.google.android.material.appbar.MaterialToolbar
|
import com.google.android.material.appbar.MaterialToolbar
|
||||||
import com.google.android.material.bottomappbar.BottomAppBar
|
import com.google.android.material.bottomappbar.BottomAppBar
|
||||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||||
import com.yausername.youtubedl_android.YoutubeDL
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.lang.StringBuilder
|
import java.util.concurrent.Executor
|
||||||
import kotlin.properties.Delegates
|
import kotlin.properties.Delegates
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -87,7 +80,7 @@ class TerminalFragment : Fragment() {
|
||||||
super.onSaveInstanceState(outState)
|
super.onSaveInstanceState(outState)
|
||||||
outState.putString("input", input?.text.toString())
|
outState.putString("input", input?.text.toString())
|
||||||
outState.putString("output", output?.text.toString())
|
outState.putString("output", output?.text.toString())
|
||||||
outState.putBoolean("run", fab!!.text == getString(R.string.run_command))
|
outState.putBoolean("run", fab!!.text == requireActivity().getString(R.string.run_command))
|
||||||
outState.putLong("downloadID", downloadID)
|
outState.putLong("downloadID", downloadID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -103,6 +96,7 @@ class TerminalFragment : Fragment() {
|
||||||
scrollView = view.findViewById(R.id.custom_command_scrollview)
|
scrollView = view.findViewById(R.id.custom_command_scrollview)
|
||||||
topAppBar = requireActivity().findViewById(R.id.custom_command_toolbar)
|
topAppBar = requireActivity().findViewById(R.id.custom_command_toolbar)
|
||||||
topAppBar!!.setNavigationOnClickListener { requireActivity().finish() }
|
topAppBar!!.setNavigationOnClickListener { requireActivity().finish() }
|
||||||
|
topAppBar!!.setOnClickListener { scrollView?.scrollTo(0,0) }
|
||||||
|
|
||||||
input = view.findViewById(R.id.command_edittext)
|
input = view.findViewById(R.id.command_edittext)
|
||||||
fab = view.findViewById(R.id.command_fab)
|
fab = view.findViewById(R.id.command_fab)
|
||||||
|
|
@ -156,7 +150,7 @@ class TerminalFragment : Fragment() {
|
||||||
when(it.itemId){
|
when(it.itemId){
|
||||||
R.id.command_templates -> {
|
R.id.command_templates -> {
|
||||||
if (templateCount == 0){
|
if (templateCount == 0){
|
||||||
Toast.makeText(requireContext(), getString(R.string.add_template_first), Toast.LENGTH_SHORT).show()
|
Toast.makeText(requireContext(), requireActivity().getString(R.string.add_template_first), Toast.LENGTH_SHORT).show()
|
||||||
}else{
|
}else{
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
UiUtil.showCommandTemplates(requireActivity(), commandTemplateViewModel){ templates ->
|
UiUtil.showCommandTemplates(requireActivity(), commandTemplateViewModel){ templates ->
|
||||||
|
|
@ -198,11 +192,12 @@ class TerminalFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
output = view.findViewById(R.id.custom_command_output)
|
output = view.findViewById(R.id.custom_command_output)
|
||||||
|
output!!.movementMethod = ScrollingMovementMethod()
|
||||||
output!!.setTextIsSelectable(true)
|
output!!.setTextIsSelectable(true)
|
||||||
output!!.layoutParams!!.width = LayoutParams.WRAP_CONTENT
|
output!!.layoutParams!!.width = LayoutParams.WRAP_CONTENT
|
||||||
input!!.requestFocus()
|
input!!.requestFocus()
|
||||||
fab!!.setOnClickListener {
|
fab!!.setOnClickListener {
|
||||||
if (fab!!.text == getString(R.string.run_command)){
|
if (fab!!.text == requireActivity().getString(R.string.run_command)){
|
||||||
input!!.visibility = View.GONE
|
input!!.visibility = View.GONE
|
||||||
output!!.text = "${output!!.text}\n~ $ ${input!!.text}\n"
|
output!!.text = "${output!!.text}\n~ $ ${input!!.text}\n"
|
||||||
showCancelFab()
|
showCancelFab()
|
||||||
|
|
@ -213,6 +208,8 @@ class TerminalFragment : Fragment() {
|
||||||
terminalViewModel.insert(TerminalItem(command = command, log = output!!.text.toString()))
|
terminalViewModel.insert(TerminalItem(command = command, log = output!!.text.toString()))
|
||||||
}
|
}
|
||||||
terminalViewModel.startTerminalDownloadWorker(TerminalItem(downloadID, command))
|
terminalViewModel.startTerminalDownloadWorker(TerminalItem(downloadID, command))
|
||||||
|
input!!.visibility = View.GONE
|
||||||
|
showCancelFab()
|
||||||
runWorkerListener()
|
runWorkerListener()
|
||||||
}
|
}
|
||||||
}else {
|
}else {
|
||||||
|
|
@ -274,12 +271,16 @@ class TerminalFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private fun hideCancelFab() {
|
private fun hideCancelFab() {
|
||||||
fab!!.text = getString(R.string.run_command)
|
kotlin.runCatching {
|
||||||
fab!!.setIconResource(R.drawable.ic_baseline_keyboard_arrow_right_24)
|
fab!!.text = getString(R.string.run_command)
|
||||||
|
fab!!.setIconResource(R.drawable.ic_baseline_keyboard_arrow_right_24)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
private fun showCancelFab() {
|
private fun showCancelFab() {
|
||||||
fab!!.text = getString(R.string.cancel_download)
|
kotlin.runCatching {
|
||||||
fab!!.setIconResource(R.drawable.ic_cancel)
|
fab!!.text = getString(R.string.cancel_download)
|
||||||
|
fab!!.setIconResource(R.drawable.ic_cancel)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var commandPathResultLauncher = registerForActivityResult(
|
private var commandPathResultLauncher = registerForActivityResult(
|
||||||
|
|
@ -307,7 +308,11 @@ class TerminalFragment : Fragment() {
|
||||||
output?.text = it.log
|
output?.text = it.log
|
||||||
}
|
}
|
||||||
output?.scrollTo(0, output!!.height)
|
output?.scrollTo(0, output!!.height)
|
||||||
scrollView?.fullScroll(View.FOCUS_DOWN)
|
if (!scrollView!!.canScrollVertically(1) && !scrollView!!.canScrollHorizontally(-1)){
|
||||||
|
scrollView?.fullScroll(View.FOCUS_DOWN)
|
||||||
|
}
|
||||||
|
input!!.visibility = View.GONE
|
||||||
|
showCancelFab()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -316,24 +321,34 @@ class TerminalFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
WorkManager.getInstance(requireContext())
|
WorkManager.getInstance(requireContext())
|
||||||
.getWorkInfosByTagLiveData(downloadID.toString())
|
.getWorkInfosForUniqueWorkLiveData(downloadID.toString())
|
||||||
.observe(viewLifecycleOwner){ list ->
|
.removeObserver(workerObserver)
|
||||||
list.forEach {work ->
|
|
||||||
if (listOf(WorkInfo.State.SUCCEEDED, WorkInfo.State.FAILED, WorkInfo.State.CANCELLED).contains(work.state)) {
|
WorkManager.getInstance(requireContext())
|
||||||
requireActivity().runOnUiThread {
|
.getWorkInfosForUniqueWorkLiveData(downloadID.toString())
|
||||||
kotlin.runCatching {
|
.observe(viewLifecycleOwner, workerObserver)
|
||||||
input!!.setText("yt-dlp ")
|
}
|
||||||
input!!.visibility = View.VISIBLE
|
|
||||||
input!!.requestFocus()
|
private val workerObserver = object: Observer<MutableList<WorkInfo>> {
|
||||||
input!!.setSelection(input!!.text.length)
|
override fun onChanged(value: MutableList<WorkInfo>) {
|
||||||
hideCancelFab()
|
value.forEach { work ->
|
||||||
}
|
if (listOf(WorkInfo.State.SUCCEEDED, WorkInfo.State.FAILED, WorkInfo.State.CANCELLED).contains(work.state)) {
|
||||||
|
requireActivity().runOnUiThread {
|
||||||
|
kotlin.runCatching {
|
||||||
|
input!!.setText("yt-dlp ")
|
||||||
|
input!!.visibility = View.VISIBLE
|
||||||
|
input!!.requestFocus()
|
||||||
|
input!!.setSelection(input!!.text.length)
|
||||||
|
hideCancelFab()
|
||||||
}
|
}
|
||||||
return@forEach
|
|
||||||
}
|
}
|
||||||
|
return@forEach
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,32 +1,21 @@
|
||||||
package com.deniscerri.ytdlnis.util
|
package com.deniscerri.ytdlnis.util
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.content.ContentResolver
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
|
||||||
import android.database.Cursor
|
|
||||||
import android.media.MediaScannerConnection
|
import android.media.MediaScannerConnection
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import android.provider.DocumentsContract
|
import android.provider.DocumentsContract
|
||||||
import android.provider.MediaStore
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.View
|
|
||||||
import android.webkit.MimeTypeMap
|
import android.webkit.MimeTypeMap
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import androidx.documentfile.provider.DocumentFile
|
import androidx.documentfile.provider.DocumentFile
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import androidx.fragment.app.FragmentActivity
|
|
||||||
import com.anggrayudi.storage.callback.FileCallback
|
import com.anggrayudi.storage.callback.FileCallback
|
||||||
import com.anggrayudi.storage.callback.FolderCallback
|
import com.anggrayudi.storage.callback.FolderCallback
|
||||||
import com.anggrayudi.storage.file.copyFolderTo
|
import com.anggrayudi.storage.file.copyFolderTo
|
||||||
import com.anggrayudi.storage.file.getAbsolutePath
|
import com.anggrayudi.storage.file.getAbsolutePath
|
||||||
import com.anggrayudi.storage.file.moveFileTo
|
import com.anggrayudi.storage.file.moveFileTo
|
||||||
import com.deniscerri.ytdlnis.App
|
import com.deniscerri.ytdlnis.App
|
||||||
import com.deniscerri.ytdlnis.R
|
|
||||||
import com.yausername.youtubedl_android.YoutubeDLRequest
|
import com.yausername.youtubedl_android.YoutubeDLRequest
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
@ -64,6 +53,7 @@ object FileUtil {
|
||||||
var dataValue = path
|
var dataValue = path
|
||||||
if (dataValue.startsWith("/storage/")) return dataValue
|
if (dataValue.startsWith("/storage/")) return dataValue
|
||||||
dataValue = dataValue.replace("content://com.android.externalstorage.documents/tree/", "")
|
dataValue = dataValue.replace("content://com.android.externalstorage.documents/tree/", "")
|
||||||
|
dataValue = dataValue.replace("raw:/storage/", "")
|
||||||
dataValue = dataValue.replace("^/document/".toRegex(), "")
|
dataValue = dataValue.replace("^/document/".toRegex(), "")
|
||||||
dataValue = dataValue.replace("^primary:".toRegex(), "primary/")
|
dataValue = dataValue.replace("^primary:".toRegex(), "primary/")
|
||||||
dataValue = dataValue.replace("%3A".toRegex(), "/")
|
dataValue = dataValue.replace("%3A".toRegex(), "/")
|
||||||
|
|
@ -296,6 +286,10 @@ object FileUtil {
|
||||||
return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)?.absolutePath + File.separator + "YTDLnis/Command"
|
return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)?.absolutePath + File.separator + "YTDLnis/Command"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getDefaultTerminalPath() : String {
|
||||||
|
return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)?.absolutePath + File.separator + "YTDLnis/TERMINAL_CACHE"
|
||||||
|
}
|
||||||
|
|
||||||
fun getCookieFile(context : Context, path: (path: String) -> Unit){
|
fun getCookieFile(context : Context, path: (path: String) -> Unit){
|
||||||
val cookiesFile = File(context.cacheDir, "cookies.txt")
|
val cookiesFile = File(context.cacheDir, "cookies.txt")
|
||||||
if (cookiesFile.exists()) path(cookiesFile.absolutePath)
|
if (cookiesFile.exists()) path(cookiesFile.absolutePath)
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import android.util.Log
|
||||||
import android.util.Patterns
|
import android.util.Patterns
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
|
import com.afollestad.materialdialogs.utils.MDUtil.getStringArray
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.database.models.ChapterItem
|
import com.deniscerri.ytdlnis.database.models.ChapterItem
|
||||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||||
|
|
@ -553,13 +554,20 @@ class InfoUtil(private val context: Context) {
|
||||||
request = YoutubeDLRequest(query)
|
request = YoutubeDLRequest(query)
|
||||||
}else{
|
}else{
|
||||||
request = YoutubeDLRequest(emptyList())
|
request = YoutubeDLRequest(emptyList())
|
||||||
if (searchEngine == "ytsearchmusic"){
|
when (searchEngine){
|
||||||
request.addOption("--default-search", "https://music.youtube.com/search?q=")
|
"ytsearchmusic" -> {
|
||||||
request.addOption("ytsearch25:\"${query}\"")
|
request.addOption("--default-search", "https://music.youtube.com/search?q=")
|
||||||
}else{
|
request.addOption("ytsearch25:\"${query}\"")
|
||||||
request.addOption("${searchEngine}25:\"${query}\"")
|
}
|
||||||
|
else -> {
|
||||||
|
request.addOption("${searchEngine}25:\"${query}\"")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
val lang = sharedPreferences.getString("app_language", "en")
|
||||||
|
if (searchEngine == "ytsearch" && context.getStringArray(R.array.subtitle_langs).contains(lang)){
|
||||||
|
request.addOption("--extractor-args", "youtube:lang=$lang")
|
||||||
|
}
|
||||||
|
|
||||||
request.addOption("--flat-playlist")
|
request.addOption("--flat-playlist")
|
||||||
request.addOption("-j")
|
request.addOption("-j")
|
||||||
|
|
@ -954,8 +962,8 @@ class InfoUtil(private val context: Context) {
|
||||||
if (!sharedPreferences.getBoolean("cache_downloads", true) && File(FileUtil.formatPath(downloadItem.downloadPath)).canWrite()){
|
if (!sharedPreferences.getBoolean("cache_downloads", true) && File(FileUtil.formatPath(downloadItem.downloadPath)).canWrite()){
|
||||||
downDir = File(FileUtil.formatPath(downloadItem.downloadPath))
|
downDir = File(FileUtil.formatPath(downloadItem.downloadPath))
|
||||||
request.addOption("--no-quiet")
|
request.addOption("--no-quiet")
|
||||||
request.addOption("-no-simulate")
|
request.addOption("--no-simulate")
|
||||||
request.addOption("--print", "after_video:'%(filename)s'")
|
request.addOption("--print", "after_move:'%(filepath,_filename)s'")
|
||||||
}else{
|
}else{
|
||||||
val cacheDir = FileUtil.getCachePath(context)
|
val cacheDir = FileUtil.getCachePath(context)
|
||||||
downDir = File(cacheDir, downloadItem.id.toString())
|
downDir = File(cacheDir, downloadItem.id.toString())
|
||||||
|
|
@ -1072,7 +1080,9 @@ class InfoUtil(private val context: Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (downloadItem.extraCommands.isNotBlank()){
|
if (downloadItem.extraCommands.isNotBlank()){
|
||||||
val conf = File(FileUtil.getCachePath(context) + "/${System.currentTimeMillis()}.txt")
|
val cache = File(FileUtil.getCachePath(context))
|
||||||
|
cache.mkdirs()
|
||||||
|
val conf = File(cache.absolutePath + "/${System.currentTimeMillis()}.txt")
|
||||||
conf.createNewFile()
|
conf.createNewFile()
|
||||||
conf.writeText(downloadItem.extraCommands)
|
conf.writeText(downloadItem.extraCommands)
|
||||||
request.addOption(
|
request.addOption(
|
||||||
|
|
@ -1135,7 +1145,7 @@ class InfoUtil(private val context: Context) {
|
||||||
if (sharedPreferences.getBoolean("embed_metadata", true)){
|
if (sharedPreferences.getBoolean("embed_metadata", true)){
|
||||||
request.addOption("--embed-metadata")
|
request.addOption("--embed-metadata")
|
||||||
|
|
||||||
request.addOption("--parse-metadata", "%(release_year,upload_date)s:%(meta_date)s")
|
request.addOption("--parse-metadata", "%(release_year,release_date>%Y,upload_date>%Y)s:%(meta_date)s")
|
||||||
|
|
||||||
if (downloadItem.playlistTitle.isNotEmpty()) {
|
if (downloadItem.playlistTitle.isNotEmpty()) {
|
||||||
request.addOption("--parse-metadata", "%(album,playlist,title)s:%(meta_album)s")
|
request.addOption("--parse-metadata", "%(album,playlist,title)s:%(meta_album)s")
|
||||||
|
|
|
||||||
|
|
@ -11,15 +11,16 @@ import android.content.SharedPreferences
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.DisplayMetrics
|
import android.util.DisplayMetrics
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.content.FileProvider
|
import androidx.core.content.FileProvider
|
||||||
|
import androidx.documentfile.provider.DocumentFile
|
||||||
import androidx.navigation.NavDeepLinkBuilder
|
import androidx.navigation.NavDeepLinkBuilder
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.App.Companion.instance
|
|
||||||
import com.deniscerri.ytdlnis.receiver.CancelDownloadNotificationReceiver
|
import com.deniscerri.ytdlnis.receiver.CancelDownloadNotificationReceiver
|
||||||
import com.deniscerri.ytdlnis.receiver.CancelWorkReceiver
|
import com.deniscerri.ytdlnis.receiver.CancelWorkReceiver
|
||||||
import com.deniscerri.ytdlnis.receiver.PauseDownloadNotificationReceiver
|
import com.deniscerri.ytdlnis.receiver.PauseDownloadNotificationReceiver
|
||||||
|
|
@ -195,7 +196,8 @@ class NotificationUtil(var context: Context) {
|
||||||
notificationManager.notify(DOWNLOAD_UPDATING_NOTIFICATION_ID, notificationBuilder.build())
|
notificationManager.notify(DOWNLOAD_UPDATING_NOTIFICATION_ID, notificationBuilder.build())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createDownloadFinished(title: String?,
|
fun createDownloadFinished(
|
||||||
|
title: String?,
|
||||||
filepath: List<String>?
|
filepath: List<String>?
|
||||||
) {
|
) {
|
||||||
val notificationBuilder = getBuilder(DOWNLOAD_FINISHED_CHANNEL_ID)
|
val notificationBuilder = getBuilder(DOWNLOAD_FINISHED_CHANNEL_ID)
|
||||||
|
|
@ -215,24 +217,36 @@ class NotificationUtil(var context: Context) {
|
||||||
.clearActions()
|
.clearActions()
|
||||||
if (filepath != null){
|
if (filepath != null){
|
||||||
try{
|
try{
|
||||||
val file = File(filepath.first())
|
val uri = filepath.first().runCatching {
|
||||||
val uri = FileProvider.getUriForFile(
|
DocumentFile.fromSingleUri(context, Uri.parse(filepath.first())).run{
|
||||||
context,
|
if (this?.exists() == true){
|
||||||
"com.deniscerri.ytdl.fileprovider",
|
this.uri
|
||||||
file
|
}else if (File(this@runCatching).exists()){
|
||||||
)
|
FileProvider.getUriForFile(context, context.packageName + ".fileprovider",
|
||||||
|
File(this@runCatching))
|
||||||
|
}else null
|
||||||
|
}
|
||||||
|
}.getOrNull()
|
||||||
|
|
||||||
|
val openFileIntent = Intent()
|
||||||
|
|
||||||
|
if (uri != null){
|
||||||
|
openFileIntent.apply {
|
||||||
|
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||||
|
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
|
action = Intent.ACTION_VIEW
|
||||||
|
data = uri
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//open intent
|
|
||||||
val intent = Intent()
|
|
||||||
intent.action = Intent.ACTION_VIEW
|
|
||||||
intent.setDataAndType(uri, "*/*")
|
|
||||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
|
||||||
val openNotificationPendingIntent: PendingIntent = TaskStackBuilder.create(context).run {
|
val openNotificationPendingIntent: PendingIntent = TaskStackBuilder.create(context).run {
|
||||||
addNextIntentWithParentStack(intent)
|
addNextIntentWithParentStack(openFileIntent)
|
||||||
getPendingIntent(0,
|
getPendingIntent(0,
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
|
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//share intent
|
//share intent
|
||||||
val shareIntent = Intent(context, ShareFileActivity::class.java)
|
val shareIntent = Intent(context, ShareFileActivity::class.java)
|
||||||
shareIntent.putExtra("path", filepath.toTypedArray())
|
shareIntent.putExtra("path", filepath.toTypedArray())
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ import android.graphics.drawable.ShapeDrawable
|
||||||
import android.graphics.drawable.shapes.OvalShape
|
import android.graphics.drawable.shapes.OvalShape
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Looper
|
|
||||||
import android.text.Editable
|
import android.text.Editable
|
||||||
import android.text.TextWatcher
|
import android.text.TextWatcher
|
||||||
import android.text.format.DateFormat
|
import android.text.format.DateFormat
|
||||||
|
|
@ -34,13 +33,9 @@ import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.content.res.AppCompatResources
|
import androidx.appcompat.content.res.AppCompatResources
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import androidx.core.content.FileProvider
|
import androidx.core.content.FileProvider
|
||||||
import androidx.core.view.allViews
|
|
||||||
import androidx.core.view.children
|
import androidx.core.view.children
|
||||||
import androidx.core.view.get
|
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.core.widget.doOnTextChanged
|
|
||||||
import androidx.documentfile.provider.DocumentFile
|
import androidx.documentfile.provider.DocumentFile
|
||||||
import androidx.fragment.app.FragmentManager
|
import androidx.fragment.app.FragmentManager
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
|
|
@ -50,7 +45,6 @@ import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.afollestad.materialdialogs.utils.MDUtil.getStringArray
|
import com.afollestad.materialdialogs.utils.MDUtil.getStringArray
|
||||||
import com.deniscerri.ytdlnis.MainActivity
|
import com.deniscerri.ytdlnis.MainActivity
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.adapter.ConfigureMultipleDownloadsAdapter
|
|
||||||
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
||||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||||
import com.deniscerri.ytdlnis.database.models.Format
|
import com.deniscerri.ytdlnis.database.models.Format
|
||||||
|
|
@ -59,9 +53,9 @@ import com.deniscerri.ytdlnis.database.models.TemplateShortcut
|
||||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.CommandTemplateViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.CommandTemplateViewModel
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||||
|
import com.deniscerri.ytdlnis.database.viewmodel.HistoryViewModel
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
|
import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel
|
||||||
import com.deniscerri.ytdlnis.ui.downloadcard.ConfigureDownloadBottomSheetDialog
|
import com.deniscerri.ytdlnis.ui.downloadcard.ConfigureDownloadBottomSheetDialog
|
||||||
import com.deniscerri.ytdlnis.ui.downloadcard.DownloadBottomSheetDialog
|
|
||||||
import com.deniscerri.ytdlnis.ui.downloadcard.VideoCutListener
|
import com.deniscerri.ytdlnis.ui.downloadcard.VideoCutListener
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
|
|
@ -285,19 +279,17 @@ object UiUtil {
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT
|
ViewGroup.LayoutParams.MATCH_PARENT
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
fun copyLinkToClipBoard(context: Context, url: String, bottomSheet: BottomSheetDialog?) {
|
fun copyLinkToClipBoard(context: Context, url: String) {
|
||||||
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||||
val clip = ClipData.newPlainText(context.getString(R.string.url), url)
|
val clip = ClipData.newPlainText(context.getString(R.string.url), url)
|
||||||
clipboard.setPrimaryClip(clip)
|
clipboard.setPrimaryClip(clip)
|
||||||
bottomSheet?.hide()
|
|
||||||
Toast.makeText(context, context.getString(R.string.link_copied_to_clipboard), Toast.LENGTH_SHORT)
|
Toast.makeText(context, context.getString(R.string.link_copied_to_clipboard), Toast.LENGTH_SHORT)
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun openLinkIntent(context: Context, url: String, bottomSheet: BottomSheetDialog?) {
|
fun openLinkIntent(context: Context, url: String) {
|
||||||
val i = Intent(Intent.ACTION_VIEW)
|
val i = Intent(Intent.ACTION_VIEW)
|
||||||
i.data = Uri.parse(url)
|
i.data = Uri.parse(url)
|
||||||
bottomSheet?.hide()
|
|
||||||
context.startActivity(i)
|
context.startActivity(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -432,18 +424,19 @@ object UiUtil {
|
||||||
|
|
||||||
// BUTTON ----------------------------------
|
// BUTTON ----------------------------------
|
||||||
val btn = bottomSheet.findViewById<FloatingActionButton>(R.id.download_button_type)
|
val btn = bottomSheet.findViewById<FloatingActionButton>(R.id.download_button_type)
|
||||||
|
val typeImageResource: Int =
|
||||||
when (item.type) {
|
when (item.type) {
|
||||||
DownloadViewModel.Type.audio -> {
|
DownloadViewModel.Type.audio -> {
|
||||||
btn?.setImageResource(R.drawable.ic_music)
|
R.drawable.ic_music
|
||||||
|
}
|
||||||
|
DownloadViewModel.Type.video -> {
|
||||||
|
R.drawable.ic_video
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
R.drawable.ic_terminal
|
||||||
|
}
|
||||||
}
|
}
|
||||||
DownloadViewModel.Type.video -> {
|
btn?.setImageResource(typeImageResource)
|
||||||
btn?.setImageResource(R.drawable.ic_video)
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
btn?.setImageResource(R.drawable.ic_terminal)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val time = bottomSheet.findViewById<Chip>(R.id.time)
|
val time = bottomSheet.findViewById<Chip>(R.id.time)
|
||||||
val formatNote = bottomSheet.findViewById<Chip>(R.id.format_note)
|
val formatNote = bottomSheet.findViewById<Chip>(R.id.format_note)
|
||||||
|
|
@ -474,8 +467,12 @@ object UiUtil {
|
||||||
View.GONE
|
View.GONE
|
||||||
else formatNote!!.text = item.format.format_note
|
else formatNote!!.text = item.format.format_note
|
||||||
|
|
||||||
if (item.format.container != "") container!!.text = item.format.container.uppercase()
|
if (item.format.container != "") {
|
||||||
else container!!.visibility = View.GONE
|
container!!.text = item.format.container.uppercase()
|
||||||
|
container.setChipIconResource(typeImageResource)
|
||||||
|
}else {
|
||||||
|
container!!.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
val codecText =
|
val codecText =
|
||||||
if (item.format.encoding != "") {
|
if (item.format.encoding != "") {
|
||||||
|
|
@ -501,10 +498,12 @@ object UiUtil {
|
||||||
link!!.text = url
|
link!!.text = url
|
||||||
link.tag = item.id
|
link.tag = item.id
|
||||||
link.setOnClickListener{
|
link.setOnClickListener{
|
||||||
openLinkIntent(context, item.url, bottomSheet)
|
bottomSheet.dismiss()
|
||||||
|
openLinkIntent(context, item.url)
|
||||||
}
|
}
|
||||||
link.setOnLongClickListener{
|
link.setOnLongClickListener{
|
||||||
copyLinkToClipBoard(context, item.url, bottomSheet)
|
bottomSheet.dismiss()
|
||||||
|
copyLinkToClipBoard(context, item.url)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
val remove = bottomSheet.findViewById<Button>(R.id.bottomsheet_remove_button)
|
val remove = bottomSheet.findViewById<Button>(R.id.bottomsheet_remove_button)
|
||||||
|
|
@ -561,6 +560,7 @@ object UiUtil {
|
||||||
item: HistoryItem?,
|
item: HistoryItem?,
|
||||||
context: Activity,
|
context: Activity,
|
||||||
isPresent: Boolean,
|
isPresent: Boolean,
|
||||||
|
removeItem: (item:HistoryItem, removeFiles: Boolean) -> Unit,
|
||||||
redownloadItem: (HistoryItem) -> Unit,
|
redownloadItem: (HistoryItem) -> Unit,
|
||||||
redownloadShowDownloadCard: (HistoryItem) -> Unit,
|
redownloadShowDownloadCard: (HistoryItem) -> Unit,
|
||||||
){
|
){
|
||||||
|
|
@ -575,21 +575,23 @@ object UiUtil {
|
||||||
// BUTTON ----------------------------------
|
// BUTTON ----------------------------------
|
||||||
val btn = bottomSheet.findViewById<FloatingActionButton>(R.id.download_button_type)
|
val btn = bottomSheet.findViewById<FloatingActionButton>(R.id.download_button_type)
|
||||||
|
|
||||||
|
val typeImageResource: Int =
|
||||||
if (item.type == DownloadViewModel.Type.audio) {
|
if (item.type == DownloadViewModel.Type.audio) {
|
||||||
if (isPresent) {
|
if (isPresent) {
|
||||||
btn?.setImageResource(R.drawable.ic_music_downloaded)
|
R.drawable.ic_music_downloaded
|
||||||
} else {
|
} else {
|
||||||
btn?.setImageResource(R.drawable.ic_music)
|
R.drawable.ic_music
|
||||||
}
|
}
|
||||||
} else if (item.type == DownloadViewModel.Type.video) {
|
} else if (item.type == DownloadViewModel.Type.video) {
|
||||||
if (isPresent) {
|
if (isPresent) {
|
||||||
btn?.setImageResource(R.drawable.ic_video_downloaded)
|
R.drawable.ic_video_downloaded
|
||||||
} else {
|
} else {
|
||||||
btn?.setImageResource(R.drawable.ic_video)
|
R.drawable.ic_video
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
btn?.setImageResource(R.drawable.ic_terminal)
|
R.drawable.ic_terminal
|
||||||
}
|
}
|
||||||
|
btn?.setImageResource(typeImageResource)
|
||||||
|
|
||||||
if (isPresent){
|
if (isPresent){
|
||||||
btn?.setOnClickListener {
|
btn?.setOnClickListener {
|
||||||
|
|
@ -599,9 +601,10 @@ object UiUtil {
|
||||||
|
|
||||||
val time = bottomSheet.findViewById<TextView>(R.id.time)
|
val time = bottomSheet.findViewById<TextView>(R.id.time)
|
||||||
val formatNote = bottomSheet.findViewById<TextView>(R.id.format_note)
|
val formatNote = bottomSheet.findViewById<TextView>(R.id.format_note)
|
||||||
val container = bottomSheet.findViewById<TextView>(R.id.container_chip)
|
val container = bottomSheet.findViewById<Chip>(R.id.container_chip)
|
||||||
val codec = bottomSheet.findViewById<TextView>(R.id.codec)
|
val codec = bottomSheet.findViewById<TextView>(R.id.codec)
|
||||||
val fileSize = bottomSheet.findViewById<TextView>(R.id.file_size)
|
val fileSize = bottomSheet.findViewById<TextView>(R.id.file_size)
|
||||||
|
val file = File(item.downloadPath)
|
||||||
|
|
||||||
val calendar = Calendar.getInstance()
|
val calendar = Calendar.getInstance()
|
||||||
calendar.timeInMillis = item.time * 1000L
|
calendar.timeInMillis = item.time * 1000L
|
||||||
|
|
@ -610,10 +613,14 @@ object UiUtil {
|
||||||
|
|
||||||
if (item.format.format_note == "?" || item.format.format_note == "") formatNote!!.visibility =
|
if (item.format.format_note == "?" || item.format.format_note == "") formatNote!!.visibility =
|
||||||
View.GONE
|
View.GONE
|
||||||
else formatNote!!.text = item.format.format_note
|
else formatNote!!.text = item.format.format_note.uppercase()
|
||||||
|
|
||||||
if (item.format.container != "") container!!.text = item.format.container.uppercase()
|
if (item.format.container != "") {
|
||||||
else container!!.visibility = View.GONE
|
container!!.text = if (file.exists()) file.extension.uppercase() else item.format.container.uppercase()
|
||||||
|
container.setChipIconResource(typeImageResource)
|
||||||
|
}else {
|
||||||
|
container!!.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
val codecText =
|
val codecText =
|
||||||
if (item.format.encoding != "") {
|
if (item.format.encoding != "") {
|
||||||
|
|
@ -630,7 +637,6 @@ object UiUtil {
|
||||||
codec.text = codecText
|
codec.text = codecText
|
||||||
}
|
}
|
||||||
|
|
||||||
val file = File(item.downloadPath)
|
|
||||||
val fileSizeReadable = FileUtil.convertFileSize(if (file.exists()) file.length() else item.format.filesize)
|
val fileSizeReadable = FileUtil.convertFileSize(if (file.exists()) file.length() else item.format.filesize)
|
||||||
if (fileSizeReadable == "?") fileSize!!.visibility = View.GONE
|
if (fileSizeReadable == "?") fileSize!!.visibility = View.GONE
|
||||||
else fileSize!!.text = fileSizeReadable
|
else fileSize!!.text = fileSizeReadable
|
||||||
|
|
@ -640,18 +646,18 @@ object UiUtil {
|
||||||
link!!.text = url
|
link!!.text = url
|
||||||
link.tag = item.id
|
link.tag = item.id
|
||||||
link.setOnClickListener{
|
link.setOnClickListener{
|
||||||
openLinkIntent(context, item.url, bottomSheet)
|
bottomSheet.dismiss()
|
||||||
|
openLinkIntent(context, item.url)
|
||||||
}
|
}
|
||||||
link.setOnLongClickListener{
|
link.setOnLongClickListener{
|
||||||
copyLinkToClipBoard(context, item.url, bottomSheet)
|
bottomSheet.dismiss()
|
||||||
|
copyLinkToClipBoard(context, item.url)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
val remove = bottomSheet.findViewById<Button>(R.id.bottomsheet_remove_button)
|
val remove = bottomSheet.findViewById<Button>(R.id.bottomsheet_remove_button)
|
||||||
remove!!.tag = item.id
|
remove!!.tag = item.id
|
||||||
remove.setOnClickListener{
|
remove.setOnClickListener{
|
||||||
showRemoveHistoryItemDialog(item, context, delete = { item, deleteFile ->
|
showRemoveHistoryItemDialog(item, context, delete = removeItem)
|
||||||
|
|
||||||
})
|
|
||||||
bottomSheet.dismiss()
|
bottomSheet.dismiss()
|
||||||
}
|
}
|
||||||
val openFile = bottomSheet.findViewById<Button>(R.id.bottomsheet_open_file_button)
|
val openFile = bottomSheet.findViewById<Button>(R.id.bottomsheet_open_file_button)
|
||||||
|
|
@ -786,15 +792,15 @@ object UiUtil {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun showSubtitleLanguagesDialog(context: Activity, currentValue: String, ok: (newValue: String) -> Unit){
|
private fun showSubtitleLanguagesDialog(context: Activity, currentValue: String, ok: (newValue: String) -> Unit){
|
||||||
val builder = MaterialAlertDialogBuilder(context)
|
val builder = MaterialAlertDialogBuilder(context)
|
||||||
builder.setTitle(context.getString(R.string.subtitle_languages))
|
builder.setTitle(context.getString(R.string.subtitle_languages))
|
||||||
val inputLayout = context.layoutInflater.inflate(R.layout.textinput, null)
|
val view = context.layoutInflater.inflate(R.layout.subtitle_dialog, null)
|
||||||
val editText = inputLayout.findViewById<EditText>(R.id.url_edittext)
|
val editText = view.findViewById<EditText>(R.id.subtitle_edittext)
|
||||||
inputLayout.findViewById<TextInputLayout>(R.id.url_textinput).hint = context.getString(R.string.subtitle_languages)
|
view.findViewById<TextInputLayout>(R.id.subtitle).hint = context.getString(R.string.subtitle_languages)
|
||||||
editText.setText(currentValue)
|
editText.setText(currentValue)
|
||||||
editText.setSelection(editText.text.length)
|
editText.setSelection(editText.text.length)
|
||||||
builder.setView(inputLayout)
|
builder.setView(view)
|
||||||
builder.setPositiveButton(
|
builder.setPositiveButton(
|
||||||
context.getString(R.string.ok)
|
context.getString(R.string.ok)
|
||||||
) { _: DialogInterface?, _: Int ->
|
) { _: DialogInterface?, _: Int ->
|
||||||
|
|
@ -812,19 +818,46 @@ object UiUtil {
|
||||||
context.startActivity(browserIntent)
|
context.startActivity(browserIntent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
view.findViewById<View>(R.id.suggested).visibility = View.GONE
|
||||||
|
|
||||||
val dialog = builder.create()
|
val dialog = builder.create()
|
||||||
editText.doOnTextChanged { _, _, _, _ ->
|
|
||||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = editText.text.isNotEmpty()
|
|
||||||
}
|
|
||||||
dialog.show()
|
dialog.show()
|
||||||
val imm = context.getSystemService(AppCompatActivity.INPUT_METHOD_SERVICE) as InputMethodManager
|
val imm = context.getSystemService(AppCompatActivity.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||||
editText.setSelection(editText.text!!.length)
|
|
||||||
editText!!.postDelayed({
|
editText!!.postDelayed({
|
||||||
editText.requestFocus()
|
editText.requestFocus()
|
||||||
imm.showSoftInput(editText, 0)
|
imm.showSoftInput(editText, 0)
|
||||||
}, 300)
|
}, 300)
|
||||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = editText.text.isNotEmpty()
|
|
||||||
|
//handle suggestion chips
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
val chipGroup = view.findViewById<ChipGroup>(R.id.subtitle_suggested_chipgroup)
|
||||||
|
val chips = mutableListOf<Chip>()
|
||||||
|
context.getStringArray(R.array.subtitle_langs).forEachIndexed { index, s ->
|
||||||
|
val tmp = context.layoutInflater.inflate(R.layout.filter_chip, chipGroup, false) as Chip
|
||||||
|
tmp.text = s
|
||||||
|
tmp.id = index
|
||||||
|
|
||||||
|
tmp.setOnClickListener {
|
||||||
|
val c = it as Chip
|
||||||
|
if(!c.isChecked){
|
||||||
|
editText.setText(editText.text.toString().replace(c.text.toString(), ""))
|
||||||
|
editText.setSelection(editText.text.length)
|
||||||
|
}else{
|
||||||
|
editText.append(c.text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
chips.add(tmp)
|
||||||
|
}
|
||||||
|
withContext(Dispatchers.Main){
|
||||||
|
view.findViewById<View>(R.id.suggested).visibility = View.VISIBLE
|
||||||
|
chips.forEach {
|
||||||
|
it.isChecked = editText.text.contains(it.text)
|
||||||
|
chipGroup!!.addView(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dialog.getButton(AlertDialog.BUTTON_NEUTRAL).gravity = Gravity.START
|
dialog.getButton(AlertDialog.BUTTON_NEUTRAL).gravity = Gravity.START
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -934,7 +967,7 @@ object UiUtil {
|
||||||
cutClicked: (VideoCutListener) -> Unit,
|
cutClicked: (VideoCutListener) -> Unit,
|
||||||
filenameTemplateSet: (String) -> Unit,
|
filenameTemplateSet: (String) -> Unit,
|
||||||
saveSubtitlesClicked: (Boolean) -> Unit,
|
saveSubtitlesClicked: (Boolean) -> Unit,
|
||||||
subtitleLanguagesClicked: () -> Unit,
|
subtitleLanguagesSet: (String) -> Unit,
|
||||||
removeAudioClicked: (Boolean) -> Unit,
|
removeAudioClicked: (Boolean) -> Unit,
|
||||||
extraCommandsClicked: () -> Unit
|
extraCommandsClicked: () -> Unit
|
||||||
){
|
){
|
||||||
|
|
@ -1093,7 +1126,14 @@ object UiUtil {
|
||||||
|
|
||||||
subtitleLanguages.isEnabled = embedSubs.isChecked || saveSubtitles.isChecked
|
subtitleLanguages.isEnabled = embedSubs.isChecked || saveSubtitles.isChecked
|
||||||
subtitleLanguages.setOnClickListener {
|
subtitleLanguages.setOnClickListener {
|
||||||
subtitleLanguagesClicked()
|
val currentSubtitleLang = if (items.size == 1 || items.all { it.videoPreferences.subsLanguages == items[0].videoPreferences.subsLanguages }){
|
||||||
|
items[0].videoPreferences.subsLanguages
|
||||||
|
}else {
|
||||||
|
""
|
||||||
|
}
|
||||||
|
showSubtitleLanguagesDialog(context, currentSubtitleLang){
|
||||||
|
subtitleLanguagesSet(it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val removeAudio = view.findViewById<Chip>(R.id.remove_audio)
|
val removeAudio = view.findViewById<Chip>(R.id.remove_audio)
|
||||||
|
|
@ -1301,7 +1341,7 @@ object UiUtil {
|
||||||
|
|
||||||
private var textHighLightSchemes = listOf(
|
private var textHighLightSchemes = listOf(
|
||||||
ColorScheme(Pattern.compile("([\"'])(?:\\\\1|.)*?\\1"), Color.parseColor("#FC8500")),
|
ColorScheme(Pattern.compile("([\"'])(?:\\\\1|.)*?\\1"), Color.parseColor("#FC8500")),
|
||||||
ColorScheme(Pattern.compile("yt-dlp"), Color.parseColor("#00FF00")),
|
ColorScheme(Pattern.compile("yt-dlp"), Color.parseColor("#FF0000")),
|
||||||
ColorScheme(Pattern.compile("(https?://(?:www\\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\\.[^\\s]{2,}|www\\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\\.[^\\s]{2,}|https?://(?:www\\.|(?!www))[a-zA-Z0-9]+\\.[^\\s]{2,}|www\\.[a-zA-Z0-9]+\\.[^\\s]{2,})"), Color.parseColor("#b5942f")),
|
ColorScheme(Pattern.compile("(https?://(?:www\\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\\.[^\\s]{2,}|www\\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\\.[^\\s]{2,}|https?://(?:www\\.|(?!www))[a-zA-Z0-9]+\\.[^\\s]{2,}|www\\.[a-zA-Z0-9]+\\.[^\\s]{2,})"), Color.parseColor("#b5942f")),
|
||||||
ColorScheme(Pattern.compile("\\d+(\\.\\d)?%"), Color.parseColor("#43a564"))
|
ColorScheme(Pattern.compile("\\d+(\\.\\d)?%"), Color.parseColor("#43a564"))
|
||||||
)
|
)
|
||||||
|
|
@ -1339,7 +1379,7 @@ object UiUtil {
|
||||||
this.requestLayout()
|
this.requestLayout()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun handleResultResponse(context: Activity, it: ResultViewModel.ResultsUiState){
|
fun handleResultResponse(context: Activity, it: ResultViewModel.ResultsUiState, closed: () -> Unit){
|
||||||
val title = context.getString(it.errorMessage!!.first)
|
val title = context.getString(it.errorMessage!!.first)
|
||||||
val message = it.errorMessage!!.second
|
val message = it.errorMessage!!.second
|
||||||
|
|
||||||
|
|
@ -1358,11 +1398,16 @@ object UiUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
errDialog.setOnCancelListener {
|
||||||
|
closed()
|
||||||
|
}
|
||||||
|
|
||||||
errDialog.show()
|
errDialog.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
fun handleDownloadsResponse(context: MainActivity, it: DownloadViewModel.DownloadsUiState, downloadViewModel: DownloadViewModel){
|
fun handleDownloadsResponse(context: MainActivity, it: DownloadViewModel.DownloadsUiState, downloadViewModel: DownloadViewModel, historyViewModel: HistoryViewModel){
|
||||||
val downloadAnywayAction = it.actions?.first { it.second == DownloadViewModel.DownloadsAction.DOWNLOAD_ANYWAY}
|
val downloadAnywayAction = it.actions?.first { it.second == DownloadViewModel.DownloadsAction.DOWNLOAD_ANYWAY}
|
||||||
if (downloadAnywayAction != null){
|
if (downloadAnywayAction != null){
|
||||||
if (downloadAnywayAction.third == null) return
|
if (downloadAnywayAction.third == null) return
|
||||||
|
|
@ -1425,14 +1470,11 @@ object UiUtil {
|
||||||
if (historyItem != null){
|
if (historyItem != null){
|
||||||
ttle.setOnClickListener {
|
ttle.setOnClickListener {
|
||||||
showHistoryItemDetailsCard(historyItem, context, isPresent = true,
|
showHistoryItemDetailsCard(historyItem, context, isPresent = true,
|
||||||
|
removeItem = { item, deleteFile ->
|
||||||
|
historyViewModel.delete(item, deleteFile)
|
||||||
|
},
|
||||||
redownloadItem = { },
|
redownloadItem = { },
|
||||||
redownloadShowDownloadCard = {
|
redownloadShowDownloadCard = {}
|
||||||
val sheet = DownloadBottomSheetDialog(
|
|
||||||
result = downloadViewModel.createResultItemFromHistory(it),
|
|
||||||
type = it.type
|
|
||||||
)
|
|
||||||
sheet.show(context.supportFragmentManager, "downloadSingleSheet")
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1455,7 +1497,7 @@ object UiUtil {
|
||||||
|
|
||||||
errDialog.setPositiveButton(downloadAnywayAction.first) { d:DialogInterface?, _:Int ->
|
errDialog.setPositiveButton(downloadAnywayAction.first) { d:DialogInterface?, _:Int ->
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
linearLayout.allViews.forEach {view ->
|
linearLayout.children.forEach {view ->
|
||||||
val downloadItem = downloads.first { it.id == (view.tag as String).toLong()}
|
val downloadItem = downloads.first { it.id == (view.tag as String).toLong()}
|
||||||
downloadItem.id = 0
|
downloadItem.id = 0
|
||||||
downloadViewModel.queueDownloads(listOf(downloadItem), true)
|
downloadViewModel.queueDownloads(listOf(downloadItem), true)
|
||||||
|
|
@ -1547,6 +1589,12 @@ object UiUtil {
|
||||||
context.getString(R.string.cancel)
|
context.getString(R.string.cancel)
|
||||||
) { _: DialogInterface?, _: Int -> }
|
) { _: DialogInterface?, _: Int -> }
|
||||||
|
|
||||||
|
builder.setNeutralButton("?") { _: DialogInterface?, _: Int ->
|
||||||
|
val browserIntent =
|
||||||
|
Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/yt-dlp/yt-dlp#user-content-outtmpl-postprocess-note"))
|
||||||
|
context.startActivity(browserIntent)
|
||||||
|
}
|
||||||
|
|
||||||
view.findViewById<View>(R.id.suggested).visibility = View.GONE
|
view.findViewById<View>(R.id.suggested).visibility = View.GONE
|
||||||
|
|
||||||
val dialog = builder.create()
|
val dialog = builder.create()
|
||||||
|
|
|
||||||
|
|
@ -1,37 +1,51 @@
|
||||||
package com.deniscerri.ytdlnis.util
|
package com.deniscerri.ytdlnis.util
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.app.DownloadManager
|
import android.app.DownloadManager
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.IntentFilter
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
|
import android.text.method.LinkMovementMethod
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import android.widget.TextView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.core.content.ContextCompat.startActivity
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import com.deniscerri.ytdlnis.BuildConfig
|
import com.deniscerri.ytdlnis.BuildConfig
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.database.models.GithubRelease
|
import com.deniscerri.ytdlnis.database.models.GithubRelease
|
||||||
import com.deniscerri.ytdlnis.database.models.GithubReleaseAsset
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import com.google.gson.reflect.TypeToken
|
import com.google.gson.reflect.TypeToken
|
||||||
import com.yausername.youtubedl_android.YoutubeDL
|
import com.yausername.youtubedl_android.YoutubeDL
|
||||||
import com.yausername.youtubedl_android.YoutubeDL.UpdateStatus
|
import com.yausername.youtubedl_android.YoutubeDL.UpdateStatus
|
||||||
|
import io.noties.markwon.AbstractMarkwonPlugin
|
||||||
|
import io.noties.markwon.Markwon
|
||||||
|
import io.noties.markwon.MarkwonConfiguration
|
||||||
|
import io.noties.markwon.MarkwonSpansFactory
|
||||||
|
import io.noties.markwon.core.MarkwonTheme
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.io.BufferedReader
|
import java.io.File
|
||||||
import java.io.InputStreamReader
|
import java.io.InputStreamReader
|
||||||
import java.net.HttpURLConnection
|
import java.net.HttpURLConnection
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
|
|
||||||
|
|
||||||
class UpdateUtil(var context: Context) {
|
class UpdateUtil(var context: Context) {
|
||||||
private val tag = "UpdateUtil"
|
private val tag = "UpdateUtil"
|
||||||
private val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
|
private val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
private val downloadManager: DownloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
|
private val downloadManager: DownloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
|
||||||
|
|
||||||
|
@SuppressLint("UnspecifiedRegisterReceiverFlag")
|
||||||
fun updateApp(result: (result: String) -> Unit) {
|
fun updateApp(result: (result: String) -> Unit) {
|
||||||
try {
|
try {
|
||||||
if (updatingApp) {
|
if (updatingApp) {
|
||||||
|
|
@ -99,7 +113,7 @@ class UpdateUtil(var context: Context) {
|
||||||
Environment
|
Environment
|
||||||
.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
|
.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
|
||||||
.mkdirs()
|
.mkdirs()
|
||||||
downloadManager.enqueue(
|
val downloadID = downloadManager.enqueue(
|
||||||
DownloadManager.Request(uri)
|
DownloadManager.Request(uri)
|
||||||
.setAllowedNetworkTypes(
|
.setAllowedNetworkTypes(
|
||||||
DownloadManager.Request.NETWORK_WIFI or
|
DownloadManager.Request.NETWORK_WIFI or
|
||||||
|
|
@ -110,10 +124,34 @@ class UpdateUtil(var context: Context) {
|
||||||
.setTitle(context.getString(R.string.downloading_update))
|
.setTitle(context.getString(R.string.downloading_update))
|
||||||
.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, releaseVersion.name)
|
.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, releaseVersion.name)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val onDownloadComplete: BroadcastReceiver =
|
||||||
|
object : BroadcastReceiver() {
|
||||||
|
override fun onReceive(context: Context?, intent: Intent) {
|
||||||
|
context?.unregisterReceiver(this)
|
||||||
|
UiUtil.openFileIntent(context!!,
|
||||||
|
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)?.absolutePath +
|
||||||
|
File.separator + releaseVersion.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
context.registerReceiver(onDownloadComplete, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
updateDialog.show()
|
val view = updateDialog.show()
|
||||||
|
val textView = view.findViewById<TextView>(android.R.id.message)
|
||||||
|
textView!!.movementMethod = LinkMovementMethod.getInstance()
|
||||||
|
val mw = Markwon.builder(context).usePlugin(object: AbstractMarkwonPlugin() {
|
||||||
|
|
||||||
|
override fun configureConfiguration(builder: MarkwonConfiguration.Builder) {
|
||||||
|
builder.linkResolver { view, link ->
|
||||||
|
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(link))
|
||||||
|
startActivity(context, browserIntent, Bundle())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).build()
|
||||||
|
mw.setMarkdown(textView, v.body)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}catch (e: Exception){
|
}catch (e: Exception){
|
||||||
|
|
|
||||||
|
|
@ -27,14 +27,12 @@ import com.deniscerri.ytdlnis.database.models.HistoryItem
|
||||||
import com.deniscerri.ytdlnis.database.models.LogItem
|
import com.deniscerri.ytdlnis.database.models.LogItem
|
||||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||||
import com.deniscerri.ytdlnis.database.repository.LogRepository
|
import com.deniscerri.ytdlnis.database.repository.LogRepository
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
|
||||||
import com.deniscerri.ytdlnis.util.FileUtil
|
import com.deniscerri.ytdlnis.util.FileUtil
|
||||||
import com.deniscerri.ytdlnis.util.InfoUtil
|
import com.deniscerri.ytdlnis.util.InfoUtil
|
||||||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
import com.deniscerri.ytdlnis.util.NotificationUtil
|
||||||
import com.yausername.youtubedl_android.YoutubeDL
|
import com.yausername.youtubedl_android.YoutubeDL
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
@ -122,6 +120,7 @@ class DownloadWorker(
|
||||||
|
|
||||||
|
|
||||||
val commandString = infoUtil.parseYTDLRequestString(request)
|
val commandString = infoUtil.parseYTDLRequestString(request)
|
||||||
|
val logString = StringBuilder("\n ${commandString}\n\n")
|
||||||
val logItem = LogItem(
|
val logItem = LogItem(
|
||||||
0,
|
0,
|
||||||
downloadItem.title.ifEmpty { downloadItem.url },
|
downloadItem.title.ifEmpty { downloadItem.url },
|
||||||
|
|
@ -129,7 +128,7 @@ class DownloadWorker(
|
||||||
"Title: ${downloadItem.title}\n" +
|
"Title: ${downloadItem.title}\n" +
|
||||||
"URL: ${downloadItem.url}\n" +
|
"URL: ${downloadItem.url}\n" +
|
||||||
"Type: ${downloadItem.type}\n" +
|
"Type: ${downloadItem.type}\n" +
|
||||||
"Command:\n ${commandString}\n\n",
|
"Command: $logString",
|
||||||
downloadItem.format,
|
downloadItem.format,
|
||||||
downloadItem.type,
|
downloadItem.type,
|
||||||
System.currentTimeMillis(),
|
System.currentTimeMillis(),
|
||||||
|
|
@ -137,7 +136,7 @@ class DownloadWorker(
|
||||||
|
|
||||||
|
|
||||||
runBlocking {
|
runBlocking {
|
||||||
logItem.id = logRepo.insert(logItem)
|
if (logDownloads) logItem.id = logRepo.insert(logItem)
|
||||||
downloadItem.logID = logItem.id
|
downloadItem.logID = logItem.id
|
||||||
dao.update(downloadItem)
|
dao.update(downloadItem)
|
||||||
}
|
}
|
||||||
|
|
@ -154,7 +153,10 @@ class DownloadWorker(
|
||||||
NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID
|
NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID
|
||||||
)
|
)
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
logRepo.update(line, logItem.id)
|
if (logDownloads) {
|
||||||
|
logRepo.update(line, logItem.id)
|
||||||
|
logString.append("$line\n")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.onSuccess {
|
}.onSuccess {
|
||||||
|
|
@ -164,16 +166,18 @@ class DownloadWorker(
|
||||||
|
|
||||||
if (noCache){
|
if (noCache){
|
||||||
setProgressAsync(workDataOf("progress" to 100, "output" to "Scanning Files", "id" to downloadItem.id))
|
setProgressAsync(workDataOf("progress" to 100, "output" to "Scanning Files", "id" to downloadItem.id))
|
||||||
val p = it.out.split("\n")
|
finalPaths = it.out.split("\n")
|
||||||
.filter { it.startsWith("'/storage") }
|
.filter { it.startsWith("'/storage") }
|
||||||
.map { it.removePrefix("'") }
|
.map { it.removePrefix("'") }
|
||||||
.map { it.removeSuffix("'\n") }
|
.map { it.removeSuffix("\n") }
|
||||||
finalPaths = File(FileUtil.formatPath(downloadLocation))
|
.map { it.removeSuffix("'") }
|
||||||
.walkTopDown()
|
|
||||||
.filter { it.isFile && p.any { f -> f.contains(it.nameWithoutExtension) }}
|
|
||||||
.sortedByDescending { it.length() }
|
|
||||||
.map { it.absolutePath }
|
|
||||||
.toList()
|
.toList()
|
||||||
|
// finalPaths = File(FileUtil.formatPath(downloadLocation))
|
||||||
|
// .walkTopDown()
|
||||||
|
// .filter { it.isFile && p.any { f -> f.contains(it.nameWithoutExtension) }}
|
||||||
|
// .sortedByDescending { it.length() }
|
||||||
|
// .map { it.absolutePath }
|
||||||
|
// .toList()
|
||||||
FileUtil.scanMedia(finalPaths, context)
|
FileUtil.scanMedia(finalPaths, context)
|
||||||
if (finalPaths.isEmpty()){
|
if (finalPaths.isEmpty()){
|
||||||
finalPaths = listOf(context.getString(R.string.unfound_file))
|
finalPaths = listOf(context.getString(R.string.unfound_file))
|
||||||
|
|
@ -236,8 +240,6 @@ class DownloadWorker(
|
||||||
|
|
||||||
if (logDownloads){
|
if (logDownloads){
|
||||||
logRepo.update(it.out, logItem.id)
|
logRepo.update(it.out, logItem.id)
|
||||||
}else{
|
|
||||||
logRepo.delete(logItem)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -250,9 +252,13 @@ class DownloadWorker(
|
||||||
if (it is YoutubeDL.CanceledException) {
|
if (it is YoutubeDL.CanceledException) {
|
||||||
|
|
||||||
}else{
|
}else{
|
||||||
if (logDownloads){
|
if(it.message != null){
|
||||||
if(it.message != null){
|
if (logDownloads){
|
||||||
logRepo.update(it.message!!, logItem.id)
|
logRepo.update(it.message!!, logItem.id)
|
||||||
|
}else{
|
||||||
|
logString.append("${it.message}\n")
|
||||||
|
logItem.content = logString.toString()
|
||||||
|
logRepo.insert(logItem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,33 +7,14 @@ import android.os.Build
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.util.Log
|
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.preference.PreferenceManager
|
|
||||||
import androidx.work.Data
|
|
||||||
import androidx.work.ForegroundInfo
|
import androidx.work.ForegroundInfo
|
||||||
import androidx.work.Worker
|
import androidx.work.Worker
|
||||||
import androidx.work.WorkerParameters
|
import androidx.work.WorkerParameters
|
||||||
import androidx.work.workDataOf
|
|
||||||
import com.deniscerri.ytdlnis.App
|
import com.deniscerri.ytdlnis.App
|
||||||
import com.deniscerri.ytdlnis.MainActivity
|
import com.deniscerri.ytdlnis.MainActivity
|
||||||
import com.deniscerri.ytdlnis.R
|
import com.deniscerri.ytdlnis.R
|
||||||
import com.deniscerri.ytdlnis.database.DBManager
|
|
||||||
import com.deniscerri.ytdlnis.database.dao.DownloadDao
|
|
||||||
import com.deniscerri.ytdlnis.database.dao.ResultDao
|
|
||||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
|
||||||
import com.deniscerri.ytdlnis.database.models.HistoryItem
|
|
||||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
|
||||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
|
||||||
import com.deniscerri.ytdlnis.util.FileUtil
|
|
||||||
import com.deniscerri.ytdlnis.util.InfoUtil
|
|
||||||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
import com.deniscerri.ytdlnis.util.NotificationUtil
|
||||||
import com.yausername.youtubedl_android.YoutubeDL
|
|
||||||
import com.yausername.youtubedl_android.YoutubeDLRequest
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.nio.file.StandardCopyOption
|
import java.nio.file.StandardCopyOption
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@ import com.deniscerri.ytdlnis.util.InfoUtil
|
||||||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
import com.deniscerri.ytdlnis.util.NotificationUtil
|
||||||
import com.yausername.youtubedl_android.YoutubeDL
|
import com.yausername.youtubedl_android.YoutubeDL
|
||||||
import com.yausername.youtubedl_android.YoutubeDLRequest
|
import com.yausername.youtubedl_android.YoutubeDLRequest
|
||||||
import kotlinx.coroutines.CancellationException
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
@ -45,10 +44,8 @@ class TerminalDownloadWorker(
|
||||||
|
|
||||||
val dbManager = DBManager.getInstance(context)
|
val dbManager = DBManager.getInstance(context)
|
||||||
val logRepo = LogRepository(dbManager.logDao)
|
val logRepo = LogRepository(dbManager.logDao)
|
||||||
|
|
||||||
val notificationUtil = NotificationUtil(context)
|
val notificationUtil = NotificationUtil(context)
|
||||||
val handler = Handler(Looper.getMainLooper())
|
val handler = Handler(Looper.getMainLooper())
|
||||||
val infoUtil = InfoUtil(context)
|
|
||||||
|
|
||||||
val intent = Intent(context, TerminalActivity::class.java)
|
val intent = Intent(context, TerminalActivity::class.java)
|
||||||
val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
|
val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
|
||||||
|
|
@ -95,7 +92,7 @@ class TerminalDownloadWorker(
|
||||||
System.currentTimeMillis(),
|
System.currentTimeMillis(),
|
||||||
)
|
)
|
||||||
|
|
||||||
runCatching {
|
kotlin.runCatching {
|
||||||
if (logDownloads){
|
if (logDownloads){
|
||||||
runBlocking {
|
runBlocking {
|
||||||
logItem.id = logRepo.insert(logItem)
|
logItem.id = logRepo.insert(logItem)
|
||||||
|
|
@ -137,12 +134,10 @@ class TerminalDownloadWorker(
|
||||||
}
|
}
|
||||||
|
|
||||||
return runBlocking {
|
return runBlocking {
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
if (logDownloads) logRepo.update(it.out, logItem.id)
|
||||||
if (logDownloads) logRepo.update(it.out, logItem.id)
|
dao.updateLog(it.out, itemId.toLong())
|
||||||
dao.updateLog(it.out, itemId.toLong())
|
Thread.sleep(1000)
|
||||||
Thread.sleep(1000)
|
dao.delete(itemId.toLong())
|
||||||
dao.delete(itemId.toLong())
|
|
||||||
}
|
|
||||||
notificationUtil.cancelDownloadNotification(itemId)
|
notificationUtil.cancelDownloadNotification(itemId)
|
||||||
|
|
||||||
Result.success()
|
Result.success()
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
android:height="108dp"
|
android:height="108dp"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24"
|
android:viewportHeight="24"
|
||||||
android:tint="#fff">
|
android:tint="@color/icon_fg">
|
||||||
<group android:scaleX="0.58"
|
<group android:scaleX="0.58"
|
||||||
android:scaleY="0.58"
|
android:scaleY="0.58"
|
||||||
android:translateX="5.04"
|
android:translateX="5.04"
|
||||||
|
|
|
||||||
|
|
@ -133,7 +133,7 @@
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
<include layout="@layout/history_no_results"
|
<include layout="@layout/no_results"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@
|
||||||
android:layout_margin="10dp"
|
android:layout_margin="10dp"
|
||||||
android:backgroundTint="@android:color/transparent"
|
android:backgroundTint="@android:color/transparent"
|
||||||
app:tabGravity="fill"
|
app:tabGravity="fill"
|
||||||
|
app:tabMinWidth="0dp"
|
||||||
app:tabMode="scrollable">
|
app:tabMode="scrollable">
|
||||||
|
|
||||||
<com.google.android.material.tabs.TabItem
|
<com.google.android.material.tabs.TabItem
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,7 @@
|
||||||
android:layout_margin="10dp"
|
android:layout_margin="10dp"
|
||||||
android:backgroundTint="@android:color/transparent"
|
android:backgroundTint="@android:color/transparent"
|
||||||
app:tabGravity="start"
|
app:tabGravity="start"
|
||||||
|
app:tabMinWidth="0dp"
|
||||||
app:tabMode="scrollable">
|
app:tabMode="scrollable">
|
||||||
|
|
||||||
<com.google.android.material.tabs.TabItem
|
<com.google.android.material.tabs.TabItem
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,42 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:tools="http://schemas.android.com/tools"
|
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_marginBottom="100dp"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<LinearLayout
|
||||||
android:id="@+id/pause_resume"
|
|
||||||
android:visibility="gone"
|
|
||||||
style="@style/Widget.Material3.Button.TextButton"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingHorizontal="30dp"
|
|
||||||
android:layout_gravity="end"
|
|
||||||
android:paddingVertical="10dp"
|
|
||||||
android:text="@string/resume"
|
|
||||||
android:textStyle="bold"/>
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:id="@+id/download_recyclerview"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent"
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
android:orientation="vertical">
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
android:scrollbars="none"
|
|
||||||
app:layout_constraintHorizontal_bias="0.0"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/pause_resume">
|
|
||||||
|
|
||||||
</androidx.recyclerview.widget.RecyclerView>
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/pause_resume"
|
||||||
|
android:visibility="gone"
|
||||||
|
style="@style/Widget.Material3.Button.TextButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingHorizontal="30dp"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:paddingVertical="10dp"
|
||||||
|
android:text="@string/resume"
|
||||||
|
android:textStyle="bold"/>
|
||||||
|
|
||||||
</LinearLayout>
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/download_recyclerview"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
android:scrollbars="none"
|
||||||
|
app:layout_constraintHorizontal_bias="0.0"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/pause_resume">
|
||||||
|
</androidx.recyclerview.widget.RecyclerView>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<include layout="@layout/no_results"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
@ -31,23 +31,15 @@
|
||||||
|
|
||||||
<HorizontalScrollView
|
<HorizontalScrollView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content"
|
||||||
|
android:scrollbars="none">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/history_selection_chips"
|
android:id="@+id/history_selection_chips"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
<com.google.android.material.chip.Chip
|
|
||||||
android:id="@+id/sortChip"
|
|
||||||
style="@style/Widget.Material3.Chip.Assist"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/sort_by"
|
|
||||||
app:chipIcon="@drawable/ic_down" />
|
|
||||||
|
|
||||||
<View style="@style/Divider.Vertical"/>
|
|
||||||
|
|
||||||
<com.google.android.material.chip.ChipGroup
|
<com.google.android.material.chip.ChipGroup
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
app:selectionRequired="false"
|
app:selectionRequired="false"
|
||||||
|
|
@ -69,9 +61,19 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/shortcuts"
|
android:text="@string/shortcuts"
|
||||||
app:chipIcon="@drawable/ic_shortcut" />
|
app:chipIcon="@drawable/ic_shortcut" />
|
||||||
|
|
||||||
</com.google.android.material.chip.ChipGroup>
|
</com.google.android.material.chip.ChipGroup>
|
||||||
|
|
||||||
|
<View style="@style/Divider.Vertical"/>
|
||||||
|
|
||||||
|
<com.google.android.material.chip.Chip
|
||||||
|
android:id="@+id/sortChip"
|
||||||
|
style="@style/Widget.Material3.Chip.Assist"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/sort_by"
|
||||||
|
app:chipIcon="@drawable/ic_down" />
|
||||||
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</HorizontalScrollView>
|
</HorizontalScrollView>
|
||||||
|
|
@ -92,7 +94,7 @@
|
||||||
</androidx.recyclerview.widget.RecyclerView>
|
</androidx.recyclerview.widget.RecyclerView>
|
||||||
|
|
||||||
|
|
||||||
<include layout="@layout/history_no_results"
|
<include layout="@layout/no_results"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
|
|
||||||
<include layout="@layout/history_no_results"
|
<include layout="@layout/no_results"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@
|
||||||
android:paddingHorizontal="10dp"
|
android:paddingHorizontal="10dp"
|
||||||
android:paddingBottom="10dp"
|
android:paddingBottom="10dp"
|
||||||
android:hint="@string/title"
|
android:hint="@string/title"
|
||||||
app:endIconMode="custom"
|
|
||||||
style="@style/Widget.Material3.TextInputLayout.FilledBox">
|
style="@style/Widget.Material3.TextInputLayout.FilledBox">
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
|
@ -44,7 +43,6 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="40"
|
android:layout_weight="40"
|
||||||
android:hint="@string/author"
|
android:hint="@string/author"
|
||||||
app:endIconMode="custom"
|
|
||||||
style="@style/Widget.Material3.TextInputLayout.FilledBox">
|
style="@style/Widget.Material3.TextInputLayout.FilledBox">
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingHorizontal="10dp"
|
android:paddingHorizontal="10dp"
|
||||||
android:paddingTop="10dp"
|
android:paddingTop="10dp"
|
||||||
android:text="@string/command" />
|
android:text="@string/command_templates" />
|
||||||
|
|
||||||
<include layout="@layout/command_template_item" />
|
<include layout="@layout/command_template_item" />
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<include layout="@layout/history_no_results"
|
<include layout="@layout/no_results"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
<com.google.android.material.bottomappbar.BottomAppBar
|
<com.google.android.material.bottomappbar.BottomAppBar
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@
|
||||||
</androidx.recyclerview.widget.RecyclerView>
|
</androidx.recyclerview.widget.RecyclerView>
|
||||||
|
|
||||||
|
|
||||||
<include layout="@layout/history_no_results"
|
<include layout="@layout/no_results"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@
|
||||||
app:navigationIcon="@drawable/ic_back"
|
app:navigationIcon="@drawable/ic_back"
|
||||||
android:layout_height="match_parent"/>
|
android:layout_height="match_parent"/>
|
||||||
|
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
|
@ -36,7 +35,8 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="10dp"
|
android:layout_margin="10dp"
|
||||||
android:backgroundTint="@android:color/transparent"
|
android:backgroundTint="@android:color/transparent"
|
||||||
app:tabGravity="fill"
|
app:tabGravity="start"
|
||||||
|
app:tabMinWidth="0dp"
|
||||||
app:tabMode="scrollable" />
|
app:tabMode="scrollable" />
|
||||||
|
|
||||||
<androidx.viewpager2.widget.ViewPager2
|
<androidx.viewpager2.widget.ViewPager2
|
||||||
|
|
@ -44,7 +44,8 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent" />
|
android:layout_height="match_parent" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
<include layout="@layout/history_no_results"
|
|
||||||
|
<include layout="@layout/no_results"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -118,7 +118,7 @@
|
||||||
|
|
||||||
</androidx.recyclerview.widget.RecyclerView>
|
</androidx.recyclerview.widget.RecyclerView>
|
||||||
|
|
||||||
<include layout="@layout/history_no_results"
|
<include layout="@layout/no_results"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,36 +1,46 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<TextView
|
<LinearLayout
|
||||||
android:id="@+id/filesize"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingHorizontal="30dp"
|
|
||||||
android:paddingVertical="10dp"
|
|
||||||
android:visibility="gone"
|
|
||||||
android:text="@string/file_size"
|
|
||||||
android:textStyle="bold"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintHorizontal_bias="0.0"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:id="@+id/download_recyclerview"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:scrollbars="none"
|
android:orientation="vertical">
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintHorizontal_bias="0.0"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/filesize">
|
|
||||||
|
|
||||||
</androidx.recyclerview.widget.RecyclerView>
|
<TextView
|
||||||
|
android:id="@+id/filesize"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingHorizontal="30dp"
|
||||||
|
android:paddingVertical="10dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:text="@string/file_size"
|
||||||
|
android:textStyle="bold"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0.0"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
</LinearLayout>
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/download_recyclerview"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:scrollbars="none"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0.0"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/filesize">
|
||||||
|
|
||||||
|
</androidx.recyclerview.widget.RecyclerView>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<include layout="@layout/no_results"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
</androidx.recyclerview.widget.RecyclerView>
|
</androidx.recyclerview.widget.RecyclerView>
|
||||||
|
|
||||||
<include layout="@layout/history_no_results"
|
<include layout="@layout/no_results"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
19
app/src/main/res/layout/generic_list.xml
Normal file
19
app/src/main/res/layout/generic_list.xml
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView android:id="@+id/download_recyclerview"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:scrollbars="none">
|
||||||
|
|
||||||
|
</androidx.recyclerview.widget.RecyclerView>
|
||||||
|
|
||||||
|
<include layout="@layout/no_results"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<androidx.recyclerview.widget.RecyclerView android:id="@+id/download_recyclerview"
|
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:scrollbars="none"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
|
|
||||||
</androidx.recyclerview.widget.RecyclerView>
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue