Skip to content

Commit 86cc7cf

Browse files
committed
6.1.0 commit
1 parent f913362 commit 86cc7cf

File tree

152 files changed

+1949
-1516
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

152 files changed

+1949
-1516
lines changed

README.md

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,15 @@ While podcast subscriptions' OPML files (from AntennaPod or any other sources) c
7373
* operations are only on the selected (single or multiple)
7474
* List info is shown in Queue and Downloads views
7575
* Left and right swipe actions on lists now have telltales and can be configured on the spot
76-
* Played episodes have clearer markings
76+
* Played or new episodes have clearer markings
7777
* Sort dialog no longer dims the main view
78+
* download date can be used to sort both feeds and episodes
79+
* Subscriptions sorting is now bi-directional based on various explicit measures
7880
* in episode list view, if episode has no media, TTS button is shown for fetching transcript (if not exist) and then generating audio file from the transcript. TTS audio files are playable in the same way as local media (with speed setting, pause and rewind/forward)
7981
* Long-press filter button in FeedEpisode view enables/disables filters without changing filter settings
80-
* Subscriptions view has various explicit measures for sorting
81-
* subscriptions sorting is now bi-directional
8282
* in Subscriptions view, click on cover image of a feed opens the FeedInfo view (not FeedEpisodes view)
8383
* History view shows time of last play, and allows filters and sorts
84-
* 5 queues are provided by default: Default queue, and Queues 1-4
84+
* Multiple queues can be used: 5 queues are provided by default: Default queue, and Queues 1-4
8585
* all queue operations are on the curQueue, which can be set in all episodes list views
8686
* on app startup, the most recently updated queue is set to curQueue
8787
* queue is circular: if the final item in queue finished, the first item in queue (if exists) will get played
@@ -115,6 +115,18 @@ While podcast subscriptions' OPML files (from AntennaPod or any other sources) c
115115
* It syncs the play states (position and played) of episodes that exist in both devices (ensure to refresh first) and that have been played (completed or not)
116116
* So far, every sync is a full sync, no sync for subscriptions and media files
117117

118+
### Automation
119+
120+
* auto download algorithm is changed to individual feed based.
121+
* When auto download is enabled in the Settings, feeds to be auto-downloaded need to be separately enabled in the feed settings.
122+
* Each feed also has its own download policy (only new episodes, newest episodes, and oldest episodes. "newest episodes" meaning most recent episodes, new or old)
123+
* Each feed has its own limit (Episode cache) for number of episodes downloaded, this limit rules in combination of the overall limit for the app.
124+
* After auto download run, episodes with New status is changed to Unplayed.
125+
* auto download feed setting dialog is also changed:
126+
* there are now separate dialogs for inclusive and exclusive filters where filter tokens can be specified independently
127+
* on exclusive dialog, there are optional check boxes "Exclude episodes shorter than" and "Mark excluded episodes played"
128+
129+
118130
### Security and reliability
119131

120132
* Disabled `usesCleartextTraffic`, so that all content transmission is more private and secure

