diff --git a/app/src/main/java/com/deniscerri/ytdl/database/dao/ResultDao.kt b/app/src/main/java/com/deniscerri/ytdl/database/dao/ResultDao.kt index cbb8f06f..dcb707b9 100644 --- a/app/src/main/java/com/deniscerri/ytdl/database/dao/ResultDao.kt +++ b/app/src/main/java/com/deniscerri/ytdl/database/dao/ResultDao.kt @@ -67,4 +67,6 @@ interface ResultDao { @Query("SELECT * from results WHERE id > :item1 AND id < :item2 ORDER BY id") fun getResultsBetweenTwoItems(item1: Long, item2: Long) : List + @Query("UPDATE results SET id = :newID where id = :id") + fun updateID(id: Long, newID: Long) } \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdl/database/repository/ResultRepository.kt b/app/src/main/java/com/deniscerri/ytdl/database/repository/ResultRepository.kt index dc63e117..748cdf5e 100644 --- a/app/src/main/java/com/deniscerri/ytdl/database/repository/ResultRepository.kt +++ b/app/src/main/java/com/deniscerri/ytdl/database/repository/ResultRepository.kt @@ -370,6 +370,10 @@ class ResultRepository(private val resultDao: ResultDao, private val commandTemp return resultDao.getAllByIDs(ids) } + fun updateID(id: Long, newID: Long) { + resultDao.updateID(id, newID) + } + suspend fun getResultsFromSource(inputQuery: String, resetResults: Boolean, addToResults: Boolean = true, singleItem: Boolean = false) : List { return when(getQueryType(inputQuery)){ SourceType.YOUTUBE_VIDEO -> { diff --git a/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/ResultViewModel.kt b/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/ResultViewModel.kt index ad3bd482..813acd6e 100644 --- a/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/ResultViewModel.kt +++ b/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/ResultViewModel.kt @@ -26,6 +26,7 @@ import com.deniscerri.ytdl.util.NotificationUtil import com.yausername.youtubedl_android.YoutubeDLException import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.joinAll @@ -383,4 +384,23 @@ class ResultViewModel(private val application: Application) : AndroidViewModel(a fun getStreamingUrlAndChapters(url: String) : Pair, List?> { return repository.getStreamingUrlAndChapters(url) } + + fun reverseResults(resultItems: List): List { + val latestResult = resultItems.max() + val newIdsMap = mutableListOf>() + + var i = 0 + resultItems.reversed().forEach { + newIdsMap.add(Pair(it, latestResult + (++i))) + } + + viewModelScope.launch(Dispatchers.IO) { + delay(1000) + newIdsMap.forEach { + repository.updateID(it.first, it.second) + } + } + + return newIdsMap.map { it.second } + } } \ No newline at end of file diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/downloadcard/SelectPlaylistItemsDialog.kt b/app/src/main/java/com/deniscerri/ytdl/ui/downloadcard/SelectPlaylistItemsDialog.kt index d3d6d07b..ea4190b8 100644 --- a/app/src/main/java/com/deniscerri/ytdl/ui/downloadcard/SelectPlaylistItemsDialog.kt +++ b/app/src/main/java/com/deniscerri/ytdl/ui/downloadcard/SelectPlaylistItemsDialog.kt @@ -232,6 +232,10 @@ class SelectPlaylistItemsDialog : BottomSheetDialogFragment(), PlaylistAdapter.O count.text = "${listAdapter.getCheckedItems().size} ${resources.getString(R.string.selected)}" } } + R.id.reverse -> { + resultItemIDs = resultViewModel.reverseResults(resultItemIDs) + reset() + } } true } @@ -251,7 +255,6 @@ class SelectPlaylistItemsDialog : BottomSheetDialogFragment(), PlaylistAdapter.O toTextInput.isEnabled = !isLoading items = it - resultItemIDs = items.map { itm -> itm.id } } } diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/more/WebViewActivity.kt b/app/src/main/java/com/deniscerri/ytdl/ui/more/WebViewActivity.kt index 95d23fdc..1865951d 100644 --- a/app/src/main/java/com/deniscerri/ytdl/ui/more/WebViewActivity.kt +++ b/app/src/main/java/com/deniscerri/ytdl/ui/more/WebViewActivity.kt @@ -6,7 +6,10 @@ import android.os.Build import android.os.Bundle import android.view.MenuItem import android.webkit.CookieManager +import android.webkit.WebSettings +import android.webkit.WebStorage import android.webkit.WebView +import android.webkit.WebViewDatabase import android.widget.Toast import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding @@ -15,6 +18,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.platform.ComposeView +import androidx.core.view.children import androidx.core.view.forEach import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope @@ -32,6 +36,7 @@ import com.google.accompanist.web.rememberWebViewState import com.google.android.material.appbar.AppBarLayout import com.google.android.material.appbar.MaterialToolbar import com.google.android.material.button.MaterialButton +import com.google.android.material.snackbar.Snackbar import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -57,27 +62,52 @@ class WebViewActivity : BaseActivity() { lifecycleScope.launch { val appbar = findViewById(R.id.webview_appbarlayout) toolbar = appbar.findViewById(R.id.webviewToolbar) - if (!url.isYoutubeURL()) { - toolbar.menu.forEach { it.isVisible = false } - }else { - toolbar.setOnMenuItemClickListener { m : MenuItem -> - when(m.itemId) { - R.id.get_data_sync_id -> { - webView?.evaluateJavascript("ytcfg.get('DATASYNC_ID')") { id -> - UiUtil.copyToClipboard(id.replace("\"", ""), this@WebViewActivity) - } - } - else -> {} - } - true - } - } - - generateBtn = toolbar.findViewById(R.id.generate) webViewCompose = findViewById(R.id.webview_compose) + + if (!url.isYoutubeURL()) { + toolbar.menu.children.firstOrNull { it.itemId == R.id.get_data_sync_id }?.isVisible = false + } + + toolbar.setOnMenuItemClickListener { m : MenuItem -> + when(m.itemId) { + R.id.get_data_sync_id -> { + webView?.evaluateJavascript("ytcfg.get('DATASYNC_ID')") { id -> + UiUtil.copyToClipboard(id.replace("\"", ""), this@WebViewActivity) + } + } + R.id.incognito -> { + m.isChecked = !m.isChecked + webView.apply { + if (this == null) { + m.isChecked = false + return@apply + } + + configureIncognito(this, m.isChecked) + this.reload() + } + } + R.id.desktop -> { + m.isChecked = !m.isChecked + webView.apply { + if (this == null) { + m.isChecked = false + return@apply + } + + configureDesktopMode(this, m.isChecked) + this.reload() + } + } + else -> {} + } + true + } + cookieManager = CookieManager.getInstance() cookieManager.removeAllCookies(null) + cookieManager.flush() preferences = PreferenceManager.getDefaultSharedPreferences(this@WebViewActivity) @@ -134,6 +164,50 @@ class WebViewActivity : BaseActivity() { } + + private fun configureIncognito(webView: WebView, incognito: Boolean) { + if (!incognito) { + webView.settings.run { + cacheMode = WebSettings.LOAD_DEFAULT + domStorageEnabled = true + setGeolocationEnabled(true) + } + }else { + webView.settings.run { + cacheMode = WebSettings.LOAD_NO_CACHE + domStorageEnabled = false + setGeolocationEnabled(false) + } + } + + if (incognito) { + WebStorage.getInstance().deleteAllData() + } + + if (incognito) { + webView.apply { + clearHistory() + clearCache(true) + clearFormData() + } + } + } + + private fun configureDesktopMode(webView: WebView, desktop: Boolean) { + webView.settings.apply { + if (desktop) { + userAgentString = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 " + + "(KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36" + useWideViewPort = true + loadWithOverviewMode = true + } else { + userAgentString = WebSettings.getDefaultUserAgent(webView.context) + useWideViewPort = false + loadWithOverviewMode = false + } + } + } + @SuppressLint("SetJavaScriptEnabled") @Composable fun WebViewView() { diff --git a/app/src/main/res/drawable/baseline_compare_arrows_24.xml b/app/src/main/res/drawable/baseline_compare_arrows_24.xml new file mode 100644 index 00000000..4069595e --- /dev/null +++ b/app/src/main/res/drawable/baseline_compare_arrows_24.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/layout/select_playlist_items.xml b/app/src/main/res/layout/select_playlist_items.xml index 4f76b865..0333bd27 100644 --- a/app/src/main/res/layout/select_playlist_items.xml +++ b/app/src/main/res/layout/select_playlist_items.xml @@ -22,18 +22,23 @@ app:menu="@menu/select_playlist_menu" android:layout_gravity="bottom"> - + app:layout_constraintStart_toEndOf="@id/from_textinput" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="parent" + > - + diff --git a/app/src/main/res/menu/select_playlist_menu.xml b/app/src/main/res/menu/select_playlist_menu.xml index 9b40120c..96259bc9 100644 --- a/app/src/main/res/menu/select_playlist_menu.xml +++ b/app/src/main/res/menu/select_playlist_menu.xml @@ -14,4 +14,11 @@ android:icon="@drawable/ic_terminal" app:showAsAction="never" android:id="@+id/invert_selected"/> + + + \ No newline at end of file diff --git a/app/src/main/res/menu/webview_menu.xml b/app/src/main/res/menu/webview_menu.xml index 8b9a4864..ec539468 100644 --- a/app/src/main/res/menu/webview_menu.xml +++ b/app/src/main/res/menu/webview_menu.xml @@ -1,10 +1,24 @@ + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d54932dd..f6686266 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -480,4 +480,5 @@ Specify the range of items to select PO Token Web Client PO Token + Reverse