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>
|
||||
|
||||
<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
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
</h1>
|
||||
|
||||
<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
|
||||
</div>
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
</h1>
|
||||
|
||||
<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
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
</h1>
|
||||
|
||||
<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
|
||||
</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-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>
|
||||
</div>
|
||||
|
|
@ -34,7 +34,7 @@
|
|||
[](https://t.me/ytdlnisupdates)
|
||||
|
||||
|
||||
|
||||
### The links above are the only trusted sources of YTDLnis. Everything else is not related to me.
|
||||
|
||||
</div>
|
||||
|
||||
|
|
@ -10,7 +10,7 @@ def properties = new Properties()
|
|||
def versionMajor = 1
|
||||
def versionMinor = 6
|
||||
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 = ""
|
||||
|
||||
if (versionBuild > 0){
|
||||
|
|
@ -188,5 +188,6 @@ dependencies {
|
|||
implementation "com.anggrayudi:storage:1.5.5"
|
||||
implementation 'me.zhanghai.android.fastscroll:library:1.3.0'
|
||||
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
|
||||
android:name=".MainActivity"
|
||||
android:configChanges="smallestScreenSize|layoutDirection|locale|orientation|screenSize"
|
||||
android:configChanges="locale"
|
||||
android:exported="true"
|
||||
android:windowSoftInputMode="adjustPan">
|
||||
|
||||
|
|
@ -53,7 +53,6 @@
|
|||
android:configChanges="smallestScreenSize|layoutDirection|locale|orientation|screenSize"
|
||||
android:excludeFromRecents="true"
|
||||
android:exported="true"
|
||||
android:launchMode="singleInstance"
|
||||
android:theme="@style/Theme.BottomSheet">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
|
|
@ -125,7 +124,7 @@
|
|||
android:enabled="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:configChanges="smallestScreenSize|layoutDirection|locale|orientation|screenSize"
|
||||
android:configChanges="locale"
|
||||
android:targetActivity=".MainActivity"
|
||||
android:windowSoftInputMode="adjustPan"
|
||||
android:exported="true">
|
||||
|
|
@ -147,7 +146,7 @@
|
|||
android:exported="true"
|
||||
android:icon="@mipmap/ic_launcher_dark"
|
||||
android:roundIcon="@mipmap/ic_launcher_round_dark"
|
||||
android:configChanges="smallestScreenSize|layoutDirection|locale|orientation|screenSize"
|
||||
android:configChanges="locale"
|
||||
android:targetActivity=".MainActivity"
|
||||
android:windowSoftInputMode="adjustPan">
|
||||
<intent-filter>
|
||||
|
|
@ -167,7 +166,7 @@
|
|||
android:exported="true"
|
||||
android:icon="@mipmap/ic_launcher_light"
|
||||
android:roundIcon="@mipmap/ic_launcher_round_light"
|
||||
android:configChanges="smallestScreenSize|layoutDirection|locale|orientation|screenSize"
|
||||
android:configChanges="locale"
|
||||
android:targetActivity=".MainActivity"
|
||||
android:windowSoftInputMode="adjustPan">
|
||||
<intent-filter>
|
||||
|
|
@ -183,7 +182,7 @@
|
|||
|
||||
<activity
|
||||
android:name=".ui.more.WebViewActivity"
|
||||
android:configChanges="smallestScreenSize|layoutDirection|locale|orientation|screenSize"
|
||||
android:configChanges="locale"
|
||||
android:exported="true"
|
||||
android:parentActivityName=".MainActivity"
|
||||
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.util.FileUtil
|
||||
import com.deniscerri.ytdlnis.util.ThemeUtil
|
||||
import com.deniscerri.ytdlnis.util.UiUtil
|
||||
import com.deniscerri.ytdlnis.util.UpdateUtil
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
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.NavigationView
|
||||
import com.google.android.material.navigationrail.NavigationRailView
|
||||
|
|
@ -65,7 +63,6 @@ import java.io.BufferedReader
|
|||
import java.io.File
|
||||
import java.io.InputStreamReader
|
||||
import java.io.Reader
|
||||
import java.net.URI
|
||||
import java.nio.charset.Charset
|
||||
import java.nio.charset.StandardCharsets
|
||||
import kotlin.system.exitProcess
|
||||
|
|
@ -81,7 +78,6 @@ class MainActivity : BaseActivity() {
|
|||
private lateinit var navigationView: View
|
||||
private lateinit var navHostFragment : NavHostFragment
|
||||
private lateinit var navController : NavController
|
||||
private lateinit var sharedPreferences: SharedPreferences
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
|
@ -93,9 +89,7 @@ class MainActivity : BaseActivity() {
|
|||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
preferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
if (preferences.getBoolean("incognito", false)){
|
||||
resultViewModel.deleteAll()
|
||||
}
|
||||
if (preferences.getBoolean("incognito", false)) resultViewModel.deleteAll()
|
||||
|
||||
askPermissions()
|
||||
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)
|
||||
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
|
||||
}
|
||||
|
||||
navController.graph = graph
|
||||
|
||||
if (navigationView is NavigationBarView){
|
||||
(navigationView as NavigationBarView).setupWithNavController(navController)
|
||||
(navigationView as NavigationBarView).setOnItemReselectedListener {
|
||||
|
|
@ -164,7 +158,7 @@ class MainActivity : BaseActivity() {
|
|||
(navigationView as NavigationView).setupWithNavController(navController)
|
||||
//terminate button
|
||||
(navigationView as NavigationView).menu.getItem(7).setOnMenuItemClickListener {
|
||||
if (sharedPreferences.getBoolean("ask_terminate_app", true)){
|
||||
if (preferences.getBoolean("ask_terminate_app", true)){
|
||||
var doNotShowAgain = false
|
||||
val terminateDialog = MaterialAlertDialogBuilder(this)
|
||||
terminateDialog.setTitle(getString(R.string.confirm_delete_history))
|
||||
|
|
@ -188,7 +182,7 @@ class MainActivity : BaseActivity() {
|
|||
runBlocking {
|
||||
job.join()
|
||||
if (doNotShowAgain){
|
||||
sharedPreferences.edit().putBoolean("ask_terminate_app", false).apply()
|
||||
preferences.edit().putBoolean("ask_terminate_app", false).apply()
|
||||
}
|
||||
finishAndRemoveTask()
|
||||
finishAffinity()
|
||||
|
|
@ -212,9 +206,6 @@ class MainActivity : BaseActivity() {
|
|||
|
||||
(navigationView as NavigationView).getHeaderView(0).findViewById<TextView>(R.id.title).text = ThemeUtil.getStyledAppName(this)
|
||||
}
|
||||
cookieViewModel.updateCookiesFile()
|
||||
val intent = intent
|
||||
handleIntents(intent)
|
||||
|
||||
navController.addOnDestinationChangedListener { _, destination, _ ->
|
||||
if (navigationView is NavigationBarView){
|
||||
|
|
@ -233,12 +224,15 @@ class MainActivity : BaseActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
when(sharedPreferences.getString("start_destination", "")) {
|
||||
"Queue" -> navController.navigate(R.id.downloadQueueMainFragment)
|
||||
when(preferences.getString("start_destination", "")) {
|
||||
"Queue" -> if (savedInstanceState == null) 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) {
|
||||
if(DBManager.getInstance(this@MainActivity).downloadDao.getDownloadsCountByStatus(listOf("Active", "Queued")) == 0){
|
||||
if (UpdateUtil(this@MainActivity).updateYoutubeDL() == YoutubeDL.UpdateStatus.DONE) {
|
||||
|
|
@ -251,8 +245,8 @@ class MainActivity : BaseActivity() {
|
|||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
override fun onSaveInstanceState(savedInstanceState: Bundle) {
|
||||
super.onSaveInstanceState(savedInstanceState)
|
||||
savedInstanceState.putBundle("nav_state", navController.saveState())
|
||||
|
|
@ -489,10 +483,6 @@ class MainActivity : BaseActivity() {
|
|||
}
|
||||
dialog.show()
|
||||
}
|
||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||
startActivity(Intent(this, MainActivity::class.java))
|
||||
super.onConfigurationChanged(newConfig)
|
||||
}
|
||||
|
||||
companion object {
|
||||
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.viewmodel.DownloadViewModel
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -1,14 +1,9 @@
|
|||
package com.deniscerri.ytdlnis.database
|
||||
|
||||
import android.content.Context
|
||||
import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import androidx.paging.PagingData
|
||||
import androidx.paging.PagingSource
|
||||
import androidx.room.*
|
||||
import com.deniscerri.ytdlnis.database.dao.*
|
||||
import com.deniscerri.ytdlnis.database.models.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@TypeConverters(Converters::class)
|
||||
@Database(
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package com.deniscerri.ytdlnis.database.dao
|
|||
|
||||
import androidx.room.*
|
||||
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
||||
import com.deniscerri.ytdlnis.database.models.HistoryItem
|
||||
import com.deniscerri.ytdlnis.database.models.TemplateShortcut
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
|
|
@ -48,10 +47,13 @@ interface CommandTemplateDao {
|
|||
fun getTotalShortcutNumber() : Int
|
||||
|
||||
@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")
|
||||
fun getFirst() : CommandTemplate
|
||||
fun getFirst() : CommandTemplate?
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
suspend fun insert(item: CommandTemplate)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.deniscerri.ytdlnis.database.dao
|
||||
|
||||
import androidx.room.*
|
||||
import com.deniscerri.ytdlnis.database.models.CookieItem
|
||||
import com.deniscerri.ytdlnis.database.models.LogItem
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,6 @@
|
|||
package com.deniscerri.ytdlnis.database.dao
|
||||
|
||||
import androidx.paging.PagingSource
|
||||
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 kotlinx.coroutines.flow.Flow
|
||||
|
||||
|
|
@ -34,11 +30,12 @@ interface TerminalDao {
|
|||
val log = t.log ?: ""
|
||||
val lines = log.split("\n")
|
||||
//clean dublicate progress + add newline
|
||||
val l = if (listOf(line, lines.last()).all { it.contains("[download")}){
|
||||
lines.dropLast(1).joinToString("\n")
|
||||
}else{
|
||||
log
|
||||
} + "\n${line}"
|
||||
var newLine = line
|
||||
if (newLine.contains("[download")){
|
||||
newLine = "[download]" + line.split("[download]").last()
|
||||
}
|
||||
|
||||
val l = lines.dropLastWhile { it.contains("[download") }.joinToString("\n") + "\n${newLine}"
|
||||
|
||||
updateTerminalLog(l, id)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package com.deniscerri.ytdlnis.database.models
|
|||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
|
||||
@Entity(tableName = "downloads")
|
||||
data class DownloadItemSimple(
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ package com.deniscerri.ytdlnis.database.models
|
|||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class GithubRelease(
|
||||
@SerializedName(value = "html_url")
|
||||
val html_url: String,
|
||||
@SerializedName(value = "tag_name")
|
||||
var tag_name: String,
|
||||
@SerializedName(value = "body")
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package com.deniscerri.ytdlnis.database.models
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package com.deniscerri.ytdlnis.database.models
|
|||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
|
||||
@Entity(tableName = "terminalDownloads")
|
||||
data class TerminalItem(
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
package com.deniscerri.ytdlnis.database.repository
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import com.deniscerri.ytdlnis.database.DBManager
|
||||
import com.deniscerri.ytdlnis.database.dao.CommandTemplateDao
|
||||
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
||||
import com.deniscerri.ytdlnis.database.models.HistoryItem
|
||||
import com.deniscerri.ytdlnis.database.models.TemplateShortcut
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
|
|
@ -37,7 +35,7 @@ class CommandTemplateRepository(private val commandDao: CommandTemplateDao) {
|
|||
}
|
||||
|
||||
fun getItem(id: Long) : CommandTemplate {
|
||||
return commandDao.getTemplate(id)
|
||||
return commandDao.getTemplate(id)!!
|
||||
}
|
||||
|
||||
suspend fun insert(item: CommandTemplate){
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package com.deniscerri.ytdlnis.database.repository
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import com.deniscerri.ytdlnis.database.dao.CookieDao
|
||||
import com.deniscerri.ytdlnis.database.models.CookieItem
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.deniscerri.ytdlnis.database.repository
|
||||
|
||||
import com.deniscerri.ytdlnis.database.dao.LogDao
|
||||
import com.deniscerri.ytdlnis.database.models.CookieItem
|
||||
import com.deniscerri.ytdlnis.database.models.LogItem
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
|
|
@ -16,6 +15,10 @@ class LogRepository(private val logDao: LogDao) {
|
|||
return logDao.getLogFlowByID(id)
|
||||
}
|
||||
|
||||
fun getLogByID(id: Long) : LogItem? {
|
||||
return logDao.getByID(id)
|
||||
}
|
||||
|
||||
|
||||
suspend fun insert(item: LogItem) : Long{
|
||||
return logDao.insert(item)
|
||||
|
|
@ -31,13 +34,17 @@ class LogRepository(private val logDao: LogDao) {
|
|||
}
|
||||
|
||||
fun getItem(id: Long) : LogItem{
|
||||
return logDao.getByID(id);
|
||||
return logDao.getByID(id)
|
||||
}
|
||||
|
||||
suspend fun update(newLine: String, id: Long){
|
||||
val item = getItem(id)
|
||||
item.content += "${newLine}\n"
|
||||
logDao.update(item)
|
||||
suspend fun update(line: String, id: Long){
|
||||
runCatching {
|
||||
val item = getItem(id)
|
||||
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
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import com.deniscerri.ytdlnis.database.dao.ResultDao
|
||||
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||
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.models.CommandTemplate
|
||||
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.repository.CommandTemplateRepository
|
||||
import com.deniscerri.ytdlnis.database.repository.HistoryRepository
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
|
@ -28,8 +26,9 @@ class CommandTemplateViewModel(private val application: Application) : AndroidVi
|
|||
val sortOrder = MutableLiveData(DBManager.SORTING.DESC)
|
||||
val sortType = MutableLiveData(CommandTemplateRepository.CommandTemplateSortType.DATE)
|
||||
private val queryFilter = MutableLiveData("")
|
||||
private var _items = MediatorLiveData<List<CommandTemplate>>()
|
||||
|
||||
val allItems: LiveData<List<CommandTemplate>>
|
||||
private var _items = MediatorLiveData<List<CommandTemplate>>()
|
||||
|
||||
val shortcuts : LiveData<List<TemplateShortcut>>
|
||||
private val jsonFormat = Json { prettyPrint = true }
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import android.content.ClipboardManager
|
|||
import android.content.Context
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import android.database.sqlite.SQLiteDatabase.OPEN_READONLY
|
||||
import android.os.Environment
|
||||
import android.util.Log
|
||||
import android.webkit.CookieManager
|
||||
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.repository.CookieRepository
|
||||
import com.deniscerri.ytdlnis.ui.more.WebViewActivity
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
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.Resources
|
||||
import android.net.ConnectivityManager
|
||||
import android.os.Bundle
|
||||
import android.os.Looper
|
||||
import android.util.DisplayMetrics
|
||||
import android.widget.Toast
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.paging.PagingData
|
||||
|
|
@ -29,7 +27,6 @@ import com.deniscerri.ytdlnis.R
|
|||
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.HistoryDao
|
||||
import com.deniscerri.ytdlnis.database.dao.ResultDao
|
||||
import com.deniscerri.ytdlnis.database.models.AudioPreferences
|
||||
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
||||
|
|
@ -272,7 +269,10 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
}
|
||||
|
||||
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(
|
||||
|
|
@ -465,7 +465,12 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
)
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
@ -474,7 +479,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
fun generateCommandFormat(c: CommandTemplate) : Format {
|
||||
return Format(
|
||||
c.title,
|
||||
"",
|
||||
c.id.toString(),
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
|
|
@ -486,7 +491,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
|
||||
|
||||
fun getLatestCommandTemplateAsFormat() : Format {
|
||||
val t = commandTemplateDao.getFirst()
|
||||
val t = commandTemplateDao.getFirst()!!
|
||||
return Format(t.title, "", "", "", "", 0, t.content)
|
||||
}
|
||||
|
||||
|
|
@ -591,7 +596,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application
|
|||
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 alarmScheduler = AlarmScheduler(context)
|
||||
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.DBManager.SORTING
|
||||
import com.deniscerri.ytdlnis.database.repository.HistoryRepository.HistorySortType
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
|
@ -23,6 +22,7 @@ class HistoryViewModel(application: Application) : AndroidViewModel(application)
|
|||
val websiteFilter = MutableLiveData("")
|
||||
private val queryFilter = MutableLiveData("")
|
||||
private val formatFilter = MutableLiveData("")
|
||||
|
||||
val allItems : LiveData<List<HistoryItem>>
|
||||
private var _items = MediatorLiveData<List<HistoryItem>>()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.deniscerri.ytdlnis.database.viewmodel
|
||||
|
||||
import android.app.Application
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.LiveData
|
||||
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.LogRepository
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class LogViewModel(private val application: Application) : AndroidViewModel(application) {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import android.util.Log
|
|||
import android.util.Patterns
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
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.repository.ResultRepository
|
||||
import com.deniscerri.ytdlnis.database.repository.SearchHistoryRepository
|
||||
import com.deniscerri.ytdlnis.util.UiUtil
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
|
|
|||
|
|
@ -1,62 +1,21 @@
|
|||
package com.deniscerri.ytdlnis.database.viewmodel
|
||||
|
||||
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.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.ExistingWorkPolicy
|
||||
import androidx.work.NetworkType
|
||||
import androidx.work.OneTimeWorkRequestBuilder
|
||||
import androidx.work.WorkInfo
|
||||
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.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.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.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.work.AlarmScheduler
|
||||
import com.deniscerri.ytdlnis.work.DownloadWorker
|
||||
import com.deniscerri.ytdlnis.work.TerminalDownloadWorker
|
||||
import com.google.gson.Gson
|
||||
import com.yausername.youtubedl_android.YoutubeDL
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
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) {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package com.deniscerri.ytdlnis.receiver
|
|||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.deniscerri.ytdlnis.database.DBManager
|
||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||
|
|
@ -13,9 +12,7 @@ import com.yausername.youtubedl_android.YoutubeDL
|
|||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Calendar
|
||||
import java.util.Locale
|
||||
|
||||
class AlarmStopReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(p0: Context?, p1: Intent?) {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import android.content.BroadcastReceiver
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import androidx.work.WorkManager
|
||||
import com.deniscerri.ytdlnis.database.DBManager
|
||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
||||
|
|
@ -12,7 +11,6 @@ import com.yausername.youtubedl_android.YoutubeDL
|
|||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
class CancelDownloadNotificationReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(c: Context, intent: Intent) {
|
||||
|
|
|
|||
|
|
@ -3,16 +3,7 @@ package com.deniscerri.ytdlnis.receiver
|
|||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
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() {
|
||||
override fun onReceive(c: Context, intent: Intent) {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package com.deniscerri.ytdlnis.receiver
|
|||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import com.deniscerri.ytdlnis.database.DBManager
|
||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
||||
|
|
|
|||
|
|
@ -4,9 +4,11 @@ import android.content.Context
|
|||
import android.graphics.drawable.ColorDrawable
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.WindowManager
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowCompat
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.ui.BaseActivity
|
||||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
||||
import com.deniscerri.ytdlnis.util.ThemeUtil
|
||||
|
|
@ -36,10 +38,13 @@ class ShareFileActivity : BaseActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
setContentView(R.layout.activity_share)
|
||||
|
||||
val paths = intent.getStringArrayExtra("path")
|
||||
val notificationId = intent.getIntExtra("notificationID", 0)
|
||||
NotificationUtil(this).cancelDownloadNotification(notificationId)
|
||||
UiUtil.shareFileIntent(this, paths!!.toList())
|
||||
Log.e("SHAREE", paths.toString())
|
||||
UiUtil.shareFileIntent(this, paths!!.toList().filter { it.isNotBlank() }.distinct())
|
||||
finishAffinity()
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ import android.os.Handler
|
|||
import android.os.Looper
|
||||
import android.text.Editable
|
||||
import android.util.Log
|
||||
import android.util.Patterns
|
||||
import android.view.*
|
||||
import android.view.View.*
|
||||
import android.widget.*
|
||||
|
|
@ -30,7 +31,7 @@ import androidx.recyclerview.widget.GridLayoutManager
|
|||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.deniscerri.ytdlnis.MainActivity
|
||||
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.ResultItem
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
|
|
@ -227,7 +228,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, OnClickListene
|
|||
launch{
|
||||
resultViewModel.uiState.collectLatest { res ->
|
||||
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) }
|
||||
}
|
||||
|
||||
|
|
@ -557,7 +558,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, OnClickListene
|
|||
lifecycleScope.launch(Dispatchers.IO){
|
||||
Thread.sleep(300)
|
||||
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)) {
|
||||
showSingleDownloadSheet(
|
||||
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.content.SharedPreferences
|
||||
import android.graphics.Color
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
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.chip.Chip
|
||||
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 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 activity: Activity
|
||||
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.content.SharedPreferences
|
||||
|
|
@ -19,18 +19,16 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.google.android.material.button.MaterialButton
|
||||
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.shape.CornerFamily
|
||||
import com.google.android.material.shape.ShapeAppearanceModel
|
||||
import com.squareup.picasso.Picasso
|
||||
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 activity: Activity
|
||||
private val sharedPreferences: SharedPreferences
|
||||
|
|
@ -132,13 +130,15 @@ class ActiveDownloadMinifiedAdapter(onItemClickListener: OnItemClickListener, ac
|
|||
|
||||
pauseButton.setOnClickListener {
|
||||
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)
|
||||
if (progressBar.progress == 0) progressBar.isIndeterminate = false
|
||||
cancelButton.visibility = View.VISIBLE
|
||||
pauseButton.tag = ActiveDownloadAdapter.ActiveDownloadAction.Resume
|
||||
}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)
|
||||
progressBar.isIndeterminate = true
|
||||
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.content.SharedPreferences
|
||||
|
|
@ -24,7 +24,9 @@ import com.google.android.material.button.MaterialButton
|
|||
import com.squareup.picasso.Picasso
|
||||
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 activity: Activity
|
||||
private val sharedPreferences : SharedPreferences
|
||||
|
|
@ -35,7 +37,7 @@ class ConfigureMultipleDownloadsAdapter(onItemClickListener: OnItemClickListener
|
|||
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(activity)
|
||||
}
|
||||
|
||||
class ViewHolder(itemView: View, onItemClickListener: OnItemClickListener?) : RecyclerView.ViewHolder(itemView) {
|
||||
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
val cardView: FrameLayout
|
||||
|
||||
init {
|
||||
|
|
@ -46,7 +48,7 @@ class ConfigureMultipleDownloadsAdapter(onItemClickListener: OnItemClickListener
|
|||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val cardView = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.download_card, parent, false)
|
||||
return ViewHolder(cardView, onItemClickListener)
|
||||
return ViewHolder(cardView)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
|
|
@ -136,11 +138,16 @@ class ConfigureMultipleDownloadsAdapter(onItemClickListener: OnItemClickListener
|
|||
card.setOnClickListener {
|
||||
onItemClickListener.onCardClick(item.url)
|
||||
}
|
||||
|
||||
card.setOnLongClickListener {
|
||||
onItemClickListener.onDelete(item.url); true
|
||||
}
|
||||
}
|
||||
|
||||
interface OnItemClickListener {
|
||||
fun onButtonClick(itemURL: String)
|
||||
fun onCardClick(itemURL: String)
|
||||
fun onDelete(itemURL: String)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
@ -1,11 +1,10 @@
|
|||
package com.deniscerri.ytdlnis.adapter
|
||||
package com.deniscerri.ytdlnis.ui.adapter
|
||||
|
||||
import android.app.Activity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.recyclerview.widget.AsyncDifferConfig
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
|
|
@ -14,7 +13,9 @@ import com.deniscerri.ytdlnis.R
|
|||
import com.deniscerri.ytdlnis.database.models.CookieItem
|
||||
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 activity: Activity
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.deniscerri.ytdlnis.adapter
|
||||
package com.deniscerri.ytdlnis.ui.adapter
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
|
|
@ -6,25 +6,23 @@ import android.text.format.DateFormat
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Button
|
||||
import android.widget.TextView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.recyclerview.widget.AsyncDifferConfig
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.models.LogItem
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
import java.io.File
|
||||
import java.text.SimpleDateFormat
|
||||
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 activity: Activity
|
||||
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.app.Activity
|
||||
|
|
@ -10,13 +10,11 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.paging.PagingDataAdapter
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItemSimple
|
||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||
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.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 activity: Activity
|
||||
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.app.Activity
|
||||
|
|
@ -24,13 +24,16 @@ import com.deniscerri.ytdlnis.database.models.HistoryItem
|
|||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
import com.squareup.picasso.Picasso
|
||||
import java.io.File
|
||||
import java.text.SimpleDateFormat
|
||||
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 onItemClickListener: OnItemClickListener
|
||||
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)
|
||||
|
||||
// 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
|
||||
|
||||
//IS IN THE FILE SYSTEM?
|
||||
|
|
@ -121,11 +124,11 @@ class HistoryAdapter(onItemClickListener: OnItemClickListener, activity: Activit
|
|||
thumbnail.alpha = 0.7f
|
||||
}
|
||||
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) {
|
||||
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{
|
||||
btn.icon = ContextCompat.getDrawable(activity, R.drawable.ic_terminal)
|
||||
btn.setImageResource(R.drawable.ic_terminal)
|
||||
}
|
||||
if (btn.hasOnClickListeners()) btn.setOnClickListener(null)
|
||||
btn.isClickable = filePresent
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.deniscerri.ytdlnis.adapter
|
||||
package com.deniscerri.ytdlnis.ui.adapter
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.SharedPreferences
|
||||
|
|
@ -9,9 +9,7 @@ import android.view.LayoutInflater
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.AsyncDifferConfig
|
||||
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.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 onItemClickListener: OnItemClickListener
|
||||
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.app.Activity
|
||||
|
|
@ -21,11 +21,12 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||
import com.squareup.picasso.Picasso
|
||||
import org.w3c.dom.Text
|
||||
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 onItemClickListener: OnItemClickListener
|
||||
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.opengl.Visibility
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.recyclerview.widget.AsyncDifferConfig
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
||||
import com.deniscerri.ytdlnis.database.models.LogItem
|
||||
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 activity: Activity
|
||||
private val checkedItems: ArrayList<Long> = ArrayList()
|
||||
|
||||
init {
|
||||
this.onItemClickListener = onItemClickListener
|
||||
|
|
@ -52,19 +55,74 @@ class TemplatesAdapter(onItemClickListener: OnItemClickListener, activity: Activ
|
|||
if (item!!.useAsExtraCommand) useInExtraCommands.visibility = View.VISIBLE
|
||||
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 {
|
||||
onItemClickListener.onItemClick(item, position)
|
||||
if (checkedItems.size > 0) {
|
||||
checkCard(card, item.id)
|
||||
} else {
|
||||
onItemClickListener.onItemClick(item, position)
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
fun onItemClick(commandTemplate: CommandTemplate, index: Int)
|
||||
fun onSelected(commandTemplate: CommandTemplate)
|
||||
fun onDelete(commandTemplate: CommandTemplate)
|
||||
fun onCardSelect(itemID: Long, isChecked: Boolean)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.deniscerri.ytdlnis.adapter
|
||||
package com.deniscerri.ytdlnis.ui.adapter
|
||||
|
||||
import android.app.Activity
|
||||
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.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 activity: Activity
|
||||
private val sharedPreferences: SharedPreferences
|
||||
|
|
@ -4,11 +4,8 @@ import android.annotation.SuppressLint
|
|||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import android.util.DisplayMetrics
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
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.UiUtil
|
||||
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.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.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.*
|
||||
import java.util.regex.Pattern
|
||||
|
||||
|
||||
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.Toast
|
||||
import androidx.core.content.edit
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
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)
|
||||
link.text = result.url
|
||||
link.setOnClickListener{
|
||||
UiUtil.openLinkIntent(requireContext(), result.url, null)
|
||||
UiUtil.openLinkIntent(requireContext(), result.url)
|
||||
}
|
||||
link.setOnLongClickListener{
|
||||
UiUtil.copyLinkToClipBoard(requireContext(), result.url, null)
|
||||
UiUtil.copyLinkToClipBoard(requireContext(), result.url)
|
||||
true
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package com.deniscerri.ytdlnis.ui.downloadcard
|
|||
import android.annotation.SuppressLint
|
||||
import android.app.Dialog
|
||||
import android.content.DialogInterface
|
||||
import android.content.SharedPreferences
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Color
|
||||
import android.net.Uri
|
||||
|
|
|
|||
|
|
@ -14,15 +14,14 @@ import android.widget.ArrayAdapter
|
|||
import android.widget.AutoCompleteTextView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.core.view.isEmpty
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.afollestad.materialdialogs.utils.MDUtil.getStringArray
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
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.google.android.material.card.MaterialCardView
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import com.google.android.material.textfield.TextInputLayout.END_ICON_NONE
|
||||
import com.google.gson.Gson
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -69,7 +69,7 @@ class DownloadAudioFragment(private var resultItem: ResultItem? = null, private
|
|||
infoUtil = InfoUtil(requireContext())
|
||||
genericAudioFormats = infoUtil.getGenericAudioFormats(requireContext().resources)
|
||||
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
|
||||
}
|
||||
|
||||
|
|
@ -92,6 +92,7 @@ class DownloadAudioFragment(private var resultItem: ResultItem? = null, private
|
|||
title.visibility = if (shownFields.contains("title")) View.VISIBLE else View.GONE
|
||||
if (title.editText?.text?.isEmpty() == true){
|
||||
title.editText!!.setText(downloadItem.title)
|
||||
title.endIconMode = END_ICON_NONE
|
||||
}
|
||||
title.editText!!.addTextChangedListener(object : TextWatcher {
|
||||
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()
|
||||
}
|
||||
})
|
||||
title.setEndIconOnClickListener {
|
||||
if (resultItem != null){
|
||||
title.editText?.setText(resultItem?.title)
|
||||
}
|
||||
title.endIconDrawable = null
|
||||
}
|
||||
|
||||
author = view.findViewById(R.id.author_textinput)
|
||||
author.visibility = if (shownFields.contains("author")) View.VISIBLE else View.GONE
|
||||
if (author.editText?.text?.isEmpty() == true){
|
||||
author.editText!!.setText(downloadItem.author)
|
||||
author.endIconMode = END_ICON_NONE
|
||||
}
|
||||
author.editText!!.addTextChangedListener(object : TextWatcher {
|
||||
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()
|
||||
}
|
||||
})
|
||||
author.setEndIconOnClickListener {
|
||||
if (resultItem != null){
|
||||
author.editText?.setText(resultItem?.author)
|
||||
}
|
||||
author.endIconDrawable = null
|
||||
}
|
||||
|
||||
if (savedInstanceState?.containsKey("updated") == true){
|
||||
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)
|
||||
downloadItem.title = title.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)
|
||||
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.editText!!.setText(
|
||||
|
|
@ -295,9 +301,9 @@ class DownloadAudioFragment(private var resultItem: ResultItem? = null, private
|
|||
downloadItem.title = t
|
||||
downloadItem.author = a
|
||||
title.editText?.setText(t)
|
||||
title.endIconDrawable = null
|
||||
title.endIconMode = END_ICON_NONE
|
||||
author.editText?.setText(a)
|
||||
title.endIconDrawable = null
|
||||
author.endIconMode = END_ICON_NONE
|
||||
}
|
||||
|
||||
override fun updateUI(res: ResultItem?){
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import androidx.lifecycle.lifecycleScope
|
|||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import com.afollestad.materialdialogs.utils.MDUtil.getStringArray
|
||||
import com.deniscerri.ytdlnis.MainActivity
|
||||
import com.deniscerri.ytdlnis.R
|
||||
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.viewmodel.DownloadViewModel
|
||||
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.receiver.ShareActivity
|
||||
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 kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.update
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
|
|
@ -53,16 +56,19 @@ class DownloadBottomSheetDialog(private var result: ResultItem, private val type
|
|||
private lateinit var viewPager2: ViewPager2
|
||||
private lateinit var fragmentAdapter : DownloadFragmentAdapter
|
||||
private lateinit var downloadViewModel: DownloadViewModel
|
||||
private lateinit var historyViewModel: HistoryViewModel
|
||||
private lateinit var resultViewModel: ResultViewModel
|
||||
private lateinit var behavior: BottomSheetBehavior<View>
|
||||
private lateinit var commandTemplateDao : CommandTemplateDao
|
||||
private lateinit var infoUtil: InfoUtil
|
||||
private lateinit var sharedPreferences : SharedPreferences
|
||||
private lateinit var updateItem : Button
|
||||
private lateinit var view: View
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
historyViewModel = ViewModelProvider(this)[HistoryViewModel::class.java]
|
||||
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
|
||||
commandTemplateDao = DBManager.getInstance(requireContext()).commandTemplateDao
|
||||
infoUtil = InfoUtil(requireContext())
|
||||
|
|
@ -87,6 +93,7 @@ class DownloadBottomSheetDialog(private var result: ResultItem, private val type
|
|||
|
||||
tabLayout = view.findViewById(R.id.download_tablayout)
|
||||
viewPager2 = view.findViewById(R.id.download_viewpager)
|
||||
updateItem = view.findViewById(R.id.update_item)
|
||||
|
||||
(viewPager2.getChildAt(0) as? RecyclerView)?.apply {
|
||||
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)?.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
|
||||
fragmentAdapter = DownloadFragmentAdapter(
|
||||
|
|
@ -200,8 +211,10 @@ class DownloadBottomSheetDialog(private var result: ResultItem, private val type
|
|||
|
||||
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)
|
||||
scheduleBtn.visibility = if(sharedPreferences.getStringSet("modify_download_card", setOf())!!.contains("schedule")){
|
||||
scheduleBtn.visibility = if(shownFields.contains("schedule")){
|
||||
View.VISIBLE
|
||||
}else{
|
||||
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)
|
||||
link.visibility = if(sharedPreferences.getStringSet("modify_download_card", setOf())!!.contains("url")){
|
||||
link.visibility = if(shownFields.contains("url")){
|
||||
View.VISIBLE
|
||||
}else{
|
||||
View.GONE
|
||||
}
|
||||
val updateItem = view.findViewById<Button>(R.id.update_item)
|
||||
|
||||
if (Patterns.WEB_URL.matcher(result.url).matches()){
|
||||
link.text = result.url
|
||||
link.setOnClickListener{
|
||||
UiUtil.openLinkIntent(requireContext(), result.url, null)
|
||||
UiUtil.openLinkIntent(requireContext(), result.url)
|
||||
}
|
||||
link.setOnLongClickListener{
|
||||
UiUtil.copyLinkToClipBoard(requireContext(), result.url, null)
|
||||
UiUtil.copyLinkToClipBoard(requireContext(), result.url)
|
||||
true
|
||||
}
|
||||
|
||||
|
|
@ -281,12 +294,12 @@ class DownloadBottomSheetDialog(private var result: ResultItem, private val type
|
|||
|
||||
}else{
|
||||
link.visibility = View.GONE
|
||||
updateItem.visibility = View.GONE
|
||||
(updateItem.parent as LinearLayout).visibility = View.GONE
|
||||
}
|
||||
|
||||
|
||||
//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)
|
||||
}else {
|
||||
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 ->
|
||||
if (res.errorMessage != null) {
|
||||
UiUtil.handleDownloadsResponse(requireActivity() as MainActivity, res, downloadViewModel)
|
||||
UiUtil.handleDownloadsResponse(requireActivity() as MainActivity, res, downloadViewModel, historyViewModel)
|
||||
downloadViewModel.uiState.value = DownloadViewModel.DownloadsUiState(
|
||||
errorMessage = 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{
|
||||
return when(selectedTabPosition){
|
||||
|
|
@ -344,12 +368,12 @@ class DownloadBottomSheetDialog(private var result: ResultItem, private val type
|
|||
}
|
||||
|
||||
private fun initUpdateData(v: View){
|
||||
CoroutineScope(SupervisorJob()).launch(Dispatchers.IO){
|
||||
val shimmerLoading = v.findViewById<ShimmerFrameLayout>(R.id.shimmer_loading_title)
|
||||
val title = v.findViewById<View>(R.id.bottom_sheet_title)
|
||||
val shimmerLoading = v.findViewById<ShimmerFrameLayout>(R.id.shimmer_loading_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 subtitle = v.findViewById<View>(R.id.bottom_sheet_subtitle)
|
||||
val updateJob = CoroutineScope(SupervisorJob()).launch(Dispatchers.IO){
|
||||
withContext(Dispatchers.Main){
|
||||
title.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))
|
||||
if (result.isEmpty()){
|
||||
withContext(Dispatchers.Main){
|
||||
Looper.prepare().run {
|
||||
Toast.makeText(requireContext(), "No Results Found!", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
dismiss()
|
||||
}
|
||||
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){
|
||||
|
|
@ -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){
|
||||
runCatching {
|
||||
|
|
|
|||
|
|
@ -8,10 +8,8 @@ import android.content.SharedPreferences
|
|||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.util.Log
|
||||
import android.util.Patterns
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.*
|
||||
|
|
@ -23,6 +21,7 @@ import androidx.fragment.app.Fragment
|
|||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.afollestad.materialdialogs.utils.MDUtil.getStringArray
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
||||
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.viewmodel.CommandTemplateViewModel
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding
|
||||
import com.deniscerri.ytdlnis.util.FileUtil
|
||||
import com.deniscerri.ytdlnis.util.UiUtil
|
||||
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.textfield.TextInputLayout
|
||||
import com.google.gson.Gson
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.File
|
||||
|
|
@ -66,7 +66,7 @@ class DownloadCommandFragment(private val resultItem: ResultItem? = null, privat
|
|||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
commandTemplateViewModel = ViewModelProvider(this)[CommandTemplateViewModel::class.java]
|
||||
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
|
||||
}
|
||||
|
||||
|
|
@ -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()){
|
||||
downloadItem.format = downloadViewModel.generateCommandFormat(CommandTemplate(0,"txt", "-a \"${downloadItem.url}\"", false))
|
||||
downloadItem.url = ""
|
||||
|
|
@ -117,6 +119,7 @@ class DownloadCommandFragment(private val resultItem: ResultItem? = null, privat
|
|||
0,
|
||||
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)
|
||||
runCatching {
|
||||
populateCommandCard(commandTemplateCard, templates.first())
|
||||
commandTemplateCard.setOnClickListener {
|
||||
lifecycleScope.launch {
|
||||
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} ")
|
||||
}
|
||||
populateCommandCard(commandTemplateCard, it.first())
|
||||
|
||||
downloadItem.format = Format(
|
||||
it.first().title,
|
||||
"",
|
||||
|
|
@ -148,15 +151,20 @@ class DownloadCommandFragment(private val resultItem: ResultItem? = null, privat
|
|||
"",
|
||||
"",
|
||||
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()){
|
||||
view.findViewById<MaterialCardView>(R.id.command_card).alpha = 0.3f
|
||||
val existingTemplate = withContext(Dispatchers.IO){
|
||||
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 {
|
||||
commandTemplateCard.visibility = View.GONE
|
||||
|
|
@ -189,7 +197,7 @@ class DownloadCommandFragment(private val resultItem: ResultItem? = null, privat
|
|||
|
||||
|
||||
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){
|
||||
UiUtil.configureCommand(
|
||||
view,
|
||||
|
|
@ -208,6 +216,7 @@ class DownloadCommandFragment(private val resultItem: ResultItem? = null, privat
|
|||
0,
|
||||
it.content
|
||||
)
|
||||
preferences.edit().putString("lastCommandTemplateUsed", it.content).apply()
|
||||
commandTemplateCard.visibility = View.VISIBLE
|
||||
view.findViewById<TextView>(R.id.command_txt).visibility = View.VISIBLE
|
||||
view.findViewById<Chip>(R.id.editSelected).isEnabled = true
|
||||
|
|
@ -237,6 +246,7 @@ class DownloadCommandFragment(private val resultItem: ResultItem? = null, privat
|
|||
0,
|
||||
it.content
|
||||
)
|
||||
preferences.edit().putString("lastCommandTemplateUsed", it.content).apply()
|
||||
}
|
||||
},
|
||||
shortcutClicked = {
|
||||
|
|
@ -244,6 +254,7 @@ class DownloadCommandFragment(private val resultItem: ResultItem? = null, privat
|
|||
itemSelected = {
|
||||
chosenCommandView.editText!!.setText("${chosenCommandView.editText!!.text} $it")
|
||||
downloadItem.format.format_note = chosenCommandView.editText!!.text.toString()
|
||||
preferences.edit().putString("lastCommandTemplateUsed", downloadItem.format.format_note).apply()
|
||||
},
|
||||
itemRemoved = {removed ->
|
||||
chosenCommandView.editText!!.setText(chosenCommandView.editText!!.text.replace("(${
|
||||
|
|
@ -252,6 +263,8 @@ class DownloadCommandFragment(private val resultItem: ResultItem? = null, privat
|
|||
)
|
||||
})(?!.*\\1)".toRegex(), "").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 com.deniscerri.ytdlnis.MainActivity
|
||||
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.Format
|
||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.CommandTemplateViewModel
|
||||
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.receiver.ShareActivity
|
||||
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,
|
||||
ConfigureDownloadBottomSheetDialog.OnDownloadItemUpdateListener {
|
||||
private lateinit var downloadViewModel: DownloadViewModel
|
||||
private lateinit var historyViewModel: HistoryViewModel
|
||||
private lateinit var commandTemplateViewModel: CommandTemplateViewModel
|
||||
private lateinit var resultViewModel: ResultViewModel
|
||||
private lateinit var listAdapter : ConfigureMultipleDownloadsAdapter
|
||||
|
|
@ -81,6 +83,7 @@ class DownloadMultipleBottomSheetDialog(private var items: MutableList<DownloadI
|
|||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
downloadViewModel = ViewModelProvider(requireActivity())[DownloadViewModel::class.java]
|
||||
historyViewModel = ViewModelProvider(requireActivity())[HistoryViewModel::class.java]
|
||||
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
|
||||
commandTemplateViewModel = ViewModelProvider(this)[CommandTemplateViewModel::class.java]
|
||||
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
|
|
@ -472,10 +475,8 @@ class DownloadMultipleBottomSheetDialog(private var items: MutableList<DownloadI
|
|||
saveSubtitlesClicked = {checked ->
|
||||
items.forEach { it.videoPreferences.writeSubs = checked }
|
||||
},
|
||||
subtitleLanguagesClicked = {
|
||||
UiUtil.showSubtitleLanguagesDialog(requireActivity(), ""){ value ->
|
||||
items.forEach { it.videoPreferences.subsLanguages = value }
|
||||
}
|
||||
subtitleLanguagesSet = {value ->
|
||||
items.forEach { it.videoPreferences.subsLanguages = value }
|
||||
},
|
||||
removeAudioClicked = {checked ->
|
||||
items.forEach { it.videoPreferences.removeAudio = checked }
|
||||
|
|
@ -509,7 +510,7 @@ class DownloadMultipleBottomSheetDialog(private var items: MutableList<DownloadI
|
|||
lifecycleScope.launch {
|
||||
downloadViewModel.uiState.collectLatest { res ->
|
||||
if (res.errorMessage != null) {
|
||||
UiUtil.handleDownloadsResponse(requireActivity() as MainActivity, res, downloadViewModel)
|
||||
UiUtil.handleDownloadsResponse(requireActivity() as MainActivity, res, downloadViewModel, historyViewModel)
|
||||
downloadViewModel.uiState.value = DownloadViewModel.DownloadsUiState(
|
||||
errorMessage = 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?) {
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import android.content.SharedPreferences
|
|||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
|
|
@ -23,6 +22,7 @@ import androidx.fragment.app.Fragment
|
|||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.afollestad.materialdialogs.utils.MDUtil.getStringArray
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
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.google.android.material.card.MaterialCardView
|
||||
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 kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -71,7 +74,7 @@ class DownloadVideoFragment(private var resultItem: ResultItem? = null, private
|
|||
infoUtil = InfoUtil(requireContext())
|
||||
genericVideoFormats = infoUtil.getGenericVideoFormats(requireContext().resources)
|
||||
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
|
||||
}
|
||||
|
||||
|
|
@ -95,6 +98,7 @@ class DownloadVideoFragment(private var resultItem: ResultItem? = null, private
|
|||
title.visibility = if (shownFields.contains("title")) View.VISIBLE else View.GONE
|
||||
if (title.editText?.text?.isEmpty() == true){
|
||||
title.editText!!.setText(downloadItem.title)
|
||||
title.endIconMode = END_ICON_NONE
|
||||
}
|
||||
title.editText!!.addTextChangedListener(object : TextWatcher {
|
||||
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
|
||||
if (author.editText?.text?.isEmpty() == true){
|
||||
author.editText!!.setText(downloadItem.author)
|
||||
author.endIconMode = END_ICON_NONE
|
||||
}
|
||||
author.editText!!.addTextChangedListener(object : TextWatcher {
|
||||
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 (!listOf(resultItem?.title, downloadItem.title).contains(title.editText?.text.toString())){
|
||||
title.endIconMode = END_ICON_CUSTOM
|
||||
title.endIconDrawable = AppCompatResources.getDrawable(requireContext(), R.drawable.ic_refresh)
|
||||
downloadItem.title = title.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)
|
||||
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.editText!!.setText(
|
||||
FileUtil.formatPath(downloadItem.downloadPath)
|
||||
|
|
@ -282,10 +303,8 @@ class DownloadVideoFragment(private var resultItem: ResultItem? = null, private
|
|||
saveSubtitlesClicked = {
|
||||
downloadItem.videoPreferences.writeSubs = it
|
||||
},
|
||||
subtitleLanguagesClicked = {
|
||||
UiUtil.showSubtitleLanguagesDialog(requireActivity(), downloadItem.videoPreferences.subsLanguages){
|
||||
downloadItem.videoPreferences.subsLanguages = it
|
||||
}
|
||||
subtitleLanguagesSet = {
|
||||
downloadItem.videoPreferences.subsLanguages = it
|
||||
},
|
||||
removeAudioClicked = {
|
||||
downloadItem.videoPreferences.removeAudio = it
|
||||
|
|
@ -313,9 +332,9 @@ class DownloadVideoFragment(private var resultItem: ResultItem? = null, private
|
|||
downloadItem.title = t
|
||||
downloadItem.author = a
|
||||
title.editText?.setText(t)
|
||||
title.endIconDrawable = null
|
||||
title.endIconMode = END_ICON_NONE
|
||||
author.editText?.setText(a)
|
||||
title.endIconDrawable = null
|
||||
title.endIconMode = END_ICON_NONE
|
||||
}
|
||||
|
||||
override fun updateUI(res: ResultItem?) {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import android.util.DisplayMetrics
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.*
|
||||
import androidx.compose.runtime.invalidateGroupsWithKey
|
||||
import androidx.core.view.forEach
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
|
|
@ -27,7 +26,6 @@ import com.google.android.material.snackbar.Snackbar
|
|||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import okhttp3.internal.format
|
||||
import java.util.*
|
||||
|
||||
|
||||
|
|
@ -217,9 +215,9 @@ class FormatSelectionBottomSheetDialog(private val items: List<DownloadItem?>, p
|
|||
dismiss()
|
||||
}
|
||||
|
||||
if (sharedPreferences.getBoolean("update_formats", false) && refreshBtn.isVisible && items.size == 1){
|
||||
refreshBtn.performClick()
|
||||
}
|
||||
// if (sharedPreferences.getBoolean("update_formats", false) && refreshBtn.isVisible && items.size == 1){
|
||||
// refreshBtn.performClick()
|
||||
// }
|
||||
}
|
||||
|
||||
private fun returnFormats(){
|
||||
|
|
|
|||
|
|
@ -37,9 +37,9 @@ import androidx.recyclerview.widget.ItemTouchHelper
|
|||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.work.WorkManager
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.adapter.ActiveDownloadAdapter
|
||||
import com.deniscerri.ytdlnis.adapter.ActiveDownloadMinifiedAdapter
|
||||
import com.deniscerri.ytdlnis.adapter.GenericDownloadAdapter
|
||||
import com.deniscerri.ytdlnis.ui.adapter.ActiveDownloadAdapter
|
||||
import com.deniscerri.ytdlnis.ui.adapter.ActiveDownloadMinifiedAdapter
|
||||
import com.deniscerri.ytdlnis.ui.adapter.GenericDownloadAdapter
|
||||
import com.deniscerri.ytdlnis.database.models.ResultItem
|
||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||
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?) {
|
||||
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())
|
||||
queuedAdapter = GenericDownloadAdapter(this,requireActivity())
|
||||
|
||||
|
|
@ -220,10 +223,10 @@ class ResultCardDetailsDialog(private val item: ResultItem) : BottomSheetDialogF
|
|||
|
||||
bottomSheetLink.text = item.url
|
||||
bottomSheetLink.setOnClickListener{
|
||||
UiUtil.openLinkIntent(requireContext(), item.url, null)
|
||||
UiUtil.openLinkIntent(requireContext(), item.url)
|
||||
}
|
||||
bottomSheetLink.setOnLongClickListener{
|
||||
UiUtil.copyLinkToClipBoard(requireContext(), item.url, null)
|
||||
UiUtil.copyLinkToClipBoard(requireContext(), item.url)
|
||||
true
|
||||
}
|
||||
|
||||
|
|
@ -505,10 +508,12 @@ class ResultCardDetailsDialog(private val item: ResultItem) : BottomSheetDialogF
|
|||
link!!.text = url
|
||||
link.tag = itemID
|
||||
link.setOnClickListener{
|
||||
UiUtil.openLinkIntent(requireContext(), item.url, bottomSheet)
|
||||
bottomSheet.dismiss()
|
||||
UiUtil.openLinkIntent(requireContext(), item.url)
|
||||
}
|
||||
link.setOnLongClickListener{
|
||||
UiUtil.copyLinkToClipBoard(requireContext(), item.url, bottomSheet)
|
||||
bottomSheet.dismiss()
|
||||
UiUtil.copyLinkToClipBoard(requireContext(), item.url)
|
||||
true
|
||||
}
|
||||
val remove = bottomSheet.findViewById<Button>(R.id.bottomsheet_remove_button)
|
||||
|
|
|
|||
|
|
@ -1,18 +1,14 @@
|
|||
package com.deniscerri.ytdlnis.ui.downloadcard
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.ActionBar.LayoutParams
|
||||
import android.app.Dialog
|
||||
import android.content.DialogInterface
|
||||
import android.os.Bundle
|
||||
import android.util.DisplayMetrics
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.Window
|
||||
import android.widget.Button
|
||||
import android.widget.TextView
|
||||
import androidx.core.widget.doAfterTextChanged
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
|
|
@ -20,7 +16,7 @@ import androidx.lifecycle.lifecycleScope
|
|||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
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.ResultItem
|
||||
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.google.android.material.appbar.MaterialToolbar
|
||||
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.textfield.TextInputLayout
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.*
|
||||
|
||||
class SelectPlaylistItemsDialog(private val items: List<ResultItem?>, private val type: DownloadViewModel.Type) : DialogFragment(), PlaylistAdapter.OnItemClickListener {
|
||||
private lateinit var downloadViewModel: DownloadViewModel
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import android.view.LayoutInflater
|
|||
import android.view.View
|
||||
import android.view.View.OnClickListener
|
||||
import android.view.ViewGroup
|
||||
import android.widget.RelativeLayout
|
||||
import android.widget.TextView
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
|
|
@ -17,7 +18,7 @@ import androidx.work.WorkInfo
|
|||
import androidx.work.WorkManager
|
||||
import androidx.work.WorkQuery
|
||||
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.repository.DownloadRepository
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
|
|
@ -41,6 +42,7 @@ class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickLis
|
|||
lateinit var downloadItem: DownloadItem
|
||||
private lateinit var notificationUtil: NotificationUtil
|
||||
private lateinit var pauseResume: MaterialButton
|
||||
private lateinit var noResults: RelativeLayout
|
||||
private lateinit var workManager: WorkManager
|
||||
|
||||
|
||||
|
|
@ -71,6 +73,7 @@ class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickLis
|
|||
activeRecyclerView.adapter = activeDownloads
|
||||
activeRecyclerView.layoutManager = GridLayoutManager(context, resources.getInteger(R.integer.grid_size))
|
||||
pauseResume = view.findViewById(R.id.pause_resume)
|
||||
noResults = view.findViewById(R.id.no_results)
|
||||
|
||||
pauseResume.setOnClickListener {
|
||||
if (pauseResume.text == requireContext().getString(R.string.pause)){
|
||||
|
|
@ -168,6 +171,7 @@ class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickLis
|
|||
activeDownloads.notifyDataSetChanged()
|
||||
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.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.RelativeLayout
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.view.ActionMode
|
||||
|
|
@ -21,7 +22,7 @@ import androidx.recyclerview.widget.GridLayoutManager
|
|||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
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.repository.DownloadRepository
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
|
|
@ -47,6 +48,7 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic
|
|||
private lateinit var downloadViewModel : DownloadViewModel
|
||||
private lateinit var cancelledRecyclerView : RecyclerView
|
||||
private lateinit var adapter : GenericDownloadAdapter
|
||||
private lateinit var noResults : RelativeLayout
|
||||
private var actionMode : ActionMode? = null
|
||||
private var totalSize = 0
|
||||
|
||||
|
|
@ -55,7 +57,7 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic
|
|||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
fragmentView = inflater.inflate(R.layout.generic_recyclerview, container, false)
|
||||
fragmentView = inflater.inflate(R.layout.generic_list, container, false)
|
||||
activity = getActivity()
|
||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
return fragmentView
|
||||
|
|
@ -70,6 +72,7 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic
|
|||
requireActivity()
|
||||
)
|
||||
|
||||
noResults = view.findViewById(R.id.no_results)
|
||||
cancelledRecyclerView = view.findViewById(R.id.download_recyclerview)
|
||||
cancelledRecyclerView.forceFastScrollMode()
|
||||
cancelledRecyclerView.adapter = adapter
|
||||
|
|
@ -90,6 +93,7 @@ class CancelledDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClic
|
|||
|
||||
downloadViewModel.getTotalSize(listOf(DownloadRepository.Status.Cancelled)).observe(viewLifecycleOwner){
|
||||
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 com.deniscerri.ytdlnis.MainActivity
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.repository.DownloadRepository
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
||||
import com.deniscerri.ytdlnis.work.DownloadWorker
|
||||
import com.google.android.material.appbar.MaterialToolbar
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import android.widget.AdapterView
|
||||
import android.widget.AdapterView.OnItemClickListener
|
||||
import android.widget.RelativeLayout
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.fragment.app.Fragment
|
||||
|
|
@ -23,7 +24,7 @@ import androidx.recyclerview.widget.GridLayoutManager
|
|||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
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.repository.DownloadRepository
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
|
|
@ -48,6 +49,7 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
|
|||
private var activity: Activity? = null
|
||||
private lateinit var downloadViewModel : DownloadViewModel
|
||||
private lateinit var erroredRecyclerView : RecyclerView
|
||||
private lateinit var noResults : RelativeLayout
|
||||
private lateinit var adapter : GenericDownloadAdapter
|
||||
private var actionMode : ActionMode? = null
|
||||
private var totalSize: Int = 0
|
||||
|
|
@ -56,7 +58,7 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
|
|||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
fragmentView = inflater.inflate(R.layout.generic_recyclerview, container, false)
|
||||
fragmentView = inflater.inflate(R.layout.generic_list, container, false)
|
||||
activity = getActivity()
|
||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
return fragmentView
|
||||
|
|
@ -71,6 +73,7 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
|
|||
requireActivity()
|
||||
)
|
||||
|
||||
noResults = view.findViewById(R.id.no_results)
|
||||
erroredRecyclerView = view.findViewById(R.id.download_recyclerview)
|
||||
erroredRecyclerView.forceFastScrollMode()
|
||||
erroredRecyclerView.adapter = adapter
|
||||
|
|
@ -90,6 +93,7 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
|
|||
|
||||
downloadViewModel.getTotalSize(listOf(DownloadRepository.Status.Error)).observe(viewLifecycleOwner){
|
||||
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 com.deniscerri.ytdlnis.MainActivity
|
||||
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.repository.HistoryRepository
|
||||
import com.deniscerri.ytdlnis.database.DBManager.SORTING
|
||||
|
|
@ -72,7 +72,6 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
private var topAppBar: MaterialToolbar? = null
|
||||
private var recyclerView: RecyclerView? = null
|
||||
private var historyAdapter: HistoryAdapter? = null
|
||||
private var bottomSheet: BottomSheetDialog? = null
|
||||
private var sortSheet: BottomSheetDialog? = null
|
||||
private var uiHandler: Handler? = null
|
||||
private var noResults: RelativeLayout? = null
|
||||
|
|
@ -401,20 +400,24 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
|
|||
override fun onCardClick(itemID: Long, isPresent: Boolean) {
|
||||
val item = findItem(itemID)
|
||||
UiUtil.showHistoryItemDetailsCard(item, requireActivity(), isPresent,
|
||||
removeItem = { it, deleteFile ->
|
||||
historyViewModel.delete(it, deleteFile)
|
||||
},
|
||||
redownloadItem = {
|
||||
val downloadItem = downloadViewModel.createDownloadItemFromHistory(it)
|
||||
runBlocking{
|
||||
downloadViewModel.queueDownloads(listOf(downloadItem))
|
||||
}
|
||||
historyViewModel.delete(it, false)
|
||||
},
|
||||
redownloadShowDownloadCard = {
|
||||
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) {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import android.view.Menu
|
|||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.RelativeLayout
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
|
|
@ -24,7 +25,7 @@ import androidx.recyclerview.widget.ItemTouchHelper
|
|||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.work.WorkManager
|
||||
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.repository.DownloadRepository
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
|
|
@ -53,6 +54,7 @@ class QueuedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLi
|
|||
private lateinit var downloadViewModel : DownloadViewModel
|
||||
private lateinit var queuedRecyclerView : RecyclerView
|
||||
private lateinit var adapter : GenericDownloadAdapter
|
||||
private lateinit var noResults : RelativeLayout
|
||||
private lateinit var notificationUtil: NotificationUtil
|
||||
private lateinit var fileSize: TextView
|
||||
private var totalSize: Int = 0
|
||||
|
|
@ -80,6 +82,7 @@ class QueuedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLi
|
|||
requireActivity()
|
||||
)
|
||||
|
||||
noResults = view.findViewById(R.id.no_results)
|
||||
queuedRecyclerView = view.findViewById(R.id.download_recyclerview)
|
||||
queuedRecyclerView.forceFastScrollMode()
|
||||
queuedRecyclerView.adapter = adapter
|
||||
|
|
@ -120,6 +123,7 @@ class QueuedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLi
|
|||
|
||||
downloadViewModel.getTotalSize(listOf(DownloadRepository.Status.Queued, DownloadRepository.Status.QueuedPaused)).observe(viewLifecycleOwner){
|
||||
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.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.RelativeLayout
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.view.ActionMode
|
||||
|
|
@ -21,7 +22,7 @@ import androidx.recyclerview.widget.GridLayoutManager
|
|||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
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.repository.DownloadRepository
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
|
||||
|
|
@ -47,6 +48,7 @@ class SavedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLis
|
|||
private lateinit var downloadViewModel : DownloadViewModel
|
||||
private lateinit var savedRecyclerView: RecyclerView
|
||||
private lateinit var adapter: GenericDownloadAdapter
|
||||
private lateinit var noResults: RelativeLayout
|
||||
private var actionMode : ActionMode? = null
|
||||
private var totalSize : Int = 0
|
||||
override fun onCreateView(
|
||||
|
|
@ -54,7 +56,7 @@ class SavedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLis
|
|||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
fragmentView = inflater.inflate(R.layout.generic_recyclerview, container, false)
|
||||
fragmentView = inflater.inflate(R.layout.generic_list, container, false)
|
||||
activity = getActivity()
|
||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
return fragmentView
|
||||
|
|
@ -69,6 +71,7 @@ class SavedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLis
|
|||
requireActivity()
|
||||
)
|
||||
|
||||
noResults = view.findViewById(R.id.no_results)
|
||||
savedRecyclerView = view.findViewById(R.id.download_recyclerview)
|
||||
savedRecyclerView.forceFastScrollMode()
|
||||
savedRecyclerView.enableFastScroll()
|
||||
|
|
@ -89,6 +92,7 @@ class SavedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLis
|
|||
|
||||
downloadViewModel.getTotalSize(listOf(DownloadRepository.Status.Saved)).observe(viewLifecycleOwner){
|
||||
totalSize = it
|
||||
noResults.visibility = if (it == 0) View.VISIBLE else View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package com.deniscerri.ytdlnis.ui.more
|
||||
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Color
|
||||
|
|
@ -9,12 +11,15 @@ import android.os.Looper
|
|||
import android.text.InputType
|
||||
import android.util.DisplayMetrics
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.Window
|
||||
import android.widget.RelativeLayout
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
|
|
@ -26,11 +31,13 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
|||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.deniscerri.ytdlnis.MainActivity
|
||||
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.viewmodel.CommandTemplateViewModel
|
||||
import com.deniscerri.ytdlnis.database.repository.CommandTemplateRepository.CommandTemplateSortType
|
||||
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.google.android.material.appbar.AppBarLayout
|
||||
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.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
|
||||
class CommandTemplatesFragment : Fragment(), TemplatesAdapter.OnItemClickListener {
|
||||
|
|
@ -53,6 +62,9 @@ class CommandTemplatesFragment : Fragment(), TemplatesAdapter.OnItemClickListene
|
|||
private lateinit var noResults: RelativeLayout
|
||||
private lateinit var mainActivity: MainActivity
|
||||
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(
|
||||
inflater: LayoutInflater,
|
||||
|
|
@ -60,6 +72,7 @@ class CommandTemplatesFragment : Fragment(), TemplatesAdapter.OnItemClickListene
|
|||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
mainActivity = activity as MainActivity
|
||||
selectedObjects = arrayListOf()
|
||||
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) {
|
||||
if (it.isEmpty()) noResults.visibility = View.VISIBLE
|
||||
else noResults.visibility = View.GONE
|
||||
|
|
@ -259,14 +272,109 @@ class CommandTemplatesFragment : Fragment(), TemplatesAdapter.OnItemClickListene
|
|||
override fun onSelected(commandTemplate: CommandTemplate) {
|
||||
}
|
||||
|
||||
override fun onDelete(commandTemplate: CommandTemplate) {
|
||||
val deleteDialog = MaterialAlertDialogBuilder(requireContext())
|
||||
deleteDialog.setTitle(getString(R.string.you_are_going_to_delete) + " \"" + commandTemplate.title + "\"!")
|
||||
deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() }
|
||||
deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int ->
|
||||
commandTemplateViewModel.delete(commandTemplate)
|
||||
override fun onCardSelect(itemID: Long, isChecked: Boolean) {
|
||||
val item = templatesList.find { it.id == itemID }
|
||||
if (isChecked) {
|
||||
selectedObjects!!.add(item!!)
|
||||
if (actionMode == null){
|
||||
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 =
|
||||
|
|
@ -282,7 +390,9 @@ class CommandTemplatesFragment : Fragment(), TemplatesAdapter.OnItemClickListene
|
|||
ItemTouchHelper.LEFT -> {
|
||||
val deletedItem = templatesList[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.RelativeLayout
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.view.children
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
|
|
@ -26,10 +25,10 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
|||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.deniscerri.ytdlnis.MainActivity
|
||||
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.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.chip.Chip
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
|
|
@ -130,6 +129,10 @@ class CookiesFragment : Fragment(), CookieAdapter.OnItemClickListener {
|
|||
}
|
||||
deleteDialog.show()
|
||||
}
|
||||
R.id.use_header -> {
|
||||
m.isChecked = !m.isChecked
|
||||
preferences.edit().putBoolean("use_header", m.isChecked).apply()
|
||||
}
|
||||
R.id.import_clipboard -> {
|
||||
lifecycleScope.launch(Dispatchers.IO){
|
||||
cookiesViewModel.importFromClipboard()
|
||||
|
|
@ -139,9 +142,18 @@ class CookiesFragment : Fragment(), CookieAdapter.OnItemClickListener {
|
|||
cookiesViewModel.exportToClipboard()
|
||||
Snackbar.make(recyclerView, getString(R.string.copied_to_clipboard), Snackbar.LENGTH_LONG).show()
|
||||
}
|
||||
R.id.use_header -> {
|
||||
m.isChecked = !m.isChecked
|
||||
preferences.edit().putBoolean("use_header", m.isChecked).apply()
|
||||
R.id.export_file -> {
|
||||
cookiesViewModel.exportToFile {f ->
|
||||
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
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@ class MoreFragment : Fragment() {
|
|||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
return inflater.inflate(R.layout.fragment_more, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,25 +1,30 @@
|
|||
package com.deniscerri.ytdlnis.ui.more.downloadLogs
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context.CLIPBOARD_SERVICE
|
||||
import android.graphics.Color
|
||||
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.MenuItem
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.HorizontalScrollView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.ScrollView
|
||||
import android.widget.TextView
|
||||
import androidx.core.view.children
|
||||
import androidx.core.view.get
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.map
|
||||
import com.deniscerri.ytdlnis.MainActivity
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.LogItem
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.LogViewModel
|
||||
import com.google.android.material.appbar.MaterialToolbar
|
||||
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 kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.regex.Pattern
|
||||
import kotlin.math.log
|
||||
|
||||
|
||||
class DownloadLogFragment : Fragment() {
|
||||
|
|
@ -56,6 +59,7 @@ class DownloadLogFragment : Fragment() {
|
|||
}
|
||||
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
|
|
@ -65,11 +69,17 @@ class DownloadLogFragment : Fragment() {
|
|||
}
|
||||
|
||||
content = view.findViewById(R.id.content)
|
||||
content.movementMethod = ScrollingMovementMethod()
|
||||
content.setTextIsSelectable(true)
|
||||
contentScrollView = view.findViewById(R.id.content_scrollview)
|
||||
|
||||
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.setOnClickListener {
|
||||
val clipboard: ClipboardManager =
|
||||
|
|
@ -81,22 +91,13 @@ class DownloadLogFragment : Fragment() {
|
|||
val id = arguments?.getLong("logID")
|
||||
if (id == null) {
|
||||
mainActivity.onBackPressedDispatcher.onBackPressed()
|
||||
}else{
|
||||
arguments?.remove("logID")
|
||||
}
|
||||
|
||||
|
||||
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 {
|
||||
val logItem = logViewModel.getItemById(id)
|
||||
val logItem = logViewModel.getItemById(id!!)
|
||||
topAppBar.title = logItem.title
|
||||
}
|
||||
|
||||
|
|
@ -118,6 +119,7 @@ class DownloadLogFragment : Fragment() {
|
|||
*schemes.map { it }.toTypedArray()
|
||||
)
|
||||
highlight.setSpan(content)
|
||||
content.isFocusable = true
|
||||
content.addTextChangedListener(highlightWatcher)
|
||||
content.setHorizontallyScrolling(false)
|
||||
|
||||
|
|
@ -144,9 +146,37 @@ class DownloadLogFragment : Fragment() {
|
|||
}
|
||||
content.setHorizontallyScrolling(!content.canScrollHorizontally(1))
|
||||
}
|
||||
|
||||
R.id.scroll_down -> {
|
||||
m.isVisible = false
|
||||
contentScrollView.fullScroll(View.FOCUS_DOWN)
|
||||
}
|
||||
}
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
|||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.deniscerri.ytdlnis.MainActivity
|
||||
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.viewmodel.LogViewModel
|
||||
import com.deniscerri.ytdlnis.util.UiUtil.enableFastScroll
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.deniscerri.ytdlnis.ui.more.settings
|
|||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.net.Uri
|
||||
import android.os.Build.VERSION
|
||||
import android.os.Bundle
|
||||
|
|
@ -35,14 +36,16 @@ class FolderSettingsFragment : BaseSettingsFragment() {
|
|||
private var videoFilenameTemplate : Preference? = null
|
||||
private var clearCache: Preference? = null
|
||||
private var moveCache: Preference? = null
|
||||
private lateinit var preferences: SharedPreferences
|
||||
private lateinit var editor: SharedPreferences.Editor
|
||||
|
||||
private var activeDownloadCount = 0
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.folders_preference, rootKey)
|
||||
|
||||
val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
val editor = preferences.edit()
|
||||
preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
editor = preferences.edit()
|
||||
|
||||
musicPath = findPreference("music_path")
|
||||
videoPath = findPreference("video_path")
|
||||
|
|
@ -110,7 +113,7 @@ class FolderSettingsFragment : BaseSettingsFragment() {
|
|||
val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
|
||||
val uri = Uri.parse("package:" + requireContext().packageName)
|
||||
intent.data = uri
|
||||
accessAllFilesLauncher.launch(intent)
|
||||
startActivity(intent)
|
||||
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(
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
) { 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) {
|
||||
val path = 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.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.os.LocaleListCompat
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.Preference
|
||||
|
|
@ -130,29 +131,24 @@ class GeneralSettingsFragment : BaseSettingsFragment() {
|
|||
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!!.onPreferenceClickListener =
|
||||
Preference.OnPreferenceClickListener {
|
||||
val intent = Intent()
|
||||
intent.action = Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
|
||||
intent.data = Uri.parse("package:" + requireContext().packageName)
|
||||
ignoreBatteryLauncher.launch(intent)
|
||||
startActivity(intent)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
private var ignoreBatteryLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
) { result ->
|
||||
if (result.resultCode == Activity.RESULT_OK) {
|
||||
ignoreBatteryOptimization?.isVisible = false
|
||||
override fun onResume() {
|
||||
val packageName: String = requireContext().packageName
|
||||
val pm = requireContext().applicationContext.getSystemService(Context.POWER_SERVICE) as PowerManager
|
||||
if (pm.isIgnoringBatteryOptimizations(packageName)) {
|
||||
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) {
|
||||
|
|
|
|||
|
|
@ -1,28 +1,21 @@
|
|||
package com.deniscerri.ytdlnis.ui.more.terminal
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.provider.MediaStore
|
||||
import android.util.Log
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.NavArgument
|
||||
import androidx.navigation.NavGraph
|
||||
import androidx.navigation.NavType
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
import androidx.navigation.navArgument
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.viewmodel.TerminalViewModel
|
||||
import com.deniscerri.ytdlnis.ui.BaseActivity
|
||||
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.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
|
|
|||
|
|
@ -1,20 +1,12 @@
|
|||
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.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.HorizontalScrollView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.RelativeLayout
|
||||
import android.widget.TextView
|
||||
import androidx.activity.addCallback
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.view.forEach
|
||||
import androidx.core.view.get
|
||||
import androidx.fragment.app.Fragment
|
||||
|
|
@ -23,17 +15,14 @@ import androidx.lifecycle.lifecycleScope
|
|||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.work.WorkInfo
|
||||
import androidx.work.WorkManager
|
||||
import androidx.work.WorkQuery
|
||||
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.viewmodel.TerminalViewModel
|
||||
import com.deniscerri.ytdlnis.util.UiUtil.enableFastScroll
|
||||
import com.google.android.material.appbar.MaterialToolbar
|
||||
import com.google.android.material.progressindicator.LinearProgressIndicator
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
|
|
|||
|
|
@ -8,9 +8,8 @@ import android.content.Context.INPUT_METHOD_SERVICE
|
|||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Bundle
|
||||
import android.os.PersistableBundle
|
||||
import android.text.method.ScrollingMovementMethod
|
||||
import android.util.DisplayMetrics
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
|
|
@ -23,19 +22,14 @@ import android.widget.ScrollView
|
|||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.view.forEach
|
||||
import androidx.core.view.get
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.work.WorkInfo
|
||||
import androidx.work.WorkManager
|
||||
import androidx.work.workDataOf
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.TerminalItem
|
||||
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.bottomappbar.BottomAppBar
|
||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
import com.yausername.youtubedl_android.YoutubeDL
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.lang.StringBuilder
|
||||
import java.util.concurrent.Executor
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
|
||||
|
|
@ -87,7 +80,7 @@ class TerminalFragment : Fragment() {
|
|||
super.onSaveInstanceState(outState)
|
||||
outState.putString("input", input?.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)
|
||||
}
|
||||
|
||||
|
|
@ -103,6 +96,7 @@ class TerminalFragment : Fragment() {
|
|||
scrollView = view.findViewById(R.id.custom_command_scrollview)
|
||||
topAppBar = requireActivity().findViewById(R.id.custom_command_toolbar)
|
||||
topAppBar!!.setNavigationOnClickListener { requireActivity().finish() }
|
||||
topAppBar!!.setOnClickListener { scrollView?.scrollTo(0,0) }
|
||||
|
||||
input = view.findViewById(R.id.command_edittext)
|
||||
fab = view.findViewById(R.id.command_fab)
|
||||
|
|
@ -156,7 +150,7 @@ class TerminalFragment : Fragment() {
|
|||
when(it.itemId){
|
||||
R.id.command_templates -> {
|
||||
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{
|
||||
lifecycleScope.launch {
|
||||
UiUtil.showCommandTemplates(requireActivity(), commandTemplateViewModel){ templates ->
|
||||
|
|
@ -198,11 +192,12 @@ class TerminalFragment : Fragment() {
|
|||
}
|
||||
|
||||
output = view.findViewById(R.id.custom_command_output)
|
||||
output!!.movementMethod = ScrollingMovementMethod()
|
||||
output!!.setTextIsSelectable(true)
|
||||
output!!.layoutParams!!.width = LayoutParams.WRAP_CONTENT
|
||||
input!!.requestFocus()
|
||||
fab!!.setOnClickListener {
|
||||
if (fab!!.text == getString(R.string.run_command)){
|
||||
if (fab!!.text == requireActivity().getString(R.string.run_command)){
|
||||
input!!.visibility = View.GONE
|
||||
output!!.text = "${output!!.text}\n~ $ ${input!!.text}\n"
|
||||
showCancelFab()
|
||||
|
|
@ -213,6 +208,8 @@ class TerminalFragment : Fragment() {
|
|||
terminalViewModel.insert(TerminalItem(command = command, log = output!!.text.toString()))
|
||||
}
|
||||
terminalViewModel.startTerminalDownloadWorker(TerminalItem(downloadID, command))
|
||||
input!!.visibility = View.GONE
|
||||
showCancelFab()
|
||||
runWorkerListener()
|
||||
}
|
||||
}else {
|
||||
|
|
@ -274,12 +271,16 @@ class TerminalFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
private fun hideCancelFab() {
|
||||
fab!!.text = getString(R.string.run_command)
|
||||
fab!!.setIconResource(R.drawable.ic_baseline_keyboard_arrow_right_24)
|
||||
kotlin.runCatching {
|
||||
fab!!.text = getString(R.string.run_command)
|
||||
fab!!.setIconResource(R.drawable.ic_baseline_keyboard_arrow_right_24)
|
||||
}
|
||||
}
|
||||
private fun showCancelFab() {
|
||||
fab!!.text = getString(R.string.cancel_download)
|
||||
fab!!.setIconResource(R.drawable.ic_cancel)
|
||||
kotlin.runCatching {
|
||||
fab!!.text = getString(R.string.cancel_download)
|
||||
fab!!.setIconResource(R.drawable.ic_cancel)
|
||||
}
|
||||
}
|
||||
|
||||
private var commandPathResultLauncher = registerForActivityResult(
|
||||
|
|
@ -307,7 +308,11 @@ class TerminalFragment : Fragment() {
|
|||
output?.text = it.log
|
||||
}
|
||||
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())
|
||||
.getWorkInfosByTagLiveData(downloadID.toString())
|
||||
.observe(viewLifecycleOwner){ list ->
|
||||
list.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()
|
||||
}
|
||||
.getWorkInfosForUniqueWorkLiveData(downloadID.toString())
|
||||
.removeObserver(workerObserver)
|
||||
|
||||
WorkManager.getInstance(requireContext())
|
||||
.getWorkInfosForUniqueWorkLiveData(downloadID.toString())
|
||||
.observe(viewLifecycleOwner, workerObserver)
|
||||
}
|
||||
|
||||
private val workerObserver = object: Observer<MutableList<WorkInfo>> {
|
||||
override fun onChanged(value: MutableList<WorkInfo>) {
|
||||
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
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.ContentResolver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.database.Cursor
|
||||
import android.media.MediaScannerConnection
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Environment
|
||||
import android.provider.DocumentsContract
|
||||
import android.provider.MediaStore
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.webkit.MimeTypeMap
|
||||
import android.widget.TextView
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.core.net.toUri
|
||||
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.FolderCallback
|
||||
import com.anggrayudi.storage.file.copyFolderTo
|
||||
import com.anggrayudi.storage.file.getAbsolutePath
|
||||
import com.anggrayudi.storage.file.moveFileTo
|
||||
import com.deniscerri.ytdlnis.App
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.yausername.youtubedl_android.YoutubeDLRequest
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
|
@ -64,6 +53,7 @@ object FileUtil {
|
|||
var dataValue = path
|
||||
if (dataValue.startsWith("/storage/")) return dataValue
|
||||
dataValue = dataValue.replace("content://com.android.externalstorage.documents/tree/", "")
|
||||
dataValue = dataValue.replace("raw:/storage/", "")
|
||||
dataValue = dataValue.replace("^/document/".toRegex(), "")
|
||||
dataValue = dataValue.replace("^primary:".toRegex(), "primary/")
|
||||
dataValue = dataValue.replace("%3A".toRegex(), "/")
|
||||
|
|
@ -296,6 +286,10 @@ object FileUtil {
|
|||
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){
|
||||
val cookiesFile = File(context.cacheDir, "cookies.txt")
|
||||
if (cookiesFile.exists()) path(cookiesFile.absolutePath)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import android.util.Log
|
|||
import android.util.Patterns
|
||||
import android.widget.Toast
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.afollestad.materialdialogs.utils.MDUtil.getStringArray
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.ChapterItem
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
|
|
@ -553,13 +554,20 @@ class InfoUtil(private val context: Context) {
|
|||
request = YoutubeDLRequest(query)
|
||||
}else{
|
||||
request = YoutubeDLRequest(emptyList())
|
||||
if (searchEngine == "ytsearchmusic"){
|
||||
request.addOption("--default-search", "https://music.youtube.com/search?q=")
|
||||
request.addOption("ytsearch25:\"${query}\"")
|
||||
}else{
|
||||
request.addOption("${searchEngine}25:\"${query}\"")
|
||||
when (searchEngine){
|
||||
"ytsearchmusic" -> {
|
||||
request.addOption("--default-search", "https://music.youtube.com/search?q=")
|
||||
request.addOption("ytsearch25:\"${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("-j")
|
||||
|
|
@ -954,8 +962,8 @@ class InfoUtil(private val context: Context) {
|
|||
if (!sharedPreferences.getBoolean("cache_downloads", true) && File(FileUtil.formatPath(downloadItem.downloadPath)).canWrite()){
|
||||
downDir = File(FileUtil.formatPath(downloadItem.downloadPath))
|
||||
request.addOption("--no-quiet")
|
||||
request.addOption("-no-simulate")
|
||||
request.addOption("--print", "after_video:'%(filename)s'")
|
||||
request.addOption("--no-simulate")
|
||||
request.addOption("--print", "after_move:'%(filepath,_filename)s'")
|
||||
}else{
|
||||
val cacheDir = FileUtil.getCachePath(context)
|
||||
downDir = File(cacheDir, downloadItem.id.toString())
|
||||
|
|
@ -1072,7 +1080,9 @@ class InfoUtil(private val context: Context) {
|
|||
}
|
||||
|
||||
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.writeText(downloadItem.extraCommands)
|
||||
request.addOption(
|
||||
|
|
@ -1135,7 +1145,7 @@ class InfoUtil(private val context: Context) {
|
|||
if (sharedPreferences.getBoolean("embed_metadata", true)){
|
||||
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()) {
|
||||
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.Resources
|
||||
import android.graphics.BitmapFactory
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.DisplayMetrics
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import androidx.navigation.NavDeepLinkBuilder
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.App.Companion.instance
|
||||
import com.deniscerri.ytdlnis.receiver.CancelDownloadNotificationReceiver
|
||||
import com.deniscerri.ytdlnis.receiver.CancelWorkReceiver
|
||||
import com.deniscerri.ytdlnis.receiver.PauseDownloadNotificationReceiver
|
||||
|
|
@ -195,7 +196,8 @@ class NotificationUtil(var context: Context) {
|
|||
notificationManager.notify(DOWNLOAD_UPDATING_NOTIFICATION_ID, notificationBuilder.build())
|
||||
}
|
||||
|
||||
fun createDownloadFinished(title: String?,
|
||||
fun createDownloadFinished(
|
||||
title: String?,
|
||||
filepath: List<String>?
|
||||
) {
|
||||
val notificationBuilder = getBuilder(DOWNLOAD_FINISHED_CHANNEL_ID)
|
||||
|
|
@ -215,24 +217,36 @@ class NotificationUtil(var context: Context) {
|
|||
.clearActions()
|
||||
if (filepath != null){
|
||||
try{
|
||||
val file = File(filepath.first())
|
||||
val uri = FileProvider.getUriForFile(
|
||||
context,
|
||||
"com.deniscerri.ytdl.fileprovider",
|
||||
file
|
||||
)
|
||||
val uri = filepath.first().runCatching {
|
||||
DocumentFile.fromSingleUri(context, Uri.parse(filepath.first())).run{
|
||||
if (this?.exists() == true){
|
||||
this.uri
|
||||
}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 {
|
||||
addNextIntentWithParentStack(intent)
|
||||
addNextIntentWithParentStack(openFileIntent)
|
||||
getPendingIntent(0,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
|
||||
}
|
||||
|
||||
|
||||
|
||||
//share intent
|
||||
val shareIntent = Intent(context, ShareFileActivity::class.java)
|
||||
shareIntent.putExtra("path", filepath.toTypedArray())
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import android.graphics.drawable.ShapeDrawable
|
|||
import android.graphics.drawable.shapes.OvalShape
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Looper
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.text.format.DateFormat
|
||||
|
|
@ -34,13 +33,9 @@ import androidx.appcompat.app.AlertDialog
|
|||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.core.view.allViews
|
||||
import androidx.core.view.children
|
||||
import androidx.core.view.get
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
|
|
@ -50,7 +45,6 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import com.afollestad.materialdialogs.utils.MDUtil.getStringArray
|
||||
import com.deniscerri.ytdlnis.MainActivity
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.adapter.ConfigureMultipleDownloadsAdapter
|
||||
import com.deniscerri.ytdlnis.database.models.CommandTemplate
|
||||
import com.deniscerri.ytdlnis.database.models.DownloadItem
|
||||
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.viewmodel.CommandTemplateViewModel
|
||||
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.ui.downloadcard.ConfigureDownloadBottomSheetDialog
|
||||
import com.deniscerri.ytdlnis.ui.downloadcard.DownloadBottomSheetDialog
|
||||
import com.deniscerri.ytdlnis.ui.downloadcard.VideoCutListener
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
|
|
@ -285,19 +279,17 @@ object UiUtil {
|
|||
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 clip = ClipData.newPlainText(context.getString(R.string.url), url)
|
||||
clipboard.setPrimaryClip(clip)
|
||||
bottomSheet?.hide()
|
||||
Toast.makeText(context, context.getString(R.string.link_copied_to_clipboard), Toast.LENGTH_SHORT)
|
||||
.show()
|
||||
}
|
||||
|
||||
fun openLinkIntent(context: Context, url: String, bottomSheet: BottomSheetDialog?) {
|
||||
fun openLinkIntent(context: Context, url: String) {
|
||||
val i = Intent(Intent.ACTION_VIEW)
|
||||
i.data = Uri.parse(url)
|
||||
bottomSheet?.hide()
|
||||
context.startActivity(i)
|
||||
}
|
||||
|
||||
|
|
@ -432,18 +424,19 @@ object UiUtil {
|
|||
|
||||
// BUTTON ----------------------------------
|
||||
val btn = bottomSheet.findViewById<FloatingActionButton>(R.id.download_button_type)
|
||||
|
||||
when (item.type) {
|
||||
DownloadViewModel.Type.audio -> {
|
||||
btn?.setImageResource(R.drawable.ic_music)
|
||||
val typeImageResource: Int =
|
||||
when (item.type) {
|
||||
DownloadViewModel.Type.audio -> {
|
||||
R.drawable.ic_music
|
||||
}
|
||||
DownloadViewModel.Type.video -> {
|
||||
R.drawable.ic_video
|
||||
}
|
||||
else -> {
|
||||
R.drawable.ic_terminal
|
||||
}
|
||||
}
|
||||
DownloadViewModel.Type.video -> {
|
||||
btn?.setImageResource(R.drawable.ic_video)
|
||||
}
|
||||
else -> {
|
||||
btn?.setImageResource(R.drawable.ic_terminal)
|
||||
}
|
||||
}
|
||||
btn?.setImageResource(typeImageResource)
|
||||
|
||||
val time = bottomSheet.findViewById<Chip>(R.id.time)
|
||||
val formatNote = bottomSheet.findViewById<Chip>(R.id.format_note)
|
||||
|
|
@ -474,8 +467,12 @@ object UiUtil {
|
|||
View.GONE
|
||||
else formatNote!!.text = item.format.format_note
|
||||
|
||||
if (item.format.container != "") container!!.text = item.format.container.uppercase()
|
||||
else container!!.visibility = View.GONE
|
||||
if (item.format.container != "") {
|
||||
container!!.text = item.format.container.uppercase()
|
||||
container.setChipIconResource(typeImageResource)
|
||||
}else {
|
||||
container!!.visibility = View.GONE
|
||||
}
|
||||
|
||||
val codecText =
|
||||
if (item.format.encoding != "") {
|
||||
|
|
@ -501,10 +498,12 @@ object UiUtil {
|
|||
link!!.text = url
|
||||
link.tag = item.id
|
||||
link.setOnClickListener{
|
||||
openLinkIntent(context, item.url, bottomSheet)
|
||||
bottomSheet.dismiss()
|
||||
openLinkIntent(context, item.url)
|
||||
}
|
||||
link.setOnLongClickListener{
|
||||
copyLinkToClipBoard(context, item.url, bottomSheet)
|
||||
bottomSheet.dismiss()
|
||||
copyLinkToClipBoard(context, item.url)
|
||||
true
|
||||
}
|
||||
val remove = bottomSheet.findViewById<Button>(R.id.bottomsheet_remove_button)
|
||||
|
|
@ -561,6 +560,7 @@ object UiUtil {
|
|||
item: HistoryItem?,
|
||||
context: Activity,
|
||||
isPresent: Boolean,
|
||||
removeItem: (item:HistoryItem, removeFiles: Boolean) -> Unit,
|
||||
redownloadItem: (HistoryItem) -> Unit,
|
||||
redownloadShowDownloadCard: (HistoryItem) -> Unit,
|
||||
){
|
||||
|
|
@ -575,21 +575,23 @@ object UiUtil {
|
|||
// BUTTON ----------------------------------
|
||||
val btn = bottomSheet.findViewById<FloatingActionButton>(R.id.download_button_type)
|
||||
|
||||
val typeImageResource: Int =
|
||||
if (item.type == DownloadViewModel.Type.audio) {
|
||||
if (isPresent) {
|
||||
btn?.setImageResource(R.drawable.ic_music_downloaded)
|
||||
R.drawable.ic_music_downloaded
|
||||
} else {
|
||||
btn?.setImageResource(R.drawable.ic_music)
|
||||
R.drawable.ic_music
|
||||
}
|
||||
} else if (item.type == DownloadViewModel.Type.video) {
|
||||
if (isPresent) {
|
||||
btn?.setImageResource(R.drawable.ic_video_downloaded)
|
||||
R.drawable.ic_video_downloaded
|
||||
} else {
|
||||
btn?.setImageResource(R.drawable.ic_video)
|
||||
R.drawable.ic_video
|
||||
}
|
||||
}else{
|
||||
btn?.setImageResource(R.drawable.ic_terminal)
|
||||
R.drawable.ic_terminal
|
||||
}
|
||||
btn?.setImageResource(typeImageResource)
|
||||
|
||||
if (isPresent){
|
||||
btn?.setOnClickListener {
|
||||
|
|
@ -599,9 +601,10 @@ object UiUtil {
|
|||
|
||||
val time = bottomSheet.findViewById<TextView>(R.id.time)
|
||||
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 fileSize = bottomSheet.findViewById<TextView>(R.id.file_size)
|
||||
val file = File(item.downloadPath)
|
||||
|
||||
val calendar = Calendar.getInstance()
|
||||
calendar.timeInMillis = item.time * 1000L
|
||||
|
|
@ -610,10 +613,14 @@ object UiUtil {
|
|||
|
||||
if (item.format.format_note == "?" || item.format.format_note == "") formatNote!!.visibility =
|
||||
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()
|
||||
else container!!.visibility = View.GONE
|
||||
if (item.format.container != "") {
|
||||
container!!.text = if (file.exists()) file.extension.uppercase() else item.format.container.uppercase()
|
||||
container.setChipIconResource(typeImageResource)
|
||||
}else {
|
||||
container!!.visibility = View.GONE
|
||||
}
|
||||
|
||||
val codecText =
|
||||
if (item.format.encoding != "") {
|
||||
|
|
@ -630,7 +637,6 @@ object UiUtil {
|
|||
codec.text = codecText
|
||||
}
|
||||
|
||||
val file = File(item.downloadPath)
|
||||
val fileSizeReadable = FileUtil.convertFileSize(if (file.exists()) file.length() else item.format.filesize)
|
||||
if (fileSizeReadable == "?") fileSize!!.visibility = View.GONE
|
||||
else fileSize!!.text = fileSizeReadable
|
||||
|
|
@ -640,18 +646,18 @@ object UiUtil {
|
|||
link!!.text = url
|
||||
link.tag = item.id
|
||||
link.setOnClickListener{
|
||||
openLinkIntent(context, item.url, bottomSheet)
|
||||
bottomSheet.dismiss()
|
||||
openLinkIntent(context, item.url)
|
||||
}
|
||||
link.setOnLongClickListener{
|
||||
copyLinkToClipBoard(context, item.url, bottomSheet)
|
||||
bottomSheet.dismiss()
|
||||
copyLinkToClipBoard(context, item.url)
|
||||
true
|
||||
}
|
||||
val remove = bottomSheet.findViewById<Button>(R.id.bottomsheet_remove_button)
|
||||
remove!!.tag = item.id
|
||||
remove.setOnClickListener{
|
||||
showRemoveHistoryItemDialog(item, context, delete = { item, deleteFile ->
|
||||
|
||||
})
|
||||
showRemoveHistoryItemDialog(item, context, delete = removeItem)
|
||||
bottomSheet.dismiss()
|
||||
}
|
||||
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)
|
||||
builder.setTitle(context.getString(R.string.subtitle_languages))
|
||||
val inputLayout = context.layoutInflater.inflate(R.layout.textinput, null)
|
||||
val editText = inputLayout.findViewById<EditText>(R.id.url_edittext)
|
||||
inputLayout.findViewById<TextInputLayout>(R.id.url_textinput).hint = context.getString(R.string.subtitle_languages)
|
||||
val view = context.layoutInflater.inflate(R.layout.subtitle_dialog, null)
|
||||
val editText = view.findViewById<EditText>(R.id.subtitle_edittext)
|
||||
view.findViewById<TextInputLayout>(R.id.subtitle).hint = context.getString(R.string.subtitle_languages)
|
||||
editText.setText(currentValue)
|
||||
editText.setSelection(editText.text.length)
|
||||
builder.setView(inputLayout)
|
||||
builder.setView(view)
|
||||
builder.setPositiveButton(
|
||||
context.getString(R.string.ok)
|
||||
) { _: DialogInterface?, _: Int ->
|
||||
|
|
@ -812,19 +818,46 @@ object UiUtil {
|
|||
context.startActivity(browserIntent)
|
||||
}
|
||||
|
||||
view.findViewById<View>(R.id.suggested).visibility = View.GONE
|
||||
|
||||
val dialog = builder.create()
|
||||
editText.doOnTextChanged { _, _, _, _ ->
|
||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = editText.text.isNotEmpty()
|
||||
}
|
||||
dialog.show()
|
||||
val imm = context.getSystemService(AppCompatActivity.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
editText.setSelection(editText.text!!.length)
|
||||
editText!!.postDelayed({
|
||||
editText.requestFocus()
|
||||
imm.showSoftInput(editText, 0)
|
||||
}, 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
|
||||
}
|
||||
|
||||
|
|
@ -934,7 +967,7 @@ object UiUtil {
|
|||
cutClicked: (VideoCutListener) -> Unit,
|
||||
filenameTemplateSet: (String) -> Unit,
|
||||
saveSubtitlesClicked: (Boolean) -> Unit,
|
||||
subtitleLanguagesClicked: () -> Unit,
|
||||
subtitleLanguagesSet: (String) -> Unit,
|
||||
removeAudioClicked: (Boolean) -> Unit,
|
||||
extraCommandsClicked: () -> Unit
|
||||
){
|
||||
|
|
@ -1093,7 +1126,14 @@ object UiUtil {
|
|||
|
||||
subtitleLanguages.isEnabled = embedSubs.isChecked || saveSubtitles.isChecked
|
||||
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)
|
||||
|
|
@ -1301,7 +1341,7 @@ object UiUtil {
|
|||
|
||||
private var textHighLightSchemes = listOf(
|
||||
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("\\d+(\\.\\d)?%"), Color.parseColor("#43a564"))
|
||||
)
|
||||
|
|
@ -1339,7 +1379,7 @@ object UiUtil {
|
|||
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 message = it.errorMessage!!.second
|
||||
|
||||
|
|
@ -1358,11 +1398,16 @@ object UiUtil {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
errDialog.setOnCancelListener {
|
||||
closed()
|
||||
}
|
||||
|
||||
errDialog.show()
|
||||
}
|
||||
|
||||
@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}
|
||||
if (downloadAnywayAction != null){
|
||||
if (downloadAnywayAction.third == null) return
|
||||
|
|
@ -1425,14 +1470,11 @@ object UiUtil {
|
|||
if (historyItem != null){
|
||||
ttle.setOnClickListener {
|
||||
showHistoryItemDetailsCard(historyItem, context, isPresent = true,
|
||||
removeItem = { item, deleteFile ->
|
||||
historyViewModel.delete(item, deleteFile)
|
||||
},
|
||||
redownloadItem = { },
|
||||
redownloadShowDownloadCard = {
|
||||
val sheet = DownloadBottomSheetDialog(
|
||||
result = downloadViewModel.createResultItemFromHistory(it),
|
||||
type = it.type
|
||||
)
|
||||
sheet.show(context.supportFragmentManager, "downloadSingleSheet")
|
||||
}
|
||||
redownloadShowDownloadCard = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1455,7 +1497,7 @@ object UiUtil {
|
|||
|
||||
errDialog.setPositiveButton(downloadAnywayAction.first) { d:DialogInterface?, _:Int ->
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
linearLayout.allViews.forEach {view ->
|
||||
linearLayout.children.forEach {view ->
|
||||
val downloadItem = downloads.first { it.id == (view.tag as String).toLong()}
|
||||
downloadItem.id = 0
|
||||
downloadViewModel.queueDownloads(listOf(downloadItem), true)
|
||||
|
|
@ -1547,6 +1589,12 @@ object UiUtil {
|
|||
context.getString(R.string.cancel)
|
||||
) { _: 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
|
||||
|
||||
val dialog = builder.create()
|
||||
|
|
|
|||
|
|
@ -1,37 +1,51 @@
|
|||
package com.deniscerri.ytdlnis.util
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.DownloadManager
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.text.method.LinkMovementMethod
|
||||
import android.util.Log
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.ContextCompat.startActivity
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.deniscerri.ytdlnis.BuildConfig
|
||||
import com.deniscerri.ytdlnis.R
|
||||
import com.deniscerri.ytdlnis.database.models.GithubRelease
|
||||
import com.deniscerri.ytdlnis.database.models.GithubReleaseAsset
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.yausername.youtubedl_android.YoutubeDL
|
||||
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.withContext
|
||||
import java.io.BufferedReader
|
||||
import java.io.File
|
||||
import java.io.InputStreamReader
|
||||
import java.net.HttpURLConnection
|
||||
import java.net.URL
|
||||
|
||||
|
||||
class UpdateUtil(var context: Context) {
|
||||
private val tag = "UpdateUtil"
|
||||
private val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
private val downloadManager: DownloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
|
||||
|
||||
@SuppressLint("UnspecifiedRegisterReceiverFlag")
|
||||
fun updateApp(result: (result: String) -> Unit) {
|
||||
try {
|
||||
if (updatingApp) {
|
||||
|
|
@ -99,7 +113,7 @@ class UpdateUtil(var context: Context) {
|
|||
Environment
|
||||
.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
|
||||
.mkdirs()
|
||||
downloadManager.enqueue(
|
||||
val downloadID = downloadManager.enqueue(
|
||||
DownloadManager.Request(uri)
|
||||
.setAllowedNetworkTypes(
|
||||
DownloadManager.Request.NETWORK_WIFI or
|
||||
|
|
@ -110,10 +124,34 @@ class UpdateUtil(var context: Context) {
|
|||
.setTitle(context.getString(R.string.downloading_update))
|
||||
.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
|
||||
}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.repository.DownloadRepository
|
||||
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.InfoUtil
|
||||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
||||
import com.yausername.youtubedl_android.YoutubeDL
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
|
|
@ -122,6 +120,7 @@ class DownloadWorker(
|
|||
|
||||
|
||||
val commandString = infoUtil.parseYTDLRequestString(request)
|
||||
val logString = StringBuilder("\n ${commandString}\n\n")
|
||||
val logItem = LogItem(
|
||||
0,
|
||||
downloadItem.title.ifEmpty { downloadItem.url },
|
||||
|
|
@ -129,7 +128,7 @@ class DownloadWorker(
|
|||
"Title: ${downloadItem.title}\n" +
|
||||
"URL: ${downloadItem.url}\n" +
|
||||
"Type: ${downloadItem.type}\n" +
|
||||
"Command:\n ${commandString}\n\n",
|
||||
"Command: $logString",
|
||||
downloadItem.format,
|
||||
downloadItem.type,
|
||||
System.currentTimeMillis(),
|
||||
|
|
@ -137,7 +136,7 @@ class DownloadWorker(
|
|||
|
||||
|
||||
runBlocking {
|
||||
logItem.id = logRepo.insert(logItem)
|
||||
if (logDownloads) logItem.id = logRepo.insert(logItem)
|
||||
downloadItem.logID = logItem.id
|
||||
dao.update(downloadItem)
|
||||
}
|
||||
|
|
@ -154,7 +153,10 @@ class DownloadWorker(
|
|||
NotificationUtil.DOWNLOAD_SERVICE_CHANNEL_ID
|
||||
)
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
logRepo.update(line, logItem.id)
|
||||
if (logDownloads) {
|
||||
logRepo.update(line, logItem.id)
|
||||
logString.append("$line\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
}.onSuccess {
|
||||
|
|
@ -164,16 +166,18 @@ class DownloadWorker(
|
|||
|
||||
if (noCache){
|
||||
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") }
|
||||
.map { it.removePrefix("'") }
|
||||
.map { it.removeSuffix("'\n") }
|
||||
finalPaths = File(FileUtil.formatPath(downloadLocation))
|
||||
.walkTopDown()
|
||||
.filter { it.isFile && p.any { f -> f.contains(it.nameWithoutExtension) }}
|
||||
.sortedByDescending { it.length() }
|
||||
.map { it.absolutePath }
|
||||
.map { it.removeSuffix("\n") }
|
||||
.map { it.removeSuffix("'") }
|
||||
.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)
|
||||
if (finalPaths.isEmpty()){
|
||||
finalPaths = listOf(context.getString(R.string.unfound_file))
|
||||
|
|
@ -236,8 +240,6 @@ class DownloadWorker(
|
|||
|
||||
if (logDownloads){
|
||||
logRepo.update(it.out, logItem.id)
|
||||
}else{
|
||||
logRepo.delete(logItem)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -250,9 +252,13 @@ class DownloadWorker(
|
|||
if (it is YoutubeDL.CanceledException) {
|
||||
|
||||
}else{
|
||||
if (logDownloads){
|
||||
if(it.message != null){
|
||||
if(it.message != null){
|
||||
if (logDownloads){
|
||||
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.Handler
|
||||
import android.os.Looper
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.work.Data
|
||||
import androidx.work.ForegroundInfo
|
||||
import androidx.work.Worker
|
||||
import androidx.work.WorkerParameters
|
||||
import androidx.work.workDataOf
|
||||
import com.deniscerri.ytdlnis.App
|
||||
import com.deniscerri.ytdlnis.MainActivity
|
||||
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.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.nio.file.Files
|
||||
import java.nio.file.StandardCopyOption
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ import com.deniscerri.ytdlnis.util.InfoUtil
|
|||
import com.deniscerri.ytdlnis.util.NotificationUtil
|
||||
import com.yausername.youtubedl_android.YoutubeDL
|
||||
import com.yausername.youtubedl_android.YoutubeDLRequest
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -45,10 +44,8 @@ class TerminalDownloadWorker(
|
|||
|
||||
val dbManager = DBManager.getInstance(context)
|
||||
val logRepo = LogRepository(dbManager.logDao)
|
||||
|
||||
val notificationUtil = NotificationUtil(context)
|
||||
val handler = Handler(Looper.getMainLooper())
|
||||
val infoUtil = InfoUtil(context)
|
||||
|
||||
val intent = Intent(context, TerminalActivity::class.java)
|
||||
val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
|
||||
|
|
@ -95,7 +92,7 @@ class TerminalDownloadWorker(
|
|||
System.currentTimeMillis(),
|
||||
)
|
||||
|
||||
runCatching {
|
||||
kotlin.runCatching {
|
||||
if (logDownloads){
|
||||
runBlocking {
|
||||
logItem.id = logRepo.insert(logItem)
|
||||
|
|
@ -137,12 +134,10 @@ class TerminalDownloadWorker(
|
|||
}
|
||||
|
||||
return runBlocking {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
if (logDownloads) logRepo.update(it.out, logItem.id)
|
||||
dao.updateLog(it.out, itemId.toLong())
|
||||
Thread.sleep(1000)
|
||||
dao.delete(itemId.toLong())
|
||||
}
|
||||
if (logDownloads) logRepo.update(it.out, logItem.id)
|
||||
dao.updateLog(it.out, itemId.toLong())
|
||||
Thread.sleep(1000)
|
||||
dao.delete(itemId.toLong())
|
||||
notificationUtil.cancelDownloadNotification(itemId)
|
||||
|
||||
Result.success()
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
android:height="108dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="#fff">
|
||||
android:tint="@color/icon_fg">
|
||||
<group android:scaleX="0.58"
|
||||
android:scaleY="0.58"
|
||||
android:translateX="5.04"
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@
|
|||
android:orientation="vertical"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<include layout="@layout/history_no_results"
|
||||
<include layout="@layout/no_results"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@
|
|||
android:layout_margin="10dp"
|
||||
android:backgroundTint="@android:color/transparent"
|
||||
app:tabGravity="fill"
|
||||
app:tabMinWidth="0dp"
|
||||
app:tabMode="scrollable">
|
||||
|
||||
<com.google.android.material.tabs.TabItem
|
||||
|
|
|
|||
|
|
@ -128,6 +128,7 @@
|
|||
android:layout_margin="10dp"
|
||||
android:backgroundTint="@android:color/transparent"
|
||||
app:tabGravity="start"
|
||||
app:tabMinWidth="0dp"
|
||||
app:tabMode="scrollable">
|
||||
|
||||
<com.google.android.material.tabs.TabItem
|
||||
|
|
|
|||
|
|
@ -1,35 +1,42 @@
|
|||
<?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_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginBottom="100dp"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<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"/>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/download_recyclerview"
|
||||
<LinearLayout
|
||||
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">
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
</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
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_height="wrap_content"
|
||||
android:scrollbars="none">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/history_selection_chips"
|
||||
android:layout_width="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
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
|
||||
android:layout_width="match_parent"
|
||||
app:selectionRequired="false"
|
||||
|
|
@ -69,9 +61,19 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:text="@string/shortcuts"
|
||||
app:chipIcon="@drawable/ic_shortcut" />
|
||||
|
||||
</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>
|
||||
|
||||
</HorizontalScrollView>
|
||||
|
|
@ -92,7 +94,7 @@
|
|||
</androidx.recyclerview.widget.RecyclerView>
|
||||
|
||||
|
||||
<include layout="@layout/history_no_results"
|
||||
<include layout="@layout/no_results"
|
||||
android:visibility="gone" />
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@
|
|||
</RelativeLayout>
|
||||
|
||||
|
||||
<include layout="@layout/history_no_results"
|
||||
<include layout="@layout/no_results"
|
||||
android:visibility="gone" />
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
android:paddingHorizontal="10dp"
|
||||
android:paddingBottom="10dp"
|
||||
android:hint="@string/title"
|
||||
app:endIconMode="custom"
|
||||
style="@style/Widget.Material3.TextInputLayout.FilledBox">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
|
|
@ -44,7 +43,6 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_weight="40"
|
||||
android:hint="@string/author"
|
||||
app:endIconMode="custom"
|
||||
style="@style/Widget.Material3.TextInputLayout.FilledBox">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:paddingHorizontal="10dp"
|
||||
android:paddingTop="10dp"
|
||||
android:text="@string/command" />
|
||||
android:text="@string/command_templates" />
|
||||
|
||||
<include layout="@layout/command_template_item" />
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@
|
|||
|
||||
</LinearLayout>
|
||||
|
||||
<include layout="@layout/history_no_results"
|
||||
<include layout="@layout/no_results"
|
||||
android:visibility="gone" />
|
||||
|
||||
<com.google.android.material.bottomappbar.BottomAppBar
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
</androidx.recyclerview.widget.RecyclerView>
|
||||
|
||||
|
||||
<include layout="@layout/history_no_results"
|
||||
<include layout="@layout/no_results"
|
||||
android:visibility="gone" />
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
app:navigationIcon="@drawable/ic_back"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<LinearLayout
|
||||
|
|
@ -36,7 +35,8 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
android:backgroundTint="@android:color/transparent"
|
||||
app:tabGravity="fill"
|
||||
app:tabGravity="start"
|
||||
app:tabMinWidth="0dp"
|
||||
app:tabMode="scrollable" />
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
|
|
@ -44,7 +44,8 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
</LinearLayout>
|
||||
<include layout="@layout/history_no_results"
|
||||
|
||||
<include layout="@layout/no_results"
|
||||
android:visibility="gone" />
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@
|
|||
|
||||
</androidx.recyclerview.widget.RecyclerView>
|
||||
|
||||
<include layout="@layout/history_no_results"
|
||||
<include layout="@layout/no_results"
|
||||
android:visibility="gone" />
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,36 +1,46 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<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" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/download_recyclerview"
|
||||
<LinearLayout
|
||||
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">
|
||||
android:orientation="vertical">
|
||||
|
||||
</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>
|
||||
|
||||
<include layout="@layout/history_no_results"
|
||||
<include layout="@layout/no_results"
|
||||
android:visibility="gone" />
|
||||
|
||||
</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