From 7d5f32b4bfb36cddeb50e631c6f8842b1215f880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=C3=87erri?= <64997243+deniscerri@users.noreply.github.com> Date: Sat, 4 Mar 2023 22:57:10 +0100 Subject: [PATCH] added ability to edit command template & delete. Fixed logs not scrolling. Implemented import/export templates from clipboard. Implemented Error Items Log Button --- app/build.gradle | 2 +- .../ytdlnis/adapter/GenericDownloadAdapter.kt | 9 +- .../ytdlnis/adapter/TemplatesAdapter.kt | 7 +- .../database/dao/CommandTemplateDao.kt | 5 +- .../ytdlnis/database/dao/DownloadDao.kt | 6 +- .../database/models/CommandTemplate.kt | 7 +- .../database/models/CommandTemplateExport.kt | 9 ++ .../database/models/TemplateShortcut.kt | 3 +- .../repository/CommandTemplateRepository.kt | 6 +- .../viewmodel/CommandTemplateViewModel.kt | 60 ++++++++++++- .../database/viewmodel/ResultViewModel.kt | 9 +- .../ytdlnis/receiver/ShareActivity.kt | 4 +- .../com/deniscerri/ytdlnis/ui/HomeFragment.kt | 2 +- .../downloadcard/DownloadBottomSheetDialog.kt | 10 ++- .../downloadcard/DownloadCommandFragment.kt | 87 +++++++++++-------- .../downloadqueue/ErroredDownloadsFragment.kt | 8 +- .../ui/more/CommandTemplatesActivity.kt | 46 ++++++---- .../more/downloadLogs/DownloadLogActivity.kt | 11 +-- .../downloadLogs/DownloadLogListActivity.kt | 28 +++++- .../ui/more/settings/SettingsFragment.kt | 10 +++ .../com/deniscerri/ytdlnis/util/UiUtil.kt | 31 +++++-- .../main/res/drawable/ic_download_type.xml | 2 +- .../main/res/layout/activity_download_log.xml | 41 +++++---- .../main/res/layout/command_template_item.xml | 1 + .../res/layout/create_command_template.xml | 2 +- app/src/main/res/layout/download_log_item.xml | 5 +- app/src/main/res/values/arrays.xml | 13 +++ app/src/main/res/values/strings.xml | 6 ++ app/src/main/res/xml/root_preferences.xml | 10 +++ build.gradle | 1 + 30 files changed, 331 insertions(+), 110 deletions(-) create mode 100644 app/src/main/java/com/deniscerri/ytdlnis/database/models/CommandTemplateExport.kt diff --git a/app/build.gradle b/app/build.gradle index d72b64d4..5f327079 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -6,6 +6,7 @@ plugins { id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin' version '2.0.1' id 'org.jetbrains.kotlin.android' id 'kotlin-kapt' + id "org.jetbrains.kotlin.plugin.serialization" version "1.7.21" } def properties = new Properties() @@ -175,5 +176,4 @@ dependencies { implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1" - } \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdlnis/adapter/GenericDownloadAdapter.kt b/app/src/main/java/com/deniscerri/ytdlnis/adapter/GenericDownloadAdapter.kt index 920968e2..1ee8ea49 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/adapter/GenericDownloadAdapter.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/adapter/GenericDownloadAdapter.kt @@ -23,6 +23,7 @@ import com.deniscerri.ytdlnis.util.FileUtil import com.google.android.material.button.MaterialButton import com.google.android.material.card.MaterialCardView import com.squareup.picasso.Picasso +import java.io.File import java.text.DateFormat import java.text.SimpleDateFormat import java.util.* @@ -106,7 +107,13 @@ class GenericDownloadAdapter(onItemClickListener: OnItemClickListener, activity: when(item.status){ DownloadRepository.Status.Cancelled.toString() -> actionButton.setIconResource(R.drawable.ic_refresh) DownloadRepository.Status.Queued.toString() -> actionButton.setIconResource(R.drawable.ic_baseline_delete_outline_24) - else -> actionButton.setIconResource(R.drawable.ic_baseline_file_open_24) + else -> { + 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""") + if (!logFile.exists()){ + actionButton.visibility = View.GONE + } + } } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/adapter/TemplatesAdapter.kt b/app/src/main/java/com/deniscerri/ytdlnis/adapter/TemplatesAdapter.kt index f569001c..5f386642 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/adapter/TemplatesAdapter.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/adapter/TemplatesAdapter.kt @@ -53,14 +53,19 @@ class TemplatesAdapter(onItemClickListener: OnItemClickListener, activity: Activ // onItemClickListener.onSelected(item!!) // } - title.setOnClickListener { + card.setOnClickListener { onItemClickListener.onItemClick(item!!) } + + card.setOnLongClickListener { + onItemClickListener.onDelete(item!!); true + } } interface OnItemClickListener { fun onItemClick(commandTemplate: CommandTemplate) fun onSelected(commandTemplate: CommandTemplate) + fun onDelete(commandTemplate: CommandTemplate) } companion object { diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/dao/CommandTemplateDao.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/dao/CommandTemplateDao.kt index 3770bdb1..0060a596 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/database/dao/CommandTemplateDao.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/database/dao/CommandTemplateDao.kt @@ -17,7 +17,10 @@ interface CommandTemplateDao { fun getAllTemplatesLiveData() : LiveData> @Query("SELECT * FROM templateShortcuts ORDER BY id DESC") - fun getAllShortcuts() : LiveData> + fun getAllShortcutsLiveData() : LiveData> + + @Query("SELECT * FROM templateShortcuts ORDER BY id DESC") + fun getAllShortcuts() : List @Query("SELECT COUNT(id) FROM commandTemplates") fun getTotalNumber() : Int diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/dao/DownloadDao.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/dao/DownloadDao.kt index 3ae1e3ff..80b9cc80 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/database/dao/DownloadDao.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/database/dao/DownloadDao.kt @@ -16,13 +16,13 @@ interface DownloadDao { @Query("SELECT * FROM downloads WHERE status='Queued'") fun getQueuedDownloads() : LiveData> - @Query("SELECT * FROM downloads WHERE status='Cancelled'") + @Query("SELECT * FROM downloads WHERE status='Cancelled' ORDER BY id DESC") fun getCancelledDownloads() : LiveData> - @Query("SELECT * FROM downloads WHERE status='Error'") + @Query("SELECT * FROM downloads WHERE status='Error' ORDER BY id DESC") fun getErroredDownloads() : LiveData> - @Query("SELECT * FROM downloads WHERE status='Processing'") + @Query("SELECT * FROM downloads WHERE status='Processing' ORDER BY id DESC") fun getProcessingDownloads() : LiveData> @Query("SELECT * FROM downloads WHERE id=:id LIMIT 1") diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/models/CommandTemplate.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/models/CommandTemplate.kt index 798f8e64..317d25a5 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/database/models/CommandTemplate.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/database/models/CommandTemplate.kt @@ -1,13 +1,14 @@ package com.deniscerri.ytdlnis.database.models -import androidx.room.ColumnInfo import androidx.room.Entity import androidx.room.PrimaryKey +import kotlinx.serialization.Serializable +@Serializable @Entity(tableName = "commandTemplates") data class CommandTemplate( @PrimaryKey(autoGenerate = true) var id: Long, - val title: String, - val content: String + var title: String, + var content: String ) \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/models/CommandTemplateExport.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/models/CommandTemplateExport.kt new file mode 100644 index 00000000..2074533b --- /dev/null +++ b/app/src/main/java/com/deniscerri/ytdlnis/database/models/CommandTemplateExport.kt @@ -0,0 +1,9 @@ +package com.deniscerri.ytdlnis.database.models + +import kotlinx.serialization.Serializable + +@Serializable +data class CommandTemplateExport( + val templates: List, + val shortcuts: List +) diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/models/TemplateShortcut.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/models/TemplateShortcut.kt index f7facded..4f32714c 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/database/models/TemplateShortcut.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/database/models/TemplateShortcut.kt @@ -1,9 +1,10 @@ package com.deniscerri.ytdlnis.database.models -import androidx.room.ColumnInfo import androidx.room.Entity import androidx.room.PrimaryKey +import kotlinx.serialization.Serializable +@Serializable @Entity(tableName = "templateShortcuts") data class TemplateShortcut( @PrimaryKey(autoGenerate = true) diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/repository/CommandTemplateRepository.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/repository/CommandTemplateRepository.kt index 85133a2b..f462c702 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/database/repository/CommandTemplateRepository.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/database/repository/CommandTemplateRepository.kt @@ -7,7 +7,7 @@ import com.deniscerri.ytdlnis.database.models.TemplateShortcut class CommandTemplateRepository(private val commandDao: CommandTemplateDao) { val items : LiveData> = commandDao.getAllTemplatesLiveData() - val shortcuts : LiveData> = commandDao.getAllShortcuts() + val shortcuts : LiveData> = commandDao.getAllShortcutsLiveData() fun getAll() : List { return commandDao.getAllTemplates(); @@ -25,6 +25,10 @@ class CommandTemplateRepository(private val commandDao: CommandTemplateDao) { commandDao.delete(item.id) } + fun getAllShortCuts() : List { + return commandDao.getAllShortcuts(); + } + suspend fun insertShortcut(item: TemplateShortcut){ commandDao.insertShortcut(item.content) } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/CommandTemplateViewModel.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/CommandTemplateViewModel.kt index 8375b3c7..93af94b5 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/CommandTemplateViewModel.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/CommandTemplateViewModel.kt @@ -1,9 +1,15 @@ package com.deniscerri.ytdlnis.database.viewmodel import android.app.Application +import android.content.ClipData +import android.content.ClipboardManager +import android.content.Context.CLIPBOARD_SERVICE +import android.widget.Toast +import androidx.core.content.ContextCompat.getSystemService import androidx.lifecycle.* 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 @@ -11,13 +17,20 @@ import com.deniscerri.ytdlnis.database.repository.HistoryRepository import com.deniscerri.ytdlnis.database.repository.HistoryRepository.HistorySort import com.deniscerri.ytdlnis.database.repository.HistoryRepository.HistorySortType import com.deniscerri.ytdlnis.util.FileUtil +import com.google.gson.Gson +import com.google.gson.JsonObject import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json -class CommandTemplateViewModel(application: Application) : AndroidViewModel(application) { +class CommandTemplateViewModel(private val application: Application) : AndroidViewModel(application) { private val repository: CommandTemplateRepository val items: LiveData> val shortcuts : LiveData> + private val jsonFormat = Json { prettyPrint = true } init { val dao = DBManager.getInstance(application).commandTemplateDao @@ -58,12 +71,53 @@ class CommandTemplateViewModel(application: Application) : AndroidViewModel(appl repository.update(item) } - fun importFromClipboard() = viewModelScope.launch(Dispatchers.IO) { + suspend fun importFromClipboard() : Int { + val allTemplates = repository.getAll() + val allShortcuts = repository.getAllShortCuts() + var count = 0 + val clipboard = application.getSystemService(CLIPBOARD_SERVICE) as ClipboardManager + val clip = clipboard.primaryClip!!.getItemAt(0).text.toString() + try{ + jsonFormat.decodeFromString(clip).run { + templates.filterNot { + allTemplates.contains(it) + }.run { + this.forEach { + repository.insert(it.copy(id=0)) + count++ + } + } + shortcuts.filterNot { + allShortcuts.contains(it) + }.run{ + this.forEach { + repository.insertShortcut(it.copy(id=0)) + count++ + } + } + } + }catch (e: Exception){ + e.printStackTrace() + } + + return count } - fun exportToClipboard() { + fun exportToClipboard() = viewModelScope.launch(Dispatchers.IO) { + val allTemplates = repository.getAll() + val allShortcuts = repository.getAllShortCuts() + val output = jsonFormat.encodeToString( + CommandTemplateExport( + templates = allTemplates, + shortcuts = allShortcuts + ) + ) + + val clipboard: ClipboardManager = + application.getSystemService(CLIPBOARD_SERVICE) as ClipboardManager + clipboard.setText(output) } } \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/ResultViewModel.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/ResultViewModel.kt index b3968278..e2fd6503 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/ResultViewModel.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/ResultViewModel.kt @@ -105,7 +105,14 @@ class ResultViewModel(application: Application) : AndroidViewModel(application) } fun addSearchQueryToHistory(query: String) = viewModelScope.launch(Dispatchers.IO) { - searchHistoryRepository.insert(query) + val allQueries = searchHistoryRepository.getAll() + allQueries.filterNot { + it.query == query + }.run { + this.forEach { + searchHistoryRepository.insert(it.query) + } + } } fun deleteAllSearchQueryHistory() = viewModelScope.launch(Dispatchers.IO){ diff --git a/app/src/main/java/com/deniscerri/ytdlnis/receiver/ShareActivity.kt b/app/src/main/java/com/deniscerri/ytdlnis/receiver/ShareActivity.kt index 3f4fb5ae..606aba8c 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/receiver/ShareActivity.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/receiver/ShareActivity.kt @@ -121,10 +121,10 @@ class ShareActivity : AppCompatActivity() { private fun showDownloadSheet(it: ResultItem){ if (sharedPreferences.getBoolean("download_card", true)){ - val bottomSheet = DownloadBottomSheetDialog(it, DownloadViewModel.Type.video) + val bottomSheet = DownloadBottomSheetDialog(it, DownloadViewModel.Type.valueOf(sharedPreferences.getString("preferred_download_type", "video")!!)) bottomSheet.show(supportFragmentManager, "downloadSingleSheet") }else{ - val downloadItem = downloadViewModel.createDownloadItemFromResult(it, DownloadViewModel.Type.video) + val downloadItem = downloadViewModel.createDownloadItemFromResult(it, DownloadViewModel.Type.valueOf(sharedPreferences.getString("preferred_download_type", "video")!!)) downloadViewModel.queueDownloads(listOf(downloadItem)) this.finish() } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/HomeFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/HomeFragment.kt index 7a74f88d..e4c44d3c 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/HomeFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/HomeFragment.kt @@ -144,7 +144,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, View.OnClickLi }else if (resultViewModel.itemCount.value!! == 1){ if (sharedPreferences!!.getBoolean("download_card", true)){ if(it.size == 1 && !firstBoot && parentFragmentManager.findFragmentByTag("downloadSingleSheet") == null){ - showSingleDownloadSheet(it[0], DownloadViewModel.Type.video) + showSingleDownloadSheet(it[0], DownloadViewModel.Type.valueOf(sharedPreferences!!.getString("preferred_download_type", "video")!!)) } } }else{ diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadBottomSheetDialog.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadBottomSheetDialog.kt index f6054876..1baa6c7d 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadBottomSheetDialog.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadBottomSheetDialog.kt @@ -109,16 +109,18 @@ class DownloadBottomSheetDialog(private val resultItem: ResultItem, private val when(type) { Type.audio -> { - tabLayout.selectTab(tabLayout.getTabAt(0)) + tabLayout.getTabAt(0)!!.select() viewPager2.setCurrentItem(0, false) } Type.video -> { - tabLayout.selectTab(tabLayout.getTabAt(1)) + tabLayout.getTabAt(1)!!.select() viewPager2.setCurrentItem(1, false) } else -> { - tabLayout.selectTab(tabLayout.getTabAt(2)) - viewPager2.setCurrentItem(2, false) + tabLayout.getTabAt(2)!!.select() + viewPager2.postDelayed( { + viewPager2.setCurrentItem(2, false) + }, 200) } } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadCommandFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadCommandFragment.kt index 10da7656..8fa546a2 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadCommandFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadCommandFragment.kt @@ -20,6 +20,7 @@ import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import com.deniscerri.ytdlnis.R +import com.deniscerri.ytdlnis.database.models.CommandTemplate import com.deniscerri.ytdlnis.database.models.DownloadItem import com.deniscerri.ytdlnis.database.models.Format import com.deniscerri.ytdlnis.database.models.ResultItem @@ -68,8 +69,8 @@ class DownloadCommandFragment(private val resultItem: ResultItem) : Fragment() { lifecycleScope.launch { val sharedPreferences = requireContext().getSharedPreferences("root_preferences", Activity.MODE_PRIVATE) try { - val templates = withContext(Dispatchers.IO){ - commandTemplateViewModel.getAll() + val templates : MutableList = withContext(Dispatchers.IO){ + commandTemplateViewModel.getAll().toMutableList() } val id = sharedPreferences.getLong("commandTemplate", templates[0].id) val chosenCommand = templates.find { it.id == id } @@ -117,21 +118,10 @@ class DownloadCommandFragment(private val resultItem: ResultItem) : Fragment() { } } - val templateTitles = templates.map {it.title} - val commandTemplates = view.findViewById(R.id.template) val autoCompleteTextView = - view.findViewById(R.id.template_textview) - autoCompleteTextView?.setAdapter( - ArrayAdapter( - requireContext(), - android.R.layout.simple_dropdown_item_1line, - templateTitles - ) - ) - if (templateTitles.isNotEmpty()) { - autoCompleteTextView!!.setText(downloadItem.format.format_id, false) - } + requireView().findViewById(R.id.template_textview) + populateCommandTemplates(templates, autoCompleteTextView) (commandTemplates!!.editText as AutoCompleteTextView?)!!.onItemClickListener = AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long -> @@ -168,29 +158,40 @@ class DownloadCommandFragment(private val resultItem: ResultItem) : Fragment() { val newTemplate : Chip = view.findViewById(R.id.newTemplate) newTemplate.setOnClickListener { - uiUtil.showCreationSheet(requireActivity(), viewLifecycleOwner, commandTemplateViewModel) { - + uiUtil.showCommandTemplateCreationOrUpdatingSheet(null, requireActivity(), viewLifecycleOwner, commandTemplateViewModel) { + templates.add(it) + chosenCommandView.editText!!.setText(it.content) + downloadItem.format = Format( + it.title, + "", + "", + "", + "", + 0, + it.content + ) + populateCommandTemplates(templates, autoCompleteTextView) } } -// -// val embedSubs = view.findViewById(R.id.embed_subtitles) -// embedSubs!!.isChecked = embedSubs.isChecked -// embedSubs.setOnClickListener { -// downloadItem.embedSubs = embedSubs.isChecked -// } -// -// val addChapters = view.findViewById(R.id.add_chapters) -// addChapters!!.isChecked = addChapters.isChecked -// addChapters.setOnClickListener{ -// downloadItem.addChapters = addChapters.isChecked -// } -// -// val saveThumbnail = view.findViewById(R.id.save_thumbnail) -// saveThumbnail!!.isChecked = saveThumbnail.isChecked -// saveThumbnail.setOnClickListener { -// downloadItem.SaveThumb = saveThumbnail.isChecked -// } + val editSelected : Chip = view.findViewById(R.id.editSelected) + editSelected.setOnClickListener { + var current = templates.find { it.title == autoCompleteTextView.text.toString() } + if (current == null) current = CommandTemplate(0, "", chosenCommandView.editText!!.text.toString()) + uiUtil.showCommandTemplateCreationOrUpdatingSheet(current, requireActivity(), viewLifecycleOwner, commandTemplateViewModel) { + templates.add(it) + chosenCommandView.editText!!.setText(it.content) + downloadItem.format = Format( + it.title, + "", + "", + "", + "", + 0, + it.content + ) + } + } } catch (e: Exception) { e.printStackTrace() @@ -198,6 +199,22 @@ class DownloadCommandFragment(private val resultItem: ResultItem) : Fragment() { } } + private fun populateCommandTemplates(templates: List, autoCompleteTextView: AutoCompleteTextView?){ + val templateTitles = templates.map {it.title} + + + autoCompleteTextView?.setAdapter( + ArrayAdapter( + requireContext(), + android.R.layout.simple_dropdown_item_1line, + templateTitles + ) + ) + if (templateTitles.isNotEmpty()) { + autoCompleteTextView!!.setText(downloadItem.format.format_id, false) + } + } + private var commandPathResultLauncher = registerForActivityResult( ActivityResultContracts.StartActivityForResult() ) { result -> diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadqueue/ErroredDownloadsFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadqueue/ErroredDownloadsFragment.kt index f6d06efe..2b180aba 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadqueue/ErroredDownloadsFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadqueue/ErroredDownloadsFragment.kt @@ -2,6 +2,7 @@ package com.deniscerri.ytdlnis.ui.downloadqueue import android.app.Activity import android.content.DialogInterface +import android.content.Intent import android.content.res.Configuration import android.os.Bundle import android.view.LayoutInflater @@ -23,6 +24,7 @@ import com.deniscerri.ytdlnis.adapter.GenericDownloadAdapter import com.deniscerri.ytdlnis.database.models.DownloadItem import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel 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.UiUtil import com.google.android.material.bottomsheet.BottomSheetDialog @@ -85,7 +87,11 @@ class ErroredDownloadsFragment() : Fragment(), GenericDownloadAdapter.OnItemClic } override fun onActionButtonClick(itemID: Long) { - TODO("Not yet implemented") + 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 intent = Intent(requireContext(), DownloadLogActivity::class.java) + intent.putExtra("path", file.absolutePath) + startActivity(intent) } override fun onCardClick(itemID: Long) { diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/more/CommandTemplatesActivity.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/more/CommandTemplatesActivity.kt index 1886dacd..b923c9bd 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/more/CommandTemplatesActivity.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/more/CommandTemplatesActivity.kt @@ -1,32 +1,27 @@ package com.deniscerri.ytdlnis.ui.more -import android.content.ClipboardManager import android.content.Context +import android.content.DialogInterface import android.os.* -import android.text.Editable -import android.text.TextWatcher import android.view.MenuItem -import android.view.ViewGroup -import android.view.Window import android.widget.* import androidx.appcompat.app.AppCompatActivity -import androidx.appcompat.app.AppCompatDelegate -import androidx.appcompat.content.res.AppCompatResources import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.adapter.TemplatesAdapter import com.deniscerri.ytdlnis.database.models.CommandTemplate -import com.deniscerri.ytdlnis.database.models.TemplateShortcut import com.deniscerri.ytdlnis.database.viewmodel.CommandTemplateViewModel import com.deniscerri.ytdlnis.util.FileUtil import com.deniscerri.ytdlnis.util.UiUtil import com.google.android.material.appbar.MaterialToolbar -import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.chip.Chip -import com.google.android.material.chip.ChipGroup -import com.google.android.material.textfield.TextInputLayout +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext class CommandTemplatesActivity : AppCompatActivity(), TemplatesAdapter.OnItemClickListener { @@ -68,9 +63,19 @@ class CommandTemplatesActivity : AppCompatActivity(), TemplatesAdapter.OnItemCli topAppBar.setOnMenuItemClickListener { m: MenuItem -> val itemId = m.itemId if (itemId == R.id.export_clipboard) { - commandTemplateViewModel.exportToClipboard() + lifecycleScope.launch(Dispatchers.IO){ + commandTemplateViewModel.exportToClipboard() + } }else if (itemId == R.id.import_clipboard){ - commandTemplateViewModel.importFromClipboard() + lifecycleScope.launch{ + withContext(Dispatchers.IO){ + val count = commandTemplateViewModel.importFromClipboard() + runOnUiThread{ + Toast.makeText(this@CommandTemplatesActivity, "$count items imported!", Toast.LENGTH_LONG).show() + } + } + + } } true } @@ -79,7 +84,7 @@ class CommandTemplatesActivity : AppCompatActivity(), TemplatesAdapter.OnItemCli private fun initChips() { val new = findViewById(R.id.newTemplate) new.setOnClickListener { - uiUtil.showCreationSheet(this@CommandTemplatesActivity, this, commandTemplateViewModel) {} + uiUtil.showCommandTemplateCreationOrUpdatingSheet(null,this@CommandTemplatesActivity, this, commandTemplateViewModel) {} } val shortcuts = findViewById(R.id.shortcuts) shortcuts.setOnClickListener { @@ -92,10 +97,21 @@ class CommandTemplatesActivity : AppCompatActivity(), TemplatesAdapter.OnItemCli } override fun onItemClick(commandTemplate: CommandTemplate) { - TODO("Not yet implemented") + uiUtil.showCommandTemplateCreationOrUpdatingSheet(commandTemplate,this@CommandTemplatesActivity, this, commandTemplateViewModel) {} + } override fun onSelected(commandTemplate: CommandTemplate) { TODO("Not yet implemented") } + + override fun onDelete(commandTemplate: CommandTemplate) { + val deleteDialog = MaterialAlertDialogBuilder(this) + 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) + } + deleteDialog.show() + } } \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/more/downloadLogs/DownloadLogActivity.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/more/downloadLogs/DownloadLogActivity.kt index 7cbc7f02..5a519fe6 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/more/downloadLogs/DownloadLogActivity.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/more/downloadLogs/DownloadLogActivity.kt @@ -36,15 +36,13 @@ class DownloadLogActivity : AppCompatActivity() { } content = findViewById(R.id.content) - content.movementMethod = ScrollingMovementMethod() contentScrollView = findViewById(R.id.content_scrollview) copyLog = findViewById(R.id.copy_log) copyLog.setOnClickListener { val clipboard: ClipboardManager = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager - val clip: ClipData = ClipData.newPlainText("Download Log", content.text) - clipboard.setPrimaryClip(clip) + clipboard.setText(content.text) } val path = intent.getStringExtra("path") @@ -60,8 +58,10 @@ class DownloadLogActivity : AppCompatActivity() { observer = object : FileObserver(file.absolutePath, MODIFY) { override fun onEvent(event: Int, p: String?) { runOnUiThread{ - content.text = File(path).readText() + val newText = File(path).readText() + content.text = newText content.scrollTo(0, content.height) + contentScrollView.fullScroll(View.FOCUS_DOWN) } } } @@ -70,7 +70,8 @@ class DownloadLogActivity : AppCompatActivity() { observer = object : FileObserver(file, MODIFY) { override fun onEvent(event: Int, p: String?) { runOnUiThread{ - content.text = File(path).readText() + val newText = File(path).readText() + content.text = newText content.scrollTo(0, content.height) contentScrollView.fullScroll(View.FOCUS_DOWN) } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/more/downloadLogs/DownloadLogListActivity.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/more/downloadLogs/DownloadLogListActivity.kt index a045080d..7bf084cf 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/more/downloadLogs/DownloadLogListActivity.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/more/downloadLogs/DownloadLogListActivity.kt @@ -1,6 +1,7 @@ package com.deniscerri.ytdlnis.ui.more.downloadLogs import android.content.Context +import android.content.DialogInterface import android.content.Intent import android.os.* import android.view.MenuItem @@ -13,6 +14,7 @@ import androidx.recyclerview.widget.RecyclerView import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.adapter.DownloadLogsAdapter import com.google.android.material.appbar.MaterialToolbar +import com.google.android.material.dialog.MaterialAlertDialogBuilder import java.io.File @@ -22,6 +24,7 @@ class DownloadLogListActivity : AppCompatActivity(), DownloadLogsAdapter.OnItemC private lateinit var noResults: RelativeLayout private lateinit var fileList: MutableList private lateinit var topAppBar: MaterialToolbar + private lateinit var logFolder : File var context: Context? = null public override fun onCreate(savedInstanceState: Bundle?) { @@ -43,7 +46,7 @@ class DownloadLogListActivity : AppCompatActivity(), DownloadLogsAdapter.OnItemC noResults = findViewById(R.id.no_results) noResults.visibility = View.GONE - val logFolder = File(filesDir.absolutePath + "/logs") + logFolder = File(filesDir.absolutePath + "/logs") updateList(logFolder) if(Build.VERSION.SDK_INT < 29){ @@ -73,9 +76,18 @@ class DownloadLogListActivity : AppCompatActivity(), DownloadLogsAdapter.OnItemC val itemId = m.itemId if (itemId == R.id.remove_logs) { try{ - logFolder.listFiles()!!.forEach { - it.delete() + val deleteDialog = MaterialAlertDialogBuilder(this) + deleteDialog.setTitle(getString(R.string.confirm_delete_history)) + deleteDialog.setMessage(getString(R.string.confirm_delete_logs_desc)) + deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() } + deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int -> + logFolder.listFiles()!!.forEach { + it.delete() + }.run { + updateList(logFolder) + } } + deleteDialog.show() }catch (e: Exception){ Toast.makeText(context, e.message, Toast.LENGTH_LONG).show() } @@ -113,6 +125,14 @@ class DownloadLogListActivity : AppCompatActivity(), DownloadLogsAdapter.OnItemC } override fun onDeleteClick(file: File) { - file.delete() + val deleteDialog = MaterialAlertDialogBuilder(this) + deleteDialog.setTitle(getString(R.string.you_are_going_to_delete) + " \"" + file.name + "\"!") + deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() } + deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int -> + file.delete().run { + updateList(logFolder) + } + } + deleteDialog.show() } } \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/more/settings/SettingsFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/more/settings/SettingsFragment.kt index ce74cff8..49b934f4 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/more/settings/SettingsFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/more/settings/SettingsFragment.kt @@ -23,6 +23,7 @@ class SettingsFragment : PreferenceFragmentCompat() { private var videoPath: Preference? = null private var commandPath: Preference? = null private var incognito: SwitchPreferenceCompat? = null + private var preferredDownloadType : ListPreference? = null private var downloadCard: SwitchPreferenceCompat? = null private var apiKey: EditTextPreference? = null private var concurrentFragments: SeekBarPreference? = null @@ -64,6 +65,7 @@ class SettingsFragment : PreferenceFragmentCompat() { videoPath = findPreference("video_path") commandPath = findPreference("command_path") incognito = findPreference("incognito") + preferredDownloadType = findPreference("preferred_download_type") downloadCard = findPreference("download_card") apiKey = findPreference("api_key") concurrentFragments = findPreference("concurrent_fragments") @@ -111,6 +113,7 @@ class SettingsFragment : PreferenceFragmentCompat() { editor.putString("command_path", getString(R.string.command_path)) } editor.putBoolean("incognito", incognito!!.isChecked) + editor.putString("preferred_download_type", preferredDownloadType!!.value) editor.putBoolean("download_card", downloadCard!!.isChecked) editor.putString("api_key", apiKey!!.text) editor.putInt("concurrent_fragments", concurrentFragments!!.value) @@ -186,6 +189,13 @@ class SettingsFragment : PreferenceFragmentCompat() { editor.apply() true } + preferredDownloadType!!.onPreferenceChangeListener = + Preference.OnPreferenceChangeListener { _: Preference?, newValue: Any -> + editor.putString("preferred_download_type", newValue.toString()) + editor.apply() + true + } + downloadCard!!.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _: Preference?, newValue: Any -> val enable = newValue as Boolean diff --git a/app/src/main/java/com/deniscerri/ytdlnis/util/UiUtil.kt b/app/src/main/java/com/deniscerri/ytdlnis/util/UiUtil.kt index 034e0297..4ece271f 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/util/UiUtil.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/util/UiUtil.kt @@ -8,7 +8,6 @@ import android.content.Intent import android.net.Uri import android.text.Editable import android.text.TextWatcher -import android.util.Log import android.view.View import android.view.ViewGroup import android.view.Window @@ -18,7 +17,6 @@ import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.content.res.AppCompatResources import androidx.constraintlayout.widget.ConstraintLayout -import androidx.core.content.ContextCompat.getSystemService import androidx.core.content.FileProvider import androidx.lifecycle.LifecycleOwner import com.deniscerri.ytdlnis.R @@ -55,7 +53,7 @@ class UiUtil(private val fileUtil: FileUtil) { } - fun showCreationSheet(context: Activity, lifeCycle: LifecycleOwner, commandTemplateViewModel: CommandTemplateViewModel, newTemplate: (newTemplate: CommandTemplate) -> Unit){ + fun showCommandTemplateCreationOrUpdatingSheet(item: CommandTemplate?, context: Activity, lifeCycle: LifecycleOwner, commandTemplateViewModel: CommandTemplateViewModel, newTemplate: (newTemplate: CommandTemplate) -> Unit){ val bottomSheet = BottomSheetDialog(context) bottomSheet.requestWindowFeature(Window.FEATURE_NO_TITLE) bottomSheet.setContentView(R.layout.create_command_template) @@ -66,7 +64,15 @@ class UiUtil(private val fileUtil: FileUtil) { val shortcutsChipGroup : ChipGroup = bottomSheet.findViewById(R.id.shortcutsChipGroup)!! val editShortcuts : Button = bottomSheet.findViewById(R.id.edit_shortcuts)!! - ok.isEnabled = false + if (item != null){ + title.editText!!.setText(item.title) + content.editText!!.setText(item.content) + bottomSheet.findViewById(R.id.bottom_sheet_subtitle)!!.text = content.resources.getString(R.string.update_template) + ok.text = content.resources.getString(R.string.update) + ok.isEnabled = true + }else{ + ok.isEnabled = false + } title.editText!!.addTextChangedListener(object : TextWatcher { override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {} @@ -91,6 +97,10 @@ class UiUtil(private val fileUtil: FileUtil) { } }) + if (content.editText!!.text.isEmpty()){ + + } + content.setEndIconOnClickListener { if(content.editText!!.text.isEmpty()){ val clipboard: ClipboardManager = @@ -118,9 +128,16 @@ class UiUtil(private val fileUtil: FileUtil) { } ok.setOnClickListener { - val t = CommandTemplate(0, title.editText!!.text.toString(), content.editText!!.text.toString()) - commandTemplateViewModel.insert(t) - newTemplate(t) + if (item == null){ + val t = CommandTemplate(0, title.editText!!.text.toString(), content.editText!!.text.toString()) + commandTemplateViewModel.insert(t) + newTemplate(t) + }else{ + item.title = title.editText!!.text.toString() + item.content = content.editText!!.text.toString() + commandTemplateViewModel.update(item) + newTemplate(item) + } bottomSheet.cancel() } diff --git a/app/src/main/res/drawable/ic_download_type.xml b/app/src/main/res/drawable/ic_download_type.xml index 6c5bd02d..98d5becc 100644 --- a/app/src/main/res/drawable/ic_download_type.xml +++ b/app/src/main/res/drawable/ic_download_type.xml @@ -1,5 +1,5 @@ - + diff --git a/app/src/main/res/layout/activity_download_log.xml b/app/src/main/res/layout/activity_download_log.xml index 63412541..72a9cb2d 100644 --- a/app/src/main/res/layout/activity_download_log.xml +++ b/app/src/main/res/layout/activity_download_log.xml @@ -23,27 +23,34 @@ - + android:layout_height="wrap_content" + android:descendantFocusability="blocksDescendants" + android:orientation="vertical"> - + - + + + + + + app:layout_constraintTop_toTopOf="parent" + android:focusable="true" />