app/build.gradle

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ android {
115115
checkOnly += ['NewApi', 'InlinedApi', 'Performance', 'DuplicateIds']
116116

117117
disable += ['TypographyDashes', 'TypographyQuotes', 'ObsoleteLintCustomCheck', 'CheckResult', 'UnusedAttribute', 'BatteryLife', 'InflateParams',
118-
'RestrictedApi', 'TrustAllX509TrustManager', 'ExportedReceiver', 'AllowBackup', 'VectorDrawableCompat',
118+
'RestrictedApi', 'TrustAllX509TrustManager', 'ExportedReceiver', 'VectorDrawableCompat',
119119
'StaticFieldLeak', 'UseCompoundDrawables', 'NestedWeights', 'Overdraw', 'UselessParent', 'TextFields',
120120
'AlwaysShowAction', 'Autofill', 'ClickableViewAccessibility', 'ContentDescription',
121121
'KeyboardInaccessibleWidget', 'LabelFor', 'SetTextI18n', 'HardcodedText', 'RelativeOverlap',
@@ -126,8 +126,8 @@ android {
126126
buildConfig true
127127
}
128128
defaultConfig {
129-
versionCode 3020213
130-
versionName "6.0.13"
129+
versionCode 3020214
130+
versionName "6.1.0"
131131

132132
applicationId "ac.mdiq.podcini.R"
133133
def commit = ""

app/src/androidTest/kotlin/ac/test/podcini/EspressoTestUtils.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,12 @@ object EspressoTestUtils {
140140
InstrumentationRegistry.getInstrumentation().targetContext
141141
.getSharedPreferences(MainActivity.PREF_NAME, Context.MODE_PRIVATE)
142142
.edit()
143-
.putBoolean(MainActivity.PREF_IS_FIRST_LAUNCH, false)
143+
.putBoolean(MainActivity.Extras.prefMainActivityIsFirstLaunch.name, false)
144144
.commit()
145145

146146
PreferenceManager.getDefaultSharedPreferences(InstrumentationRegistry.getInstrumentation().targetContext)
147147
.edit()
148-
.putString(UserPreferences.PREF_UPDATE_INTERVAL, "0")
148+
.putString(UserPreferences.Prefs.prefAutoUpdateIntervall.name, "0")
149149
.commit()
150150

151151
RatingDialog.init(InstrumentationRegistry.getInstrumentation().targetContext)
@@ -160,7 +160,7 @@ object EspressoTestUtils {
160160
.commit()
161161
PreferenceManager.getDefaultSharedPreferences(InstrumentationRegistry.getInstrumentation().targetContext)
162162
.edit()
163-
.putString(UserPreferences.PREF_DEFAULT_PAGE, UserPreferences.DEFAULT_PAGE_REMEMBER)
163+
.putString(UserPreferences.Prefs.prefDefaultPage.name, UserPreferences.DEFAULT_PAGE_REMEMBER)
164164
.commit()
165165
}
166166

app/src/androidTest/kotlin/ac/test/podcini/playback/PlaybackTest.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -194,17 +194,17 @@ class PlaybackTest {
194194

195195
protected fun setContinuousPlaybackPreference(value: Boolean) {
196196
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
197-
prefs.edit().putBoolean(UserPreferences.PREF_FOLLOW_QUEUE, value).commit()
197+
prefs.edit().putBoolean(UserPreferences.Prefs.prefFollowQueue.name, value).commit()
198198
}
199199

200200
protected fun setSkipKeepsEpisodePreference(value: Boolean) {
201201
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
202-
prefs.edit().putBoolean(UserPreferences.PREF_SKIP_KEEPS_EPISODE, value).commit()
202+
prefs.edit().putBoolean(UserPreferences.Prefs.prefSkipKeepsEpisode.name, value).commit()
203203
}
204204

205205
protected fun setSmartMarkAsPlayedPreference(smartMarkAsPlayedSecs: Int) {
206206
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
207-
prefs.edit().putString(UserPreferences.PREF_SMART_MARK_AS_PLAYED_SECS,
207+
prefs.edit().putString(UserPreferences.Prefs.prefSmartMarkAsPlayedSecs.name,
208208
smartMarkAsPlayedSecs.toString(10))
209209
.commit()
210210
}

app/src/androidTest/kotlin/ac/test/podcini/storage/AutoDownloadTest.kt

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,22 +39,19 @@ class AutoDownloadTest {
3939
// Setup: enable automatic download
4040
// it is not needed, as the actual automatic download is stubbed.
4141
stubDownloadAlgorithm = StubDownloadAlgorithm()
42-
// setDownloadAlgorithm(stubDownloadAlgorithm!!)
4342
downloadAlgorithm = stubDownloadAlgorithm!!
4443
}
4544

4645
@After
4746
@Throws(Exception::class)
4847
fun tearDown() {
49-
// setDownloadAlgorithm(Episodes.AutomaticDownloadAlgorithm())
5048
downloadAlgorithm = AutoDownloads.AutoDownloadAlgorithm()
5149
EspressoTestUtils.tryKillPlaybackService()
5250
stubFeedsServer!!.tearDown()
5351
}
5452

5553
/**
5654
* A cross-functional test, ensuring playback's behavior works with Auto Download in boundary condition.
57-
*
5855
* Scenario:
5956
* - For setting enqueue location AFTER_CURRENTLY_PLAYING
6057
* - when playback of an episode is complete and the app advances to the next episode (continuous playback on)
@@ -107,7 +104,7 @@ class AutoDownloadTest {
107104
var currentlyPlayingAtDownload: Long = -1
108105
private set
109106

110-
override fun autoDownloadEpisodeMedia(context: Context): Runnable {
107+
override fun autoDownloadEpisodeMediaNew(context: Context): Runnable {
111108
return Runnable {
112109
if (currentlyPlayingAtDownload == -1L) {
113110
// currentlyPlayingAtDownload = currentlyPlayingFeedMediaId

app/src/androidTest/kotlin/ac/test/podcini/ui/FeedSettingsTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class FeedSettingsTest {
3939
uiTestUtils!!.addLocalFeedData(false)
4040
feed = uiTestUtils!!.hostedFeeds[0]
4141
val intent = Intent(InstrumentationRegistry.getInstrumentation().targetContext, MainActivity::class.java)
42-
intent.putExtra(MainActivity.EXTRA_FEED_ID, feed!!.id)
42+
intent.putExtra(MainActivity.Extras.fragment_feed_id.name, feed!!.id)
4343
activityRule.launchActivity(intent)
4444
}
4545

app/src/androidTest/kotlin/ac/test/podcini/ui/PreferencesTest.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@ import ac.mdiq.podcini.preferences.UserPreferences.isAutoDeleteLocal
3232
import ac.mdiq.podcini.preferences.UserPreferences.isEnableAutodownload
3333
import ac.mdiq.podcini.preferences.UserPreferences.isEnableAutodownloadOnBattery
3434
import ac.mdiq.podcini.preferences.UserPreferences.rewindSecs
35-
import ac.mdiq.podcini.preferences.UserPreferences.shouldDeleteRemoveFromQueue
3635
import ac.mdiq.podcini.preferences.UserPreferences.shouldPauseForFocusLoss
3736
import ac.mdiq.podcini.preferences.UserPreferences.showNextChapterOnFullNotification
3837
import ac.mdiq.podcini.preferences.UserPreferences.showPlaybackSpeedOnFullNotification
3938
import ac.mdiq.podcini.preferences.UserPreferences.showSkipOnFullNotification
39+
import ac.mdiq.podcini.storage.database.Episodes.shouldDeleteRemoveFromQueue
4040
import ac.mdiq.podcini.storage.database.Queues
4141
import ac.mdiq.podcini.storage.database.Queues.enqueueLocation
4242
import de.test.podcini.EspressoTestUtils
@@ -65,7 +65,7 @@ class PreferencesTest {
6565
EspressoTestUtils.clearPreferences()
6666
activityTestRule.launchActivity(Intent())
6767
val prefs = PreferenceManager.getDefaultSharedPreferences(activityTestRule.activity)
68-
prefs.edit().putBoolean(UserPreferences.PREF_ENABLE_AUTODL, true).commit()
68+
prefs.edit().putBoolean(UserPreferences.Prefs.prefEnableAutoDl.name, true).commit()
6969

7070
res = activityTestRule.activity.resources
7171
init(activityTestRule.activity)

app/src/main/kotlin/ac/mdiq/podcini/net/download/service/DownloadServiceInterfaceImpl.kt

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import ac.mdiq.podcini.net.sync.model.EpisodeAction
99
import ac.mdiq.podcini.net.sync.queue.SynchronizationQueueSink
1010
import ac.mdiq.podcini.net.utils.NetworkUtils.isAllowMobileEpisodeDownload
1111
import ac.mdiq.podcini.preferences.UserPreferences
12-
import ac.mdiq.podcini.preferences.UserPreferences.PREF_ENQUEUE_DOWNLOADED
1312
import ac.mdiq.podcini.preferences.UserPreferences.appPrefs
1413
import ac.mdiq.podcini.storage.database.Episodes
1514
import ac.mdiq.podcini.storage.database.LogsAndStats
@@ -126,7 +125,7 @@ class DownloadServiceInterfaceImpl : DownloadServiceInterface() {
126125
return workRequest
127126
}
128127
private fun enqueueDownloadedEpisodes(): Boolean {
129-
return appPrefs.getBoolean(PREF_ENQUEUE_DOWNLOADED, true)
128+
return appPrefs.getBoolean(UserPreferences.Prefs.prefEnqueueDownloaded.name, true)
130129
}
131130
}
132131

@@ -291,7 +290,7 @@ class DownloadServiceInterfaceImpl : DownloadServiceInterface() {
291290
// sendMessage(title, false)
292291
// return
293292
// }
294-
val builder = NotificationCompat.Builder(applicationContext, NotificationUtils.CHANNEL_ID_DOWNLOAD_ERROR)
293+
val builder = NotificationCompat.Builder(applicationContext, NotificationUtils.CHANNEL_ID.error.name)
295294
builder.setTicker(applicationContext.getString(R.string.download_report_title))
296295
.setContentTitle(applicationContext.getString(R.string.download_report_title))
297296
.setContentText(applicationContext.getString(R.string.download_error_tap_for_details))
@@ -314,7 +313,7 @@ class DownloadServiceInterfaceImpl : DownloadServiceInterface() {
314313
val bigText = bigTextB.toString().trim { it <= ' ' }
315314
val contentText = if (progressCopy.size == 1) bigText
316315
else applicationContext.resources.getQuantityString(R.plurals.downloads_left, progressCopy.size, progressCopy.size)
317-
val builder = NotificationCompat.Builder(applicationContext, NotificationUtils.CHANNEL_ID_DOWNLOADING)
316+
val builder = NotificationCompat.Builder(applicationContext, NotificationUtils.CHANNEL_ID.downloading.name)
318317
builder.setTicker(applicationContext.getString(R.string.download_notification_title_episodes))
319318
.setContentTitle(applicationContext.getString(R.string.download_notification_title_episodes))
320319
.setContentText(contentText)

app/src/main/kotlin/ac/mdiq/podcini/net/feed/FeedUpdateManager.kt

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,13 @@ import ac.mdiq.podcini.net.download.serviceinterface.DownloadRequest
88
import ac.mdiq.podcini.net.feed.parser.FeedHandler
99
import ac.mdiq.podcini.net.feed.parser.FeedHandlerResult
1010
import ac.mdiq.podcini.net.utils.NetworkUtils.isAllowMobileFeedRefresh
11-
import ac.mdiq.podcini.preferences.UserPreferences
1211
import ac.mdiq.podcini.storage.model.Feed
1312
import ac.mdiq.podcini.util.Logd
1413
import ac.mdiq.podcini.net.utils.NetworkUtils.isFeedRefreshAllowed
1514
import ac.mdiq.podcini.net.utils.NetworkUtils.isNetworkRestricted
1615
import ac.mdiq.podcini.net.utils.NetworkUtils.isVpnOverWifi
1716
import ac.mdiq.podcini.net.utils.NetworkUtils.networkAvailable
18-
import ac.mdiq.podcini.preferences.UserPreferences.PREF_UPDATE_INTERVAL
17+
import ac.mdiq.podcini.preferences.UserPreferences
1918
import ac.mdiq.podcini.preferences.UserPreferences.appPrefs
2019
import ac.mdiq.podcini.storage.algorithms.AutoDownloads.autodownloadEpisodeMedia
2120
import ac.mdiq.podcini.storage.database.Feeds
@@ -66,7 +65,7 @@ object FeedUpdateManager {
6665
const val EXTRA_EVEN_ON_MOBILE: String = "even_on_mobile"
6766

6867
val updateInterval: Long
69-
get() = appPrefs.getString(PREF_UPDATE_INTERVAL, "12")!!.toInt().toLong()
68+
get() = appPrefs.getString(UserPreferences.Prefs.prefAutoUpdateIntervall.name, "12")!!.toInt().toLong()
7069

7170
val isAutoUpdateDisabled: Boolean
7271
get() = updateInterval == 0L
@@ -77,9 +76,8 @@ object FeedUpdateManager {
7776
*/
7877
@JvmStatic
7978
fun restartUpdateAlarm(context: Context, replace: Boolean) {
80-
if (isAutoUpdateDisabled) {
81-
WorkManager.getInstance(context).cancelUniqueWork(WORK_ID_FEED_UPDATE)
82-
} else {
79+
if (isAutoUpdateDisabled) WorkManager.getInstance(context).cancelUniqueWork(WORK_ID_FEED_UPDATE)
80+
else {
8381
val workRequest: PeriodicWorkRequest = PeriodicWorkRequest.Builder(FeedUpdateWorker::class.java, updateInterval, TimeUnit.HOURS)
8482
.setConstraints(Builder()
8583
.setRequiredNetworkType(if (isAllowMobileFeedRefresh) NetworkType.CONNECTED else NetworkType.UNMETERED)
@@ -172,7 +170,8 @@ object FeedUpdateManager {
172170
}
173171
refreshFeeds(toUpdate, force)
174172
notificationManager.cancel(R.id.notification_updating_feeds)
175-
autodownloadEpisodeMedia(applicationContext)
173+
autodownloadEpisodeMedia(applicationContext, toUpdate.toList())
174+
toUpdate.clear()
176175
return Result.success()
177176
}
178177
private fun createNotification(toUpdate: List<Feed?>?): Notification {
@@ -184,7 +183,7 @@ object FeedUpdateManager {
184183
toUpdate.size, toUpdate.size)
185184
bigText = Stream.of(toUpdate).map { feed: Feed? -> "" + feed!!.title }.collect(Collectors.joining("\n"))
186185
}
187-
return NotificationCompat.Builder(context, NotificationUtils.CHANNEL_ID_DOWNLOADING)
186+
return NotificationCompat.Builder(context, NotificationUtils.CHANNEL_ID.downloading.name)
188187
.setContentTitle(context.getString(R.string.download_notification_title_feeds))
189188
.setContentText(contentText)
190189
.setStyle(NotificationCompat.BigTextStyle().bigText(bigText))
@@ -212,10 +211,11 @@ object FeedUpdateManager {
212211
// Toast.makeText(applicationContext, R.string.notification_permission_text, Toast.LENGTH_LONG).show()
213212
return
214213
}
215-
while (toUpdate.isNotEmpty()) {
214+
var i = 0
215+
while (i < toUpdate.size) {
216216
if (isStopped) return
217217
notificationManager.notify(R.id.notification_updating_feeds, createNotification(toUpdate))
218-
val feed = unmanaged(toUpdate[0])
218+
val feed = unmanaged(toUpdate[i++])
219219
try {
220220
Logd(TAG, "updating local feed? ${feed.isLocalFeed} ${feed.title}")
221221
if (feed.isLocalFeed) LocalFeedUpdater.updateFeed(feed, applicationContext, null)
@@ -226,7 +226,7 @@ object FeedUpdateManager {
226226
val status = DownloadResult(feed.id, feed.title?:"", DownloadError.ERROR_IO_ERROR, false, e.message?:"")
227227
LogsAndStats.addDownloadStatus(status)
228228
}
229-
toUpdate.removeAt(0)
229+
// toUpdate.removeAt(0)
230230
}
231231
}
232232
@UnstableApi
@@ -363,8 +363,8 @@ object FeedUpdateManager {
363363
}
364364

365365
class FeedSyncTask(private val context: Context, request: DownloadRequest) {
366-
var savedFeed: Feed? = null
367-
private set
366+
// var savedFeed: Feed? = null
367+
// private set
368368
private val task = FeedParserTask(request)
369369
private var feedHandlerResult: FeedHandlerResult? = null
370370
val downloadStatus: DownloadResult
@@ -375,7 +375,7 @@ object FeedUpdateManager {
375375
fun run(): Boolean {
376376
feedHandlerResult = task.call()
377377
if (!task.isSuccessful) return false
378-
savedFeed = Feeds.updateFeed(context, feedHandlerResult!!.feed, false)
378+
Feeds.updateFeed(context, feedHandlerResult!!.feed, false)
379379
return true
380380
}
381381
}

app/src/main/kotlin/ac/mdiq/podcini/net/feed/discovery/CombinedSearcher.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import kotlinx.coroutines.supervisorScope
88

99
class CombinedSearcher : PodcastSearcher {
1010

11-
override suspend fun search1(query: String): List<PodcastSearchResult?> {
11+
override suspend fun search(query: String): List<PodcastSearchResult?> {
1212
val searchProviders = PodcastSearcherRegistry.searchProviders
1313
val searchResults = MutableList<List<PodcastSearchResult?>?>(searchProviders.size) { null }
1414

@@ -19,7 +19,7 @@ class CombinedSearcher : PodcastSearcher {
1919
if (searchProviderInfo.weight > 0.00001f && searcher.javaClass != CombinedSearcher::class.java) {
2020
async(Dispatchers.IO) {
2121
try {
22-
val results = searcher.search1(query)
22+
val results = searcher.search(query)
2323
searchResults[index] = results
2424
} catch (e: Throwable) {
2525
Log.d(TAG, Log.getStackTraceString(e))
@@ -70,7 +70,7 @@ class CombinedSearcher : PodcastSearcher {
7070
// return PodcastSearcherRegistry.lookupUrl(url)
7171
// }
7272

73-
override suspend fun lookupUrl1(resultUrl: String): String {
73+
override suspend fun lookupUrl(resultUrl: String): String {
7474
return PodcastSearcherRegistry.lookupUrl1(resultUrl)
7575
}
7676

app/src/main/kotlin/ac/mdiq/podcini/net/feed/discovery/FyydPodcastSearcher.kt

Lines changed: 0 additions & 40 deletions
This file was deleted.

0 commit comments

Comments
 (0)