From 26ea19ab8cfa76ac12cba9f0053dbf3a462393ae Mon Sep 17 00:00:00 2001 From: deniscerri <64997243+deniscerri@users.noreply.github.com> Date: Sat, 29 Jul 2023 14:00:14 +0200 Subject: [PATCH] CHANGELOG - I think i fixed pausing and resuming multiple downloads since it was doing some funky stuff - added rewind button - fixed play button appearing in cut section when the video is playing - fixed add extra command not working in the command template edit screen - removed "Downloading" word in the preferences screen. Its Downloads now - Show terminal preference was reversed so now its in correct behaviour - Fixed share card not showing up - Added embed metadata preference. Turning it off will remove any embedding metadata and parsing metadata commands --- app/build.gradle | 6 +- .../ytdlnis/adapter/ActiveDownloadAdapter.kt | 6 +- .../adapter/ActiveDownloadMinifiedAdapter.kt | 6 +- .../ytdlnis/adapter/TemplatesAdapter.kt | 2 +- .../ytdlnis/database/dao/DownloadDao.kt | 6 +- .../database/repository/DownloadRepository.kt | 2 +- .../database/viewmodel/DownloadViewModel.kt | 2 +- .../ytdlnis/receiver/ShareActivity.kt | 7 +- .../downloadcard/CutVideoBottomSheetDialog.kt | 49 +++++-- .../DownloadMultipleBottomSheetDialog.kt | 2 + .../downloadcard/ResultCardDetailsDialog.kt | 36 +++-- .../SelectPlaylistItemsBottomSheetDialog.kt | 9 +- .../ui/downloads/ActiveDownloadsFragment.kt | 65 ++++++--- .../ui/downloads/QueuedDownloadsFragment.kt | 4 +- .../more/settings/DownloadSettingsFragment.kt | 2 +- .../more/settings/GeneralSettingsFragment.kt | 5 +- .../com/deniscerri/ytdlnis/util/InfoUtil.kt | 103 ++++++++----- .../com/deniscerri/ytdlnis/util/UiUtil.kt | 24 +++- .../res/drawable/baseline_video_metadata.xml | 7 + app/src/main/res/drawable/thumb.xml | 1 + app/src/main/res/drawable/thumb_drawable.xml | 2 + .../res/layout-sw600dp-land/fragment_home.xml | 5 +- .../main/res/layout-sw600dp/fragment_home.xml | 6 +- .../res/layout-sw950dp-land/fragment_home.xml | 6 +- .../res/layout/create_command_template.xml | 3 +- app/src/main/res/layout/cut_video_sheet.xml | 22 ++- .../layout/extra_commands_bottom_sheet.xml | 135 ++++++++++-------- app/src/main/res/layout/fragment_active.xml | 5 - app/src/main/res/layout/fragment_home.xml | 2 + app/src/main/res/layout/fragment_inqueue.xml | 9 +- app/src/main/res/values/arrays.xml | 1 + app/src/main/res/values/strings.xml | 2 + app/src/main/res/xml/locales_config.xml | 1 + .../main/res/xml/processing_preferences.xml | 13 ++ 34 files changed, 362 insertions(+), 194 deletions(-) create mode 100644 app/src/main/res/drawable/baseline_video_metadata.xml diff --git a/app/build.gradle b/app/build.gradle index 8f687d6b..7055416b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,7 +10,7 @@ def properties = new Properties() def versionMajor = 1 def versionMinor = 6 def versionPatch = 3 -def versionBuild = 13 // bump for dogfood builds, public betas, etc. +def versionBuild = 15 // bump for dogfood builds, public betas, etc. def versionExt = "" if (versionBuild > 0){ @@ -148,8 +148,8 @@ dependencies { implementation "androidx.constraintlayout:constraintlayout:2.1.4" implementation 'com.google.android.material:material:1.9.0-rc01' implementation 'androidx.legacy:legacy-support-v4:1.0.0' - implementation 'androidx.recyclerview:recyclerview:1.3.0' - implementation 'androidx.preference:preference:1.2.0' + implementation 'androidx.recyclerview:recyclerview:1.3.1' + implementation 'androidx.preference:preference:1.2.1' implementation "androidx.navigation:navigation-fragment-ktx:$navVer" implementation "androidx.navigation:navigation-ui-ktx:$navVer" implementation 'androidx.core:core-ktx:1.10.1' diff --git a/app/src/main/java/com/deniscerri/ytdlnis/adapter/ActiveDownloadAdapter.kt b/app/src/main/java/com/deniscerri/ytdlnis/adapter/ActiveDownloadAdapter.kt index 23c9c942..c7deb943 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/adapter/ActiveDownloadAdapter.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/adapter/ActiveDownloadAdapter.kt @@ -147,10 +147,10 @@ class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity: pauseButton.setOnClickListener { if (pauseButton.tag == ActiveDownloadAction.Pause){ - onItemClickListener.onPauseClick(item.id, ActiveDownloadAction.Pause) + onItemClickListener.onPauseClick(item.id, ActiveDownloadAction.Pause, position) }else{ - onItemClickListener.onPauseClick(item.id, ActiveDownloadAction.Resume) + onItemClickListener.onPauseClick(item.id, ActiveDownloadAction.Resume, position) } } @@ -158,7 +158,7 @@ class ActiveDownloadAdapter(onItemClickListener: OnItemClickListener, activity: } interface OnItemClickListener { fun onCancelClick(itemID: Long) - fun onPauseClick(itemID: Long, action: ActiveDownloadAction) + fun onPauseClick(itemID: Long, action: ActiveDownloadAction, position: Int) fun onOutputClick(item: DownloadItem) } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/adapter/ActiveDownloadMinifiedAdapter.kt b/app/src/main/java/com/deniscerri/ytdlnis/adapter/ActiveDownloadMinifiedAdapter.kt index 86b8b5b0..bac3a682 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/adapter/ActiveDownloadMinifiedAdapter.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/adapter/ActiveDownloadMinifiedAdapter.kt @@ -132,13 +132,13 @@ class ActiveDownloadMinifiedAdapter(onItemClickListener: OnItemClickListener, ac pauseButton.setOnClickListener { if (pauseButton.tag == ActiveDownloadAdapter.ActiveDownloadAction.Pause){ - onItemClickListener.onPauseClick(item.id, ActiveDownloadAdapter.ActiveDownloadAction.Pause) + 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) + 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 @@ -152,7 +152,7 @@ class ActiveDownloadMinifiedAdapter(onItemClickListener: OnItemClickListener, ac } interface OnItemClickListener { fun onCancelClick(itemID: Long) - fun onPauseClick(itemID: Long, action: ActiveDownloadAdapter.ActiveDownloadAction) + fun onPauseClick(itemID: Long, action: ActiveDownloadAdapter.ActiveDownloadAction, position: Int) fun onCardClick() } 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 9912dbcf..906a8490 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/adapter/TemplatesAdapter.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/adapter/TemplatesAdapter.kt @@ -73,7 +73,7 @@ class TemplatesAdapter(onItemClickListener: OnItemClickListener, activity: Activ } override fun areContentsTheSame(oldItem: CommandTemplate, newItem: CommandTemplate): Boolean { - return oldItem.title == newItem.title && oldItem.content == newItem.content + return oldItem.title == newItem.title && oldItem.content == newItem.content && oldItem.useAsExtraCommand == newItem.useAsExtraCommand } } } 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 0dd77f13..15550964 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 @@ -19,13 +19,13 @@ interface DownloadDao { @Query("SELECT * FROM downloads WHERE status='Active' or status='Paused'") fun getActiveDownloadsList() : List - @Query("SELECT * FROM downloads WHERE status='Active' or status='Queued' or status='Paused'") + @Query("SELECT * FROM downloads WHERE status='Active' or status='Queued' or status='QueuedPaused' or status='Paused'") fun getActiveAndQueuedDownloadsList() : List - @Query("SELECT * FROM downloads WHERE status='Queued' ORDER BY downloadStartTime, id") + @Query("SELECT * FROM downloads WHERE status='Queued' or status='QueuedPaused' ORDER BY downloadStartTime, id") fun getQueuedDownloads() : Flow> - @Query("SELECT * FROM downloads WHERE status='Queued' ORDER BY downloadStartTime, id") + @Query("SELECT * FROM downloads WHERE status='Queued' or status='QueuedPaused' ORDER BY downloadStartTime, id") fun getQueuedDownloadsList() : List @Query("SELECT * FROM downloads WHERE status='Cancelled' ORDER BY id DESC") diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/repository/DownloadRepository.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/repository/DownloadRepository.kt index 17620bec..87c695c7 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/database/repository/DownloadRepository.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/database/repository/DownloadRepository.kt @@ -16,7 +16,7 @@ class DownloadRepository(private val downloadDao: DownloadDao) { val savedDownloads : Flow> = downloadDao.getSavedDownloads() enum class Status { - Active, Paused, Queued, Error, Cancelled, Saved + Active, Paused, Queued, QueuedPaused, Error, Cancelled, Saved } suspend fun insert(item: DownloadItem) : Long { diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/DownloadViewModel.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/DownloadViewModel.kt index fa8c6793..7454e6ca 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/DownloadViewModel.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/DownloadViewModel.kt @@ -148,7 +148,7 @@ class DownloadViewModel(application: Application) : AndroidViewModel(application repository.delete(item) } - fun updateDownload(item: DownloadItem) = viewModelScope.launch(Dispatchers.IO){ + suspend fun updateDownload(item: DownloadItem){ repository.update(item) } 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 1c332cd7..8255ff22 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/receiver/ShareActivity.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/receiver/ShareActivity.kt @@ -51,10 +51,7 @@ class ShareActivity : BaseActivity() { private lateinit var sharedPreferences: SharedPreferences private var quickDownload by Delegates.notNull() - override fun onPause() { - super.onPause() - finishAndRemoveTask() - } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -108,6 +105,8 @@ class ShareActivity : BaseActivity() { return } + runCatching { supportFragmentManager.popBackStack() } + quickDownload = intent.getBooleanExtra("quick_download", sharedPreferences.getBoolean("quick_download", false)) val loadingBottomSheet = BottomSheetDialog(this) diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/CutVideoBottomSheetDialog.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/CutVideoBottomSheetDialog.kt index 519d0c8d..6d2056a7 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/CutVideoBottomSheetDialog.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/CutVideoBottomSheetDialog.kt @@ -19,6 +19,7 @@ import androidx.lifecycle.lifecycleScope import androidx.media3.common.AudioAttributes import androidx.media3.common.C import androidx.media3.common.MediaItem.fromUri +import androidx.media3.common.Player import androidx.media3.datasource.DefaultDataSource import androidx.media3.datasource.cronet.CronetDataSource import androidx.media3.exoplayer.DefaultLoadControl @@ -33,6 +34,7 @@ import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.database.models.ChapterItem import com.deniscerri.ytdlnis.database.models.DownloadItem import com.deniscerri.ytdlnis.util.InfoUtil +import com.deniscerri.ytdlnis.util.UiUtil.setTextAndRecalculateWidth import com.deniscerri.ytdlnis.util.VideoPlayerUtil import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialogFragment @@ -68,6 +70,7 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private var urls private lateinit var durationText: TextView private lateinit var progress : ProgressBar private lateinit var pauseBtn : MaterialButton + private lateinit var rewindBtn : MaterialButton private lateinit var muteBtn : MaterialButton private lateinit var rangeSlider : RangeSlider private lateinit var fromTextInput : TextInputLayout @@ -119,6 +122,7 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private var urls durationText.text = "" progress = view.findViewById(R.id.progress) pauseBtn = view.findViewById(R.id.pause) + rewindBtn = view.findViewById(R.id.rewind) muteBtn = view.findViewById(R.id.mute) rangeSlider = view.findViewById(R.id.rangeSlider) fromTextInput = view.findViewById(R.id.from_textinput) @@ -211,14 +215,23 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private var urls } } + player.addListener(object : Player.Listener { + override fun onIsPlayingChanged(isPlaying: Boolean) { + if (isPlaying){ + pauseBtn.visibility = View.GONE + }else{ + pauseBtn.visibility = View.VISIBLE + } + super.onIsPlayingChanged(isPlaying) + } + }) + videoView.setOnClickListener { if (player.isPlaying){ player.pause() - pauseBtn.visibility = View.VISIBLE } else { player.play() - pauseBtn.visibility = View.GONE } } @@ -232,12 +245,22 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private var urls } } + rewindBtn.setOnClickListener { + try { + val seconds = convertStringToTimestamp(fromTextInput.editText!!.text.toString()) + val endTimestamp = (rangeSlider.valueTo.toInt() * timeSeconds) / 100 + val startValue = (seconds.toFloat() / endTimestamp) * 100 + player.seekTo((((startValue * timeSeconds) / 100) * 1000).toLong()) + player.play() + }catch (ignored: Exception) {} + } + } @SuppressLint("SetTextI18n") private fun initCutSection(){ - fromTextInput.editText!!.setText("0:00") - toTextInput.editText!!.setText(item.duration) + fromTextInput.editText!!.setTextAndRecalculateWidth("0:00") + toTextInput.editText!!.setTextAndRecalculateWidth(item.duration) rangeSlider.addOnSliderTouchListener(object : RangeSlider.OnSliderTouchListener { override fun onStartTrackingTouch(slider: RangeSlider) { @@ -252,8 +275,8 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private var urls val startTimestampString = infoUtil.formatIntegerDuration(startTimestamp, Locale.US) val endTimestampString = infoUtil.formatIntegerDuration(endTimestamp, Locale.US) - fromTextInput.editText!!.setText(startTimestampString) - toTextInput.editText!!.setText(endTimestampString) + fromTextInput.editText!!.setTextAndRecalculateWidth(startTimestampString) + toTextInput.editText!!.setTextAndRecalculateWidth(endTimestampString) okBtn.isEnabled = !(values[0] == 0F && values[1] == 100F) @@ -282,9 +305,9 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private var urls val endValue = (endSeconds.toFloat() / endTimestamp) * 100 if (seconds == 0) { - fromTextInput.editText!!.setText(infoUtil.formatIntegerDuration(startTimestamp, Locale.US)) + fromTextInput.editText!!.setTextAndRecalculateWidth(infoUtil.formatIntegerDuration(startTimestamp, Locale.US)) }else if (startValue > 100){ - fromTextInput.editText!!.setText(infoUtil.formatIntegerDuration(startTimestamp, Locale.US)) + fromTextInput.editText!!.setTextAndRecalculateWidth(infoUtil.formatIntegerDuration(startTimestamp, Locale.US)) } rangeSlider.setValues(startValue, endValue) @@ -318,9 +341,9 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private var urls val endValue = (seconds.toFloat() / endTimestamp) * 100 if (seconds == 0) { - toTextInput.editText!!.setText(infoUtil.formatIntegerDuration(endTimestamp, Locale.US)) + toTextInput.editText!!.setTextAndRecalculateWidth(infoUtil.formatIntegerDuration(endTimestamp, Locale.US)) }else if (endValue > 100 || endValue <= rangeSlider.valueFrom.toInt()){ - toTextInput.editText!!.setText(infoUtil.formatIntegerDuration(endTimestamp, Locale.US)) + toTextInput.editText!!.setTextAndRecalculateWidth(infoUtil.formatIntegerDuration(endTimestamp, Locale.US)) } rangeSlider.setValues(startValue, endValue) @@ -520,8 +543,10 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private var urls private fun videoProgress(player: ExoPlayer?) = flow { while (true) { - emit((player!!.currentPosition / 1000).toInt()) - delay(1000) + runCatching { + emit((player!!.currentPosition / 1000).toInt()) + delay(1000) + } } }.flowOn(Dispatchers.Main) diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadMultipleBottomSheetDialog.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadMultipleBottomSheetDialog.kt index c64118a1..af0d4883 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadMultipleBottomSheetDialog.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/DownloadMultipleBottomSheetDialog.kt @@ -88,6 +88,8 @@ class DownloadMultipleBottomSheetDialog(private var results: List, val view = LayoutInflater.from(context).inflate(R.layout.download_multiple_bottom_sheet, null) dialog.setContentView(view) + if (items.isEmpty()) dismiss() + dialog.setOnShowListener { behavior = BottomSheetBehavior.from(view.parent as View) val displayMetrics = DisplayMetrics() diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/ResultCardDetailsDialog.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/ResultCardDetailsDialog.kt index cabf37f7..c2b720be 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/ResultCardDetailsDialog.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/ResultCardDetailsDialog.kt @@ -61,6 +61,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext +import java.text.FieldPosition import java.text.SimpleDateFormat import java.util.* @@ -324,7 +325,9 @@ class ResultCardDetailsDialog(private val item: ResultItem) : BottomSheetDialogF deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() } deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int -> item.status = DownloadRepository.Status.Cancelled.toString() - downloadViewModel.updateDownload(item) + lifecycleScope.launch(Dispatchers.IO){ + downloadViewModel.updateDownload(item) + } Snackbar.make(requireView().rootView, getString(R.string.cancelled) + ": " + item.title, Snackbar.LENGTH_LONG) .setAction(getString(R.string.undo)) { @@ -533,19 +536,30 @@ class ResultCardDetailsDialog(private val item: ResultItem) : BottomSheetDialogF override fun onCancelClick(itemID: Long) { cancelActiveDownload(itemID) } - override fun onPauseClick(itemID: Long, action: ActiveDownloadAdapter.ActiveDownloadAction) { + override fun onPauseClick(itemID: Long, action: ActiveDownloadAdapter.ActiveDownloadAction, position: Int) { val item = activeItems.find { it.id == itemID } ?: return when(action){ ActiveDownloadAdapter.ActiveDownloadAction.Pause -> { - cancelItem(itemID.toInt()) - item.status = DownloadRepository.Status.Paused.toString() - downloadViewModel.updateDownload(item) + lifecycleScope.launch { + cancelItem(itemID.toInt()) + item.status = DownloadRepository.Status.Paused.toString() + withContext(Dispatchers.IO){ + downloadViewModel.updateDownload(item) + } + activeDownloads.notifyItemChanged(position) + } } ActiveDownloadAdapter.ActiveDownloadAction.Resume -> { - item.status = DownloadRepository.Status.Active.toString() - downloadViewModel.updateDownload(item) - runBlocking { - downloadViewModel.queueDownloads(listOf(item)) + lifecycleScope.launch { + item.status = DownloadRepository.Status.Active.toString() + withContext(Dispatchers.IO){ + downloadViewModel.updateDownload(item) + } + activeDownloads.notifyItemChanged(position) + + runBlocking { + downloadViewModel.queueDownloads(listOf(item)) + } } } } @@ -572,7 +586,9 @@ class ResultCardDetailsDialog(private val item: ResultItem) : BottomSheetDialogF activeItems.find { it.id == itemID }?.let { it.status = DownloadRepository.Status.Cancelled.toString() - downloadViewModel.updateDownload(it) + lifecycleScope.launch(Dispatchers.IO){ + downloadViewModel.updateDownload(it) + } } } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/SelectPlaylistItemsBottomSheetDialog.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/SelectPlaylistItemsBottomSheetDialog.kt index 5b6d6a3b..5a57603e 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/SelectPlaylistItemsBottomSheetDialog.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/SelectPlaylistItemsBottomSheetDialog.kt @@ -22,6 +22,7 @@ import com.deniscerri.ytdlnis.database.models.ResultItem import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel import com.deniscerri.ytdlnis.database.viewmodel.ResultViewModel import com.deniscerri.ytdlnis.receiver.ShareActivity +import com.deniscerri.ytdlnis.util.UiUtil.setTextAndRecalculateWidth import com.google.android.material.bottomappbar.BottomAppBar import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialogFragment @@ -120,8 +121,8 @@ class SelectPlaylistItemsBottomSheetDialog(private val items: List, val checkAll = view.findViewById(R.id.check_all) checkAll!!.setOnClickListener { if (listAdapter.getCheckedItems().size != items.size){ - fromTextInput.editText!!.setText("1") - toTextInput.editText!!.setText(items.size.toString()) + fromTextInput.editText!!.setTextAndRecalculateWidth("1") + toTextInput.editText!!.setTextAndRecalculateWidth(items.size.toString()) listAdapter.checkAll() fromTextInput.isEnabled = true toTextInput.isEnabled = true @@ -130,8 +131,8 @@ class SelectPlaylistItemsBottomSheetDialog(private val items: List, reset() fromTextInput.isEnabled = true toTextInput.isEnabled = true - fromTextInput.editText!!.setText("") - toTextInput.editText!!.setText("") + fromTextInput.editText!!.setTextAndRecalculateWidth("") + toTextInput.editText!!.setTextAndRecalculateWidth("") } } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/ActiveDownloadsFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/ActiveDownloadsFragment.kt index bc4381fb..a8dbeb39 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/ActiveDownloadsFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/ActiveDownloadsFragment.kt @@ -1,17 +1,12 @@ package com.deniscerri.ytdlnis.ui.downloads -import android.annotation.SuppressLint import android.app.Activity import android.os.Bundle import android.view.LayoutInflater -import android.view.MotionEvent import android.view.View import android.view.View.OnClickListener import android.view.ViewGroup import android.widget.TextView -import androidx.core.content.ContextCompat -import androidx.core.view.allViews -import androidx.core.view.children import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope @@ -27,10 +22,10 @@ import com.deniscerri.ytdlnis.database.viewmodel.DownloadViewModel import com.deniscerri.ytdlnis.util.NotificationUtil import com.deniscerri.ytdlnis.util.UiUtil.forceFastScrollMode import com.google.android.material.button.MaterialButton -import com.google.android.material.card.MaterialCardView import com.google.android.material.progressindicator.LinearProgressIndicator import com.yausername.youtubedl_android.YoutubeDL import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext @@ -80,15 +75,21 @@ class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickLis if (pauseResume.text == requireContext().getString(R.string.pause)){ lifecycleScope.launch { - runBlocking { - val queued = withContext(Dispatchers.IO){ - downloadViewModel.getQueued() - } - queued.forEach { - WorkManager.getInstance(requireContext()).cancelUniqueWork(it.id.toString()) + val queued = withContext(Dispatchers.IO){ + downloadViewModel.getQueued() + } + + queued.forEach { + it.status = DownloadRepository.Status.QueuedPaused.toString() + runBlocking { + downloadViewModel.updateDownload(it) } } + queued.forEach { + WorkManager.getInstance(requireContext()).cancelUniqueWork(it.id.toString()) + } + list.forEach { cancelItem(it.id.toInt()) it.status = DownloadRepository.Status.Paused.toString() @@ -108,6 +109,7 @@ class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickLis val queuedItems = withContext(Dispatchers.IO){ downloadViewModel.getQueued() } + queuedItems.map { it.status = DownloadRepository.Status.Queued.toString() } toQueue.addAll(queuedItems) runBlocking { downloadViewModel.queueDownloads(toQueue) @@ -163,19 +165,38 @@ class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickLis cancelDownload(itemID) } - override fun onPauseClick(itemID: Long, action: ActiveDownloadAdapter.ActiveDownloadAction) { + override fun onPauseClick(itemID: Long, action: ActiveDownloadAdapter.ActiveDownloadAction, position: Int) { val item = list.find { it.id == itemID } ?: return when(action){ ActiveDownloadAdapter.ActiveDownloadAction.Pause -> { - cancelItem(itemID.toInt()) - item.status = DownloadRepository.Status.Paused.toString() - downloadViewModel.updateDownload(item) + lifecycleScope.launch { + cancelItem(itemID.toInt()) + item.status = DownloadRepository.Status.Paused.toString() + withContext(Dispatchers.IO){ + downloadViewModel.updateDownload(item) + } + activeDownloads.notifyItemChanged(position) + } } ActiveDownloadAdapter.ActiveDownloadAction.Resume -> { - item.status = DownloadRepository.Status.Active.toString() - downloadViewModel.updateDownload(item) - runBlocking { - downloadViewModel.queueDownloads(listOf(item)) + lifecycleScope.launch { + item.status = DownloadRepository.Status.Active.toString() + withContext(Dispatchers.IO){ + downloadViewModel.updateDownload(item) + } + activeDownloads.notifyItemChanged(position) + + val queue = if (list.size > 1) listOf(item) + else withContext(Dispatchers.IO){ + val list = downloadViewModel.getQueued().toMutableList() + list.map { it.status = DownloadRepository.Status.Queued.toString() } + list.add(0, item) + list + } + + runBlocking { + downloadViewModel.queueDownloads(queue) + } } } } @@ -203,7 +224,9 @@ class ActiveDownloadsFragment : Fragment(), ActiveDownloadAdapter.OnItemClickLis cancelItem(itemID.toInt()) list.find { it.id == itemID }?.let { it.status = DownloadRepository.Status.Cancelled.toString() - downloadViewModel.updateDownload(it) + lifecycleScope.launch(Dispatchers.IO){ + downloadViewModel.updateDownload(it) + } } } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/QueuedDownloadsFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/QueuedDownloadsFragment.kt index 64e46331..f7ef4f74 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/QueuedDownloadsFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/QueuedDownloadsFragment.kt @@ -279,7 +279,9 @@ class QueuedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLi deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() } deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int -> item.status = DownloadRepository.Status.Cancelled.toString() - downloadViewModel.updateDownload(item) + lifecycleScope.launch(Dispatchers.IO){ + downloadViewModel.updateDownload(item) + } Snackbar.make(queuedRecyclerView, getString(R.string.cancelled) + ": " + item.title, Snackbar.LENGTH_LONG) .setAction(getString(R.string.undo)) { diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/more/settings/DownloadSettingsFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/more/settings/DownloadSettingsFragment.kt index 250c2743..a0aa274b 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/more/settings/DownloadSettingsFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/more/settings/DownloadSettingsFragment.kt @@ -15,7 +15,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder class DownloadSettingsFragment : BaseSettingsFragment() { - override val title: Int = R.string.downloading + override val title: Int = R.string.downloads private var concurrentDownloads: SeekBarPreference? = null private var ignoreBatteryOptimization: Preference? = null diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/more/settings/GeneralSettingsFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/more/settings/GeneralSettingsFragment.kt index 33dd9c49..31ba4e4c 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/more/settings/GeneralSettingsFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/more/settings/GeneralSettingsFragment.kt @@ -115,14 +115,13 @@ class GeneralSettingsFragment : BaseSettingsFragment() { Preference.OnPreferenceChangeListener { pref: Preference?, _: Any -> val packageManager = requireContext().packageManager val aliasComponentName = ComponentName(requireContext(), "com.deniscerri.ytdlnis.terminalShareAlias") - if ((pref as SwitchPreferenceCompat).isChecked){ packageManager.setComponentEnabledSetting(aliasComponentName, - PackageManager.COMPONENT_ENABLED_STATE_ENABLED, + PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP) }else{ packageManager.setComponentEnabledSetting(aliasComponentName, - PackageManager.COMPONENT_ENABLED_STATE_DISABLED, + PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP) } true diff --git a/app/src/main/java/com/deniscerri/ytdlnis/util/InfoUtil.kt b/app/src/main/java/com/deniscerri/ytdlnis/util/InfoUtil.kt index 82bcc014..26c6f40b 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/util/InfoUtil.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/util/InfoUtil.kt @@ -75,7 +75,7 @@ class InfoUtil(private val context: Context) { val element = dataArray.getJSONObject(i) if (element.getInt("duration") == -1) continue element.put("uploader", element.getString("uploaderName")) - val v = createVideoFromPipedJSON(element, element.getString("url").removePrefix("/watch?v=")) + val v = createVideoFromPipedJSON(element, "https://youtube.com" + element.getString("url")) if (v == null || v.thumb.isEmpty()) { continue } @@ -93,7 +93,7 @@ class InfoUtil(private val context: Context) { val element = dataArray.getJSONObject(i) if (element.getInt("duration") == -1) continue element.put("uploader", element.getString("uploaderName")) - val v = createVideoFromPipedJSON(element, element.getString("url").removePrefix("/watch?v=")) + val v = createVideoFromPipedJSON(element, "https://youtube.com" + element.getString("url")) if (v == null || v.thumb.isEmpty()) { continue } @@ -118,7 +118,7 @@ class InfoUtil(private val context: Context) { var nextpage = res.getString("nextpage") for (i in 0 until dataArray.length()){ val obj = dataArray.getJSONObject(i) - val itm = createVideoFromPipedJSON(obj, obj.getString("url").removePrefix("/watch?v=")) + val itm = createVideoFromPipedJSON(obj, "https://youtube.com" + obj.getString("url")) itm?.playlistTitle = "YTDLnis" items.add(itm) } @@ -137,9 +137,7 @@ class InfoUtil(private val context: Context) { return try { val id = getIDFromYoutubeURL(url) val res = genericRequest("$pipedURL/streams/$id") - if (res.length() == 0) getFromYTDL(url) else listOf(createVideoFromPipedJSON( - res, url - )) + if (res.length() == 0) getFromYTDL(url) else listOf(createVideoFromPipedJSON(res, url)) }catch (e: Exception){ val v = getFromYTDL(url) v.forEach { it!!.url = url } @@ -176,7 +174,6 @@ class InfoUtil(private val context: Context) { private fun createVideoFromPipedJSON(obj: JSONObject, url: String): ResultItem? { var video: ResultItem? = null try { - val id = getIDFromYoutubeURL(url) val title = Html.fromHtml(obj.getString("title").toString()).toString() val author = try { @@ -399,7 +396,7 @@ class InfoUtil(private val context: Context) { val element = res.getJSONObject(i) if (element.getInt("duration") < 0) continue element.put("uploader", element.getString("uploaderName")) - val v = createVideoFromPipedJSON(element, element.getString("url").removePrefix("/watch?v=")) + val v = createVideoFromPipedJSON(element, "https://youtube.com" + element.getString("url")) if (v == null || v.thumb.isEmpty()) continue v.playlistTitle = context.getString(R.string.trendingPlaylist) items.add(v) @@ -410,7 +407,7 @@ class InfoUtil(private val context: Context) { return items } - fun getIDFromYoutubeURL(inputQuery: String) : String { + private fun getIDFromYoutubeURL(inputQuery: String) : String { var el: Array = inputQuery.split("/".toRegex()).dropLastWhile { it.isEmpty() } .toTypedArray() @@ -437,7 +434,7 @@ class InfoUtil(private val context: Context) { val id = getIDFromYoutubeURL(url) val res = genericRequest("$pipedURL/streams/$id") if (res.length() == 0) getFromYTDL(url)[0]!! - val item = createVideoFromPipedJSON(res, id) + val item = createVideoFromPipedJSON(res, "https://youtube.com/watch?v=$id") item!!.formats }else{ getFormatsFromYTDL(url) @@ -507,11 +504,16 @@ class InfoUtil(private val context: Context) { request.addOption("--skip-download") request.addOption("-R", "1") request.addOption("--socket-timeout", "5") - val cookiesFile = File(context.cacheDir, "cookies.txt") - if (cookiesFile.exists()){ - request.addOption("--cookies", cookiesFile.absolutePath) + + + if (sharedPreferences.getBoolean("use_cookies", false)){ + val cookiesFile = File(context.cacheDir, "cookies.txt") + if (cookiesFile.exists()){ + request.addOption("--cookies", cookiesFile.absolutePath) + } } + val proxy = sharedPreferences.getString("proxy", "") if (proxy!!.isNotBlank()){ request.addOption("--proxy", proxy) @@ -535,7 +537,7 @@ class InfoUtil(private val context: Context) { urls.forEach { val id = getIDFromYoutubeURL(it) val res = genericRequest("$pipedURL/streams/$id") - val vid = createVideoFromPipedJSON(res, id) + val vid = createVideoFromPipedJSON(res, it) progress(vid!!.formats) } } @@ -566,11 +568,15 @@ class InfoUtil(private val context: Context) { request.addOption("-R", "1") request.addOption("--socket-timeout", "5") - val cookiesFile = File(context.cacheDir, "cookies.txt") - if (cookiesFile.exists()){ - request.addOption("--cookies", cookiesFile.absolutePath) + if (sharedPreferences.getBoolean("use_cookies", false)){ + val cookiesFile = File(context.cacheDir, "cookies.txt") + if (cookiesFile.exists()){ + request.addOption("--cookies", cookiesFile.absolutePath) + } } + + val proxy = sharedPreferences.getString("proxy", "") if (proxy!!.isNotBlank()){ request.addOption("--proxy", proxy) @@ -715,11 +721,15 @@ class InfoUtil(private val context: Context) { request.addOption("-R", "1") request.addOption("--socket-timeout", "5") - val cookiesFile = File(context.cacheDir, "cookies.txt") - if (cookiesFile.exists()){ - request.addOption("--cookies", cookiesFile.absolutePath) + if (sharedPreferences.getBoolean("use_cookies", false)){ + val cookiesFile = File(context.cacheDir, "cookies.txt") + if (cookiesFile.exists()){ + request.addOption("--cookies", cookiesFile.absolutePath) + } } + + val proxy = sharedPreferences.getString("proxy", "") if (proxy!!.isNotBlank()){ request.addOption("--proxy", proxy) @@ -861,7 +871,7 @@ class InfoUtil(private val context: Context) { val m = p.matcher(url) if (m.find()){ - return getStreamingUrlAndChaptersFromPIPED(getIDFromYoutubeURL(url)) + return getStreamingUrlAndChaptersFromPIPED(url) }else{ throw Exception() } @@ -874,11 +884,15 @@ class InfoUtil(private val context: Context) { request.addOption("-R", "1") request.addOption("--socket-timeout", "5") - val cookiesFile = File(context.cacheDir, "cookies.txt") - if (cookiesFile.exists()){ - request.addOption("--cookies", cookiesFile.absolutePath) + if (sharedPreferences.getBoolean("use_cookies", false)){ + val cookiesFile = File(context.cacheDir, "cookies.txt") + if (cookiesFile.exists()){ + request.addOption("--cookies", cookiesFile.absolutePath) + } } + + val proxy = sharedPreferences.getString("proxy", "") if (proxy!!.isNotBlank()){ request.addOption("--proxy", proxy) @@ -898,12 +912,13 @@ class InfoUtil(private val context: Context) { } } - private fun getStreamingUrlAndChaptersFromPIPED(id: String) : MutableList { + private fun getStreamingUrlAndChaptersFromPIPED(url: String) : MutableList { + val id = getIDFromYoutubeURL(url) val res = genericRequest("$pipedURL/streams/$id") if (res.length() == 0) { throw Exception() }else{ - val item = createVideoFromPipedJSON(res, id) + val item = createVideoFromPipedJSON(res, url) if (item!!.urls.isBlank()) throw Exception() val list = mutableListOf(Gson().toJson(item.chapters)) list.addAll(item.urls.split(",")) @@ -974,6 +989,7 @@ class InfoUtil(private val context: Context) { request.addCommands(listOf("--replace-in-metadata","uploader",".*.",downloadItem.author.take(25))) } request.addCommands(listOf("--replace-in-metadata","uploader"," - Topic$","")) + downloadItem.customFileNameTemplate = downloadItem.customFileNameTemplate.replace("%(uploader)s", "%(uploader|${downloadItem.author})s") if (downloadItem.downloadSections.isNotBlank()){ @@ -1015,9 +1031,11 @@ class InfoUtil(private val context: Context) { request.addOption("--restrict-filenames") } - val cookiesFile = File(context.cacheDir, "cookies.txt") - if (cookiesFile.exists()){ - request.addOption("--cookies", cookiesFile.absolutePath) + if (sharedPreferences.getBoolean("use_cookies", false)){ + val cookiesFile = File(context.cacheDir, "cookies.txt") + if (cookiesFile.exists()){ + request.addOption("--cookies", cookiesFile.absolutePath) + } } val proxy = sharedPreferences.getString("proxy", "") @@ -1055,7 +1073,20 @@ class InfoUtil(private val context: Context) { request.addOption("--split-chapters") request.addOption("-o", "chapter:%(section_title)s.%(ext)s") }else{ - request.addOption("--embed-metadata") + + if (sharedPreferences.getBoolean("embed_metadata", true)){ + request.addOption("--embed-metadata") + + request.addOption("--parse-metadata", "%(release_year,upload_date)s:%(meta_date)s") + + if (downloadItem.playlistTitle.isNotEmpty()) { + request.addOption("--parse-metadata", "%(album,playlist,title)s:%(meta_album)s") + request.addOption("--parse-metadata", "%(track_number,playlist_index)d:%(meta_track)s") + } else { + request.addOption("--parse-metadata", "%(album,title)s:%(meta_album)s") + } + } + if (downloadItem.audioPreferences.embedThumb) { request.addOption("--embed-thumbnail") @@ -1072,14 +1103,6 @@ class InfoUtil(private val context: Context) { } } } - request.addOption("--parse-metadata", "%(release_year,upload_date)s:%(meta_date)s") - - if (downloadItem.playlistTitle.isNotEmpty()) { - request.addOption("--parse-metadata", "%(album,playlist,title)s:%(meta_album)s") - request.addOption("--parse-metadata", "%(track_number,playlist_index)d:%(meta_track)s") - } else { - request.addOption("--parse-metadata", "%(album,title)s:%(meta_album)s") - } if (downloadItem.customFileNameTemplate.isNotBlank()){ request.addOption("-o", "${downloadItem.customFileNameTemplate}.%(ext)s") @@ -1090,6 +1113,10 @@ class InfoUtil(private val context: Context) { DownloadViewModel.Type.video -> { val supportedContainers = context.resources.getStringArray(R.array.video_containers) + if (!sharedPreferences.getBoolean("embed_metadata", true)){ + request.addOption("--no-embed-metadata") + } + if (downloadItem.videoPreferences.addChapters) { request.addOption("--sponsorblock-mark", "all") request.addOption("--embed-chapters") 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 84a62603..2918b4b5 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/util/UiUtil.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/util/UiUtil.kt @@ -32,7 +32,6 @@ import androidx.core.content.FileProvider import androidx.core.widget.doOnTextChanged import androidx.fragment.app.FragmentManager import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.RecyclerView import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.database.models.CommandTemplate @@ -53,7 +52,6 @@ import com.google.android.material.textfield.TextInputLayout import com.google.android.material.timepicker.MaterialTimePicker import com.google.android.material.timepicker.TimeFormat import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.io.File import java.util.Calendar @@ -105,7 +103,7 @@ object UiUtil { val ok : Button = bottomSheet.findViewById(R.id.template_create)!! val title : TextInputLayout = bottomSheet.findViewById(R.id.title)!! val content : TextInputLayout = bottomSheet.findViewById(R.id.content)!! - val extraCommandsSwitch : MaterialSwitch = bottomSheet.findViewById(R.id.extra_command_switch)!! + val extraCommandsSwitch : MaterialSwitch = bottomSheet.findViewById(R.id.extraCommandsSwitch)!! val shortcutsChipGroup : ChipGroup = bottomSheet.findViewById(R.id.shortcutsChipGroup)!! val editShortcuts : Button = bottomSheet.findViewById(R.id.edit_shortcuts)!! @@ -154,7 +152,9 @@ object UiUtil { } } - extraCommandsSwitch.isChecked = item!!.useAsExtraCommand + if (item != null){ + extraCommandsSwitch.isChecked = item.useAsExtraCommand + } commandTemplateViewModel.shortcuts.observe(lifeCycle){ shortcutsChipGroup.removeAllViews() @@ -180,6 +180,7 @@ object UiUtil { }else{ item.title = title.editText!!.text.toString() item.content = content.editText!!.text.toString() + item.useAsExtraCommand = extraCommandsSwitch.isChecked Log.e("aa", item.toString()) commandTemplateViewModel.update(item) newTemplate(item) @@ -559,4 +560,19 @@ object UiUtil { false } } + + + fun EditText.setTextAndRecalculateWidth(t : String){ + this.setText(t) + val widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED) + val heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED) + this.measure(widthMeasureSpec, heightMeasureSpec) + val requiredWidth: Int = this.measuredWidth + if (t.isEmpty()){ + this.layoutParams.width = 70 + }else{ + this.layoutParams.width = requiredWidth + } + this.requestLayout() + } } \ No newline at end of file diff --git a/app/src/main/res/drawable/baseline_video_metadata.xml b/app/src/main/res/drawable/baseline_video_metadata.xml new file mode 100644 index 00000000..977f487a --- /dev/null +++ b/app/src/main/res/drawable/baseline_video_metadata.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/app/src/main/res/drawable/thumb.xml b/app/src/main/res/drawable/thumb.xml index 6ffd3a03..6dc405ed 100644 --- a/app/src/main/res/drawable/thumb.xml +++ b/app/src/main/res/drawable/thumb.xml @@ -1,6 +1,7 @@ + diff --git a/app/src/main/res/drawable/thumb_drawable.xml b/app/src/main/res/drawable/thumb_drawable.xml index 162eddc4..7ace2332 100644 --- a/app/src/main/res/drawable/thumb_drawable.xml +++ b/app/src/main/res/drawable/thumb_drawable.xml @@ -1,8 +1,10 @@ \ No newline at end of file diff --git a/app/src/main/res/layout-sw600dp-land/fragment_home.xml b/app/src/main/res/layout-sw600dp-land/fragment_home.xml index b153d663..03e6f16e 100644 --- a/app/src/main/res/layout-sw600dp-land/fragment_home.xml +++ b/app/src/main/res/layout-sw600dp-land/fragment_home.xml @@ -36,6 +36,8 @@ android:id="@+id/providers" android:layout_margin="10dp" app:chipSpacingVertical="-10dp" + android:paddingStart="0dp" + android:paddingEnd="20dp" app:singleSelection="true" android:layout_width="wrap_content" android:layout_height="wrap_content" @@ -166,7 +168,6 @@ app:layoutManager="androidx.recyclerview.widget.GridLayoutManager" /> - + + - - - + @@ -147,7 +149,6 @@ - - + + + + + @@ -154,7 +172,7 @@ - + android:layout_height="wrap_content" + android:fillViewport="true"> - - - - - - - + android:orientation="vertical"> + android:scrollbars="none" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + + + + + + + + app:layout_constraintTop_toBottomOf="@+id/scr"> + + +