Skip to content

Commit

Permalink
6.0.1 commit
Browse files Browse the repository at this point in the history
  • Loading branch information
XilinJia committed Jun 24, 2024
1 parent 2a66e7f commit 393063a
Show file tree
Hide file tree
Showing 23 changed files with 283 additions and 279 deletions.
25 changes: 19 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,12 @@ Compared to AntennaPod this project:
1. Migrated all media routines to `androidx.media3`, with `AudioOffloadMode` enabled, nicer to device battery,
2. Is purely `Kotlin` based and mono-modular, and targets Android 14,
3. Iron-age celebrity SQLite is replaced with modern object-base Realm DB
4. Outfits with Viewbinding, Coil replacing Glide, coroutines replacing RxJava and threads, and SharedFlow replacing EventBus,
5. Boasts new UI's including streamlined drawer, subscriptions view and player controller,
6. Accepts podcast as well as plain RSS and YouTube feeds,
7. Offers Readability and Text-to-Speech for RSS contents,
8. Features `instant sync` across devices without a server.
4. Removed the need for support libraries and jetifier
5. Outfits with Viewbinding, Coil replacing Glide, coroutines replacing RxJava and threads, and SharedFlow replacing EventBus,
6. Boasts new UI's including streamlined drawer, subscriptions view and player controller,
7. Accepts podcast as well as plain RSS and YouTube feeds,
8. Offers Readability and Text-to-Speech for RSS contents,
9. Features `instant sync` across devices without a server.

The project aims to profit from modern frameworks, improve efficiency and provide more useful and user-friendly features.

Expand Down Expand Up @@ -75,16 +76,27 @@ While podcast subscriptions' OPML files (from AntennaPod or any other sources) c
* Played episodes have clearer markings
* Sort dialog no longer dims the main view
* 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)
* Subscriptions view has sorting by "Unread publication date"
* Long-press filter button in FeedEpisode view enables/disables filters without changing filter settings
* Subscriptions view has various explicit measures for sorting
* in Subscriptions view, click on cover image of a feed opens the FeedInfo view (not FeedEpisodes view)
* History view shows time of last play, and allows filters and sorts
* 5 queues are provided by default: Default queue, and Queues 1-4
* all queue operations are on the curQueue, which can be set in all episodes list views
* on app startup, the most recently updated queue is set to curQueue
* queue is circular: if the final item in queue finished, the first item in queue (if exists) will get played
* on action bar of FeedEpisodes view there is a direct access to Queue


### Podcast/Episode

* New share notes menu option on various episode views
* Feed info view offers a link for direct search of feeds related to author
* FeedInfo view has button showing number of episodes to open the FeedEpisodes view
* in EpisodeInfo view, "mark played/unplayed", "add to/remove from queue", and "favoraite/unfovorite" are at the action bar
* New episode home view with two display modes: webpage or reader
* In episode, in addition to "description" there is a new "transcript" field to save text (if any) fetched from the episode's website
* RSS feeds with no playable media can be subscribed and read/listened (via TTS)
* deleting feeds is performed promptly

### Online feed

Expand All @@ -107,6 +119,7 @@ While podcast subscriptions' OPML files (from AntennaPod or any other sources) c
* Disabled `usesCleartextTraffic`, so that all content transmission is more private and secure
* Settings/Preferences can now be exported and imported
* Play history/progress can be separately exported/imported as Json files
* There is a setting to disable/enable auto backup OPML files to Google

For more details of the changes, see the [Changelog](changelog.md)

