added ignore battery optimization and other small stuff

This commit is contained in:
deniscerri 2023-03-31 23:07:36 +02:00
parent e732bf0103
commit 78a80a734d
No known key found for this signature in database
GPG key ID: 95C43D517D830350
21 changed files with 211 additions and 106 deletions

View file

@ -154,10 +154,10 @@ dependencies {
implementation "androidx.work:work-runtime-ktx:$workVer" implementation "androidx.work:work-runtime-ktx:$workVer"
implementation "androidx.room:room-runtime:2.5.0" implementation "androidx.room:room-runtime:2.5.1"
implementation "androidx.room:room-ktx:2.5.0" implementation "androidx.room:room-ktx:2.5.1"
kapt "androidx.room:room-compiler:2.5.0" kapt "androidx.room:room-compiler:2.5.1"
androidTestImplementation "androidx.room:room-testing:2.5.0" androidTestImplementation "androidx.room:room-testing:2.5.1"
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1' implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1'
implementation "androidx.compose.runtime:runtime:$composeVer" implementation "androidx.compose.runtime:runtime:$composeVer"
androidTestImplementation "com.google.truth:truth:1.1.3" androidTestImplementation "com.google.truth:truth:1.1.3"

View file

@ -12,6 +12,7 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" /> <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.ACTION_OPEN_DOCUMENT" /> <uses-permission android:name="android.permission.ACTION_OPEN_DOCUMENT" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
<application <application
android:name=".App" android:name=".App"

View file

@ -91,6 +91,7 @@ class MainActivity : AppCompatActivity() {
startActivity(intent) startActivity(intent)
} }
R.id.moreFragment -> { R.id.moreFragment -> {
//navController.navigate(R.id.settingsFragment)
val intent = Intent(context, SettingsActivity::class.java) val intent = Intent(context, SettingsActivity::class.java)
startActivity(intent) startActivity(intent)
} }

View file

