6.6.1 commit
This commit is contained in:
parent
7a1f2feac2
commit
efd51ed6e1
|
@ -31,8 +31,8 @@ android {
|
|||
testApplicationId "ac.mdiq.podcini.tests"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
versionCode 3020245
|
||||
versionName "6.6.0"
|
||||
versionCode 3020246
|
||||
versionName "6.6.1"
|
||||
|
||||
applicationId "ac.mdiq.podcini.R"
|
||||
def commit = ""
|
||||
|
|
|
@ -32,6 +32,7 @@ import ac.mdiq.podcini.preferences.UserPreferences
|
|||
import ac.mdiq.podcini.preferences.UserPreferences.appPrefs
|
||||
import ac.mdiq.podcini.preferences.UserPreferences.fastForwardSecs
|
||||
import ac.mdiq.podcini.preferences.UserPreferences.isSkipSilence
|
||||
import ac.mdiq.podcini.preferences.UserPreferences.prefLowQualityMedia
|
||||
import ac.mdiq.podcini.preferences.UserPreferences.rewindSecs
|
||||
import ac.mdiq.podcini.receiver.MediaButtonReceiver
|
||||
import ac.mdiq.podcini.storage.database.Episodes.addToHistory
|
||||
|
@ -1432,7 +1433,7 @@ class PlaybackService : MediaLibraryService() {
|
|||
val streamInfo = StreamInfo.getInfo(vService, url)
|
||||
val audioStreamsList = getFilteredAudioStreams(streamInfo.audioStreams)
|
||||
Logd(TAG, "setDataSource1 audioStreamsList ${audioStreamsList.size}")
|
||||
val audioIndex = if (isNetworkRestricted) 0 else audioStreamsList.size - 1
|
||||
val audioIndex = if (isNetworkRestricted && prefLowQualityMedia) 0 else audioStreamsList.size - 1
|
||||
val audioStream = audioStreamsList[audioIndex]
|
||||
Logd(TAG, "setDataSource1 use audio quality: ${audioStream.bitrate}")
|
||||
val aSource = DefaultMediaSourceFactory(context).createMediaSource(
|
||||
|
|
|
@ -197,6 +197,12 @@ object UserPreferences {
|
|||
appPrefs.edit().putBoolean(Prefs.prefStreamOverDownload.name, stream).apply()
|
||||
}
|
||||
|
||||
var prefLowQualityMedia: Boolean
|
||||
get() = appPrefs.getBoolean(Prefs.prefLowQualityOnMobile.name, false)
|
||||
set(stream) {
|
||||
appPrefs.edit().putBoolean(Prefs.prefLowQualityOnMobile.name, stream).apply()
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the UserPreferences class.
|
||||
* @throws IllegalArgumentException if context is null
|
||||
|
@ -324,6 +330,7 @@ object UserPreferences {
|
|||
prefPauseForFocusLoss,
|
||||
prefPlaybackTimeRespectsSpeed,
|
||||
prefStreamOverDownload,
|
||||
prefLowQualityOnMobile,
|
||||
prefSpeedforwardSpeed,
|
||||
|
||||
// Network
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package ac.mdiq.podcini.storage.database
|
||||
|
||||
import ac.mdiq.podcini.BuildConfig
|
||||
import ac.mdiq.podcini.net.download.DownloadError
|
||||
import ac.mdiq.podcini.net.sync.model.EpisodeAction
|
||||
import ac.mdiq.podcini.net.sync.queue.SynchronizationQueueSink
|
||||
|
@ -20,18 +19,20 @@ import ac.mdiq.podcini.storage.database.RealmDB.upsertBlk
|
|||
import ac.mdiq.podcini.storage.model.*
|
||||
import ac.mdiq.podcini.storage.model.FeedPreferences.AutoDeleteAction
|
||||
import ac.mdiq.podcini.storage.model.FeedPreferences.Companion.TAG_ROOT
|
||||
import ac.mdiq.podcini.storage.model.VolumeAdaptionSetting
|
||||
import ac.mdiq.podcini.storage.utils.FilesUtils.feedfilePath
|
||||
import ac.mdiq.podcini.storage.utils.FilesUtils.getFeedfileName
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
import ac.mdiq.podcini.util.EventFlow
|
||||
import ac.mdiq.podcini.util.FlowEvent
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
import android.app.backup.BackupManager
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import io.realm.kotlin.ext.asFlow
|
||||
import io.realm.kotlin.notifications.*
|
||||
import io.realm.kotlin.notifications.ResultsChange
|
||||
import io.realm.kotlin.notifications.SingleQueryChange
|
||||
import io.realm.kotlin.notifications.UpdatedObject
|
||||
import io.realm.kotlin.notifications.UpdatedResults
|
||||
import kotlinx.coroutines.*
|
||||
import java.io.File
|
||||
import java.text.DateFormat
|
||||
|
@ -241,7 +242,7 @@ object Feeds {
|
|||
""".trimIndent()))
|
||||
continue
|
||||
}
|
||||
var oldItem = EpisodeAssistant.searchEpisodeByIdentifyingValue(savedFeed.episodes, episode)
|
||||
var oldItem = searchEpisodeByIdentifyingValue(savedFeed.episodes, episode)
|
||||
if (!newFeed.isLocalFeed && oldItem == null) {
|
||||
oldItem = EpisodeAssistant.searchEpisodeGuessDuplicate(savedFeed.episodes, episode)
|
||||
if (oldItem != null) {
|
||||
|
@ -299,7 +300,7 @@ object Feeds {
|
|||
val it = savedFeed.episodes.toMutableList().iterator()
|
||||
while (it.hasNext()) {
|
||||
val feedItem = it.next()
|
||||
if (EpisodeAssistant.searchEpisodeByIdentifyingValue(newFeed.episodes, feedItem) == null) {
|
||||
if (searchEpisodeByIdentifyingValue(newFeed.episodes, feedItem) == null) {
|
||||
unlistedItems.add(feedItem)
|
||||
it.remove()
|
||||
}
|
||||
|
@ -442,15 +443,13 @@ object Feeds {
|
|||
if (searchEpisodeByIdentifyingValue(feed.episodes, episode) != null) return
|
||||
|
||||
Logd(TAG, "addToYoutubeSyndicate adding new episode: ${episode.title}")
|
||||
runOnIOScope {
|
||||
episode.feed = feed
|
||||
episode.id = Feed.newId()
|
||||
episode.feedId = feed.id
|
||||
episode.media?.id = episode.id
|
||||
upsert(episode) {}
|
||||
feed.episodes.add(episode)
|
||||
upsert(feed) {}
|
||||
}
|
||||
episode.feed = feed
|
||||
episode.id = Feed.newId()
|
||||
episode.feedId = feed.id
|
||||
episode.media?.id = episode.id
|
||||
upsertBlk(episode) {}
|
||||
feed.episodes.add(episode)
|
||||
upsertBlk(feed) {}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -3,7 +3,6 @@ package ac.mdiq.podcini.ui.activity
|
|||
import ac.mdiq.podcini.R
|
||||
import ac.mdiq.podcini.storage.database.Episodes.episodeFromStreamInfo
|
||||
import ac.mdiq.podcini.storage.database.Feeds.addToYoutubeSyndicate
|
||||
import ac.mdiq.podcini.storage.model.Episode
|
||||
import ac.mdiq.podcini.ui.compose.CustomTheme
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
import ac.mdiq.vista.extractor.Vista
|
||||
|
@ -13,7 +12,6 @@ import android.content.Intent
|
|||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.ViewGroup
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
|
@ -23,7 +21,6 @@ import androidx.compose.material.*
|
|||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
|
@ -32,14 +29,14 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.net.URLDecoder
|
||||
|
||||
class ShareReceiverActivity : AppCompatActivity() {
|
||||
var feedUrl: String? = null
|
||||
|
||||
@OptIn(UnstableApi::class) override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
var feedUrl: String? = null
|
||||
when {
|
||||
intent.hasExtra(ARG_FEEDURL) -> feedUrl = intent.getStringExtra(ARG_FEEDURL)
|
||||
intent.action == Intent.ACTION_SEND -> feedUrl = intent.getStringExtra(Intent.EXTRA_TEXT)
|
||||
|
@ -50,7 +47,7 @@ class ShareReceiverActivity : AppCompatActivity() {
|
|||
showNoPodcastFoundError()
|
||||
return
|
||||
}
|
||||
if (!feedUrl.startsWith("http")) {
|
||||
if (!feedUrl!!.startsWith("http")) {
|
||||
val uri = Uri.parse(feedUrl)
|
||||
val urlString = uri?.getQueryParameter("url")
|
||||
if (urlString != null) feedUrl = URLDecoder.decode(urlString, "UTF-8")
|
||||
|
@ -59,32 +56,26 @@ class ShareReceiverActivity : AppCompatActivity() {
|
|||
when {
|
||||
// plain text
|
||||
feedUrl!!.matches(Regex("^[^\\s<>/]+\$")) -> {
|
||||
val intent = MainActivity.showOnlineSearch(this, feedUrl)
|
||||
val intent = MainActivity.showOnlineSearch(this, feedUrl!!)
|
||||
startActivity(intent)
|
||||
finish()
|
||||
}
|
||||
// Youtube media
|
||||
feedUrl.startsWith("https://youtube.com/watch?") -> {
|
||||
feedUrl!!.startsWith("https://youtube.com/watch?") -> {
|
||||
Logd(TAG, "got youtube media")
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val info = StreamInfo.getInfo(Vista.getService(0), feedUrl)
|
||||
Logd(TAG, "info: $info")
|
||||
val episode = episodeFromStreamInfo(info)
|
||||
Logd(TAG, "episode: $episode")
|
||||
withContext(Dispatchers.Main) {
|
||||
setContent {
|
||||
val showDialog = remember { mutableStateOf(true) }
|
||||
CustomTheme(this@ShareReceiverActivity) {
|
||||
confirmAddEpisode(showDialog.value, episode, onDismissRequest = { showDialog.value = false })
|
||||
}
|
||||
}
|
||||
setContent {
|
||||
val showDialog = remember { mutableStateOf(true) }
|
||||
CustomTheme(this@ShareReceiverActivity) {
|
||||
confirmAddEpisode(showDialog.value, onDismissRequest = {
|
||||
showDialog.value = false
|
||||
finish()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else -> {
|
||||
Logd(TAG, "Activity was started with url $feedUrl")
|
||||
val intent = MainActivity.showOnlineFeed(this, feedUrl)
|
||||
val intent = MainActivity.showOnlineFeed(this, feedUrl!!)
|
||||
// intent.putExtra(MainActivity.Extras.started_from_share.name, getIntent().getBooleanExtra(MainActivity.Extras.started_from_share.name, false))
|
||||
startActivity(intent)
|
||||
finish()
|
||||
|
@ -93,7 +84,7 @@ class ShareReceiverActivity : AppCompatActivity() {
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun confirmAddEpisode(showDialog: Boolean, episode: Episode, onDismissRequest: () -> Unit) {
|
||||
fun confirmAddEpisode(showDialog: Boolean, onDismissRequest: () -> Unit) {
|
||||
if (showDialog) {
|
||||
Dialog(onDismissRequest = { onDismissRequest() }) {
|
||||
Card(
|
||||
|
@ -106,11 +97,11 @@ class ShareReceiverActivity : AppCompatActivity() {
|
|||
modifier = Modifier.padding(16.dp),
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
var checked by remember { mutableStateOf(false) }
|
||||
var audioOnly by remember { mutableStateOf(false) }
|
||||
Row(Modifier.fillMaxWidth()) {
|
||||
Checkbox(checked = checked,
|
||||
Checkbox(checked = audioOnly,
|
||||
onCheckedChange = {
|
||||
checked = it
|
||||
audioOnly = it
|
||||
}
|
||||
)
|
||||
Text(
|
||||
|
@ -119,8 +110,14 @@ class ShareReceiverActivity : AppCompatActivity() {
|
|||
)
|
||||
}
|
||||
Button(onClick = {
|
||||
addToYoutubeSyndicate(episode, !checked)
|
||||
finish()
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val info = StreamInfo.getInfo(Vista.getService(0), feedUrl!!)
|
||||
Logd(TAG, "info: $info")
|
||||
val episode = episodeFromStreamInfo(info)
|
||||
Logd(TAG, "episode: $episode")
|
||||
addToYoutubeSyndicate(episode, !audioOnly)
|
||||
}
|
||||
onDismissRequest()
|
||||
}) {
|
||||
Text("Confirm")
|
||||
}
|
||||
|
|
|
@ -71,6 +71,8 @@ import java.util.concurrent.Semaphore
|
|||
private lateinit var swipeActions: SwipeActions
|
||||
private lateinit var nextPageLoader: MoreContentListFooterUtil
|
||||
|
||||
private var infoTextFiltered = ""
|
||||
private var infoTextUpdate = ""
|
||||
private var displayUpArrow = false
|
||||
private var headerCreated = false
|
||||
private var feedID: Long = 0
|
||||
|
@ -155,6 +157,7 @@ import java.util.concurrent.Semaphore
|
|||
})
|
||||
|
||||
binding.swipeRefresh.setDistanceToTriggerSync(resources.getInteger(R.integer.swipe_refresh_distance))
|
||||
binding.swipeRefresh.setProgressViewEndTarget(false, 0)
|
||||
binding.swipeRefresh.setOnRefreshListener {
|
||||
FeedUpdateManager.runOnceOrAsk(requireContext(), feed)
|
||||
}
|
||||
|
@ -429,6 +432,8 @@ import java.util.concurrent.Semaphore
|
|||
private fun onFeedUpdateRunningEvent(event: FlowEvent.FeedUpdatingEvent) {
|
||||
nextPageLoader.setLoadingState(event.isRunning)
|
||||
if (!event.isRunning) nextPageLoader.root.visibility = View.GONE
|
||||
infoTextUpdate = if (event.isRunning) getString(R.string.refreshing_label) else ""
|
||||
binding.header.txtvInformation.text = ("{gmo-info} $infoTextFiltered $infoTextUpdate")
|
||||
binding.swipeRefresh.isRefreshing = event.isRunning
|
||||
}
|
||||
|
||||
|
@ -454,18 +459,20 @@ import java.util.concurrent.Semaphore
|
|||
|
||||
binding.header.txtvTitle.text = feed!!.title
|
||||
binding.header.txtvAuthor.text = feed!!.author
|
||||
binding.header.txtvInformation.setOnClickListener {}
|
||||
infoTextFiltered = ""
|
||||
if (!feed?.preferences?.filterString.isNullOrEmpty()) {
|
||||
val filter: EpisodeFilter = feed!!.episodeFilter
|
||||
if (filter.values.isNotEmpty()) {
|
||||
binding.header.txtvInformation.text = ("{gmo-info} " + this.getString(R.string.filtered_label))
|
||||
infoTextFiltered = this.getString(R.string.filtered_label)
|
||||
binding.header.txtvInformation.setOnClickListener {
|
||||
val dialog = FeedEpisodeFilterDialog(feed)
|
||||
dialog.filter = feed!!.episodeFilter
|
||||
dialog.show(childFragmentManager, null)
|
||||
}
|
||||
binding.header.txtvInformation.visibility = View.VISIBLE
|
||||
} else binding.header.txtvInformation.visibility = View.GONE
|
||||
} else binding.header.txtvInformation.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
binding.header.txtvInformation.text = ("{gmo-info} $infoTextFiltered $infoTextUpdate")
|
||||
}
|
||||
|
||||
@UnstableApi private fun setupHeaderView() {
|
||||
|
|
|
@ -110,6 +110,8 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener, Selec
|
|||
|
||||
private lateinit var catAdapter: ArrayAdapter<String>
|
||||
|
||||
private var infoTextFiltered = ""
|
||||
private var infoTextUpdate = ""
|
||||
private var tagFilterIndex = 1
|
||||
// TODO: currently not used
|
||||
private var displayedFolder: String = ""
|
||||
|
@ -187,7 +189,8 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener, Selec
|
|||
} else false
|
||||
}
|
||||
|
||||
binding.progressBar.visibility = View.VISIBLE
|
||||
// binding.progressBar.visibility = View.VISIBLE
|
||||
binding.progressBar.visibility = View.GONE
|
||||
|
||||
val subscriptionAddButton: FloatingActionButton = binding.subscriptionsAdd
|
||||
subscriptionAddButton.setOnClickListener {
|
||||
|
@ -218,8 +221,10 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener, Selec
|
|||
private fun setSwipeRefresh() {
|
||||
if (swipeToRefresh) {
|
||||
binding.swipeRefresh.isEnabled = true
|
||||
binding.swipeRefresh.setProgressViewEndTarget(false, 0)
|
||||
binding.swipeRefresh.setDistanceToTriggerSync(resources.getInteger(R.integer.swipe_refresh_distance))
|
||||
binding.swipeRefresh.setOnRefreshListener {
|
||||
Logd(TAG, "running FeedUpdateManager")
|
||||
FeedUpdateManager.runOnceOrAsk(requireContext())
|
||||
}
|
||||
} else binding.swipeRefresh.isEnabled = false
|
||||
|
@ -327,7 +332,9 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener, Selec
|
|||
when (event) {
|
||||
is FlowEvent.FeedUpdatingEvent -> {
|
||||
Logd(TAG, "FeedUpdateRunningEvent: ${event.isRunning}")
|
||||
binding.swipeRefresh.isRefreshing = event.isRunning
|
||||
infoTextUpdate = if (event.isRunning) " " + this@SubscriptionsFragment.getString(R.string.refreshing_label) else ""
|
||||
binding.txtvInformation.text = (infoTextFiltered + infoTextUpdate)
|
||||
if (swipeToRefresh) binding.swipeRefresh.isRefreshing = event.isRunning
|
||||
if (!event.isRunning && event.id != prevFeedUpdatingEvent?.id) loadSubscriptions()
|
||||
prevFeedUpdatingEvent = event
|
||||
}
|
||||
|
@ -377,18 +384,20 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener, Selec
|
|||
// We have fewer items. This can result in items being selected that are no longer visible.
|
||||
if (feedListFiltered.size > feedList.size) adapter.endSelectMode()
|
||||
filterOnTag()
|
||||
binding.progressBar.visibility = View.GONE
|
||||
// binding.progressBar.visibility = View.GONE
|
||||
adapter.setItems(feedListFiltered)
|
||||
binding.count.text = feedListFiltered.size.toString() + " / " + feedList.size.toString()
|
||||
infoTextFiltered = " "
|
||||
binding.txtvInformation.setOnClickListener {}
|
||||
if (feedsFilter.isNotEmpty()) {
|
||||
val filter = FeedFilter(feedsFilter)
|
||||
binding.txtvInformation.text = ("{gmo-info} " + getString(R.string.filtered_label))
|
||||
infoTextFiltered = getString(R.string.filtered_label)
|
||||
binding.txtvInformation.setOnClickListener {
|
||||
val dialog = FeedFilterDialog.newInstance(filter)
|
||||
dialog.show(childFragmentManager, null)
|
||||
}
|
||||
binding.txtvInformation.visibility = View.VISIBLE
|
||||
} else binding.txtvInformation.visibility = View.GONE
|
||||
}
|
||||
binding.txtvInformation.text = (infoTextFiltered + infoTextUpdate)
|
||||
emptyView.updateVisibility()
|
||||
}
|
||||
} catch (e: Throwable) { Log.e(TAG, Log.getStackTraceString(e))
|
||||
|
@ -1187,7 +1196,7 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener, Selec
|
|||
}
|
||||
}
|
||||
|
||||
fun onFilterChanged(newFilterValues: Set<String>) {
|
||||
private fun onFilterChanged(newFilterValues: Set<String>) {
|
||||
feedsFilter = StringUtils.join(newFilterValues, ",")
|
||||
Logd(TAG, "onFilterChanged: $feedsFilter")
|
||||
EventFlow.postEvent(FlowEvent.FeedsFilterEvent(newFilterValues))
|
||||
|
|
|
@ -187,7 +187,6 @@
|
|||
android:padding="2dp"
|
||||
android:background="?android:attr/colorBackground"
|
||||
android:foreground="?android:attr/selectableItemBackground"
|
||||
android:visibility="gone"
|
||||
android:gravity="center"
|
||||
android:textColor="?attr/colorAccent"
|
||||
tools:visibility="visible"
|
||||
|
|
|
@ -50,7 +50,6 @@
|
|||
android:padding="2dp"
|
||||
android:background="?android:attr/colorBackground"
|
||||
android:foreground="?android:attr/selectableItemBackground"
|
||||
android:visibility="gone"
|
||||
android:gravity="center"
|
||||
android:textColor="?attr/colorAccent"
|
||||
tools:visibility="visible"
|
||||
|
|
|
@ -119,6 +119,7 @@
|
|||
<string name="error_label">Error</string>
|
||||
<string name="error_msg_prefix">An error occurred:</string>
|
||||
<string name="refresh_label">Refresh</string>
|
||||
<string name="refreshing_label">Refreshing</string>
|
||||
<string name="reconsile_label">Reconsile</string>
|
||||
<string name="chapters_label">Chapters</string>
|
||||
<string name="no_chapters_label">No chapters</string>
|
||||
|
@ -478,6 +479,8 @@
|
|||
<string name="pref_audio_only_sum">Only play audio of a video media</string>
|
||||
<string name="pref_stream_over_download_title">Prefer streaming</string>
|
||||
<string name="pref_stream_over_download_sum">Display stream button instead of download button in lists</string>
|
||||
<string name="pref_low_quality_on_mobile_title">Prefer low quality on mobile</string>
|
||||
<string name="pref_low_quality_on_mobile_sum">On metered network, only low quality media (if available) is fetched</string>
|
||||
<string name="pref_mobileUpdate_title">Mobile updates</string>
|
||||
<string name="pref_mobileUpdate_sum">Select what should be allowed over the mobile data connection</string>
|
||||
<string name="pref_mobileUpdate_refresh">Podcast refresh</string>
|
||||
|
|
|
@ -57,10 +57,15 @@
|
|||
android:summary="@string/pref_speed_forward_sum"
|
||||
android:title="@string/pref_speed_forward"/>
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="prefStreamOverDownload"
|
||||
android:summary="@string/pref_stream_over_download_sum"
|
||||
android:title="@string/pref_stream_over_download_title"/>
|
||||
android:defaultValue="false"
|
||||
android:key="prefStreamOverDownload"
|
||||
android:summary="@string/pref_stream_over_download_sum"
|
||||
android:title="@string/pref_stream_over_download_title"/>
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="prefLowQualityOnMobile"
|
||||
android:summary="@string/pref_low_quality_on_mobile_sum"
|
||||
android:title="@string/pref_low_quality_on_mobile_title"/>
|
||||
<Preference
|
||||
android:title="@string/pref_playback_video_mode"
|
||||
android:key="prefPlaybackVideoModeLauncher"
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
# 6.6.1
|
||||
|
||||
* the confirm dialog is more responsive when receiving a youtube media share
|
||||
* receiving a youtube media share can be dismissed by not pressing the confirm button
|
||||
* in Subscriptions and FeedEpisodes views, swipe down to refresh no longer blocks UI, only shows "Refreshing" status on the info bar
|
||||
* added preference "Prefer low quality on mobile" under Settings -> Playback -> Playback control, and default it to false,
|
||||
* if set true, Youtube media will use low quality audio on mobile network (which has been the default way of handling)
|
||||
|
||||
# 6.6.0
|
||||
|
||||
* added ability to receive shared Youtube media,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Version 6.5.10:
|
||||
Version 6.6.0:
|
||||
|
||||
* added ability to receive shared Youtube media,
|
||||
* once received, the user can choose to set it as "audio only" before confirm
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
Version 6.6.1:
|
||||
|
||||
* the confirm dialog is more responsive when receiving a youtube media share
|
||||
* receiving a youtube media share can be dismissed by not pressing the confirm button
|
||||
* in Subscriptions and FeedEpisodes views, swipe down to refresh no longer blocks UI, only shows "Refreshing" status on the info bar
|
||||
* added preference "Prefer low quality on mobile" under Settings -> Playback -> Playback control, and default it to false,
|
||||
* if set true, Youtube media will use low quality audio on mobile network (which has been the default way of handling)
|
Loading…
Reference in New Issue