Expand Down
16 changes: 11 additions & 5 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -108,21 +108,27 @@ android {
// start of the app build.gradle
android {
namespace "ac.mdiq.podcini"
lintOptions {
disable 'ObsoleteLintCustomCheck', 'CheckResult', 'UnusedAttribute', 'BatteryLife', 'InflateParams',
lint {
lintConfig = file("lint.xml")
// checkOnly += ['NewApi', 'InlinedApi']
checkOnly += ['NewApi', 'InlinedApi', 'UnusedResources', 'ObsoleteSdkInt',
'Performance', 'ViewId', 'MissingTranslation',
'Deprecation', 'DuplicateIds', 'UseSparseArrays']

disable += ['TypographyDashes', 'TypographyQuotes', 'ObsoleteLintCustomCheck', 'CheckResult', 'UnusedAttribute', 'BatteryLife', 'InflateParams',
'RestrictedApi', 'TrustAllX509TrustManager', 'ExportedReceiver', 'AllowBackup', 'VectorDrawableCompat',
'StaticFieldLeak', 'UseCompoundDrawables', 'NestedWeights', 'Overdraw', 'UselessParent', 'TextFields',
'AlwaysShowAction', 'Autofill', 'ClickableViewAccessibility', 'ContentDescription',
'KeyboardInaccessibleWidget', 'LabelFor', 'SetTextI18n', 'HardcodedText', 'RelativeOverlap',
'RtlCompat', 'RtlHardcoded', 'MissingMediaBrowserServiceIntentFilter', 'VectorPath',
'InvalidPeriodicWorkRequestInterval', 'NotifyDataSetChanged', 'RtlEnabled'
'InvalidPeriodicWorkRequestInterval', 'NotifyDataSetChanged', 'RtlEnabled']
}
buildFeatures {
buildConfig true
}
defaultConfig {
versionCode 3020200
versionName "6.0.0"
versionCode 3020201
versionName "6.0.1"

applicationId "ac.mdiq.podcini.R"
def commit = ""
Expand Down
3 changes: 2 additions & 1 deletion app/src/main/kotlin/ac/mdiq/podcini/net/sync/SyncService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import ac.mdiq.podcini.storage.database.Episodes.getEpisodeByGuidOrUrl
import ac.mdiq.podcini.storage.database.Episodes.getEpisodes
import ac.mdiq.podcini.storage.database.Episodes.persistEpisodes
import ac.mdiq.podcini.storage.database.Feeds.deleteFeed
import ac.mdiq.podcini.storage.database.Feeds.getFeedList
import ac.mdiq.podcini.storage.database.Feeds.getFeedListDownloadUrls
import ac.mdiq.podcini.storage.database.Feeds.updateFeed
import ac.mdiq.podcini.storage.database.Queues.removeFromQueue
Expand Down Expand Up @@ -161,7 +162,7 @@ open class SyncService(context: Context, params: WorkerParameters) : Worker(cont
private fun removeFeedWithDownloadUrl(context: Context, downloadUrl: String) {
Logd(TAG, "removeFeedWithDownloadUrl called")
var feedID: Long? = null
val feeds = realm.query(Feed::class).find()
val feeds = getFeedList()
for (f in feeds) {
val url = f.downloadUrl
if (url != null && !url.startsWith(Feed.PREFIX_LOCAL_FOLDER)) feedID = f.id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import ac.mdiq.podcini.storage.database.Episodes.getEpisodes
import ac.mdiq.podcini.storage.database.Episodes.persistEpisode
import ac.mdiq.podcini.storage.model.Episode
import ac.mdiq.podcini.storage.utils.EpisodeFilter
import ac.mdiq.podcini.storage.utils.SortOrder
import ac.mdiq.podcini.storage.utils.EpisodeUtil.hasAlmostEnded
import ac.mdiq.podcini.storage.utils.SortOrder
import ac.mdiq.podcini.util.Logd
import ac.mdiq.podcini.util.event.EventFlow
import ac.mdiq.podcini.util.event.FlowEvent
Expand Down
18 changes: 7 additions & 11 deletions app/src/main/kotlin/ac/mdiq/podcini/playback/base/InTheatre.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ object InTheatre {
}

var curMedia: Playable? = null
get() {
if (field == null) field = loadPlayableFromPreferences()
return field
}
// get() {
// if (field == null) field = loadPlayableFromPreferences()
// return field
// }
set(value) {
field = value
if (field is EpisodeMedia) {
Expand Down Expand Up @@ -83,6 +83,7 @@ object InTheatre {
copyToRealm(curState_)
}
}
loadPlayableFromPreferences()
}
// val curState_ = realm.query(CurrentState::class).first()
// val job = CoroutineScope(Dispatchers.Default).launch {
Expand Down Expand Up @@ -114,7 +115,7 @@ object InTheatre {
* depending on the type of playable that was restored.
* @return The restored Playable object
*/
fun loadPlayableFromPreferences(): Playable? {
fun loadPlayableFromPreferences() {
Logd(TAG, "loadPlayableFromPreferences currentlyPlayingType: $curState.curMediaType")
if (curState.curMediaType != NO_MEDIA_PLAYING) {
val type = curState.curMediaType.toInt()
Expand All @@ -124,13 +125,8 @@ object InTheatre {
curMedia = getEpisodeMedia(mediaId)
if (curEpisode != null) curEpisode = (curMedia as EpisodeMedia).episode
}
return curMedia
} else {
Log.e(TAG, "Could not restore Playable object from preferences")
return null
}
} else Log.e(TAG, "Could not restore Playable object from preferences")
}
return null
}

@OptIn(UnstableApi::class) @JvmStatic
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ class LocalMediaPlayer(context: Context, callback: MediaPlayerCallback) : MediaP
* @param prepareImmediately Set to true if the method should also prepare the episode for playback.
*/
override fun playMediaObject(playable: Playable, stream: Boolean, startWhenPrepared: Boolean, prepareImmediately: Boolean, forceReset: Boolean) {
Logd(TAG, "playMediaObject $forceReset $stream $startWhenPrepared $prepareImmediately $status ${curMedia?.getEpisodeTitle()} ")
Logd(TAG, "playMediaObject $forceReset $stream $startWhenPrepared $prepareImmediately $status ${playable.getEpisodeTitle()} ")
if (curMedia != null) {
if (!forceReset && curMedia!!.getIdentifier() == prevMedia?.getIdentifier() && status == PlayerStatus.PLAYING) {
// episode is already playing -> ignore method call
Expand All @@ -255,10 +255,6 @@ class LocalMediaPlayer(context: Context, callback: MediaPlayerCallback) : MediaP
setPlayerStatus(PlayerStatus.INDETERMINATE, null)
}
}
// else {
// Log.e(TAG, "playMediaObject curMedia is null")
// return
// }

curMedia = playable
this.isStreaming = stream
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import ac.mdiq.podcini.storage.model.FeedPreferences
import ac.mdiq.podcini.storage.model.FeedPreferences.AutoDeleteAction
import ac.mdiq.podcini.storage.model.Playable
import ac.mdiq.podcini.storage.utils.EpisodeUtil.hasAlmostEnded
import ac.mdiq.podcini.storage.utils.EpisodeUtil.indexOfItemWithId
import ac.mdiq.podcini.storage.utils.MediaType
import ac.mdiq.podcini.storage.utils.VolumeAdaptionSetting
import ac.mdiq.podcini.ui.activity.starter.MainActivityStarter
Expand All @@ -68,6 +69,7 @@ import android.annotation.SuppressLint
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.PendingIntent.FLAG_IMMUTABLE
import android.app.PendingIntent.FLAG_UPDATE_CURRENT
import android.bluetooth.BluetoothA2dp
import android.content.*
import android.content.Intent.EXTRA_KEY_EVENT
Expand Down Expand Up @@ -259,7 +261,10 @@ class PlaybackService : MediaSessionService() {

recreateMediaPlayer()
if (LocalMediaPlayer.exoPlayer == null) LocalMediaPlayer.createStaticPlayer(applicationContext)
val intent = packageManager.getLaunchIntentForPackage(packageName)
val pendingIntent = PendingIntent.getActivity(this, 0, intent, FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT)
mediaSession = MediaSession.Builder(applicationContext, LocalMediaPlayer.exoPlayer!!)
.setSessionActivity(pendingIntent)
.setCallback(MyCallback())
.setCustomLayout(notificationCustomButtons)
.build()
Expand Down Expand Up @@ -845,7 +850,7 @@ class PlaybackService : MediaSessionService() {
return nextItem.media
}

fun getNextInQueue(episode: Episode): Episode? {
private fun getNextInQueue(episode: Episode): Episode? {
Logd(TAG, "getNextInQueue() with: itemId ${episode.id}")
if (curQueue.episodes.isEmpty()) return null

Expand Down
Loading

0 comments on commit 393063a

Please sign in to comment.