diff --git a/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/HistoryViewModel.kt b/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/HistoryViewModel.kt index 5d271bc3..5b6d4f37 100644 --- a/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/HistoryViewModel.kt +++ b/app/src/main/java/com/deniscerri/ytdl/database/viewmodel/HistoryViewModel.kt @@ -24,6 +24,8 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.buffer import kotlinx.coroutines.flow.cache import kotlinx.coroutines.flow.combine @@ -32,6 +34,7 @@ import kotlinx.coroutines.flow.flattenMerge import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -45,6 +48,21 @@ class HistoryViewModel(application: Application) : AndroidViewModel(application) private val queryFilter = MutableStateFlow("") private val typeFilter = MutableStateFlow("") + var filterCount : StateFlow = combine( + websiteFilter, + statusFilter + ) { website, status -> + val activeFilters = listOf( + website.isNotEmpty(), + status != HistoryStatus.ALL + ) + activeFilters.count { it } + }.stateIn( + scope = viewModelScope, + started = SharingStarted.WhileSubscribed(5000), + initialValue = 0 + ) + enum class HistoryStatus { UNSET, DELETED, NOT_DELETED, ALL } diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/downloadcard/DownloadVideoFragment.kt b/app/src/main/java/com/deniscerri/ytdl/ui/downloadcard/DownloadVideoFragment.kt index 3d8500d1..7fb29bac 100644 --- a/app/src/main/java/com/deniscerri/ytdl/ui/downloadcard/DownloadVideoFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdl/ui/downloadcard/DownloadVideoFragment.kt @@ -324,9 +324,6 @@ class DownloadVideoFragment(private var resultItem: ResultItem? = null, private if (currentDownloadItem == null || !containers.contains(downloadItem.container.ifEmpty { getString(R.string.defaultValue) })){ downloadItem.container = if (containerPreference == getString(R.string.defaultValue)) "" else containerPreference!! } - if (downloadItem.videoPreferences.compatibilityMode) { - container.editText?.setText("mkv") - } containerAutoCompleteTextView!!.setText( downloadItem.container.ifEmpty { getString(R.string.defaultValue) }, false) @@ -347,7 +344,9 @@ class DownloadVideoFragment(private var resultItem: ResultItem? = null, private downloadItem.videoPreferences.recodeVideo = false } } - + if (downloadItem.videoPreferences.compatibilityMode) { + containerAutoCompleteTextView.setText("mkv",false) + } view.findViewById(R.id.adjust).apply { visibility = if (shownFields.contains("adjust_video")) View.VISIBLE else View.GONE if (isVisible){ diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/downloads/HistoryFragment.kt b/app/src/main/java/com/deniscerri/ytdl/ui/downloads/HistoryFragment.kt index 811b672e..63b5f793 100644 --- a/app/src/main/java/com/deniscerri/ytdl/ui/downloads/HistoryFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdl/ui/downloads/HistoryFragment.kt @@ -34,6 +34,7 @@ import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController +import androidx.paging.PagingData import androidx.preference.PreferenceManager import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.ItemTouchHelper @@ -48,8 +49,10 @@ import com.deniscerri.ytdl.database.repository.HistoryRepository import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel import com.deniscerri.ytdl.database.viewmodel.HistoryViewModel import com.deniscerri.ytdl.ui.adapter.HistoryPaginatedAdapter +import com.deniscerri.ytdl.util.Extensions.createBadge import com.deniscerri.ytdl.util.Extensions.enableFastScroll import com.deniscerri.ytdl.util.Extensions.toListString +import com.deniscerri.ytdl.util.Extensions.updateMenuItemBadge import com.deniscerri.ytdl.util.FileUtil import com.deniscerri.ytdl.util.NavbarUtil import com.deniscerri.ytdl.util.UiUtil @@ -143,6 +146,12 @@ class HistoryFragment : Fragment(), HistoryPaginatedAdapter.OnItemClickListener{ } } + lifecycleScope.launch { + historyViewModel.filterCount.collectLatest { + topAppBar.updateMenuItemBadge(R.id.filters, it) + } + } + lifecycleScope.launch { historyViewModel.websites.collectLatest { if(it.isEmpty()) { @@ -288,6 +297,7 @@ class HistoryFragment : Fragment(), HistoryPaginatedAdapter.OnItemClickListener{ deleteDialog.setMessage(getString(R.string.confirm_delete_history_desc)) deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() } deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int -> + historyAdapter.submitData(lifecycle, PagingData.empty()) historyViewModel.clearDeleted() } deleteDialog.show() @@ -302,6 +312,7 @@ class HistoryFragment : Fragment(), HistoryPaginatedAdapter.OnItemClickListener{ deleteDialog.setMessage(getString(R.string.confirm_delete_history_desc)) deleteDialog.setNegativeButton(getString(R.string.cancel)) { dialogInterface: DialogInterface, _: Int -> dialogInterface.cancel() } deleteDialog.setPositiveButton(getString(R.string.ok)) { _: DialogInterface?, _: Int -> + historyAdapter.submitData(lifecycle, PagingData.empty()) historyViewModel.deleteDuplicates() } deleteDialog.show() diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/advanced/generateyoutubepotokens/GenerateYoutubePoTokensFragment.kt b/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/advanced/generateyoutubepotokens/GenerateYoutubePoTokensFragment.kt index 139264de..3ab4c8c7 100644 --- a/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/advanced/generateyoutubepotokens/GenerateYoutubePoTokensFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/advanced/generateyoutubepotokens/GenerateYoutubePoTokensFragment.kt @@ -224,7 +224,7 @@ class GenerateYoutubePoTokensFragment : Fragment() { val intent = Intent(requireContext(), PoTokenWebViewLoginActivity::class.java) intent.putExtra("url", "https://www.youtube.com") - //intent.putExtra("redirect_url", "https://www.youtube.com/embed/${editText.text.toString().getIDFromYoutubeURL()}") + intent.putExtra("redirect_url", "https://www.youtube.com/embed/${editText.text.toString().getIDFromYoutubeURL()}") intent.putExtra("no_auth", true) webPoTokenResultLauncher.launch(intent) } diff --git a/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/advanced/generateyoutubepotokens/webview/PoTokenWebViewLoginActivity.kt b/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/advanced/generateyoutubepotokens/webview/PoTokenWebViewLoginActivity.kt index db2c4d03..f11caadb 100644 --- a/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/advanced/generateyoutubepotokens/webview/PoTokenWebViewLoginActivity.kt +++ b/app/src/main/java/com/deniscerri/ytdl/ui/more/settings/advanced/generateyoutubepotokens/webview/PoTokenWebViewLoginActivity.kt @@ -11,7 +11,6 @@ import android.view.MenuItem import android.webkit.CookieManager import android.webkit.WebChromeClient import android.webkit.WebSettings -import android.webkit.WebStorage import android.webkit.WebView import android.webkit.WebViewClient import android.widget.Toast @@ -25,7 +24,6 @@ import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.viewinterop.AndroidView import androidx.core.view.children -import androidx.core.view.forEach import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import androidx.preference.PreferenceManager @@ -35,10 +33,6 @@ import com.deniscerri.ytdl.database.viewmodel.CookieViewModel import com.deniscerri.ytdl.ui.BaseActivity import com.deniscerri.ytdl.util.UiUtil import com.deniscerri.ytdl.util.extractors.newpipe.potoken.NewPipePoTokenGenerator -import com.google.accompanist.web.AccompanistWebChromeClient -import com.google.accompanist.web.AccompanistWebViewClient -import com.google.accompanist.web.WebView -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 @@ -127,29 +121,32 @@ class PoTokenWebViewLoginActivity : BaseActivity() { } - //update cookies - withContext(Dispatchers.IO) { - val cookieURL = "Po Token Generated Cookies" - cookiesViewModel.getCookiesFromDB(cookieURL).getOrNull()?.let { - kotlin.runCatching { - cookiesViewModel.insert( - CookieItem( - 0, - cookieURL, - it, - "", - true + + if (!noAuth) { + //update cookies + withContext(Dispatchers.IO) { + val cookieURL = "Po Token Generated Cookies" + cookiesViewModel.getCookiesFromDB(cookieURL).getOrNull()?.let { + kotlin.runCatching { + cookiesViewModel.insert( + CookieItem( + 0, + cookieURL, + it, + "", + true + ) ) - ) - cookiesViewModel.updateCookiesFile() - preferences.edit().putBoolean("use_cookies", true).apply() - }.onFailure { - withContext(Dispatchers.Main) { - Toast.makeText( - this@PoTokenWebViewLoginActivity, - "Tokens were generated but cookies were not updated", - Toast.LENGTH_SHORT - ).show() + cookiesViewModel.updateCookiesFile() + preferences.edit().putBoolean("use_cookies", true).apply() + }.onFailure { + withContext(Dispatchers.Main) { + Toast.makeText( + this@PoTokenWebViewLoginActivity, + "Tokens were generated but cookies were not updated", + Toast.LENGTH_SHORT + ).show() + } } } } @@ -169,7 +166,10 @@ class PoTokenWebViewLoginActivity : BaseActivity() { if (value?.trim('"') == "complete") { Handler(Looper.getMainLooper()).postDelayed({ redirectUrl?.apply { - webView.loadUrl(this) + val extraHeaders: MutableMap = + HashMap() + extraHeaders["Referer"] = url + webView.loadUrl(this, extraHeaders) } redirectUrl = null }, 2500) diff --git a/app/src/main/java/com/deniscerri/ytdl/util/Extensions.kt b/app/src/main/java/com/deniscerri/ytdl/util/Extensions.kt index f4535e29..dbe75d08 100644 --- a/app/src/main/java/com/deniscerri/ytdl/util/Extensions.kt +++ b/app/src/main/java/com/deniscerri/ytdl/util/Extensions.kt @@ -21,6 +21,7 @@ import android.text.Spanned import android.text.TextWatcher import android.util.DisplayMetrics import android.util.TypedValue +import android.view.MenuItem import android.view.MotionEvent import android.view.View import android.view.ViewGroup @@ -33,6 +34,7 @@ import android.widget.ScrollView import android.widget.TextView import androidx.annotation.OptIn import androidx.annotation.Px +import androidx.appcompat.widget.Toolbar import androidx.core.content.ContextCompat import androidx.core.graphics.drawable.DrawableCompat import androidx.core.text.HtmlCompat @@ -46,6 +48,7 @@ import com.deniscerri.ytdl.database.models.DownloadItem import com.deniscerri.ytdl.database.models.observeSources.ObserveSourcesItem import com.deniscerri.ytdl.database.repository.DownloadRepository import com.deniscerri.ytdl.database.repository.ObserveSourcesRepository.EveryCategory +import com.google.android.material.appbar.MaterialToolbar import com.google.android.material.badge.BadgeDrawable import com.google.android.material.badge.BadgeUtils import com.google.android.material.badge.ExperimentalBadgeUtils @@ -67,7 +70,9 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch import kotlinx.serialization.json.Json import me.zhanghai.android.fastscroll.FastScrollerBuilder +import org.json.JSONArray import org.json.JSONObject +import org.json.JSONTokener import java.io.File import java.net.HttpCookie import java.util.Calendar @@ -257,9 +262,9 @@ object Extensions { runCatching { val tmp = this.getString(it) if (tmp != "null") { - return if (tmp.startsWith("[") && tmp.endsWith("]")) { + return try { Json.decodeFromString>(tmp).joinToString(", ") - }else{ + } catch (e: Exception) { tmp } } @@ -324,6 +329,25 @@ object Extensions { } } + @OptIn(ExperimentalBadgeUtils::class) + fun MaterialToolbar.updateMenuItemBadge(menuItemId: Int, nr: Int) { + this.findViewById(menuItemId).overlay.clear() + + val badge = BadgeDrawable.create(context).apply { + number = nr + backgroundColor = ContextCompat.getColor(context, R.color.white) + badgeTextColor = ContextCompat.getColor(context, R.color.black) + verticalOffset = dpToPx(resources, 4f) + horizontalOffset = dpToPx(resources, 4f) + } + + if (nr > 0) { + BadgeUtils.attachBadgeDrawable(badge, this, menuItemId) + } else { + BadgeUtils.detachBadgeDrawable(badge, this, menuItemId) + } + } + fun TabLayout.Tab.createBadge(nr: Int){ removeBadge() if (nr > 0) { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e8862f0e..3250f718 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -509,5 +509,5 @@ App Icon Show option to download immediately in the share menu Don\'t fetch data - Hook + Hook/Greetings