@ -16,6 +16,7 @@ import androidx.recyclerview.widget.RecyclerView
import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.DownloadItem import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.util.FileUtil import com.deniscerri.ytdlnis.util.FileUtil
import com.google.android.exoplayer2.offline.Download
import com.google.android.material.button.MaterialButton import com.google.android.material.button.MaterialButton
import com.google.android.material.card.MaterialCardView import com.google.android.material.card.MaterialCardView
import com.google.android.material.progressindicator.LinearProgressIndicator import com.google.android.material.progressindicator.LinearProgressIndicator
@ -114,6 +115,10 @@ class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
val output = card.findViewById<TextView>(R.id.output) val output = card.findViewById<TextView>(R.id.output)
output.tag = "${item.id}##output" output.tag = "${item.id}##output"
output.setOnClickListener {
onItemClickListener.onOutputClick(item)
}
// CANCEL BUTTON ---------------------------------- // CANCEL BUTTON ----------------------------------
val cancelButton = card.findViewById<MaterialButton>(R.id.active_download_cancel) val cancelButton = card.findViewById<MaterialButton>(R.id.active_download_cancel)
@ -125,6 +130,7 @@ class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
} }
interface OnItemClickListener { interface OnItemClickListener {
fun onCancelClick(itemID: Long) fun onCancelClick(itemID: Long)
fun onOutputClick(item: DownloadItem)
} }
companion object { companion object {

View file

@ -108,7 +108,7 @@ class GenericDownloadAdapter(onItemClickListener: OnItemClickListener, activity:
DownloadRepository.Status.Queued.toString() -> actionButton.setIconResource(R.drawable.ic_baseline_delete_outline_24) DownloadRepository.Status.Queued.toString() -> actionButton.setIconResource(R.drawable.ic_baseline_delete_outline_24)
else -> { else -> {
actionButton.setIconResource(R.drawable.ic_baseline_file_open_24) actionButton.setIconResource(R.drawable.ic_baseline_file_open_24)
val logFile = File(activity.filesDir.absolutePath + """/logs/${item.id} - ${item.title}##${item.type}##${item.format.format_id}.log""") val logFile = fileUtil.getLogFile(activity, item)
if (!logFile.exists()){ if (!logFile.exists()){
actionButton.visibility = View.GONE actionButton.visibility = View.GONE
} }

View file

@ -1,6 +1,7 @@
package com.deniscerri.ytdlnis.ui.downloads package com.deniscerri.ytdlnis.ui.downloads
import android.app.Activity import android.app.Activity
import android.content.Intent
import android.content.res.Configuration import android.content.res.Configuration
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
@ -19,6 +20,8 @@ import com.deniscerri.ytdlnis.adapter.ActiveDownloadAdapter
import com.deniscerri.ytdlnis.database.models.DownloadItem import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding import com.deniscerri.ytdlnis.databinding.FragmentHomeBinding
import com.deniscerri.ytdlnis.ui.more.downloadLogs.DownloadLogActivity
import com.deniscerri.ytdlnis.util.FileUtil
import com.deniscerri.ytdlnis.util.NotificationUtil import com.deniscerri.ytdlnis.util.NotificationUtil
import com.google.android.material.progressindicator.LinearProgressIndicator import com.google.android.material.progressindicator.LinearProgressIndicator
import com.yausername.youtubedl_android.YoutubeDL import com.yausername.youtubedl_android.YoutubeDL
@ -33,6 +36,7 @@ class ActiveDownloadsFragment() : Fragment(), ActiveDownloadAdapter.OnItemClickL
private lateinit var activeDownloads : ActiveDownloadAdapter private lateinit var activeDownloads : ActiveDownloadAdapter
lateinit var downloadItem: DownloadItem lateinit var downloadItem: DownloadItem
private lateinit var notificationUtil: NotificationUtil private lateinit var notificationUtil: NotificationUtil
private lateinit var fileUtil: FileUtil
override fun onCreateView( override fun onCreateView(
@ -44,6 +48,7 @@ class ActiveDownloadsFragment() : Fragment(), ActiveDownloadAdapter.OnItemClickL
fragmentView = inflater.inflate(R.layout.fragment_generic_download_queue, container, false) fragmentView = inflater.inflate(R.layout.fragment_generic_download_queue, container, false)
activity = getActivity() activity = getActivity()
notificationUtil = NotificationUtil(requireContext()) notificationUtil = NotificationUtil(requireContext())
fileUtil = FileUtil()
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java] downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
return fragmentView return fragmentView
} }
@ -101,6 +106,15 @@ class ActiveDownloadsFragment() : Fragment(), ActiveDownloadAdapter.OnItemClickL
cancelDownload(itemID) cancelDownload(itemID)
} }
override fun onOutputClick(item: DownloadItem) {
val logFile = fileUtil.getLogFile(requireContext(), item)
if (logFile.exists()) {
val intent = Intent(requireContext(), DownloadLogActivity::class.java)
intent.putExtra("path", logFile.absolutePath)
startActivity(intent)
}
}
private fun cancelDownload(itemID: Long){ private fun cancelDownload(itemID: Long){
val id = itemID.toInt() val id = itemID.toInt()
YoutubeDL.getInstance().destroyProcessById(id.toString()) YoutubeDL.getInstance().destroyProcessById(id.toString())

View file

@ -87,7 +87,7 @@ class ErroredDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickL
override fun onActionButtonClick(itemID: Long) { override fun onActionButtonClick(itemID: Long) {
val item = items.find { it.id == itemID } ?: return val item = items.find { it.id == itemID } ?: return
val file = File(requireContext().filesDir.absolutePath + """/logs/${item.id} - ${item.title}##${item.type}##${item.format.format_id}.log""") val file = fileUtil.getLogFile(requireContext(), item)
val intent = Intent(requireContext(), DownloadLogActivity::class.java) val intent = Intent(requireContext(), DownloadLogActivity::class.java)
intent.putExtra("path", file.absolutePath) intent.putExtra("path", file.absolutePath)
startActivity(intent) startActivity(intent)

View file

@ -17,6 +17,9 @@ import androidx.appcompat.widget.SearchView
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupWithNavController
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
@ -242,10 +245,10 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
private fun changeSortIcon(item: TextView, order: HistorySort){ private fun changeSortIcon(item: TextView, order: HistorySort){
when(order){ when(order){
HistorySort.DESC ->{ HistorySort.DESC ->{
item.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_up, 0,0,0) item.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_up, 0,0,0)
} }
HistorySort.ASC -> { HistorySort.ASC -> {
item.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_down, 0,0,0) item.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_down, 0,0,0)
} }
} }
} }
@ -264,7 +267,7 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
val filesize = sortSheet!!.findViewById<TextView>(R.id.filesize) val filesize = sortSheet!!.findViewById<TextView>(R.id.filesize)
val sortOptions = listOf(date!!, title!!, author!!, filesize!!) val sortOptions = listOf(date!!, title!!, author!!, filesize!!)
sortOptions.forEach { it.setCompoundDrawablesWithIntrinsicBounds(R.drawable.empty,0,0,0) } sortOptions.forEach { it.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.empty,0,0,0) }
when(historyViewModel.sortType.value!!) { when(historyViewModel.sortType.value!!) {
HistoryRepository.HistorySortType.DATE -> changeSortIcon(date, historyViewModel.sortOrder.value!!) HistoryRepository.HistorySortType.DATE -> changeSortIcon(date, historyViewModel.sortOrder.value!!)
HistoryRepository.HistorySortType.TITLE -> changeSortIcon(title, historyViewModel.sortOrder.value!!) HistoryRepository.HistorySortType.TITLE -> changeSortIcon(title, historyViewModel.sortOrder.value!!)
@ -273,22 +276,22 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
} }
date.setOnClickListener { date.setOnClickListener {
sortOptions.forEach { it.setCompoundDrawablesWithIntrinsicBounds(R.drawable.empty,0,0,0) } sortOptions.forEach { it.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.empty,0,0,0) }
historyViewModel.setSorting(HistoryRepository.HistorySortType.DATE) historyViewModel.setSorting(HistoryRepository.HistorySortType.DATE)
changeSortIcon(date, historyViewModel.sortOrder.value!!) changeSortIcon(date, historyViewModel.sortOrder.value!!)
} }
title.setOnClickListener { title.setOnClickListener {
sortOptions.forEach { it.setCompoundDrawablesWithIntrinsicBounds(R.drawable.empty,0,0,0) } sortOptions.forEach { it.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.empty,0,0,0) }
historyViewModel.setSorting(HistoryRepository.HistorySortType.TITLE) historyViewModel.setSorting(HistoryRepository.HistorySortType.TITLE)
changeSortIcon(title, historyViewModel.sortOrder.value!!) changeSortIcon(title, historyViewModel.sortOrder.value!!)
} }
author.setOnClickListener { author.setOnClickListener {
sortOptions.forEach { it.setCompoundDrawablesWithIntrinsicBounds(R.drawable.empty,0,0,0) } sortOptions.forEach { it.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.empty,0,0,0) }
historyViewModel.setSorting(HistoryRepository.HistorySortType.AUTHOR) historyViewModel.setSorting(HistoryRepository.HistorySortType.AUTHOR)
changeSortIcon(author, historyViewModel.sortOrder.value!!) changeSortIcon(author, historyViewModel.sortOrder.value!!)
} }
filesize.setOnClickListener { filesize.setOnClickListener {
sortOptions.forEach { it.setCompoundDrawablesWithIntrinsicBounds(R.drawable.empty,0,0,0) } sortOptions.forEach { it.setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.empty,0,0,0) }
historyViewModel.setSorting(HistoryRepository.HistorySortType.FILESIZE) historyViewModel.setSorting(HistoryRepository.HistorySortType.FILESIZE)
changeSortIcon(filesize, historyViewModel.sortOrder.value!!) changeSortIcon(filesize, historyViewModel.sortOrder.value!!)
} }
@ -332,9 +335,10 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
val websites = mutableListOf<String>() val websites = mutableListOf<String>()
val websiteFilter = historyViewModel.websiteFilter.value val websiteFilter = historyViewModel.websiteFilter.value
for (item in list){ for (item in list){
if (!websites.contains(item.website)) websites.add(item.website) if (!websites.contains(item.website.lowercase())) websites.add(item.website.lowercase())
} }
websiteGroup!!.removeAllViews() websiteGroup!!.removeAllViews()
if (websites.size <= 1) return
//val websites = historyRecyclerViewAdapter!!.websites //val websites = historyRecyclerViewAdapter!!.websites
for (i in websites.indices) { for (i in websites.indices) {
val w = websites[i] val w = websites[i]

View file

@ -1,15 +1,19 @@
package com.deniscerri.ytdlnis.ui.more.settings package com.deniscerri.ytdlnis.ui.more.settings
import android.app.Activity import android.app.Activity
import android.content.Context
import android.content.Context.POWER_SERVICE
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.Environment import android.os.Environment
import android.os.PowerManager
import android.provider.Settings import android.provider.Settings
import android.widget.Toast import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import androidx.core.content.ContextCompat.getSystemService
import androidx.core.os.LocaleListCompat import androidx.core.os.LocaleListCompat
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.preference.* import androidx.preference.*
@ -26,8 +30,10 @@ import kotlinx.coroutines.launch
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import java.util.* import java.util.*
class SettingsFragment : PreferenceFragmentCompat() { class SettingsFragment : PreferenceFragmentCompat() {
private var language: ListPreference? = null private var language: ListPreference? = null
private var ignoreBatteryOptimization: Preference? = null
private var musicPath: Preference? = null private var musicPath: Preference? = null
private var videoPath: Preference? = null private var videoPath: Preference? = null
private var commandPath: Preference? = null private var commandPath: Preference? = null
@ -90,6 +96,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
requireContext().getSharedPreferences("root_preferences", Activity.MODE_PRIVATE) requireContext().getSharedPreferences("root_preferences", Activity.MODE_PRIVATE)
val editor = preferences.edit() val editor = preferences.edit()
language = findPreference("app_language") language = findPreference("app_language")
ignoreBatteryOptimization = findPreference("ignore_battery")
musicPath = findPreference("music_path") musicPath = findPreference("music_path")
videoPath = findPreference("video_path") videoPath = findPreference("video_path")
commandPath = findPreference("command_path") commandPath = findPreference("command_path")
@ -140,6 +147,12 @@ class SettingsFragment : PreferenceFragmentCompat() {
val lang = if (values.contains(Locale.getDefault().language)) Locale.getDefault().language else "en" val lang = if (values.contains(Locale.getDefault().language)) Locale.getDefault().language else "en"
editor.putString("app_language", lang) editor.putString("app_language", lang)
val packageName: String = requireContext().packageName
val pm = requireContext().applicationContext.getSystemService(POWER_SERVICE) as PowerManager
if (pm.isIgnoringBatteryOptimizations(packageName)) {
ignoreBatteryOptimization!!.isVisible = false
}
if (preferences.getString("music_path", "")!!.isEmpty()) { if (preferences.getString("music_path", "")!!.isEmpty()) {
editor.putString("music_path", getString(R.string.music_path)) editor.putString("music_path", getString(R.string.music_path))
} }
@ -197,6 +210,15 @@ class SettingsFragment : PreferenceFragmentCompat() {
true true
} }
ignoreBatteryOptimization!!.onPreferenceClickListener =
Preference.OnPreferenceClickListener {
val intent = Intent()
intent.action = Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
intent.data = Uri.parse("package:" + requireContext().packageName)
startActivity(intent)
true
}
musicPath!!.summary = fileUtil?.formatPath(preferences.getString("music_path", "")!!) musicPath!!.summary = fileUtil?.formatPath(preferences.getString("music_path", "")!!)
musicPath!!.onPreferenceClickListener = musicPath!!.onPreferenceClickListener =
Preference.OnPreferenceClickListener { Preference.OnPreferenceClickListener {

View file

@ -7,6 +7,7 @@ import android.os.Build
import android.provider.DocumentsContract import android.provider.DocumentsContract
import android.webkit.MimeTypeMap import android.webkit.MimeTypeMap
import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.DownloadItem
import okhttp3.internal.closeQuietly import okhttp3.internal.closeQuietly
import java.io.File import java.io.File
import java.net.URLDecoder import java.net.URLDecoder
@ -135,6 +136,11 @@ class FileUtil() {
return scanMedia(fileList, context) return scanMedia(fileList, context)
} }
fun getLogFile(context: Context, item: DownloadItem) : File {
val titleRegex = Regex("[^A-Za-z\\d ]")
return File(context.filesDir.absolutePath + """/logs/${item.id} - ${titleRegex.replace(item.title, "")}##${item.type}##${item.format.format_id}.log""")
}
fun convertFileSize(s: Long): String{ fun convertFileSize(s: Long): String{
if (s <= 0) return "?" if (s <= 0) return "?"
val units = arrayOf("B", "kB", "MB", "GB", "TB") val units = arrayOf("B", "kB", "MB", "GB", "TB")

View file

@ -36,6 +36,7 @@ class DownloadWorker(
if (itemId == 0L) return Result.failure() if (itemId == 0L) return Result.failure()
val notificationUtil = NotificationUtil(context) val notificationUtil = NotificationUtil(context)
val fileUtil = FileUtil()
val dbManager = DBManager.getInstance(context) val dbManager = DBManager.getInstance(context)
val dao = dbManager.downloadDao val dao = dbManager.downloadDao
val repository = DownloadRepository(dao) val repository = DownloadRepository(dao)
@ -225,10 +226,9 @@ class DownloadWorker(
} }
} }
val titleRegex = Regex("[^A-Za-z\\d ]")
val logDownloads = sharedPreferences.getBoolean("log_downloads", false) && !sharedPreferences.getBoolean("incognito", false) val logDownloads = sharedPreferences.getBoolean("log_downloads", false) && !sharedPreferences.getBoolean("incognito", false)
val logFolder = File(context.filesDir.absolutePath + "/logs") val logFolder = File(context.filesDir.absolutePath + "/logs")
val logFile = File(context.filesDir.absolutePath + """/logs/${downloadItem.id} - ${titleRegex.replace(downloadItem.title, "")}##${downloadItem.type}##${downloadItem.format.format_id}.log""") val logFile = fileUtil.getLogFile(context, downloadItem)
runCatching { runCatching {
if (logDownloads){ if (logDownloads){
@ -260,6 +260,7 @@ class DownloadWorker(
finalPath = moveFile(tempFileDir.absoluteFile, downloadLocation){ progress -> finalPath = moveFile(tempFileDir.absoluteFile, downloadLocation){ progress ->
setProgressAsync(workDataOf("progress" to progress)) setProgressAsync(workDataOf("progress" to progress))
} }
setProgressAsync(workDataOf("progress" to 1000, "output" to "Moved file to $finalPath", "id" to downloadItem.id, "log" to logDownloads))
}catch (e: Exception){ }catch (e: Exception){
finalPath = context.getString(R.string.unfound_file) finalPath = context.getString(R.string.unfound_file)
e.printStackTrace() e.printStackTrace()

View file

@ -0,0 +1,5 @@
<vector android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="?android:colorAccent" android:pathData="M15.67,4L14,4L14,2h-4v2L8.33,4C7.6,4 7,4.6 7,5.33v15.33C7,21.4 7.6,22 8.33,22h7.33c0.74,0 1.34,-0.6 1.34,-1.33L17,5.33C17,4.6 16.4,4 15.67,4zM13,18h-2v-2h2v2zM13,14h-2L11,9h2v5z"/>
</vector>

View file

@ -47,6 +47,7 @@
android:layout_height="match_parent"> android:layout_height="match_parent">
<LinearLayout <LinearLayout
android:id="@+id/title_author"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
android:orientation="vertical" android:orientation="vertical"
@ -94,15 +95,22 @@
</LinearLayout> </LinearLayout>
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier"
app:barrierDirection="bottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="title_author,active_download_cancel"/>
<HorizontalScrollView <HorizontalScrollView
android:id="@+id/linearlayout2_horizontalscrollview" android:id="@+id/linearlayout2_horizontalscrollview"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:scrollbars="none" android:scrollbars="none"
app:layout_constraintBottom_toTopOf="@+id/output" android:paddingTop="10dp"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/active_download_cancel" app:layout_constraintTop_toBottomOf="@+id/barrier"
app:layout_constraintVertical_bias="1.0"> app:layout_constraintVertical_bias="1.0">
<com.google.android.material.chip.ChipGroup <com.google.android.material.chip.ChipGroup

View file

@ -66,6 +66,7 @@
<androidx.viewpager2.widget.ViewPager2 <androidx.viewpager2.widget.ViewPager2
android:id="@+id/download_viewpager" android:id="@+id/download_viewpager"
android:layout_width="match_parent" android:layout_width="match_parent"
android:paddingHorizontal="10dp"
android:layout_height="match_parent" /> android:layout_height="match_parent" />
</LinearLayout> </LinearLayout>
<include layout="@layout/history_no_results" <include layout="@layout/history_no_results"

View file

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
@ -23,9 +23,11 @@
<TextView <TextView
android:id="@+id/bottom_sheet_title" android:id="@+id/bottom_sheet_title"
android:layout_width="wrap_content" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="4dp" android:layout_marginTop="4dp"
android:maxLines="2"
android:singleLine="false"
android:text="@string/download" android:text="@string/download"
android:textSize="25sp" android:textSize="25sp"
app:layout_constraintEnd_toStartOf="@+id/bottomsheet_schedule_button" app:layout_constraintEnd_toStartOf="@+id/bottomsheet_schedule_button"
@ -35,10 +37,14 @@
<TextView <TextView
android:id="@+id/bottom_sheet_subtitle" android:id="@+id/bottom_sheet_subtitle"
android:layout_width="wrap_content" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:maxLines="2"
android:singleLine="false"
android:text="@string/configure_download" android:text="@string/configure_download"
android:textSize="12sp" android:textSize="12sp"
app:layout_constraintEnd_toStartOf="@+id/bottomsheet_schedule_button"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/bottom_sheet_title" /> app:layout_constraintTop_toBottomOf="@+id/bottom_sheet_title" />
@ -102,5 +108,4 @@
</LinearLayout> </LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -70,6 +70,7 @@
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_weight="0.7" app:layout_constraintHorizontal_weight="0.7"
app:layout_constraintVertical_bias="0.0"
app:layout_constraintStart_toEndOf="@+id/downloads_image_view" app:layout_constraintStart_toEndOf="@+id/downloads_image_view"
app:layout_constraintTop_toTopOf="parent"> app:layout_constraintTop_toTopOf="parent">

View file

@ -10,6 +10,8 @@
android:id="@+id/history_appbarlayout" android:id="@+id/history_appbarlayout"
app:liftOnScroll="true" app:liftOnScroll="true"
android:background="@android:color/transparent" android:background="@android:color/transparent"
android:elevation="0dp"
app:elevation="0dp"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
@ -17,111 +19,111 @@
android:id="@+id/history_toolbar" android:id="@+id/history_toolbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="scroll|enterAlways|snap" app:layout_scrollFlags="scroll"
app:title="@string/downloads" app:title="@string/downloads"
app:menu="@menu/history_menu" app:menu="@menu/history_menu"
android:theme="@style/Toolbar" android:theme="@style/Toolbar"
/> />
</com.google.android.material.appbar.AppBarLayout> <RelativeLayout
android:layout_width="match_parent"
<RelativeLayout android:layout_height="match_parent"
android:layout_width="match_parent" android:orientation="vertical"
android:layout_height="match_parent" app:layout_scrollFlags="scroll|enterAlways"
android:orientation="vertical" android:layout_margin="10dp">
android:layout_margin="10dp" <HorizontalScrollView
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"> android:id="@+id/chips_recycler_horizontalscrollview"
<HorizontalScrollView
android:id="@+id/chips_recycler_horizontalscrollview"
android:layout_width="wrap_content"
android:scrollbars="none"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/history_selection_chips"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:visibility="gone" android:scrollbars="none"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<com.google.android.material.chip.ChipGroup <LinearLayout
android:id="@+id/history_selection_chips"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:visibility="gone"
app:selectionRequired="false"
app:singleSelection="false">
<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" />
</com.google.android.material.chip.ChipGroup>
<View style="@style/Divider.Vertical"/>
<com.google.android.material.chip.ChipGroup
android:id="@+id/format_chip_group"
android:layout_width="wrap_content"
app:selectionRequired="false"
app:singleSelection="true"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<com.google.android.material.chip.Chip <com.google.android.material.chip.ChipGroup
android:id="@+id/audio_chip"
style="@style/Widget.Material3.Chip.Filter"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/audio"/> app:selectionRequired="false"
app:singleSelection="false">
<com.google.android.material.chip.Chip <com.google.android.material.chip.Chip
android:id="@+id/video_chip" android:id="@+id/sortChip"
style="@style/Widget.Material3.Chip.Filter" 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" />
</com.google.android.material.chip.ChipGroup>
<View style="@style/Divider.Vertical"/>
<com.google.android.material.chip.ChipGroup
android:id="@+id/format_chip_group"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" app:selectionRequired="false"
android:text="@string/video"/> app:singleSelection="true"
android:layout_height="wrap_content">
<com.google.android.material.chip.Chip <com.google.android.material.chip.Chip
android:id="@+id/command_chip" android:id="@+id/audio_chip"
style="@style/Widget.Material3.Chip.Filter" style="@style/Widget.Material3.Chip.Filter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/audio"/>
<com.google.android.material.chip.Chip
android:id="@+id/video_chip"
style="@style/Widget.Material3.Chip.Filter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/video"/>
<com.google.android.material.chip.Chip
android:id="@+id/command_chip"
style="@style/Widget.Material3.Chip.Filter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/command"/>
</com.google.android.material.chip.ChipGroup>
<View style="@style/Divider.Vertical"/>
<com.google.android.material.chip.ChipGroup
android:id="@+id/website_chip_group"
app:selectionRequired="false"
app:singleSelection="true"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content">
android:text="@string/command"/>
</com.google.android.material.chip.ChipGroup> </com.google.android.material.chip.ChipGroup>
<View style="@style/Divider.Vertical"/> </LinearLayout>
<com.google.android.material.chip.ChipGroup </HorizontalScrollView>
android:id="@+id/website_chip_group"
app:selectionRequired="false"
app:singleSelection="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</com.google.android.material.chip.ChipGroup> </RelativeLayout>
</LinearLayout> </com.google.android.material.appbar.AppBarLayout>
</HorizontalScrollView> <androidx.recyclerview.widget.RecyclerView
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:layout_width="match_parent"
android:id="@+id/recyclerviewhistorys"
android:orientation="vertical"
android:layout_height="wrap_content"
android:scrollbars="vertical"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:clipToPadding="false"
android:paddingBottom="100dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager">
<androidx.recyclerview.widget.RecyclerView </androidx.recyclerview.widget.RecyclerView>
android:id="@+id/recyclerviewhistorys"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/chips_recycler_horizontalscrollview"
android:clipToPadding="false"
android:nestedScrollingEnabled="false"
android:orientation="vertical"
android:paddingBottom="150dp"
android:scrollbars="vertical"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager">
</androidx.recyclerview.widget.RecyclerView>
</RelativeLayout>
<androidx.coordinatorlayout.widget.CoordinatorLayout <androidx.coordinatorlayout.widget.CoordinatorLayout

View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.appbar.AppBarLayout android:id="@+id/home_appbarlayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@null"
android:elevation="0dp"
app:elevation="0dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:liftOnScroll="true"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/Toolbar"
app:layout_scrollFlags="scroll"
app:title="@string/app_name" />
</com.google.android.material.appbar.AppBarLayout>

View file

@ -189,4 +189,5 @@
<string name="end">End</string> <string name="end">End</string>
<string name="start">Start</string> <string name="start">Start</string>
<string name="update_formats_summary">Automatically search for missing formats when clicking the format card</string> <string name="update_formats_summary">Automatically search for missing formats when clicking the format card</string>
<string name="ignore_battery_optimization">Ignore Battery Optimization</string>
</resources> </resources>

View file

@ -8,6 +8,11 @@
app:summary="en" app:summary="en"
app:title="@string/language" /> app:title="@string/language" />
<Preference
app:icon="@drawable/ic_battery"
app:key="ignore_battery"
app:title="@string/ignore_battery_optimization" />
<PreferenceCategory android:title="@string/directories"> <PreferenceCategory android:title="@string/directories">

View file

@ -22,7 +22,7 @@ buildscript {
// supports java 1.6 // supports java 1.6
commonsCompressVer = '1.12' commonsCompressVer = '1.12'
youtubedlAndroidVer = "7222fe9637" youtubedlAndroidVer = "7222fe9637"
workVer = "2.8.0" workVer = "2.8.1"
composeVer = "1.4.0-alpha02" composeVer = "1.4.0-alpha02"
kotlinVer = "1.7.21" kotlinVer = "1.7.21"
coroutineVer = "1.6.4" coroutineVer = "1.6.4"