From 9476d7d6811c5468b7a2066b131acbb63a30bbb6 Mon Sep 17 00:00:00 2001 From: Xilin Jia <6257601+XilinJia@users.noreply.github.com> Date: Thu, 25 Apr 2024 11:47:28 +0100 Subject: [PATCH] 4.9.3 commit --- app/build.gradle | 4 +- .../playback/CancelablePSMPCallback.kt | 9 +- .../service/playback/DefaultPSMPCallback.kt | 2 +- .../main/java/ac/mdiq/podcini/PodciniApp.kt | 3 +- .../ac/mdiq/podcini/feed/ChapterMerger.kt | 28 +- .../mdiq/podcini/feed/FeedItemFilterGroup.kt | 18 +- .../ac/mdiq/podcini/feed/LocalFeedUpdater.kt | 64 ++-- .../podcini/feed/SubscriptionsFilterGroup.kt | 11 +- .../mdiq/podcini/feed/parser/SyndHandler.kt | 20 +- .../parser/UnsupportedFeedtypeException.kt | 12 +- .../podcini/feed/parser/element/AtomText.kt | 17 +- .../feed/parser/media/id3/ChapterReader.kt | 8 +- .../feed/parser/media/id3/ID3Reader.kt | 35 +-- .../parser/media/id3/Id3MetadataReader.kt | 3 +- .../vorbis/VorbisCommentChapterReader.kt | 33 +- .../vorbis/VorbisCommentMetadataReader.kt | 4 +- .../media/vorbis/VorbisCommentReader.kt | 40 +-- .../podcini/feed/parser/namespace/Atom.kt | 87 ++---- .../podcini/feed/parser/namespace/Itunes.kt | 36 +-- .../podcini/feed/parser/namespace/Media.kt | 26 +- .../feed/parser/namespace/PodcastIndex.kt | 13 +- .../podcini/feed/parser/namespace/Rss20.kt | 55 +--- .../feed/parser/namespace/SimpleChapters.kt | 4 +- .../podcini/feed/parser/namespace/YouTube.kt | 36 +-- .../podcini/feed/parser/util/DateUtils.kt | 27 +- .../feed/parser/util/DurationParser.kt | 20 +- .../podcini/feed/parser/util/MimeTypeUtils.kt | 40 +-- .../podcini/feed/parser/util/TypeGetter.kt | 8 +- .../podcini/feed/util/ImageResourceUtils.kt | 30 +- .../podcini/feed/util/PlaybackSpeedUtils.kt | 8 +- .../mdiq/podcini/glide/ApOkHttpUrlLoader.kt | 6 +- .../mdiq/podcini/glide/AudioCoverFetcher.kt | 12 +- .../podcini/glide/ChapterImageModelLoader.kt | 11 +- .../podcini/glide/FastBlurTransformation.kt | 25 +- .../GenerativePlaceholderImageModelLoader.kt | 27 +- .../podcini/glide/MetadataRetrieverLoader.kt | 10 +- .../glide/ResizingOkHttpStreamFetcher.kt | 31 +- .../ac/mdiq/podcini/net/common/UrlChecker.kt | 33 +- .../podcini/net/discovery/CombinedSearcher.kt | 9 +- .../net/discovery/ItunesPodcastSearcher.kt | 12 +- .../net/discovery/ItunesTopListLoader.kt | 33 +- .../discovery/PodcastIndexPodcastSearcher.kt | 4 +- .../net/discovery/PodcastSearchResult.kt | 18 +- .../net/discovery/PodcastSearcherRegistry.kt | 11 +- .../net/download/ConnectionStateMonitor.kt | 6 +- .../podcini/net/download/FeedUpdateManager.kt | 39 +-- .../podcini/net/download/MediaSizeLoader.kt | 14 +- .../service/BasicAuthorizationInterceptor.kt | 15 +- .../service/DownloadRequestCreator.kt | 44 +-- .../service/DownloadServiceInterfaceImpl.kt | 35 +-- .../download/service/EpisodeDownloadWorker.kt | 61 ++-- .../net/download/service/FeedUpdateWorker.kt | 67 ++-- .../net/download/service/HttpDownloader.kt | 28 +- .../net/download/service/PodciniHttpClient.kt | 4 +- .../service/handler/FeedParserTask.kt | 25 +- .../download/service/handler/FeedSyncTask.kt | 4 +- .../service/handler/MediaDownloadedHandler.kt | 20 +- .../serviceinterface/DownloadRequest.kt | 20 +- .../DownloadServiceInterface.kt | 6 +- .../DownloadServiceInterfaceStub.kt | 12 +- .../podcini/net/ssl/BackportTrustManager.kt | 4 +- .../podcini/net/sync/EpisodeActionFilter.kt | 29 +- .../ac/mdiq/podcini/net/sync/GuidValidator.kt | 3 +- .../mdiq/podcini/net/sync/HostnameParser.kt | 30 +- .../ac/mdiq/podcini/net/sync/SyncService.kt | 62 ++-- .../sync/SynchronizationProviderViewData.kt | 4 +- .../net/sync/SynchronizationSettings.kt | 20 +- .../net/sync/gpoddernet/GpodnetService.kt | 9 +- .../sync/gpoddernet/mapper/ResponseMapper.kt | 4 +- .../sync/gpoddernet/model/GpodnetDevice.kt | 13 +- .../model/GpodnetEpisodeActionPostResponse.kt | 14 +- .../sync/gpoddernet/model/GpodnetPodcast.kt | 17 +- .../model/GpodnetUploadChangesResponse.kt | 18 +- .../podcini/net/sync/model/EpisodeAction.kt | 49 +-- .../net/sync/model/EpisodeActionChanges.kt | 5 +- .../podcini/net/sync/model/ISyncService.kt | 4 +- .../net/sync/model/SubscriptionChanges.kt | 4 +- .../net/sync/model/UploadChangesResponse.kt | 10 +- .../net/sync/nextcloud/NextcloudLoginFlow.kt | 25 +- .../sync/nextcloud/NextcloudSyncService.kt | 27 +- .../sync/queue/SynchronizationQueueSink.kt | 36 +-- .../sync/queue/SynchronizationQueueStorage.kt | 20 +- .../ac/mdiq/podcini/playback/PlayableUtils.kt | 4 +- .../podcini/playback/PlaybackController.kt | 17 +- .../base/PlaybackServiceMediaPlayer.kt | 9 +- .../playback/service/ExoPlayerWrapper.kt | 1 - .../podcini/playback/service/LocalPSMP.kt | 217 ++++++------- .../playback/service/PlaybackService.kt | 294 ++++-------------- .../PlaybackServiceNotificationBuilder.kt | 222 ------------- .../service/PlaybackServiceStateManager.kt | 58 ---- .../service/PlaybackServiceTaskManager.kt | 25 +- .../playback/service/PlaybackVolumeUpdater.kt | 3 +- .../service/QuickSettingsTileService.kt | 5 +- .../podcini/playback/service/ShakeListener.kt | 9 +- .../preferences/MaterialListPreference.kt | 8 +- .../MaterialMultiSelectListPreference.kt | 7 +- .../preferences/PlaybackPreferences.kt | 8 +- .../podcini/preferences/PreferenceUpgrader.kt | 75 ++--- .../preferences/SleepTimerPreferences.kt | 8 +- .../podcini/preferences/ThemePreference.kt | 4 +- .../mdiq/podcini/preferences/ThemeSwitcher.kt | 10 +- .../podcini/preferences/UsageStatistics.kt | 3 +- .../podcini/preferences/UserPreferences.kt | 156 +++------- .../AutoDownloadPreferencesFragment.kt | 76 ++--- .../fragments/DownloadsPreferencesFragment.kt | 62 ++-- .../ImportExportPreferencesFragment.kt | 102 +++--- .../fragments/MainPreferencesFragment.kt | 126 ++++---- .../fragments/PlaybackPreferencesFragment.kt | 85 +++-- .../fragments/SwipePreferencesFragment.kt | 65 ++-- .../UserInterfacePreferencesFragment.kt | 95 ++---- .../fragments/about/AboutFragment.kt | 10 +- .../about/ContributorsPagerFragment.kt | 7 +- .../fragments/about/DevelopersFragment.kt | 39 +-- .../fragments/about/LicensesFragment.kt | 30 +- .../fragments/about/SpecialThanksFragment.kt | 38 +-- .../fragments/about/TranslatorsFragment.kt | 39 +-- .../fragments/dialog/PreferenceListDialog.kt | 4 +- .../dialog/PreferenceSwitchDialog.kt | 4 +- .../GpodderAuthenticationFragment.kt | 42 +-- .../NextcloudAuthenticationFragment.kt | 25 +- .../SynchronizationPreferencesFragment.kt | 90 +++--- .../podcini/receiver/MediaButtonReceiver.kt | 11 +- .../ac/mdiq/podcini/receiver/PlayerWidget.kt | 3 +- .../receiver/PowerConnectionReceiver.kt | 5 +- .../ac/mdiq/podcini/receiver/SPAReceiver.kt | 8 +- .../podcini/storage/APCleanupAlgorithm.kt | 33 +- .../storage/APQueueCleanupAlgorithm.kt | 26 +- .../storage/AutomaticDownloadAlgorithm.kt | 17 +- .../java/ac/mdiq/podcini/storage/DBReader.kt | 98 ++---- .../java/ac/mdiq/podcini/storage/DBTasks.kt | 35 +-- .../java/ac/mdiq/podcini/storage/DBWriter.kt | 145 +++------ .../podcini/storage/DatabaseTransporter.kt | 21 +- .../storage/EpisodeCleanupAlgorithm.kt | 8 +- .../storage/EpisodeCleanupAlgorithmFactory.kt | 5 +- .../storage/ExceptFavoriteCleanupAlgorithm.kt | 35 +-- .../storage/FeedItemDuplicateGuesser.kt | 39 +-- .../storage/ItemEnqueuePositionCalculator.kt | 20 +- .../asynctask/DocumentFileExportWorker.kt | 6 +- .../podcini/storage/asynctask/ExportWorker.kt | 5 +- .../podcini/storage/backup/OpmlBackupAgent.kt | 19 +- .../podcini/storage/database/DBUpgrader.kt | 86 ++--- .../podcini/storage/database/PodDBAdapter.kt | 160 +++------- .../database/mapper/FeedItemFilterQuery.kt | 56 +--- .../database/mapper/FeedMediaCursorMapper.kt | 5 +- .../mapper/FeedPreferencesCursorMapper.kt | 11 +- .../export/favorites/FavoritesWriter.kt | 15 +- .../podcini/storage/export/opml/OpmlReader.kt | 3 +- .../podcini/storage/export/opml/OpmlWriter.kt | 8 +- .../storage/model/download/DownloadError.kt | 10 +- .../storage/model/download/DownloadResult.kt | 9 +- .../model/feed/EmbeddedChapterImage.kt | 17 +- .../mdiq/podcini/storage/model/feed/Feed.kt | 128 +++----- .../podcini/storage/model/feed/FeedCounter.kt | 4 +- .../podcini/storage/model/feed/FeedFile.kt | 17 +- .../podcini/storage/model/feed/FeedFilter.kt | 30 +- .../podcini/storage/model/feed/FeedFunding.kt | 43 +-- .../podcini/storage/model/feed/FeedItem.kt | 105 ++----- .../storage/model/feed/FeedItemFilter.kt | 56 +--- .../podcini/storage/model/feed/FeedMedia.kt | 108 ++----- .../storage/model/feed/FeedPreferences.kt | 21 +- .../podcini/storage/model/feed/SortOrder.kt | 9 +- .../storage/model/feed/SubscriptionsFilter.kt | 34 +- .../model/feed/VolumeAdaptionSetting.kt | 4 +- .../storage/model/playback/MediaType.kt | 24 +- .../storage/model/playback/RemoteMedia.kt | 17 +- .../EpisodeMultiSelectActionHandler.kt | 44 +-- .../actions/FeedMultiSelectActionHandler.kt | 51 +-- .../actionbutton/DeleteActionButton.kt | 6 +- .../actionbutton/DownloadActionButton.kt | 19 +- .../actions/actionbutton/ItemActionButton.kt | 28 +- .../actionbutton/MarkAsPlayedActionButton.kt | 4 +- .../actions/actionbutton/PauseActionButton.kt | 4 +- .../actions/actionbutton/PlayActionButton.kt | 4 +- .../actionbutton/PlayLocalActionButton.kt | 4 +- .../actionbutton/StreamActionButton.kt | 4 +- .../menuhandler/FeedItemMenuHandler.kt | 56 +--- .../ui/actions/menuhandler/FeedMenuHandler.kt | 16 +- .../ui/actions/menuhandler/MenuItemUtils.kt | 4 +- .../swipeactions/AddToQueueSwipeAction.kt | 7 +- .../actions/swipeactions/DeleteSwipeAction.kt | 5 +- .../swipeactions/NoActionSwipeAction.kt | 3 +- .../RemoveFromHistorySwipeAction.kt | 4 +- .../RemoveFromQueueSwipeAction.kt | 9 +- .../swipeactions/StartDownloadSwipeAction.kt | 3 +- .../ui/actions/swipeactions/SwipeActions.kt | 40 +-- .../TogglePlaybackStateSwipeAction.kt | 7 +- .../podcini/ui/activity/BugReportActivity.kt | 16 +- .../mdiq/podcini/ui/activity/MainActivity.kt | 26 +- .../ui/activity/OnlineFeedViewActivity.kt | 15 +- .../podcini/ui/activity/OpmlImportActivity.kt | 30 +- .../podcini/ui/activity/PreferenceActivity.kt | 4 +- .../ui/activity/SelectSubscriptionActivity.kt | 24 +- .../podcini/ui/activity/SplashActivity.kt | 23 +- .../ui/activity/VideoplayerActivity.kt | 57 +--- .../ui/activity/WidgetConfigActivity.kt | 15 +- .../appstartintent/MainActivityStarter.kt | 4 +- .../podcini/ui/adapter/ChaptersListAdapter.kt | 16 +- .../ac/mdiq/podcini/ui/adapter/CoverLoader.kt | 10 +- .../podcini/ui/adapter/DataFolderAdapter.kt | 15 +- .../podcini/ui/adapter/DownloadLogAdapter.kt | 34 +- .../ui/adapter/EpisodeItemListAdapter.kt | 13 +- .../podcini/ui/adapter/FeedDiscoverAdapter.kt | 4 +- .../ui/adapter/HorizontalFeedListAdapter.kt | 8 +- .../mdiq/podcini/ui/adapter/NavListAdapter.kt | 67 ++-- .../podcini/ui/adapter/OnlineFeedsAdapter.kt | 5 +- .../ui/adapter/QueueRecyclerAdapter.kt | 19 +- .../podcini/ui/adapter/SelectableAdapter.kt | 25 +- .../ui/adapter/SimpleIconListAdapter.kt | 9 +- .../ui/adapter/SubscriptionsAdapter.kt | 14 +- .../podcini/ui/dialog/AuthenticationDialog.kt | 20 +- .../podcini/ui/dialog/ConfirmationDialog.kt | 4 +- .../ui/dialog/DownloadLogDetailsDialog.kt | 16 +- .../ui/dialog/DrawerPreferencesDialog.kt | 11 +- .../podcini/ui/dialog/EpisodeFilterDialog.kt | 20 +- .../podcini/ui/dialog/ItemFilterDialog.kt | 18 +- .../mdiq/podcini/ui/dialog/ItemSortDialog.kt | 3 +- .../ac/mdiq/podcini/ui/dialog/ProxyDialog.kt | 50 ++- .../podcini/ui/dialog/RemoveFeedDialog.kt | 12 +- .../podcini/ui/dialog/RenameItemDialog.kt | 4 +- .../ac/mdiq/podcini/ui/dialog/ShareDialog.kt | 10 +- .../podcini/ui/dialog/SkipPreferenceDialog.kt | 27 +- .../podcini/ui/dialog/SleepTimerDialog.kt | 22 +- .../ui/dialog/SubscriptionsFilterDialog.kt | 27 +- .../podcini/ui/dialog/SwipeActionsDialog.kt | 17 +- .../podcini/ui/dialog/TagSettingsDialog.kt | 14 +- .../mdiq/podcini/ui/dialog/TimeRangeDialog.kt | 43 +-- .../podcini/ui/dialog/VariableSpeedDialog.kt | 19 +- .../mdiq/podcini/ui/dialog/VideoModeDialog.kt | 4 +- .../podcini/ui/fragment/AddFeedFragment.kt | 47 +-- .../ui/fragment/AllEpisodesFragment.kt | 19 +- .../ui/fragment/AudioPlayerFragment.kt | 76 ++--- .../ui/fragment/BaseEpisodesListFragment.kt | 107 +++---- .../podcini/ui/fragment/ChaptersFragment.kt | 21 +- .../podcini/ui/fragment/DiscoveryFragment.kt | 45 ++- .../ui/fragment/DownloadLogFragment.kt | 12 +- .../podcini/ui/fragment/DownloadsFragment.kt | 64 ++-- .../ui/fragment/EpisodeHomeFragment.kt | 29 +- .../ui/fragment/EpisodeInfoFragment.kt | 11 +- .../ui/fragment/EpisodesListFragment.kt | 5 +- .../podcini/ui/fragment/FeedInfoFragment.kt | 64 ++-- .../ui/fragment/FeedItemlistFragment.kt | 173 ++++------- .../ui/fragment/FeedSettingsFragment.kt | 288 ++++++++--------- .../podcini/ui/fragment/NavDrawerFragment.kt | 52 ++-- .../ui/fragment/OnlineFeedViewFragment.kt | 71 ++--- .../ui/fragment/OnlineSearchFragment.kt | 14 +- .../ui/fragment/PagedToolbarFragment.kt | 12 +- .../ui/fragment/PlaybackHistoryFragment.kt | 11 +- .../ui/fragment/PlayerDetailsFragment.kt | 7 +- .../mdiq/podcini/ui/fragment/QueueFragment.kt | 111 +++---- .../ui/fragment/QuickFeedDiscoveryFragment.kt | 14 +- .../podcini/ui/fragment/SearchFragment.kt | 76 ++--- .../ui/fragment/SubscriptionFragment.kt | 54 ++-- .../ui/fragment/VideoEpisodeFragment.kt | 67 ++-- .../podcini/ui/utils/PictureInPictureUtil.kt | 12 +- .../mdiq/podcini/ui/utils/ShownotesCleaner.kt | 15 +- .../ac/mdiq/podcini/ui/utils/ThemeUtils.kt | 4 +- .../podcini/ui/view/AspectRatioVideoView.kt | 4 +- .../ac/mdiq/podcini/ui/view/ChapterSeekBar.kt | 32 +- .../podcini/ui/view/CircularProgressBar.kt | 11 +- .../mdiq/podcini/ui/view/EmptyViewHandler.kt | 12 +- .../ui/view/EpisodeItemListRecyclerView.kt | 4 +- .../podcini/ui/view/LiftOnScrollListener.kt | 26 +- .../ui/view/LockableBottomSheetBehavior.kt | 36 +-- .../podcini/ui/view/NoRelayoutTextView.kt | 4 +- .../ac/mdiq/podcini/ui/view/PlayButton.kt | 8 +- .../ui/view/PlaybackSpeedIndicatorView.kt | 5 +- .../mdiq/podcini/ui/view/ShownotesWebView.kt | 34 +- .../podcini/ui/view/ToolbarIconTintManager.kt | 5 +- .../mdiq/podcini/ui/view/TriangleLabelView.kt | 29 +- .../mdiq/podcini/ui/view/WrappingGridView.kt | 11 +- .../view/viewholder/EpisodeItemViewHolder.kt | 30 +- .../mdiq/podcini/ui/widget/WidgetUpdater.kt | 24 +- .../podcini/ui/widget/WidgetUpdaterWorker.kt | 7 +- .../java/ac/mdiq/podcini/util/ChapterUtils.kt | 83 ++--- .../java/ac/mdiq/podcini/util/Converter.kt | 16 +- .../ac/mdiq/podcini/util/DateFormatter.kt | 10 +- .../ac/mdiq/podcini/util/FastDocumentFile.kt | 14 +- .../ac/mdiq/podcini/util/FeedItemPermutors.kt | 12 +- .../java/ac/mdiq/podcini/util/FeedItemUtil.kt | 25 +- .../java/ac/mdiq/podcini/util/FeedUtil.kt | 5 +- .../ac/mdiq/podcini/util/FileNameGenerator.kt | 23 +- .../java/ac/mdiq/podcini/util/IntentUtils.kt | 4 +- .../java/ac/mdiq/podcini/util/LongList.kt | 65 ++-- .../java/ac/mdiq/podcini/util/NetworkUtils.kt | 26 +- .../ac/mdiq/podcini/util/PlaybackStatus.kt | 3 +- .../java/ac/mdiq/podcini/util/PowerUtils.kt | 3 +- .../main/java/ac/mdiq/podcini/util/SPAUtil.kt | 4 +- .../java/ac/mdiq/podcini/util/ShareUtils.kt | 3 +- .../java/ac/mdiq/podcini/util/StorageUtils.kt | 6 +- .../mdiq/podcini/util/TimeSpeedConverter.kt | 5 +- .../comparator/FeedItemPubdateComparator.kt | 16 +- .../PlaybackCompletionDateComparator.kt | 4 +- .../podcini/util/config/ClientConfigurator.kt | 5 +- .../util/error/RxJavaErrorHandlerSetup.kt | 3 +- .../ac/mdiq/podcini/util/event/QueueEvent.kt | 40 +-- .../util/syndication/FeedDiscoverer.kt | 8 +- .../util/syndication/HtmlToPlainText.kt | 31 +- .../res/layout/internal_player_fragment.xml | 1 + app/src/main/res/values/strings.xml | 2 + changelog.md | 9 +- .../android/en-US/changelogs/3020134.txt | 7 + 301 files changed, 2687 insertions(+), 5976 deletions(-) delete mode 100644 app/src/main/java/ac/mdiq/podcini/playback/service/PlaybackServiceNotificationBuilder.kt delete mode 100644 app/src/main/java/ac/mdiq/podcini/playback/service/PlaybackServiceStateManager.kt create mode 100644 fastlane/metadata/android/en-US/changelogs/3020134.txt diff --git a/app/build.gradle b/app/build.gradle index 623d5a2a..bf635d26 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -158,8 +158,8 @@ android { // Version code schema (not used): // "1.2.3-beta4" -> 1020304 // "1.2.3" -> 1020395 - versionCode 3020133 - versionName "4.9.2" + versionCode 3020134 + versionName "4.9.3" def commit = "" try { diff --git a/app/src/androidTest/java/ac/test/podcini/service/playback/CancelablePSMPCallback.kt b/app/src/androidTest/java/ac/test/podcini/service/playback/CancelablePSMPCallback.kt index 09c38193..e7f71a7b 100644 --- a/app/src/androidTest/java/ac/test/podcini/service/playback/CancelablePSMPCallback.kt +++ b/app/src/androidTest/java/ac/test/podcini/service/playback/CancelablePSMPCallback.kt @@ -20,10 +20,9 @@ class CancelablePSMPCallback(private val originalCallback: PSMPCallback) : PSMPC } override fun shouldStop() { - if (isCancelled) { - return - } - originalCallback.shouldStop() + if (isCancelled) return + +// originalCallback.shouldStop() } override fun onMediaChanged(reloadUI: Boolean) { @@ -33,7 +32,7 @@ class CancelablePSMPCallback(private val originalCallback: PSMPCallback) : PSMPC originalCallback.onMediaChanged(reloadUI) } - override fun onPostPlayback(media: Playable, ended: Boolean, skipped: Boolean, playingNext: Boolean) { + override fun onPostPlayback(media: Playable?, ended: Boolean, skipped: Boolean, playingNext: Boolean) { if (isCancelled) { return } diff --git a/app/src/androidTest/java/ac/test/podcini/service/playback/DefaultPSMPCallback.kt b/app/src/androidTest/java/ac/test/podcini/service/playback/DefaultPSMPCallback.kt index 86ad1cda..eee4b1d0 100644 --- a/app/src/androidTest/java/ac/test/podcini/service/playback/DefaultPSMPCallback.kt +++ b/app/src/androidTest/java/ac/test/podcini/service/playback/DefaultPSMPCallback.kt @@ -15,7 +15,7 @@ open class DefaultPSMPCallback : PSMPCallback { override fun onMediaChanged(reloadUI: Boolean) { } - override fun onPostPlayback(media: Playable, ended: Boolean, skipped: Boolean, playingNext: Boolean) { + override fun onPostPlayback(media: Playable?, ended: Boolean, skipped: Boolean, playingNext: Boolean) { } override fun onPlaybackStart(playable: Playable, position: Int) { diff --git a/app/src/main/java/ac/mdiq/podcini/PodciniApp.kt b/app/src/main/java/ac/mdiq/podcini/PodciniApp.kt index 4e3d5ad2..111b7ddf 100644 --- a/app/src/main/java/ac/mdiq/podcini/PodciniApp.kt +++ b/app/src/main/java/ac/mdiq/podcini/PodciniApp.kt @@ -25,8 +25,7 @@ class PodciniApp : Application() { override fun onCreate() { super.onCreate() ClientConfig.USER_AGENT = "Podcini/" + BuildConfig.VERSION_NAME - ClientConfig.applicationCallbacks = - ApplicationCallbacksImpl() + ClientConfig.applicationCallbacks = ApplicationCallbacksImpl() Thread.setDefaultUncaughtExceptionHandler(CrashReportWriter()) RxJavaErrorHandlerSetup.setupRxJavaErrorHandler() diff --git a/app/src/main/java/ac/mdiq/podcini/feed/ChapterMerger.kt b/app/src/main/java/ac/mdiq/podcini/feed/ChapterMerger.kt index 6decd572..ef7f70ea 100644 --- a/app/src/main/java/ac/mdiq/podcini/feed/ChapterMerger.kt +++ b/app/src/main/java/ac/mdiq/podcini/feed/ChapterMerger.kt @@ -13,18 +13,10 @@ object ChapterMerger { fun merge(chapters1: List?, chapters2: List?): List? { Log.d(TAG, "Merging chapters") when { - chapters1 == null -> { - return chapters2 - } - chapters2 == null -> { - return chapters1 - } - chapters2.size > chapters1.size -> { - return chapters2 - } - chapters2.size < chapters1.size -> { - return chapters1 - } + chapters1 == null -> return chapters2 + chapters2 == null -> return chapters1 + chapters2.size > chapters1.size -> return chapters2 + chapters2.size < chapters1.size -> return chapters1 else -> { // Merge chapter lists of same length. Store in chapters2 array. // In case the lists can not be merged, return chapters1 array. @@ -37,15 +29,9 @@ object ChapterMerger { return if (score(chapters1) > score(chapters2)) chapters1 else chapters2 } - if (chapterTarget.imageUrl.isNullOrEmpty()) { - chapterTarget.imageUrl = chapterOther.imageUrl - } - if (chapterTarget.link.isNullOrEmpty()) { - chapterTarget.link = chapterOther.link - } - if (chapterTarget.title.isNullOrEmpty()) { - chapterTarget.title = chapterOther.title - } + if (chapterTarget.imageUrl.isNullOrEmpty()) chapterTarget.imageUrl = chapterOther.imageUrl + if (chapterTarget.link.isNullOrEmpty()) chapterTarget.link = chapterOther.link + if (chapterTarget.title.isNullOrEmpty()) chapterTarget.title = chapterOther.title } return chapters2 } diff --git a/app/src/main/java/ac/mdiq/podcini/feed/FeedItemFilterGroup.kt b/app/src/main/java/ac/mdiq/podcini/feed/FeedItemFilterGroup.kt index 1b2e0006..191e53fe 100644 --- a/app/src/main/java/ac/mdiq/podcini/feed/FeedItemFilterGroup.kt +++ b/app/src/main/java/ac/mdiq/podcini/feed/FeedItemFilterGroup.kt @@ -4,18 +4,12 @@ import ac.mdiq.podcini.R import ac.mdiq.podcini.storage.model.feed.FeedItemFilter enum class FeedItemFilterGroup(vararg values: ItemProperties) { - PLAYED(ItemProperties(R.string.hide_played_episodes_label, FeedItemFilter.PLAYED), - ItemProperties(R.string.not_played, FeedItemFilter.UNPLAYED)), - PAUSED(ItemProperties(R.string.hide_paused_episodes_label, FeedItemFilter.PAUSED), - ItemProperties(R.string.not_paused, FeedItemFilter.NOT_PAUSED)), - FAVORITE(ItemProperties(R.string.hide_is_favorite_label, FeedItemFilter.IS_FAVORITE), - ItemProperties(R.string.not_favorite, FeedItemFilter.NOT_FAVORITE)), - MEDIA(ItemProperties(R.string.has_media, FeedItemFilter.HAS_MEDIA), - ItemProperties(R.string.no_media, FeedItemFilter.NO_MEDIA)), - QUEUED(ItemProperties(R.string.queued_label, FeedItemFilter.QUEUED), - ItemProperties(R.string.not_queued_label, FeedItemFilter.NOT_QUEUED)), - DOWNLOADED(ItemProperties(R.string.hide_downloaded_episodes_label, FeedItemFilter.DOWNLOADED), - ItemProperties(R.string.hide_not_downloaded_episodes_label, FeedItemFilter.NOT_DOWNLOADED)); + PLAYED(ItemProperties(R.string.hide_played_episodes_label, FeedItemFilter.PLAYED), ItemProperties(R.string.not_played, FeedItemFilter.UNPLAYED)), + PAUSED(ItemProperties(R.string.hide_paused_episodes_label, FeedItemFilter.PAUSED), ItemProperties(R.string.not_paused, FeedItemFilter.NOT_PAUSED)), + FAVORITE(ItemProperties(R.string.hide_is_favorite_label, FeedItemFilter.IS_FAVORITE), ItemProperties(R.string.not_favorite, FeedItemFilter.NOT_FAVORITE)), + MEDIA(ItemProperties(R.string.has_media, FeedItemFilter.HAS_MEDIA), ItemProperties(R.string.no_media, FeedItemFilter.NO_MEDIA)), + QUEUED(ItemProperties(R.string.queued_label, FeedItemFilter.QUEUED), ItemProperties(R.string.not_queued_label, FeedItemFilter.NOT_QUEUED)), + DOWNLOADED(ItemProperties(R.string.hide_downloaded_episodes_label, FeedItemFilter.DOWNLOADED), ItemProperties(R.string.hide_not_downloaded_episodes_label, FeedItemFilter.NOT_DOWNLOADED)); @JvmField val values: Array diff --git a/app/src/main/java/ac/mdiq/podcini/feed/LocalFeedUpdater.kt b/app/src/main/java/ac/mdiq/podcini/feed/LocalFeedUpdater.kt index 9167ba7f..b08d63c8 100644 --- a/app/src/main/java/ac/mdiq/podcini/feed/LocalFeedUpdater.kt +++ b/app/src/main/java/ac/mdiq/podcini/feed/LocalFeedUpdater.kt @@ -39,24 +39,17 @@ object LocalFeedUpdater { val PREFERRED_FEED_IMAGE_FILENAMES: Array = arrayOf("folder.jpg", "Folder.jpg", "folder.png", "Folder.png") @UnstableApi @JvmStatic - fun updateFeed(feed: Feed, context: Context, - updaterProgressListener: UpdaterProgressListener? - ) { + fun updateFeed(feed: Feed, context: Context, updaterProgressListener: UpdaterProgressListener?) { if (feed.download_url.isNullOrEmpty()) return try { val uriString = feed.download_url!!.replace(Feed.PREFIX_LOCAL_FOLDER, "") val documentFolder = DocumentFile.fromTreeUri(context, Uri.parse(uriString)) - ?: throw IOException("Unable to retrieve document tree. " - + "Try re-connecting the folder on the podcast info page.") - if (!documentFolder.exists() || !documentFolder.canRead()) { - throw IOException("Cannot read local directory. " - + "Try re-connecting the folder on the podcast info page.") - } - tryUpdateFeed(feed, context, documentFolder.uri, updaterProgressListener) + ?: throw IOException("Unable to retrieve document tree. Try re-connecting the folder on the podcast info page.") + if (!documentFolder.exists() || !documentFolder.canRead()) + throw IOException("Cannot read local directory. Try re-connecting the folder on the podcast info page.") - if (mustReportDownloadSuccessful(feed)) { - reportSuccess(feed) - } + tryUpdateFeed(feed, context, documentFolder.uri, updaterProgressListener) + if (mustReportDownloadSuccessful(feed)) reportSuccess(feed) } catch (e: Exception) { e.printStackTrace() reportError(feed, e.message) @@ -66,9 +59,7 @@ object LocalFeedUpdater { @UnstableApi @JvmStatic @VisibleForTesting @Throws(IOException::class) - fun tryUpdateFeed(feed: Feed, context: Context, folderUri: Uri?, - updaterProgressListener: UpdaterProgressListener? - ) { + fun tryUpdateFeed(feed: Feed, context: Context, folderUri: Uri?, updaterProgressListener: UpdaterProgressListener?) { var feed = feed //make sure it is the latest 'version' of this feed from the db (all items etc) feed = DBTasks.updateFeed(context, feed, false)?: feed @@ -99,9 +90,7 @@ object LocalFeedUpdater { val it = newItems.iterator() while (it.hasNext()) { val feedItem = it.next() - if (!mediaFileNames.contains(feedItem.link)) { - it.remove() - } + if (!mediaFileNames.contains(feedItem.link)) it.remove() } if (folderUri != null) feed.imageUrl = getImageUrl(allFiles, folderUri) @@ -120,18 +109,14 @@ object LocalFeedUpdater { // look for special file names for (iconLocation in PREFERRED_FEED_IMAGE_FILENAMES) { for (file in files) { - if (iconLocation == file.name) { - return file.uri.toString() - } + if (iconLocation == file.name) return file.uri.toString() } } // use the first image in the folder if existing for (file in files) { val mime = file.type - if (mime.startsWith("image/jpeg") || mime.startsWith("image/png")) { - return file.uri.toString() - } + if (mime.startsWith("image/jpeg") || mime.startsWith("image/png")) return file.uri.toString() } // use default icon as fallback @@ -141,16 +126,13 @@ object LocalFeedUpdater { private fun feedContainsFile(feed: Feed, filename: String): FeedItem? { val items = feed.items for (i in items) { - if (i.media != null && i.link == filename) { - return i - } + if (i.media != null && i.link == filename) return i } return null } private fun createFeedItem(feed: Feed, file: FastDocumentFile, context: Context): FeedItem { - val item = FeedItem(0, file.name, UUID.randomUUID().toString(), - file.name, Date(file.lastModified), FeedItem.UNPLAYED, feed) + val item = FeedItem(0, file.name, UUID.randomUUID().toString(), file.name, Date(file.lastModified), FeedItem.UNPLAYED, feed) item.disableAutoDownload() val size = file.length @@ -159,9 +141,8 @@ object LocalFeedUpdater { item.media = media for (existingItem in feed.items) { - if (existingItem.media != null && existingItem.media!! - .download_url == file.uri.toString() && file.length == existingItem.media!! - .size) { + if (existingItem.media != null && existingItem.media!!.download_url == file.uri.toString() + && file.length == existingItem.media!!.size) { // We found an old file that we already scanned. Re-use metadata. item.updateFromOther(existingItem) return item @@ -187,16 +168,12 @@ object LocalFeedUpdater { item.pubDate = simpleDateFormat.parse(dateStr) } catch (parseException: ParseException) { val date = DateUtils.parse(dateStr) - if (date != null) { - item.pubDate = date - } + if (date != null) item.pubDate = date } } val title = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE) - if (!title.isNullOrEmpty()) { - item.title = title - } + if (!title.isNullOrEmpty()) item.title = title val durationStr = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION) item.media!!.setDuration(durationStr!!.toLong().toInt()) @@ -204,8 +181,7 @@ object LocalFeedUpdater { item.media!!.setHasEmbeddedPicture(mediaMetadataRetriever.embeddedPicture != null) try { context.contentResolver.openInputStream(file.uri).use { inputStream -> - val reader = Id3MetadataReader( - CountingInputStream(BufferedInputStream(inputStream))) + val reader = Id3MetadataReader(CountingInputStream(BufferedInputStream(inputStream))) reader.readInputStream() item.setDescriptionIfLonger(reader.comment) } @@ -263,10 +239,8 @@ object LocalFeedUpdater { private fun mustReportDownloadSuccessful(feed: Feed): Boolean { val downloadResults = DBReader.getFeedDownloadLog(feed.id).toMutableList() - if (downloadResults.isEmpty()) { - // report success if never reported before - return true - } + // report success if never reported before + if (downloadResults.isEmpty()) return true downloadResults.sortWith { downloadStatus1: DownloadResult, downloadStatus2: DownloadResult -> downloadStatus1.getCompletionDate().compareTo(downloadStatus2.getCompletionDate()) diff --git a/app/src/main/java/ac/mdiq/podcini/feed/SubscriptionsFilterGroup.kt b/app/src/main/java/ac/mdiq/podcini/feed/SubscriptionsFilterGroup.kt index 497afe29..091140b0 100644 --- a/app/src/main/java/ac/mdiq/podcini/feed/SubscriptionsFilterGroup.kt +++ b/app/src/main/java/ac/mdiq/podcini/feed/SubscriptionsFilterGroup.kt @@ -4,14 +4,9 @@ import ac.mdiq.podcini.R enum class SubscriptionsFilterGroup(vararg values: ItemProperties) { COUNTER_GREATER_ZERO(ItemProperties(R.string.subscriptions_counter_greater_zero, "counter_greater_zero")), - AUTO_DOWNLOAD(ItemProperties(R.string.auto_downloaded, "enabled_auto_download"), - ItemProperties(R.string.not_auto_downloaded, "disabled_auto_download")), - UPDATED(ItemProperties(R.string.kept_updated, "enabled_updates"), - ItemProperties(R.string.not_kept_updated, "disabled_updates")), - NEW_EPISODE_NOTIFICATION(ItemProperties(R.string.new_episode_notification_enabled, - "episode_notification_enabled"), - ItemProperties(R.string.new_episode_notification_disabled, "episode_notification_disabled")); - + AUTO_DOWNLOAD(ItemProperties(R.string.auto_downloaded, "enabled_auto_download"), ItemProperties(R.string.not_auto_downloaded, "disabled_auto_download")), + UPDATED(ItemProperties(R.string.kept_updated, "enabled_updates"), ItemProperties(R.string.not_kept_updated, "disabled_updates")), + NEW_EPISODE_NOTIFICATION(ItemProperties(R.string.new_episode_notification_enabled, "episode_notification_enabled"), ItemProperties(R.string.new_episode_notification_disabled, "episode_notification_disabled")); @JvmField val values: Array diff --git a/app/src/main/java/ac/mdiq/podcini/feed/parser/SyndHandler.kt b/app/src/main/java/ac/mdiq/podcini/feed/parser/SyndHandler.kt index b4d1fb5e..6d06c87a 100644 --- a/app/src/main/java/ac/mdiq/podcini/feed/parser/SyndHandler.kt +++ b/app/src/main/java/ac/mdiq/podcini/feed/parser/SyndHandler.kt @@ -14,9 +14,7 @@ class SyndHandler(feed: Feed, type: TypeGetter.Type) : DefaultHandler() { val state: HandlerState = HandlerState(feed) init { - if (type == TypeGetter.Type.RSS20 || type == TypeGetter.Type.RSS091) { - state.defaultNamespaces.push(Rss20()) - } + if (type == TypeGetter.Type.RSS20 || type == TypeGetter.Type.RSS091) state.defaultNamespaces.push(Rss20()) } @Throws(SAXException::class) @@ -31,9 +29,7 @@ class SyndHandler(feed: Feed, type: TypeGetter.Type) : DefaultHandler() { @Throws(SAXException::class) override fun characters(ch: CharArray, start: Int, length: Int) { - if (state.tagstack.size >= 2 && state.contentBuf != null) { - state.contentBuf!!.appendRange(ch, start, start + length) - } + if (state.tagstack.size >= 2 && state.contentBuf != null) state.contentBuf!!.appendRange(ch, start, start + length) } @Throws(SAXException::class) @@ -48,9 +44,7 @@ class SyndHandler(feed: Feed, type: TypeGetter.Type) : DefaultHandler() { @Throws(SAXException::class) override fun endPrefixMapping(prefix: String) { - if (state.defaultNamespaces.size > 1 && prefix == DEFAULT_PREFIX) { - state.defaultNamespaces.pop() - } + if (state.defaultNamespaces.size > 1 && prefix == DEFAULT_PREFIX) state.defaultNamespaces.pop() } @Throws(SAXException::class) @@ -60,9 +54,7 @@ class SyndHandler(feed: Feed, type: TypeGetter.Type) : DefaultHandler() { when { uri == Atom.NSURI -> { when (prefix) { - DEFAULT_PREFIX -> { - state.defaultNamespaces.push(Atom()) - } + DEFAULT_PREFIX -> state.defaultNamespaces.push(Atom()) Atom.NSTAG -> { state.namespaces[uri] = Atom() Log.d(TAG, "Recognized Atom namespace") @@ -103,9 +95,7 @@ class SyndHandler(feed: Feed, type: TypeGetter.Type) : DefaultHandler() { private fun getHandlingNamespace(uri: String, qualifiedName: String): Namespace? { var handler = state.namespaces[uri] - if (handler == null && !state.defaultNamespaces.empty() && !qualifiedName.contains(":")) { - handler = state.defaultNamespaces.peek() - } + if (handler == null && !state.defaultNamespaces.empty() && !qualifiedName.contains(":")) handler = state.defaultNamespaces.peek() return handler } diff --git a/app/src/main/java/ac/mdiq/podcini/feed/parser/UnsupportedFeedtypeException.kt b/app/src/main/java/ac/mdiq/podcini/feed/parser/UnsupportedFeedtypeException.kt index cc05ea97..94cf3883 100644 --- a/app/src/main/java/ac/mdiq/podcini/feed/parser/UnsupportedFeedtypeException.kt +++ b/app/src/main/java/ac/mdiq/podcini/feed/parser/UnsupportedFeedtypeException.kt @@ -9,15 +9,9 @@ class UnsupportedFeedtypeException : Exception { override var message: String? = null get() { return when { - field != null -> { - field!! - } - type == TypeGetter.Type.INVALID -> { - "Invalid type" - } - else -> { - "Type $type not supported" - } + field != null -> field!! + type == TypeGetter.Type.INVALID -> "Invalid type" + else -> "Type $type not supported" } } diff --git a/app/src/main/java/ac/mdiq/podcini/feed/parser/element/AtomText.kt b/app/src/main/java/ac/mdiq/podcini/feed/parser/element/AtomText.kt index 7132e3b0..846232c6 100644 --- a/app/src/main/java/ac/mdiq/podcini/feed/parser/element/AtomText.kt +++ b/app/src/main/java/ac/mdiq/podcini/feed/parser/element/AtomText.kt @@ -11,18 +11,11 @@ class AtomText(name: String?, namespace: Namespace?, private val type: String?) val processedContent: String? /** Processes the content according to the type and returns it. */ get() = when (type) { - null -> { - content - } - TYPE_HTML -> { - HtmlCompat.fromHtml(content!!, HtmlCompat.FROM_HTML_MODE_LEGACY).toString() - } - TYPE_XHTML -> { - content - } - else -> { // Handle as text by default - content - } + null -> content + TYPE_HTML -> HtmlCompat.fromHtml(content!!, HtmlCompat.FROM_HTML_MODE_LEGACY).toString() + TYPE_XHTML -> content + // Handle as text by default + else -> content } fun setContent(content: String?) { diff --git a/app/src/main/java/ac/mdiq/podcini/feed/parser/media/id3/ChapterReader.kt b/app/src/main/java/ac/mdiq/podcini/feed/parser/media/id3/ChapterReader.kt index 61f58f9c..e56ba036 100644 --- a/app/src/main/java/ac/mdiq/podcini/feed/parser/media/id3/ChapterReader.kt +++ b/app/src/main/java/ac/mdiq/podcini/feed/parser/media/id3/ChapterReader.kt @@ -75,15 +75,11 @@ class ChapterReader(input: CountingInputStream?) : ID3Reader(input!!) { if (MIME_IMAGE_URL == mime) { val link = readIsoStringNullTerminated(frameHeader.size) Log.d(TAG, "Link: $link") - if (chapter.imageUrl.isNullOrEmpty() || type.toInt() == IMAGE_TYPE_COVER) { - chapter.imageUrl = link - } + if (chapter.imageUrl.isNullOrEmpty() || type.toInt() == IMAGE_TYPE_COVER) chapter.imageUrl = link } else { val alreadyConsumed = position - frameStartPosition val rawImageDataLength = frameHeader.size - alreadyConsumed - if (chapter.imageUrl.isNullOrEmpty() || type.toInt() == IMAGE_TYPE_COVER) { - chapter.imageUrl = makeUrl(position, rawImageDataLength) - } + if (chapter.imageUrl.isNullOrEmpty() || type.toInt() == IMAGE_TYPE_COVER) chapter.imageUrl = makeUrl(position, rawImageDataLength) } } else -> Log.d(TAG, "Unknown chapter sub-frame.") diff --git a/app/src/main/java/ac/mdiq/podcini/feed/parser/media/id3/ID3Reader.kt b/app/src/main/java/ac/mdiq/podcini/feed/parser/media/id3/ID3Reader.kt index a5ed6c3c..2e38d1b9 100644 --- a/app/src/main/java/ac/mdiq/podcini/feed/parser/media/id3/ID3Reader.kt +++ b/app/src/main/java/ac/mdiq/podcini/feed/parser/media/id3/ID3Reader.kt @@ -46,9 +46,8 @@ open class ID3Reader(private val inputStream: CountingInputStream) { */ @Throws(IOException::class, ID3ReaderException::class) fun skipBytes(number: Int) { - if (number < 0) { - throw ID3ReaderException("Trying to read a negative number of bytes") - } + if (number < 0) throw ID3ReaderException("Trying to read a negative number of bytes") + IOUtils.skipFully(inputStream, number.toLong()) } @@ -76,9 +75,7 @@ open class ID3Reader(private val inputStream: CountingInputStream) { @Throws(ID3ReaderException::class, IOException::class) fun expectChar(expected: Char) { val read = inputStream.read().toChar() - if (read != expected) { - throw ID3ReaderException("Expected $expected and got $read") - } + if (read != expected) throw ID3ReaderException("Expected $expected and got $read") } @Throws(ID3ReaderException::class, IOException::class) @@ -100,9 +97,8 @@ open class ID3Reader(private val inputStream: CountingInputStream) { fun readFrameHeader(): FrameHeader { val id = readPlainBytesToString(FRAME_ID_LENGTH) var size = readInt() - if (tagHeader != null && tagHeader!!.version >= 0x0400) { - size = unsynchsafe(size) - } + if (tagHeader != null && tagHeader!!.version >= 0x0400) size = unsynchsafe(size) + val flags = readShort() return FrameHeader(id, size, flags) } @@ -148,15 +144,9 @@ open class ID3Reader(private val inputStream: CountingInputStream) { @Throws(IOException::class) fun readEncodedString(encoding: Int, max: Int): String { return when (encoding) { - ENCODING_UTF16_WITH_BOM.toInt(), ENCODING_UTF16_WITHOUT_BOM.toInt() -> { - readEncodedString2(Charset.forName("UTF-16"), max) - } - ENCODING_UTF8.toInt() -> { - readEncodedString2(Charset.forName("UTF-8"), max) - } - else -> { - readEncodedString1(Charset.forName("ISO-8859-1"), max) - } + ENCODING_UTF16_WITH_BOM.toInt(), ENCODING_UTF16_WITHOUT_BOM.toInt() -> readEncodedString2(Charset.forName("UTF-16"), max) + ENCODING_UTF8.toInt() -> readEncodedString2(Charset.forName("UTF-8"), max) + else -> readEncodedString1(Charset.forName("ISO-8859-1"), max) } } @@ -170,9 +160,8 @@ open class ID3Reader(private val inputStream: CountingInputStream) { while (bytesRead < max) { val c = readByte() bytesRead++ - if (c.toInt() == 0) { - break - } + if (c.toInt() == 0) break + bytes.write(c.toInt()) } return charset.newDecoder().decode(ByteBuffer.wrap(bytes.toByteArray())).toString() @@ -200,9 +189,7 @@ open class ID3Reader(private val inputStream: CountingInputStream) { if (!foundEnd && bytesRead < max) { // Last character val c = readByte() - if (c.toInt() != 0) { - bytes.write(c.toInt()) - } + if (c.toInt() != 0) bytes.write(c.toInt()) } return try { charset.newDecoder().decode(ByteBuffer.wrap(bytes.toByteArray())).toString() diff --git a/app/src/main/java/ac/mdiq/podcini/feed/parser/media/id3/Id3MetadataReader.kt b/app/src/main/java/ac/mdiq/podcini/feed/parser/media/id3/Id3MetadataReader.kt index 0113a0fe..c3d0bf70 100644 --- a/app/src/main/java/ac/mdiq/podcini/feed/parser/media/id3/Id3MetadataReader.kt +++ b/app/src/main/java/ac/mdiq/podcini/feed/parser/media/id3/Id3MetadataReader.kt @@ -18,8 +18,7 @@ class Id3MetadataReader(input: CountingInputStream?) : ID3Reader(input!!) { val encoding = readByte().toInt() skipBytes(3) // Language val shortDescription = readEncodedString(encoding, frameHeader.size - 4) - val longDescription = readEncodedString(encoding, - (frameHeader.size - (position - frameStart)).toInt()) + val longDescription = readEncodedString(encoding, (frameHeader.size - (position - frameStart)).toInt()) comment = if (shortDescription.length > longDescription.length) shortDescription else longDescription } else { super.readFrame(frameHeader) diff --git a/app/src/main/java/ac/mdiq/podcini/feed/parser/media/vorbis/VorbisCommentChapterReader.kt b/app/src/main/java/ac/mdiq/podcini/feed/parser/media/vorbis/VorbisCommentChapterReader.kt index 263ee1b3..fb1bf380 100644 --- a/app/src/main/java/ac/mdiq/podcini/feed/parser/media/vorbis/VorbisCommentChapterReader.kt +++ b/app/src/main/java/ac/mdiq/podcini/feed/parser/media/vorbis/VorbisCommentChapterReader.kt @@ -15,9 +15,8 @@ class VorbisCommentChapterReader(input: InputStream?) : VorbisCommentReader(inpu @Throws(VorbisCommentReaderException::class) public override fun onContentVectorValue(key: String?, value: String?) { - if (BuildConfig.DEBUG) { - Log.d(TAG, "Key: $key, value: $value") - } + if (BuildConfig.DEBUG) Log.d(TAG, "Key: $key, value: $value") + val attribute = getAttributeTypeFromKey(key) val id = getIdFromKey(key) var chapter = getChapterById(id.toLong()) @@ -30,24 +29,16 @@ class VorbisCommentChapterReader(input: InputStream?) : VorbisCommentReader(inpu chapter.chapterId = "" + id chapter.start = start chapters.add(chapter) - } else { - throw VorbisCommentReaderException("Found chapter with duplicate ID ($key, $value)") - } - } - CHAPTER_ATTRIBUTE_TITLE -> { - if (chapter != null) chapter.title = value - } - CHAPTER_ATTRIBUTE_LINK -> { - if (chapter != null) chapter.link = value + } else throw VorbisCommentReaderException("Found chapter with duplicate ID ($key, $value)") } + CHAPTER_ATTRIBUTE_TITLE -> if (chapter != null) chapter.title = value + CHAPTER_ATTRIBUTE_LINK -> if (chapter != null) chapter.link = value } } private fun getChapterById(id: Long): Chapter? { for (c in chapters) { - if (("" + id) == c.chapterId) { - return c - } + if (("" + id) == c.chapterId) return c } return null } @@ -73,11 +64,8 @@ class VorbisCommentChapterReader(input: InputStream?) : VorbisCommentReader(inpu parts[0].toLong(), TimeUnit.HOURS) val minutes = TimeUnit.MILLISECONDS.convert( parts[1].toLong(), TimeUnit.MINUTES) - if (parts[2].contains("-->")) { - parts[2] = parts[2].substring(0, parts[2].indexOf("-->")) - } - val seconds = TimeUnit.MILLISECONDS.convert( - (parts[2].toFloat().toLong()), TimeUnit.SECONDS) + if (parts[2].contains("-->")) parts[2] = parts[2].substring(0, parts[2].indexOf("-->")) + val seconds = TimeUnit.MILLISECONDS.convert((parts[2].toFloat().toLong()), TimeUnit.SECONDS) return hours + minutes + seconds } catch (e: NumberFormatException) { throw VorbisCommentReaderException(e) @@ -111,9 +99,8 @@ class VorbisCommentChapterReader(input: InputStream?) : VorbisCommentReader(inpu * 'url'. */ private fun getAttributeTypeFromKey(key: String?): String? { - if (key!!.length > CHAPTERXXX_LENGTH) { - return key.substring(CHAPTERXXX_LENGTH) - } + if (key!!.length > CHAPTERXXX_LENGTH) return key.substring(CHAPTERXXX_LENGTH) + return null } } diff --git a/app/src/main/java/ac/mdiq/podcini/feed/parser/media/vorbis/VorbisCommentMetadataReader.kt b/app/src/main/java/ac/mdiq/podcini/feed/parser/media/vorbis/VorbisCommentMetadataReader.kt index 3ba8cf80..78c1db0c 100644 --- a/app/src/main/java/ac/mdiq/podcini/feed/parser/media/vorbis/VorbisCommentMetadataReader.kt +++ b/app/src/main/java/ac/mdiq/podcini/feed/parser/media/vorbis/VorbisCommentMetadataReader.kt @@ -12,9 +12,7 @@ class VorbisCommentMetadataReader(input: InputStream?) : VorbisCommentReader(inp public override fun onContentVectorValue(key: String?, value: String?) { if (KEY_DESCRIPTION == key || KEY_COMMENT == key) { - if (description == null || (value != null && value.length > description!!.length)) { - description = value - } + if (description == null || (value != null && value.length > description!!.length)) description = value } } diff --git a/app/src/main/java/ac/mdiq/podcini/feed/parser/media/vorbis/VorbisCommentReader.kt b/app/src/main/java/ac/mdiq/podcini/feed/parser/media/vorbis/VorbisCommentReader.kt index dd0c1b80..2c813f8a 100644 --- a/app/src/main/java/ac/mdiq/podcini/feed/parser/media/vorbis/VorbisCommentReader.kt +++ b/app/src/main/java/ac/mdiq/podcini/feed/parser/media/vorbis/VorbisCommentReader.kt @@ -33,13 +33,10 @@ abstract class VorbisCommentReader internal constructor(private val input: Input val oggPageHeader = byteArrayOf('O'.code.toByte(), 'g'.code.toByte(), 'g'.code.toByte(), 'S'.code.toByte()) for (bytesRead in 0 until SECOND_PAGE_MAX_LENGTH) { val data = input.read() - if (data == -1) { - throw IOException("EOF while trying to find vorbis page") - } + if (data == -1) throw IOException("EOF while trying to find vorbis page") + buffer[bytesRead % buffer.size] = data.toByte() - if (bufferMatches(buffer, oggPageHeader, bytesRead)) { - break - } + if (bufferMatches(buffer, oggPageHeader, bytesRead)) break } // read segments IOUtils.skipFully(input, 22) @@ -53,8 +50,7 @@ abstract class VorbisCommentReader internal constructor(private val input: Input val vectorLength = EndianUtils.readSwappedUnsignedInteger(input) if (vectorLength > 20 * 1024 * 1024) { val keyPart = readUtf8String(10) - throw VorbisCommentReaderException("User comment unrealistically long. " - + "key=" + keyPart + ", length=" + vectorLength) + throw VorbisCommentReaderException("User comment unrealistically long. key=$keyPart, length=$vectorLength") } val key = readContentVectorKey(vectorLength)!!.lowercase() val shouldReadValue = handles(key) @@ -62,9 +58,8 @@ abstract class VorbisCommentReader internal constructor(private val input: Input if (shouldReadValue) { val value = readUtf8String(vectorLength - key.length - 1) onContentVectorValue(key, value) - } else { - IOUtils.skipFully(input, vectorLength - key.length - 1) - } + } else IOUtils.skipFully(input, vectorLength - key.length - 1) + } catch (e: IOException) { e.printStackTrace() } @@ -99,9 +94,7 @@ abstract class VorbisCommentReader internal constructor(private val input: Input IOUtils.skip(input, (FIRST_OGG_PAGE_LENGTH - FIRST_OPUS_PAGE_LENGTH).toLong()) return } - bufferMatches(buffer, "OpusHead".toByteArray(), i) -> { - return - } + bufferMatches(buffer, "OpusHead".toByteArray(), i) -> return } } throw IOException("No vorbis identification header found") @@ -120,12 +113,8 @@ abstract class VorbisCommentReader internal constructor(private val input: Input for (bytesRead in 0 until SECOND_PAGE_MAX_LENGTH) { buffer[bytesRead % buffer.size] = input.read().toByte() when { - bufferMatches(buffer, oggCommentHeader, bytesRead) -> { - return - } - bufferMatches(buffer, "OpusTags".toByteArray(), bytesRead) -> { - return - } + bufferMatches(buffer, oggCommentHeader, bytesRead) -> return + bufferMatches(buffer, "OpusTags".toByteArray(), bytesRead) -> return } } throw IOException("No comment header found") @@ -142,9 +131,7 @@ abstract class VorbisCommentReader internal constructor(private val input: Input posInHaystack += haystack.size } posInHaystack %= haystack.size - if (haystack[posInHaystack] != needle[needle.size - 1 - i]) { - return false - } + if (haystack[posInHaystack] != needle[needle.size - 1 - i]) return false } return true } @@ -166,11 +153,8 @@ abstract class VorbisCommentReader internal constructor(private val input: Input val builder = StringBuilder() for (i in 0 until vectorLength) { val c = input.read().toChar() - if (c == '=') { - return builder.toString() - } else { - builder.append(c) - } + if (c == '=') return builder.toString() + else builder.append(c) } return null // no key found } diff --git a/app/src/main/java/ac/mdiq/podcini/feed/parser/namespace/Atom.kt b/app/src/main/java/ac/mdiq/podcini/feed/parser/namespace/Atom.kt index 8c06138f..6e427b2e 100644 --- a/app/src/main/java/ac/mdiq/podcini/feed/parser/namespace/Atom.kt +++ b/app/src/main/java/ac/mdiq/podcini/feed/parser/namespace/Atom.kt @@ -33,29 +33,22 @@ class Atom : Namespace() { when { parent.name.matches(isFeedItem.toRegex()) -> { when { - rel == null || LINK_REL_ALTERNATE == rel -> { - if (state.currentItem != null) state.currentItem!!.link = href - } + rel == null || LINK_REL_ALTERNATE == rel -> if (state.currentItem != null) state.currentItem!!.link = href LINK_REL_ENCLOSURE == rel -> { val strSize: String? = attributes.getValue(LINK_LENGTH) var size: Long = 0 try { - if (strSize != null) { - size = strSize.toLong() - } + if (strSize != null) size = strSize.toLong() } catch (e: NumberFormatException) { Log.d(TAG, "Length attribute could not be parsed.") } val mimeType: String? = getMimeType(attributes.getValue(LINK_TYPE), href) val currItem = state.currentItem - if (isMediaFile(mimeType) && currItem != null && !currItem.hasMedia()) { + if (isMediaFile(mimeType) && currItem != null && !currItem.hasMedia()) currItem.media = FeedMedia(currItem, href, size, mimeType) - } - } - LINK_REL_PAYMENT == rel -> { - if (state.currentItem != null) state.currentItem!!.paymentLink = href } + LINK_REL_PAYMENT == rel -> if (state.currentItem != null) state.currentItem!!.paymentLink = href } } parent.name.matches(isFeed.toRegex()) -> { @@ -68,15 +61,12 @@ class Atom : Namespace() { * LINK_TYPE_HTML or LINK_TYPE_XHTML */ when { - type == null && state.feed.link == null || LINK_TYPE_HTML == type || LINK_TYPE_XHTML == type -> { + type == null && state.feed.link == null || LINK_TYPE_HTML == type || LINK_TYPE_XHTML == type -> state.feed.link = href - } LINK_TYPE_ATOM == type || LINK_TYPE_RSS == type -> { // treat as podlove alternate feed var title: String? = attributes.getValue(LINK_TITLE) - if (title.isNullOrEmpty()) { - title = href?:"" - } + if (title.isNullOrEmpty()) title = href?:"" if (!href.isNullOrEmpty()) state.addAlternateFeedUrl(title, href) } } @@ -86,9 +76,7 @@ class Atom : Namespace() { when { LINK_TYPE_ATOM == type || LINK_TYPE_RSS == type -> { var title: String? = attributes.getValue(LINK_TITLE) - if (title.isNullOrEmpty()) { - title = href?:"" - } + if (title.isNullOrEmpty()) title = href?:"" if (!href.isNullOrEmpty()) state.addAlternateFeedUrl(title, href) } LINK_TYPE_HTML == type || LINK_TYPE_XHTML == type -> { @@ -96,9 +84,7 @@ class Atom : Namespace() { } } } - LINK_REL_PAYMENT == rel -> { - state.feed.addPayment(FeedFunding(href, "")) - } + LINK_REL_PAYMENT == rel -> state.feed.addPayment(FeedFunding(href, "")) LINK_REL_NEXT == rel -> { state.feed.isPaged = true state.feed.nextPageLink = href @@ -114,8 +100,7 @@ class Atom : Namespace() { override fun handleElementEnd(localName: String, state: HandlerState) { Log.d(TAG, "handleElementEnd $localName") if (ENTRY == localName) { - if (state.currentItem != null && - state.tempObjects.containsKey(Itunes.DURATION)) { + if (state.currentItem != null && state.tempObjects.containsKey(Itunes.DURATION)) { val currentItem = state.currentItem if (currentItem!!.hasMedia()) { val duration = state.tempObjects[Itunes.DURATION] as Int? @@ -128,11 +113,7 @@ class Atom : Namespace() { if (state.tagstack.size >= 2) { var textElement: AtomText? = null - val contentRaw = if (state.contentBuf != null) { - state.contentBuf.toString() - } else { - "" - } + val contentRaw = if (state.contentBuf != null) state.contentBuf.toString() else "" val content = trimAllWhitespace(contentRaw) val topElement = state.tagstack.peek() val top = topElement.name @@ -147,52 +128,30 @@ class Atom : Namespace() { when { ID == top -> { when { - FEED == second -> { - state.feed.feedIdentifier = contentRaw - } - ENTRY == second && state.currentItem != null -> { - state.currentItem!!.itemIdentifier = contentRaw - } + FEED == second -> state.feed.feedIdentifier = contentRaw + ENTRY == second && state.currentItem != null -> state.currentItem!!.itemIdentifier = contentRaw } } TITLE == top && textElement != null -> { when { - FEED == second -> { - state.feed.title = textElement.processedContent - } - ENTRY == second && state.currentItem != null -> { - state.currentItem!!.title = textElement.processedContent - } + FEED == second -> state.feed.title = textElement.processedContent + ENTRY == second && state.currentItem != null -> state.currentItem!!.title = textElement.processedContent } } - SUBTITLE == top && FEED == second && textElement != null -> { - state.feed.description = textElement.processedContent - } - CONTENT == top && ENTRY == second && textElement != null && state.currentItem != null -> { + SUBTITLE == top && FEED == second && textElement != null -> state.feed.description = textElement.processedContent + CONTENT == top && ENTRY == second && textElement != null && state.currentItem != null -> state.currentItem!!.setDescriptionIfLonger(textElement.processedContent) - } - SUMMARY == top && ENTRY == second && textElement != null && state.currentItem != null -> { + SUMMARY == top && ENTRY == second && textElement != null && state.currentItem != null -> state.currentItem!!.setDescriptionIfLonger(textElement.processedContent) - } - UPDATED == top && ENTRY == second && state.currentItem != null && state.currentItem!!.pubDate == null -> { + UPDATED == top && ENTRY == second && state.currentItem != null && state.currentItem!!.pubDate == null -> state.currentItem!!.pubDate = parseOrNullIfFuture(content) - } - PUBLISHED == top && ENTRY == second && state.currentItem != null -> { - state.currentItem!!.pubDate = parseOrNullIfFuture(content) - } - IMAGE_LOGO == top && state.feed.imageUrl == null -> { - state.feed.imageUrl = content - } - IMAGE_ICON == top -> { - state.feed.imageUrl = content - } + PUBLISHED == top && ENTRY == second && state.currentItem != null -> state.currentItem!!.pubDate = parseOrNullIfFuture(content) + IMAGE_LOGO == top && state.feed.imageUrl == null -> state.feed.imageUrl = content + IMAGE_ICON == top -> state.feed.imageUrl = content AUTHOR_NAME == top && AUTHOR == second && state.currentItem == null -> { val currentName = state.feed.author - if (currentName == null) { - state.feed.author = content - } else { - state.feed.author = "$currentName, $content" - } + if (currentName == null) state.feed.author = content + else state.feed.author = "$currentName, $content" } } } diff --git a/app/src/main/java/ac/mdiq/podcini/feed/parser/namespace/Itunes.kt b/app/src/main/java/ac/mdiq/podcini/feed/parser/namespace/Itunes.kt index b313534e..43bb89d0 100644 --- a/app/src/main/java/ac/mdiq/podcini/feed/parser/namespace/Itunes.kt +++ b/app/src/main/java/ac/mdiq/podcini/feed/parser/namespace/Itunes.kt @@ -18,29 +18,21 @@ class Itunes : Namespace() { } else { // this is the feed image // prefer to all other images - if (!url.isNullOrEmpty()) { - state.feed.imageUrl = url - } + if (!url.isNullOrEmpty()) state.feed.imageUrl = url } } return SyndElement(localName, this) } override fun handleElementEnd(localName: String, state: HandlerState) { - if (state.contentBuf == null) { - return - } + if (state.contentBuf == null) return val content = state.contentBuf.toString() val contentFromHtml = HtmlCompat.fromHtml(content, HtmlCompat.FROM_HTML_MODE_COMPACT).toString() - if (content.isEmpty()) { - return - } + if (content.isEmpty()) return when { - AUTHOR == localName && state.tagstack.size <= 3 -> { - state.feed.author = contentFromHtml - } + AUTHOR == localName && state.tagstack.size <= 3 -> state.feed.author = contentFromHtml DURATION == localName -> { try { val durationMs = inMillis(content) @@ -51,27 +43,17 @@ class Itunes : Namespace() { } SUBTITLE == localName -> { when { - state.currentItem != null && state.currentItem?.description.isNullOrEmpty() -> { - state.currentItem!!.setDescriptionIfLonger(content) - } - state.feed.description.isNullOrEmpty() -> { - state.feed.description = content - } + state.currentItem != null && state.currentItem?.description.isNullOrEmpty() -> state.currentItem!!.setDescriptionIfLonger(content) + state.feed.description.isNullOrEmpty() -> state.feed.description = content } } SUMMARY == localName -> { when { - state.currentItem != null -> { - state.currentItem!!.setDescriptionIfLonger(content) - } - Rss20.CHANNEL == state.secondTag.name -> { - state.feed.description = content - } + state.currentItem != null -> state.currentItem!!.setDescriptionIfLonger(content) + Rss20.CHANNEL == state.secondTag.name -> state.feed.description = content } } - NEW_FEED_URL == localName && content.trim { it <= ' ' }.startsWith("http") -> { - state.redirectUrl = content.trim { it <= ' ' } - } + NEW_FEED_URL == localName && content.trim { it <= ' ' }.startsWith("http") -> state.redirectUrl = content.trim { it <= ' ' } } } diff --git a/app/src/main/java/ac/mdiq/podcini/feed/parser/namespace/Media.kt b/app/src/main/java/ac/mdiq/podcini/feed/parser/namespace/Media.kt index 9517bba9..9e807c56 100644 --- a/app/src/main/java/ac/mdiq/podcini/feed/parser/namespace/Media.kt +++ b/app/src/main/java/ac/mdiq/podcini/feed/parser/namespace/Media.kt @@ -34,20 +34,15 @@ class Media : Namespace() { validTypeMedia = true mimeType = "video/*" } - MEDIUM_IMAGE == medium && (mimeType == null - || (!mimeType.startsWith("audio/") && !mimeType.startsWith("video/"))) -> { + MEDIUM_IMAGE == medium && (mimeType == null || (!mimeType.startsWith("audio/") && !mimeType.startsWith("video/"))) -> { // Apparently, some publishers explicitly specify the audio file as an image validTypeImage = true mimeType = "image/*" } else -> { when { - isMediaFile(mimeType) -> { - validTypeMedia = true - } - isImageFile(mimeType) -> { - validTypeImage = true - } + isMediaFile(mimeType) -> validTypeMedia = true + isImageFile(mimeType) -> validTypeImage = true } } } @@ -75,9 +70,8 @@ class Media : Namespace() { } Log.d(TAG, "handleElementStart creating media: ${state.currentItem?.title} $url $size $mimeType") val media = FeedMedia(state.currentItem, url, size, mimeType) - if (durationMs > 0) { - media.setDuration( durationMs) - } + if (durationMs > 0) media.setDuration( durationMs) + state.currentItem!!.media = media } state.currentItem != null && url != null && validTypeImage -> { @@ -89,14 +83,8 @@ class Media : Namespace() { val url: String? = attributes.getValue(IMAGE_URL) if (url != null) { when { - state.currentItem != null -> { - state.currentItem!!.imageUrl = url - } - else -> { - if (state.feed.imageUrl == null) { - state.feed.imageUrl = url - } - } + state.currentItem != null -> state.currentItem!!.imageUrl = url + else -> if (state.feed.imageUrl == null) state.feed.imageUrl = url } } } diff --git a/app/src/main/java/ac/mdiq/podcini/feed/parser/namespace/PodcastIndex.kt b/app/src/main/java/ac/mdiq/podcini/feed/parser/namespace/PodcastIndex.kt index 7d88dc53..b3f95c0e 100644 --- a/app/src/main/java/ac/mdiq/podcini/feed/parser/namespace/PodcastIndex.kt +++ b/app/src/main/java/ac/mdiq/podcini/feed/parser/namespace/PodcastIndex.kt @@ -17,22 +17,17 @@ class PodcastIndex : Namespace() { } CHAPTERS == localName -> { val href: String? = attributes.getValue(URL) - if (state.currentItem != null && !href.isNullOrEmpty()) { - state.currentItem!!.podcastIndexChapterUrl = href - } + if (state.currentItem != null && !href.isNullOrEmpty()) state.currentItem!!.podcastIndexChapterUrl = href } } return SyndElement(localName, this) } override fun handleElementEnd(localName: String, state: HandlerState) { - if (state.contentBuf == null) { - return - } + if (state.contentBuf == null) return + val content = state.contentBuf.toString() - if (FUNDING == localName && state.currentFunding != null && content.isNotEmpty()) { - state.currentFunding!!.setContent(content) - } + if (FUNDING == localName && state.currentFunding != null && content.isNotEmpty()) state.currentFunding!!.setContent(content) } companion object { diff --git a/app/src/main/java/ac/mdiq/podcini/feed/parser/namespace/Rss20.kt b/app/src/main/java/ac/mdiq/podcini/feed/parser/namespace/Rss20.kt index 3bfec56a..c0002bb2 100644 --- a/app/src/main/java/ac/mdiq/podcini/feed/parser/namespace/Rss20.kt +++ b/app/src/main/java/ac/mdiq/podcini/feed/parser/namespace/Rss20.kt @@ -32,10 +32,8 @@ class Rss20 : Namespace() { var size: Long = 0 try { size = attributes.getValue(ENC_LEN)?.toLong() ?: 0 - if (size < 16384) { - // less than 16kb is suspicious, check manually - size = 0 - } + // less than 16kb is suspicious, check manually + if (size < 16384) size = 0 } catch (e: NumberFormatException) { Log.d(TAG, "Length attribute could not be parsed.") } @@ -54,9 +52,7 @@ class Rss20 : Namespace() { val currentItem = state.currentItem!! // the title tag is optional in RSS 2.0. The description is used // as a title if the item has no title-tag. - if (currentItem.title == null) { - currentItem.title = currentItem.description - } + if (currentItem.title == null) currentItem.title = currentItem.description if (state.tempObjects.containsKey(Itunes.DURATION)) { if (currentItem.hasMedia()) { @@ -77,59 +73,38 @@ class Rss20 : Namespace() { val secondElement = state.secondTag val second = secondElement.name var third: String? = null - if (state.tagstack.size >= 3) { - third = state.thirdTag.name - } + if (state.tagstack.size >= 3) third = state.thirdTag.name + when { GUID == top && ITEM == second -> { // some feed creators include an empty or non-standard guid-element in their feed, // which should be ignored - if (contentRaw.isNotEmpty() && state.currentItem != null) { - state.currentItem!!.itemIdentifier = contentRaw - } + if (contentRaw.isNotEmpty() && state.currentItem != null) state.currentItem!!.itemIdentifier = contentRaw } TITLE == top -> { when { - ITEM == second && state.currentItem != null -> { - state.currentItem!!.title = contentFromHtml - } - CHANNEL == second -> { - state.feed.title = contentFromHtml - } + ITEM == second && state.currentItem != null -> state.currentItem!!.title = contentFromHtml + CHANNEL == second -> state.feed.title = contentFromHtml } } LINK == top -> { when { - CHANNEL == second -> { - state.feed.link = content - } - ITEM == second && state.currentItem != null -> { - state.currentItem!!.link = content - } + CHANNEL == second -> state.feed.link = content + ITEM == second && state.currentItem != null -> state.currentItem!!.link = content } } - PUBDATE == top && ITEM == second && state.currentItem != null -> { - state.currentItem!!.pubDate = parseOrNullIfFuture(content) - } + PUBDATE == top && ITEM == second && state.currentItem != null -> state.currentItem!!.pubDate = parseOrNullIfFuture(content) URL == top && IMAGE == second && CHANNEL == third -> { // prefer itunes:image - if (state.feed.imageUrl == null) { - state.feed.imageUrl = content - } + if (state.feed.imageUrl == null) state.feed.imageUrl = content } DESCR == localName -> { when { - CHANNEL == second -> { - state.feed.description = contentFromHtml - } - ITEM == second && state.currentItem != null -> { - state.currentItem!!.setDescriptionIfLonger(content) // fromHtml here breaks \n when not html - } + CHANNEL == second -> state.feed.description = contentFromHtml + ITEM == second && state.currentItem != null -> state.currentItem!!.setDescriptionIfLonger(content) // fromHtml here breaks \n when not html } } - LANGUAGE == localName -> { - state.feed.language = content.lowercase() - } + LANGUAGE == localName -> state.feed.language = content.lowercase() } } } diff --git a/app/src/main/java/ac/mdiq/podcini/feed/parser/namespace/SimpleChapters.kt b/app/src/main/java/ac/mdiq/podcini/feed/parser/namespace/SimpleChapters.kt index e39e5ead..a22aa038 100644 --- a/app/src/main/java/ac/mdiq/podcini/feed/parser/namespace/SimpleChapters.kt +++ b/app/src/main/java/ac/mdiq/podcini/feed/parser/namespace/SimpleChapters.kt @@ -12,9 +12,7 @@ class SimpleChapters : Namespace() { val currentItem = state.currentItem if (currentItem != null) { when { - localName == CHAPTERS -> { - currentItem.chapters = mutableListOf() - } + localName == CHAPTERS -> currentItem.chapters = mutableListOf() localName == CHAPTER && !attributes.getValue(START).isNullOrEmpty() -> { // if the chapter's START is empty, we don't need to do anything try { diff --git a/app/src/main/java/ac/mdiq/podcini/feed/parser/namespace/YouTube.kt b/app/src/main/java/ac/mdiq/podcini/feed/parser/namespace/YouTube.kt index fa666287..ec468ea8 100644 --- a/app/src/main/java/ac/mdiq/podcini/feed/parser/namespace/YouTube.kt +++ b/app/src/main/java/ac/mdiq/podcini/feed/parser/namespace/YouTube.kt @@ -18,9 +18,7 @@ class YouTube : Namespace() { } else { // this is the feed image // prefer to all other images - if (!url.isNullOrEmpty()) { - state.feed.imageUrl = url - } + if (!url.isNullOrEmpty()) state.feed.imageUrl = url } } return SyndElement(localName, this) @@ -28,20 +26,14 @@ class YouTube : Namespace() { override fun handleElementEnd(localName: String, state: HandlerState) { Log.d(TAG, "handleElementEnd $localName") - if (state.contentBuf == null) { - return - } + if (state.contentBuf == null) return val content = state.contentBuf.toString() val contentFromHtml = HtmlCompat.fromHtml(content, HtmlCompat.FROM_HTML_MODE_COMPACT).toString() - if (content.isEmpty()) { - return - } + if (content.isEmpty()) return when { - AUTHOR == localName && state.tagstack.size <= 3 -> { - state.feed.author = contentFromHtml - } + AUTHOR == localName && state.tagstack.size <= 3 -> state.feed.author = contentFromHtml DURATION == localName -> { try { val durationMs = inMillis(content) @@ -52,27 +44,17 @@ class YouTube : Namespace() { } SUBTITLE == localName -> { when { - state.currentItem != null && state.currentItem?.description.isNullOrEmpty() -> { - state.currentItem!!.setDescriptionIfLonger(content) - } - state.feed.description.isNullOrEmpty() -> { - state.feed.description = content - } + state.currentItem != null && state.currentItem?.description.isNullOrEmpty() -> state.currentItem!!.setDescriptionIfLonger(content) + state.feed.description.isNullOrEmpty() -> state.feed.description = content } } SUMMARY == localName -> { when { - state.currentItem != null -> { - state.currentItem!!.setDescriptionIfLonger(content) - } - Rss20.CHANNEL == state.secondTag.name -> { - state.feed.description = content - } + state.currentItem != null -> state.currentItem!!.setDescriptionIfLonger(content) + Rss20.CHANNEL == state.secondTag.name -> state.feed.description = content } } - NEW_FEED_URL == localName && content.trim { it <= ' ' }.startsWith("http") -> { - state.redirectUrl = content.trim { it <= ' ' } - } + NEW_FEED_URL == localName && content.trim { it <= ' ' }.startsWith("http") -> state.redirectUrl = content.trim { it <= ' ' } } } diff --git a/app/src/main/java/ac/mdiq/podcini/feed/parser/util/DateUtils.kt b/app/src/main/java/ac/mdiq/podcini/feed/parser/util/DateUtils.kt index 4821919a..14b3b18e 100644 --- a/app/src/main/java/ac/mdiq/podcini/feed/parser/util/DateUtils.kt +++ b/app/src/main/java/ac/mdiq/podcini/feed/parser/util/DateUtils.kt @@ -38,20 +38,13 @@ object DateUtils { // even more precise than microseconds: discard further decimal places when { current - start > 4 -> { - date = if (current < date.length - 1) { - date.substring(0, start + 4) + date.substring(current) - } else { - date.substring(0, start + 4) - } + date = if (current < date.length - 1) date.substring(0, start + 4) + date.substring(current) else date.substring(0, start + 4) // less than 4 decimal places: pad to have a consistent format for the parser } current - start < 4 -> { - date = if (current < date.length - 1) { - (date.substring(0, current) + StringUtils.repeat("0", 4 - (current - start)) - + date.substring(current)) - } else { - date.substring(0, current) + StringUtils.repeat("0", 4 - (current - start)) - } + date = if (current < date.length - 1) + (date.substring(0, current) + StringUtils.repeat("0", 4 - (current - start)) + date.substring(current)) + else date.substring(0, current) + StringUtils.repeat("0", 4 - (current - start)) } } } @@ -96,18 +89,14 @@ object DateUtils { pos.index = 0 try { val result = parser.parse(date, pos) - if (result != null && pos.index == date.length) { - return result - } + if (result != null && pos.index == date.length) return result } catch (e: Exception) { Log.e(TAG, Log.getStackTraceString(e)) } } // if date string starts with a weekday, try parsing date string without it - if (date.matches("^\\w+, .*$".toRegex())) { - return parse(date.substring(date.indexOf(',') + 1)) - } + if (date.matches("^\\w+, .*$".toRegex())) return parse(date.substring(date.indexOf(',') + 1)) Log.d(TAG, "Could not parse date string \"$input\" [$date]") return null @@ -120,9 +109,7 @@ object DateUtils { fun parseOrNullIfFuture(input: String?): Date? { val date = parse(input) ?: return null val now = Date() - if (date.after(now)) { - return null - } + if (date.after(now)) return null return date } diff --git a/app/src/main/java/ac/mdiq/podcini/feed/parser/util/DurationParser.kt b/app/src/main/java/ac/mdiq/podcini/feed/parser/util/DurationParser.kt index da7f3167..2649ed02 100644 --- a/app/src/main/java/ac/mdiq/podcini/feed/parser/util/DurationParser.kt +++ b/app/src/main/java/ac/mdiq/podcini/feed/parser/util/DurationParser.kt @@ -9,25 +9,15 @@ object DurationParser { val parts = durationStr.trim { it <= ' ' }.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() return when (parts.size) { - 1 -> { - toMillis(parts[0]) - } - 2 -> { - toMillis("0", parts[0], parts[1]) - } - 3 -> { - toMillis(parts[0], parts[1], parts[2]) - } - else -> { - throw NumberFormatException() - } + 1 -> toMillis(parts[0]) + 2 -> toMillis("0", parts[0], parts[1]) + 3 -> toMillis(parts[0], parts[1], parts[2]) + else -> throw NumberFormatException() } } private fun toMillis(hours: String, minutes: String, seconds: String): Long { - return (TimeUnit.HOURS.toMillis(hours.toLong()) - + TimeUnit.MINUTES.toMillis(minutes.toLong()) - + toMillis(seconds)) + return (TimeUnit.HOURS.toMillis(hours.toLong()) + TimeUnit.MINUTES.toMillis(minutes.toLong()) + toMillis(seconds)) } private fun toMillis(seconds: String): Long { diff --git a/app/src/main/java/ac/mdiq/podcini/feed/parser/util/MimeTypeUtils.kt b/app/src/main/java/ac/mdiq/podcini/feed/parser/util/MimeTypeUtils.kt index 61e5f3c6..4e0b3b16 100644 --- a/app/src/main/java/ac/mdiq/podcini/feed/parser/util/MimeTypeUtils.kt +++ b/app/src/main/java/ac/mdiq/podcini/feed/parser/util/MimeTypeUtils.kt @@ -21,24 +21,19 @@ object MimeTypeUtils { @JvmStatic fun getMimeType(type: String?, filename: String?): String? { - if (isMediaFile(type) && OCTET_STREAM != type) { - return type - } + if (isMediaFile(type) && OCTET_STREAM != type) return type + val filenameType = getMimeTypeFromUrl(filename) - if (isMediaFile(filenameType)) { - return filenameType - } + if (isMediaFile(filenameType)) return filenameType + return type } @JvmStatic fun isMediaFile(type: String?): Boolean { - return if (type == null) { - false - } else { - type.startsWith("audio/") || type.startsWith("video/") || - type == "application/ogg" || type == "application/octet-stream" || type == "application/x-shockwave-flash" - } + return if (type == null) false + else type.startsWith("audio/") || type.startsWith("video/") || type == "application/ogg" + || type == "application/octet-stream" || type == "application/x-shockwave-flash" } @JvmStatic @@ -51,23 +46,16 @@ object MimeTypeUtils { * method will return the mime-type of the file extension. */ private fun getMimeTypeFromUrl(url: String?): String? { - if (url == null) { - return null - } + if (url == null) return null + val extension = FilenameUtils.getExtension(url) val mapResult = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension) - if (mapResult != null) { - return mapResult - } + if (mapResult != null) return mapResult - when { - AUDIO_FILE_EXTENSIONS.contains(extension) -> { - return "audio/*" - } - VIDEO_FILE_EXTENSIONS.contains(extension) -> { - return "video/*" - } - else -> return null + return when { + AUDIO_FILE_EXTENSIONS.contains(extension) -> "audio/*" + VIDEO_FILE_EXTENSIONS.contains(extension) -> "video/*" + else -> null } } } diff --git a/app/src/main/java/ac/mdiq/podcini/feed/parser/util/TypeGetter.kt b/app/src/main/java/ac/mdiq/podcini/feed/parser/util/TypeGetter.kt index 675ac848..2a705f9c 100644 --- a/app/src/main/java/ac/mdiq/podcini/feed/parser/util/TypeGetter.kt +++ b/app/src/main/java/ac/mdiq/podcini/feed/parser/util/TypeGetter.kt @@ -39,9 +39,7 @@ class TypeGetter { Log.d(TAG, "Recognized type Atom") val strLang = xpp.getAttributeValue("http://www.w3.org/XML/1998/namespace", "lang") - if (strLang != null) { - feed.language = strLang - } + if (strLang != null) feed.language = strLang return Type.ATOM } @@ -62,9 +60,7 @@ class TypeGetter { Log.d(TAG, "Recognized type RSS 0.91/0.92") return Type.RSS091 } - else -> { - throw UnsupportedFeedtypeException("Unsupported rss version") - } + else -> throw UnsupportedFeedtypeException("Unsupported rss version") } } else -> { diff --git a/app/src/main/java/ac/mdiq/podcini/feed/util/ImageResourceUtils.kt b/app/src/main/java/ac/mdiq/podcini/feed/util/ImageResourceUtils.kt index 7cb71cc6..847a2c66 100644 --- a/app/src/main/java/ac/mdiq/podcini/feed/util/ImageResourceUtils.kt +++ b/app/src/main/java/ac/mdiq/podcini/feed/util/ImageResourceUtils.kt @@ -14,11 +14,8 @@ object ImageResourceUtils { */ @JvmStatic fun getEpisodeListImageLocation(playable: Playable): String? { - return if (UserPreferences.useEpisodeCoverSetting) { - playable.getImageLocation() - } else { - getFallbackImageLocation(playable) - } + return if (UserPreferences.useEpisodeCoverSetting) playable.getImageLocation() + else getFallbackImageLocation(playable) } /** @@ -26,33 +23,20 @@ object ImageResourceUtils { */ @JvmStatic fun getEpisodeListImageLocation(feedItem: FeedItem): String? { - return if (UserPreferences.useEpisodeCoverSetting) { - feedItem.imageLocation - } else { - getFallbackImageLocation(feedItem) - } + return if (UserPreferences.useEpisodeCoverSetting) feedItem.imageLocation + else getFallbackImageLocation(feedItem) } @JvmStatic fun getFallbackImageLocation(playable: Playable): String? { if (playable is FeedMedia) { val item = playable.item - return if (item?.feed != null) { - item.feed!!.imageUrl - } else { - null - } - } else { - return playable.getImageLocation() - } + return item?.feed?.imageUrl + } else return playable.getImageLocation() } @JvmStatic fun getFallbackImageLocation(feedItem: FeedItem): String? { - return if (feedItem.feed != null) { - feedItem.feed!!.imageUrl - } else { - null - } + return feedItem.feed?.imageUrl } } diff --git a/app/src/main/java/ac/mdiq/podcini/feed/util/PlaybackSpeedUtils.kt b/app/src/main/java/ac/mdiq/podcini/feed/util/PlaybackSpeedUtils.kt index 0d86be42..5ace8f92 100644 --- a/app/src/main/java/ac/mdiq/podcini/feed/util/PlaybackSpeedUtils.kt +++ b/app/src/main/java/ac/mdiq/podcini/feed/util/PlaybackSpeedUtils.kt @@ -33,16 +33,12 @@ object PlaybackSpeedUtils { if (feed?.preferences != null) { playbackSpeed = feed.preferences!!.feedPlaybackSpeed Log.d(TAG, "using feed speed $playbackSpeed") - } else { - Log.d(TAG, "Can not get feed specific playback speed: $feed") - } + } else Log.d(TAG, "Can not get feed specific playback speed: $feed") } } } - if (mediaType != null && playbackSpeed == FeedPreferences.SPEED_USE_GLOBAL) { - playbackSpeed = UserPreferences.getPlaybackSpeed(mediaType) - } + if (mediaType != null && playbackSpeed == FeedPreferences.SPEED_USE_GLOBAL) playbackSpeed = UserPreferences.getPlaybackSpeed(mediaType) return playbackSpeed } diff --git a/app/src/main/java/ac/mdiq/podcini/glide/ApOkHttpUrlLoader.kt b/app/src/main/java/ac/mdiq/podcini/glide/ApOkHttpUrlLoader.kt index 93231ead..5b4431b3 100644 --- a/app/src/main/java/ac/mdiq/podcini/glide/ApOkHttpUrlLoader.kt +++ b/app/src/main/java/ac/mdiq/podcini/glide/ApOkHttpUrlLoader.kt @@ -57,11 +57,7 @@ internal class ApOkHttpUrlLoader private constructor(private val client: OkHttpC } } - override fun buildLoadData(model: String, - width: Int, - height: Int, - options: Options - ): ModelLoader.LoadData { + override fun buildLoadData(model: String, width: Int, height: Int, options: Options): ModelLoader.LoadData { return ModelLoader.LoadData(ObjectKey(model), ResizingOkHttpStreamFetcher(client, GlideUrl(model))) } diff --git a/app/src/main/java/ac/mdiq/podcini/glide/AudioCoverFetcher.kt b/app/src/main/java/ac/mdiq/podcini/glide/AudioCoverFetcher.kt index 2ba34a30..af92abe3 100644 --- a/app/src/main/java/ac/mdiq/podcini/glide/AudioCoverFetcher.kt +++ b/app/src/main/java/ac/mdiq/podcini/glide/AudioCoverFetcher.kt @@ -15,15 +15,11 @@ internal class AudioCoverFetcher(private val path: String, private val context: override fun loadData(priority: Priority, callback: DataFetcher.DataCallback) { try { MediaMetadataRetrieverCompat().use { retriever -> - if (path.startsWith(ContentResolver.SCHEME_CONTENT)) { - retriever.setDataSource(context, Uri.parse(path)) - } else { - retriever.setDataSource(path) - } + if (path.startsWith(ContentResolver.SCHEME_CONTENT)) retriever.setDataSource(context, Uri.parse(path)) + else retriever.setDataSource(path) + val picture = retriever.embeddedPicture - if (picture != null) { - callback.onDataReady(ByteArrayInputStream(picture)) - } + if (picture != null) callback.onDataReady(ByteArrayInputStream(picture)) } } catch (e: Exception) { callback.onLoadFailed(e) diff --git a/app/src/main/java/ac/mdiq/podcini/glide/ChapterImageModelLoader.kt b/app/src/main/java/ac/mdiq/podcini/glide/ChapterImageModelLoader.kt index 41a24fdb..54882fb4 100644 --- a/app/src/main/java/ac/mdiq/podcini/glide/ChapterImageModelLoader.kt +++ b/app/src/main/java/ac/mdiq/podcini/glide/ChapterImageModelLoader.kt @@ -29,11 +29,7 @@ class ChapterImageModelLoader : ModelLoader } } - override fun buildLoadData(model: EmbeddedChapterImage, - width: Int, - height: Int, - options: Options - ): ModelLoader.LoadData { + override fun buildLoadData(model: EmbeddedChapterImage, width: Int, height: Int, options: Options): ModelLoader.LoadData { return ModelLoader.LoadData(ObjectKey(model), EmbeddedImageFetcher(model)) } @@ -59,9 +55,8 @@ class ChapterImageModelLoader : ModelLoader val url = image.media.getStreamUrl() if (url != null) httpReq.url(url) val response = getHttpClient()!!.newCall(httpReq.build()).execute() - if (!response.isSuccessful || response.body == null) { - throw IOException("Invalid response: " + response.code + " " + response.message) - } + if (!response.isSuccessful || response.body == null) throw IOException("Invalid response: " + response.code + " " + response.message) + callback.onDataReady(ByteBuffer.wrap(response.body!!.bytes())) } } catch (e: IOException) { diff --git a/app/src/main/java/ac/mdiq/podcini/glide/FastBlurTransformation.kt b/app/src/main/java/ac/mdiq/podcini/glide/FastBlurTransformation.kt index d22a3246..5b531677 100644 --- a/app/src/main/java/ac/mdiq/podcini/glide/FastBlurTransformation.kt +++ b/app/src/main/java/ac/mdiq/podcini/glide/FastBlurTransformation.kt @@ -12,11 +12,7 @@ import kotlin.math.max import kotlin.math.min class FastBlurTransformation : BitmapTransformation() { - override fun transform(pool: BitmapPool, - source: Bitmap, - outWidth: Int, - outHeight: Int - ): Bitmap { + override fun transform(pool: BitmapPool, source: Bitmap, outWidth: Int, outHeight: Int): Bitmap { val targetWidth = outWidth / 3 val targetHeight = (1.0 * outHeight * targetWidth / outWidth).toInt() val resized = ThumbnailUtils.extractThumbnail(source, targetWidth, targetHeight) @@ -76,9 +72,7 @@ class FastBlurTransformation : BitmapTransformation() { // // Stack Blur Algorithm by Mario Klingemann - if (radius < 1) { - return null - } + if (radius < 1) return null val w = bitmap.width val h = bitmap.height @@ -182,9 +176,8 @@ class FastBlurTransformation : BitmapTransformation() { goutsum -= sir[1] boutsum -= sir[2] - if (y == 0) { - vmin[x] = min((x + radius + 1).toDouble(), wm.toDouble()).toInt() - } + if (y == 0) vmin[x] = min((x + radius + 1).toDouble(), wm.toDouble()).toInt() + p = pix[yw + vmin[x]] sir[0] = (p and 0xff0000) shr 16 @@ -254,9 +247,8 @@ class FastBlurTransformation : BitmapTransformation() { boutsum += sir[2] } - if (i < hm) { - yp += w - } + if (i < hm) yp += w + i++ } yi = x @@ -277,9 +269,8 @@ class FastBlurTransformation : BitmapTransformation() { goutsum -= sir[1] boutsum -= sir[2] - if (x == 0) { - vmin[y] = (min((y + r1).toDouble(), hm.toDouble()) * w).toInt() - } + if (x == 0) vmin[y] = (min((y + r1).toDouble(), hm.toDouble()) * w).toInt() + p = x + vmin[y] sir[0] = r[p] diff --git a/app/src/main/java/ac/mdiq/podcini/glide/GenerativePlaceholderImageModelLoader.kt b/app/src/main/java/ac/mdiq/podcini/glide/GenerativePlaceholderImageModelLoader.kt index 8c89d942..10e15c74 100644 --- a/app/src/main/java/ac/mdiq/podcini/glide/GenerativePlaceholderImageModelLoader.kt +++ b/app/src/main/java/ac/mdiq/podcini/glide/GenerativePlaceholderImageModelLoader.kt @@ -26,11 +26,7 @@ class GenerativePlaceholderImageModelLoader : ModelLoader { } } - override fun buildLoadData(model: String, - width: Int, - height: Int, - options: Options - ): ModelLoader.LoadData { + override fun buildLoadData(model: String, width: Int, height: Int, options: Options): ModelLoader.LoadData { return ModelLoader.LoadData(ObjectKey(model), EmbeddedImageFetcher(model, width, height)) } @@ -38,8 +34,8 @@ class GenerativePlaceholderImageModelLoader : ModelLoader { return model.startsWith(Feed.PREFIX_GENERATIVE_COVER) } - internal class EmbeddedImageFetcher(private val model: String, private val width: Int, private val height: Int) : - DataFetcher { + internal class EmbeddedImageFetcher(private val model: String, private val width: Int, private val height: Int) : DataFetcher { + override fun loadData(priority: Priority, callback: DataFetcher.DataCallback) { val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) val canvas = Canvas(bitmap) @@ -70,22 +66,14 @@ class GenerativePlaceholderImageModelLoader : ModelLoader { } color = newColor paint.color = newColor - canvas.drawLine(linePos + slope + shadowWidth, -slope.toFloat(), - linePos - slope + shadowWidth, (height + slope).toFloat(), paintShadow) + canvas.drawLine(linePos + slope + shadowWidth, -slope.toFloat(), linePos - slope + shadowWidth, (height + slope).toFloat(), paintShadow) } - canvas.drawLine(linePos + slope, -slope.toFloat(), - linePos - slope, (height + slope).toFloat(), paint) + canvas.drawLine(linePos + slope, -slope.toFloat(), linePos - slope, (height + slope).toFloat(), paint) } val gradientPaint = Paint() paint.isDither = true - gradientPaint.setShader(LinearGradient(0f, - 0f, - 0f, - height.toFloat(), - 0x00000000, - 0x55000000, - Shader.TileMode.CLAMP)) + gradientPaint.setShader(LinearGradient(0f, 0f, 0f, height.toFloat(), 0x00000000, 0x55000000, Shader.TileMode.CLAMP)) canvas.drawRect(0f, 0f, width.toFloat(), height.toFloat(), gradientPaint) val baos = ByteArrayOutputStream() @@ -111,8 +99,7 @@ class GenerativePlaceholderImageModelLoader : ModelLoader { } companion object { - private val PALETTES = intArrayOf(-0x876f64, -0x9100, -0xc771c4, - -0xff7c71, -0x84e05e, -0x48e3e4, -0xde690d) + private val PALETTES = intArrayOf(-0x876f64, -0x9100, -0xc771c4, -0xff7c71, -0x84e05e, -0x48e3e4, -0xde690d) private fun randomShadeOfGrey(generator: Random): Int { return -0x888889 + 0x222222 * generator.nextInt(5) diff --git a/app/src/main/java/ac/mdiq/podcini/glide/MetadataRetrieverLoader.kt b/app/src/main/java/ac/mdiq/podcini/glide/MetadataRetrieverLoader.kt index acc02b1f..272c96f2 100644 --- a/app/src/main/java/ac/mdiq/podcini/glide/MetadataRetrieverLoader.kt +++ b/app/src/main/java/ac/mdiq/podcini/glide/MetadataRetrieverLoader.kt @@ -9,8 +9,7 @@ import com.bumptech.glide.signature.ObjectKey import ac.mdiq.podcini.storage.model.feed.FeedMedia import java.io.InputStream -internal class MetadataRetrieverLoader private constructor(private val context: Context) : - ModelLoader { +internal class MetadataRetrieverLoader private constructor(private val context: Context) : ModelLoader { /** * The default factory for [MetadataRetrieverLoader]s. */ @@ -24,11 +23,8 @@ internal class MetadataRetrieverLoader private constructor(private val context: } } - override fun buildLoadData(model: String, - width: Int, height: Int, options: Options - ): ModelLoader.LoadData { - return ModelLoader.LoadData(ObjectKey(model), - AudioCoverFetcher(model.replace(FeedMedia.FILENAME_PREFIX_EMBEDDED_COVER, ""), context)) + override fun buildLoadData(model: String, width: Int, height: Int, options: Options): ModelLoader.LoadData { + return ModelLoader.LoadData(ObjectKey(model), AudioCoverFetcher(model.replace(FeedMedia.FILENAME_PREFIX_EMBEDDED_COVER, ""), context)) } override fun handles(model: String): Boolean { diff --git a/app/src/main/java/ac/mdiq/podcini/glide/ResizingOkHttpStreamFetcher.kt b/app/src/main/java/ac/mdiq/podcini/glide/ResizingOkHttpStreamFetcher.kt index 387f3fb8..397b5194 100644 --- a/app/src/main/java/ac/mdiq/podcini/glide/ResizingOkHttpStreamFetcher.kt +++ b/app/src/main/java/ac/mdiq/podcini/glide/ResizingOkHttpStreamFetcher.kt @@ -54,9 +54,7 @@ class ResizingOkHttpStreamFetcher(client: Call.Factory?, url: GlideUrl?) : OkHtt IOUtils.closeQuietly(inVal) when { - options.outWidth == -1 || options.outHeight == -1 -> { - throw IOException("Not a valid image") - } + options.outWidth == -1 || options.outHeight == -1 -> throw IOException("Not a valid image") max(options.outHeight.toDouble(), options.outWidth.toDouble()) >= MAX_DIMENSIONS -> { val sampleSize = max(options.outHeight.toDouble(), options.outWidth.toDouble()) / MAX_DIMENSIONS options.inSampleSize = 2.0.pow(floor(ln(sampleSize) / ln(2.0))).toInt() @@ -68,8 +66,7 @@ class ResizingOkHttpStreamFetcher(client: Call.Factory?, url: GlideUrl?) : OkHtt val bitmap = BitmapFactory.decodeStream(inVal, null, options) IOUtils.closeQuietly(inVal) - val format = if (Build.VERSION.SDK_INT < 30 - ) CompressFormat.WEBP else CompressFormat.WEBP_LOSSY + val format = if (Build.VERSION.SDK_INT < 30) CompressFormat.WEBP else CompressFormat.WEBP_LOSSY var quality = 100 if (tempOut != null) while (true) { @@ -78,29 +75,19 @@ class ResizingOkHttpStreamFetcher(client: Call.Factory?, url: GlideUrl?) : OkHtt IOUtils.closeQuietly(out) quality -= when { - tempOut!!.length() > 3 * MAX_FILE_SIZE && quality >= 45 -> { - 40 - } - tempOut!!.length() > 2 * MAX_FILE_SIZE && quality >= 25 -> { - 20 - } - tempOut!!.length() > MAX_FILE_SIZE && quality >= 15 -> { - 10 - } - tempOut!!.length() > MAX_FILE_SIZE && quality >= 10 -> { - 5 - } - else -> { - break - } + tempOut!!.length() > 3 * MAX_FILE_SIZE && quality >= 45 -> 40 + tempOut!!.length() > 2 * MAX_FILE_SIZE && quality >= 25 -> 20 + tempOut!!.length() > MAX_FILE_SIZE && quality >= 15 -> 10 + tempOut!!.length() > MAX_FILE_SIZE && quality >= 10 -> 5 + else -> break } } bitmap?.recycle() stream = FileInputStream(tempOut) callback.onDataReady(stream) - if (tempIn != null && tempOut != null) Log.d(TAG, - "Compressed image from " + tempIn!!.length() / 1024 + " to " + tempOut!!.length() / 1024 + " kB (quality: " + quality + "%)") + if (tempIn != null && tempOut != null) + Log.d(TAG, "Compressed image from ${tempIn!!.length() / 1024} to ${tempOut!!.length() / 1024} kB (quality: $quality%)") } catch (e: Throwable) { e.printStackTrace() diff --git a/app/src/main/java/ac/mdiq/podcini/net/common/UrlChecker.kt b/app/src/main/java/ac/mdiq/podcini/net/common/UrlChecker.kt index d680b77b..9ab58636 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/common/UrlChecker.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/common/UrlChecker.kt @@ -61,9 +61,7 @@ object UrlChecker { Log.d(TAG, "Adding http:// at the beginning of the URL") return "http://$url" } - else -> { - return url - } + else -> return url } } @@ -84,18 +82,12 @@ object UrlChecker { base = prepareUrl(base) val urlUri = Uri.parse(url) val baseUri = Uri.parse(base) - return if (urlUri.isRelative && baseUri.isAbsolute) { - urlUri.buildUpon().scheme(baseUri.scheme).build().toString() - } else { - prepareUrl(url) - } + return if (urlUri.isRelative && baseUri.isAbsolute) urlUri.buildUpon().scheme(baseUri.scheme).build().toString() else prepareUrl(url) } fun containsUrl(list: List, url: String?): Boolean { for (item in list) { - if (urlEquals(item, url)) { - return true - } + if (urlEquals(item, url)) return true } return false } @@ -104,17 +96,14 @@ object UrlChecker { fun urlEquals(string1: String?, string2: String?): Boolean { val url1 = string1!!.toHttpUrlOrNull() val url2 = string2!!.toHttpUrlOrNull() - if (url1!!.host != url2!!.host) { - return false - } + if (url1!!.host != url2!!.host) return false + val pathSegments1 = normalizePathSegments(url1.pathSegments) val pathSegments2 = normalizePathSegments(url2.pathSegments) - if (pathSegments1 != pathSegments2) { - return false - } - if (url1.query.isNullOrEmpty()) { - return url2.query.isNullOrEmpty() - } + if (pathSegments1 != pathSegments2) return false + + if (url1.query.isNullOrEmpty()) return url2.query.isNullOrEmpty() + return url1.query == url2.query } @@ -126,9 +115,7 @@ object UrlChecker { private fun normalizePathSegments(input: List): List { val result: MutableList = ArrayList() for (string in input) { - if (string.isNotEmpty()) { - result.add(string.lowercase()) - } + if (string.isNotEmpty()) result.add(string.lowercase()) } return result } diff --git a/app/src/main/java/ac/mdiq/podcini/net/discovery/CombinedSearcher.kt b/app/src/main/java/ac/mdiq/podcini/net/discovery/CombinedSearcher.kt index 397b1887..bed41b5a 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/discovery/CombinedSearcher.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/discovery/CombinedSearcher.kt @@ -58,9 +58,8 @@ class CombinedSearcher : PodcastSearcher { urlToResult[result!!.feedUrl] = result var ranking = 0f - if (resultRanking.containsKey(result.feedUrl)) { - ranking = resultRanking[result.feedUrl]!! - } + if (resultRanking.containsKey(result.feedUrl)) ranking = resultRanking[result.feedUrl]!! + ranking += 1f / (position + 1f) resultRanking[result.feedUrl] = ranking * providerPriority } @@ -92,9 +91,7 @@ class CombinedSearcher : PodcastSearcher { for (i in PodcastSearcherRegistry.searchProviders.indices) { val searchProviderInfo = PodcastSearcherRegistry.searchProviders[i] val searcher = searchProviderInfo.searcher - if (searchProviderInfo.weight > 0.00001f && searcher.javaClass != CombinedSearcher::class.java) { - names.add(searcher.name) - } + if (searchProviderInfo.weight > 0.00001f && searcher.javaClass != CombinedSearcher::class.java) names.add(searcher.name) } return TextUtils.join(", ", names) } diff --git a/app/src/main/java/ac/mdiq/podcini/net/discovery/ItunesPodcastSearcher.kt b/app/src/main/java/ac/mdiq/podcini/net/discovery/ItunesPodcastSearcher.kt index 889dfcb2..76b49eea 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/discovery/ItunesPodcastSearcher.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/discovery/ItunesPodcastSearcher.kt @@ -26,8 +26,7 @@ class ItunesPodcastSearcher : PodcastSearcher { val formattedUrl = String.format(ITUNES_API_URL, encodedQuery) val client = getHttpClient() - val httpReq: Builder = Builder() - .url(formattedUrl) + val httpReq: Builder = Builder().url(formattedUrl) val podcasts: MutableList = ArrayList() try { val response = client.newCall(httpReq.build()).execute() @@ -40,9 +39,7 @@ class ItunesPodcastSearcher : PodcastSearcher { for (i in 0 until j.length()) { val podcastJson = j.getJSONObject(i) val podcast = PodcastSearchResult.fromItunes(podcastJson) - if (podcast.feedUrl != null) { - podcasts.add(podcast) - } + if (podcast.feedUrl != null) podcasts.add(podcast) } } else { subscriber.onError(IOException(response.toString())) @@ -80,9 +77,8 @@ class ItunesPodcastSearcher : PodcastSearcher { } val feedUrl = results.getString(feedUrlName) emitter.onSuccess(feedUrl) - } else { - emitter.onError(IOException(response.toString())) - } + } else emitter.onError(IOException(response.toString())) + } catch (e: IOException) { emitter.onError(e) } catch (e: JSONException) { diff --git a/app/src/main/java/ac/mdiq/podcini/net/discovery/ItunesTopListLoader.kt b/app/src/main/java/ac/mdiq/podcini/net/discovery/ItunesTopListLoader.kt index d8e8af46..0f88bf39 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/discovery/ItunesTopListLoader.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/discovery/ItunesTopListLoader.kt @@ -22,17 +22,13 @@ class ItunesTopListLoader(private val context: Context) { val client = getHttpClient() val feedString: String var loadCountry = country - if (COUNTRY_CODE_UNSET == country) { - loadCountry = Locale.getDefault().country - } + if (COUNTRY_CODE_UNSET == country) loadCountry = Locale.getDefault().country + feedString = try { getTopListFeed(client, loadCountry) } catch (e: IOException) { - if (COUNTRY_CODE_UNSET == country) { - getTopListFeed(client, "US") - } else { - throw e - } + if (COUNTRY_CODE_UNSET == country) getTopListFeed(client, "US") + else throw e } return removeSubscribed(parseFeed(feedString), subscribed, limit) } @@ -46,12 +42,9 @@ class ItunesTopListLoader(private val context: Context) { .url(String.format(url, country)) client!!.newCall(httpReq.build()).execute().use { response -> - if (response.isSuccessful) { - return response.body!!.string() - } - if (response.code == 400) { - throw IOException("iTunes does not have data for the selected country.") - } + if (response.isSuccessful) return response.body!!.string() + if (response.code == 400) throw IOException("iTunes does not have data for the selected country.") + val prefix = context.getString(R.string.error_msg_prefix) throw IOException(prefix + response) } @@ -87,9 +80,7 @@ class ItunesTopListLoader(private val context: Context) { const val COUNTRY_CODE_UNSET: String = "99" private const val NUM_LOADED = 25 - private fun removeSubscribed( - suggestedPodcasts: List, subscribedFeeds: List, limit: Int - ): List { + private fun removeSubscribed(suggestedPodcasts: List, subscribedFeeds: List, limit: Int): List { val subscribedPodcastsSet: MutableSet = HashSet() for (subscribedFeed in subscribedFeeds) { if (subscribedFeed.title != null && subscribedFeed.author != null) { @@ -98,12 +89,8 @@ class ItunesTopListLoader(private val context: Context) { } val suggestedNotSubscribed: MutableList = ArrayList() for (suggested in suggestedPodcasts) { - if (!subscribedPodcastsSet.contains(suggested.title.trim { it <= ' ' })) { - suggestedNotSubscribed.add(suggested) - } - if (suggestedNotSubscribed.size == limit) { - return suggestedNotSubscribed - } + if (!subscribedPodcastsSet.contains(suggested.title.trim { it <= ' ' })) suggestedNotSubscribed.add(suggested) + if (suggestedNotSubscribed.size == limit) return suggestedNotSubscribed } return suggestedNotSubscribed } diff --git a/app/src/main/java/ac/mdiq/podcini/net/discovery/PodcastIndexPodcastSearcher.kt b/app/src/main/java/ac/mdiq/podcini/net/discovery/PodcastIndexPodcastSearcher.kt index 14597ef4..4ea60a8d 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/discovery/PodcastIndexPodcastSearcher.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/discovery/PodcastIndexPodcastSearcher.kt @@ -40,9 +40,7 @@ class PodcastIndexPodcastSearcher : PodcastSearcher { for (i in 0 until j.length()) { val podcastJson = j.getJSONObject(i) val podcast = PodcastSearchResult.fromPodcastIndex(podcastJson) - if (podcast.feedUrl != null) { - podcasts.add(podcast) - } + if (podcast.feedUrl != null) podcasts.add(podcast) } } else { subscriber.onError(IOException(response.toString())) diff --git a/app/src/main/java/ac/mdiq/podcini/net/discovery/PodcastSearchResult.kt b/app/src/main/java/ac/mdiq/podcini/net/discovery/PodcastSearchResult.kt index adcc9997..2e8f1c1b 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/discovery/PodcastSearchResult.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/discovery/PodcastSearchResult.kt @@ -7,15 +7,8 @@ import org.json.JSONObject import java.text.SimpleDateFormat import java.util.* -class PodcastSearchResult private constructor( - val title: String, - val imageUrl: String?, - val feedUrl: String?, - val author: String?, - val count: Int?, - val update: String?, - val source: String -) { +class PodcastSearchResult private constructor(val title: String, val imageUrl: String?, val feedUrl: String?, + val author: String?, val count: Int?, val update: String?, val source: String) { companion object { fun dummy(): PodcastSearchResult { return PodcastSearchResult("", "", "", "", 0, "", "dummy") @@ -50,13 +43,10 @@ class PodcastSearchResult private constructor( while (imageUrl == null && i < images.length()) { val image = images.getJSONObject(i) val height = image.getJSONObject("attributes").getString("height") - if (height.toInt() >= 100) { - imageUrl = image.getString("label") - } + if (height.toInt() >= 100) imageUrl = image.getString("label") i++ } - val feedUrl = "https://itunes.apple.com/lookup?id=" + - json.getJSONObject("id").getJSONObject("attributes").getString("im:id") + val feedUrl = "https://itunes.apple.com/lookup?id=" + json.getJSONObject("id").getJSONObject("attributes").getString("im:id") var author: String? = null try { diff --git a/app/src/main/java/ac/mdiq/podcini/net/discovery/PodcastSearcherRegistry.kt b/app/src/main/java/ac/mdiq/podcini/net/discovery/PodcastSearcherRegistry.kt index adf74e07..5b0cd507 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/discovery/PodcastSearcherRegistry.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/discovery/PodcastSearcherRegistry.kt @@ -20,22 +20,15 @@ object PodcastSearcherRegistry { fun lookupUrl(url: String): Single { for (searchProviderInfo in searchProviders) { - if (searchProviderInfo.searcher.javaClass != CombinedSearcher::class.java - && searchProviderInfo.searcher.urlNeedsLookup(url)) { - + if (searchProviderInfo.searcher.javaClass != CombinedSearcher::class.java && searchProviderInfo.searcher.urlNeedsLookup(url)) return searchProviderInfo.searcher.lookupUrl(url) - } } return Single.just(url) } fun urlNeedsLookup(url: String): Boolean { for (searchProviderInfo in searchProviders) { - if (searchProviderInfo.searcher.javaClass != CombinedSearcher::class.java - && searchProviderInfo.searcher.urlNeedsLookup(url)) { - - return true - } + if (searchProviderInfo.searcher.javaClass != CombinedSearcher::class.java && searchProviderInfo.searcher.urlNeedsLookup(url)) return true } return false } diff --git a/app/src/main/java/ac/mdiq/podcini/net/download/ConnectionStateMonitor.kt b/app/src/main/java/ac/mdiq/podcini/net/download/ConnectionStateMonitor.kt index 9dbad2bf..70558136 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/download/ConnectionStateMonitor.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/download/ConnectionStateMonitor.kt @@ -22,15 +22,13 @@ class ConnectionStateMonitor } fun enable(context: Context) { - val connectivityManager = - context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager connectivityManager.registerNetworkCallback(networkRequest, this) connectivityManager.addDefaultNetworkActiveListener(this) } fun disable(context: Context) { - val connectivityManager = - context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager connectivityManager.unregisterNetworkCallback(this) connectivityManager.removeDefaultNetworkActiveListener(this) } diff --git a/app/src/main/java/ac/mdiq/podcini/net/download/FeedUpdateManager.kt b/app/src/main/java/ac/mdiq/podcini/net/download/FeedUpdateManager.kt index f641d2f0..4782f137 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/download/FeedUpdateManager.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/download/FeedUpdateManager.kt @@ -39,8 +39,7 @@ object FeedUpdateManager { val workRequest: PeriodicWorkRequest = PeriodicWorkRequest.Builder( FeedUpdateWorker::class.java, UserPreferences.updateInterval, TimeUnit.HOURS) .setConstraints(Builder() - .setRequiredNetworkType(if (UserPreferences.isAllowMobileFeedRefresh - ) NetworkType.CONNECTED else NetworkType.UNMETERED).build()) + .setRequiredNetworkType(if (UserPreferences.isAllowMobileFeedRefresh) NetworkType.CONNECTED else NetworkType.UNMETERED).build()) .build() WorkManager.getInstance(context).enqueueUniquePeriodicWork(WORK_ID_FEED_UPDATE, if (replace) ExistingPeriodicWorkPolicy.REPLACE else ExistingPeriodicWorkPolicy.KEEP, workRequest) @@ -54,10 +53,8 @@ object FeedUpdateManager { .setInitialDelay(0L, TimeUnit.MILLISECONDS) .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST) .addTag(WORK_TAG_FEED_UPDATE) - if (feed == null || !feed.isLocalFeed) { - workRequest.setConstraints(Builder() - .setRequiredNetworkType(NetworkType.CONNECTED).build()) - } + if (feed == null || !feed.isLocalFeed) workRequest.setConstraints(Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()) + val builder = Data.Builder() builder.putBoolean(EXTRA_EVEN_ON_MOBILE, true) if (feed != null) { @@ -65,8 +62,7 @@ object FeedUpdateManager { builder.putBoolean(EXTRA_NEXT_PAGE, nextPage) } workRequest.setInputData(builder.build()) - WorkManager.getInstance(context).enqueueUniqueWork(WORK_ID_FEED_UPDATE_MANUAL, - ExistingWorkPolicy.REPLACE, workRequest.build()) + WorkManager.getInstance(context).enqueueUniqueWork(WORK_ID_FEED_UPDATE_MANUAL, ExistingWorkPolicy.REPLACE, workRequest.build()) } @JvmStatic @@ -74,36 +70,25 @@ object FeedUpdateManager { fun runOnceOrAsk(context: Context, feed: Feed? = null) { Log.d(TAG, "Run auto update immediately in background.") when { - feed != null && feed.isLocalFeed -> { - runOnce(context, feed) - } - !networkAvailable() -> { - EventBus.getDefault().post(MessageEvent(context.getString(R.string.download_error_no_connection))) - } - isFeedRefreshAllowed -> { - runOnce(context, feed) - } - else -> { - confirmMobileRefresh(context, feed) - } + feed != null && feed.isLocalFeed -> runOnce(context, feed) + !networkAvailable() -> EventBus.getDefault().post(MessageEvent(context.getString(R.string.download_error_no_connection))) + isFeedRefreshAllowed -> runOnce(context, feed) + else -> confirmMobileRefresh(context, feed) } } private fun confirmMobileRefresh(context: Context, feed: Feed?) { val builder = MaterialAlertDialogBuilder(context) .setTitle(R.string.feed_refresh_title) - .setPositiveButton(R.string.confirm_mobile_streaming_button_once - ) { _: DialogInterface?, _: Int -> runOnce(context, feed) } + .setPositiveButton(R.string.confirm_mobile_streaming_button_once) { _: DialogInterface?, _: Int -> runOnce(context, feed) } .setNeutralButton(R.string.confirm_mobile_streaming_button_always) { _: DialogInterface?, _: Int -> UserPreferences.isAllowMobileFeedRefresh = true runOnce(context, feed) } .setNegativeButton(R.string.no, null) - if (isNetworkRestricted && isVpnOverWifi) { - builder.setMessage(R.string.confirm_mobile_feed_refresh_dialog_message_vpn) - } else { - builder.setMessage(R.string.confirm_mobile_feed_refresh_dialog_message) - } + if (isNetworkRestricted && isVpnOverWifi) builder.setMessage(R.string.confirm_mobile_feed_refresh_dialog_message_vpn) + else builder.setMessage(R.string.confirm_mobile_feed_refresh_dialog_message) + builder.show() } } diff --git a/app/src/main/java/ac/mdiq/podcini/net/download/MediaSizeLoader.kt b/app/src/main/java/ac/mdiq/podcini/net/download/MediaSizeLoader.kt index fc69facc..990b86c1 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/download/MediaSizeLoader.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/download/MediaSizeLoader.kt @@ -29,9 +29,7 @@ object MediaSizeLoader { when { media.isDownloaded() -> { val mediaFile = File(media.getLocalMediaUrl()) - if (mediaFile.exists()) { - size = mediaFile.length() - } + if (mediaFile.exists()) size = mediaFile.length() } !media.checkedOnSizeButUnknown() -> { // only query the network if we haven't already checked @@ -65,12 +63,10 @@ object MediaSizeLoader { } } Log.d(TAG, "new size: $size") - if (size <= 0) { - // they didn't tell us the size, but we don't want to keep querying on it - media.setCheckedOnSizeButUnknown() - } else { - media.size = size - } + // they didn't tell us the size, but we don't want to keep querying on it + if (size <= 0) media.setCheckedOnSizeButUnknown() + else media.size = size + emitter.onSuccess(size) DBWriter.setFeedMedia(media) }) diff --git a/app/src/main/java/ac/mdiq/podcini/net/download/service/BasicAuthorizationInterceptor.kt b/app/src/main/java/ac/mdiq/podcini/net/download/service/BasicAuthorizationInterceptor.kt index 7734e718..554d7eba 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/download/service/BasicAuthorizationInterceptor.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/download/service/BasicAuthorizationInterceptor.kt @@ -21,9 +21,7 @@ class BasicAuthorizationInterceptor : Interceptor { var response: Response = chain.proceed(request) - if (response.code != HttpURLConnection.HTTP_UNAUTHORIZED) { - return response - } + if (response.code != HttpURLConnection.HTTP_UNAUTHORIZED) return response val newRequest: Builder = request.newBuilder() if (!TextUtils.equals(response.request.url.toString(), request.url.toString())) { @@ -43,13 +41,10 @@ class BasicAuthorizationInterceptor : Interceptor { val downloadRequest = request.tag() as? DownloadRequest if (downloadRequest?.source != null) { userInfo = URIUtil.getURIFromRequestUrl(downloadRequest.source!!).userInfo - if (userInfo.isEmpty() && (!downloadRequest.username.isNullOrEmpty() || !downloadRequest.password.isNullOrEmpty())) { + if (userInfo.isEmpty() && (!downloadRequest.username.isNullOrEmpty() || !downloadRequest.password.isNullOrEmpty())) userInfo = downloadRequest.username + ":" + downloadRequest.password - } } - } else { - userInfo = DBReader.getImageAuthentication(request.url.toString()) - } + } else userInfo = DBReader.getImageAuthentication(request.url.toString()) if (userInfo.isEmpty()) { Log.d(TAG, "no credentials for '" + request.url + "'") @@ -67,9 +62,7 @@ class BasicAuthorizationInterceptor : Interceptor { newRequest.header(HEADER_AUTHORIZATION, encode(username, password, "ISO-8859-1")) response = chain.proceed(newRequest.build()) - if (response.code != HttpURLConnection.HTTP_UNAUTHORIZED) { - return response - } + if (response.code != HttpURLConnection.HTTP_UNAUTHORIZED) return response Log.d(TAG, "Authorization failed, re-trying with UTF-8 encoded credentials") newRequest.header(HEADER_AUTHORIZATION, encode(username, password, "UTF-8")) diff --git a/app/src/main/java/ac/mdiq/podcini/net/download/service/DownloadRequestCreator.kt b/app/src/main/java/ac/mdiq/podcini/net/download/service/DownloadRequestCreator.kt index e1d8d816..9e0974f6 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/download/service/DownloadRequestCreator.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/download/service/DownloadRequestCreator.kt @@ -21,9 +21,8 @@ object DownloadRequestCreator { @JvmStatic fun create(feed: Feed): DownloadRequest.Builder { val dest = File(feedfilePath, getFeedfileName(feed)) - if (dest.exists()) { - dest.delete() - } + if (dest.exists()) dest.delete() + Log.d(TAG, "Requesting download feed from url " + feed.download_url) val username = feed.preferences?.username @@ -39,15 +38,10 @@ object DownloadRequestCreator { val pdFile = if (media.file_url != null) File(media.file_url!!) else null val partiallyDownloadedFileExists = pdFile?.exists() ?: false var dest: File - dest = if (partiallyDownloadedFileExists) { - pdFile!! - } else { - File(getMediafilePath(media), getMediafilename(media)) - } + dest = if (partiallyDownloadedFileExists) pdFile!! else File(getMediafilePath(media), getMediafilename(media)) + + if (dest.exists() && !partiallyDownloadedFileExists) dest = findUnusedFile(dest)!! - if (dest.exists() && !partiallyDownloadedFileExists) { - dest = findUnusedFile(dest)!! - } Log.d(TAG, "Requesting download media from url " + media.download_url) val username = media.item?.feed?.preferences?.username @@ -60,11 +54,7 @@ object DownloadRequestCreator { // find different name var newDest: File? = null for (i in 1 until Int.MAX_VALUE) { - val newName = (FilenameUtils.getBaseName(dest.name) - + "-" - + i - + FilenameUtils.EXTENSION_SEPARATOR - + FilenameUtils.getExtension(dest.name)) + val newName = (FilenameUtils.getBaseName(dest.name) + "-" + i + FilenameUtils.EXTENSION_SEPARATOR + FilenameUtils.getExtension(dest.name)) Log.d(TAG, "Testing filename $newName") newDest = File(dest.parent, newName) if (!newDest.exists()) { @@ -80,17 +70,15 @@ object DownloadRequestCreator { private fun getFeedfileName(feed: Feed): String { var filename = feed.download_url - if (!feed.title.isNullOrEmpty()) { - filename = feed.title - } + if (!feed.title.isNullOrEmpty()) filename = feed.title + if (filename == null) return "" return "feed-" + FileNameGenerator.generateFileName(filename) + feed.id } private fun getMediafilePath(media: FeedMedia): String { val title = media.item?.feed?.title?:return "" - val mediaPath = (MEDIA_DOWNLOADPATH - + FileNameGenerator.generateFileName(title)) + val mediaPath = (MEDIA_DOWNLOADPATH + FileNameGenerator.generateFileName(title)) return UserPreferences.getDataFolder(mediaPath).toString() + "/" } @@ -106,16 +94,10 @@ object DownloadRequestCreator { val urlBaseFilename = URLUtil.guessFileName(media.download_url, null, media.mime_type) var baseFilename: String - baseFilename = if (titleBaseFilename != "") { - titleBaseFilename - } else { - urlBaseFilename - } + baseFilename = if (titleBaseFilename != "") titleBaseFilename else urlBaseFilename val filenameMaxLength = 220 - if (baseFilename.length > filenameMaxLength) { - baseFilename = baseFilename.substring(0, filenameMaxLength) - } - return (baseFilename + FilenameUtils.EXTENSION_SEPARATOR + media.id - + FilenameUtils.EXTENSION_SEPARATOR + FilenameUtils.getExtension(urlBaseFilename)) + if (baseFilename.length > filenameMaxLength) baseFilename = baseFilename.substring(0, filenameMaxLength) + + return (baseFilename + FilenameUtils.EXTENSION_SEPARATOR + media.id + FilenameUtils.EXTENSION_SEPARATOR + FilenameUtils.getExtension(urlBaseFilename)) } } diff --git a/app/src/main/java/ac/mdiq/podcini/net/download/service/DownloadServiceInterfaceImpl.kt b/app/src/main/java/ac/mdiq/podcini/net/download/service/DownloadServiceInterfaceImpl.kt index 696a2cfc..1cf768bb 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/download/service/DownloadServiceInterfaceImpl.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/download/service/DownloadServiceInterfaceImpl.kt @@ -18,24 +18,20 @@ import java.util.concurrent.TimeUnit class DownloadServiceInterfaceImpl : DownloadServiceInterface() { override fun downloadNow(context: Context, item: FeedItem, ignoreConstraints: Boolean) { - val workRequest: OneTimeWorkRequest.Builder = - getRequest(context, item) + val workRequest: OneTimeWorkRequest.Builder = getRequest(context, item) workRequest.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST) - if (ignoreConstraints) { - workRequest.setConstraints(Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()) - } else { - workRequest.setConstraints(constraints) - } - if (item.media?.download_url != null) WorkManager.getInstance(context).enqueueUniqueWork(item.media!!.download_url!!, - ExistingWorkPolicy.KEEP, workRequest.build()) + if (ignoreConstraints) workRequest.setConstraints(Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()) + else workRequest.setConstraints(constraints) + + if (item.media?.download_url != null) + WorkManager.getInstance(context).enqueueUniqueWork(item.media!!.download_url!!, ExistingWorkPolicy.KEEP, workRequest.build()) } override fun download(context: Context, item: FeedItem) { - val workRequest: OneTimeWorkRequest.Builder = - getRequest(context, item) + val workRequest: OneTimeWorkRequest.Builder = getRequest(context, item) workRequest.setConstraints(constraints) - if (item.media?.download_url != null) WorkManager.getInstance(context).enqueueUniqueWork(item.media!!.download_url!!, - ExistingWorkPolicy.KEEP, workRequest.build()) + if (item.media?.download_url != null) + WorkManager.getInstance(context).enqueueUniqueWork(item.media!!.download_url!!, ExistingWorkPolicy.KEEP, workRequest.build()) } @OptIn(UnstableApi::class) override fun cancel(context: Context, media: FeedMedia) { @@ -65,7 +61,7 @@ class DownloadServiceInterfaceImpl : DownloadServiceInterface() { } companion object { - private fun getRequest(context: Context, item: FeedItem): OneTimeWorkRequest.Builder { + @OptIn(UnstableApi::class) private fun getRequest(context: Context, item: FeedItem): OneTimeWorkRequest.Builder { val workRequest: OneTimeWorkRequest.Builder = OneTimeWorkRequest.Builder(EpisodeDownloadWorker::class.java) .setInitialDelay(0L, TimeUnit.MILLISECONDS) .addTag(WORK_TAG) @@ -74,19 +70,16 @@ class DownloadServiceInterfaceImpl : DownloadServiceInterface() { DBWriter.addQueueItem(context, false, item.id) workRequest.addTag(WORK_DATA_WAS_QUEUED) } - workRequest.setInputData(Data.Builder().putLong(WORK_DATA_MEDIA_ID, item.media!! - .id).build()) + workRequest.setInputData(Data.Builder().putLong(WORK_DATA_MEDIA_ID, item.media!!.id).build()) return workRequest } private val constraints: Constraints get() { val constraints = Builder() - if (UserPreferences.isAllowMobileEpisodeDownload) { - constraints.setRequiredNetworkType(NetworkType.CONNECTED) - } else { - constraints.setRequiredNetworkType(NetworkType.UNMETERED) - } + if (UserPreferences.isAllowMobileEpisodeDownload) constraints.setRequiredNetworkType(NetworkType.CONNECTED) + else constraints.setRequiredNetworkType(NetworkType.UNMETERED) + return constraints.build() } } diff --git a/app/src/main/java/ac/mdiq/podcini/net/download/service/EpisodeDownloadWorker.kt b/app/src/main/java/ac/mdiq/podcini/net/download/service/EpisodeDownloadWorker.kt index 8a0605ab..0a1346bf 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/download/service/EpisodeDownloadWorker.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/download/service/EpisodeDownloadWorker.kt @@ -50,9 +50,7 @@ class EpisodeDownloadWorker(context: Context, params: WorkerParameters) : Worker while (true) { try { synchronized(notificationProgress) { - if (isInterrupted) { - return - } + if (isInterrupted) return notificationProgress.put(media.getEpisodeTitle(), request.progressPercent) } setProgressAsync( @@ -60,8 +58,7 @@ class EpisodeDownloadWorker(context: Context, params: WorkerParameters) : Worker .putInt(DownloadServiceInterface.WORK_DATA_PROGRESS, request.progressPercent) .build()) .get() - val nm = applicationContext - .getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + val nm = applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager nm.notify(R.id.notification_downloading, generateProgressNotification()) sleep(1000) } catch (e: InterruptedException) { @@ -80,9 +77,9 @@ class EpisodeDownloadWorker(context: Context, params: WorkerParameters) : Worker e.printStackTrace() result = Result.failure() } - if (result == Result.failure() && downloader?.downloadRequest?.destination != null) { + if (result == Result.failure() && downloader?.downloadRequest?.destination != null) FileUtils.deleteQuietly(File(downloader!!.downloadRequest.destination!!)) - } + progressUpdaterThread.interrupt() try { progressUpdaterThread.join() @@ -92,8 +89,7 @@ class EpisodeDownloadWorker(context: Context, params: WorkerParameters) : Worker synchronized(notificationProgress) { notificationProgress.remove(media.getEpisodeTitle()) if (notificationProgress.isEmpty()) { - val nm = applicationContext - .getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + val nm = applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager nm.cancel(R.id.notification_downloading) } } @@ -107,8 +103,7 @@ class EpisodeDownloadWorker(context: Context, params: WorkerParameters) : Worker } override fun getForegroundInfoAsync(): ListenableFuture { - return Futures.immediateFuture( - ForegroundInfo(R.id.notification_downloading, generateProgressNotification())) + return Futures.immediateFuture(ForegroundInfo(R.id.notification_downloading, generateProgressNotification())) } @OptIn(UnstableApi::class) private fun performDownload(media: FeedMedia, request: DownloadRequest): Result { @@ -144,22 +139,18 @@ class EpisodeDownloadWorker(context: Context, params: WorkerParameters) : Worker return Result.failure() } - if (downloader!!.cancelled) { - // This also happens when the worker was preempted, not just when the user cancelled it - return Result.success() - } + // This also happens when the worker was preempted, not just when the user cancelled it + if (downloader!!.cancelled) return Result.success() val status = downloader!!.result if (status.isSuccessful) { - val handler = MediaDownloadedHandler( - applicationContext, downloader!!.result, request) + val handler = MediaDownloadedHandler(applicationContext, downloader!!.result, request) handler.run() DBWriter.addDownloadStatus(handler.updatedStatus) return Result.success() } - if (status.reason == DownloadError.ERROR_HTTP_DATA_ERROR - && status.reasonDetailed.toInt() == 416) { + if (status.reason == DownloadError.ERROR_HTTP_DATA_ERROR && status.reasonDetailed.toInt() == 416) { Log.d(TAG, "Requested invalid range, restarting download from the beginning") if (downloader?.downloadRequest?.destination != null) FileUtils.deleteQuietly(File(downloader!!.downloadRequest.destination!!)) sendMessage(request.title?:"", false) @@ -181,9 +172,7 @@ class EpisodeDownloadWorker(context: Context, params: WorkerParameters) : Worker if (isLastRunAttempt) { sendErrorNotification(downloader!!.downloadRequest.title?:"") return Result.failure() - } else { - return Result.retry() - } + } else return Result.retry() } private val isLastRunAttempt: Boolean @@ -192,14 +181,11 @@ class EpisodeDownloadWorker(context: Context, params: WorkerParameters) : Worker private fun sendMessage(episodeTitle: String, isImmediateFail: Boolean) { var episodeTitle = episodeTitle val retrying = !isLastRunAttempt && !isImmediateFail - if (episodeTitle.length > 20) { - episodeTitle = episodeTitle.substring(0, 19) + "…" - } - EventBus.getDefault().post(MessageEvent( - applicationContext.getString( - if (retrying) R.string.download_error_retrying else R.string.download_error_not_retrying, - episodeTitle), { ctx: Context -> MainActivityStarter(ctx).withDownloadLogsOpen().start() }, - applicationContext.getString(R.string.download_error_details))) + if (episodeTitle.length > 20) episodeTitle = episodeTitle.substring(0, 19) + "…" + + EventBus.getDefault().post(MessageEvent(applicationContext.getString( + if (retrying) R.string.download_error_retrying else R.string.download_error_not_retrying, + episodeTitle), { ctx: Context -> MainActivityStarter(ctx).withDownloadLogsOpen().start() }, applicationContext.getString(R.string.download_error_details))) } private fun getDownloadLogsIntent(context: Context): PendingIntent { @@ -220,8 +206,7 @@ class EpisodeDownloadWorker(context: Context, params: WorkerParameters) : Worker return } - val builder = NotificationCompat.Builder(applicationContext, - NotificationUtils.CHANNEL_ID_DOWNLOAD_ERROR) + val builder = NotificationCompat.Builder(applicationContext, NotificationUtils.CHANNEL_ID_DOWNLOAD_ERROR) builder.setTicker(applicationContext.getString(R.string.download_report_title)) .setContentTitle(applicationContext.getString(R.string.download_report_title)) .setContentText(applicationContext.getString(R.string.download_error_tap_for_details)) @@ -229,8 +214,7 @@ class EpisodeDownloadWorker(context: Context, params: WorkerParameters) : Worker .setContentIntent(getDownloadLogsIntent(applicationContext)) .setAutoCancel(true) builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) - val nm = applicationContext - .getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + val nm = applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager nm.notify(R.id.notification_download_report, builder.build()) } @@ -244,12 +228,9 @@ class EpisodeDownloadWorker(context: Context, params: WorkerParameters) : Worker bigTextB.append(String.format(Locale.getDefault(), "%s (%d%%)\n", key, value)) } val bigText = bigTextB.toString().trim { it <= ' ' } - val contentText = if (progressCopy.size == 1) { - bigText - } else { - applicationContext.resources.getQuantityString(R.plurals.downloads_left, - progressCopy.size, progressCopy.size) - } + val contentText = if (progressCopy.size == 1) bigText + else applicationContext.resources.getQuantityString(R.plurals.downloads_left, progressCopy.size, progressCopy.size) + val builder = NotificationCompat.Builder(applicationContext, NotificationUtils.CHANNEL_ID_DOWNLOADING) builder.setTicker(applicationContext.getString(R.string.download_notification_title_episodes)) .setContentTitle(applicationContext.getString(R.string.download_notification_title_episodes)) diff --git a/app/src/main/java/ac/mdiq/podcini/net/download/service/FeedUpdateWorker.kt b/app/src/main/java/ac/mdiq/podcini/net/download/service/FeedUpdateWorker.kt index a2300d66..5a5c4455 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/download/service/FeedUpdateWorker.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/download/service/FeedUpdateWorker.kt @@ -48,20 +48,14 @@ class FeedUpdateWorker(context: Context, params: WorkerParameters) : Worker(cont val itr = toUpdate.iterator() while (itr.hasNext()) { val feed = itr.next() - if (feed.preferences?.keepUpdated == false) { - itr.remove() - } - if (!feed.isLocalFeed) { - allAreLocal = false - } + if (feed.preferences?.keepUpdated == false) itr.remove() + if (!feed.isLocalFeed) allAreLocal = false } toUpdate.shuffle() // If the worker gets cancelled early, every feed has a chance to be updated } else { val feed = DBReader.getFeed(feedId) ?: return Result.success() Log.d(TAG, "doWork feed.download_url: ${feed.download_url}") - if (!feed.isLocalFeed) { - allAreLocal = false - } + if (!feed.isLocalFeed) allAreLocal = false toUpdate = ArrayList() toUpdate.add(feed) // Needs to be updatable, so no singletonList force = true @@ -87,8 +81,7 @@ class FeedUpdateWorker(context: Context, params: WorkerParameters) : Worker(cont if (toUpdate != null) { contentText = context.resources.getQuantityString(R.plurals.downloads_left, toUpdate.size, toUpdate.size) - bigText = Stream.of(toUpdate).map { feed: Feed? -> "• " + feed!!.title } - .collect(Collectors.joining("\n")) + bigText = Stream.of(toUpdate).map { feed: Feed? -> "• " + feed!!.title }.collect(Collectors.joining("\n")) } return NotificationCompat.Builder(context, NotificationUtils.CHANNEL_ID_DOWNLOADING) .setContentTitle(context.getString(R.string.download_notification_title_feeds)) @@ -96,8 +89,7 @@ class FeedUpdateWorker(context: Context, params: WorkerParameters) : Worker(cont .setStyle(NotificationCompat.BigTextStyle().bigText(bigText)) .setSmallIcon(R.drawable.ic_notification_sync) .setOngoing(true) - .addAction(R.drawable.ic_cancel, context.getString(R.string.cancel_label), - WorkManager.getInstance(context).createCancelPendingIntent(id)) + .addAction(R.drawable.ic_cancel, context.getString(R.string.cancel_label), WorkManager.getInstance(context).createCancelPendingIntent(id)) .build() } @@ -122,21 +114,16 @@ class FeedUpdateWorker(context: Context, params: WorkerParameters) : Worker(cont } while (toUpdate.isNotEmpty()) { - if (isStopped) { - return - } + if (isStopped) return + notificationManager.notify(R.id.notification_updating_feeds, createNotification(toUpdate)) val feed = toUpdate[0] try { - if (feed.isLocalFeed) { - LocalFeedUpdater.updateFeed(feed, applicationContext, null) - } else { - refreshFeed(feed, force) - } + if (feed.isLocalFeed) LocalFeedUpdater.updateFeed(feed, applicationContext, null) + else refreshFeed(feed, force) } catch (e: Exception) { DBWriter.setFeedLastUpdateFailed(feed.id, true) - val status = DownloadResult(feed, feed.title?:"", - DownloadError.ERROR_IO_ERROR, false, e.message?:"") + val status = DownloadResult(feed, feed.title?:"", DownloadError.ERROR_IO_ERROR, false, e.message?:"") DBWriter.addDownloadStatus(status) } toUpdate.removeAt(0) @@ -145,16 +132,12 @@ class FeedUpdateWorker(context: Context, params: WorkerParameters) : Worker(cont @UnstableApi @Throws(Exception::class) fun refreshFeed(feed: Feed, force: Boolean) { - val nextPage = (inputData.getBoolean(FeedUpdateManager.EXTRA_NEXT_PAGE, false) - && feed.nextPageLink != null) - if (nextPage) { - feed.pageNr += 1 - } + val nextPage = (inputData.getBoolean(FeedUpdateManager.EXTRA_NEXT_PAGE, false) && feed.nextPageLink != null) + if (nextPage) feed.pageNr += 1 + val builder = create(feed) builder.setForce(force || feed.hasLastUpdateFailed()) - if (nextPage) { - builder.source = feed.nextPageLink - } + if (nextPage) builder.source = feed.nextPageLink val request = builder.build() val downloader = DefaultDownloaderFactory().create(request) ?: throw Exception("Unable to create downloader") @@ -162,9 +145,8 @@ class FeedUpdateWorker(context: Context, params: WorkerParameters) : Worker(cont downloader.call() if (!downloader.result.isSuccessful) { - if (downloader.cancelled || downloader.result.reason == DownloadError.ERROR_DOWNLOAD_CANCELLED) { - return - } + if (downloader.cancelled || downloader.result.reason == DownloadError.ERROR_DOWNLOAD_CANCELLED) return + DBWriter.setFeedLastUpdateFailed(request.feedfileId, true) DBWriter.addDownloadStatus(downloader.result) return @@ -179,23 +161,18 @@ class FeedUpdateWorker(context: Context, params: WorkerParameters) : Worker(cont return } - if (request.feedfileId == 0L) { - return // No download logs for new subscriptions - } + if (request.feedfileId == 0L) return // No download logs for new subscriptions + // we create a 'successful' download log if the feed's last refresh failed val log = DBReader.getFeedDownloadLog(request.feedfileId) - if (log.isNotEmpty() && !log[0].isSuccessful) { - DBWriter.addDownloadStatus(feedSyncTask.downloadStatus) - } + if (log.isNotEmpty() && !log[0].isSuccessful) DBWriter.addDownloadStatus(feedSyncTask.downloadStatus) + // newEpisodesNotification.showIfNeeded(applicationContext, feedSyncTask.savedFeed!!) if (!request.source.isNullOrEmpty()) { when { - !downloader.permanentRedirectUrl.isNullOrEmpty() -> { - DBWriter.updateFeedDownloadURL(request.source, downloader.permanentRedirectUrl!!) - } - feedSyncTask.redirectUrl.isNotEmpty() && feedSyncTask.redirectUrl != request.source -> { + !downloader.permanentRedirectUrl.isNullOrEmpty() -> DBWriter.updateFeedDownloadURL(request.source, downloader.permanentRedirectUrl!!) + feedSyncTask.redirectUrl.isNotEmpty() && feedSyncTask.redirectUrl != request.source -> DBWriter.updateFeedDownloadURL(request.source, feedSyncTask.redirectUrl) - } } } } diff --git a/app/src/main/java/ac/mdiq/podcini/net/download/service/HttpDownloader.kt b/app/src/main/java/ac/mdiq/podcini/net/download/service/HttpDownloader.kt index 30d869b9..ec9e3cf5 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/download/service/HttpDownloader.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/download/service/HttpDownloader.kt @@ -50,9 +50,7 @@ class HttpDownloader(request: DownloadRequest) : Downloader(request) { httpReq.cacheControl(CacheControl.Builder().noCache().build()) // noStore breaks CDNs } - if (uri.scheme == "http") { - httpReq.addHeader("Upgrade-Insecure-Requests", "1") - } + if (uri.scheme == "http") httpReq.addHeader("Upgrade-Insecure-Requests", "1") if (!downloadRequest.lastModified.isNullOrEmpty()) { val lastModified = downloadRequest.lastModified @@ -80,9 +78,7 @@ class HttpDownloader(request: DownloadRequest) : Downloader(request) { responseBody = response.body val contentEncodingHeader = response.header("Content-Encoding") var isGzip = false - if (!contentEncodingHeader.isNullOrEmpty()) { - isGzip = TextUtils.equals(contentEncodingHeader.lowercase(Locale.getDefault()), "gzip") - } + if (!contentEncodingHeader.isNullOrEmpty()) isGzip = TextUtils.equals(contentEncodingHeader.lowercase(Locale.getDefault()), "gzip") Log.d(TAG, "Response code is " + response.code)// check if size specified in the response header is the same as the size of the // written file. This check cannot be made if compression was used @@ -117,9 +113,8 @@ class HttpDownloader(request: DownloadRequest) : Downloader(request) { } else { var success = destination.delete() success = success or destination.createNewFile() - if (!success) { - throw IOException("Unable to recreate partially downloaded file") - } + if (!success) throw IOException("Unable to recreate partially downloaded file") + out = RandomAccessFile(destination, "rw") } @@ -129,9 +124,7 @@ class HttpDownloader(request: DownloadRequest) : Downloader(request) { Log.d(TAG, "Getting size of download") downloadRequest.size = responseBody.contentLength() + downloadRequest.soFar Log.d(TAG, "Size is " + downloadRequest.size) - if (downloadRequest.size < 0) { - downloadRequest.size = DownloadResult.SIZE_UNKNOWN.toLong() - } + if (downloadRequest.size < 0) downloadRequest.size = DownloadResult.SIZE_UNKNOWN.toLong() val freeSpace = freeSpaceAvailable Log.d(TAG, "Free space is $freeSpace") @@ -159,8 +152,8 @@ class HttpDownloader(request: DownloadRequest) : Downloader(request) { // written file. This check cannot be made if compression was used when { !isGzip && downloadRequest.size != DownloadResult.SIZE_UNKNOWN.toLong() && downloadRequest.soFar != downloadRequest.size -> { - onFail(DownloadError.ERROR_IO_WRONG_SIZE, "Download completed but size: " - + downloadRequest.soFar + " does not equal expected size " + downloadRequest.size) + onFail(DownloadError.ERROR_IO_WRONG_SIZE, + "Download completed but size: ${downloadRequest.soFar} does not equal expected size ${downloadRequest.size}") return } downloadRequest.size > 0 && downloadRequest.soFar == 0L -> { @@ -169,11 +162,8 @@ class HttpDownloader(request: DownloadRequest) : Downloader(request) { } else -> { val lastModified = response.header("Last-Modified") - if (lastModified != null) { - downloadRequest.setLastModified(lastModified) - } else { - downloadRequest.setLastModified(response.header("ETag")) - } + if (lastModified != null) downloadRequest.setLastModified(lastModified) + else downloadRequest.setLastModified(response.header("ETag")) onSuccess() } } diff --git a/app/src/main/java/ac/mdiq/podcini/net/download/service/PodciniHttpClient.kt b/app/src/main/java/ac/mdiq/podcini/net/download/service/PodciniHttpClient.kt index fe9ef501..c9301e08 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/download/service/PodciniHttpClient.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/download/service/PodciniHttpClient.kt @@ -31,9 +31,7 @@ object PodciniHttpClient { @JvmStatic @Synchronized fun getHttpClient(): OkHttpClient { - if (httpClient == null) { - httpClient = newBuilder().build() - } + if (httpClient == null) httpClient = newBuilder().build() return httpClient!! } diff --git a/app/src/main/java/ac/mdiq/podcini/net/download/service/handler/FeedParserTask.kt b/app/src/main/java/ac/mdiq/podcini/net/download/service/handler/FeedParserTask.kt index 3c3fd64e..f99ecaf7 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/download/service/handler/FeedParserTask.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/download/service/handler/FeedParserTask.kt @@ -24,10 +24,8 @@ class FeedParserTask(private val request: DownloadRequest) : Callable, - queuedEpisodeActions: List - ): Map, EpisodeAction> { + fun getRemoteActionsOverridingLocalActions(remoteActions: List, queuedEpisodeActions: List): Map, EpisodeAction> { // make sure more recent local actions are not overwritten by older remote actions val remoteActionsThatOverrideLocalActions: MutableMap, EpisodeAction> = ArrayMap() val localMostRecentPlayActions = createUniqueLocalMostRecentPlayActions(queuedEpisodeActions) @@ -22,13 +19,9 @@ object EpisodeActionFilter { EpisodeAction.Action.NEW, EpisodeAction.Action.DOWNLOAD -> {} EpisodeAction.Action.PLAY -> { val localMostRecent = localMostRecentPlayActions[key] - if (secondActionOverridesFirstAction(remoteAction, localMostRecent)) { - break - } + if (secondActionOverridesFirstAction(remoteAction, localMostRecent)) break val remoteMostRecentAction = remoteActionsThatOverrideLocalActions[key] - if (secondActionOverridesFirstAction(remoteAction, remoteMostRecentAction)) { - break - } + if (secondActionOverridesFirstAction(remoteAction, remoteMostRecentAction)) break remoteActionsThatOverrideLocalActions[key] = remoteAction } EpisodeAction.Action.DELETE -> {} @@ -39,9 +32,7 @@ object EpisodeActionFilter { return remoteActionsThatOverrideLocalActions } - private fun createUniqueLocalMostRecentPlayActions( - queuedEpisodeActions: List - ): Map, EpisodeAction> { + private fun createUniqueLocalMostRecentPlayActions(queuedEpisodeActions: List): Map, EpisodeAction> { val localMostRecentPlayAction: MutableMap, EpisodeAction> = ArrayMap() for (action in queuedEpisodeActions) { @@ -49,20 +40,14 @@ object EpisodeActionFilter { val key = Pair(action.podcast!!, action.episode!!) val mostRecent = localMostRecentPlayAction[key] when { - mostRecent?.timestamp == null -> { - localMostRecentPlayAction[key] = action - } - mostRecent.timestamp!!.before(action.timestamp) -> { - localMostRecentPlayAction[key] = action - } + mostRecent?.timestamp == null -> localMostRecentPlayAction[key] = action + mostRecent.timestamp!!.before(action.timestamp) -> localMostRecentPlayAction[key] = action } } return localMostRecentPlayAction } - private fun secondActionOverridesFirstAction(firstAction: EpisodeAction, - secondAction: EpisodeAction? - ): Boolean { + private fun secondActionOverridesFirstAction(firstAction: EpisodeAction, secondAction: EpisodeAction?): Boolean { return secondAction?.timestamp != null && (firstAction.timestamp == null || secondAction.timestamp!!.after(firstAction.timestamp)) } } diff --git a/app/src/main/java/ac/mdiq/podcini/net/sync/GuidValidator.kt b/app/src/main/java/ac/mdiq/podcini/net/sync/GuidValidator.kt index 9e80d389..c2b9fb1f 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/sync/GuidValidator.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/sync/GuidValidator.kt @@ -3,8 +3,7 @@ package ac.mdiq.podcini.net.sync object GuidValidator { @JvmStatic fun isValidGuid(guid: String?): Boolean { - return (guid != null && !guid.trim { it <= ' ' }.isEmpty() - && guid != "null") + return (guid != null && !guid.trim { it <= ' ' }.isEmpty() && guid != "null") } } diff --git a/app/src/main/java/ac/mdiq/podcini/net/sync/HostnameParser.kt b/app/src/main/java/ac/mdiq/podcini/net/sync/HostnameParser.kt index 39cfc458..4d16f60d 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/sync/HostnameParser.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/sync/HostnameParser.kt @@ -19,16 +19,9 @@ class HostnameParser(hosturl: String?) { if (m.matches()) { scheme = m.group(1) host = IDN.toASCII(m.group(2)) - port = if (m.group(3) == null) { - -1 - } else { - m.group(3).toInt() // regex -> can only be digits - } - subfolder = if (m.group(4) == null) { - "" - } else { - StringUtils.stripEnd(m.group(4), "/") - } + // regex -> can only be digits + port = if (m.group(3) == null) -1 else m.group(3).toInt() + subfolder = if (m.group(4) == null) "" else StringUtils.stripEnd(m.group(4), "/") } else { // URL does not match regex: use it anyway -> this will cause an exception on connect scheme = "https" @@ -37,21 +30,12 @@ class HostnameParser(hosturl: String?) { } when { - scheme == null && port == 80 -> { - scheme = "http" - } - scheme == null -> { - scheme = "https" // assume https - } + scheme == null && port == 80 -> scheme = "http" + scheme == null -> scheme = "https" // assume https } - when { - scheme == "https" && port == -1 -> { - port = 443 - } - scheme == "http" && port == -1 -> { - port = 80 - } + scheme == "https" && port == -1 -> port = 443 + scheme == "http" && port == -1 -> port = 80 } } diff --git a/app/src/main/java/ac/mdiq/podcini/net/sync/SyncService.kt b/app/src/main/java/ac/mdiq/podcini/net/sync/SyncService.kt index decf8613..50ebe75e 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/sync/SyncService.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/sync/SyncService.kt @@ -73,10 +73,8 @@ class SyncService(context: Context, params: WorkerParameters) : Worker(context, Log.e(TAG, Log.getStackTraceString(e)) if (e is SyncServiceException) { - if (runAttemptCount % 3 == 2) { - // Do not spam users with notification and retry before notifying - updateErrorNotification(e) - } + // Do not spam users with notification and retry before notifying + if (runAttemptCount % 3 == 2) updateErrorNotification(e) return Result.retry() } else { updateErrorNotification(e) @@ -115,9 +113,7 @@ class SyncService(context: Context, params: WorkerParameters) : Worker(context, // remove subscription if not just subscribed (again) for (downloadUrl in subscriptionChanges.removed) { - if (!queuedAddedFeeds.contains(downloadUrl)) { - removeFeedWithDownloadUrl(applicationContext, downloadUrl) - } + if (!queuedAddedFeeds.contains(downloadUrl)) removeFeedWithDownloadUrl(applicationContext, downloadUrl) } if (lastSync == 0L) { @@ -148,11 +144,8 @@ class SyncService(context: Context, params: WorkerParameters) : Worker(context, try { while (true) { Thread.sleep(1000) - val event = EventBus.getDefault().getStickyEvent( - FeedUpdateRunningEvent::class.java) - if (event == null || !event.isFeedUpdateRunning) { - return - } + val event = EventBus.getDefault().getStickyEvent(FeedUpdateRunningEvent::class.java) + if (event == null || !event.isFeedUpdateRunning) return } } catch (e: InterruptedException) { e.printStackTrace() @@ -173,8 +166,7 @@ class SyncService(context: Context, params: WorkerParameters) : Worker(context, val queuedEpisodeActions: MutableList = synchronizationQueueStorage.queuedEpisodeActions if (lastSync == 0L) { EventBus.getDefault().postSticky(SyncServiceEvent(R.string.sync_status_upload_played)) - val readItems = getEpisodes(0, Int.MAX_VALUE, - FeedItemFilter(FeedItemFilter.PLAYED), SortOrder.DATE_NEW_OLD) + val readItems = getEpisodes(0, Int.MAX_VALUE, FeedItemFilter(FeedItemFilter.PLAYED), SortOrder.DATE_NEW_OLD) Log.d(TAG, "First sync. Upload state for all " + readItems.size + " played episodes") for (item in readItems) { val media = item.media ?: continue @@ -190,8 +182,7 @@ class SyncService(context: Context, params: WorkerParameters) : Worker(context, if (queuedEpisodeActions.size > 0) { LockingAsyncExecutor.lock.lock() try { - Log.d(TAG, "Uploading " + queuedEpisodeActions.size + " actions: " - + StringUtils.join(queuedEpisodeActions, ", ")) + Log.d(TAG, "Uploading ${queuedEpisodeActions.size} actions: ${StringUtils.join(queuedEpisodeActions, ", ")}") val postResponse = syncServiceImpl.uploadEpisodeActions(queuedEpisodeActions) newTimeStamp = postResponse?.timestamp?:0L Log.d(TAG, "Upload episode response: $postResponse") @@ -206,12 +197,9 @@ class SyncService(context: Context, params: WorkerParameters) : Worker(context, @UnstableApi @Synchronized private fun processEpisodeActions(remoteActions: List) { Log.d(TAG, "Processing " + remoteActions.size + " actions") - if (remoteActions.isEmpty()) { - return - } + if (remoteActions.isEmpty()) return - val playActionsToUpdate = getRemoteActionsOverridingLocalActions(remoteActions, - synchronizationQueueStorage.queuedEpisodeActions) + val playActionsToUpdate = getRemoteActionsOverridingLocalActions(remoteActions, synchronizationQueueStorage.queuedEpisodeActions) val queueToBeRemoved = LongList() val updatedItems: MutableList = ArrayList() for (action in playActionsToUpdate.values) { @@ -231,9 +219,8 @@ class SyncService(context: Context, params: WorkerParameters) : Worker(context, feedItem.setPlayed(true) feedItem.media!!.setPosition(0) queueToBeRemoved.add(feedItem.id) - } else { - Log.d(TAG, "Setting position: $action") - } + } else Log.d(TAG, "Setting position: $action") + updatedItems.add(feedItem) } removeQueueItem(applicationContext, false, *queueToBeRemoved.toArray()) @@ -242,16 +229,14 @@ class SyncService(context: Context, params: WorkerParameters) : Worker(context, } private fun clearErrorNotifications() { - val nm = applicationContext - .getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + val nm = applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager nm.cancel(R.id.notification_gpodnet_sync_error) nm.cancel(R.id.notification_gpodnet_sync_autherror) } private fun updateErrorNotification(exception: Exception) { Log.d(TAG, "Posting sync error notification") - val description = (applicationContext.getString(R.string.gpodnetsync_error_descr) - + exception.message) + val description = ("${applicationContext.getString(R.string.gpodnetsync_error_descr)}${exception.message}") if (!gpodnetNotificationsEnabled()) { Log.d(TAG, "Skipping sync error notification because of user setting") @@ -265,8 +250,7 @@ class SyncService(context: Context, params: WorkerParameters) : Worker(context, val intent = applicationContext.packageManager.getLaunchIntentForPackage( applicationContext.packageName) val pendingIntent = PendingIntent.getActivity(applicationContext, - R.id.pending_intent_sync_error, intent, PendingIntent.FLAG_UPDATE_CURRENT - or PendingIntent.FLAG_IMMUTABLE) + R.id.pending_intent_sync_error, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) val notification = NotificationCompat.Builder(applicationContext, NotificationUtils.CHANNEL_ID_SYNC_ERROR) .setContentTitle(applicationContext.getString(R.string.gpodnetsync_error_title)) @@ -277,17 +261,15 @@ class SyncService(context: Context, params: WorkerParameters) : Worker(context, .setAutoCancel(true) .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) .build() - val nm = applicationContext - .getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + val nm = applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager nm.notify(R.id.notification_gpodnet_sync_error, notification) } private fun getActiveSyncProvider(): ISyncService? { val selectedSyncProviderKey = SynchronizationSettings.selectedSyncProviderKey val selectedService = fromIdentifier(selectedSyncProviderKey?:"") - if (selectedService == null) { - return null - } + if (selectedService == null) return null + return when (selectedService) { SynchronizationProviderViewData.GPODDER_NET -> GpodnetService(getHttpClient(), hosturl, deviceID?:"", username?:"", password?:"") @@ -307,11 +289,8 @@ class SyncService(context: Context, params: WorkerParameters) : Worker(context, private fun getWorkRequest(): OneTimeWorkRequest.Builder { val constraints = Builder() - if (isAllowMobileSync) { - constraints.setRequiredNetworkType(NetworkType.CONNECTED) - } else { - constraints.setRequiredNetworkType(NetworkType.UNMETERED) - } + if (isAllowMobileSync) constraints.setRequiredNetworkType(NetworkType.CONNECTED) + else constraints.setRequiredNetworkType(NetworkType.UNMETERED) val builder: OneTimeWorkRequest.Builder = OneTimeWorkRequest.Builder(SyncService::class.java) .setConstraints(constraints.build()) @@ -346,8 +325,7 @@ class SyncService(context: Context, params: WorkerParameters) : Worker(context, val workRequest: OneTimeWorkRequest = getWorkRequest() .setInitialDelay(0L, TimeUnit.SECONDS) .build() - WorkManager.getInstance(context!!) - .enqueueUniqueWork(WORK_ID_SYNC, ExistingWorkPolicy.REPLACE, workRequest) + WorkManager.getInstance(context!!).enqueueUniqueWork(WORK_ID_SYNC, ExistingWorkPolicy.REPLACE, workRequest) } } } diff --git a/app/src/main/java/ac/mdiq/podcini/net/sync/SynchronizationProviderViewData.kt b/app/src/main/java/ac/mdiq/podcini/net/sync/SynchronizationProviderViewData.kt index b7134c19..c34ce87e 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/sync/SynchronizationProviderViewData.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/sync/SynchronizationProviderViewData.kt @@ -19,9 +19,7 @@ enum class SynchronizationProviderViewData(@JvmField val identifier: String, val @JvmStatic fun fromIdentifier(provider: String): SynchronizationProviderViewData? { for (synchronizationProvider in entries) { - if (synchronizationProvider.identifier == provider) { - return synchronizationProvider - } + if (synchronizationProvider.identifier == provider) return synchronizationProvider } return null } diff --git a/app/src/main/java/ac/mdiq/podcini/net/sync/SynchronizationSettings.kt b/app/src/main/java/ac/mdiq/podcini/net/sync/SynchronizationSettings.kt index e7cb1795..c86bbed0 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/sync/SynchronizationSettings.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/sync/SynchronizationSettings.kt @@ -40,35 +40,27 @@ object SynchronizationSettings { get() = sharedPreferences.getString(SELECTED_SYNC_PROVIDER, null) fun updateLastSynchronizationAttempt() { - sharedPreferences.edit() - .putLong(LAST_SYNC_ATTEMPT_TIMESTAMP, System.currentTimeMillis()) - .apply() + sharedPreferences.edit().putLong(LAST_SYNC_ATTEMPT_TIMESTAMP, System.currentTimeMillis()).apply() } fun setLastSynchronizationAttemptSuccess(isSuccess: Boolean) { - sharedPreferences.edit() - .putBoolean(LAST_SYNC_ATTEMPT_SUCCESS, isSuccess) - .apply() + sharedPreferences.edit().putBoolean(LAST_SYNC_ATTEMPT_SUCCESS, isSuccess).apply() } val lastSubscriptionSynchronizationTimestamp: Long get() = sharedPreferences.getLong(LAST_SUBSCRIPTION_SYNC_TIMESTAMP, 0) fun setLastSubscriptionSynchronizationAttemptTimestamp(newTimeStamp: Long) { - sharedPreferences.edit() - .putLong(LAST_SUBSCRIPTION_SYNC_TIMESTAMP, newTimeStamp).apply() + sharedPreferences.edit().putLong(LAST_SUBSCRIPTION_SYNC_TIMESTAMP, newTimeStamp).apply() } val lastEpisodeActionSynchronizationTimestamp: Long - get() = sharedPreferences - .getLong(LAST_EPISODE_ACTIONS_SYNC_TIMESTAMP, 0) + get() = sharedPreferences.getLong(LAST_EPISODE_ACTIONS_SYNC_TIMESTAMP, 0) fun setLastEpisodeActionSynchronizationAttemptTimestamp(timestamp: Long) { - sharedPreferences.edit() - .putLong(LAST_EPISODE_ACTIONS_SYNC_TIMESTAMP, timestamp).apply() + sharedPreferences.edit().putLong(LAST_EPISODE_ACTIONS_SYNC_TIMESTAMP, timestamp).apply() } private val sharedPreferences: SharedPreferences - get() = ClientConfig.applicationCallbacks!!.getApplicationInstance()!! - .getSharedPreferences(NAME, Context.MODE_PRIVATE) + get() = ClientConfig.applicationCallbacks!!.getApplicationInstance()!!.getSharedPreferences(NAME, Context.MODE_PRIVATE) } diff --git a/app/src/main/java/ac/mdiq/podcini/net/sync/gpoddernet/GpodnetService.kt b/app/src/main/java/ac/mdiq/podcini/net/sync/gpoddernet/GpodnetService.kt index 715b73c6..7e73ac81 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/sync/gpoddernet/GpodnetService.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/sync/gpoddernet/GpodnetService.kt @@ -29,8 +29,7 @@ import kotlin.math.min * Communicates with the gpodder.net service. */ class GpodnetService(private val httpClient: OkHttpClient, baseHosturl: String?, - private val deviceId: String, private var username: String, private var password: String -) : ISyncService { + private val deviceId: String, private var username: String, private var password: String) : ISyncService { private val baseScheme: String? private val basePort: Int private val baseHost: String? @@ -62,8 +61,7 @@ class GpodnetService(private val httpClient: OkHttpClient, baseHosturl: String?, query, scaledLogoSize) else String.format("q=%s", query) try { - val url = URI(baseScheme, null, baseHost, basePort, "/search.json", - parameters, null).toURL() + val url = URI(baseScheme, null, baseHost, basePort, "/search.json", parameters, null).toURL() val request: Builder = Builder().url(url) val response = executeRequest(request) @@ -94,8 +92,7 @@ class GpodnetService(private val httpClient: OkHttpClient, baseHosturl: String?, get() { requireLoggedIn() try { - val url = URI(baseScheme, null, baseHost, basePort, - String.format("/api/2/devices/%s.json", username), null, null).toURL() + val url = URI(baseScheme, null, baseHost, basePort, String.format("/api/2/devices/%s.json", username), null, null).toURL() val request: Builder = Builder().url(url) val response = executeRequest(request) val devicesArray = JSONArray(response) diff --git a/app/src/main/java/ac/mdiq/podcini/net/sync/gpoddernet/mapper/ResponseMapper.kt b/app/src/main/java/ac/mdiq/podcini/net/sync/gpoddernet/mapper/ResponseMapper.kt index 084cf30d..dc94a367 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/sync/gpoddernet/mapper/ResponseMapper.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/sync/gpoddernet/mapper/ResponseMapper.kt @@ -44,9 +44,7 @@ object ResponseMapper { for (i in 0 until jsonActions.length()) { val jsonAction = jsonActions.getJSONObject(i) val episodeAction = readFromJsonObject(jsonAction) - if (episodeAction != null) { - episodeActions.add(episodeAction) - } + if (episodeAction != null) episodeActions.add(episodeAction) } return EpisodeActionChanges(episodeActions, timestamp) } diff --git a/app/src/main/java/ac/mdiq/podcini/net/sync/gpoddernet/model/GpodnetDevice.kt b/app/src/main/java/ac/mdiq/podcini/net/sync/gpoddernet/model/GpodnetDevice.kt index 2842b7c6..713e5a98 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/sync/gpoddernet/model/GpodnetDevice.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/sync/gpoddernet/model/GpodnetDevice.kt @@ -1,10 +1,6 @@ package ac.mdiq.podcini.net.sync.gpoddernet.model -class GpodnetDevice(val id: String, - val caption: String, - type: String?, - val subscriptions: Int -) { +class GpodnetDevice(val id: String, val caption: String, type: String?, val subscriptions: Int) { val type: DeviceType init { @@ -12,8 +8,7 @@ class GpodnetDevice(val id: String, } override fun toString(): String { - return ("GpodnetDevice [id=" + id + ", caption=" + caption + ", type=" - + type + ", subscriptions=" + subscriptions + "]") + return ("GpodnetDevice [id=" + id + ", caption=" + caption + ", type=" + type + ", subscriptions=" + subscriptions + "]") } enum class DeviceType { @@ -25,9 +20,7 @@ class GpodnetDevice(val id: String, companion object { fun fromString(s: String?): DeviceType { - if (s == null) { - return OTHER - } + if (s == null) return OTHER return when (s) { "desktop" -> DESKTOP diff --git a/app/src/main/java/ac/mdiq/podcini/net/sync/gpoddernet/model/GpodnetEpisodeActionPostResponse.kt b/app/src/main/java/ac/mdiq/podcini/net/sync/gpoddernet/model/GpodnetEpisodeActionPostResponse.kt index 8e13555f..2125d5ae 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/sync/gpoddernet/model/GpodnetEpisodeActionPostResponse.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/sync/gpoddernet/model/GpodnetEpisodeActionPostResponse.kt @@ -7,13 +7,13 @@ import org.apache.commons.lang3.builder.ToStringStyle import org.json.JSONException import org.json.JSONObject -class GpodnetEpisodeActionPostResponse private constructor(timestamp: Long, - /** - * URLs that should be updated. The key of the map is the original URL, the value of the map - * is the sanitized URL. - */ - private val updatedUrls: Map -) : UploadChangesResponse(timestamp) { +/** + * URLs that should be updated. The key of the map is the original URL, the value of the map + * is the sanitized URL. + */ +class GpodnetEpisodeActionPostResponse private constructor(timestamp: Long, private val updatedUrls: Map) + : UploadChangesResponse(timestamp) { + override fun toString(): String { return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE) } diff --git a/app/src/main/java/ac/mdiq/podcini/net/sync/gpoddernet/model/GpodnetPodcast.kt b/app/src/main/java/ac/mdiq/podcini/net/sync/gpoddernet/model/GpodnetPodcast.kt index 78bd0f3e..ccd84447 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/sync/gpoddernet/model/GpodnetPodcast.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/sync/gpoddernet/model/GpodnetPodcast.kt @@ -1,18 +1,9 @@ package ac.mdiq.podcini.net.sync.gpoddernet.model -class GpodnetPodcast(val url: String, - val title: String, - val description: String, - val subscribers: Int, - val logoUrl: String, - val website: String, - val mygpoLink: String, - val author: String -) { +class GpodnetPodcast(val url: String, val title: String, val description: String, val subscribers: Int, val logoUrl: String, + val website: String, val mygpoLink: String, val author: String) { + override fun toString(): String { - return ("GpodnetPodcast [url=" + url + ", title=" + title - + ", description=" + description + ", subscribers=" - + subscribers + ", logoUrl=" + logoUrl + ", website=" + website - + ", mygpoLink=" + mygpoLink + "]") + return ("GpodnetPodcast [url=$url, title=$title, description=$description, subscribers=$subscribers, logoUrl=$logoUrl, website=$website, mygpoLink=$mygpoLink]") } } diff --git a/app/src/main/java/ac/mdiq/podcini/net/sync/gpoddernet/model/GpodnetUploadChangesResponse.kt b/app/src/main/java/ac/mdiq/podcini/net/sync/gpoddernet/model/GpodnetUploadChangesResponse.kt index e614baeb..6d34b51a 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/sync/gpoddernet/model/GpodnetUploadChangesResponse.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/sync/gpoddernet/model/GpodnetUploadChangesResponse.kt @@ -8,18 +8,14 @@ import org.json.JSONObject /** * Object returned by [GpodnetService] in uploadChanges method. */ -class GpodnetUploadChangesResponse(timestamp: Long, - /** - * URLs that should be updated. The key of the map is the original URL, the value of the map - * is the sanitized URL. - */ - val updatedUrls: Map -) : UploadChangesResponse(timestamp) { +/** + * URLs that should be updated. The key of the map is the original URL, the value of the map + * is the sanitized URL. + */ +class GpodnetUploadChangesResponse(timestamp: Long, val updatedUrls: Map) : UploadChangesResponse(timestamp) { + override fun toString(): String { - return "GpodnetUploadChangesResponse{" + - "timestamp=" + timestamp + - ", updatedUrls=" + updatedUrls + - '}' + return "GpodnetUploadChangesResponse{timestamp=$timestamp, updatedUrls=$updatedUrls}" } companion object { diff --git a/app/src/main/java/ac/mdiq/podcini/net/sync/model/EpisodeAction.kt b/app/src/main/java/ac/mdiq/podcini/net/sync/model/EpisodeAction.kt index b297936b..c17edcd9 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/sync/model/EpisodeAction.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/sync/model/EpisodeAction.kt @@ -49,12 +49,9 @@ class EpisodeAction private constructor(builder: Builder) { get() = action!!.name.lowercase() override fun equals(o: Any?): Boolean { - if (this === o) { - return true - } - if (o !is EpisodeAction) { - return false - } + if (this === o) return true + + if (o !is EpisodeAction) return false val that = o return started == that.started && position == that.position && total == that.total && action != that.action && podcast == that.podcast && episode == that.episode && timestamp == that.timestamp && guid == that.guid @@ -100,16 +97,7 @@ class EpisodeAction private constructor(builder: Builder) { } override fun toString(): String { - return ("EpisodeAction{" - + "podcast='" + podcast + '\'' - + ", episode='" + episode + '\'' - + ", guid='" + guid + '\'' - + ", action=" + action - + ", timestamp=" + timestamp - + ", started=" + started - + ", position=" + position - + ", total=" + total - + '}') + return ("EpisodeAction{podcast='$podcast', episode='$episode', guid='$guid', action=$action, timestamp=$timestamp, started=$started, position=$position, total=$total}") } enum class Action { @@ -144,23 +132,17 @@ class EpisodeAction private constructor(builder: Builder) { } fun started(seconds: Int): Builder { - if (action == Action.PLAY) { - this.started = seconds - } + if (action == Action.PLAY) this.started = seconds return this } fun position(seconds: Int): Builder { - if (action == Action.PLAY) { - this.position = seconds - } + if (action == Action.PLAY) this.position = seconds return this } fun total(seconds: Int): Builder { - if (action == Action.PLAY) { - this.total = seconds - } + if (action == Action.PLAY) this.total = seconds return this } @@ -189,9 +171,8 @@ class EpisodeAction private constructor(builder: Builder) { val podcast = `object`.optString("podcast") val episode = `object`.optString("episode") val actionString = `object`.optString("action") - if (podcast.isNullOrEmpty() || episode.isNullOrEmpty() || actionString.isNullOrEmpty()) { - return null - } + if (podcast.isNullOrEmpty() || episode.isNullOrEmpty() || actionString.isNullOrEmpty()) return null + val action: Action try { action = Action.valueOf(actionString.uppercase()) @@ -210,19 +191,13 @@ class EpisodeAction private constructor(builder: Builder) { } } val guid = `object`.optString("guid") - if (guid.isNotEmpty()) { - builder.guid(guid) - } + if (guid.isNotEmpty()) builder.guid(guid) + if (action == Action.PLAY) { val started = `object`.optInt("started", -1) val position = `object`.optInt("position", -1) val total = `object`.optInt("total", -1) - if (started >= 0 && position > 0 && total > 0) { - builder - .started(started) - .position(position) - .total(total) - } + if (started >= 0 && position > 0 && total > 0) builder.started(started).position(position).total(total) } return builder.build() } diff --git a/app/src/main/java/ac/mdiq/podcini/net/sync/model/EpisodeActionChanges.kt b/app/src/main/java/ac/mdiq/podcini/net/sync/model/EpisodeActionChanges.kt index 20979b30..581dd827 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/sync/model/EpisodeActionChanges.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/sync/model/EpisodeActionChanges.kt @@ -3,9 +3,6 @@ package ac.mdiq.podcini.net.sync.model class EpisodeActionChanges(val episodeActions: List, val timestamp: Long) { override fun toString(): String { - return ("EpisodeActionGetResponse{" - + "episodeActions=" + episodeActions - + ", timestamp=" + timestamp - + '}') + return ("EpisodeActionGetResponse{episodeActions=$episodeActions, timestamp=$timestamp}") } } diff --git a/app/src/main/java/ac/mdiq/podcini/net/sync/model/ISyncService.kt b/app/src/main/java/ac/mdiq/podcini/net/sync/model/ISyncService.kt index 8bdf1dfb..d12b8da6 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/sync/model/ISyncService.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/sync/model/ISyncService.kt @@ -10,9 +10,7 @@ interface ISyncService { fun getSubscriptionChanges(lastSync: Long): SubscriptionChanges? @Throws(SyncServiceException::class) - fun uploadSubscriptionChanges( - addedFeeds: List?, removedFeeds: List? - ): UploadChangesResponse? + fun uploadSubscriptionChanges(addedFeeds: List?, removedFeeds: List?): UploadChangesResponse? @Throws(SyncServiceException::class) fun getEpisodeActionChanges(lastSync: Long): EpisodeActionChanges? diff --git a/app/src/main/java/ac/mdiq/podcini/net/sync/model/SubscriptionChanges.kt b/app/src/main/java/ac/mdiq/podcini/net/sync/model/SubscriptionChanges.kt index 8ce19c74..4909982a 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/sync/model/SubscriptionChanges.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/sync/model/SubscriptionChanges.kt @@ -5,8 +5,6 @@ class SubscriptionChanges(val added: List, val timestamp: Long ) { override fun toString(): String { - return ("SubscriptionChange [added=" + added.toString() - + ", removed=" + removed.toString() + ", timestamp=" - + timestamp + "]") + return ("SubscriptionChange [added=$added, removed=$removed, timestamp=$timestamp]") } } diff --git a/app/src/main/java/ac/mdiq/podcini/net/sync/model/UploadChangesResponse.kt b/app/src/main/java/ac/mdiq/podcini/net/sync/model/UploadChangesResponse.kt index ece4eac2..de95f75b 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/sync/model/UploadChangesResponse.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/sync/model/UploadChangesResponse.kt @@ -1,8 +1,6 @@ package ac.mdiq.podcini.net.sync.model -abstract class UploadChangesResponse( - /** - * timestamp/ID that can be used for requesting changes since this upload. - */ - @JvmField val timestamp: Long -) +/** + * timestamp/ID that can be used for requesting changes since this upload. + */ +abstract class UploadChangesResponse(@JvmField val timestamp: Long) diff --git a/app/src/main/java/ac/mdiq/podcini/net/sync/nextcloud/NextcloudLoginFlow.kt b/app/src/main/java/ac/mdiq/podcini/net/sync/nextcloud/NextcloudLoginFlow.kt index a7f04452..dd3434e4 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/sync/nextcloud/NextcloudLoginFlow.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/sync/nextcloud/NextcloudLoginFlow.kt @@ -21,11 +21,8 @@ import java.net.URI import java.net.URL import java.util.concurrent.TimeUnit -class NextcloudLoginFlow(private val httpClient: OkHttpClient, - private val rawHostUrl: String, - private val context: Context, - private val callback: AuthenticationCallback -) { +class NextcloudLoginFlow(private val httpClient: OkHttpClient, private val rawHostUrl: String, private val context: Context, + private val callback: AuthenticationCallback) { private val hostname = HostnameParser(rawHostUrl) private var token: String? = null private var endpoint: String? = null @@ -76,8 +73,7 @@ class NextcloudLoginFlow(private val httpClient: OkHttpClient, .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe({ result: JSONObject -> - callback.onNextcloudAuthenticated( - result.getString("server"), result.getString("loginName"), result.getString("appPassword")) + callback.onNextcloudAuthenticated(result.getString("server"), result.getString("loginName"), result.getString("appPassword")) }, { error: Throwable -> this.token = null @@ -87,18 +83,13 @@ class NextcloudLoginFlow(private val httpClient: OkHttpClient, } fun cancel() { - if (startDisposable != null) { - startDisposable!!.dispose() - } - if (pollDisposable != null) { - pollDisposable!!.dispose() - } + startDisposable?.dispose() + pollDisposable?.dispose() } @Throws(IOException::class, JSONException::class) private fun doRequest(url: URL, bodyContent: String): JSONObject { - val requestBody = RequestBody.create( - "application/x-www-form-urlencoded".toMediaType(), bodyContent) + val requestBody = RequestBody.create("application/x-www-form-urlencoded".toMediaType(), bodyContent) val request: Request = Builder().url(url).method("POST", requestBody).build() val response = httpClient.newCall(request).execute() if (response.code != 200) { @@ -118,9 +109,7 @@ class NextcloudLoginFlow(private val httpClient: OkHttpClient, companion object { private const val TAG = "NextcloudLoginFlow" - fun fromInstanceState(httpClient: OkHttpClient, context: Context, - callback: AuthenticationCallback, instanceState: ArrayList - ): NextcloudLoginFlow { + fun fromInstanceState(httpClient: OkHttpClient, context: Context, callback: AuthenticationCallback, instanceState: ArrayList): NextcloudLoginFlow { val flow = NextcloudLoginFlow(httpClient, instanceState[0], context, callback) flow.token = instanceState[1] flow.endpoint = instanceState[2] diff --git a/app/src/main/java/ac/mdiq/podcini/net/sync/nextcloud/NextcloudSyncService.kt b/app/src/main/java/ac/mdiq/podcini/net/sync/nextcloud/NextcloudSyncService.kt index 3c61c525..628c8c74 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/sync/nextcloud/NextcloudSyncService.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/sync/nextcloud/NextcloudSyncService.kt @@ -14,13 +14,11 @@ import java.io.IOException import java.net.MalformedURLException import kotlin.math.min -class NextcloudSyncService(private val httpClient: OkHttpClient, baseHosturl: String?, - private val username: String, private val password: String -) : ISyncService { +class NextcloudSyncService(private val httpClient: OkHttpClient, baseHosturl: String?, private val username: String, private val password: String) + : ISyncService { private val hostname = HostnameParser(baseHosturl) - override fun login() { - } + override fun login() {} @Throws(SyncServiceException::class) override fun getSubscriptionChanges(lastSync: Long): SubscriptionChanges { @@ -85,8 +83,7 @@ class NextcloudSyncService(private val httpClient: OkHttpClient, baseHosturl: St override fun uploadEpisodeActions(queuedEpisodeActions: List?): UploadChangesResponse { var i = 0 while (i < queuedEpisodeActions!!.size) { - uploadEpisodeActionsPartial(queuedEpisodeActions, - i, min(queuedEpisodeActions.size.toDouble(), (i + UPLOAD_BULK_SIZE).toDouble()).toInt()) + uploadEpisodeActionsPartial(queuedEpisodeActions, i, min(queuedEpisodeActions.size.toDouble(), (i + UPLOAD_BULK_SIZE).toDouble()).toInt()) i += UPLOAD_BULK_SIZE } return NextcloudGpodderEpisodeActionPostResponse(System.currentTimeMillis() / 1000) @@ -99,9 +96,7 @@ class NextcloudSyncService(private val httpClient: OkHttpClient, baseHosturl: St for (i in from until to) { val episodeAction = queuedEpisodeActions!![i] val obj = episodeAction!!.writeToJsonObject() - if (obj != null) { - list.put(obj) - } + if (obj != null) list.put(obj) } val url: HttpUrl.Builder = makeUrl("/index.php/apps/gpoddersync/episode_action/create") val requestBody = RequestBody.create("application/json".toMediaType(), list.toString()) @@ -121,9 +116,8 @@ class NextcloudSyncService(private val httpClient: OkHttpClient, baseHosturl: St .method(method, body) .build() val response = httpClient.newCall(request).execute() - if (response.code != 200) { - throw IOException("Response code: " + response.code) - } + if (response.code != 200) throw IOException("Response code: " + response.code) + return response.body!!.string() } @@ -131,14 +125,13 @@ class NextcloudSyncService(private val httpClient: OkHttpClient, baseHosturl: St val builder = HttpUrl.Builder() if (hostname.scheme != null) builder.scheme(hostname.scheme!!) if (hostname.host != null) builder.host(hostname.host!!) - return builder.port(hostname.port) - .addPathSegments(hostname.subfolder + path) + return builder.port(hostname.port).addPathSegments(hostname.subfolder + path) } - override fun logout() { - } + override fun logout() {} private class NextcloudGpodderEpisodeActionPostResponse(epochSecond: Long) : UploadChangesResponse(epochSecond) + companion object { private const val UPLOAD_BULK_SIZE = 30 } diff --git a/app/src/main/java/ac/mdiq/podcini/net/sync/queue/SynchronizationQueueSink.kt b/app/src/main/java/ac/mdiq/podcini/net/sync/queue/SynchronizationQueueSink.kt index 9f2ee35b..1739c006 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/sync/queue/SynchronizationQueueSink.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/sync/queue/SynchronizationQueueSink.kt @@ -19,9 +19,7 @@ object SynchronizationQueueSink { } fun syncNowIfNotSyncedRecently() { - if (System.currentTimeMillis() - SynchronizationSettings.lastSyncAttempt > 1000 * 60 * 10) { - syncNow() - } + if (System.currentTimeMillis() - SynchronizationSettings.lastSyncAttempt > 1000 * 60 * 10) syncNow() } @JvmStatic @@ -30,9 +28,8 @@ object SynchronizationQueueSink { } fun enqueueFeedAddedIfSynchronizationIsActive(context: Context, downloadUrl: String) { - if (!SynchronizationSettings.isProviderConnected) { - return - } + if (!SynchronizationSettings.isProviderConnected) return + LockingAsyncExecutor.executeLockedAsync { SynchronizationQueueStorage(context).enqueueFeedAdded(downloadUrl) syncNow() @@ -40,9 +37,8 @@ object SynchronizationQueueSink { } fun enqueueFeedRemovedIfSynchronizationIsActive(context: Context, downloadUrl: String) { - if (!SynchronizationSettings.isProviderConnected) { - return - } + if (!SynchronizationSettings.isProviderConnected) return + LockingAsyncExecutor.executeLockedAsync { SynchronizationQueueStorage(context).enqueueFeedRemoved(downloadUrl) syncNow() @@ -50,27 +46,19 @@ object SynchronizationQueueSink { } fun enqueueEpisodeActionIfSynchronizationIsActive(context: Context, action: EpisodeAction) { - if (!SynchronizationSettings.isProviderConnected) { - return - } + if (!SynchronizationSettings.isProviderConnected) return + LockingAsyncExecutor.executeLockedAsync { SynchronizationQueueStorage(context).enqueueEpisodeAction(action) syncNow() } } - fun enqueueEpisodePlayedIfSynchronizationIsActive(context: Context, media: FeedMedia, - completed: Boolean - ) { - if (!SynchronizationSettings.isProviderConnected) { - return - } - if (media.item?.feed == null || media.item!!.feed!!.isLocalFeed) { - return - } - if (media.startPosition < 0 || (!completed && media.startPosition >= media.getPosition())) { - return - } + fun enqueueEpisodePlayedIfSynchronizationIsActive(context: Context, media: FeedMedia, completed: Boolean) { + if (!SynchronizationSettings.isProviderConnected) return + if (media.item?.feed == null || media.item!!.feed!!.isLocalFeed) return + if (media.startPosition < 0 || (!completed && media.startPosition >= media.getPosition())) return + val action = EpisodeAction.Builder(media.item!!, EpisodeAction.PLAY) .currentTimestamp() .started(media.startPosition / 1000) diff --git a/app/src/main/java/ac/mdiq/podcini/net/sync/queue/SynchronizationQueueStorage.kt b/app/src/main/java/ac/mdiq/podcini/net/sync/queue/SynchronizationQueueStorage.kt index 0d9aa171..7b89f82b 100644 --- a/app/src/main/java/ac/mdiq/podcini/net/sync/queue/SynchronizationQueueStorage.kt +++ b/app/src/main/java/ac/mdiq/podcini/net/sync/queue/SynchronizationQueueStorage.kt @@ -14,8 +14,7 @@ class SynchronizationQueueStorage(context: Context) { get() { val actions = ArrayList() try { - val json = sharedPreferences - .getString(QUEUED_EPISODE_ACTIONS, "[]") + val json = sharedPreferences.getString(QUEUED_EPISODE_ACTIONS, "[]") val queue = JSONArray(json) for (i in 0 until queue.length()) { val act = EpisodeAction.readFromJsonObject(queue.getJSONObject(i))?: continue @@ -31,8 +30,7 @@ class SynchronizationQueueStorage(context: Context) { get() { val removedFeedUrls = ArrayList() try { - val json = sharedPreferences - .getString(QUEUED_FEEDS_REMOVED, "[]") + val json = sharedPreferences.getString(QUEUED_FEEDS_REMOVED, "[]") val queue = JSONArray(json) for (i in 0 until queue.length()) { removedFeedUrls.add(queue.getString(i)) @@ -47,8 +45,7 @@ class SynchronizationQueueStorage(context: Context) { get() { val addedFeedUrls = ArrayList() try { - val json = sharedPreferences - .getString(QUEUED_FEEDS_ADDED, "[]") + val json = sharedPreferences.getString(QUEUED_FEEDS_ADDED, "[]") val queue = JSONArray(json) for (i in 0 until queue.length()) { addedFeedUrls.add(queue.getString(i)) @@ -60,8 +57,7 @@ class SynchronizationQueueStorage(context: Context) { } fun clearEpisodeActionQueue() { - sharedPreferences.edit() - .putString(QUEUED_EPISODE_ACTIONS, "[]").apply() + sharedPreferences.edit().putString(QUEUED_EPISODE_ACTIONS, "[]").apply() } fun clearFeedQueues() { @@ -115,9 +111,7 @@ class SynchronizationQueueStorage(context: Context) { private fun indexOf(string: String, array: JSONArray): Int { try { for (i in 0 until array.length()) { - if (array.getString(i) == string) { - return i - } + if (array.getString(i) == string) return i } } catch (jsonException: JSONException) { jsonException.printStackTrace() @@ -131,9 +125,7 @@ class SynchronizationQueueStorage(context: Context) { try { val queue = JSONArray(json) queue.put(action.writeToJsonObject()) - sharedPreferences.edit().putString( - QUEUED_EPISODE_ACTIONS, queue.toString() - ).apply() + sharedPreferences.edit().putString(QUEUED_EPISODE_ACTIONS, queue.toString()).apply() } catch (jsonException: JSONException) { jsonException.printStackTrace() } diff --git a/app/src/main/java/ac/mdiq/podcini/playback/PlayableUtils.kt b/app/src/main/java/ac/mdiq/podcini/playback/PlayableUtils.kt index 659d943d..191891fe 100644 --- a/app/src/main/java/ac/mdiq/podcini/playback/PlayableUtils.kt +++ b/app/src/main/java/ac/mdiq/podcini/playback/PlayableUtils.kt @@ -25,9 +25,9 @@ object PlayableUtils { val item = playable.item if (item != null && item.isNew) DBWriter.markItemPlayed(FeedItem.UNPLAYED, item.id) - if (playable.startPosition >= 0 && playable.getPosition() > playable.startPosition) { + if (playable.startPosition >= 0 && playable.getPosition() > playable.startPosition) playable.playedDuration = (playable.playedDurationWhenStarted + playable.getPosition() - playable.startPosition) - } + DBWriter.setFeedMediaPlaybackInformation(playable) } } diff --git a/app/src/main/java/ac/mdiq/podcini/playback/PlaybackController.kt b/app/src/main/java/ac/mdiq/podcini/playback/PlaybackController.kt index ecf6ef6e..5f004db6 100644 --- a/app/src/main/java/ac/mdiq/podcini/playback/PlaybackController.kt +++ b/app/src/main/java/ac/mdiq/podcini/playback/PlaybackController.kt @@ -41,6 +41,7 @@ abstract class PlaybackController(private val activity: FragmentActivity) { private var released = false private var initialized = false private var eventsRegistered = false + private var loadedFeedMedia: Long = -1 /** @@ -109,7 +110,7 @@ abstract class PlaybackController(private val activity: FragmentActivity) { } fun isPlaybackServiceReady() : Boolean { - return playbackService != null + return playbackService != null && playbackService!!.isServiceReady() } private fun unbind() { @@ -311,9 +312,7 @@ abstract class PlaybackController(private val activity: FragmentActivity) { fun extendSleepTimer(extendTime: Long) { val timeLeft = sleepTimerTimeLeft - if (playbackService != null && timeLeft != Playable.INVALID_TIME.toLong()) { - setSleepTimer(timeLeft + extendTime) - } + if (playbackService != null && timeLeft != Playable.INVALID_TIME.toLong()) setSleepTimer(timeLeft + extendTime) } fun setSleepTimer(time: Long) { @@ -324,11 +323,13 @@ abstract class PlaybackController(private val activity: FragmentActivity) { if (playbackService != null) { playbackService!!.seekTo(time) } else { - val media = getMedia() +// val media = getMedia() + if (media == null) return + PlaybackServiceStarter(activity, media!!).start() if (media is FeedMedia) { - media.setPosition(time) - DBWriter.setFeedItem(media.item) - EventBus.getDefault().post(PlaybackPositionEvent(time, media.getDuration())) + media!!.setPosition(time) + DBWriter.setFeedItem((media as FeedMedia).item) + EventBus.getDefault().post(PlaybackPositionEvent(time, media!!.getDuration())) } } } diff --git a/app/src/main/java/ac/mdiq/podcini/playback/base/PlaybackServiceMediaPlayer.kt b/app/src/main/java/ac/mdiq/podcini/playback/base/PlaybackServiceMediaPlayer.kt index 5649d9de..5bfe3dbe 100644 --- a/app/src/main/java/ac/mdiq/podcini/playback/base/PlaybackServiceMediaPlayer.kt +++ b/app/src/main/java/ac/mdiq/podcini/playback/base/PlaybackServiceMediaPlayer.kt @@ -291,8 +291,7 @@ abstract class PlaybackServiceMediaPlayer protected constructor(protected val co protected fun acquireWifiLockIfNecessary() { if (shouldLockWifi()) { if (wifiLock == null) { - wifiLock = (context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager) - .createWifiLock(WifiManager.WIFI_MODE_FULL, TAG) + wifiLock = (context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager).createWifiLock(WifiManager.WIFI_MODE_FULL, TAG) wifiLock?.setReferenceCounted(false) } wifiLock?.acquire() @@ -301,9 +300,7 @@ abstract class PlaybackServiceMediaPlayer protected constructor(protected val co @Synchronized protected fun releaseWifiLockIfNecessary() { - if (wifiLock != null && wifiLock!!.isHeld) { - wifiLock!!.release() - } + if (wifiLock != null && wifiLock!!.isHeld) wifiLock!!.release() } /** @@ -361,7 +358,7 @@ abstract class PlaybackServiceMediaPlayer protected constructor(protected val co fun onMediaChanged(reloadUI: Boolean) - fun onPostPlayback(media: Playable, ended: Boolean, skipped: Boolean, playingNext: Boolean) + fun onPostPlayback(media: Playable?, ended: Boolean, skipped: Boolean, playingNext: Boolean) fun onPlaybackStart(playable: Playable, position: Int) diff --git a/app/src/main/java/ac/mdiq/podcini/playback/service/ExoPlayerWrapper.kt b/app/src/main/java/ac/mdiq/podcini/playback/service/ExoPlayerWrapper.kt index 903d0fe3..f9b573ae 100644 --- a/app/src/main/java/ac/mdiq/podcini/playback/service/ExoPlayerWrapper.kt +++ b/app/src/main/java/ac/mdiq/podcini/playback/service/ExoPlayerWrapper.kt @@ -40,7 +40,6 @@ import java.util.concurrent.TimeUnit @UnstableApi class ExoPlayerWrapper internal constructor(private val context: Context) { - // TODO: need to experiment this, 5 seconds for now private val bufferUpdateInterval = 5L private val bufferingUpdateDisposable: Disposable diff --git a/app/src/main/java/ac/mdiq/podcini/playback/service/LocalPSMP.kt b/app/src/main/java/ac/mdiq/podcini/playback/service/LocalPSMP.kt index c1ef7dac..8aec591c 100644 --- a/app/src/main/java/ac/mdiq/podcini/playback/service/LocalPSMP.kt +++ b/app/src/main/java/ac/mdiq/podcini/playback/service/LocalPSMP.kt @@ -46,13 +46,13 @@ class LocalPSMP(context: Context, callback: PSMPCallback) : PlaybackServiceMedia private var statusBeforeSeeking: PlayerStatus? = null @Volatile - private var mediaPlayer: ExoPlayerWrapper? = null + private var playerWrapper: ExoPlayerWrapper? = null @Volatile - private var media: Playable? = null + private var playable: Playable? = null @Volatile - private var stream = false + private var isStreaming = false @Volatile private var mediaType: MediaType @@ -118,21 +118,21 @@ class LocalPSMP(context: Context, callback: PSMPCallback) : PlaybackServiceMedia * @see .playMediaObject */ private fun playMediaObject(playable: Playable, forceReset: Boolean, stream: Boolean, startWhenPrepared: Boolean, prepareImmediately: Boolean) { - if (media != null) { - if (!forceReset && media!!.getIdentifier() == playable.getIdentifier() && playerStatus == PlayerStatus.PLAYING) { + if (this.playable != null) { + if (!forceReset && this.playable!!.getIdentifier() == playable.getIdentifier() && playerStatus == PlayerStatus.PLAYING) { // episode is already playing -> ignore method call Log.d(TAG, "Method call to playMediaObject was ignored: media file already playing.") return } else { // stop playback of this episode if (playerStatus == PlayerStatus.PAUSED || playerStatus == PlayerStatus.PLAYING || playerStatus == PlayerStatus.PREPARED) - mediaPlayer?.stop() + playerWrapper?.stop() // set temporarily to pause in order to update list with current position - if (playerStatus == PlayerStatus.PLAYING) callback.onPlaybackPause(media, getPosition()) + if (playerStatus == PlayerStatus.PLAYING) callback.onPlaybackPause(this.playable, getPosition()) - if (media!!.getIdentifier() != playable.getIdentifier()) { - val oldMedia: Playable = media!! + if (this.playable!!.getIdentifier() != playable.getIdentifier()) { + val oldMedia: Playable = this.playable!! callback.onPostPlayback(oldMedia, ended = false, skipped = false, true) } @@ -140,39 +140,40 @@ class LocalPSMP(context: Context, callback: PSMPCallback) : PlaybackServiceMedia } } - media = playable - this.stream = stream - mediaType = media!!.getMediaType() + this.playable = playable + this.isStreaming = stream + mediaType = this.playable!!.getMediaType() videoSize = null createMediaPlayer() this@LocalPSMP.startWhenPrepared.set(startWhenPrepared) - setPlayerStatus(PlayerStatus.INITIALIZING, media) + setPlayerStatus(PlayerStatus.INITIALIZING, this.playable) try { - callback.ensureMediaInfoLoaded(media!!) + callback.ensureMediaInfoLoaded(this.playable!!) callback.onMediaChanged(false) - setPlaybackParams(PlaybackSpeedUtils.getCurrentPlaybackSpeed(media), UserPreferences.isSkipSilence) + setPlaybackParams(PlaybackSpeedUtils.getCurrentPlaybackSpeed(this.playable), UserPreferences.isSkipSilence) when { stream -> { - val streamurl = media!!.getStreamUrl() + val streamurl = this.playable!!.getStreamUrl() if (streamurl != null) { if (playable is FeedMedia && playable.item?.feed?.preferences != null) { val preferences = playable.item!!.feed!!.preferences!! - mediaPlayer?.setDataSource(streamurl, preferences.username, preferences.password) - } else mediaPlayer?.setDataSource(streamurl) + playerWrapper?.setDataSource(streamurl, preferences.username, preferences.password) + } else playerWrapper?.setDataSource(streamurl) } } else -> { - val localMediaurl = media!!.getLocalMediaUrl() - if (localMediaurl != null && File(localMediaurl).canRead()) mediaPlayer?.setDataSource(localMediaurl) + val localMediaurl = this.playable!!.getLocalMediaUrl() + if (localMediaurl != null && File(localMediaurl).canRead()) playerWrapper?.setDataSource(localMediaurl) else throw IOException("Unable to read local file $localMediaurl") } } val uiModeManager = context.getSystemService(Context.UI_MODE_SERVICE) as UiModeManager - if (uiModeManager.currentModeType != Configuration.UI_MODE_TYPE_CAR) setPlayerStatus(PlayerStatus.INITIALIZED, media) + if (uiModeManager.currentModeType != Configuration.UI_MODE_TYPE_CAR) setPlayerStatus(PlayerStatus.INITIALIZED, + this.playable) if (prepareImmediately) { - setPlayerStatus(PlayerStatus.PREPARING, media) - mediaPlayer?.prepare() + setPlayerStatus(PlayerStatus.PREPARING, this.playable) + playerWrapper?.prepare() onPrepared(startWhenPrepared) } } catch (e: IOException) { @@ -201,23 +202,19 @@ class LocalPSMP(context: Context, callback: PSMPCallback) : PlaybackServiceMedia Log.d(TAG, "Audiofocus successfully requested") Log.d(TAG, "Resuming/Starting playback") acquireWifiLockIfNecessary() - setPlaybackParams(PlaybackSpeedUtils.getCurrentPlaybackSpeed(media), UserPreferences.isSkipSilence) + setPlaybackParams(PlaybackSpeedUtils.getCurrentPlaybackSpeed(playable), UserPreferences.isSkipSilence) setVolume(1.0f, 1.0f) - if (media != null && playerStatus == PlayerStatus.PREPARED && media!!.getPosition() > 0) { - val newPosition = RewindAfterPauseUtils.calculatePositionWithRewind(media!!.getPosition(), media!!.getLastPlayedTime()) + if (playable != null && playerStatus == PlayerStatus.PREPARED && playable!!.getPosition() > 0) { + val newPosition = RewindAfterPauseUtils.calculatePositionWithRewind(playable!!.getPosition(), playable!!.getLastPlayedTime()) seekTo(newPosition) } - mediaPlayer?.start() + playerWrapper?.start() - setPlayerStatus(PlayerStatus.PLAYING, media) + setPlayerStatus(PlayerStatus.PLAYING, playable) pausedBecauseOfTransientAudiofocusLoss = false - } else { - Log.e(TAG, "Failed to request audio focus") - } - } else { - Log.d(TAG, "Call to resume() was ignored because current state of PSMP object is $playerStatus") - } + } else Log.e(TAG, "Failed to request audio focus") + } else Log.d(TAG, "Call to resume() was ignored because current state of PSMP object is $playerStatus") } @@ -236,14 +233,14 @@ class LocalPSMP(context: Context, callback: PSMPCallback) : PlaybackServiceMedia releaseWifiLockIfNecessary() if (playerStatus == PlayerStatus.PLAYING) { Log.d(TAG, "Pausing playback.") - mediaPlayer?.pause() - setPlayerStatus(PlayerStatus.PAUSED, media, getPosition()) + playerWrapper?.pause() + setPlayerStatus(PlayerStatus.PAUSED, playable, getPosition()) if (abandonFocus) { abandonAudioFocus() pausedBecauseOfTransientAudiofocusLoss = false } - if (stream && reinit) reinit() + if (isStreaming && reinit) reinit() } else { Log.d(TAG, "Ignoring call to pause: Player is in $playerStatus state") } @@ -263,8 +260,8 @@ class LocalPSMP(context: Context, callback: PSMPCallback) : PlaybackServiceMedia override fun prepare() { if (playerStatus == PlayerStatus.INITIALIZED) { Log.d(TAG, "Preparing media player") - setPlayerStatus(PlayerStatus.PREPARING, media) - mediaPlayer?.prepare() + setPlayerStatus(PlayerStatus.PREPARING, playable) + playerWrapper?.prepare() onPrepared(startWhenPrepared.get()) } } @@ -276,18 +273,18 @@ class LocalPSMP(context: Context, callback: PSMPCallback) : PlaybackServiceMedia check(playerStatus == PlayerStatus.PREPARING) { "Player is not in PREPARING state" } Log.d(TAG, "Resource prepared") - if (mediaPlayer != null && mediaType == MediaType.VIDEO) videoSize = Pair(mediaPlayer!!.videoWidth, mediaPlayer!!.videoHeight) + if (playerWrapper != null && mediaType == MediaType.VIDEO) videoSize = Pair(playerWrapper!!.videoWidth, playerWrapper!!.videoHeight) - if (media != null) { + if (playable != null) { // TODO this call has no effect! - if (media!!.getPosition() > 0) seekTo(media!!.getPosition()) + if (playable!!.getPosition() > 0) seekTo(playable!!.getPosition()) - if (media!!.getDuration() <= 0) { + if (playable!!.getDuration() <= 0) { Log.d(TAG, "Setting duration of media") - if (mediaPlayer != null) media!!.setDuration(mediaPlayer!!.duration) + if (playerWrapper != null) playable!!.setDuration(playerWrapper!!.duration) } } - setPlayerStatus(PlayerStatus.PREPARED, media) + setPlayerStatus(PlayerStatus.PREPARED, playable) if (startWhenPrepared) resume() } @@ -302,8 +299,8 @@ class LocalPSMP(context: Context, callback: PSMPCallback) : PlaybackServiceMedia Log.d(TAG, "reinit()") releaseWifiLockIfNecessary() when { - media != null -> playMediaObject(media!!, true, stream, startWhenPrepared.get(), false) - mediaPlayer != null -> mediaPlayer!!.reset() + playable != null -> playMediaObject(playable!!, true, isStreaming, startWhenPrepared.get(), false) + playerWrapper != null -> playerWrapper!!.reset() else -> Log.d(TAG, "Call to reinit was ignored: media and mediaPlayer were null") } } @@ -336,9 +333,9 @@ class LocalPSMP(context: Context, callback: PSMPCallback) : PlaybackServiceMedia } seekLatch = CountDownLatch(1) statusBeforeSeeking = playerStatus - setPlayerStatus(PlayerStatus.SEEKING, media, getPosition()) - mediaPlayer?.seekTo(t) - if (statusBeforeSeeking == PlayerStatus.PREPARED) media?.setPosition(t) + setPlayerStatus(PlayerStatus.SEEKING, playable, getPosition()) + playerWrapper?.seekTo(t) + if (statusBeforeSeeking == PlayerStatus.PREPARED) playable?.setPosition(t) try { seekLatch!!.await(3, TimeUnit.SECONDS) } catch (e: InterruptedException) { @@ -346,7 +343,7 @@ class LocalPSMP(context: Context, callback: PSMPCallback) : PlaybackServiceMedia } } PlayerStatus.INITIALIZED -> { - media?.setPosition(t) + playable?.setPosition(t) startWhenPrepared.set(false) prepare() } @@ -361,11 +358,8 @@ class LocalPSMP(context: Context, callback: PSMPCallback) : PlaybackServiceMedia */ override fun seekDelta(d: Int) { val currentPosition = getPosition() - if (currentPosition != Playable.INVALID_TIME) { - seekTo(currentPosition + d) - } else { - Log.e(TAG, "getPosition() returned INVALID_TIME in seekDelta") - } + if (currentPosition != Playable.INVALID_TIME) seekTo(currentPosition + d) + else Log.e(TAG, "getPosition() returned INVALID_TIME in seekDelta") } /** @@ -374,10 +368,9 @@ class LocalPSMP(context: Context, callback: PSMPCallback) : PlaybackServiceMedia override fun getDuration(): Int { var retVal = Playable.INVALID_TIME if (playerStatus == PlayerStatus.PLAYING || playerStatus == PlayerStatus.PAUSED || playerStatus == PlayerStatus.PREPARED) { - if (mediaPlayer != null) retVal = mediaPlayer!!.duration + if (playerWrapper != null) retVal = playerWrapper!!.duration } - if (retVal <= 0 && media != null && media!!.getDuration() > 0) retVal = media!!.getDuration() - + if (retVal <= 0 && playable != null && playable!!.getDuration() > 0) retVal = playable!!.getDuration() return retVal } @@ -387,10 +380,9 @@ class LocalPSMP(context: Context, callback: PSMPCallback) : PlaybackServiceMedia override fun getPosition(): Int { var retVal = Playable.INVALID_TIME if (playerStatus.isAtLeast(PlayerStatus.PREPARED)) { - if (mediaPlayer != null) retVal = mediaPlayer!!.currentPosition + if (playerWrapper != null) retVal = playerWrapper!!.currentPosition } - if (retVal <= 0 && media != null && media!!.getPosition() >= 0) retVal = media!!.getPosition() - + if (retVal <= 0 && playable != null && playable!!.getPosition() >= 0) retVal = playable!!.getPosition() return retVal } @@ -409,7 +401,7 @@ class LocalPSMP(context: Context, callback: PSMPCallback) : PlaybackServiceMedia override fun setPlaybackParams(speed: Float, skipSilence: Boolean) { Log.d(TAG, "Playback speed was set to $speed") EventBus.getDefault().post(SpeedChangedEvent(speed)) - mediaPlayer?.setPlaybackParams(speed, skipSilence) + playerWrapper?.setPlaybackParams(speed, skipSilence) } /** @@ -418,7 +410,7 @@ class LocalPSMP(context: Context, callback: PSMPCallback) : PlaybackServiceMedia override fun getPlaybackSpeed(): Float { var retVal = 1f if (playerStatus == PlayerStatus.PLAYING || playerStatus == PlayerStatus.PAUSED || playerStatus == PlayerStatus.INITIALIZED || playerStatus == PlayerStatus.PREPARED) { - if (mediaPlayer != null) retVal = mediaPlayer!!.currentSpeedMultiplier + if (playerWrapper != null) retVal = playerWrapper!!.currentSpeedMultiplier } return retVal } @@ -440,7 +432,7 @@ class LocalPSMP(context: Context, callback: PSMPCallback) : PlaybackServiceMedia volumeRight *= adaptionFactor } } - mediaPlayer?.setVolume(volumeLeft, volumeRight) + playerWrapper?.setVolume(volumeLeft, volumeRight) Log.d(TAG, "Media player volume was set to $volumeLeft $volumeRight") } @@ -449,22 +441,22 @@ class LocalPSMP(context: Context, callback: PSMPCallback) : PlaybackServiceMedia } override fun isStreaming(): Boolean { - return stream + return isStreaming } /** * Releases internally used resources. This method should only be called when the object is not used anymore. */ override fun shutdown() { - if (mediaPlayer != null) { + if (playerWrapper != null) { try { clearMediaPlayerListeners() - if (mediaPlayer!!.isPlaying) mediaPlayer!!.stop() + if (playerWrapper!!.isPlaying) playerWrapper!!.stop() } catch (e: Exception) { e.printStackTrace() } - mediaPlayer!!.release() - mediaPlayer = null + playerWrapper!!.release() + playerWrapper = null playerStatus = PlayerStatus.STOPPED } isShutDown = true @@ -473,13 +465,13 @@ class LocalPSMP(context: Context, callback: PSMPCallback) : PlaybackServiceMedia } override fun setVideoSurface(surface: SurfaceHolder?) { - mediaPlayer?.setDisplay(surface) + playerWrapper?.setDisplay(surface) } override fun resetVideoSurface() { if (mediaType == MediaType.VIDEO) { Log.d(TAG, "Resetting video surface") - mediaPlayer?.setDisplay(null) + playerWrapper?.setDisplay(null) reinit() } else { Log.e(TAG, "Resetting video surface for media of Audio type") @@ -494,9 +486,8 @@ class LocalPSMP(context: Context, callback: PSMPCallback) : PlaybackServiceMedia * invalid values. */ override fun getVideoSize(): Pair? { - if (mediaPlayer != null && playerStatus != PlayerStatus.ERROR && mediaType == MediaType.VIDEO) - videoSize = Pair(mediaPlayer!!.videoWidth, mediaPlayer!!.videoHeight) - + if (playerWrapper != null && playerStatus != PlayerStatus.ERROR && mediaType == MediaType.VIDEO) + videoSize = Pair(playerWrapper!!.videoWidth, playerWrapper!!.videoHeight) return videoSize } @@ -507,37 +498,37 @@ class LocalPSMP(context: Context, callback: PSMPCallback) : PlaybackServiceMedia * @return the current media. May be null */ override fun getPlayable(): Playable? { - return media + return playable } override fun setPlayable(playable: Playable?) { - media = playable + this.playable = playable } override fun getAudioTracks(): List { - return mediaPlayer?.audioTracks?: listOf() + return playerWrapper?.audioTracks?: listOf() } override fun setAudioTrack(track: Int) { - if (mediaPlayer != null) mediaPlayer!!.setAudioTrack(track) + if (playerWrapper != null) playerWrapper!!.setAudioTrack(track) } override fun getSelectedAudioTrack(): Int { - return mediaPlayer?.selectedAudioTrack?:0 + return playerWrapper?.selectedAudioTrack?:0 } override fun createMediaPlayer() { - mediaPlayer?.release() + playerWrapper?.release() - if (media == null) { - mediaPlayer = null + if (playable == null) { + playerWrapper = null playerStatus = PlayerStatus.STOPPED return } - mediaPlayer = ExoPlayerWrapper(context) - mediaPlayer!!.setAudioStreamType(AudioManager.STREAM_MUSIC) - setMediaPlayerListeners(mediaPlayer) + playerWrapper = ExoPlayerWrapper(context) + playerWrapper!!.setAudioStreamType(AudioManager.STREAM_MUSIC) + setMediaPlayerListeners(playerWrapper) } private val audioFocusChangeListener = OnAudioFocusChangeListener { focusChange -> @@ -552,7 +543,7 @@ class LocalPSMP(context: Context, callback: PSMPCallback) : PlaybackServiceMedia focusChange == AudioManager.AUDIOFOCUS_LOSS -> { Log.d(TAG, "Lost audio focus") pause(true, reinit = false) - callback.shouldStop() +// callback.shouldStop() } focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK && !UserPreferences.shouldPauseForFocusLoss() -> { if (playerStatus == PlayerStatus.PLAYING) { @@ -564,20 +555,19 @@ class LocalPSMP(context: Context, callback: PSMPCallback) : PlaybackServiceMedia focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT || focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> { if (playerStatus == PlayerStatus.PLAYING) { Log.d(TAG, "Lost audio focus temporarily. Pausing...") - mediaPlayer?.pause() // Pause without telling the PlaybackService + playerWrapper?.pause() // Pause without telling the PlaybackService pausedBecauseOfTransientAudiofocusLoss = true audioFocusCanceller.removeCallbacksAndMessages(null) - audioFocusCanceller.postDelayed({ - // Still did not get back the audio focus. Now actually pause. - if (pausedBecauseOfTransientAudiofocusLoss) pause(abandonFocus = true, reinit = false) - }, 30000) + // Still did not get back the audio focus. Now actually pause. + audioFocusCanceller.postDelayed({ if (pausedBecauseOfTransientAudiofocusLoss) pause(abandonFocus = true, reinit = false) }, + 30000) } } focusChange == AudioManager.AUDIOFOCUS_GAIN -> { Log.d(TAG, "Gained audio focus") audioFocusCanceller.removeCallbacksAndMessages(null) - if (pausedBecauseOfTransientAudiofocusLoss) mediaPlayer?.start() // we paused => play now + if (pausedBecauseOfTransientAudiofocusLoss) playerWrapper?.start() // we paused => play now else setVolume(1.0f, 1.0f) // we ducked => raise audio level back pausedBecauseOfTransientAudiofocusLoss = false @@ -606,13 +596,13 @@ class LocalPSMP(context: Context, callback: PSMPCallback) : PlaybackServiceMedia // we're relying on the position stored in the Playable object for post-playback processing val position = getPosition() - if (position >= 0) media?.setPosition(position) + if (position >= 0) playable?.setPosition(position) - mediaPlayer?.reset() + playerWrapper?.reset() abandonAudioFocus() - val currentMedia = media + val currentMedia = playable var nextMedia: Playable? = null if (shouldContinue) { @@ -624,7 +614,7 @@ class LocalPSMP(context: Context, callback: PSMPCallback) : PlaybackServiceMedia callback.onPlaybackEnded(nextMedia.getMediaType(), false) // setting media to null signals to playMediaObject() that // we're taking care of post-playback processing - media = null + playable = null playMediaObject(nextMedia, false, !nextMedia.localFileAvailable(), isPlaying, isPlaying) } } @@ -635,12 +625,9 @@ class LocalPSMP(context: Context, callback: PSMPCallback) : PlaybackServiceMedia stop() } val hasNext = nextMedia != null - - callback.onPostPlayback(currentMedia!!, hasEnded, wasSkipped, hasNext) - } - isPlaying -> { - callback.onPlaybackPause(currentMedia, currentMedia!!.getPosition()) + callback.onPostPlayback(currentMedia, hasEnded, wasSkipped, hasNext) } + isPlaying -> callback.onPlaybackPause(currentMedia, currentMedia!!.getPosition()) } } @@ -652,20 +639,16 @@ class LocalPSMP(context: Context, callback: PSMPCallback) : PlaybackServiceMedia */ private fun stop() { releaseWifiLockIfNecessary() - - if (playerStatus == PlayerStatus.INDETERMINATE) { - setPlayerStatus(PlayerStatus.STOPPED, null) - } else { - Log.d(TAG, "Ignored call to stop: Current player state is: $playerStatus") - } + if (playerStatus == PlayerStatus.INDETERMINATE) setPlayerStatus(PlayerStatus.STOPPED, null) + else Log.d(TAG, "Ignored call to stop: Current player state is: $playerStatus") } override fun shouldLockWifi(): Boolean { - return stream + return isStreaming } private fun setMediaPlayerListeners(mp: ExoPlayerWrapper?) { - if (mp == null || media == null) return + if (mp == null || playable == null) return mp.setOnCompletionListener(Runnable { endPlayback(hasEnded = true, wasSkipped = false, shouldContinue = true, toStoppedState = true) }) mp.setOnSeekCompleteListener(Runnable { this.genericSeekCompleteListener() }) @@ -682,11 +665,11 @@ class LocalPSMP(context: Context, callback: PSMPCallback) : PlaybackServiceMedia } private fun clearMediaPlayerListeners() { - if (mediaPlayer == null) return - mediaPlayer!!.setOnCompletionListener {} - mediaPlayer!!.setOnSeekCompleteListener {} - mediaPlayer!!.setOnBufferingUpdateListener { } - mediaPlayer!!.setOnErrorListener { } + if (playerWrapper == null) return + playerWrapper!!.setOnCompletionListener {} + playerWrapper!!.setOnSeekCompleteListener {} + playerWrapper!!.setOnBufferingUpdateListener { } + playerWrapper!!.setOnErrorListener { } } private fun genericSeekCompleteListener() { @@ -694,9 +677,9 @@ class LocalPSMP(context: Context, callback: PSMPCallback) : PlaybackServiceMedia seekLatch?.countDown() if (playerStatus == PlayerStatus.PLAYING) { - if (media != null) callback.onPlaybackStart(media!!, getPosition()) + if (playable != null) callback.onPlaybackStart(playable!!, getPosition()) } - if (playerStatus == PlayerStatus.SEEKING && statusBeforeSeeking != null) setPlayerStatus(statusBeforeSeeking!!, media, getPosition()) + if (playerStatus == PlayerStatus.SEEKING && statusBeforeSeeking != null) setPlayerStatus(statusBeforeSeeking!!, playable, getPosition()) } override fun isCasting(): Boolean { diff --git a/app/src/main/java/ac/mdiq/podcini/playback/service/PlaybackService.kt b/app/src/main/java/ac/mdiq/podcini/playback/service/PlaybackService.kt index c4fe091c..5cae6733 100644 --- a/app/src/main/java/ac/mdiq/podcini/playback/service/PlaybackService.kt +++ b/app/src/main/java/ac/mdiq/podcini/playback/service/PlaybackService.kt @@ -124,13 +124,9 @@ class PlaybackService : MediaSessionService() { private val notificationCustomButtons = NotificationCustomButton.entries.map { command -> command.commandButton } private lateinit var taskManager: PlaybackServiceTaskManager -// private lateinit var stateManager: PlaybackServiceStateManager -// private lateinit var notificationBuilder: PlaybackServiceNotificationBuilder private lateinit var castStateListener: CastStateListener private var autoSkippedFeedMediaId: String? = null -// private var clickCount = 0 -// private val clickHandler = Handler(Looper.getMainLooper()) private var isSpeedForward = false private var normalSpeed = 1.0f @@ -160,11 +156,6 @@ class PlaybackService : MediaSessionService() { Log.d(TAG, "Service created.") isRunning = true -// this.startForeground() - -// stateManager = PlaybackServiceStateManager(this) -// notificationBuilder = PlaybackServiceNotificationBuilder(this) - if (Build.VERSION.SDK_INT >= VERSION_CODES.TIRAMISU) { registerReceiver(autoStateUpdated, IntentFilter("com.google.android.gms.car.media.STATUS"), RECEIVER_NOT_EXPORTED) registerReceiver(shutdownReceiver, IntentFilter(PlaybackServiceInterface.ACTION_SHUTDOWN_PLAYBACK_SERVICE), RECEIVER_NOT_EXPORTED) @@ -236,26 +227,6 @@ class PlaybackService : MediaSessionService() { super.onDestroy() Log.d(TAG, "Service is about to be destroyed") -// if (notificationBuilder.playerStatus == PlayerStatus.PLAYING || notificationBuilder.playerStatus == PlayerStatus.FALLBACK) { -// notificationBuilder.playerStatus = PlayerStatus.STOPPED -// val notificationManager = NotificationManagerCompat.from(this) -// if (Build.VERSION.SDK_INT >= 33 && ActivityCompat.checkSelfPermission(this, -// Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { -// // TODO: Consider calling -// // ActivityCompat#requestPermissions -//// requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS) -// // here to request the missing permissions, and then overriding -// // public void onRequestPermissionsResult(int requestCode, String[] permissions, -// // int[] grantResults) -// // to handle the case where the user grants the permission. See the documentation -// // for ActivityCompat#requestPermissions for more details. -// Log.e(TAG, "onDestroy: require POST_NOTIFICATIONS permission") -// Toast.makeText(applicationContext, R.string.notification_permission_text, Toast.LENGTH_LONG).show() -// return -// } -// notificationManager.notify(R.id.notification_playing, notificationBuilder.build()) -// } -// stateManager.stopForeground(!isPersistNotify) isRunning = false currentMediaType = MediaType.UNKNOWN castStateListener.destroy() @@ -279,6 +250,10 @@ class PlaybackService : MediaSessionService() { EventBus.getDefault().unregister(this) } + fun isServiceReady(): Boolean { + return mediaSession?.player?.playbackState != STATE_IDLE + } + private inner class MyCallback : MediaSession.Callback { override fun onConnect(session: MediaSession, controller: MediaSession.ControllerInfo): MediaSession.ConnectionResult { Log.d(TAG, "in onConnect") @@ -305,13 +280,6 @@ class PlaybackService : MediaSessionService() { // .setAvailableSessionCommands(sessionCommands.build()) // .build() - val connectionResult = super.onConnect(session, controller) - val defaultPlayerCommands = connectionResult.availablePlayerCommands - Log.d(TAG, defaultPlayerCommands.toString()) -// for (command in defaultPlayerCommands.toString()) { -// Log.d(TAG, command.toString()) -// } - // val availableSessionCommands = connectionResult.availableSessionCommands.buildUpon() /* Registering custom player command buttons for player notification. */ @@ -509,23 +477,17 @@ class PlaybackService : MediaSessionService() { super.onStartCommand(intent, flags, startId) Log.d(TAG, "OnStartCommand called") -// stateManager.startForeground(R.id.notification_playing, notificationBuilder.build()) -// val notificationManager = NotificationManagerCompat.from(this) -// notificationManager.cancel(R.id.notification_streaming_confirmation) - val keycode = intent?.getIntExtra(MediaButtonReceiver.EXTRA_KEYCODE, -1) ?: -1 val customAction = intent?.getStringExtra(MediaButtonReceiver.EXTRA_CUSTOM_ACTION) val hardwareButton = intent?.getBooleanExtra(MediaButtonReceiver.EXTRA_HARDWAREBUTTON, false) ?: false val playable = intent?.getParcelableExtra(PlaybackServiceInterface.EXTRA_PLAYABLE) if (keycode == -1 && playable == null && customAction == null) { Log.e(TAG, "PlaybackService was started with no arguments") -// stateManager.stopService() return START_NOT_STICKY } if ((flags and START_FLAG_REDELIVERY) != 0) { Log.d(TAG, "onStartCommand is a redelivered intent, calling stopForeground now.") -// stateManager.stopForeground(true) } else { when { keycode != -1 -> { @@ -537,14 +499,9 @@ class PlaybackService : MediaSessionService() { Log.d(TAG, "Received media button event") notificationButton = true } - val handled = handleKeycode(keycode, notificationButton) -// if (!handled && !stateManager.hasReceivedValidStartCommand()) { -// stateManager.stopService() -// return START_NOT_STICKY -// } +// val handled = handleKeycode(keycode, notificationButton) } playable != null -> { -// stateManager.validStartCommandWasReceived() val allowStreamThisTime = intent.getBooleanExtra(PlaybackServiceInterface.EXTRA_ALLOW_STREAM_THIS_TIME, false) val allowStreamAlways = intent.getBooleanExtra(PlaybackServiceInterface.EXTRA_ALLOW_STREAM_ALWAYS, false) sendNotificationBroadcast(PlaybackServiceInterface.NOTIFICATION_TYPE_RELOAD, 0) @@ -552,7 +509,6 @@ class PlaybackService : MediaSessionService() { Observable.fromCallable { if (playable is FeedMedia) return@fromCallable DBReader.getFeedMedia(playable.id) else return@fromCallable playable - } .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) @@ -561,7 +517,6 @@ class PlaybackService : MediaSessionService() { { error: Throwable -> Log.d(TAG, "Playable was not found. Stopping service.") error.printStackTrace() -// stateManager.stopService() }) return START_NOT_STICKY } @@ -601,56 +556,37 @@ class PlaybackService : MediaSessionService() { return } - val intentAllowThisTime = Intent(originalIntent) - intentAllowThisTime.setAction(PlaybackServiceInterface.EXTRA_ALLOW_STREAM_THIS_TIME) - intentAllowThisTime.putExtra(PlaybackServiceInterface.EXTRA_ALLOW_STREAM_THIS_TIME, true) - val pendingIntentAllowThisTime = if (Build.VERSION.SDK_INT >= VERSION_CODES.O) { - PendingIntent.getForegroundService(this, R.id.pending_intent_allow_stream_this_time, intentAllowThisTime, - PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) - } else { - PendingIntent.getService(this, R.id.pending_intent_allow_stream_this_time, intentAllowThisTime, - PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) - } +// val intentAllowThisTime = Intent(originalIntent) +// intentAllowThisTime.setAction(PlaybackServiceInterface.EXTRA_ALLOW_STREAM_THIS_TIME) +// intentAllowThisTime.putExtra(PlaybackServiceInterface.EXTRA_ALLOW_STREAM_THIS_TIME, true) +// val pendingIntentAllowThisTime = if (Build.VERSION.SDK_INT >= VERSION_CODES.O) +// PendingIntent.getForegroundService(this, R.id.pending_intent_allow_stream_this_time, intentAllowThisTime, +// PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) +// else PendingIntent.getService(this, R.id.pending_intent_allow_stream_this_time, intentAllowThisTime, +// PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) - val intentAlwaysAllow = Intent(intentAllowThisTime) - intentAlwaysAllow.setAction(PlaybackServiceInterface.EXTRA_ALLOW_STREAM_ALWAYS) - intentAlwaysAllow.putExtra(PlaybackServiceInterface.EXTRA_ALLOW_STREAM_ALWAYS, true) - val pendingIntentAlwaysAllow = if (Build.VERSION.SDK_INT >= VERSION_CODES.O) { - PendingIntent.getForegroundService(this, R.id.pending_intent_allow_stream_always, intentAlwaysAllow, - PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) - } else { - PendingIntent.getService(this, R.id.pending_intent_allow_stream_always, intentAlwaysAllow, - PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) - } +// val intentAlwaysAllow = Intent(intentAllowThisTime) +// intentAlwaysAllow.setAction(PlaybackServiceInterface.EXTRA_ALLOW_STREAM_ALWAYS) +// intentAlwaysAllow.putExtra(PlaybackServiceInterface.EXTRA_ALLOW_STREAM_ALWAYS, true) +// val pendingIntentAlwaysAllow = if (Build.VERSION.SDK_INT >= VERSION_CODES.O) +// PendingIntent.getForegroundService(this, R.id.pending_intent_allow_stream_always, intentAlwaysAllow, +// PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) +// else PendingIntent.getService(this, R.id.pending_intent_allow_stream_always, intentAlwaysAllow, +// PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) - val builder = NotificationCompat.Builder(this, - NotificationUtils.CHANNEL_ID_USER_ACTION) - .setSmallIcon(R.drawable.ic_notification_stream) - .setContentTitle(getString(R.string.confirm_mobile_streaming_notification_title)) - .setContentText(getString(R.string.confirm_mobile_streaming_notification_message)) - .setStyle(NotificationCompat.BigTextStyle() - .bigText(getString(R.string.confirm_mobile_streaming_notification_message))) - .setPriority(NotificationCompat.PRIORITY_DEFAULT) - .setContentIntent(pendingIntentAllowThisTime) - .addAction(R.drawable.ic_notification_stream, getString(R.string.confirm_mobile_streaming_button_once), pendingIntentAllowThisTime) - .addAction(R.drawable.ic_notification_stream, getString(R.string.confirm_mobile_streaming_button_always), pendingIntentAlwaysAllow) - .setAutoCancel(true) -// val notificationManager = NotificationManagerCompat.from(this) - if (Build.VERSION.SDK_INT >= 33 && ActivityCompat.checkSelfPermission(this, - Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { - // TODO: Consider calling - // ActivityCompat#requestPermissions -// requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS) - // here to request the missing permissions, and then overriding - // public void onRequestPermissionsResult(int requestCode, String[] permissions, - // int[] grantResults) - // to handle the case where the user grants the permission. See the documentation - // for ActivityCompat#requestPermissions for more details. - Log.e(TAG, "displayStreamingNotAllowedNotification: require POST_NOTIFICATIONS permission") - Toast.makeText(applicationContext, R.string.notification_permission_text, Toast.LENGTH_LONG).show() - return - } -// notificationManager.notify(R.id.notification_streaming_confirmation, builder.build()) + +// val builder = NotificationCompat.Builder(this, +// NotificationUtils.CHANNEL_ID_USER_ACTION) +// .setSmallIcon(R.drawable.ic_notification_stream) +// .setContentTitle(getString(R.string.confirm_mobile_streaming_notification_title)) +// .setContentText(getString(R.string.confirm_mobile_streaming_notification_message)) +// .setStyle(NotificationCompat.BigTextStyle() +// .bigText(getString(R.string.confirm_mobile_streaming_notification_message))) +// .setPriority(NotificationCompat.PRIORITY_DEFAULT) +// .setContentIntent(pendingIntentAllowThisTime) +// .addAction(R.drawable.ic_notification_stream, getString(R.string.confirm_mobile_streaming_button_once), pendingIntentAllowThisTime) +// .addAction(R.drawable.ic_notification_stream, getString(R.string.confirm_mobile_streaming_button_always), pendingIntentAlwaysAllow) +// .setAutoCancel(true) } /** @@ -734,10 +670,7 @@ class PlaybackService : MediaSessionService() { return false } KeyEvent.KEYCODE_MEDIA_STOP -> { - if (this.status == PlayerStatus.FALLBACK || status == PlayerStatus.PLAYING) { - mediaPlayer?.pause(true, true) - } -// stateManager.stopForeground(true) // gets rid of persistent notification + if (this.status == PlayerStatus.FALLBACK || status == PlayerStatus.PLAYING) mediaPlayer?.pause(true, true) return true } else -> { @@ -763,7 +696,6 @@ class PlaybackService : MediaSessionService() { { error: Throwable -> Log.d(TAG, "Playable was not loaded from preferences. Stopping service.") error.printStackTrace() -// stateManager.stopService() }) } @@ -773,9 +705,8 @@ class PlaybackService : MediaSessionService() { val localFeed = URLUtil.isContentUrl(playable.getStreamUrl()) val stream = !playable.localFileAvailable() || localFeed if (stream && !localFeed && !isStreamingAllowed && !allowStreamThisTime) { - displayStreamingNotAllowedNotification(PlaybackServiceStarter(this, playable).intent) +// displayStreamingNotAllowedNotification(PlaybackServiceStarter(this, playable).intent) writeNoMediaPlaying() -// stateManager.stopService() return } @@ -784,8 +715,6 @@ class PlaybackService : MediaSessionService() { } mediaPlayer?.playMediaObject(playable, stream, true, true) -// stateManager.validStartCommandWasReceived() -// stateManager.startForeground(R.id.notification_playing, notificationBuilder.build()) recreateMediaSessionIfNeeded() updateNotificationAndMediaSession(playable) addPlayableToQueue(playable) @@ -804,7 +733,6 @@ class PlaybackService : MediaSessionService() { mediaPlayer?.pause(true, false) mediaPlayer?.resetVideoSurface() updateNotificationAndMediaSession(playable) -// stateManager.stopForeground(!isPersistNotify) } private val taskManagerCallback: PSTMCallback = object : PSTMCallback { @@ -840,9 +768,6 @@ class PlaybackService : MediaSessionService() { } PlayerStatus.PAUSED -> { updateNotificationAndMediaSession(newInfo.playable) - if (!isCasting) { -// stateManager.stopForeground(!isPersistNotify) - } cancelPositionObserver() if (mediaPlayer != null) writePlayerStatus(mediaPlayer!!.playerStatus) } @@ -853,8 +778,6 @@ class PlaybackService : MediaSessionService() { recreateMediaSessionIfNeeded() updateNotificationAndMediaSession(newInfo.playable) setupPositionObserver() -// stateManager.validStartCommandWasReceived() -// stateManager.startForeground(R.id.notification_playing, notificationBuilder.build()) // set sleep timer if auto-enabled var autoEnableByTime = true val fromSetting = autoEnableFrom() @@ -872,10 +795,7 @@ class PlaybackService : MediaSessionService() { } loadQueueForMediaSession() } - PlayerStatus.ERROR -> { - writeNoMediaPlaying() -// stateManager.stopService() - } + PlayerStatus.ERROR -> writeNoMediaPlaying() else -> {} } } @@ -889,10 +809,8 @@ class PlaybackService : MediaSessionService() { taskManager.requestWidgetUpdate() } - - override fun shouldStop() { -// stateManager.stopForeground(!isPersistNotify) - } + // TODO: not used + override fun shouldStop() {} override fun onMediaChanged(reloadUI: Boolean) { Log.d(TAG, "reloadUI callback reached") @@ -900,7 +818,7 @@ class PlaybackService : MediaSessionService() { updateNotificationAndMediaSession(this@PlaybackService.playable) } - override fun onPostPlayback(media: Playable, ended: Boolean, skipped: Boolean, playingNext: Boolean) { + override fun onPostPlayback(media: Playable?, ended: Boolean, skipped: Boolean, playingNext: Boolean) { this@PlaybackService.onPostPlayback(media, ended, skipped, playingNext) } @@ -947,7 +865,6 @@ class PlaybackService : MediaSessionService() { fun playerError(event: PlayerErrorEvent?) { if (mediaPlayer?.playerStatus == PlayerStatus.PLAYING || mediaPlayer?.playerStatus == PlayerStatus.FALLBACK) mediaPlayer!!.pause(true, false) -// stateManager.stopService() } @Subscribe(threadMode = ThreadMode.MAIN) @@ -1012,9 +929,8 @@ class PlaybackService : MediaSessionService() { } if (!nextItem.media!!.localFileAvailable() && !isStreamingAllowed && isFollowQueue && nextItem.feed != null && !nextItem.feed!!.isLocalFeed) { - displayStreamingNotAllowedNotification(PlaybackServiceStarter(this, nextItem.media!!).intent) +// displayStreamingNotAllowedNotification(PlaybackServiceStarter(this, nextItem.media!!).intent) writeNoMediaPlaying() -// stateManager.stopService() return null } return nextItem.media @@ -1029,10 +945,6 @@ class PlaybackService : MediaSessionService() { if (stopPlaying) { taskManager.cancelPositionSaver() cancelPositionObserver() -// if (!isCasting) { -// stateManager.stopForeground(true) -// stateManager.stopService() -// } } if (mediaType == null) { sendNotificationBroadcast(PlaybackServiceInterface.NOTIFICATION_TYPE_PLAYBACK_END, 0) @@ -1228,59 +1140,32 @@ class PlaybackService : MediaSessionService() { } private fun updateNotificationAndMediaSession(p: Playable?) { - setupNotification(p) +// setupNotification(p) updateMediaSessionMetadata(p) } private fun updateMediaSessionMetadata(p: Playable?) { if (p == null || mediaSession == null) return - val builder = MediaMetadataCompat.Builder() - builder.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, p.getFeedTitle()) - builder.putString(MediaMetadataCompat.METADATA_KEY_TITLE, p.getEpisodeTitle()) - builder.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, p.getFeedTitle()) - builder.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, p.getDuration().toLong()) - builder.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, p.getEpisodeTitle()) - builder.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, p.getFeedTitle()) + // TODO: what's this? +// val builder = MediaMetadataCompat.Builder() +// builder.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, p.getFeedTitle()) +// builder.putString(MediaMetadataCompat.METADATA_KEY_TITLE, p.getEpisodeTitle()) +// builder.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, p.getFeedTitle()) +// builder.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, p.getDuration().toLong()) +// builder.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, p.getEpisodeTitle()) +// builder.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, p.getFeedTitle()) + // TODO: what's this? +// mediaSession!!.setSessionActivity(PendingIntent.getActivity(this, R.id.pending_intent_player_activity, +// getPlayerActivityIntent(this), FLAG_IMMUTABLE)) -// if (notificationBuilder.isIconCached) { -// builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ART, notificationBuilder.cachedIcon) -// } else { -// var iconUri = p.getImageLocation() -// // Don't use embedded cover etc, which Android can't load -// if (p is FeedMedia) { -// val m = p -// if (m.item != null) { -// val item = m.item!! -// when { -// item.imageUrl != null -> { -// iconUri = item.imageUrl -// } -// item.feed != null -> { -// iconUri = item.feed!!.imageUrl -// } -// } -// } -// } -// if (!iconUri.isNullOrEmpty()) { -// builder.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON_URI, iconUri) -// } -// } - -// if (stateManager.hasReceivedValidStartCommand()) { -// mediaSession!!.setSessionActivity(PendingIntent.getActivity(this, R.id.pending_intent_player_activity, -// getPlayerActivityIntent(this), PendingIntent.FLAG_UPDATE_CURRENT -// or (if (Build.VERSION.SDK_INT >= 31) PendingIntent.FLAG_MUTABLE else 0))) - mediaSession!!.setSessionActivity(PendingIntent.getActivity(this, R.id.pending_intent_player_activity, - getPlayerActivityIntent(this), FLAG_IMMUTABLE)) -// try { -// mediaSession!!.setMetadata(builder.build()) -// } catch (e: OutOfMemoryError) { -// Log.e(TAG, "Setting media session metadata", e) -// builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ART, null) -// mediaSession!!.setMetadata(builder.build()) -// } +// try { +// mediaSession!!.setMetadata(builder.build()) +// } catch (e: OutOfMemoryError) { +// Log.e(TAG, "Setting media session metadata", e) +// builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ART, null) +// mediaSession!!.setMetadata(builder.build()) // } } @@ -1292,6 +1177,7 @@ class PlaybackService : MediaSessionService() { /** * Prepares notification and starts the service in the foreground. */ + // TODO: not needed? @Synchronized private fun setupNotification(playable: Playable?) { Log.d(TAG, "setupNotification") @@ -1299,46 +1185,8 @@ class PlaybackService : MediaSessionService() { if (playable == null || mediaPlayer == null) { Log.d(TAG, "setupNotification: playable=$playable mediaPlayer=$mediaPlayer") -// if (!stateManager.hasReceivedValidStartCommand()) { -// stateManager.stopService() -// } return } - - val playerStatus = mediaPlayer!!.playerStatus -// notificationBuilder.setPlayable(playable) -// if (mediaSession != null) notificationBuilder.setMediaSessionToken(mediaSession!!.getSessionCompatToken()) -// notificationBuilder.playerStatus = playerStatus -// notificationBuilder.updatePosition(currentPosition, currentPlaybackSpeed) - -// val notificationManager = NotificationManagerCompat.from(this) - if (Build.VERSION.SDK_INT >= 33 && ActivityCompat.checkSelfPermission(this, - Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { - // TODO: Consider calling - // ActivityCompat#requestPermissions -// requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS) - // here to request the missing permissions, and then overriding - // public void onRequestPermissionsResult(int requestCode, String[] permissions, - // int[] grantResults) - // to handle the case where the user grants the permission. See the documentation - // for ActivityCompat#requestPermissions for more details. - Log.e(TAG, "setupNotification: require POST_NOTIFICATIONS permission") - Toast.makeText(applicationContext, R.string.notification_permission_text, Toast.LENGTH_LONG).show() - return - } -// notificationManager.notify(R.id.notification_playing, notificationBuilder.build()) - -// if (!notificationBuilder.isIconCached) { -// playableIconLoaderThread = Thread { -// Log.d(TAG, "Loading notification icon") -// notificationBuilder.loadIcon() -// if (!Thread.currentThread().isInterrupted) { -// notificationManager.notify(R.id.notification_playing, notificationBuilder.build()) -// updateMediaSessionMetadata(playable) -// } -// } -// playableIconLoaderThread?.start() -// } } /** @@ -1485,10 +1333,7 @@ class PlaybackService : MediaSessionService() { } if (transientPause) { transientPause = false - if (Build.VERSION.SDK_INT >= 31) { -// stateManager.stopService() - return - } + if (Build.VERSION.SDK_INT >= 31) return when { !bluetooth && isUnpauseOnHeadsetReconnect -> mediaPlayer?.resume() bluetooth && isUnpauseOnBluetoothReconnect -> { @@ -1503,10 +1348,8 @@ class PlaybackService : MediaSessionService() { private val shutdownReceiver: BroadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { - if (TextUtils.equals(intent.action, PlaybackServiceInterface.ACTION_SHUTDOWN_PLAYBACK_SERVICE)) { + if (TextUtils.equals(intent.action, PlaybackServiceInterface.ACTION_SHUTDOWN_PLAYBACK_SERVICE)) EventBus.getDefault().post(PlaybackServiceEvent(PlaybackServiceEvent.Action.SERVICE_SHUT_DOWN)) -// stateManager.stopService() - } } } @@ -1520,7 +1363,6 @@ class PlaybackService : MediaSessionService() { @Subscribe(threadMode = ThreadMode.MAIN) @Suppress("unused") fun speedPresetChanged(event: SpeedPresetChangedEvent) { -// TODO: speed val item = (playable as? FeedMedia)?.item ?: currentitem // if (playable is FeedMedia) { if (item?.feed?.id == event.feedId) { @@ -1715,12 +1557,6 @@ class PlaybackService : MediaSessionService() { .subscribe { Log.d(TAG, "setupPositionObserver currentPosition: $currentPosition, currentPlaybackSpeed: $currentPlaybackSpeed") EventBus.getDefault().post(PlaybackPositionEvent(currentPosition, duration)) -// TODO: why set SDK_INT < 29 - if (Build.VERSION.SDK_INT < 29) { -// notificationBuilder.updatePosition(currentPosition, currentPlaybackSpeed) -// val notificationManager = getSystemService(NOTIFICATION_SERVICE) as? NotificationManager -// notificationManager?.notify(R.id.notification_playing, notificationBuilder.build()) - } skipEndingIfNecessary() } } @@ -1737,15 +1573,9 @@ class PlaybackService : MediaSessionService() { } } -// private val sessionCallback: MediaSession.Callback = object : MediaSession.Callback { -// private val TAG = "MediaSessionCompat" -//// TODO: not used now with media3 -// } - companion object { private const val TAG = "PlaybackService" -// TODO: need to experiment this value private const val POSITION_EVENT_INTERVAL = 5L const val ACTION_PLAYER_STATUS_CHANGED: String = "action.ac.mdiq.podcini.service.playerStatusChanged" diff --git a/app/src/main/java/ac/mdiq/podcini/playback/service/PlaybackServiceNotificationBuilder.kt b/app/src/main/java/ac/mdiq/podcini/playback/service/PlaybackServiceNotificationBuilder.kt deleted file mode 100644 index d52bc1cd..00000000 --- a/app/src/main/java/ac/mdiq/podcini/playback/service/PlaybackServiceNotificationBuilder.kt +++ /dev/null @@ -1,222 +0,0 @@ -package ac.mdiq.podcini.playback.service - -import ac.mdiq.podcini.R -import android.app.Notification -import android.app.PendingIntent -import android.content.Context -import android.content.Intent -import android.graphics.Bitmap -import android.graphics.Canvas -import android.graphics.drawable.BitmapDrawable -import android.graphics.drawable.VectorDrawable -import android.os.Build -import android.support.v4.media.session.MediaSessionCompat -import android.util.Log -import android.view.KeyEvent -import androidx.appcompat.content.res.AppCompatResources -import androidx.core.app.NotificationCompat -import androidx.media3.common.util.UnstableApi -import com.bumptech.glide.Glide -import com.bumptech.glide.request.RequestOptions -import ac.mdiq.podcini.feed.util.ImageResourceUtils -import ac.mdiq.podcini.receiver.MediaButtonReceiver -import ac.mdiq.podcini.util.TimeSpeedConverter -import ac.mdiq.podcini.ui.utils.NotificationUtils -import ac.mdiq.podcini.storage.model.playback.Playable -import ac.mdiq.podcini.playback.base.PlayerStatus -import ac.mdiq.podcini.preferences.UserPreferences -import ac.mdiq.podcini.util.Converter -import org.apache.commons.lang3.ArrayUtils - -// TODO: not needed with media3 -@UnstableApi -class PlaybackServiceNotificationBuilder(private val context: Context) { - private var playable: Playable? = null - private var mediaSessionToken: MediaSessionCompat.Token? = null - @JvmField - var playerStatus: PlayerStatus? = null - var cachedIcon: Bitmap? = null - private set - private var position: String? = null - - fun setPlayable(playable: Playable) { - if (playable !== this.playable) clearCache() - - this.playable = playable - } - - private fun clearCache() { - this.cachedIcon = null - this.position = null - } - - fun updatePosition(position: Int, speed: Float) { - val converter = TimeSpeedConverter(speed) - this.position = Converter.getDurationStringLong(converter.convert(position)) - } - - val isIconCached: Boolean - get() = cachedIcon != null - - fun loadIcon() { - val iconSize = (128 * context.resources.displayMetrics.density).toInt() - val options = RequestOptions().centerCrop() - try { - val imgLoc = playable?.getImageLocation() - val imgLoc1 = ImageResourceUtils.getFallbackImageLocation(playable!!) - Log.d(TAG, "loadIcon imgLoc $imgLoc $imgLoc1") - cachedIcon = Glide.with(context) - .asBitmap() - .load(imgLoc) - .error(Glide.with(context) - .asBitmap() - .load(imgLoc1) - .apply(options) - .submit(iconSize, iconSize) - .get()) - .apply(options) - .submit(iconSize, iconSize) - .get() - } catch (ignore: InterruptedException) { - Log.e(TAG, "Media icon loader was interrupted") - } catch (tr: Throwable) { - Log.e(TAG, "Error loading the media icon for the notification", tr) - } - } - - private val defaultIcon: Bitmap? - get() { - if (Companion.defaultIcon == null) Companion.defaultIcon = getBitmap(context, R.mipmap.ic_launcher) - return Companion.defaultIcon - } - - fun build(): Notification { - val notification = NotificationCompat.Builder(context, NotificationUtils.CHANNEL_ID_PLAYING) - - if (playable != null) { - notification.setContentTitle(playable!!.getFeedTitle()) - notification.setContentText(playable!!.getEpisodeTitle()) - addActions(notification, mediaSessionToken, playerStatus) - - if (cachedIcon != null) notification.setLargeIcon(cachedIcon) - else notification.setLargeIcon(this.defaultIcon) - - if (Build.VERSION.SDK_INT < 29) notification.setSubText(position) - } else { - notification.setContentTitle(context.getString(R.string.app_name)) - notification.setContentText("Loading. If this does not go away, play any episode and contact us.") - } - - notification.setContentIntent(playerActivityPendingIntent) - notification.setWhen(0) - notification.setSmallIcon(R.drawable.ic_notification) - notification.setOngoing(false) - notification.setOnlyAlertOnce(true) - notification.setShowWhen(false) - notification.setPriority(UserPreferences.notifyPriority) - notification.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) - notification.setColor(NotificationCompat.COLOR_DEFAULT) - return notification.build() - } - - private val playerActivityPendingIntent: PendingIntent - get() = PendingIntent.getActivity(context, R.id.pending_intent_player_activity, PlaybackService.getPlayerActivityIntent(context), - PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) - - private fun addActions(notification: NotificationCompat.Builder, mediaSessionToken: MediaSessionCompat.Token?, playerStatus: PlayerStatus?) { - val compactActionList = ArrayList() - - var numActions = 0 // we start and 0 and then increment by 1 for each call to addAction - - val rewindButtonPendingIntent = getPendingIntentForMediaAction(KeyEvent.KEYCODE_MEDIA_REWIND, numActions) - notification.addAction(R.drawable.ic_notification_fast_rewind, context.getString(R.string.rewind_label), rewindButtonPendingIntent) - compactActionList.add(numActions) - numActions++ - - if (playerStatus == PlayerStatus.PLAYING) { - val pauseButtonPendingIntent = getPendingIntentForMediaAction(KeyEvent.KEYCODE_MEDIA_PAUSE, numActions) - //pause action - notification.addAction(R.drawable.ic_notification_pause, context.getString(R.string.pause_label), pauseButtonPendingIntent) - } else { - val playButtonPendingIntent = getPendingIntentForMediaAction(KeyEvent.KEYCODE_MEDIA_PLAY, numActions) - //play action - notification.addAction(R.drawable.ic_notification_play, context.getString(R.string.play_label), playButtonPendingIntent) - } - compactActionList.add(numActions++) - - // ff follows play, then we have skip (if it's present) - val ffButtonPendingIntent = getPendingIntentForMediaAction(KeyEvent.KEYCODE_MEDIA_FAST_FORWARD, numActions) - notification.addAction(R.drawable.ic_notification_fast_forward, context.getString(R.string.fast_forward_label), ffButtonPendingIntent) - compactActionList.add(numActions) - numActions++ - - if (UserPreferences.showNextChapterOnFullNotification() && playable?.getChapters() != null) { - val nextChapterPendingIntent = getPendingIntentForCustomMediaAction(PlaybackService.CUSTOM_ACTION_NEXT_CHAPTER, numActions) - notification.addAction(R.drawable.ic_notification_next_chapter, context.getString(R.string.next_chapter), nextChapterPendingIntent) - numActions++ - } - - if (UserPreferences.showSkipOnFullNotification()) { - val skipButtonPendingIntent = getPendingIntentForMediaAction(KeyEvent.KEYCODE_MEDIA_NEXT, numActions) - notification.addAction(R.drawable.ic_notification_skip, context.getString(R.string.skip_episode_label), skipButtonPendingIntent) - numActions++ - } - - val stopButtonPendingIntent = getPendingIntentForMediaAction(KeyEvent.KEYCODE_MEDIA_STOP, numActions) - notification - .setStyle(androidx.media.app.NotificationCompat.MediaStyle() - .setMediaSession(mediaSessionToken) - .setShowActionsInCompactView(*ArrayUtils.toPrimitive(compactActionList.toTypedArray())) - .setShowCancelButton(true) - .setCancelButtonIntent(stopButtonPendingIntent)) - } - - private fun getPendingIntentForMediaAction(keycodeValue: Int, requestCode: Int): PendingIntent { - val intent = Intent(context, PlaybackService::class.java) - intent.setAction("MediaCode$keycodeValue") - intent.putExtra(MediaButtonReceiver.EXTRA_KEYCODE, keycodeValue) - - return if (Build.VERSION.SDK_INT >= 26) { - PendingIntent.getForegroundService(context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) - } else { - PendingIntent.getService(context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) - } - } - - private fun getPendingIntentForCustomMediaAction(action: String, requestCode: Int): PendingIntent { - val intent = Intent(context, PlaybackService::class.java) - intent.setAction("MediaAction$action") - intent.putExtra(MediaButtonReceiver.EXTRA_CUSTOM_ACTION, action) - - return if (Build.VERSION.SDK_INT >= 26) { - PendingIntent.getForegroundService(context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) - } else { - PendingIntent.getService(context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) - } - } - - fun setMediaSessionToken(mediaSessionToken: MediaSessionCompat.Token?) { - this.mediaSessionToken = mediaSessionToken - } - - companion object { - private const val TAG = "PlaybackSrvNotification" - private var defaultIcon: Bitmap? = null - - private fun getBitmap(vectorDrawable: VectorDrawable): Bitmap { - val bitmap = Bitmap.createBitmap(vectorDrawable.intrinsicWidth, vectorDrawable.intrinsicHeight, Bitmap.Config.ARGB_8888) - val canvas = Canvas(bitmap) - vectorDrawable.setBounds(0, 0, canvas.width, canvas.height) - vectorDrawable.draw(canvas) - return bitmap - } - - private fun getBitmap(context: Context, drawableId: Int): Bitmap? { - return when (val drawable = AppCompatResources.getDrawable(context, drawableId)) { - is BitmapDrawable -> drawable.bitmap - is VectorDrawable -> getBitmap(drawable) - else -> null - } - } - } -} diff --git a/app/src/main/java/ac/mdiq/podcini/playback/service/PlaybackServiceStateManager.kt b/app/src/main/java/ac/mdiq/podcini/playback/service/PlaybackServiceStateManager.kt deleted file mode 100644 index af4a0f40..00000000 --- a/app/src/main/java/ac/mdiq/podcini/playback/service/PlaybackServiceStateManager.kt +++ /dev/null @@ -1,58 +0,0 @@ -package ac.mdiq.podcini.playback.service - -import android.app.Notification -import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK -import android.os.Build -import android.util.Log -import androidx.core.app.ServiceCompat -import kotlin.concurrent.Volatile - -// TODO: not needed with media3 -internal class PlaybackServiceStateManager(private val playbackService: PlaybackService) { - @Volatile - private var isInForeground = false - - @Volatile - private var hasReceivedValidStartCommand = false - - fun startForeground(notificationId: Int, notification: Notification) { - Log.d(TAG, "startForeground") - if (Build.VERSION.SDK_INT >= 29) { - playbackService.startForeground(notificationId, notification, FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK) - } else { - playbackService.startForeground(notificationId, notification) - } - isInForeground = true - } - - fun stopService() { - Log.d(TAG, "stopService") - stopForeground(true) - playbackService.stopSelf() - hasReceivedValidStartCommand = false - } - - fun stopForeground(removeNotification: Boolean) { - Log.d(TAG, "stopForeground") - if (isInForeground) { - if (removeNotification) { - ServiceCompat.stopForeground(playbackService, ServiceCompat.STOP_FOREGROUND_REMOVE) - } else { - ServiceCompat.stopForeground(playbackService, ServiceCompat.STOP_FOREGROUND_DETACH) - } - } - isInForeground = false - } - - fun hasReceivedValidStartCommand(): Boolean { - return hasReceivedValidStartCommand - } - - fun validStartCommandWasReceived() { - this.hasReceivedValidStartCommand = true - } - - companion object { - private const val TAG = "PlaybackSrvState" - } -} diff --git a/app/src/main/java/ac/mdiq/podcini/playback/service/PlaybackServiceTaskManager.kt b/app/src/main/java/ac/mdiq/podcini/playback/service/PlaybackServiceTaskManager.kt index c4b11eb6..60f63417 100644 --- a/app/src/main/java/ac/mdiq/podcini/playback/service/PlaybackServiceTaskManager.kt +++ b/app/src/main/java/ac/mdiq/podcini/playback/service/PlaybackServiceTaskManager.kt @@ -68,9 +68,7 @@ class PlaybackServiceTaskManager(private val context: Context, private val callb positionSaverFuture = schedExecutor.scheduleWithFixedDelay(positionSaver, POSITION_SAVER_WAITING_INTERVAL.toLong(), POSITION_SAVER_WAITING_INTERVAL.toLong(), TimeUnit.MILLISECONDS) Log.d(TAG, "Started PositionSaver") - } else { - Log.d(TAG, "Call to startPositionSaver was ignored.") - } + } else Log.d(TAG, "Call to startPositionSaver was ignored.") } @get:Synchronized @@ -102,9 +100,7 @@ class PlaybackServiceTaskManager(private val context: Context, private val callb widgetUpdaterFuture = schedExecutor.scheduleWithFixedDelay(widgetUpdater, WIDGET_UPDATER_NOTIFICATION_INTERVAL.toLong(), WIDGET_UPDATER_NOTIFICATION_INTERVAL.toLong(), TimeUnit.MILLISECONDS) Log.d(TAG, "Started WidgetUpdater") - } else { - Log.d(TAG, "Call to startWidgetUpdater was ignored.") - } + } else Log.d(TAG, "Call to startWidgetUpdater was ignored.") } /** @@ -243,9 +239,7 @@ class PlaybackServiceTaskManager(private val context: Context, private val callb // Run on ui thread even if called from schedExecutor val handler = Handler(Looper.getMainLooper()) return Runnable { handler.post(runnable) } - } else { - return runnable - } + } else return runnable } /** @@ -287,10 +281,9 @@ class PlaybackServiceTaskManager(private val context: Context, private val callb } if (timeLeft <= 0) { Log.d(TAG, "Sleep timer expired") - if (shakeListener != null) { - shakeListener!!.pause() - shakeListener = null - } + shakeListener?.pause() + shakeListener = null + hasVibrated = false } } @@ -303,10 +296,8 @@ class PlaybackServiceTaskManager(private val context: Context, private val callb fun restart() { EventBus.getDefault().post(SleepTimerUpdatedEvent.cancelled()) setSleepTimer(waitingTime) - if (shakeListener != null) { - shakeListener!!.pause() - shakeListener = null - } + shakeListener?.pause() + shakeListener = null } fun cancel() { diff --git a/app/src/main/java/ac/mdiq/podcini/playback/service/PlaybackVolumeUpdater.kt b/app/src/main/java/ac/mdiq/podcini/playback/service/PlaybackVolumeUpdater.kt index d5c2c24c..61667c81 100644 --- a/app/src/main/java/ac/mdiq/podcini/playback/service/PlaybackVolumeUpdater.kt +++ b/app/src/main/java/ac/mdiq/podcini/playback/service/PlaybackVolumeUpdater.kt @@ -6,8 +6,7 @@ import ac.mdiq.podcini.playback.base.PlaybackServiceMediaPlayer import ac.mdiq.podcini.playback.base.PlayerStatus internal class PlaybackVolumeUpdater { - fun updateVolumeIfNecessary(mediaPlayer: PlaybackServiceMediaPlayer, feedId: Long, - volumeAdaptionSetting: VolumeAdaptionSetting) { + fun updateVolumeIfNecessary(mediaPlayer: PlaybackServiceMediaPlayer, feedId: Long, volumeAdaptionSetting: VolumeAdaptionSetting) { val playable = mediaPlayer.getPlayable() if (playable is FeedMedia) updateFeedMediaVolumeIfNecessary(mediaPlayer, feedId, volumeAdaptionSetting, playable) diff --git a/app/src/main/java/ac/mdiq/podcini/playback/service/QuickSettingsTileService.kt b/app/src/main/java/ac/mdiq/podcini/playback/service/QuickSettingsTileService.kt index 55805172..6ddf4569 100644 --- a/app/src/main/java/ac/mdiq/podcini/playback/service/QuickSettingsTileService.kt +++ b/app/src/main/java/ac/mdiq/podcini/playback/service/QuickSettingsTileService.kt @@ -43,9 +43,8 @@ class QuickSettingsTileService : TileService() { fun updateTile() { val qsTile = qsTile - if (qsTile == null) { - Log.d(TAG, "Ignored call to update QS tile: getQsTile() returned null.") - } else { + if (qsTile == null) Log.d(TAG, "Ignored call to update QS tile: getQsTile() returned null.") + else { val isPlaying = (PlaybackService.isRunning && PlaybackPreferences.currentPlayerStatus == PlaybackPreferences.PLAYER_STATUS_PLAYING) qsTile.state = if (isPlaying) Tile.STATE_ACTIVE else Tile.STATE_INACTIVE qsTile.updateTile() diff --git a/app/src/main/java/ac/mdiq/podcini/playback/service/ShakeListener.kt b/app/src/main/java/ac/mdiq/podcini/playback/service/ShakeListener.kt index 8f2c10d1..45686e5a 100644 --- a/app/src/main/java/ac/mdiq/podcini/playback/service/ShakeListener.kt +++ b/app/src/main/java/ac/mdiq/podcini/playback/service/ShakeListener.kt @@ -31,10 +31,8 @@ internal class ShakeListener(private val mContext: Context, private val mSleepTi } fun pause() { - if (mSensorMgr != null) { - mSensorMgr!!.unregisterListener(this) - mSensorMgr = null - } + mSensorMgr?.unregisterListener(this) + mSensorMgr = null } override fun onSensorChanged(event: SensorEvent) { @@ -49,8 +47,7 @@ internal class ShakeListener(private val mContext: Context, private val mSleepTi } } - override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) { - } + override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {} companion object { private val TAG: String = ShakeListener::class.java.simpleName diff --git a/app/src/main/java/ac/mdiq/podcini/preferences/MaterialListPreference.kt b/app/src/main/java/ac/mdiq/podcini/preferences/MaterialListPreference.kt index e1bdba55..b20ed3ca 100644 --- a/app/src/main/java/ac/mdiq/podcini/preferences/MaterialListPreference.kt +++ b/app/src/main/java/ac/mdiq/podcini/preferences/MaterialListPreference.kt @@ -20,17 +20,13 @@ class MaterialListPreference : ListPreference { val values = entryValues var selected = -1 for (i in values.indices) { - if (values[i].toString() == value) { - selected = i - } + if (values[i].toString() == value) selected = i } builder.setSingleChoiceItems(entries, selected) { dialog: DialogInterface, which: Int -> dialog.dismiss() if (which >= 0 && entryValues != null) { val value = entryValues[which].toString() - if (callChangeListener(value)) { - setValue(value) - } + if (callChangeListener(value)) setValue(value) } } builder.show() diff --git a/app/src/main/java/ac/mdiq/podcini/preferences/MaterialMultiSelectListPreference.kt b/app/src/main/java/ac/mdiq/podcini/preferences/MaterialMultiSelectListPreference.kt index 765aa3f7..393dbd86 100644 --- a/app/src/main/java/ac/mdiq/podcini/preferences/MaterialMultiSelectListPreference.kt +++ b/app/src/main/java/ac/mdiq/podcini/preferences/MaterialMultiSelectListPreference.kt @@ -22,14 +22,11 @@ class MaterialMultiSelectListPreference : MultiSelectListPreference { for (i in values.indices) { selected[i] = getValues().contains(values[i].toString()) } - builder.setMultiChoiceItems(entries, selected - ) { dialog: DialogInterface?, which: Int, isChecked: Boolean -> selected[which] = isChecked } + builder.setMultiChoiceItems(entries, selected) { dialog: DialogInterface?, which: Int, isChecked: Boolean -> selected[which] = isChecked } builder.setPositiveButton("OK") { dialog: DialogInterface?, which: Int -> val selectedValues: MutableSet = HashSet() for (i in values.indices) { - if (selected[i]) { - selectedValues.add(entryValues[i].toString()) - } + if (selected[i]) selectedValues.add(entryValues[i].toString()) } setValues(selectedValues) } diff --git a/app/src/main/java/ac/mdiq/podcini/preferences/PlaybackPreferences.kt b/app/src/main/java/ac/mdiq/podcini/preferences/PlaybackPreferences.kt index e6d1a7de..3703996e 100644 --- a/app/src/main/java/ac/mdiq/podcini/preferences/PlaybackPreferences.kt +++ b/app/src/main/java/ac/mdiq/podcini/preferences/PlaybackPreferences.kt @@ -22,9 +22,7 @@ import org.greenrobot.eventbus.EventBus */ class PlaybackPreferences private constructor() : OnSharedPreferenceChangeListener { override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String?) { - if (PREF_CURRENT_PLAYER_STATUS == key) { - EventBus.getDefault().post(PlayerStatusEvent()) - } + if (PREF_CURRENT_PLAYER_STATUS == key) EventBus.getDefault().post(PlayerStatusEvent()) } companion object { @@ -222,9 +220,7 @@ class PlaybackPreferences private constructor() : OnSharedPreferenceChangeListen private fun createFeedMediaInstance(pref: SharedPreferences): Playable? { var result: Playable? = null val mediaId = pref.getLong(FeedMedia.PREF_MEDIA_ID, -1) - if (mediaId != -1L) { - result = DBReader.getFeedMedia(mediaId) - } + if (mediaId != -1L) result = DBReader.getFeedMedia(mediaId) return result } } diff --git a/app/src/main/java/ac/mdiq/podcini/preferences/PreferenceUpgrader.kt b/app/src/main/java/ac/mdiq/podcini/preferences/PreferenceUpgrader.kt index 3db9f475..a039a638 100644 --- a/app/src/main/java/ac/mdiq/podcini/preferences/PreferenceUpgrader.kt +++ b/app/src/main/java/ac/mdiq/podcini/preferences/PreferenceUpgrader.kt @@ -48,10 +48,9 @@ object PreferenceUpgrader { } private fun upgrade(oldVersion: Int, context: Context) { - if (oldVersion == -1) { - //New installation - return - } + //New installation + if (oldVersion == -1) return + if (oldVersion < 1070196) { // migrate episode cleanup value (unit changed from days to hours) val oldValueInDays = episodeCleanupValue @@ -60,14 +59,10 @@ object PreferenceUpgrader { } // else 0 or special negative values, no change needed } if (oldVersion < 1070197) { - if (prefs.getBoolean("prefMobileUpdate", false)) { - prefs.edit().putString("prefMobileUpdateAllowed", "everything").apply() - } + if (prefs.getBoolean("prefMobileUpdate", false)) prefs.edit().putString("prefMobileUpdateAllowed", "everything").apply() } if (oldVersion < 1070300) { - if (prefs.getBoolean("prefEnableAutoDownloadOnMobile", false)) { - isAllowMobileAutoDownload = true - } + if (prefs.getBoolean("prefEnableAutoDownloadOnMobile", false)) isAllowMobileAutoDownload = true when (prefs.getString("prefMobileUpdateAllowed", "images")) { "everything" -> { isAllowMobileFeedRefresh = true @@ -80,9 +75,7 @@ object PreferenceUpgrader { } if (oldVersion < 1070400) { val theme = theme - if (theme == UserPreferences.ThemePreference.LIGHT) { - prefs.edit().putString(UserPreferences.PREF_THEME, "system").apply() - } + if (theme == UserPreferences.ThemePreference.LIGHT) prefs.edit().putString(UserPreferences.PREF_THEME, "system").apply() isQueueLocked = false isStreamOverDownload = false @@ -96,48 +89,37 @@ object PreferenceUpgrader { } if (oldVersion < 2010300) { // Migrate hardware button preferences - if (prefs.getBoolean("prefHardwareForwardButtonSkips", false)) { - prefs.edit().putString(UserPreferences.PREF_HARDWARE_FORWARD_BUTTON, - KeyEvent.KEYCODE_MEDIA_NEXT.toString()).apply() - } - if (prefs.getBoolean("prefHardwarePreviousButtonRestarts", false)) { - prefs.edit().putString(UserPreferences.PREF_HARDWARE_PREVIOUS_BUTTON, - KeyEvent.KEYCODE_MEDIA_PREVIOUS.toString()).apply() - } + if (prefs.getBoolean("prefHardwareForwardButtonSkips", false)) + prefs.edit().putString(UserPreferences.PREF_HARDWARE_FORWARD_BUTTON, KeyEvent.KEYCODE_MEDIA_NEXT.toString()).apply() + + if (prefs.getBoolean("prefHardwarePreviousButtonRestarts", false)) + prefs.edit().putString(UserPreferences.PREF_HARDWARE_PREVIOUS_BUTTON, KeyEvent.KEYCODE_MEDIA_PREVIOUS.toString()).apply() } if (oldVersion < 2040000) { val swipePrefs = context.getSharedPreferences(SwipeActions.PREF_NAME, Context.MODE_PRIVATE) swipePrefs.edit().putString(SwipeActions.KEY_PREFIX_SWIPEACTIONS + QueueFragment.TAG, SwipeAction.REMOVE_FROM_QUEUE + "," + SwipeAction.REMOVE_FROM_QUEUE).apply() } - if (oldVersion < 2050000) { - prefs.edit().putBoolean(UserPreferences.PREF_PAUSE_PLAYBACK_FOR_FOCUS_LOSS, true).apply() - } + if (oldVersion < 2050000) prefs.edit().putBoolean(UserPreferences.PREF_PAUSE_PLAYBACK_FOR_FOCUS_LOSS, true).apply() + if (oldVersion < 2080000) { // Migrate drawer feed counter setting to reflect removal of // "unplayed and in inbox" (0), by changing it to "unplayed" (2) val feedCounterSetting = prefs.getString(UserPreferences.PREF_DRAWER_FEED_COUNTER, "2") - if (feedCounterSetting == "0") { - prefs.edit().putString(UserPreferences.PREF_DRAWER_FEED_COUNTER, "2").apply() - } + if (feedCounterSetting == "0") prefs.edit().putString(UserPreferences.PREF_DRAWER_FEED_COUNTER, "2").apply() - val sleepTimerPreferences = - context.getSharedPreferences(SleepTimerPreferences.PREF_NAME, Context.MODE_PRIVATE) + val sleepTimerPreferences = context.getSharedPreferences(SleepTimerPreferences.PREF_NAME, Context.MODE_PRIVATE) val timeUnits = arrayOf(TimeUnit.SECONDS, TimeUnit.MINUTES, TimeUnit.HOURS) val value = lastTimerValue()!!.toLong() val unit = timeUnits[sleepTimerPreferences.getInt("LastTimeUnit", 1)] setLastTimer(unit.toMinutes(value).toString()) - if (prefs.getString(UserPreferences.PREF_EPISODE_CACHE_SIZE, "20") - == context.getString(R.string.pref_episode_cache_unlimited)) { - prefs.edit().putString(UserPreferences.PREF_EPISODE_CACHE_SIZE, - "" + UserPreferences.EPISODE_CACHE_SIZE_UNLIMITED).apply() - } + if (prefs.getString(UserPreferences.PREF_EPISODE_CACHE_SIZE, "20") == context.getString(R.string.pref_episode_cache_unlimited)) + prefs.edit().putString(UserPreferences.PREF_EPISODE_CACHE_SIZE, "" + UserPreferences.EPISODE_CACHE_SIZE_UNLIMITED).apply() } if (oldVersion < 3000007) { - if (prefs.getString("prefBackButtonBehavior", "") == "drawer") { + if (prefs.getString("prefBackButtonBehavior", "") == "drawer") prefs.edit().putBoolean(UserPreferences.PREF_BACK_OPENS_DRAWER, true).apply() - } } if (oldVersion < 3010000) { if (prefs.getString(UserPreferences.PREF_THEME, "system") == "2") { @@ -147,27 +129,20 @@ object PreferenceUpgrader { .apply() } isAllowMobileSync = true - if (prefs.getString(UserPreferences.PREF_UPDATE_INTERVAL, ":")!! - .contains(":")) { // Unset or "time of day" + // Unset or "time of day" + if (prefs.getString(UserPreferences.PREF_UPDATE_INTERVAL, ":")!!.contains(":")) prefs.edit().putString(UserPreferences.PREF_UPDATE_INTERVAL, "12").apply() - } - } - if (oldVersion < 3020000) { - NotificationManagerCompat.from(context).deleteNotificationChannel("auto_download") + } + if (oldVersion < 3020000) NotificationManagerCompat.from(context).deleteNotificationChannel("auto_download") if (oldVersion < 3030000) { - val allEpisodesPreferences = - context.getSharedPreferences(AllEpisodesFragment.PREF_NAME, Context.MODE_PRIVATE) + val allEpisodesPreferences = context.getSharedPreferences(AllEpisodesFragment.PREF_NAME, Context.MODE_PRIVATE) val oldEpisodeSort = allEpisodesPreferences.getString(UserPreferences.PREF_SORT_ALL_EPISODES, "") - if (!StringUtils.isAllEmpty(oldEpisodeSort)) { - prefs.edit().putString(UserPreferences.PREF_SORT_ALL_EPISODES, oldEpisodeSort).apply() - } + if (!StringUtils.isAllEmpty(oldEpisodeSort)) prefs.edit().putString(UserPreferences.PREF_SORT_ALL_EPISODES, oldEpisodeSort).apply() val oldEpisodeFilter = allEpisodesPreferences.getString("filter", "") - if (!StringUtils.isAllEmpty(oldEpisodeFilter)) { - prefs.edit().putString(UserPreferences.PREF_FILTER_ALL_EPISODES, oldEpisodeFilter).apply() - } + if (!StringUtils.isAllEmpty(oldEpisodeFilter)) prefs.edit().putString(UserPreferences.PREF_FILTER_ALL_EPISODES, oldEpisodeFilter).apply() } } } diff --git a/app/src/main/java/ac/mdiq/podcini/preferences/SleepTimerPreferences.kt b/app/src/main/java/ac/mdiq/podcini/preferences/SleepTimerPreferences.kt index e0373f65..7d163dd5 100644 --- a/app/src/main/java/ac/mdiq/podcini/preferences/SleepTimerPreferences.kt +++ b/app/src/main/java/ac/mdiq/podcini/preferences/SleepTimerPreferences.kt @@ -103,14 +103,10 @@ object SleepTimerPreferences { @JvmStatic fun isInTimeRange(from: Int, to: Int, current: Int): Boolean { // Range covers one day - if (from < to) { - return from <= current && current < to - } + if (from < to) return from <= current && current < to // Range covers two days - if (from <= current) { - return true - } + if (from <= current) return true return current < to } diff --git a/app/src/main/java/ac/mdiq/podcini/preferences/ThemePreference.kt b/app/src/main/java/ac/mdiq/podcini/preferences/ThemePreference.kt index b6f9c3a2..9414de4c 100644 --- a/app/src/main/java/ac/mdiq/podcini/preferences/ThemePreference.kt +++ b/app/src/main/java/ac/mdiq/podcini/preferences/ThemePreference.kt @@ -34,9 +34,7 @@ class ThemePreference : Preference { card.setCardBackgroundColor(if (theme == activeTheme) surfaceColorActive else surfaceColor) card.setOnClickListener { UserPreferences.theme = theme - if (onPreferenceChangeListener != null) { - onPreferenceChangeListener!!.onPreferenceChange(this, UserPreferences.theme) - } + onPreferenceChangeListener?.onPreferenceChange(this, UserPreferences.theme) updateUi() } } diff --git a/app/src/main/java/ac/mdiq/podcini/preferences/ThemeSwitcher.kt b/app/src/main/java/ac/mdiq/podcini/preferences/ThemeSwitcher.kt index c7fa6273..2b5733f3 100644 --- a/app/src/main/java/ac/mdiq/podcini/preferences/ThemeSwitcher.kt +++ b/app/src/main/java/ac/mdiq/podcini/preferences/ThemeSwitcher.kt @@ -53,15 +53,9 @@ object ThemeSwitcher { var theme = UserPreferences.theme if (theme == UserPreferences.ThemePreference.SYSTEM) { val nightMode = context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK - theme = if (nightMode == Configuration.UI_MODE_NIGHT_YES) { - UserPreferences.ThemePreference.DARK - } else { - UserPreferences.ThemePreference.LIGHT - } - } - if (theme == UserPreferences.ThemePreference.DARK && UserPreferences.isBlackTheme) { - theme = UserPreferences.ThemePreference.BLACK + theme = if (nightMode == Configuration.UI_MODE_NIGHT_YES) UserPreferences.ThemePreference.DARK else UserPreferences.ThemePreference.LIGHT } + if (theme == UserPreferences.ThemePreference.DARK && UserPreferences.isBlackTheme) theme = UserPreferences.ThemePreference.BLACK return theme!! } } diff --git a/app/src/main/java/ac/mdiq/podcini/preferences/UsageStatistics.kt b/app/src/main/java/ac/mdiq/podcini/preferences/UsageStatistics.kt index 46cd1758..6f92cb25 100644 --- a/app/src/main/java/ac/mdiq/podcini/preferences/UsageStatistics.kt +++ b/app/src/main/java/ac/mdiq/podcini/preferences/UsageStatistics.kt @@ -40,8 +40,7 @@ object UsageStatistics { val movingAverage = prefs!!.getFloat(action.type, 0.5f) prefs!!.edit() .putInt(action.type + action.value, numExecutions + 1) - .putFloat(action.type, MOVING_AVERAGE_WEIGHT * movingAverage - + (1 - MOVING_AVERAGE_WEIGHT) * action.value) + .putFloat(action.type, MOVING_AVERAGE_WEIGHT * movingAverage + (1 - MOVING_AVERAGE_WEIGHT) * action.value) .apply() } diff --git a/app/src/main/java/ac/mdiq/podcini/preferences/UserPreferences.kt b/app/src/main/java/ac/mdiq/podcini/preferences/UserPreferences.kt index 1190e4f6..5549dc94 100644 --- a/app/src/main/java/ac/mdiq/podcini/preferences/UserPreferences.kt +++ b/app/src/main/java/ac/mdiq/podcini/preferences/UserPreferences.kt @@ -190,10 +190,8 @@ object UserPreferences { @JvmStatic var fullNotificationButtons: List? get() { - val buttons = TextUtils.split( - prefs.getString(PREF_FULL_NOTIFICATION_BUTTONS, - "$NOTIFICATION_BUTTON_SKIP,$NOTIFICATION_BUTTON_PLAYBACK_SPEED"), ",") - + val buttons = TextUtils.split(prefs.getString(PREF_FULL_NOTIFICATION_BUTTONS, + "$NOTIFICATION_BUTTON_SKIP,$NOTIFICATION_BUTTON_PLAYBACK_SPEED"), ",") val notificationButtons: MutableList = ArrayList() for (button in buttons) { notificationButtons.add(button.toInt()) @@ -287,11 +285,7 @@ object UserPreferences { * * @return NotificationCompat.PRIORITY_MAX or NotificationCompat.PRIORITY_DEFAULT */ - get() = if (prefs.getBoolean(PREF_EXPANDED_NOTIFICATION, false)) { - NotificationCompat.PRIORITY_MAX - } else { - NotificationCompat.PRIORITY_DEFAULT - } + get() = if (prefs.getBoolean(PREF_EXPANDED_NOTIFICATION, false)) NotificationCompat.PRIORITY_MAX else NotificationCompat.PRIORITY_DEFAULT @JvmStatic val isPersistNotify: Boolean @@ -326,9 +320,7 @@ object UserPreferences { } } set(location) { - prefs.edit() - .putString(PREF_ENQUEUE_LOCATION, location.name) - .apply() + prefs.edit().putString(PREF_ENQUEUE_LOCATION, location.name).apply() } @JvmStatic @@ -345,14 +337,11 @@ object UserPreferences { @JvmStatic val hardwareForwardButton: Int - get() = prefs.getString(PREF_HARDWARE_FORWARD_BUTTON, - KeyEvent.KEYCODE_MEDIA_FAST_FORWARD.toString())!!.toInt() + get() = prefs.getString(PREF_HARDWARE_FORWARD_BUTTON, KeyEvent.KEYCODE_MEDIA_FAST_FORWARD.toString())!!.toInt() @JvmStatic val hardwarePreviousButton: Int - get() = prefs.getString(PREF_HARDWARE_PREVIOUS_BUTTON, - KeyEvent.KEYCODE_MEDIA_REWIND.toString())!!.toInt() - + get() = prefs.getString(PREF_HARDWARE_PREVIOUS_BUTTON, KeyEvent.KEYCODE_MEDIA_REWIND.toString())!!.toInt() @JvmStatic @set:VisibleForTesting @@ -393,11 +382,7 @@ object UserPreferences { @JvmStatic fun getPlaybackSpeed(mediaType: MediaType): Float { - return if (mediaType == MediaType.VIDEO) { - videoPlaybackSpeed - } else { - audioPlaybackSpeed - } + return if (mediaType == MediaType.VIDEO) videoPlaybackSpeed else audioPlaybackSpeed } private val audioPlaybackSpeed: Float @@ -443,9 +428,7 @@ object UserPreferences { var isSkipSilence: Boolean get() = prefs.getBoolean(PREF_PLAYBACK_SKIP_SILENCE, false) set(skipSilence) { - prefs.edit() - .putBoolean(PREF_PLAYBACK_SKIP_SILENCE, skipSilence) - .apply() + prefs.edit().putBoolean(PREF_PLAYBACK_SKIP_SILENCE, skipSilence).apply() } @JvmStatic @@ -459,9 +442,7 @@ object UserPreferences { for (speed in speeds) { jsonArray.put(speedFormat.format(speed.toDouble())) } - prefs.edit() - .putString(PREF_PLAYBACK_SPEED_ARRAY, jsonArray.toString()) - .apply() + prefs.edit().putString(PREF_PLAYBACK_SPEED_ARRAY, jsonArray.toString()).apply() } @JvmStatic @@ -529,11 +510,9 @@ object UserPreferences { defaultValue.add("images") val getValueStringSet = prefs.getStringSet(PREF_MOBILE_UPDATE, defaultValue) val allowed: MutableSet = HashSet(getValueStringSet) - if (allow) { - allowed.add(type) - } else { - allowed.remove(type) - } + if (allow) allowed.add(type) + else allowed.remove(type) + prefs.edit().putStringSet(PREF_MOBILE_UPDATE, allowed).apply() } @@ -574,9 +553,7 @@ object UserPreferences { } } set(speed) { - prefs.edit() - .putString(PREF_SPEEDFORWRD_SPEED, speed.toString()) - .apply() + prefs.edit().putString(PREF_SPEEDFORWRD_SPEED, speed.toString()).apply() } @JvmStatic @@ -591,27 +568,21 @@ object UserPreferences { } } set(speed) { - prefs.edit() - .putString(PREF_FALLBACK_SPEED, speed.toString()) - .apply() + prefs.edit().putString(PREF_FALLBACK_SPEED, speed.toString()).apply() } @JvmStatic var fastForwardSecs: Int get() = prefs.getInt(PREF_FAST_FORWARD_SECS, 30) set(secs) { - prefs.edit() - .putInt(PREF_FAST_FORWARD_SECS, secs) - .apply() + prefs.edit().putInt(PREF_FAST_FORWARD_SECS, secs).apply() } @JvmStatic var rewindSecs: Int get() = prefs.getInt(PREF_REWIND_SECS, 10) set(secs) { - prefs.edit() - .putInt(PREF_REWIND_SECS, secs) - .apply() + prefs.edit().putInt(PREF_REWIND_SECS, secs).apply() } @JvmStatic @@ -634,26 +605,18 @@ object UserPreferences { set(config) { val editor = prefs.edit() editor.putString(PREF_PROXY_TYPE, config.type.name) - if (config.host.isNullOrEmpty()) { - editor.remove(PREF_PROXY_HOST) - } else { - editor.putString(PREF_PROXY_HOST, config.host) - } - if (config.port <= 0 || config.port > 65535) { - editor.remove(PREF_PROXY_PORT) - } else { - editor.putInt(PREF_PROXY_PORT, config.port) - } - if (config.username.isNullOrEmpty()) { - editor.remove(PREF_PROXY_USER) - } else { - editor.putString(PREF_PROXY_USER, config.username) - } - if (config.password.isNullOrEmpty()) { - editor.remove(PREF_PROXY_PASSWORD) - } else { - editor.putString(PREF_PROXY_PASSWORD, config.password) - } + if (config.host.isNullOrEmpty()) editor.remove(PREF_PROXY_HOST) + else editor.putString(PREF_PROXY_HOST, config.host) + + if (config.port <= 0 || config.port > 65535) editor.remove(PREF_PROXY_PORT) + else editor.putInt(PREF_PROXY_PORT, config.port) + + if (config.username.isNullOrEmpty()) editor.remove(PREF_PROXY_USER) + else editor.putString(PREF_PROXY_USER, config.username) + + if (config.password.isNullOrEmpty()) editor.remove(PREF_PROXY_PASSWORD) + else editor.putString(PREF_PROXY_PASSWORD, config.password) + editor.apply() } @@ -661,37 +624,28 @@ object UserPreferences { var isQueueLocked: Boolean get() = prefs.getBoolean(PREF_QUEUE_LOCKED, false) set(locked) { - prefs.edit() - .putBoolean(PREF_QUEUE_LOCKED, locked) - .apply() + prefs.edit().putBoolean(PREF_QUEUE_LOCKED, locked).apply() } @JvmStatic fun setPlaybackSpeed(speed: Float) { - prefs.edit() - .putString(PREF_PLAYBACK_SPEED, speed.toString()) - .apply() + prefs.edit().putString(PREF_PLAYBACK_SPEED, speed.toString()).apply() } @JvmStatic fun setVideoMode(mode: Int) { - prefs.edit() - .putString(PREF_VIDEO_MODE, mode.toString()) - .apply() + prefs.edit().putString(PREF_VIDEO_MODE, mode.toString()).apply() } @JvmStatic fun setAutodownloadSelectedNetworks(value: Array?) { - prefs.edit() - .putString(PREF_AUTODL_SELECTED_NETWORKS, TextUtils.join(",", value!!)) - .apply() + prefs.edit().putString(PREF_AUTODL_SELECTED_NETWORKS, TextUtils.join(",", value!!)).apply() } @JvmStatic fun gpodnetNotificationsEnabled(): Boolean { - if (Build.VERSION.SDK_INT >= 26) { - return true // System handles notification preferences - } + if (Build.VERSION.SDK_INT >= 26) return true // System handles notification preferences + return prefs.getBoolean(PREF_GPODNET_NOTIFICATIONS, true) } @@ -704,9 +658,7 @@ object UserPreferences { @JvmStatic fun setGpodnetNotificationsEnabled() { - prefs.edit() - .putBoolean(PREF_GPODNET_NOTIFICATIONS, true) - .apply() + prefs.edit().putBoolean(PREF_GPODNET_NOTIFICATIONS, true).apply() } private fun readPlaybackSpeedArray(valueFromPrefs: String?): List { @@ -729,12 +681,9 @@ object UserPreferences { @JvmStatic var episodeCleanupValue: Int - get() = prefs.getString(PREF_EPISODE_CLEANUP, "" + EPISODE_CLEANUP_NULL)!! - .toInt() + get() = prefs.getString(PREF_EPISODE_CLEANUP, "" + EPISODE_CLEANUP_NULL)!!.toInt() set(episodeCleanupValue) { - prefs.edit() - .putString(PREF_EPISODE_CLEANUP, episodeCleanupValue.toString()) - .apply() + prefs.edit().putString(PREF_EPISODE_CLEANUP, episodeCleanupValue.toString()).apply() } /** @@ -760,9 +709,8 @@ object UserPreferences { } private fun getTypeDir(baseDirPath: String?, type: String?): File? { - if (baseDirPath == null) { - return null - } + if (baseDirPath == null) return null + val baseDir = File(baseDirPath) val typeDir = if (type == null) baseDir else File(baseDir, type) if (!typeDir.exists()) { @@ -781,9 +729,7 @@ object UserPreferences { @JvmStatic fun setDataFolder(dir: String) { Log.d(TAG, "setDataFolder(dir: $dir)") - prefs.edit() - .putString(PREF_DATA_FOLDER, dir) - .apply() + prefs.edit().putString(PREF_DATA_FOLDER, dir).apply() } /** @@ -840,9 +786,7 @@ object UserPreferences { * @see .setQueueKeepSortedOrder */ set(keepSorted) { - prefs.edit() - .putBoolean(PREF_QUEUE_KEEP_SORTED, keepSorted) - .apply() + prefs.edit().putBoolean(PREF_QUEUE_KEEP_SORTED, keepSorted).apply() } @JvmStatic @@ -863,19 +807,14 @@ object UserPreferences { * @see .setQueueKeepSorted */ set(sortOrder) { - if (sortOrder == null) { - return - } - prefs.edit() - .putString(PREF_QUEUE_KEEP_SORTED_ORDER, sortOrder.name) - .apply() + if (sortOrder == null) return + prefs.edit().putString(PREF_QUEUE_KEEP_SORTED_ORDER, sortOrder.name).apply() } @JvmStatic val newEpisodesAction: NewEpisodesAction get() { - val str = prefs.getString(PREF_NEW_EPISODES_ACTION, - "" + NewEpisodesAction.GLOBAL.code) + val str = prefs.getString(PREF_NEW_EPISODES_ACTION, "" + NewEpisodesAction.GLOBAL.code) return NewEpisodesAction.fromCode(str!!.toInt()) } @@ -912,9 +851,7 @@ object UserPreferences { return SubscriptionsFilter(value) } set(value) { - prefs.edit() - .putString(PREF_FILTER_FEED, value.serialize()) - .apply() + prefs.edit().putString(PREF_FILTER_FEED, value.serialize()).apply() } @JvmStatic @@ -925,8 +862,7 @@ object UserPreferences { @JvmStatic var allEpisodesSortOrder: SortOrder? - get() = SortOrder.fromCodeString(prefs.getString(PREF_SORT_ALL_EPISODES, - "" + SortOrder.DATE_NEW_OLD.code)) + get() = SortOrder.fromCodeString(prefs.getString(PREF_SORT_ALL_EPISODES, "" + SortOrder.DATE_NEW_OLD.code)) set(s) { prefs.edit().putString(PREF_SORT_ALL_EPISODES, "" + s!!.code).apply() } diff --git a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/AutoDownloadPreferencesFragment.kt b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/AutoDownloadPreferencesFragment.kt index 5d744cfe..05b27d76 100644 --- a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/AutoDownloadPreferencesFragment.kt +++ b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/AutoDownloadPreferencesFragment.kt @@ -46,29 +46,23 @@ class AutoDownloadPreferencesFragment : PreferenceFragmentCompat() { private fun setupAutoDownloadScreen() { findPreference(UserPreferences.PREF_ENABLE_AUTODL)!!.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _: Preference?, newValue: Any? -> - if (newValue is Boolean) { - checkAutodownloadItemVisibility(newValue) - } + if (newValue is Boolean) checkAutodownloadItemVisibility(newValue) true } - if (Build.VERSION.SDK_INT >= 29) { - findPreference(UserPreferences.PREF_ENABLE_AUTODL_WIFI_FILTER)!!.isVisible = false - } + if (Build.VERSION.SDK_INT >= 29) findPreference(UserPreferences.PREF_ENABLE_AUTODL_WIFI_FILTER)!!.isVisible = false + findPreference(UserPreferences.PREF_ENABLE_AUTODL_WIFI_FILTER)?.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _: Preference?, newValue: Any? -> if (newValue is Boolean) { setSelectedNetworksEnabled(newValue) return@OnPreferenceChangeListener true - } else { - return@OnPreferenceChangeListener false - } + } else return@OnPreferenceChangeListener false } } private fun checkAutodownloadItemVisibility(autoDownload: Boolean) { findPreference(UserPreferences.PREF_EPISODE_CACHE_SIZE)!!.isEnabled = autoDownload - findPreference(UserPreferences.PREF_ENABLE_AUTODL_ON_BATTERY)!!.isEnabled = - autoDownload + findPreference(UserPreferences.PREF_ENABLE_AUTODL_ON_BATTERY)!!.isEnabled = autoDownload findPreference(UserPreferences.PREF_ENABLE_AUTODL_WIFI_FILTER)!!.isEnabled = autoDownload findPreference(UserPreferences.PREF_EPISODE_CLEANUP)!!.isEnabled = autoDownload setSelectedNetworksEnabled(autoDownload && isEnableAutodownloadWifiFilter) @@ -76,15 +70,12 @@ class AutoDownloadPreferencesFragment : PreferenceFragmentCompat() { @SuppressLint("MissingPermission") // getConfiguredNetworks needs location permission starting with API 29 private fun buildAutodownloadSelectedNetworksPreference() { - if (Build.VERSION.SDK_INT >= 29) { - return - } + if (Build.VERSION.SDK_INT >= 29) return val activity: Activity? = activity - if (selectedNetworks != null) { - clearAutodownloadSelectedNetworsPreference() - } + if (selectedNetworks != null) clearAutodownloadSelectedNetworsPreference() + // get configured networks val wifiservice = activity!!.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager val networks = wifiservice.configuredNetworks @@ -94,8 +85,7 @@ class AutoDownloadPreferencesFragment : PreferenceFragmentCompat() { return } networks.sortWith { x: WifiConfiguration, y: WifiConfiguration -> - blankIfNull(x.SSID).compareTo( - blankIfNull(y.SSID), ignoreCase = true) + blankIfNull(x.SSID).compareTo(blankIfNull(y.SSID), ignoreCase = true) } selectedNetworks = arrayOfNulls(networks.size) val prefValues = listOf(*autodownloadSelectedNetworks) @@ -103,29 +93,20 @@ class AutoDownloadPreferencesFragment : PreferenceFragmentCompat() { val clickListener = Preference.OnPreferenceClickListener { preference: Preference -> if (preference is CheckBoxPreference) { val key = preference.getKey() - val prefValuesList: MutableList = ArrayList( - listOf(*autodownloadSelectedNetworks) - ) - val newValue = preference - .isChecked + val prefValuesList: MutableList = ArrayList(listOf(*autodownloadSelectedNetworks)) + val newValue = preference.isChecked Log.d(TAG, "Selected network $key. New state: $newValue") val index = prefValuesList.indexOf(key) when { - index >= 0 && !newValue -> { - // remove network - prefValuesList.removeAt(index) - } - index < 0 && newValue -> { - prefValuesList.add(key) - } + // remove network + index >= 0 && !newValue -> prefValuesList.removeAt(index) + index < 0 && newValue -> prefValuesList.add(key) } setAutodownloadSelectedNetworks(prefValuesList.toTypedArray()) return@OnPreferenceClickListener true - } else { - return@OnPreferenceClickListener false - } + } else return@OnPreferenceClickListener false } // create preference for each known network. attach listener and set // value @@ -149,9 +130,7 @@ class AutoDownloadPreferencesFragment : PreferenceFragmentCompat() { val prefScreen = preferenceScreen for (network in selectedNetworks!!) { - if (network != null) { - prefScreen.removePreference(network) - } + if (network != null) prefScreen.removePreference(network) } } } @@ -160,26 +139,15 @@ class AutoDownloadPreferencesFragment : PreferenceFragmentCompat() { val res = requireActivity().resources val pref = findPreference(UserPreferences.PREF_EPISODE_CLEANUP) - val values = res.getStringArray( - R.array.episode_cleanup_values) + val values = res.getStringArray(R.array.episode_cleanup_values) val entries = arrayOfNulls(values.size) for (x in values.indices) { when (val v = values[x].toInt()) { - UserPreferences.EPISODE_CLEANUP_EXCEPT_FAVORITE -> { - entries[x] = res.getString(R.string.episode_cleanup_except_favorite_removal) - } - UserPreferences.EPISODE_CLEANUP_QUEUE -> { - entries[x] = res.getString(R.string.episode_cleanup_queue_removal) - } - UserPreferences.EPISODE_CLEANUP_NULL -> { - entries[x] = res.getString(R.string.episode_cleanup_never) - } - 0 -> { - entries[x] = res.getString(R.string.episode_cleanup_after_listening) - } - in 1..23 -> { - entries[x] = res.getQuantityString(R.plurals.episode_cleanup_hours_after_listening, v, v) - } + UserPreferences.EPISODE_CLEANUP_EXCEPT_FAVORITE -> entries[x] = res.getString(R.string.episode_cleanup_except_favorite_removal) + UserPreferences.EPISODE_CLEANUP_QUEUE -> entries[x] = res.getString(R.string.episode_cleanup_queue_removal) + UserPreferences.EPISODE_CLEANUP_NULL -> entries[x] = res.getString(R.string.episode_cleanup_never) + 0 -> entries[x] = res.getString(R.string.episode_cleanup_after_listening) + in 1..23 -> entries[x] = res.getQuantityString(R.plurals.episode_cleanup_hours_after_listening, v, v) else -> { val numDays = v / 24 // assume underlying value will be NOT fraction of days, e.g., 36 (hours) entries[x] = res.getQuantityString(R.plurals.episode_cleanup_days_after_listening, numDays, numDays) diff --git a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/DownloadsPreferencesFragment.kt b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/DownloadsPreferencesFragment.kt index 726762a9..16f262ed 100644 --- a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/DownloadsPreferencesFragment.kt +++ b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/DownloadsPreferencesFragment.kt @@ -32,14 +32,12 @@ class DownloadsPreferencesFragment : PreferenceFragmentCompat(), OnSharedPrefere override fun onStart() { super.onStart() (activity as PreferenceActivity).supportActionBar!!.setTitle(R.string.downloads_pref) - PreferenceManager.getDefaultSharedPreferences(requireContext()).registerOnSharedPreferenceChangeListener( - this) + PreferenceManager.getDefaultSharedPreferences(requireContext()).registerOnSharedPreferenceChangeListener(this) } override fun onStop() { super.onStop() - PreferenceManager.getDefaultSharedPreferences(requireContext()).unregisterOnSharedPreferenceChangeListener( - this) + PreferenceManager.getDefaultSharedPreferences(requireContext()).unregisterOnSharedPreferenceChangeListener(this) } override fun onResume() { @@ -48,48 +46,38 @@ class DownloadsPreferencesFragment : PreferenceFragmentCompat(), OnSharedPrefere } private fun setupNetworkScreen() { - findPreference(PREF_SCREEN_AUTODL)!!.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - (activity as PreferenceActivity).openScreen(R.xml.preferences_autodownload) - true - } + findPreference(PREF_SCREEN_AUTODL)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + (activity as PreferenceActivity).openScreen(R.xml.preferences_autodownload) + true + } // validate and set correct value: number of downloads between 1 and 50 (inclusive) - findPreference(PREF_PROXY)!!.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - val dialog = ProxyDialog(requireContext()) - dialog.show() - true - } - findPreference(PREF_CHOOSE_DATA_DIR)!!.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - ChooseDataFolderDialog.showDialog(requireContext()) { path: String? -> - setDataFolder(path!!) - setDataFolderText() - } - true - } - findPreference(PREF_AUTO_DELETE_LOCAL)!!.onPreferenceChangeListener = - Preference.OnPreferenceChangeListener { _: Preference?, newValue: Any -> - if (blockAutoDeleteLocal && newValue as Boolean) { - showAutoDeleteEnableDialog() - return@OnPreferenceChangeListener false - } else { - return@OnPreferenceChangeListener true - } + findPreference(PREF_PROXY)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + val dialog = ProxyDialog(requireContext()) + dialog.show() + true + } + findPreference(PREF_CHOOSE_DATA_DIR)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + ChooseDataFolderDialog.showDialog(requireContext()) { path: String? -> + setDataFolder(path!!) + setDataFolderText() } + true + } + findPreference(PREF_AUTO_DELETE_LOCAL)!!.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _: Preference?, newValue: Any -> + if (blockAutoDeleteLocal && newValue as Boolean) { + showAutoDeleteEnableDialog() + return@OnPreferenceChangeListener false + } else return@OnPreferenceChangeListener true + } } private fun setDataFolderText() { val f = getDataFolder(null) - if (f != null) { - findPreference(PREF_CHOOSE_DATA_DIR)!!.summary = f.absolutePath - } + if (f != null) findPreference(PREF_CHOOSE_DATA_DIR)!!.summary = f.absolutePath } override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String?) { - if (UserPreferences.PREF_UPDATE_INTERVAL == key) { - restartUpdateAlarm(requireContext(), true) - } + if (UserPreferences.PREF_UPDATE_INTERVAL == key) restartUpdateAlarm(requireContext(), true) } private fun showAutoDeleteEnableDialog() { diff --git a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/ImportExportPreferencesFragment.kt b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/ImportExportPreferencesFragment.kt index 7f7e4f5a..cbd2131a 100644 --- a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/ImportExportPreferencesFragment.kt +++ b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/ImportExportPreferencesFragment.kt @@ -57,8 +57,7 @@ class ImportExportPreferencesFragment : PreferenceFragmentCompat() { registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result: ActivityResult -> this.restoreDatabaseResult(result) } - private val backupDatabaseLauncher = registerForActivityResult(BackupDatabase() - ) { uri: Uri? -> this.backupDatabaseResult(uri) } + private val backupDatabaseLauncher = registerForActivityResult(BackupDatabase()) { uri: Uri? -> this.backupDatabaseResult(uri) } private val chooseOpmlImportPathLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? -> this.chooseOpmlImportPathResult(uri) } private var disposable: Disposable? = null @@ -79,9 +78,7 @@ class ImportExportPreferencesFragment : PreferenceFragmentCompat() { override fun onStop() { super.onStop() - if (disposable != null) { - disposable!!.dispose() - } + disposable?.dispose() } private fun dateStampFilename(fname: String): String { @@ -89,40 +86,34 @@ class ImportExportPreferencesFragment : PreferenceFragmentCompat() { } private fun setupStorageScreen() { - findPreference(PREF_OPML_EXPORT)!!.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - openExportPathPicker(Export.OPML, chooseOpmlExportPathLauncher, OpmlWriter()) - true - } - findPreference(PREF_HTML_EXPORT)!!.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - openExportPathPicker(Export.HTML, chooseHtmlExportPathLauncher, HtmlWriter()) - true - } - findPreference(PREF_OPML_IMPORT)!!.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - try { - chooseOpmlImportPathLauncher.launch("*/*") - } catch (e: ActivityNotFoundException) { - Log.e(TAG, "No activity found. Should never happen...") - } - true - } - findPreference(PREF_DATABASE_IMPORT)!!.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - importDatabase() - true - } - findPreference(PREF_DATABASE_EXPORT)!!.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - exportDatabase() - true - } - findPreference(PREF_FAVORITE_EXPORT)!!.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - openExportPathPicker(Export.FAVORITES, chooseFavoritesExportPathLauncher, FavoritesWriter()) - true + findPreference(PREF_OPML_EXPORT)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + openExportPathPicker(Export.OPML, chooseOpmlExportPathLauncher, OpmlWriter()) + true + } + findPreference(PREF_HTML_EXPORT)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + openExportPathPicker(Export.HTML, chooseHtmlExportPathLauncher, HtmlWriter()) + true + } + findPreference(PREF_OPML_IMPORT)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + try { + chooseOpmlImportPathLauncher.launch("*/*") + } catch (e: ActivityNotFoundException) { + Log.e(TAG, "No activity found. Should never happen...") } + true + } + findPreference(PREF_DATABASE_IMPORT)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + importDatabase() + true + } + findPreference(PREF_DATABASE_EXPORT)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + exportDatabase() + true + } + findPreference(PREF_FAVORITE_EXPORT)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + openExportPathPicker(Export.FAVORITES, chooseFavoritesExportPathLauncher, FavoritesWriter()) + true + } } private fun exportWithWriter(exportWriter: ExportWriter, uri: Uri?, exportType: Export) { @@ -133,8 +124,7 @@ class ImportExportPreferencesFragment : PreferenceFragmentCompat() { disposable = observable.subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe({ output: File? -> - val fileUri = FileProvider.getUriForFile(context!!.applicationContext, - context.getString(R.string.provider_authority), output!!) + val fileUri = FileProvider.getUriForFile(context!!.applicationContext, context.getString(R.string.provider_authority), output!!) showExportSuccessSnackbar(fileUri, exportType.contentType) }, { error: Throwable -> this.showExportErrorDialog(error) }, { progressDialog!!.dismiss() }) } else { @@ -143,8 +133,7 @@ class ImportExportPreferencesFragment : PreferenceFragmentCompat() { .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe({ output: DocumentFile? -> - showExportSuccessSnackbar(output?.uri, - exportType.contentType) + showExportSuccessSnackbar(output?.uri, exportType.contentType) }, { error: Throwable -> this.showExportErrorDialog(error) }, { progressDialog!!.dismiss() }) @@ -204,33 +193,25 @@ class ImportExportPreferencesFragment : PreferenceFragmentCompat() { } private fun chooseOpmlExportPathResult(result: ActivityResult) { - if (result.resultCode != Activity.RESULT_OK || result.data == null) { - return - } + if (result.resultCode != Activity.RESULT_OK || result.data == null) return val uri = result.data!!.data exportWithWriter(OpmlWriter(), uri, Export.OPML) } private fun chooseHtmlExportPathResult(result: ActivityResult) { - if (result.resultCode != Activity.RESULT_OK || result.data == null) { - return - } + if (result.resultCode != Activity.RESULT_OK || result.data == null) return val uri = result.data!!.data exportWithWriter(HtmlWriter(), uri, Export.HTML) } private fun chooseFavoritesExportPathResult(result: ActivityResult) { - if (result.resultCode != Activity.RESULT_OK || result.data == null) { - return - } + if (result.resultCode != Activity.RESULT_OK || result.data == null) return val uri = result.data!!.data exportWithWriter(FavoritesWriter(), uri, Export.FAVORITES) } private fun restoreDatabaseResult(result: ActivityResult) { - if (result.resultCode != Activity.RESULT_OK || result.data == null) { - return - } + if (result.resultCode != Activity.RESULT_OK || result.data == null) return val uri = result.data!!.data progressDialog!!.show() disposable = Completable.fromAction { DatabaseTransporter.importBackup(uri, requireContext()) } @@ -243,9 +224,7 @@ class ImportExportPreferencesFragment : PreferenceFragmentCompat() { } private fun backupDatabaseResult(uri: Uri?) { - if (uri == null) { - return - } + if (uri == null) return progressDialog!!.show() disposable = Completable.fromAction { DatabaseTransporter.exportToDocument(uri, requireContext()) } .subscribeOn(Schedulers.io()) @@ -257,9 +236,7 @@ class ImportExportPreferencesFragment : PreferenceFragmentCompat() { } private fun chooseOpmlImportPathResult(uri: Uri?) { - if (uri == null) { - return - } + if (uri == null) return val intent = Intent(context, OpmlImportActivity::class.java) intent.setData(uri) startActivity(intent) @@ -295,10 +272,7 @@ class ImportExportPreferencesFragment : PreferenceFragmentCompat() { } } - private enum class Export(val contentType: String, - val outputNameTemplate: String, - @field:StringRes val labelResId: Int - ) { + private enum class Export(val contentType: String, val outputNameTemplate: String, @field:StringRes val labelResId: Int) { OPML(CONTENT_TYPE_OPML, DEFAULT_OPML_OUTPUT_NAME, R.string.opml_export_label), HTML(CONTENT_TYPE_HTML, DEFAULT_HTML_OUTPUT_NAME, R.string.html_export_label), FAVORITES(CONTENT_TYPE_HTML, DEFAULT_FAVORITES_OUTPUT_NAME, R.string.favorites_export_label) diff --git a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/MainPreferencesFragment.kt b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/MainPreferencesFragment.kt index cf610e23..cf4eb30b 100644 --- a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/MainPreferencesFragment.kt +++ b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/MainPreferencesFragment.kt @@ -57,64 +57,53 @@ class MainPreferencesFragment : PreferenceFragmentCompat() { @SuppressLint("CommitTransaction") private fun setupMainScreen() { - findPreference(PREF_SCREEN_USER_INTERFACE)!!.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - (activity as PreferenceActivity).openScreen(R.xml.preferences_user_interface) - true - } - findPreference(PREF_SCREEN_PLAYBACK)!!.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - (activity as PreferenceActivity).openScreen(R.xml.preferences_playback) - true - } - findPreference(PREF_SCREEN_DOWNLOADS)!!.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - (activity as PreferenceActivity).openScreen(R.xml.preferences_downloads) - true - } - findPreference(PREF_SCREEN_SYNCHRONIZATION)!!.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - (activity as PreferenceActivity).openScreen(R.xml.preferences_synchronization) - true - } - findPreference(PREF_SCREEN_IMPORT_EXPORT)!!.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - (activity as PreferenceActivity).openScreen(R.xml.preferences_import_export) - true - } - findPreference(PREF_NOTIFICATION)!!.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - (activity as PreferenceActivity).openScreen(R.xml.preferences_notifications) - true - } - findPreference(PREF_ABOUT)!!.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - parentFragmentManager.beginTransaction() - .replace(R.id.settingsContainer, AboutFragment()) - .addToBackStack(getString(R.string.about_pref)) - .commit() - true - } - findPreference(PREF_DOCUMENTATION)!!.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - openInBrowser(requireContext(), "https://github.com/XilinJia/Podcini") - true - } - findPreference(PREF_VIEW_FORUM)!!.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - openInBrowser(requireContext(), "https://github.com/XilinJia/Podcini/discussions") - true - } - findPreference(PREF_CONTRIBUTE)!!.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - openInBrowser(requireContext(), "https://github.com/XilinJia/Podcini") - true - } - findPreference(PREF_SEND_BUG_REPORT)!!.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - startActivity(Intent(activity, BugReportActivity::class.java)) - true - } + findPreference(PREF_SCREEN_USER_INTERFACE)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + (activity as PreferenceActivity).openScreen(R.xml.preferences_user_interface) + true + } + findPreference(PREF_SCREEN_PLAYBACK)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + (activity as PreferenceActivity).openScreen(R.xml.preferences_playback) + true + } + findPreference(PREF_SCREEN_DOWNLOADS)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + (activity as PreferenceActivity).openScreen(R.xml.preferences_downloads) + true + } + findPreference(PREF_SCREEN_SYNCHRONIZATION)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + (activity as PreferenceActivity).openScreen(R.xml.preferences_synchronization) + true + } + findPreference(PREF_SCREEN_IMPORT_EXPORT)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + (activity as PreferenceActivity).openScreen(R.xml.preferences_import_export) + true + } + findPreference(PREF_NOTIFICATION)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + (activity as PreferenceActivity).openScreen(R.xml.preferences_notifications) + true + } + findPreference(PREF_ABOUT)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + parentFragmentManager.beginTransaction() + .replace(R.id.settingsContainer, AboutFragment()) + .addToBackStack(getString(R.string.about_pref)) + .commit() + true + } + findPreference(PREF_DOCUMENTATION)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + openInBrowser(requireContext(), "https://github.com/XilinJia/Podcini") + true + } + findPreference(PREF_VIEW_FORUM)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + openInBrowser(requireContext(), "https://github.com/XilinJia/Podcini/discussions") + true + } + findPreference(PREF_CONTRIBUTE)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + openInBrowser(requireContext(), "https://github.com/XilinJia/Podcini") + true + } + findPreference(PREF_SEND_BUG_REPORT)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + startActivity(Intent(activity, BugReportActivity::class.java)) + true + } } // private val localizedWebsiteLink: String @@ -143,24 +132,17 @@ class MainPreferencesFragment : PreferenceFragmentCompat() { config.setFragmentContainerViewId(R.id.settingsContainer) config.setBreadcrumbsEnabled(true) - config.index(R.xml.preferences_user_interface) - .addBreadcrumb(getTitleOfPage(R.xml.preferences_user_interface)) - config.index(R.xml.preferences_playback) - .addBreadcrumb(getTitleOfPage(R.xml.preferences_playback)) - config.index(R.xml.preferences_downloads) - .addBreadcrumb(getTitleOfPage(R.xml.preferences_downloads)) - config.index(R.xml.preferences_import_export) - .addBreadcrumb(getTitleOfPage(R.xml.preferences_import_export)) + config.index(R.xml.preferences_user_interface).addBreadcrumb(getTitleOfPage(R.xml.preferences_user_interface)) + config.index(R.xml.preferences_playback).addBreadcrumb(getTitleOfPage(R.xml.preferences_playback)) + config.index(R.xml.preferences_downloads).addBreadcrumb(getTitleOfPage(R.xml.preferences_downloads)) + config.index(R.xml.preferences_import_export).addBreadcrumb(getTitleOfPage(R.xml.preferences_import_export)) config.index(R.xml.preferences_autodownload) .addBreadcrumb(getTitleOfPage(R.xml.preferences_downloads)) .addBreadcrumb(R.string.automation) .addBreadcrumb(getTitleOfPage(R.xml.preferences_autodownload)) - config.index(R.xml.preferences_synchronization) - .addBreadcrumb(getTitleOfPage(R.xml.preferences_synchronization)) - config.index(R.xml.preferences_notifications) - .addBreadcrumb(getTitleOfPage(R.xml.preferences_notifications)) - config.index(R.xml.feed_settings) - .addBreadcrumb(getTitleOfPage(R.xml.feed_settings)) + config.index(R.xml.preferences_synchronization).addBreadcrumb(getTitleOfPage(R.xml.preferences_synchronization)) + config.index(R.xml.preferences_notifications).addBreadcrumb(getTitleOfPage(R.xml.preferences_notifications)) + config.index(R.xml.feed_settings).addBreadcrumb(getTitleOfPage(R.xml.feed_settings)) config.index(R.xml.preferences_swipe) .addBreadcrumb(getTitleOfPage(R.xml.preferences_user_interface)) .addBreadcrumb(getTitleOfPage(R.xml.preferences_swipe)) diff --git a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/PlaybackPreferencesFragment.kt b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/PlaybackPreferencesFragment.kt index 8122a21c..33250a73 100644 --- a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/PlaybackPreferencesFragment.kt +++ b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/PlaybackPreferencesFragment.kt @@ -34,45 +34,38 @@ class PlaybackPreferencesFragment : PreferenceFragmentCompat() { @OptIn(UnstableApi::class) private fun setupPlaybackScreen() { val activity: Activity? = activity - findPreference(PREF_PLAYBACK_SPEED_LAUNCHER)!!.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - VariableSpeedDialog.newInstance(booleanArrayOf(false, false, true),2)?.show(childFragmentManager, null) - true - } - findPreference(PREF_PLAYBACK_REWIND_DELTA_LAUNCHER)!!.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - SkipPreferenceDialog.showSkipPreference(requireContext(), SkipPreferenceDialog.SkipDirection.SKIP_REWIND, null) - true - } - findPreference(PREF_PLAYBACK_VIDEO_MODE_LAUNCHER)?.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - VideoModeDialog.showDialog(requireContext()) - true - } + findPreference(PREF_PLAYBACK_SPEED_LAUNCHER)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + VariableSpeedDialog.newInstance(booleanArrayOf(false, false, true),2)?.show(childFragmentManager, null) + true + } + findPreference(PREF_PLAYBACK_REWIND_DELTA_LAUNCHER)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + SkipPreferenceDialog.showSkipPreference(requireContext(), SkipPreferenceDialog.SkipDirection.SKIP_REWIND, null) + true + } + findPreference(PREF_PLAYBACK_VIDEO_MODE_LAUNCHER)?.onPreferenceClickListener = Preference.OnPreferenceClickListener { + VideoModeDialog.showDialog(requireContext()) + true + } - findPreference(PREF_PLAYBACK_SPEED_FORWARD_LAUNCHER)!!.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - EditForwardSpeedDialog(requireActivity()).show() - true - } - findPreference(PREF_PLAYBACK_FALLBACK_SPEED_LAUNCHER)!!.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - EditFallbackSpeedDialog(requireActivity()).show() - true - } - findPreference(PREF_PLAYBACK_FAST_FORWARD_DELTA_LAUNCHER)!!.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - SkipPreferenceDialog.showSkipPreference(requireContext(), SkipPreferenceDialog.SkipDirection.SKIP_FORWARD, null) - true - } - findPreference(PREF_PLAYBACK_PREFER_STREAMING)!!.onPreferenceChangeListener = - Preference.OnPreferenceChangeListener { _: Preference?, _: Any? -> - // Update all visible lists to reflect new streaming action button - EventBus.getDefault().post(UnreadItemsUpdateEvent()) - // User consciously decided whether to prefer the streaming button, disable suggestion to change that - doNotAskAgain(UsageStatistics.ACTION_STREAM) - true - } + findPreference(PREF_PLAYBACK_SPEED_FORWARD_LAUNCHER)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + EditForwardSpeedDialog(requireActivity()).show() + true + } + findPreference(PREF_PLAYBACK_FALLBACK_SPEED_LAUNCHER)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + EditFallbackSpeedDialog(requireActivity()).show() + true + } + findPreference(PREF_PLAYBACK_FAST_FORWARD_DELTA_LAUNCHER)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + SkipPreferenceDialog.showSkipPreference(requireContext(), SkipPreferenceDialog.SkipDirection.SKIP_FORWARD, null) + true + } + findPreference(PREF_PLAYBACK_PREFER_STREAMING)!!.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _: Preference?, _: Any? -> + // Update all visible lists to reflect new streaming action button + EventBus.getDefault().post(UnreadItemsUpdateEvent()) + // User consciously decided whether to prefer the streaming button, disable suggestion to change that + doNotAskAgain(UsageStatistics.ACTION_STREAM) + true + } if (Build.VERSION.SDK_INT >= 31) { findPreference(UserPreferences.PREF_UNPAUSE_ON_HEADSET_RECONNECT)!!.isVisible = false findPreference(UserPreferences.PREF_UNPAUSE_ON_BLUETOOTH_RECONNECT)!!.isVisible = false @@ -95,20 +88,16 @@ class PlaybackPreferencesFragment : PreferenceFragmentCompat() { val pref = requirePreference(UserPreferences.PREF_ENQUEUE_LOCATION) pref.summary = res.getString(R.string.pref_enqueue_location_sum, options[pref.value]) - pref.onPreferenceChangeListener = - Preference.OnPreferenceChangeListener { _: Preference?, newValue: Any? -> - if (newValue !is String) { - return@OnPreferenceChangeListener false - } - pref.summary = res.getString(R.string.pref_enqueue_location_sum, options[newValue]) - true - } + pref.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _: Preference?, newValue: Any? -> + if (newValue !is String) return@OnPreferenceChangeListener false + pref.summary = res.getString(R.string.pref_enqueue_location_sum, options[newValue]) + true + } } private fun requirePreference(key: CharSequence): T { // Possibly put it to a common method in abstract base class - val result = findPreference(key) - ?: throw IllegalArgumentException("Preference with key '$key' is not found") + val result = findPreference(key) ?: throw IllegalArgumentException("Preference with key '$key' is not found") return result } diff --git a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/SwipePreferencesFragment.kt b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/SwipePreferencesFragment.kt index db9cb8f5..cc083eff 100644 --- a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/SwipePreferencesFragment.kt +++ b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/SwipePreferencesFragment.kt @@ -12,41 +12,36 @@ class SwipePreferencesFragment : PreferenceFragmentCompat() { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { addPreferencesFromResource(R.xml.preferences_swipe) - findPreference(PREF_SWIPE_QUEUE)?.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - SwipeActionsDialog(requireContext(), QueueFragment.TAG).show(object : SwipeActionsDialog.Callback { - override fun onCall() {} - }) - true - } - findPreference(PREF_SWIPE_EPISODES)?.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - SwipeActionsDialog(requireContext(), AllEpisodesFragment.TAG).show (object : SwipeActionsDialog.Callback { - override fun onCall() {} - }) - true - } - findPreference(PREF_SWIPE_DOWNLOADS)?.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - SwipeActionsDialog(requireContext(), DownloadsFragment.TAG).show (object : SwipeActionsDialog.Callback { - override fun onCall() {} - }) - true - } - findPreference(PREF_SWIPE_FEED)?.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - SwipeActionsDialog(requireContext(), FeedItemlistFragment.TAG).show (object : SwipeActionsDialog.Callback { - override fun onCall() {} - }) - true - } - findPreference(PREF_SWIPE_HISTORY)?.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - SwipeActionsDialog(requireContext(), PlaybackHistoryFragment.TAG).show (object : SwipeActionsDialog.Callback { - override fun onCall() {} - }) - true - } + findPreference(PREF_SWIPE_QUEUE)?.onPreferenceClickListener = Preference.OnPreferenceClickListener { + SwipeActionsDialog(requireContext(), QueueFragment.TAG).show(object : SwipeActionsDialog.Callback { + override fun onCall() {} + }) + true + } + findPreference(PREF_SWIPE_EPISODES)?.onPreferenceClickListener = Preference.OnPreferenceClickListener { + SwipeActionsDialog(requireContext(), AllEpisodesFragment.TAG).show (object : SwipeActionsDialog.Callback { + override fun onCall() {} + }) + true + } + findPreference(PREF_SWIPE_DOWNLOADS)?.onPreferenceClickListener = Preference.OnPreferenceClickListener { + SwipeActionsDialog(requireContext(), DownloadsFragment.TAG).show (object : SwipeActionsDialog.Callback { + override fun onCall() {} + }) + true + } + findPreference(PREF_SWIPE_FEED)?.onPreferenceClickListener = Preference.OnPreferenceClickListener { + SwipeActionsDialog(requireContext(), FeedItemlistFragment.TAG).show (object : SwipeActionsDialog.Callback { + override fun onCall() {} + }) + true + } + findPreference(PREF_SWIPE_HISTORY)?.onPreferenceClickListener = Preference.OnPreferenceClickListener { + SwipeActionsDialog(requireContext(), PlaybackHistoryFragment.TAG).show (object : SwipeActionsDialog.Callback { + override fun onCall() {} + }) + true + } } override fun onStart() { diff --git a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/UserInterfacePreferencesFragment.kt b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/UserInterfacePreferencesFragment.kt index 7dc57e66..2feeda01 100644 --- a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/UserInterfacePreferencesFragment.kt +++ b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/UserInterfacePreferencesFragment.kt @@ -40,49 +40,39 @@ class UserInterfacePreferencesFragment : PreferenceFragmentCompat() { findPreference(UserPreferences.PREF_THEME)!!.onPreferenceChangeListener = restartApp findPreference(UserPreferences.PREF_THEME_BLACK)!!.onPreferenceChangeListener = restartApp findPreference(UserPreferences.PREF_TINTED_COLORS)!!.onPreferenceChangeListener = restartApp - if (Build.VERSION.SDK_INT < 31) { - findPreference(UserPreferences.PREF_TINTED_COLORS)!!.isVisible = false + if (Build.VERSION.SDK_INT < 31) findPreference(UserPreferences.PREF_TINTED_COLORS)!!.isVisible = false + + findPreference(UserPreferences.PREF_SHOW_TIME_LEFT)?.setOnPreferenceChangeListener { _: Preference?, newValue: Any? -> + setShowRemainTimeSetting(newValue as Boolean?) + EventBus.getDefault().post(UnreadItemsUpdateEvent()) + EventBus.getDefault().post(PlayerStatusEvent()) + true } - findPreference(UserPreferences.PREF_SHOW_TIME_LEFT) - ?.setOnPreferenceChangeListener { _: Preference?, newValue: Any? -> - setShowRemainTimeSetting(newValue as Boolean?) - EventBus.getDefault().post(UnreadItemsUpdateEvent()) - EventBus.getDefault().post(PlayerStatusEvent()) - true - } + findPreference(UserPreferences.PREF_HIDDEN_DRAWER_ITEMS)?.setOnPreferenceClickListener { + DrawerPreferencesDialog.show(requireContext(), null) + true + } - findPreference(UserPreferences.PREF_HIDDEN_DRAWER_ITEMS) - ?.setOnPreferenceClickListener { - DrawerPreferencesDialog.show(requireContext(), null) - true - } - - findPreference(UserPreferences.PREF_FULL_NOTIFICATION_BUTTONS) - ?.setOnPreferenceClickListener { - showFullNotificationButtonsDialog() - true - } + findPreference(UserPreferences.PREF_FULL_NOTIFICATION_BUTTONS)?.setOnPreferenceClickListener { + showFullNotificationButtonsDialog() + true + } // findPreference(UserPreferences.PREF_FILTER_FEED)?.onPreferenceClickListener = // (Preference.OnPreferenceClickListener { // SubscriptionsFilterDialog().show(childFragmentManager, "filter") // true // }) - findPreference(UserPreferences.PREF_DRAWER_FEED_ORDER)?.onPreferenceClickListener = - (Preference.OnPreferenceClickListener { - FeedSortDialog.showDialog(requireContext()) - true - }) - findPreference(PREF_SWIPE) - ?.setOnPreferenceClickListener { - (activity as PreferenceActivity).openScreen(R.xml.preferences_swipe) - true - } - - if (Build.VERSION.SDK_INT >= 26) { - findPreference(UserPreferences.PREF_EXPANDED_NOTIFICATION)!!.isVisible = false + findPreference(UserPreferences.PREF_DRAWER_FEED_ORDER)?.onPreferenceClickListener = (Preference.OnPreferenceClickListener { + FeedSortDialog.showDialog(requireContext()) + true + }) + findPreference(PREF_SWIPE)?.setOnPreferenceClickListener { + (activity as PreferenceActivity).openScreen(R.xml.preferences_swipe) + true } + if (Build.VERSION.SDK_INT >= 26) findPreference(UserPreferences.PREF_EXPANDED_NOTIFICATION)!!.isVisible = false } @@ -90,8 +80,7 @@ class UserInterfacePreferencesFragment : PreferenceFragmentCompat() { val context: Context? = activity val preferredButtons = fullNotificationButtons - val allButtonNames = context!!.resources.getStringArray( - R.array.full_notification_buttons_options) + val allButtonNames = context!!.resources.getStringArray(R.array.full_notification_buttons_options) val buttonIDs = intArrayOf(2, 3, 4) val exactItems = 2 val completeListener = DialogInterface.OnClickListener { _: DialogInterface?, _: Int -> @@ -100,15 +89,11 @@ class UserInterfacePreferencesFragment : PreferenceFragmentCompat() { val title = context.resources.getString( R.string.pref_full_notification_buttons_title) - showNotificationButtonsDialog(preferredButtons?.toMutableList(), allButtonNames, buttonIDs, title, - exactItems, completeListener - ) + showNotificationButtonsDialog(preferredButtons?.toMutableList(), allButtonNames, buttonIDs, title, exactItems, completeListener) } - private fun showNotificationButtonsDialog(preferredButtons: MutableList?, - allButtonNames: Array, buttonIds: IntArray, title: String, - exactItems: Int, completeListener: DialogInterface.OnClickListener - ) { + private fun showNotificationButtonsDialog(preferredButtons: MutableList?, allButtonNames: Array, buttonIds: IntArray, + title: String, exactItems: Int, completeListener: DialogInterface.OnClickListener) { val checked = BooleanArray(allButtonNames.size) // booleans default to false in java val context: Context? = activity @@ -117,20 +102,13 @@ class UserInterfacePreferencesFragment : PreferenceFragmentCompat() { for (i in preferredButtons!!.indices.reversed()) { var isValid = false for (j in checked.indices) { - if (buttonIds[j] == preferredButtons[i]) { - isValid = true - } - } - - if (!isValid) { - preferredButtons.removeAt(i) + if (buttonIds[j] == preferredButtons[i]) isValid = true } + if (!isValid) preferredButtons.removeAt(i) } for (i in checked.indices) { - if (preferredButtons.contains(buttonIds[i])) { - checked[i] = true - } + if (preferredButtons.contains(buttonIds[i])) checked[i] = true } val builder = MaterialAlertDialogBuilder(context!!) @@ -138,11 +116,8 @@ class UserInterfacePreferencesFragment : PreferenceFragmentCompat() { builder.setMultiChoiceItems(allButtonNames, checked) { _: DialogInterface?, which: Int, isChecked: Boolean -> checked[which] = isChecked - if (isChecked) { - preferredButtons.add(buttonIds[which]) - } else { - preferredButtons.remove(buttonIds[which]) - } + if (isChecked) preferredButtons.add(buttonIds[which]) + else preferredButtons.remove(buttonIds[which]) } builder.setPositiveButton(R.string.confirm_label, null) builder.setNegativeButton(R.string.cancel_label, null) @@ -155,11 +130,7 @@ class UserInterfacePreferencesFragment : PreferenceFragmentCompat() { positiveButton.setOnClickListener { if (preferredButtons.size != exactItems) { val selectionView = dialog.listView - Snackbar.make( - selectionView, - String.format(context.resources.getString( - R.string.pref_compact_notification_buttons_dialog_error_exact), exactItems), - Snackbar.LENGTH_SHORT).show() + Snackbar.make(selectionView, String.format(context.resources.getString(R.string.pref_compact_notification_buttons_dialog_error_exact), exactItems), Snackbar.LENGTH_SHORT).show() } else { completeListener.onClick(dialog, AlertDialog.BUTTON_POSITIVE) dialog.cancel() diff --git a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/about/AboutFragment.kt b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/about/AboutFragment.kt index a3a314ba..7ed4c790 100644 --- a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/about/AboutFragment.kt +++ b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/about/AboutFragment.kt @@ -19,17 +19,13 @@ class AboutFragment : PreferenceFragmentCompat() { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { addPreferencesFromResource(R.xml.preferences_about) - findPreference("about_version")!!.summary = String.format( - "%s (%s)", BuildConfig.VERSION_NAME, BuildConfig.COMMIT_HASH) + findPreference("about_version")!!.summary = String.format("%s (%s)", BuildConfig.VERSION_NAME, BuildConfig.COMMIT_HASH) findPreference("about_version")!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { preference: Preference? -> val clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager - val clip = ClipData.newPlainText(getString(R.string.bug_report_title), - findPreference("about_version")!!.summary) + val clip = ClipData.newPlainText(getString(R.string.bug_report_title), findPreference("about_version")!!.summary) clipboard.setPrimaryClip(clip) - if (Build.VERSION.SDK_INT <= 32) { - Snackbar.make(requireView(), R.string.copied_to_clipboard, Snackbar.LENGTH_SHORT).show() - } + if (Build.VERSION.SDK_INT <= 32) Snackbar.make(requireView(), R.string.copied_to_clipboard, Snackbar.LENGTH_SHORT).show() true } findPreference("about_contributors")!!.onPreferenceClickListener = diff --git a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/about/ContributorsPagerFragment.kt b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/about/ContributorsPagerFragment.kt index 34e9e8c3..7a642918 100644 --- a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/about/ContributorsPagerFragment.kt +++ b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/about/ContributorsPagerFragment.kt @@ -16,15 +16,12 @@ import com.google.android.material.tabs.TabLayoutMediator * Displays the 'about->Contributors' pager screen. */ class ContributorsPagerFragment : Fragment() { - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? - ): View { + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { super.onCreateView(inflater, container, savedInstanceState) setHasOptionsMenu(true) val binding = PagerFragmentBinding.inflate(inflater) val viewPager = binding.viewpager - viewPager.adapter = StatisticsPagerAdapter( - this) + viewPager.adapter = StatisticsPagerAdapter(this) // Give the TabLayout the ViewPager val tabLayout = binding.slidingTabs TabLayoutMediator(tabLayout, viewPager) { tab: TabLayout.Tab, position: Int -> diff --git a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/about/DevelopersFragment.kt b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/about/DevelopersFragment.kt index bb2e73c5..3c57900a 100644 --- a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/about/DevelopersFragment.kt +++ b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/about/DevelopersFragment.kt @@ -22,33 +22,26 @@ class DevelopersFragment : ListFragment() { listView.divider = null listView.setSelector(color.transparent) - developersLoader = - Single.create { emitter: SingleEmitter?> -> - val developers = ArrayList() - val reader = BufferedReader(InputStreamReader( - requireContext().assets.open("developers.csv"), "UTF-8")) - var line: String - while ((reader.readLine().also { line = it }) != null) { - val info = line.split(";".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() - developers.add(SimpleIconListAdapter.ListItem(info[0], info[2], - "https://avatars2.githubusercontent.com/u/" + info[1] + "?s=60&v=4")) - } - emitter.onSuccess(developers) + developersLoader = Single.create { emitter: SingleEmitter?> -> + val developers = ArrayList() + val reader = BufferedReader(InputStreamReader(requireContext().assets.open("developers.csv"), "UTF-8")) + var line: String + while ((reader.readLine().also { line = it }) != null) { + val info = line.split(";".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() + developers.add(SimpleIconListAdapter.ListItem(info[0], info[2], "https://avatars2.githubusercontent.com/u/" + info[1] + "?s=60&v=4")) } - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe( - { developers: ArrayList? -> - if (developers != null) listAdapter = SimpleIconListAdapter(requireContext(), developers) - }, - { error: Throwable -> Toast.makeText(context, error.message, Toast.LENGTH_LONG).show() } - ) + emitter.onSuccess(developers) + } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ developers: ArrayList? -> + if (developers != null) listAdapter = SimpleIconListAdapter(requireContext(), developers) + }, { error: Throwable -> Toast.makeText(context, error.message, Toast.LENGTH_LONG).show() } + ) } override fun onStop() { super.onStop() - if (developersLoader != null) { - developersLoader!!.dispose() - } + developersLoader?.dispose() } } diff --git a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/about/LicensesFragment.kt b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/about/LicensesFragment.kt index 60113aaa..414bfd6d 100644 --- a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/about/LicensesFragment.kt +++ b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/about/LicensesFragment.kt @@ -36,14 +36,9 @@ class LicensesFragment : ListFragment() { val libraryList = docBuilder.parse(stream).getElementsByTagName("library") for (i in 0 until libraryList.length) { val lib = libraryList.item(i).attributes - licenses.add(LicenseItem( - lib.getNamedItem("name").textContent, - String.format("By %s, %s license", - lib.getNamedItem("author").textContent, - lib.getNamedItem("license").textContent), - "", - lib.getNamedItem("website").textContent, - lib.getNamedItem("licenseText").textContent)) + licenses.add(LicenseItem(lib.getNamedItem("name").textContent, + String.format("By %s, %s license", lib.getNamedItem("author").textContent, lib.getNamedItem("license").textContent), + "", lib.getNamedItem("website").textContent, lib.getNamedItem("licenseText").textContent)) } emitter.onSuccess(licenses) } @@ -55,12 +50,8 @@ class LicensesFragment : ListFragment() { ) } - private class LicenseItem(title: String, - subtitle: String, - imageUrl: String, - val licenseUrl: String, - val licenseTextFile: String - ) : SimpleIconListAdapter.ListItem(title, subtitle, imageUrl) + private class LicenseItem(title: String, subtitle: String, imageUrl: String, val licenseUrl: String, val licenseTextFile: String) + : SimpleIconListAdapter.ListItem(title, subtitle, imageUrl) override fun onListItemClick(l: ListView, v: View, position: Int, id: Long) { super.onListItemClick(l, v, position, id) @@ -71,20 +62,15 @@ class LicensesFragment : ListFragment() { .setTitle(item.title) .setItems(items) { dialog: DialogInterface?, which: Int -> when (which) { - 0 -> { - openInBrowser(requireContext(), item.licenseUrl) - } - 1 -> { - showLicenseText(item.licenseTextFile) - } + 0 -> openInBrowser(requireContext(), item.licenseUrl) + 1 -> showLicenseText(item.licenseTextFile) } }.show() } private fun showLicenseText(licenseTextFile: String) { try { - val reader = BufferedReader(InputStreamReader( - requireContext().assets.open(licenseTextFile), "UTF-8")) + val reader = BufferedReader(InputStreamReader(requireContext().assets.open(licenseTextFile), "UTF-8")) val licenseText = StringBuilder() var line: String? while ((reader.readLine().also { line = it }) != null) { diff --git a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/about/SpecialThanksFragment.kt b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/about/SpecialThanksFragment.kt index 28b89108..a0ab2258 100644 --- a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/about/SpecialThanksFragment.kt +++ b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/about/SpecialThanksFragment.kt @@ -22,32 +22,26 @@ class SpecialThanksFragment : ListFragment() { listView.divider = null listView.setSelector(color.transparent) - translatorsLoader = - Single.create { emitter: SingleEmitter?> -> - val translators = ArrayList() - val reader = BufferedReader(InputStreamReader( - requireContext().assets.open("special_thanks.csv"), "UTF-8")) - var line: String - while ((reader.readLine().also { line = it }) != null) { - val info = line.split(";".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() - translators.add(SimpleIconListAdapter.ListItem(info[0], info[1], info[2])) - } - emitter.onSuccess(translators) + translatorsLoader = Single.create { emitter: SingleEmitter?> -> + val translators = ArrayList() + val reader = BufferedReader(InputStreamReader(requireContext().assets.open("special_thanks.csv"), "UTF-8")) + var line: String + while ((reader.readLine().also { line = it }) != null) { + val info = line.split(";".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() + translators.add(SimpleIconListAdapter.ListItem(info[0], info[1], info[2])) } - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe( - { translators: ArrayList? -> - if (translators != null) listAdapter = SimpleIconListAdapter(requireContext(), translators) - }, - { error: Throwable -> Toast.makeText(context, error.message, Toast.LENGTH_LONG).show() } - ) + emitter.onSuccess(translators) + } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ translators: ArrayList? -> + if (translators != null) listAdapter = SimpleIconListAdapter(requireContext(), translators) + }, { error: Throwable -> Toast.makeText(context, error.message, Toast.LENGTH_LONG).show() } + ) } override fun onStop() { super.onStop() - if (translatorsLoader != null) { - translatorsLoader!!.dispose() - } + translatorsLoader?.dispose() } } diff --git a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/about/TranslatorsFragment.kt b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/about/TranslatorsFragment.kt index 778e2b1a..73d25a9e 100644 --- a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/about/TranslatorsFragment.kt +++ b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/about/TranslatorsFragment.kt @@ -22,32 +22,27 @@ class TranslatorsFragment : ListFragment() { listView.divider = null listView.setSelector(color.transparent) - translatorsLoader = - Single.create { emitter: SingleEmitter?> -> - val translators = ArrayList() - val reader = BufferedReader(InputStreamReader( - requireContext().assets.open("translators.csv"), "UTF-8")) - var line: String - while ((reader.readLine().also { line = it }) != null) { - val info = line.split(";".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() - translators.add(SimpleIconListAdapter.ListItem(info[0], info[1], "")) - } - emitter.onSuccess(translators) + translatorsLoader = Single.create { emitter: SingleEmitter?> -> + val translators = ArrayList() + val reader = BufferedReader(InputStreamReader(requireContext().assets.open("translators.csv"), "UTF-8")) + var line: String + while ((reader.readLine().also { line = it }) != null) { + val info = line.split(";".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() + translators.add(SimpleIconListAdapter.ListItem(info[0], info[1], "")) } - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe( - { translators: ArrayList? -> - if (translators != null) listAdapter = SimpleIconListAdapter(requireContext(), translators) - }, - { error: Throwable -> Toast.makeText(context, error.message, Toast.LENGTH_LONG).show() } - ) + emitter.onSuccess(translators) + } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ translators: ArrayList? -> + if (translators != null) listAdapter = SimpleIconListAdapter(requireContext(), translators) + }, + { error: Throwable -> Toast.makeText(context, error.message, Toast.LENGTH_LONG).show() } + ) } override fun onStop() { super.onStop() - if (translatorsLoader != null) { - translatorsLoader!!.dispose() - } + translatorsLoader?.dispose() } } diff --git a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/dialog/PreferenceListDialog.kt b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/dialog/PreferenceListDialog.kt index 001a60ad..42cd670e 100644 --- a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/dialog/PreferenceListDialog.kt +++ b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/dialog/PreferenceListDialog.kt @@ -25,9 +25,7 @@ class PreferenceListDialog(private var context: Context, private val title: Stri selectedPos = which } builder.setPositiveButton(R.string.confirm_label) { _: DialogInterface?, _: Int -> - if (onPreferenceChangedListener != null && selectedPos >= 0) { - onPreferenceChangedListener!!.preferenceChanged(selectedPos) - } + if (onPreferenceChangedListener != null && selectedPos >= 0) onPreferenceChangedListener!!.preferenceChanged(selectedPos) } builder.setNegativeButton(R.string.cancel_label, null) builder.create().show() diff --git a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/dialog/PreferenceSwitchDialog.kt b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/dialog/PreferenceSwitchDialog.kt index 2751e357..31da95c5 100644 --- a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/dialog/PreferenceSwitchDialog.kt +++ b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/dialog/PreferenceSwitchDialog.kt @@ -31,9 +31,7 @@ class PreferenceSwitchDialog(private var context: Context, private val title: St builder.setView(layout) builder.setPositiveButton(R.string.confirm_label) { _: DialogInterface?, _: Int -> - if (onPreferenceChangedListener != null) { - onPreferenceChangedListener!!.preferenceChanged(switchButton.isChecked) - } + onPreferenceChangedListener?.preferenceChanged(switchButton.isChecked) } builder.setNegativeButton(R.string.cancel_label, null) builder.create().show() diff --git a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/synchronization/GpodderAuthenticationFragment.kt b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/synchronization/GpodderAuthenticationFragment.kt index 1b427a84..d62a14a2 100644 --- a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/synchronization/GpodderAuthenticationFragment.kt +++ b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/synchronization/GpodderAuthenticationFragment.kt @@ -69,13 +69,11 @@ class GpodderAuthenticationFragment : DialogFragment() { val selectHost = binding.chooseHostButton val serverUrlText = binding.serverUrlText selectHost.setOnClickListener { - if (serverUrlText.text.isNullOrEmpty()) { - return@setOnClickListener - } + if (serverUrlText.text.isNullOrEmpty()) return@setOnClickListener + SynchronizationCredentials.clear(requireContext()) SynchronizationCredentials.hosturl = serverUrlText.text.toString() - service = GpodnetService(getHttpClient(), - SynchronizationCredentials.hosturl, SynchronizationCredentials.deviceID?:"", + service = GpodnetService(getHttpClient(), SynchronizationCredentials.hosturl, SynchronizationCredentials.deviceID?:"", SynchronizationCredentials.username?:"", SynchronizationCredentials.password?:"") dialog?.setTitle(SynchronizationCredentials.hosturl) advance() @@ -91,9 +89,9 @@ class GpodderAuthenticationFragment : DialogFragment() { val progressBar = binding.progBarLogin val createAccountWarning = binding.createAccountWarning - if (SynchronizationCredentials.hosturl != null && SynchronizationCredentials.hosturl!!.startsWith("http://")) { + if (SynchronizationCredentials.hosturl != null && SynchronizationCredentials.hosturl!!.startsWith("http://")) createAccountWarning.visibility = View.VISIBLE - } + password.setOnEditorActionListener { _: TextView?, actionID: Int, _: KeyEvent? -> actionID == EditorInfo.IME_ACTION_GO && login.performClick() } login.setOnClickListener { @@ -162,9 +160,8 @@ class GpodderAuthenticationFragment : DialogFragment() { val progBarCreateDevice = binding.progbarCreateDevice val deviceNameStr = deviceName.text.toString() - if (isDeviceInList(deviceNameStr)) { - return - } + if (isDeviceInList(deviceNameStr)) return + progBarCreateDevice.visibility = View.VISIBLE txtvError.visibility = View.GONE deviceName.isEnabled = false @@ -206,14 +203,11 @@ class GpodderAuthenticationFragment : DialogFragment() { } private fun isDeviceInList(name: String): Boolean { - if (devices == null) { - return false - } + if (devices == null) return false + val id = generateDeviceId(name) for (device in devices!!) { - if (device.id == id || device.caption == name) { - return true - } + if (device.id == id || device.caption == name) return true } return false } @@ -232,12 +226,8 @@ class GpodderAuthenticationFragment : DialogFragment() { if (currentStep < STEP_FINISH) { val view = viewFlipper!!.getChildAt(currentStep + 1) when (currentStep) { - STEP_DEFAULT -> { - setupHostView(view) - } - STEP_HOSTNAME -> { - setupLoginView(view) - } + STEP_DEFAULT -> setupHostView(view) + STEP_HOSTNAME -> setupLoginView(view) STEP_LOGIN -> { check(!(username == null || password == null)) { "Username and password must not be null here" } setupDeviceView(view) @@ -251,13 +241,9 @@ class GpodderAuthenticationFragment : DialogFragment() { setupFinishView(view) } } - if (currentStep != STEP_DEFAULT) { - viewFlipper!!.showNext() - } + if (currentStep != STEP_DEFAULT) viewFlipper!!.showNext() currentStep++ - } else { - dismiss() - } + } else dismiss() } private fun usernameHasUnwantedChars(username: String): Boolean { diff --git a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/synchronization/NextcloudAuthenticationFragment.kt b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/synchronization/NextcloudAuthenticationFragment.kt index c757c787..e3abbcdb 100644 --- a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/synchronization/NextcloudAuthenticationFragment.kt +++ b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/synchronization/NextcloudAuthenticationFragment.kt @@ -34,13 +34,11 @@ class NextcloudAuthenticationFragment : DialogFragment(), NextcloudLoginFlow.Aut dialog.setView(viewBinding!!.root) viewBinding!!.chooseHostButton.setOnClickListener { - nextcloudLoginFlow = NextcloudLoginFlow(getHttpClient(), - viewBinding!!.serverUrlText.text.toString(), requireContext(), this) + nextcloudLoginFlow = NextcloudLoginFlow(getHttpClient(), viewBinding!!.serverUrlText.text.toString(), requireContext(), this) startLoginFlow() } if (savedInstanceState?.getStringArrayList(EXTRA_LOGIN_FLOW) != null) { - nextcloudLoginFlow = NextcloudLoginFlow.fromInstanceState(getHttpClient(), - requireContext(), this, savedInstanceState.getStringArrayList(EXTRA_LOGIN_FLOW)!!) + nextcloudLoginFlow = NextcloudLoginFlow.fromInstanceState(getHttpClient(), requireContext(), this, savedInstanceState.getStringArrayList(EXTRA_LOGIN_FLOW)!!) startLoginFlow() } return dialog.create() @@ -56,23 +54,17 @@ class NextcloudAuthenticationFragment : DialogFragment(), NextcloudLoginFlow.Aut override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) - if (nextcloudLoginFlow != null) { - outState.putStringArrayList(EXTRA_LOGIN_FLOW, nextcloudLoginFlow!!.saveInstanceState()) - } + if (nextcloudLoginFlow != null) outState.putStringArrayList(EXTRA_LOGIN_FLOW, nextcloudLoginFlow!!.saveInstanceState()) } override fun onDismiss(dialog: DialogInterface) { super.onDismiss(dialog) - if (nextcloudLoginFlow != null) { - nextcloudLoginFlow!!.cancel() - } + nextcloudLoginFlow?.cancel() } override fun onResume() { super.onResume() - if (shouldDismiss) { - dismiss() - } + if (shouldDismiss) dismiss() } override fun onNextcloudAuthenticated(server: String, username: String, password: String) { @@ -82,11 +74,8 @@ class NextcloudAuthenticationFragment : DialogFragment(), NextcloudLoginFlow.Aut SynchronizationCredentials.hosturl = server SynchronizationCredentials.username = username SyncService.fullSync(requireContext()) - if (isResumed) { - dismiss() - } else { - shouldDismiss = true - } + if (isResumed) dismiss() + else shouldDismiss = true } override fun onNextcloudAuthError(errorMessage: String?) { diff --git a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/synchronization/SynchronizationPreferencesFragment.kt b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/synchronization/SynchronizationPreferencesFragment.kt index b85d5489..4a3ada52 100644 --- a/app/src/main/java/ac/mdiq/podcini/preferences/fragments/synchronization/SynchronizationPreferencesFragment.kt +++ b/app/src/main/java/ac/mdiq/podcini/preferences/fragments/synchronization/SynchronizationPreferencesFragment.kt @@ -51,52 +51,41 @@ class SynchronizationPreferencesFragment : PreferenceFragmentCompat() { @Subscribe(threadMode = ThreadMode.MAIN, sticky = true) fun syncStatusChanged(event: SyncServiceEvent) { - if (!SynchronizationSettings.isProviderConnected) { - return - } + if (!SynchronizationSettings.isProviderConnected) return + updateScreen() - if (event.messageResId == R.string.sync_status_error - || event.messageResId == R.string.sync_status_success) { - updateLastSyncReport(SynchronizationSettings.isLastSyncSuccessful, - SynchronizationSettings.lastSyncAttempt) - } else { - (activity as PreferenceActivity).supportActionBar!! - .setSubtitle(event.messageResId) - } + if (event.messageResId == R.string.sync_status_error || event.messageResId == R.string.sync_status_success) + updateLastSyncReport(SynchronizationSettings.isLastSyncSuccessful, SynchronizationSettings.lastSyncAttempt) + else (activity as PreferenceActivity).supportActionBar!!.setSubtitle(event.messageResId) } private fun setupScreen() { val activity: Activity? = activity - findPreference(PREFERENCE_GPODNET_SETLOGIN_INFORMATION) - ?.setOnPreferenceClickListener { - val dialog: AuthenticationDialog = object : AuthenticationDialog(requireContext(), - R.string.pref_gpodnet_setlogin_information_title, - false, SynchronizationCredentials.username, null) { - override fun onConfirmed(username: String, password: String) { - SynchronizationCredentials.password = password - } + findPreference(PREFERENCE_GPODNET_SETLOGIN_INFORMATION)?.setOnPreferenceClickListener { + val dialog: AuthenticationDialog = object : AuthenticationDialog(requireContext(), R.string.pref_gpodnet_setlogin_information_title, + false, SynchronizationCredentials.username, null) { + override fun onConfirmed(username: String, password: String) { + SynchronizationCredentials.password = password } - dialog.show() - true - } - findPreference(PREFERENCE_SYNC)!!.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - SyncService.syncImmediately(requireActivity().applicationContext) - true - } - findPreference(PREFERENCE_FORCE_FULL_SYNC)!!.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - SyncService.fullSync(requireContext()) - true - } - findPreference(PREFERENCE_LOGOUT)!!.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - SynchronizationCredentials.clear(requireContext()) - Snackbar.make(requireView(), R.string.pref_synchronization_logout_toast, Snackbar.LENGTH_LONG).show() - SynchronizationSettings.setSelectedSyncProvider(null) - updateScreen() - true } + dialog.show() + true + } + findPreference(PREFERENCE_SYNC)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + SyncService.syncImmediately(requireActivity().applicationContext) + true + } + findPreference(PREFERENCE_FORCE_FULL_SYNC)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + SyncService.fullSync(requireContext()) + true + } + findPreference(PREFERENCE_LOGOUT)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { + SynchronizationCredentials.clear(requireContext()) + Snackbar.make(requireView(), R.string.pref_synchronization_logout_toast, Snackbar.LENGTH_LONG).show() + SynchronizationSettings.setSelectedSyncProvider(null) + updateScreen() + true + } } private fun updateScreen() { @@ -114,11 +103,10 @@ class SynchronizationPreferencesFragment : PreferenceFragmentCompat() { preferenceHeader!!.setTitle(R.string.synchronization_choose_title) preferenceHeader.setSummary(R.string.synchronization_summary_unchoosen) preferenceHeader.setIcon(R.drawable.ic_cloud) - preferenceHeader.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - chooseProviderAndLogin() - true - } + preferenceHeader.onPreferenceClickListener = Preference.OnPreferenceClickListener { + chooseProviderAndLogin() + true + } } val gpodnetSetLoginPreference = findPreference(PREFERENCE_GPODNET_SETLOGIN_INFORMATION) @@ -132,8 +120,7 @@ class SynchronizationPreferencesFragment : PreferenceFragmentCompat() { SynchronizationCredentials.username, SynchronizationCredentials.hosturl) val formattedSummary = HtmlCompat.fromHtml(summary, HtmlCompat.FROM_HTML_MODE_LEGACY) findPreference(PREFERENCE_LOGOUT)!!.summary = formattedSummary - updateLastSyncReport(SynchronizationSettings.isLastSyncSuccessful, - SynchronizationSettings.lastSyncAttempt) + updateLastSyncReport(SynchronizationSettings.isLastSyncSuccessful, SynchronizationSettings.lastSyncAttempt) } else { findPreference(PREFERENCE_LOGOUT)?.summary = "" (activity as PreferenceActivity).supportActionBar?.setSubtitle("") @@ -166,9 +153,8 @@ class SynchronizationPreferencesFragment : PreferenceFragmentCompat() { holder!!.title = binding.title convertView.tag = holder } - } else { - holder = convertView.tag as ViewHolder - } + } else holder = convertView.tag as ViewHolder + val synchronizationProviderViewData = getItem(position) holder!!.title!!.setText(synchronizationProviderViewData!!.summaryResource) holder!!.icon!!.setImageResource(synchronizationProviderViewData.iconResource) @@ -198,10 +184,8 @@ class SynchronizationPreferencesFragment : PreferenceFragmentCompat() { get() = SynchronizationSettings.selectedSyncProviderKey?:"" private fun updateLastSyncReport(successful: Boolean, lastTime: Long) { - val status = String.format("%1\$s (%2\$s)", getString(if (successful - ) R.string.gpodnetsync_pref_report_successful else R.string.gpodnetsync_pref_report_failed), - DateUtils.getRelativeDateTimeString(context, - lastTime, DateUtils.MINUTE_IN_MILLIS, DateUtils.WEEK_IN_MILLIS, DateUtils.FORMAT_SHOW_TIME)) + val status = String.format("%1\$s (%2\$s)", getString(if (successful) R.string.gpodnetsync_pref_report_successful else R.string.gpodnetsync_pref_report_failed), + DateUtils.getRelativeDateTimeString(context, lastTime, DateUtils.MINUTE_IN_MILLIS, DateUtils.WEEK_IN_MILLIS, DateUtils.FORMAT_SHOW_TIME)) (activity as PreferenceActivity).supportActionBar!!.subtitle = status } diff --git a/app/src/main/java/ac/mdiq/podcini/receiver/MediaButtonReceiver.kt b/app/src/main/java/ac/mdiq/podcini/receiver/MediaButtonReceiver.kt index 85b8489f..a7c220b1 100644 --- a/app/src/main/java/ac/mdiq/podcini/receiver/MediaButtonReceiver.kt +++ b/app/src/main/java/ac/mdiq/podcini/receiver/MediaButtonReceiver.kt @@ -18,9 +18,8 @@ class MediaButtonReceiver : BroadcastReceiver() { @UnstableApi override fun onReceive(context: Context, intent: Intent) { Log.d(TAG, "Received intent") - if (intent.extras == null) { - return - } + if (intent.extras == null) return + val event = intent.extras!![Intent.EXTRA_KEY_EVENT] as? KeyEvent if (event != null && event.action == KeyEvent.ACTION_DOWN && event.repeatCount == 0) { ClientConfigurator.initialize(context) @@ -40,11 +39,9 @@ class MediaButtonReceiver : BroadcastReceiver() { companion object { private const val TAG = "MediaButtonReceiver" const val EXTRA_KEYCODE: String = "ac.mdiq.podcini.service.extra.MediaButtonReceiver.KEYCODE" - const val EXTRA_CUSTOM_ACTION: String = - "ac.mdiq.podcini.service.extra.MediaButtonReceiver.CUSTOM_ACTION" + const val EXTRA_CUSTOM_ACTION: String = "ac.mdiq.podcini.service.extra.MediaButtonReceiver.CUSTOM_ACTION" const val EXTRA_SOURCE: String = "ac.mdiq.podcini.service.extra.MediaButtonReceiver.SOURCE" - const val EXTRA_HARDWAREBUTTON - : String = "ac.mdiq.podcini.service.extra.MediaButtonReceiver.HARDWAREBUTTON" + const val EXTRA_HARDWAREBUTTON: String = "ac.mdiq.podcini.service.extra.MediaButtonReceiver.HARDWAREBUTTON" const val NOTIFY_BUTTON_RECEIVER: String = "ac.mdiq.podcini.NOTIFY_BUTTON_RECEIVER" const val PLAYBACK_SERVICE_INTENT: String = "ac.mdiq.podcini.intents.PLAYBACK_SERVICE" diff --git a/app/src/main/java/ac/mdiq/podcini/receiver/PlayerWidget.kt b/app/src/main/java/ac/mdiq/podcini/receiver/PlayerWidget.kt index 41c679d9..0e0b0953 100644 --- a/app/src/main/java/ac/mdiq/podcini/receiver/PlayerWidget.kt +++ b/app/src/main/java/ac/mdiq/podcini/receiver/PlayerWidget.kt @@ -81,8 +81,7 @@ class PlayerWidget : AppWidgetProvider() { val workRequest: OneTimeWorkRequest = OneTimeWorkRequest.Builder(WidgetUpdaterWorker::class.java) .setInitialDelay((100 * 356).toLong(), TimeUnit.DAYS) .build() - WorkManager.getInstance(context) - .enqueueUniqueWork(WORKAROUND_WORK_NAME, ExistingWorkPolicy.REPLACE, workRequest) + WorkManager.getInstance(context).enqueueUniqueWork(WORKAROUND_WORK_NAME, ExistingWorkPolicy.REPLACE, workRequest) } @JvmStatic diff --git a/app/src/main/java/ac/mdiq/podcini/receiver/PowerConnectionReceiver.kt b/app/src/main/java/ac/mdiq/podcini/receiver/PowerConnectionReceiver.kt index 4ebca118..2bc6bfd3 100644 --- a/app/src/main/java/ac/mdiq/podcini/receiver/PowerConnectionReceiver.kt +++ b/app/src/main/java/ac/mdiq/podcini/receiver/PowerConnectionReceiver.kt @@ -35,10 +35,7 @@ class PowerConnectionReceiver : BroadcastReceiver() { if (!isEnableAutodownloadOnBattery) { Log.d(TAG, "not charging anymore, canceling auto-download") DownloadServiceInterface.get()?.cancelAll(context) - } else { - Log.d(TAG, "not charging anymore, but the user allows auto-download " + - "when on battery so we'll keep going") - } + } else Log.d(TAG, "not charging anymore, but the user allows auto-download when on battery so we'll keep going") } } diff --git a/app/src/main/java/ac/mdiq/podcini/receiver/SPAReceiver.kt b/app/src/main/java/ac/mdiq/podcini/receiver/SPAReceiver.kt index 675faad4..b5ee92ec 100644 --- a/app/src/main/java/ac/mdiq/podcini/receiver/SPAReceiver.kt +++ b/app/src/main/java/ac/mdiq/podcini/receiver/SPAReceiver.kt @@ -18,9 +18,8 @@ import ac.mdiq.podcini.storage.model.feed.Feed */ class SPAReceiver : BroadcastReceiver() { @UnstableApi override fun onReceive(context: Context, intent: Intent) { - if (!TextUtils.equals(intent.action, ACTION_SP_APPS_QUERY_FEEDS_REPSONSE)) { - return - } + if (!TextUtils.equals(intent.action, ACTION_SP_APPS_QUERY_FEEDS_REPSONSE)) return + Log.d(TAG, "Received SP_APPS_QUERY_RESPONSE") if (!intent.hasExtra(ACTION_SP_APPS_QUERY_FEEDS_REPSONSE_FEEDS_EXTRA)) { Log.e(TAG, "Received invalid SP_APPS_QUERY_RESPONSE: Contains no extra") @@ -46,8 +45,7 @@ class SPAReceiver : BroadcastReceiver() { private const val TAG = "SPAReceiver" const val ACTION_SP_APPS_QUERY_FEEDS: String = "de.danoeh.antennapdsp.intent.SP_APPS_QUERY_FEEDS" - private const val ACTION_SP_APPS_QUERY_FEEDS_REPSONSE = - "de.danoeh.antennapdsp.intent.SP_APPS_QUERY_FEEDS_RESPONSE" + private const val ACTION_SP_APPS_QUERY_FEEDS_REPSONSE = "de.danoeh.antennapdsp.intent.SP_APPS_QUERY_FEEDS_RESPONSE" private const val ACTION_SP_APPS_QUERY_FEEDS_REPSONSE_FEEDS_EXTRA = "feeds" } } diff --git a/app/src/main/java/ac/mdiq/podcini/storage/APCleanupAlgorithm.kt b/app/src/main/java/ac/mdiq/podcini/storage/APCleanupAlgorithm.kt index 2e00d6db..d05c3316 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/APCleanupAlgorithm.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/APCleanupAlgorithm.kt @@ -7,6 +7,8 @@ import ac.mdiq.podcini.storage.DBReader.getEpisodes import ac.mdiq.podcini.storage.model.feed.FeedItem import ac.mdiq.podcini.storage.model.feed.FeedItemFilter import ac.mdiq.podcini.storage.model.feed.SortOrder +import androidx.annotation.OptIn +import androidx.media3.common.util.UnstableApi import java.util.* import java.util.concurrent.ExecutionException @@ -25,27 +27,20 @@ class APCleanupAlgorithm( return candidates.size } - public override fun performCleanup(context: Context, numberOfEpisodesToDelete: Int): Int { + @OptIn(UnstableApi::class) public override fun performCleanup(context: Context, numberOfEpisodesToDelete: Int): Int { val candidates = candidates.toMutableList() candidates.sortWith { lhs: FeedItem, rhs: FeedItem -> var l = lhs.media!!.getPlaybackCompletionDate() var r = rhs.media!!.getPlaybackCompletionDate() - if (l == null) { - l = Date() - } - if (r == null) { - r = Date() - } + if (l == null) l = Date() + if (r == null) r = Date() + l.compareTo(r) } - val delete = if (candidates.size > numberOfEpisodesToDelete) { - candidates.subList(0, numberOfEpisodesToDelete) - } else { - candidates - } + val delete = if (candidates.size > numberOfEpisodesToDelete) candidates.subList(0, numberOfEpisodesToDelete) else candidates for (item in delete) { try { @@ -59,10 +54,7 @@ class APCleanupAlgorithm( val counter = delete.size - - Log.i(TAG, String.format(Locale.US, - "Auto-delete deleted %d episodes (%d requested)", counter, - numberOfEpisodesToDelete)) + Log.i(TAG, String.format(Locale.US, "Auto-delete deleted %d episodes (%d requested)", counter, numberOfEpisodesToDelete)) return counter } @@ -80,18 +72,13 @@ class APCleanupAlgorithm( val mostRecentDateForDeletion = calcMostRecentDateForDeletion(Date()) for (item in downloadedItems) { - if (item.hasMedia() - && item.media!!.isDownloaded() - && !item.isTagged(FeedItem.TAG_QUEUE) - && item.isPlayed() + if (item.hasMedia() && item.media!!.isDownloaded() && !item.isTagged(FeedItem.TAG_QUEUE) && item.isPlayed() && !item.isTagged(FeedItem.TAG_FAVORITE)) { val media = item.media // make sure this candidate was played at least the proper amount of days prior // to now - if (media?.getPlaybackCompletionDate() != null && media.getPlaybackCompletionDate()!! - .before(mostRecentDateForDeletion)) { + if (media?.getPlaybackCompletionDate() != null && media.getPlaybackCompletionDate()!!.before(mostRecentDateForDeletion)) candidates.add(item) - } } } return candidates diff --git a/app/src/main/java/ac/mdiq/podcini/storage/APQueueCleanupAlgorithm.kt b/app/src/main/java/ac/mdiq/podcini/storage/APQueueCleanupAlgorithm.kt index 6913aa47..7364260d 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/APQueueCleanupAlgorithm.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/APQueueCleanupAlgorithm.kt @@ -29,20 +29,13 @@ class APQueueCleanupAlgorithm : EpisodeCleanupAlgorithm() { var l = lhs.getPubDate() var r = rhs.getPubDate() - if (l == null) { - l = Date() - } - if (r == null) { - r = Date() - } + if (l == null) l = Date() + if (r == null) r = Date() + l.compareTo(r) } - val delete = if (candidates.size > numberOfEpisodesToDelete) { - candidates.subList(0, numberOfEpisodesToDelete) - } else { - candidates - } + val delete = if (candidates.size > numberOfEpisodesToDelete) candidates.subList(0, numberOfEpisodesToDelete) else candidates for (item in delete) { try { @@ -56,10 +49,7 @@ class APQueueCleanupAlgorithm : EpisodeCleanupAlgorithm() { val counter = delete.size - - Log.i(TAG, String.format(Locale.US, - "Auto-delete deleted %d episodes (%d requested)", counter, - numberOfEpisodesToDelete)) + Log.i(TAG, String.format(Locale.US, "Auto-delete deleted %d episodes (%d requested)", counter, numberOfEpisodesToDelete)) return counter } @@ -70,12 +60,8 @@ class APQueueCleanupAlgorithm : EpisodeCleanupAlgorithm() { val downloadedItems = getEpisodes(0, Int.MAX_VALUE, FeedItemFilter(FeedItemFilter.DOWNLOADED), SortOrder.DATE_NEW_OLD) for (item in downloadedItems) { - if (item.hasMedia() - && item.media!!.isDownloaded() - && !item.isTagged(FeedItem.TAG_QUEUE) - && !item.isTagged(FeedItem.TAG_FAVORITE)) { + if (item.hasMedia() && item.media!!.isDownloaded() && !item.isTagged(FeedItem.TAG_QUEUE) && !item.isTagged(FeedItem.TAG_FAVORITE)) candidates.add(item) - } } return candidates } diff --git a/app/src/main/java/ac/mdiq/podcini/storage/AutomaticDownloadAlgorithm.kt b/app/src/main/java/ac/mdiq/podcini/storage/AutomaticDownloadAlgorithm.kt index 67346de2..c36299b3 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/AutomaticDownloadAlgorithm.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/AutomaticDownloadAlgorithm.kt @@ -54,22 +54,16 @@ open class AutomaticDownloadAlgorithm { candidates.addAll(queue) for (newItem in newItems) { val feedPrefs = newItem.feed!!.preferences - if (feedPrefs!!.autoDownload && !candidates.contains(newItem) && feedPrefs.filter.shouldAutoDownload(newItem)) { + if (feedPrefs!!.autoDownload && !candidates.contains(newItem) && feedPrefs.filter.shouldAutoDownload(newItem)) candidates.add(newItem) - } } // filter items that are not auto downloadable val it = candidates.iterator() while (it.hasNext()) { val item = it.next() - if (!item.isAutoDownloadEnabled - || item.isDownloaded - || !item.hasMedia() - || isPlaying(item.media) - || item.feed!!.isLocalFeed) { + if (!item.isAutoDownloadEnabled || item.isDownloaded || !item.hasMedia() || isPlaying(item.media) || item.feed!!.isLocalFeed) it.remove() - } } val autoDownloadableEpisodes = candidates.size @@ -78,11 +72,8 @@ open class AutomaticDownloadAlgorithm { val cacheIsUnlimited = episodeCacheSize == UserPreferences.EPISODE_CACHE_SIZE_UNLIMITED val episodeCacheSize = episodeCacheSize val episodeSpaceLeft = - if (cacheIsUnlimited || episodeCacheSize >= downloadedEpisodes + autoDownloadableEpisodes) { - autoDownloadableEpisodes - } else { - episodeCacheSize - (downloadedEpisodes - deletedEpisodes) - } + if (cacheIsUnlimited || episodeCacheSize >= downloadedEpisodes + autoDownloadableEpisodes) autoDownloadableEpisodes + else episodeCacheSize - (downloadedEpisodes - deletedEpisodes) val itemsToDownload: List = candidates.subList(0, episodeSpaceLeft) if (itemsToDownload.isNotEmpty()) { diff --git a/app/src/main/java/ac/mdiq/podcini/storage/DBReader.kt b/app/src/main/java/ac/mdiq/podcini/storage/DBReader.kt index ac237872..9db74ad6 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/DBReader.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/DBReader.kt @@ -95,9 +95,7 @@ object DBReader { val result: MutableList = ArrayList(cursor.count) while (cursor.moveToNext()) { val url = cursor.getString(1) - if (url != null && !url.startsWith(Feed.PREFIX_LOCAL_FOLDER)) { - result.add(url) - } + if (url != null && !url.startsWith(Feed.PREFIX_LOCAL_FOLDER)) result.add(url) } return result } @@ -124,12 +122,8 @@ object DBReader { val queueIds = getQueueIDList() for (item in items) { - if (favoriteIds.contains(item.id)) { - item.addTag(FeedItem.TAG_FAVORITE) - } - if (queueIds.contains(item.id)) { - item.addTag(FeedItem.TAG_QUEUE) - } + if (favoriteIds.contains(item.id)) item.addTag(FeedItem.TAG_FAVORITE) + if (queueIds.contains(item.id)) item.addTag(FeedItem.TAG_QUEUE) } } @@ -219,9 +213,7 @@ object DBReader { do { val item = FeedItemCursorMapper.convert(cursor) result.add(item) - if (!cursor.isNull(indexMediaId)) { - item.setMedia(FeedMediaCursorMapper.convert(cursor)) - } + if (!cursor.isNull(indexMediaId)) item.setMedia(FeedMediaCursorMapper.convert(cursor)) } while (cursor.moveToNext()) } return result @@ -329,9 +321,7 @@ object DBReader { adapter.open() try { adapter.getEpisodeCountCursor(filter).use { cursor -> - if (cursor.moveToFirst()) { - return cursor.getInt(0) - } + if (cursor.moveToFirst()) return cursor.getInt(0) return -1 } } finally { @@ -411,8 +401,7 @@ object DBReader { adapter.open() try { adapter.getDownloadLogCursor(DOWNLOAD_LOG_SIZE).use { cursor -> - val downloadLog: MutableList = - ArrayList(cursor.count) + val downloadLog: MutableList = ArrayList(cursor.count) while (cursor.moveToNext()) { downloadLog.add(convert(cursor)) } @@ -479,11 +468,8 @@ object DBReader { var feed: Feed? = null if (cursor.moveToNext()) { feed = extractFeedFromCursorRow(cursor) - if (filtered) { - feed.items = getFeedItemList(feed, feed.itemFilter).toMutableList() - } else { - feed.items = getFeedItemList(feed).toMutableList() - } + if (filtered) feed.items = getFeedItemList(feed, feed.itemFilter).toMutableList() + else feed.items = getFeedItemList(feed).toMutableList() } else { Log.e(TAG, "getFeed could not find feed with id $feedId") } @@ -586,13 +572,9 @@ object DBReader { private fun getFeedItemByGuidOrEpisodeUrl(guid: String?, episodeUrl: String, adapter: PodDBAdapter?): FeedItem? { adapter?.getFeedItemCursor(guid, episodeUrl)?.use { cursor -> - if (!cursor.moveToNext()) { - return null - } + if (!cursor.moveToNext()) return null val list = extractItemlistFromCursor(adapter, cursor) - if (list.isNotEmpty()) { - return list[0] - } + if (list.isNotEmpty()) return list[0] return null } return null @@ -622,11 +604,7 @@ object DBReader { if (cursor.moveToFirst()) { val username = cursor.getString(0) val password = cursor.getString(1) - credentials = if (!username.isNullOrEmpty() && password != null) { - "$username:$password" - } else { - "" - } + credentials = if (!username.isNullOrEmpty() && password != null) "$username:$password" else "" } else { credentials = "" } @@ -731,9 +709,8 @@ object DBReader { adapter.open() try { adapter.getSingleFeedMediaCursor(mediaId).use { mediaCursor -> - if (!mediaCursor.moveToFirst()) { - return null - } + if (!mediaCursor.moveToFirst()) return null + val indexFeedItem = mediaCursor.getColumnIndex(PodDBAdapter.KEY_FEEDITEM) val itemId = mediaCursor.getLong(indexFeedItem) val media = FeedMediaCursorMapper.convert(mediaCursor) @@ -818,12 +795,10 @@ object DBReader { val episodesDownloadCount = cursor.getString(indexNumDownloaded).toLong() val oldestDate = cursor.getString(indexOldestDate).toLong() - if (episodes > 0 && oldestDate < Long.MAX_VALUE) { + if (episodes > 0 && oldestDate < Long.MAX_VALUE) result.oldestDate = min(result.oldestDate.toDouble(), oldestDate.toDouble()).toLong() - } - result.feedTime.add(StatisticsItem(feed, feedTotalTime, feedPlayedTime, episodes, - episodesStarted, totalDownloadSize, episodesDownloadCount)) + result.feedTime.add(StatisticsItem(feed, feedTotalTime, feedPlayedTime, episodes, episodesStarted, totalDownloadSize, episodesDownloadCount)) } } adapter.close() @@ -868,16 +843,10 @@ object DBReader { val counterLhs = (if (feedCounters.containsKey(lhs.id)) feedCounters[lhs.id]!! else 0).toLong() val counterRhs = (if (feedCounters.containsKey(rhs.id)) feedCounters[rhs.id]!! else 0).toLong() when { - counterLhs > counterRhs -> { - // reverse natural order: podcast with most unplayed episodes first - return@Comparator -1 - } - counterLhs == counterRhs -> { - return@Comparator lhs.title?.compareTo(rhs.title!!, ignoreCase = true) ?: -1 - } - else -> { - return@Comparator 1 - } + // reverse natural order: podcast with most unplayed episodes first + counterLhs > counterRhs -> return@Comparator -1 + counterLhs == counterRhs -> return@Comparator lhs.title?.compareTo(rhs.title!!, ignoreCase = true) ?: -1 + else -> return@Comparator 1 } } } @@ -886,15 +855,9 @@ object DBReader { val t1 = lhs.title val t2 = rhs.title when { - t1 == null -> { - return@Comparator 1 - } - t2 == null -> { - return@Comparator -1 - } - else -> { - return@Comparator t1.compareTo(t2, ignoreCase = true) - } + t1 == null -> return@Comparator 1 + t2 == null -> return@Comparator -1 + else -> return@Comparator t1.compareTo(t2, ignoreCase = true) } } } @@ -905,16 +868,10 @@ object DBReader { val counterLhs = (if (playedCounters.containsKey(lhs.id)) playedCounters[lhs.id] else 0)!!.toLong() val counterRhs = (if (playedCounters.containsKey(rhs.id)) playedCounters[rhs.id] else 0)!!.toLong() when { - counterLhs > counterRhs -> { - // podcast with most played episodes first - return@Comparator -1 - } - counterLhs == counterRhs -> { - return@Comparator lhs.title!!.compareTo(rhs.title!!, ignoreCase = true) - } - else -> { - return@Comparator 1 - } + // podcast with most played episodes first + counterLhs > counterRhs -> return@Comparator -1 + counterLhs == counterRhs -> return@Comparator lhs.title!!.compareTo(rhs.title!!, ignoreCase = true) + else -> return@Comparator 1 } } } @@ -948,8 +905,7 @@ object DBReader { val drawerItem = FeedDrawerItem(feed, feed.id, counter) items.add(drawerItem) } - val result = NavDrawerData(items, queueSize, numNewItems, numDownloadedItems, - feedCounters, EpisodeCleanupAlgorithmFactory.build().getReclaimableItems()) + val result = NavDrawerData(items, queueSize, numNewItems, numDownloadedItems, feedCounters, EpisodeCleanupAlgorithmFactory.build().getReclaimableItems()) adapter.close() return result } diff --git a/app/src/main/java/ac/mdiq/podcini/storage/DBTasks.kt b/app/src/main/java/ac/mdiq/podcini/storage/DBTasks.kt index 45b38fad..c5dce9c1 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/DBTasks.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/DBTasks.kt @@ -61,9 +61,7 @@ import java.util.concurrent.* var feedID: Long = 0 if (cursor.moveToFirst()) { do { - if (cursor.getString(1) == downloadUrl) { - feedID = cursor.getLong(0) - } + if (cursor.getString(1) == downloadUrl) feedID = cursor.getLong(0) } while (cursor.moveToNext()) } cursor.close() @@ -155,9 +153,7 @@ import java.util.concurrent.* private fun searchFeedItemByIdentifyingValue(items: List?, searchItem: FeedItem): FeedItem? { if (items == null) return null for (item in items) { - if (TextUtils.equals(item.identifyingValue, searchItem.identifyingValue)) { - return item - } + if (TextUtils.equals(item.identifyingValue, searchItem.identifyingValue)) return item } return null } @@ -169,9 +165,7 @@ import java.util.concurrent.* private fun searchFeedItemGuessDuplicate(items: List?, searchItem: FeedItem): FeedItem? { if (items == null) return null for (item in items) { - if (FeedItemDuplicateGuesser.seemDuplicates(item, searchItem)) { - return item - } + if (FeedItemDuplicateGuesser.seemDuplicates(item, searchItem)) return item } return null } @@ -286,11 +280,8 @@ import java.util.concurrent.* Log.d(TAG, "Found new item: " + item.title) item.feed = savedFeed - if (idx >= savedFeed.items.size) { - savedFeed.items.add(item) - } else { - savedFeed.items.add(idx, item) - } + if (idx >= savedFeed.items.size) savedFeed.items.add(item) + else savedFeed.items.add(idx, item) } } @@ -319,13 +310,10 @@ import java.util.concurrent.* DBWriter.addNewFeed(context, newFeed).get() // Update with default values that are set in database resultFeed = searchFeedByIdentifyingValueOrID(newFeed) - } else { - DBWriter.setCompleteFeed(savedFeed).get() - } + } else DBWriter.setCompleteFeed(savedFeed).get() + DBReader.updateFeedList(adapter) - if (removeUnlistedItems) { - DBWriter.deleteFeedItems(context, unlistedItems).get() - } + if (removeUnlistedItems) DBWriter.deleteFeedItems(context, unlistedItems).get() } catch (e: InterruptedException) { e.printStackTrace() } catch (e: ExecutionException) { @@ -334,11 +322,8 @@ import java.util.concurrent.* adapter.close() - if (savedFeed != null) { - EventBus.getDefault().post(FeedListUpdateEvent(savedFeed)) - } else { - EventBus.getDefault().post(FeedListUpdateEvent(emptyList())) - } + if (savedFeed != null) EventBus.getDefault().post(FeedListUpdateEvent(savedFeed)) + else EventBus.getDefault().post(FeedListUpdateEvent(emptyList())) return resultFeed } diff --git a/app/src/main/java/ac/mdiq/podcini/storage/DBWriter.kt b/app/src/main/java/ac/mdiq/podcini/storage/DBWriter.kt index 42f6f27b..83c977f2 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/DBWriter.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/DBWriter.kt @@ -93,11 +93,8 @@ import java.util.concurrent.TimeUnit val media = getFeedMedia(mediaId) if (media != null) { val result = deleteFeedMediaSynchronous(context, media) - val item = media.item - if (result && item != null && shouldDeleteRemoveFromQueue()) { - removeQueueItemSynchronous(context, false, item.id) - } + if (result && item != null && shouldDeleteRemoveFromQueue()) removeQueueItemSynchronous(context, false, item.id) } } } @@ -172,9 +169,7 @@ import java.util.concurrent.TimeUnit return runOnDbThread { val feed = getFeed(feedId) ?: return@runOnDbThread // delete stored media files and mark them as read - if (feed.items.isEmpty()) { - getFeedItemList(feed) - } + if (feed.items.isEmpty()) getFeedItemList(feed) deleteFeedItemsSynchronous(context, feed.items) // delete feed @@ -183,9 +178,9 @@ import java.util.concurrent.TimeUnit adapter.removeFeed(feed) adapter.close() - if (!feed.isLocalFeed && feed.download_url != null) { + if (!feed.isLocalFeed && feed.download_url != null) SynchronizationQueueSink.enqueueFeedRemovedIfSynchronizationIsActive(context, feed.download_url!!) - } + EventBus.getDefault().post(FeedListUpdateEvent(feed)) } } @@ -207,9 +202,7 @@ import java.util.concurrent.TimeUnit val queue = getQueue().toMutableList() val removedFromQueue: MutableList = ArrayList() for (item in items) { - if (queue.remove(item)) { - removedFromQueue.add(item) - } + if (queue.remove(item)) removedFromQueue.add(item) if (item.media != null) { if (item.media?.id == currentlyPlayingFeedMediaId) { // Applies to both downloaded and streamed media @@ -218,18 +211,14 @@ import java.util.concurrent.TimeUnit } if (item.feed != null && !item.feed!!.isLocalFeed) { DownloadServiceInterface.get()?.cancel(context, item.media!!) - if (item.media!!.isDownloaded()) { - deleteFeedMediaSynchronous(context, item.media!!) - } + if (item.media!!.isDownloaded()) deleteFeedMediaSynchronous(context, item.media!!) } } } val adapter = getInstance() adapter.open() - if (removedFromQueue.isNotEmpty()) { - adapter.setQueue(queue) - } + if (removedFromQueue.isNotEmpty()) adapter.setQueue(queue) adapter.removeFeedItems(items) adapter.close() @@ -328,9 +317,7 @@ import java.util.concurrent.TimeUnit * @param performAutoDownload True if an auto-download process should be started after the operation * @throws IndexOutOfBoundsException if index < 0 || index >= queue.size() */ - @UnstableApi fun addQueueItemAt(context: Context, itemId: Long, - index: Int, performAutoDownload: Boolean - ): Future<*> { + @UnstableApi fun addQueueItemAt(context: Context, itemId: Long, index: Int, performAutoDownload: Boolean): Future<*> { Log.d(TAG, "addQueueItemAt called") return runOnDbThread { val adapter = getInstance() @@ -346,16 +333,12 @@ import java.util.concurrent.TimeUnit item.addTag(FeedItem.TAG_QUEUE) EventBus.getDefault().post(added(item, index)) EventBus.getDefault().post(updated(item)) - if (item.isNew) { - markItemPlayed(FeedItem.UNPLAYED, item.id) - } + if (item.isNew) markItemPlayed(FeedItem.UNPLAYED, item.id) } } adapter.close() - if (performAutoDownload) { - autodownloadUndownloadedItems(context) - } + if (performAutoDownload) autodownloadUndownloadedItems(context) } } @@ -368,9 +351,7 @@ import java.util.concurrent.TimeUnit Log.d(TAG, "addQueueItem called") val itemIds = LongList(items.size) for (item in items) { - if (!item.hasMedia()) { - continue - } + if (!item.hasMedia()) continue itemIds.add(item.id) item.addTag(FeedItem.TAG_QUEUE) } @@ -385,9 +366,7 @@ import java.util.concurrent.TimeUnit * @param performAutoDownload true if an auto-download process should be started after the operation. * @param itemIds IDs of the FeedItem objects that should be added to the queue. */ - @UnstableApi fun addQueueItem(context: Context, performAutoDownload: Boolean, - vararg itemIds: Long - ): Future<*> { + @UnstableApi fun addQueueItem(context: Context, performAutoDownload: Boolean, vararg itemIds: Long): Future<*> { return addQueueItem(context, performAutoDownload, true, *itemIds) } @@ -400,13 +379,11 @@ import java.util.concurrent.TimeUnit * @param markAsUnplayed true if the items should be marked as unplayed when enqueueing * @param itemIds IDs of the FeedItem objects that should be added to the queue. */ - @UnstableApi fun addQueueItem(context: Context, performAutoDownload: Boolean, - markAsUnplayed: Boolean, vararg itemIds: Long): Future<*> { + @UnstableApi fun addQueueItem(context: Context, performAutoDownload: Boolean, markAsUnplayed: Boolean, vararg itemIds: Long): Future<*> { Log.d(TAG, "addQueueItem(context ...) called") return runOnDbThread { - if (itemIds.isEmpty()) { - return@runOnDbThread - } + if (itemIds.isEmpty()) return@runOnDbThread + val adapter = getInstance() adapter.open() val queue = getQueue(adapter).toMutableList() @@ -429,9 +406,7 @@ import java.util.concurrent.TimeUnit item.addTag(FeedItem.TAG_QUEUE) updatedItems.add(item) queueModified = true - if (item.isNew) { - markAsUnplayedIds.add(item.id) - } + if (item.isNew) markAsUnplayedIds.add(item.id) insertPosition++ } } @@ -443,14 +418,10 @@ import java.util.concurrent.TimeUnit EventBus.getDefault().post(event) } EventBus.getDefault().post(updated(updatedItems)) - if (markAsUnplayed && markAsUnplayedIds.size() > 0) { - markItemPlayed(FeedItem.UNPLAYED, *markAsUnplayedIds.toArray()) - } + if (markAsUnplayed && markAsUnplayedIds.size() > 0) markItemPlayed(FeedItem.UNPLAYED, *markAsUnplayedIds.toArray()) } adapter.close() - if (performAutoDownload) { - autodownloadUndownloadedItems(context) - } + if (performAutoDownload) autodownloadUndownloadedItems(context) } } @@ -462,17 +433,14 @@ import java.util.concurrent.TimeUnit * @param events Replaces the events by a single SORT event if the list has to be sorted automatically. */ private fun applySortOrder(queue: MutableList, events: MutableList) { - if (!isQueueKeepSorted) { - // queue is not in keep sorted mode, there's nothing to do - return - } + // queue is not in keep sorted mode, there's nothing to do + if (!isQueueKeepSorted) return // Sort queue by configured sort order val sortOrder = queueKeepSortedOrder - if (sortOrder == SortOrder.RANDOM) { - // do not shuffle the list on every change - return - } + // do not shuffle the list on every change + if (sortOrder == SortOrder.RANDOM) return + if (sortOrder != null) { val permutor = getPermutor(sortOrder) permutor.reorder(queue) @@ -530,8 +498,7 @@ import java.util.concurrent.TimeUnit if (position >= 0) { val item = getFeedItem(itemId) if (item == null) { - Log.e(TAG, "removeQueueItem - item in queue but somehow cannot be loaded." + - " Item ignored. It should never happen. id:" + itemId) + Log.e(TAG, "removeQueueItem - item in queue but somehow cannot be loaded. Item ignored. It should never happen. id:$itemId") continue } queue.removeAt(position) @@ -549,21 +516,14 @@ import java.util.concurrent.TimeUnit EventBus.getDefault().post(event) } EventBus.getDefault().post(updated(updatedItems)) - } else { - Log.w(TAG, "Queue was not modified by call to removeQueueItem") - } + } else Log.w(TAG, "Queue was not modified by call to removeQueueItem") + adapter.close() - if (performAutoDownload) { - autodownloadUndownloadedItems(context) - } + if (performAutoDownload) autodownloadUndownloadedItems(context) } fun toggleFavoriteItem(item: FeedItem): Future<*> { - return if (item.isTagged(FeedItem.TAG_FAVORITE)) { - removeFavoriteItem(item) - } else { - addFavoriteItem(item) - } + return if (item.isTagged(FeedItem.TAG_FAVORITE)) removeFavoriteItem(item) else addFavoriteItem(item) } fun addFavoriteItem(item: FeedItem): Future<*> { @@ -598,11 +558,8 @@ import java.util.concurrent.TimeUnit return runOnDbThread { val queueIdList = getQueueIDList() val index = queueIdList.indexOf(itemId) - if (index >= 0) { - moveQueueItemHelper(index, 0, broadcastUpdate) - } else { - Log.e(TAG, "moveQueueItemToTop: item not found") - } + if (index >= 0) moveQueueItemHelper(index, 0, broadcastUpdate) + else Log.e(TAG, "moveQueueItemToTop: item not found") } } @@ -616,12 +573,8 @@ import java.util.concurrent.TimeUnit return runOnDbThread { val queueIdList = getQueueIDList() val index = queueIdList.indexOf(itemId) - if (index >= 0) { - moveQueueItemHelper(index, queueIdList.size() - 1, - broadcastUpdate) - } else { - Log.e(TAG, "moveQueueItemToBottom: item not found") - } + if (index >= 0) moveQueueItemHelper(index, queueIdList.size() - 1, broadcastUpdate) + else Log.e(TAG, "moveQueueItemToBottom: item not found") } } @@ -660,15 +613,11 @@ import java.util.concurrent.TimeUnit if (from >= 0 && from < queue.size && to >= 0 && to < queue.size) { val item: FeedItem = queue.removeAt(from) queue.add(to, item) - adapter.setQueue(queue) - if (broadcastUpdate) { - EventBus.getDefault().post(moved(item, to)) - } + if (broadcastUpdate) EventBus.getDefault().post(moved(item, to)) } - } else { - Log.e(TAG, "moveQueueItemHelper: Could not load queue") - } + } else Log.e(TAG, "moveQueueItemHelper: Could not load queue") + adapter.close() } @@ -709,9 +658,7 @@ import java.util.concurrent.TimeUnit adapter.open() adapter.setFeedItemRead(played, *itemIds) adapter.close() - if (broadcastUpdate) { - EventBus.getDefault().post(UnreadItemsUpdateEvent()) - } + if (broadcastUpdate) EventBus.getDefault().post(UnreadItemsUpdateEvent()) } } @@ -728,10 +675,7 @@ import java.util.concurrent.TimeUnit return markItemPlayed(item.id, played, mediaId, resetMediaPosition) } - private fun markItemPlayed(itemId: Long, - played: Int, - mediaId: Long, - resetMediaPosition: Boolean): Future<*> { + private fun markItemPlayed(itemId: Long, played: Int, mediaId: Long, resetMediaPosition: Boolean): Future<*> { return runOnDbThread { val adapter = getInstance() adapter.open() @@ -778,9 +722,8 @@ import java.util.concurrent.TimeUnit adapter.close() for (feed in feeds) { - if (!feed.isLocalFeed && feed.download_url != null) { + if (!feed.isLocalFeed && feed.download_url != null) SynchronizationQueueSink.enqueueFeedAddedIfSynchronizationIsActive(context, feed.download_url!!) - } } val backupManager = BackupManager(context) @@ -897,9 +840,7 @@ import java.util.concurrent.TimeUnit Log.d(TAG, "indexInItemList called") for (i in items.indices) { val item = items[i] - if (item?.id == itemId) { - return i - } + if (item?.id == itemId) return i } return -1 } @@ -949,9 +890,7 @@ import java.util.concurrent.TimeUnit permutor.reorder(queue) adapter.setQueue(queue) - if (broadcastUpdate) { - EventBus.getDefault().post(QueueEvent.sorted(queue)) - } + if (broadcastUpdate) EventBus.getDefault().post(QueueEvent.sorted(queue)) adapter.close() } } @@ -1007,8 +946,6 @@ import java.util.concurrent.TimeUnit if ("DatabaseExecutor" == Thread.currentThread().name) { runnable.run() return Futures.immediateFuture(null) - } else { - return dbExec.submit(runnable) - } + } else return dbExec.submit(runnable) } } diff --git a/app/src/main/java/ac/mdiq/podcini/storage/DatabaseTransporter.kt b/app/src/main/java/ac/mdiq/podcini/storage/DatabaseTransporter.kt index 7cd377c3..93c930b8 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/DatabaseTransporter.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/DatabaseTransporter.kt @@ -59,12 +59,8 @@ object DatabaseTransporter { dst.transferFrom(src, 0, srcSize) val newDstSize = dst.size() - if (newDstSize != srcSize) { - throw IOException(String.format( - "Unable to write entire database. Expected to write %s, but wrote %s.", - Formatter.formatShortFileSize(context, srcSize), - Formatter.formatShortFileSize(context, newDstSize))) - } + if (newDstSize != srcSize) + throw IOException(String.format("Unable to write entire database. Expected to write %s, but wrote %s.", Formatter.formatShortFileSize(context, srcSize), Formatter.formatShortFileSize(context, newDstSize))) } else { throw IOException("Can not access current database") } @@ -85,18 +81,15 @@ object DatabaseTransporter { inputStream = context.contentResolver.openInputStream(inputUri!!) FileUtils.copyInputStreamToFile(inputStream, tempDB) - val db = SQLiteDatabase.openDatabase(tempDB.absolutePath, - null, SQLiteDatabase.OPEN_READONLY) - if (db.version > PodDBAdapter.VERSION) { - throw IOException(context.getString(R.string.import_no_downgrade)) - } + val db = SQLiteDatabase.openDatabase(tempDB.absolutePath, null, SQLiteDatabase.OPEN_READONLY) + if (db.version > PodDBAdapter.VERSION) throw IOException(context.getString(R.string.import_no_downgrade)) + db.close() val currentDB = context.getDatabasePath(PodDBAdapter.DATABASE_NAME) val success = currentDB.delete() - if (!success) { - throw IOException("Unable to delete old database") - } + if (!success) throw IOException("Unable to delete old database") + FileUtils.moveFile(tempDB, currentDB) } catch (e: IOException) { Log.e(TAG, Log.getStackTraceString(e)) diff --git a/app/src/main/java/ac/mdiq/podcini/storage/EpisodeCleanupAlgorithm.kt b/app/src/main/java/ac/mdiq/podcini/storage/EpisodeCleanupAlgorithm.kt index acfcc3bd..d6d0ee82 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/EpisodeCleanupAlgorithm.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/EpisodeCleanupAlgorithm.kt @@ -51,13 +51,9 @@ abstract class EpisodeCleanupAlgorithm { * @return the number of episodes to delete in order to make room */ fun getNumEpisodesToCleanup(amountOfRoomNeeded: Int): Int { - if (amountOfRoomNeeded >= 0 - && episodeCacheSize != UserPreferences.EPISODE_CACHE_SIZE_UNLIMITED) { + if (amountOfRoomNeeded >= 0 && episodeCacheSize != UserPreferences.EPISODE_CACHE_SIZE_UNLIMITED) { val downloadedEpisodes = getTotalEpisodeCount(FeedItemFilter(FeedItemFilter.DOWNLOADED)) - if (downloadedEpisodes + amountOfRoomNeeded >= episodeCacheSize) { - return (downloadedEpisodes + amountOfRoomNeeded - - episodeCacheSize) - } + if (downloadedEpisodes + amountOfRoomNeeded >= episodeCacheSize) return (downloadedEpisodes + amountOfRoomNeeded - episodeCacheSize) } return 0 } diff --git a/app/src/main/java/ac/mdiq/podcini/storage/EpisodeCleanupAlgorithmFactory.kt b/app/src/main/java/ac/mdiq/podcini/storage/EpisodeCleanupAlgorithmFactory.kt index f77822d9..c743b40d 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/EpisodeCleanupAlgorithmFactory.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/EpisodeCleanupAlgorithmFactory.kt @@ -7,9 +7,8 @@ import ac.mdiq.podcini.preferences.UserPreferences.isEnableAutodownload object EpisodeCleanupAlgorithmFactory { @JvmStatic fun build(): EpisodeCleanupAlgorithm { - if (!isEnableAutodownload) { - return APNullCleanupAlgorithm() - } + if (!isEnableAutodownload) return APNullCleanupAlgorithm() + return when (val cleanupValue = episodeCleanupValue) { UserPreferences.EPISODE_CLEANUP_EXCEPT_FAVORITE -> ExceptFavoriteCleanupAlgorithm() UserPreferences.EPISODE_CLEANUP_QUEUE -> APQueueCleanupAlgorithm() diff --git a/app/src/main/java/ac/mdiq/podcini/storage/ExceptFavoriteCleanupAlgorithm.kt b/app/src/main/java/ac/mdiq/podcini/storage/ExceptFavoriteCleanupAlgorithm.kt index a7e62a0e..38f5c7b6 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/ExceptFavoriteCleanupAlgorithm.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/ExceptFavoriteCleanupAlgorithm.kt @@ -9,6 +9,8 @@ import ac.mdiq.podcini.storage.model.feed.FeedItemFilter import ac.mdiq.podcini.storage.model.feed.SortOrder import ac.mdiq.podcini.preferences.UserPreferences import ac.mdiq.podcini.preferences.UserPreferences.episodeCacheSize +import androidx.annotation.OptIn +import androidx.media3.common.util.UnstableApi import java.util.* import java.util.concurrent.ExecutionException @@ -25,26 +27,18 @@ class ExceptFavoriteCleanupAlgorithm : EpisodeCleanupAlgorithm() { return candidates.size } - public override fun performCleanup(context: Context, numberOfEpisodesToDelete: Int): Int { + @OptIn(UnstableApi::class) public override fun performCleanup(context: Context, numberOfEpisodesToDelete: Int): Int { var candidates = candidates // in the absence of better data, we'll sort by item publication date candidates = candidates.sortedWith { lhs: FeedItem, rhs: FeedItem -> val l = lhs.getPubDate() val r = rhs.getPubDate() - if (l != null && r != null) { - return@sortedWith l.compareTo(r) - } else { - // No date - compare by id which should be always incremented - return@sortedWith lhs.id.compareTo(rhs.id) - } + if (l != null && r != null) return@sortedWith l.compareTo(r) + else return@sortedWith lhs.id.compareTo(rhs.id) // No date - compare by id which should be always incremented } - val delete = if (candidates.size > numberOfEpisodesToDelete) { - candidates.subList(0, numberOfEpisodesToDelete) - } else { - candidates - } + val delete = if (candidates.size > numberOfEpisodesToDelete) candidates.subList(0, numberOfEpisodesToDelete) else candidates for (item in delete) { try { @@ -57,9 +51,7 @@ class ExceptFavoriteCleanupAlgorithm : EpisodeCleanupAlgorithm() { } val counter = delete.size - Log.i(TAG, String.format(Locale.US, - "Auto-delete deleted %d episodes (%d requested)", counter, - numberOfEpisodesToDelete)) + Log.i(TAG, String.format(Locale.US, "Auto-delete deleted %d episodes (%d requested)", counter, numberOfEpisodesToDelete)) return counter } @@ -67,14 +59,9 @@ class ExceptFavoriteCleanupAlgorithm : EpisodeCleanupAlgorithm() { private val candidates: List get() { val candidates: MutableList = ArrayList() - val downloadedItems = getEpisodes(0, Int.MAX_VALUE, - FeedItemFilter(FeedItemFilter.DOWNLOADED), SortOrder.DATE_NEW_OLD) + val downloadedItems = getEpisodes(0, Int.MAX_VALUE, FeedItemFilter(FeedItemFilter.DOWNLOADED), SortOrder.DATE_NEW_OLD) for (item in downloadedItems) { - if (item.hasMedia() - && item.media!!.isDownloaded() - && !item.isTagged(FeedItem.TAG_FAVORITE)) { - candidates.add(item) - } + if (item.hasMedia() && item.media!!.isDownloaded() && !item.isTagged(FeedItem.TAG_FAVORITE)) candidates.add(item) } return candidates } @@ -83,9 +70,7 @@ class ExceptFavoriteCleanupAlgorithm : EpisodeCleanupAlgorithm() { val cacheSize = episodeCacheSize if (cacheSize != UserPreferences.EPISODE_CACHE_SIZE_UNLIMITED) { val downloadedEpisodes = getTotalEpisodeCount(FeedItemFilter(FeedItemFilter.DOWNLOADED)) - if (downloadedEpisodes > cacheSize) { - return downloadedEpisodes - cacheSize - } + if (downloadedEpisodes > cacheSize) return downloadedEpisodes - cacheSize } return 0 } diff --git a/app/src/main/java/ac/mdiq/podcini/storage/FeedItemDuplicateGuesser.kt b/app/src/main/java/ac/mdiq/podcini/storage/FeedItemDuplicateGuesser.kt index c9893c99..eabf414a 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/FeedItemDuplicateGuesser.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/FeedItemDuplicateGuesser.kt @@ -15,34 +15,25 @@ import kotlin.math.abs object FeedItemDuplicateGuesser { @JvmStatic fun seemDuplicates(item1: FeedItem, item2: FeedItem): Boolean { - if (sameAndNotEmpty(item1.itemIdentifier, item2.itemIdentifier)) { - return true - } + if (sameAndNotEmpty(item1.itemIdentifier, item2.itemIdentifier)) return true + val media1 = item1.media val media2 = item2.media - if (media1 == null || media2 == null) { - return false - } - if (sameAndNotEmpty(media1.getStreamUrl(), media2.getStreamUrl())) { - return true - } - return (titlesLookSimilar(item1, item2) - && datesLookSimilar(item1, item2) - && durationsLookSimilar(media1, media2) - && mimeTypeLooksSimilar(media1, media2)) + if (media1 == null || media2 == null) return false + + if (sameAndNotEmpty(media1.getStreamUrl(), media2.getStreamUrl())) return true + + return (titlesLookSimilar(item1, item2) && datesLookSimilar(item1, item2) && durationsLookSimilar(media1, media2) && mimeTypeLooksSimilar(media1, media2)) } private fun sameAndNotEmpty(string1: String?, string2: String?): Boolean { - if (string1.isNullOrEmpty() || string2.isNullOrEmpty()) { - return false - } + if (string1.isNullOrEmpty() || string2.isNullOrEmpty()) return false return string1 == string2 } private fun datesLookSimilar(item1: FeedItem, item2: FeedItem): Boolean { - if (item1.getPubDate() == null || item2.getPubDate() == null) { - return false - } + if (item1.getPubDate() == null || item2.getPubDate() == null) return false + val dateFormat = DateFormat.getDateInstance(DateFormat.SHORT, Locale.US) // MM/DD/YY val dateOriginal = dateFormat.format(item2.getPubDate()!!) val dateNew = dateFormat.format(item1.getPubDate()!!) @@ -56,9 +47,8 @@ object FeedItemDuplicateGuesser { private fun mimeTypeLooksSimilar(media1: FeedMedia, media2: FeedMedia): Boolean { var mimeType1 = media1.mime_type var mimeType2 = media2.mime_type - if (mimeType1 == null || mimeType2 == null) { - return true - } + if (mimeType1 == null || mimeType2 == null) return true + if (mimeType1.contains("/") && mimeType2.contains("/")) { mimeType1 = mimeType1.substring(0, mimeType1.indexOf("/")) mimeType2 = mimeType2.substring(0, mimeType2.indexOf("/")) @@ -71,9 +61,8 @@ object FeedItemDuplicateGuesser { } private fun canonicalizeTitle(title: String?): String { - if (title == null) { - return "" - } + if (title == null) return "" + return title .trim { it <= ' ' } .replace('“', '"') diff --git a/app/src/main/java/ac/mdiq/podcini/storage/ItemEnqueuePositionCalculator.kt b/app/src/main/java/ac/mdiq/podcini/storage/ItemEnqueuePositionCalculator.kt index 996a4299..ba482a0c 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/ItemEnqueuePositionCalculator.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/ItemEnqueuePositionCalculator.kt @@ -27,8 +27,7 @@ class ItemEnqueuePositionCalculator(private val enqueueLocation: EnqueueLocation return getPositionOfFirstNonDownloadingItem(0, curQueue) EnqueueLocation.AFTER_CURRENTLY_PLAYING -> { val currentlyPlayingPosition = getCurrentlyPlayingPosition(curQueue, currentPlaying) - return getPositionOfFirstNonDownloadingItem( - currentlyPlayingPosition + 1, curQueue) + return getPositionOfFirstNonDownloadingItem(currentlyPlayingPosition + 1, curQueue) } EnqueueLocation.RANDOM -> { val random = Random() @@ -41,9 +40,7 @@ class ItemEnqueuePositionCalculator(private val enqueueLocation: EnqueueLocation private fun getPositionOfFirstNonDownloadingItem(startPosition: Int, curQueue: List): Int { val curQueueSize = curQueue.size for (i in startPosition until curQueueSize) { - if (!isItemAtPositionDownloading(i, curQueue)) { - return i - } // else continue to search; + if (!isItemAtPositionDownloading(i, curQueue)) return i } return curQueueSize } @@ -59,17 +56,12 @@ class ItemEnqueuePositionCalculator(private val enqueueLocation: EnqueueLocation } companion object { - private fun getCurrentlyPlayingPosition(curQueue: List, - currentPlaying: Playable? - ): Int { - if (currentPlaying !is FeedMedia) { - return -1 - } + private fun getCurrentlyPlayingPosition(curQueue: List, currentPlaying: Playable?): Int { + if (currentPlaying !is FeedMedia) return -1 + val curPlayingItemId = currentPlaying.item!!.id for (i in curQueue.indices) { - if (curPlayingItemId == curQueue[i].id) { - return i - } + if (curPlayingItemId == curQueue[i].id) return i } return -1 } diff --git a/app/src/main/java/ac/mdiq/podcini/storage/asynctask/DocumentFileExportWorker.kt b/app/src/main/java/ac/mdiq/podcini/storage/asynctask/DocumentFileExportWorker.kt index 28f9bbfb..b5fa5184 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/asynctask/DocumentFileExportWorker.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/asynctask/DocumentFileExportWorker.kt @@ -15,10 +15,8 @@ import java.nio.charset.Charset /** * Writes an OPML file into the user selected export directory in the background. */ -class DocumentFileExportWorker(private val exportWriter: ExportWriter, - private val context: Context, - private val outputFileUri: Uri -) { +class DocumentFileExportWorker(private val exportWriter: ExportWriter, private val context: Context, private val outputFileUri: Uri) { + fun exportObservable(): Observable { val output = DocumentFile.fromSingleUri(context, outputFileUri) return Observable.create { subscriber: ObservableEmitter -> diff --git a/app/src/main/java/ac/mdiq/podcini/storage/asynctask/ExportWorker.kt b/app/src/main/java/ac/mdiq/podcini/storage/asynctask/ExportWorker.kt index 55f49771..966baf85 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/asynctask/ExportWorker.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/asynctask/ExportWorker.kt @@ -16,10 +16,7 @@ import java.nio.charset.Charset /** * Writes an OPML file into the export directory in the background. */ -class ExportWorker private constructor(private val exportWriter: ExportWriter, - private val output: File, - private val context: Context -) { +class ExportWorker private constructor(private val exportWriter: ExportWriter, private val output: File, private val context: Context) { constructor(exportWriter: ExportWriter, context: Context) : this(exportWriter, File(getDataFolder(EXPORT_DIR), DEFAULT_OUTPUT_NAME + "." + exportWriter.fileExtension()), context) diff --git a/app/src/main/java/ac/mdiq/podcini/storage/backup/OpmlBackupAgent.kt b/app/src/main/java/ac/mdiq/podcini/storage/backup/OpmlBackupAgent.kt index 7f173e53..e85a9450 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/backup/OpmlBackupAgent.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/backup/OpmlBackupAgent.kt @@ -13,6 +13,8 @@ import ac.mdiq.podcini.storage.DBReader.getFeedList import ac.mdiq.podcini.storage.DBTasks.updateFeed import ac.mdiq.podcini.net.download.FeedUpdateManager.runOnce import ac.mdiq.podcini.storage.model.feed.Feed +import androidx.annotation.OptIn +import androidx.media3.common.util.UnstableApi import org.apache.commons.io.IOUtils import org.xmlpull.v1.XmlPullParserException import java.io.* @@ -37,10 +39,7 @@ class OpmlBackupAgent : BackupAgentHelper() { */ private var mChecksum: ByteArray = byteArrayOf() - override fun performBackup(oldState: ParcelFileDescriptor, - data: BackupDataOutput, - newState: ParcelFileDescriptor - ) { + override fun performBackup(oldState: ParcelFileDescriptor, data: BackupDataOutput, newState: ParcelFileDescriptor) { Log.d(TAG, "Performing backup") val byteStream = ByteArrayOutputStream() var digester: MessageDigest? = null @@ -48,8 +47,7 @@ class OpmlBackupAgent : BackupAgentHelper() { try { digester = MessageDigest.getInstance("MD5") - writer = OutputStreamWriter(DigestOutputStream(byteStream, digester), - Charset.forName("UTF-8")) + writer = OutputStreamWriter(DigestOutputStream(byteStream, digester), Charset.forName("UTF-8")) } catch (e: NoSuchAlgorithmException) { writer = OutputStreamWriter(byteStream, Charset.forName("UTF-8")) } @@ -94,7 +92,7 @@ class OpmlBackupAgent : BackupAgentHelper() { } } - override fun restoreEntity(data: BackupDataInputStream) { + @OptIn(UnstableApi::class) override fun restoreEntity(data: BackupDataInputStream) { Log.d(TAG, "Backup restore") if (OPML_ENTITY_KEY != data.key) { @@ -107,8 +105,7 @@ class OpmlBackupAgent : BackupAgentHelper() { try { digester = MessageDigest.getInstance("MD5") - reader = InputStreamReader(DigestInputStream(data, digester), - Charset.forName("UTF-8")) + reader = InputStreamReader(DigestInputStream(data, digester), Charset.forName("UTF-8")) } catch (e: NoSuchAlgorithmException) { reader = InputStreamReader(data, Charset.forName("UTF-8")) } @@ -142,9 +139,7 @@ class OpmlBackupAgent : BackupAgentHelper() { * @param checksum */ private fun writeNewStateDescription(newState: ParcelFileDescriptor, checksum: ByteArray?) { - if (checksum == null) { - return - } + if (checksum == null) return try { val outState = FileOutputStream(newState.fileDescriptor) diff --git a/app/src/main/java/ac/mdiq/podcini/storage/database/DBUpgrader.kt b/app/src/main/java/ac/mdiq/podcini/storage/database/DBUpgrader.kt index 8c7dfc69..96a004a9 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/database/DBUpgrader.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/database/DBUpgrader.kt @@ -13,44 +13,33 @@ internal object DBUpgrader { */ fun upgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { if (oldVersion <= 1) { - db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS + " ADD COLUMN " - + PodDBAdapter.KEY_TYPE + " TEXT") + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS + " ADD COLUMN " + PodDBAdapter.KEY_TYPE + " TEXT") } if (oldVersion <= 2) { - db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_SIMPLECHAPTERS - + " ADD COLUMN " + PodDBAdapter.KEY_LINK + " TEXT") + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_SIMPLECHAPTERS + " ADD COLUMN " + PodDBAdapter.KEY_LINK + " TEXT") } if (oldVersion <= 3) { - db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS - + " ADD COLUMN " + PodDBAdapter.KEY_ITEM_IDENTIFIER + " TEXT") + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS + " ADD COLUMN " + PodDBAdapter.KEY_ITEM_IDENTIFIER + " TEXT") } if (oldVersion <= 4) { - db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS + " ADD COLUMN " - + PodDBAdapter.KEY_FEED_IDENTIFIER + " TEXT") + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS + " ADD COLUMN " + PodDBAdapter.KEY_FEED_IDENTIFIER + " TEXT") } if (oldVersion <= 5) { - db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_DOWNLOAD_LOG - + " ADD COLUMN " + PodDBAdapter.KEY_REASON_DETAILED + " TEXT") - db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_DOWNLOAD_LOG - + " ADD COLUMN " + PodDBAdapter.KEY_DOWNLOADSTATUS_TITLE + " TEXT") + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_DOWNLOAD_LOG + " ADD COLUMN " + PodDBAdapter.KEY_REASON_DETAILED + " TEXT") + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_DOWNLOAD_LOG + " ADD COLUMN " + PodDBAdapter.KEY_DOWNLOADSTATUS_TITLE + " TEXT") } if (oldVersion <= 6) { - db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_SIMPLECHAPTERS - + " ADD COLUMN type INTEGER") + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_SIMPLECHAPTERS + " ADD COLUMN type INTEGER") } if (oldVersion <= 7) { - db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA - + " ADD COLUMN " + PodDBAdapter.KEY_PLAYBACK_COMPLETION_DATE - + " INTEGER") + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA + " ADD COLUMN " + PodDBAdapter.KEY_PLAYBACK_COMPLETION_DATE + " INTEGER") } if (oldVersion <= 8) { val KEY_ID_POSITION = 0 val KEY_MEDIA_POSITION = 1 // Add feeditem column to feedmedia table - db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA - + " ADD COLUMN " + PodDBAdapter.KEY_FEEDITEM - + " INTEGER") + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA + " ADD COLUMN " + PodDBAdapter.KEY_FEEDITEM + " INTEGER") val feeditemCursor = db.query(PodDBAdapter.TABLE_NAME_FEED_ITEMS, arrayOf(PodDBAdapter.KEY_ID, PodDBAdapter.KEY_MEDIA), "? > 0", arrayOf(PodDBAdapter.KEY_MEDIA), null, null, null) @@ -72,42 +61,25 @@ internal object DBUpgrader { feeditemCursor.close() } if (oldVersion <= 9) { - db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS - + " ADD COLUMN " + PodDBAdapter.KEY_AUTO_DOWNLOAD_ENABLED - + " INTEGER DEFAULT 1") + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS + " ADD COLUMN " + PodDBAdapter.KEY_AUTO_DOWNLOAD_ENABLED + " INTEGER DEFAULT 1") } if (oldVersion <= 10) { - db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS - + " ADD COLUMN flattr_status" - + " INTEGER") - db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS - + " ADD COLUMN flattr_status" - + " INTEGER") - db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA - + " ADD COLUMN " + PodDBAdapter.KEY_PLAYED_DURATION - + " INTEGER") + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS + " ADD COLUMN flattr_status" + " INTEGER") + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS + " ADD COLUMN flattr_status" + " INTEGER") + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA + " ADD COLUMN " + PodDBAdapter.KEY_PLAYED_DURATION + " INTEGER") } if (oldVersion <= 11) { - db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS - + " ADD COLUMN " + PodDBAdapter.KEY_USERNAME - + " TEXT") - db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS - + " ADD COLUMN " + PodDBAdapter.KEY_PASSWORD - + " TEXT") - db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS - + " ADD COLUMN image" - + " INTEGER") + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS + " ADD COLUMN " + PodDBAdapter.KEY_USERNAME + " TEXT") + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS + " ADD COLUMN " + PodDBAdapter.KEY_PASSWORD + " TEXT") + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS + " ADD COLUMN image" + " INTEGER") } if (oldVersion <= 12) { - db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS - + " ADD COLUMN " + PodDBAdapter.KEY_IS_PAGED + " INTEGER DEFAULT 0") - db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS - + " ADD COLUMN " + PodDBAdapter.KEY_NEXT_PAGE_LINK + " TEXT") + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS + " ADD COLUMN " + PodDBAdapter.KEY_IS_PAGED + " INTEGER DEFAULT 0") + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS + " ADD COLUMN " + PodDBAdapter.KEY_NEXT_PAGE_LINK + " TEXT") } if (oldVersion <= 13) { // remove duplicate rows in "Chapters" table that were created because of a bug. - db.execSQL(String.format("DELETE FROM %s WHERE %s NOT IN " + - "(SELECT MIN(%s) as %s FROM %s GROUP BY %s,%s,%s,%s,%s)", + db.execSQL(String.format("DELETE FROM %s WHERE %s NOT IN " + "(SELECT MIN(%s) as %s FROM %s GROUP BY %s,%s,%s,%s,%s)", PodDBAdapter.TABLE_NAME_SIMPLECHAPTERS, PodDBAdapter.KEY_ID, PodDBAdapter.KEY_ID, @@ -120,8 +92,7 @@ internal object DBUpgrader { "type")) } if (oldVersion <= 14) { - db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS - + " ADD COLUMN " + PodDBAdapter.KEY_AUTO_DOWNLOAD_ENABLED + " INTEGER") + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS + " ADD COLUMN " + PodDBAdapter.KEY_AUTO_DOWNLOAD_ENABLED + " INTEGER") db.execSQL("UPDATE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS + " SET " + PodDBAdapter.KEY_AUTO_DOWNLOAD_ENABLED + " = " + "(SELECT " + PodDBAdapter.KEY_AUTO_DOWNLOAD_ENABLED @@ -129,11 +100,9 @@ internal object DBUpgrader { + " WHERE " + PodDBAdapter.TABLE_NAME_FEEDS + "." + PodDBAdapter.KEY_ID + " = " + PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + PodDBAdapter.KEY_FEED + ")") - db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS - + " ADD COLUMN " + PodDBAdapter.KEY_HIDE + " TEXT") + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS + " ADD COLUMN " + PodDBAdapter.KEY_HIDE + " TEXT") - db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS - + " ADD COLUMN " + PodDBAdapter.KEY_LAST_UPDATE_FAILED + " INTEGER DEFAULT 0") + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS + " ADD COLUMN " + PodDBAdapter.KEY_LAST_UPDATE_FAILED + " INTEGER DEFAULT 0") // create indexes db.execSQL(PodDBAdapter.CREATE_INDEX_FEEDITEMS_FEED) @@ -142,11 +111,8 @@ internal object DBUpgrader { db.execSQL(PodDBAdapter.CREATE_INDEX_SIMPLECHAPTERS_FEEDITEM) } if (oldVersion <= 15) { - db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA - + " ADD COLUMN " + PodDBAdapter.KEY_HAS_EMBEDDED_PICTURE + " INTEGER DEFAULT -1") - db.execSQL("UPDATE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA - + " SET " + PodDBAdapter.KEY_HAS_EMBEDDED_PICTURE + "=0" - + " WHERE " + PodDBAdapter.KEY_DOWNLOADED + "=0") + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA + " ADD COLUMN " + PodDBAdapter.KEY_HAS_EMBEDDED_PICTURE + " INTEGER DEFAULT -1") + db.execSQL("UPDATE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA + " SET " + PodDBAdapter.KEY_HAS_EMBEDDED_PICTURE + "=0" + " WHERE " + PodDBAdapter.KEY_DOWNLOADED + "=0") val c = db.rawQuery("SELECT " + PodDBAdapter.KEY_FILE_URL + " FROM " + PodDBAdapter.TABLE_NAME_FEED_MEDIA + " WHERE " + PodDBAdapter.KEY_DOWNLOADED + "=1 " @@ -188,9 +154,7 @@ internal object DBUpgrader { + PodDBAdapter.TABLE_NAME_FEED_MEDIA + "." + PodDBAdapter.KEY_DOWNLOADED + " = 0 AND " // undownloaded + PodDBAdapter.TABLE_NAME_FEED_MEDIA + "." + PodDBAdapter.KEY_POSITION + " = 0 AND " // not partially played + PodDBAdapter.TABLE_NAME_QUEUE + "." + PodDBAdapter.KEY_ID + " IS NULL") // not in queue - val sql = ("UPDATE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS - + " SET " + PodDBAdapter.KEY_READ + "=" + FeedItem.NEW - + " WHERE " + PodDBAdapter.KEY_ID + " IN (" + selectNew + ")") + val sql = ("UPDATE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS + " SET " + PodDBAdapter.KEY_READ + "=" + FeedItem.NEW + " WHERE " + PodDBAdapter.KEY_ID + " IN (" + selectNew + ")") Log.d("Migration", "SQL: $sql") db.execSQL(sql) } diff --git a/app/src/main/java/ac/mdiq/podcini/storage/database/PodDBAdapter.kt b/app/src/main/java/ac/mdiq/podcini/storage/database/PodDBAdapter.kt index dc1081cf..50221c3d 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/database/PodDBAdapter.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/database/PodDBAdapter.kt @@ -149,19 +149,14 @@ class PodDBAdapter private constructor() { values.put(KEY_HAS_EMBEDDED_PICTURE, media.hasEmbeddedPicture()) values.put(KEY_LAST_PLAYED_TIME, media.getLastPlayedTime()) - if (media.getPlaybackCompletionDate() != null) { - values.put(KEY_PLAYBACK_COMPLETION_DATE, media.getPlaybackCompletionDate()!!.time) - } else { - values.put(KEY_PLAYBACK_COMPLETION_DATE, 0) - } - if (media.item != null) { - values.put(KEY_FEEDITEM, media.item!!.id) - } - if (media.id == 0L) { - media.id = db.insert(TABLE_NAME_FEED_MEDIA, null, values) - } else { - db.update(TABLE_NAME_FEED_MEDIA, values, "$KEY_ID=?", arrayOf(media.id.toString())) - } + if (media.getPlaybackCompletionDate() != null) values.put(KEY_PLAYBACK_COMPLETION_DATE, media.getPlaybackCompletionDate()!!.time) + else values.put(KEY_PLAYBACK_COMPLETION_DATE, 0) + + if (media.item != null) values.put(KEY_FEEDITEM, media.item!!.id) + + if (media.id == 0L) media.id = db.insert(TABLE_NAME_FEED_MEDIA, null, values) + else db.update(TABLE_NAME_FEED_MEDIA, values, "$KEY_ID=?", arrayOf(media.id.toString())) + return media.id } @@ -173,9 +168,7 @@ class PodDBAdapter private constructor() { values.put(KEY_PLAYED_DURATION, media.playedDuration) values.put(KEY_LAST_PLAYED_TIME, media.getLastPlayedTime()) db.update(TABLE_NAME_FEED_MEDIA, values, "$KEY_ID=?", arrayOf(media.id.toString())) - } else { - Log.e(TAG, "setFeedMediaPlaybackInformation: ID of media was 0") - } + } else Log.e(TAG, "setFeedMediaPlaybackInformation: ID of media was 0") } fun setFeedMediaPlaybackCompletionDate(media: FeedMedia) { @@ -184,9 +177,7 @@ class PodDBAdapter private constructor() { values.put(KEY_PLAYBACK_COMPLETION_DATE, media.getPlaybackCompletionDate()!!.time) values.put(KEY_PLAYED_DURATION, media.playedDuration) db.update(TABLE_NAME_FEED_MEDIA, values, "$KEY_ID=?", arrayOf(media.id.toString())) - } else { - Log.e(TAG, "setFeedMediaPlaybackCompletionDate: ID of media was 0") - } + } else Log.e(TAG, "setFeedMediaPlaybackCompletionDate: ID of media was 0") } fun resetAllMediaPlayedDuration() { @@ -217,9 +208,7 @@ class PodDBAdapter private constructor() { updateOrInsertFeedItem(item, false) } } - if (feed.preferences != null) { - setFeedPreferences(feed.preferences!!) - } + if (feed.preferences != null) setFeedPreferences(feed.preferences!!) } db.setTransactionSuccessful() } catch (e: SQLException) { @@ -283,9 +272,8 @@ class PodDBAdapter private constructor() { val values = ContentValues() values.put(KEY_TITLE, item.title) values.put(KEY_LINK, item.link) - if (item.description != null) { - values.put(KEY_DESCRIPTION, item.description) - } + if (item.description != null) values.put(KEY_DESCRIPTION, item.description) + values.put(KEY_PUBDATE, item.getPubDate()!!.time) values.put(KEY_PAYMENT_LINK, item.paymentLink) if (item.feed != null) { @@ -293,15 +281,9 @@ class PodDBAdapter private constructor() { values.put(KEY_FEED, item.feed!!.id) } when { - item.isNew -> { - values.put(KEY_READ, FeedItem.NEW) - } - item.isPlayed() -> { - values.put(KEY_READ, FeedItem.PLAYED) - } - else -> { - values.put(KEY_READ, FeedItem.UNPLAYED) - } + item.isNew -> values.put(KEY_READ, FeedItem.NEW) + item.isPlayed() -> values.put(KEY_READ, FeedItem.PLAYED) + else -> values.put(KEY_READ, FeedItem.UNPLAYED) } values.put(KEY_HAS_CHAPTERS, item.chapters != null || item.hasChapters()) values.put(KEY_ITEM_IDENTIFIER, item.itemIdentifier) @@ -309,17 +291,12 @@ class PodDBAdapter private constructor() { values.put(KEY_IMAGE_URL, item.imageUrl) values.put(KEY_PODCASTINDEX_CHAPTER_URL, item.podcastIndexChapterUrl) - if (item.id == 0L) { - item.id = db.insert(TABLE_NAME_FEED_ITEMS, null, values) - } else { - db.update(TABLE_NAME_FEED_ITEMS, values, "$KEY_ID=?", arrayOf(item.id.toString())) - } - if (item.media != null) { - setMedia(item.media) - } - if (item.chapters != null) { - setChapters(item) - } + if (item.id == 0L) item.id = db.insert(TABLE_NAME_FEED_ITEMS, null, values) + else db.update(TABLE_NAME_FEED_ITEMS, values, "$KEY_ID=?", arrayOf(item.id.toString())) + + if (item.media != null) setMedia(item.media) + if (item.chapters != null) setChapters(item) + return item.id } @@ -376,18 +353,13 @@ class PodDBAdapter private constructor() { values.put(KEY_FEEDITEM, item.id) values.put(KEY_LINK, chapter.link) values.put(KEY_IMAGE_URL, chapter.imageUrl) - if (chapter.id == 0L) { - chapter.id = db.insert(TABLE_NAME_SIMPLECHAPTERS, null, values) - } else { - db.update(TABLE_NAME_SIMPLECHAPTERS, values, "$KEY_ID=?", arrayOf(chapter.id.toString())) - } + if (chapter.id == 0L) chapter.id = db.insert(TABLE_NAME_SIMPLECHAPTERS, null, values) + else db.update(TABLE_NAME_SIMPLECHAPTERS, values, "$KEY_ID=?", arrayOf(chapter.id.toString())) } } fun resetPagedFeedPage(feed: Feed) { - val sql = ("UPDATE " + TABLE_NAME_FEEDS - + " SET " + KEY_NEXT_PAGE_LINK + "=" + KEY_DOWNLOAD_URL - + " WHERE " + KEY_ID + "=" + feed.id) + val sql = ("UPDATE " + TABLE_NAME_FEEDS + " SET " + KEY_NEXT_PAGE_LINK + "=" + KEY_DOWNLOAD_URL + " WHERE " + KEY_ID + "=" + feed.id) db.execSQL(sql) } @@ -416,11 +388,9 @@ class PodDBAdapter private constructor() { values.put(KEY_COMPLETION_DATE, status.getCompletionDate().time) values.put(KEY_REASON_DETAILED, status.reasonDetailed) values.put(KEY_DOWNLOADSTATUS_TITLE, status.title) - if (status.id == 0L) { - status.id = db.insert(TABLE_NAME_DOWNLOAD_LOG, null, values) - } else { - db.update(TABLE_NAME_DOWNLOAD_LOG, values, "$KEY_ID=?", arrayOf(status.id.toString())) - } + if (status.id == 0L) status.id = db.insert(TABLE_NAME_DOWNLOAD_LOG, null, values) + else db.update(TABLE_NAME_DOWNLOAD_LOG, values, "$KEY_ID=?", arrayOf(status.id.toString())) + return status.id } @@ -505,21 +475,17 @@ class PodDBAdapter private constructor() { val itemIds = StringBuilder() for (item in items) { if (item.media != null) { - if (mediaIds.isNotEmpty()) { - mediaIds.append(",") - } + if (mediaIds.isNotEmpty()) mediaIds.append(",") mediaIds.append(item.media!!.id) } - if (itemIds.isNotEmpty()) { - itemIds.append(",") - } + if (itemIds.isNotEmpty()) itemIds.append(",") itemIds.append(item.id) } db.beginTransactionNonExclusive() db.delete(TABLE_NAME_SIMPLECHAPTERS, "$KEY_FEEDITEM IN ($itemIds)", null) - db.delete(TABLE_NAME_DOWNLOAD_LOG, (KEY_FEEDFILETYPE + "=" + FeedMedia.FEEDFILETYPE_FEEDMEDIA - ) + " AND " + KEY_FEEDFILE + " IN (" + mediaIds + ")", null) + db.delete(TABLE_NAME_DOWNLOAD_LOG, (KEY_FEEDFILETYPE + "=" + FeedMedia.FEEDFILETYPE_FEEDMEDIA) + + " AND " + KEY_FEEDFILE + " IN (" + mediaIds + ")", null) db.delete(TABLE_NAME_FEED_MEDIA, "$KEY_ID IN ($mediaIds)", null) db.delete(TABLE_NAME_FEED_ITEMS, "$KEY_ID IN ($itemIds)", null) db.setTransactionSuccessful() @@ -569,9 +535,7 @@ class PodDBAdapter private constructor() { * @return The cursor of the query */ get() { - val query = ("SELECT " + KEYS_FEED - + " FROM " + TABLE_NAME_FEEDS - + " ORDER BY " + TABLE_NAME_FEEDS + "." + KEY_TITLE + " COLLATE NOCASE ASC") + val query = ("SELECT " + KEYS_FEED + " FROM " + TABLE_NAME_FEEDS + " ORDER BY " + TABLE_NAME_FEEDS + "." + KEY_TITLE + " COLLATE NOCASE ASC") return db.rawQuery(query, null) } @@ -587,9 +551,7 @@ class PodDBAdapter private constructor() { fun getItemsOfFeedCursor(feed: Feed, filter: FeedItemFilter?): Cursor { val filterQuery = generateFrom(filter!!) val whereClauseAnd = if ("" == filterQuery) "" else " AND $filterQuery" - val query = (SELECT_FEED_ITEMS_AND_MEDIA - + " WHERE " + TABLE_NAME_FEED_ITEMS + "." + KEY_FEED + "=" + feed.id - + whereClauseAnd) + val query = (SELECT_FEED_ITEMS_AND_MEDIA + " WHERE " + TABLE_NAME_FEED_ITEMS + "." + KEY_FEED + "=" + feed.id + whereClauseAnd) return db.rawQuery(query, null) } @@ -597,17 +559,13 @@ class PodDBAdapter private constructor() { * Return the description and content_encoded of item */ fun getDescriptionOfItem(item: FeedItem): Cursor { - val query = ("SELECT " + KEY_DESCRIPTION - + " FROM " + TABLE_NAME_FEED_ITEMS - + " WHERE " + KEY_ID + "=" + item.id) + val query = ("SELECT " + KEY_DESCRIPTION + " FROM " + TABLE_NAME_FEED_ITEMS + " WHERE " + KEY_ID + "=" + item.id) return db.rawQuery(query, null) } fun getSimpleChaptersOfFeedItemCursor(item: FeedItem): Cursor { - return db.query(TABLE_NAME_SIMPLECHAPTERS, null, KEY_FEEDITEM - + "=?", arrayOf(item.id.toString()), null, - null, null - ) + return db.query(TABLE_NAME_SIMPLECHAPTERS, null, KEY_FEEDITEM + "=?", arrayOf(item.id.toString()), + null, null, null) } fun getDownloadLog(feedFileType: Int, feedFileId: Long): Cursor { @@ -688,9 +646,8 @@ class PodDBAdapter private constructor() { fun setFeedItems(oldState: Int, newState: Int, feedId: Long) { var sql = "UPDATE $TABLE_NAME_FEED_ITEMS SET $KEY_READ=$newState" - if (feedId > 0) { - sql += " WHERE $KEY_FEED=$feedId" - } + if (feedId > 0) sql += " WHERE $KEY_FEED=$feedId" + if (FeedItem.NEW <= oldState && oldState <= FeedItem.PLAYED) { sql += if (feedId > 0) " AND " else " WHERE " sql += "$KEY_READ=$oldState" @@ -772,8 +729,7 @@ class PodDBAdapter private constructor() { fun getFeedItemCursor(ids: Array): Cursor { require(ids.size <= IN_OPERATOR_MAXIMUM) { "number of IDs must not be larger than $IN_OPERATOR_MAXIMUM" } - val query = (SELECT_FEED_ITEMS_AND_MEDIA - + " WHERE " + SELECT_KEY_ITEM_ID + " IN (" + TextUtils.join(",", ids) + ")") + val query = (SELECT_FEED_ITEMS_AND_MEDIA + " WHERE " + SELECT_KEY_ITEM_ID + " IN (" + TextUtils.join(",", ids) + ")") return db.rawQuery(query, null) } @@ -781,13 +737,10 @@ class PodDBAdapter private constructor() { require(urls.size <= IN_OPERATOR_MAXIMUM) { "number of IDs must not be larger than $IN_OPERATOR_MAXIMUM" } val urlsString = StringBuilder() for (i in urls.indices) { - if (i != 0) { - urlsString.append(",") - } + if (i != 0) urlsString.append(",") urlsString.append(DatabaseUtils.sqlEscapeString(urls[i])) } - val query = (SELECT_FEED_ITEMS_AND_MEDIA - + " WHERE " + KEY_DOWNLOAD_URL + " IN (" + urlsString + ")") + val query = (SELECT_FEED_ITEMS_AND_MEDIA + " WHERE " + KEY_DOWNLOAD_URL + " IN (" + urlsString + ")") return db.rawQuery(query, null) } @@ -840,8 +793,7 @@ class PodDBAdapter private constructor() { + TABLE_NAME_FEED_ITEMS + "." + KEY_READ + "=" + FeedItem.PLAYED + " OR " + TABLE_NAME_FEED_MEDIA + "." + KEY_POSITION + "> 0") } - val timeFilter = (lastPlayedTime + ">=" + timeFilterFrom - + " AND " + lastPlayedTime + "<" + timeFilterTo) + val timeFilter = (lastPlayedTime + ">=" + timeFilterFrom + " AND " + lastPlayedTime + "<" + timeFilterTo) var playedTime = "$TABLE_NAME_FEED_MEDIA.$KEY_PLAYED_DURATION" if (includeMarkedAsPlayed) { playedTime = ("(CASE WHEN " + playedTime + " != 0" @@ -891,9 +843,7 @@ class PodDBAdapter private constructor() { val query = String.format("SELECT COUNT(%s) FROM %s", KEY_ID, TABLE_NAME_QUEUE) val c = db.rawQuery(query, null) var result = 0 - if (c.moveToFirst()) { - result = c.getInt(0) - } + if (c.moveToFirst()) result = c.getInt(0) c.close() return result } @@ -1018,13 +968,9 @@ class PodDBAdapter private constructor() { */ fun searchItems(feedID: Long, searchQuery: String): Cursor { val queryWords = prepareSearchQuery(searchQuery) - val queryFeedId = if (feedID != 0L) { - // search items in specific feed - "$KEY_FEED = $feedID" - } else { - // search through all items - "1 = 1" - } + // search items in specific feed + // search through all items + val queryFeedId = if (feedID != 0L) "$KEY_FEED = $feedID" else "1 = 1" val queryStart = (SELECT_FEED_ITEMS_AND_MEDIA_WITH_DESCRIPTION + " WHERE " + queryFeedId + " AND (") val sb = StringBuilder(queryStart) @@ -1036,9 +982,7 @@ class PodDBAdapter private constructor() { .append(KEY_TITLE).append(" LIKE '%").append(queryWords[i]) .append("%') ") - if (i != queryWords.size - 1) { - sb.append("AND ") - } + if (i != queryWords.size - 1) sb.append("AND ") } sb.append(") ORDER BY $KEY_PUBDATE DESC LIMIT 300") @@ -1068,9 +1012,7 @@ class PodDBAdapter private constructor() { .append(KEY_DESCRIPTION).append(" LIKE '%").append(queryWords[i]) .append("%') ") - if (i != queryWords.size - 1) { - sb.append("AND ") - } + if (i != queryWords.size - 1) sb.append("AND ") } sb.append("ORDER BY $KEY_TITLE ASC LIMIT 300") @@ -1432,9 +1374,7 @@ class PodDBAdapter private constructor() { @JvmStatic @Synchronized fun getInstance(): PodDBAdapter { - if (instance == null) { - instance = PodDBAdapter() - } + if (instance == null) instance = PodDBAdapter() return instance!! } diff --git a/app/src/main/java/ac/mdiq/podcini/storage/database/mapper/FeedItemFilterQuery.kt b/app/src/main/java/ac/mdiq/podcini/storage/database/mapper/FeedItemFilterQuery.kt index 524f4184..8fd0faad 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/database/mapper/FeedItemFilterQuery.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/database/mapper/FeedItemFilterQuery.kt @@ -25,60 +25,32 @@ object FeedItemFilterQuery { val statements: MutableList = ArrayList() when { - filter.showPlayed -> { - statements.add("$keyRead = 1 ") - } - filter.showUnplayed -> { - statements.add(" NOT $keyRead = 1 ") // Match "New" items (read = -1) as well - } - filter.showNew -> { - statements.add("$keyRead = -1 ") - } + filter.showPlayed -> statements.add("$keyRead = 1 ") + filter.showUnplayed -> statements.add(" NOT $keyRead = 1 ") // Match "New" items (read = -1) as well + filter.showNew -> statements.add("$keyRead = -1 ") } when { - filter.showPaused -> { - statements.add(" ($keyPosition NOT NULL AND $keyPosition > 0 ) ") - } - filter.showNotPaused -> { - statements.add(" ($keyPosition IS NULL OR $keyPosition = 0 ) ") - } + filter.showPaused -> statements.add(" ($keyPosition NOT NULL AND $keyPosition > 0 ) ") + filter.showNotPaused -> statements.add(" ($keyPosition IS NULL OR $keyPosition = 0 ) ") } when { - filter.showQueued -> { - statements.add("$keyItemId IN (SELECT $keyFeedItem FROM $tableQueue) ") - } - filter.showNotQueued -> { - statements.add("$keyItemId NOT IN (SELECT $keyFeedItem FROM $tableQueue) ") - } + filter.showQueued -> statements.add("$keyItemId IN (SELECT $keyFeedItem FROM $tableQueue) ") + filter.showNotQueued -> statements.add("$keyItemId NOT IN (SELECT $keyFeedItem FROM $tableQueue) ") } when { - filter.showDownloaded -> { - statements.add("$keyDownloaded = 1 ") - } - filter.showNotDownloaded -> { - statements.add("$keyDownloaded = 0 ") - } + filter.showDownloaded -> statements.add("$keyDownloaded = 1 ") + filter.showNotDownloaded -> statements.add("$keyDownloaded = 0 ") } when { - filter.showHasMedia -> { - statements.add("$keyMediaId NOT NULL ") - } - filter.showNoMedia -> { - statements.add("$keyMediaId IS NULL ") - } + filter.showHasMedia -> statements.add("$keyMediaId NOT NULL ") + filter.showNoMedia -> statements.add("$keyMediaId IS NULL ") } when { - filter.showIsFavorite -> { - statements.add("$keyItemId IN (SELECT $keyFeedItem FROM $tableFavorites) ") - } - filter.showNotFavorite -> { - statements.add("$keyItemId NOT IN (SELECT $keyFeedItem FROM $tableFavorites) ") - } + filter.showIsFavorite -> statements.add("$keyItemId IN (SELECT $keyFeedItem FROM $tableFavorites) ") + filter.showNotFavorite -> statements.add("$keyItemId NOT IN (SELECT $keyFeedItem FROM $tableFavorites) ") } - if (statements.isEmpty()) { - return "" - } + if (statements.isEmpty()) return "" val query = StringBuilder(" (" + statements[0]) for (r in statements.subList(1, statements.size)) { diff --git a/app/src/main/java/ac/mdiq/podcini/storage/database/mapper/FeedMediaCursorMapper.kt b/app/src/main/java/ac/mdiq/podcini/storage/database/mapper/FeedMediaCursorMapper.kt index a945f3db..c7a2e262 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/database/mapper/FeedMediaCursorMapper.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/database/mapper/FeedMediaCursorMapper.kt @@ -30,9 +30,8 @@ object FeedMediaCursorMapper { val mediaId = cursor.getLong(indexId) var playbackCompletionDate: Date? = null val playbackCompletionTime = cursor.getLong(indexPlaybackCompletionDate) - if (playbackCompletionTime > 0) { - playbackCompletionDate = Date(playbackCompletionTime) - } + if (playbackCompletionTime > 0) playbackCompletionDate = Date(playbackCompletionTime) + val hasEmbeddedPicture = when (cursor.getInt(cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_HAS_EMBEDDED_PICTURE))) { 1 -> Boolean.TRUE diff --git a/app/src/main/java/ac/mdiq/podcini/storage/database/mapper/FeedPreferencesCursorMapper.kt b/app/src/main/java/ac/mdiq/podcini/storage/database/mapper/FeedPreferencesCursorMapper.kt index 6820d8f2..690fe52e 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/database/mapper/FeedPreferencesCursorMapper.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/database/mapper/FeedPreferencesCursorMapper.kt @@ -38,8 +38,7 @@ object FeedPreferencesCursorMapper { val feedId = cursor.getLong(indexId) val autoDownload = cursor.getInt(indexAutoDownload) > 0 val autoRefresh = cursor.getInt(indexAutoRefresh) > 0 - val autoDeleteAction = - AutoDeleteAction.fromCode(cursor.getInt(indexAutoDeleteAction)) + val autoDeleteAction = AutoDeleteAction.fromCode(cursor.getInt(indexAutoDeleteAction)) val volumeAdaptionValue = cursor.getInt(indexVolumeAdaption) val volumeAdaptionSetting = fromInteger(volumeAdaptionValue) val username = cursor.getString(indexUsername) @@ -50,13 +49,11 @@ object FeedPreferencesCursorMapper { val feedPlaybackSpeed = cursor.getFloat(indexFeedPlaybackSpeed) val feedAutoSkipIntro = cursor.getInt(indexAutoSkipIntro) val feedAutoSkipEnding = cursor.getInt(indexAutoSkipEnding) - val feedNewEpisodesAction = - NewEpisodesAction.fromCode(cursor.getInt(indexNewEpisodesAction)) + val feedNewEpisodesAction = NewEpisodesAction.fromCode(cursor.getInt(indexNewEpisodesAction)) val showNotification = cursor.getInt(indexEpisodeNotification) > 0 var tagsString = cursor.getString(indexTags) - if (tagsString.isNullOrEmpty()) { - tagsString = FeedPreferences.TAG_ROOT - } + if (tagsString.isNullOrEmpty()) tagsString = FeedPreferences.TAG_ROOT + return FeedPreferences(feedId, autoDownload, autoRefresh, diff --git a/app/src/main/java/ac/mdiq/podcini/storage/export/favorites/FavoritesWriter.kt b/app/src/main/java/ac/mdiq/podcini/storage/export/favorites/FavoritesWriter.kt index 99c1404d..c3f21311 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/export/favorites/FavoritesWriter.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/export/favorites/FavoritesWriter.kt @@ -90,16 +90,11 @@ class FavoritesWriter : ExportWriter { @Throws(IOException::class) private fun writeFavoriteItem(writer: Writer?, item: FeedItem, favoriteTemplate: String) { var favItem = favoriteTemplate.replace("{FAV_TITLE}", item.title!!.trim { it <= ' ' }) - favItem = if (item.link != null) { - favItem.replace("{FAV_WEBSITE}", item.link!!) - } else { - favItem.replace("{FAV_WEBSITE}", "") - } - favItem = if (item.media != null && item.media!!.download_url != null) { - favItem.replace("{FAV_MEDIA}", item.media!!.download_url!!) - } else { - favItem.replace("{FAV_MEDIA}", "") - } + favItem = if (item.link != null) favItem.replace("{FAV_WEBSITE}", item.link!!) + else favItem.replace("{FAV_WEBSITE}", "") + + favItem = if (item.media != null && item.media!!.download_url != null) favItem.replace("{FAV_MEDIA}", item.media!!.download_url!!) + else favItem.replace("{FAV_MEDIA}", "") writer!!.append(favItem) } diff --git a/app/src/main/java/ac/mdiq/podcini/storage/export/opml/OpmlReader.kt b/app/src/main/java/ac/mdiq/podcini/storage/export/opml/OpmlReader.kt index 4c416d98..9097a91c 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/export/opml/OpmlReader.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/export/opml/OpmlReader.kt @@ -61,8 +61,7 @@ class OpmlReader { } elementList!!.add(element) } else { - if (BuildConfig.DEBUG) Log.d(TAG, - "Skipping element because of missing xml url") + if (BuildConfig.DEBUG) Log.d(TAG, "Skipping element because of missing xml url") } } } diff --git a/app/src/main/java/ac/mdiq/podcini/storage/export/opml/OpmlWriter.kt b/app/src/main/java/ac/mdiq/podcini/storage/export/opml/OpmlWriter.kt index 48eb91ed..fe5fa60f 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/export/opml/OpmlWriter.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/export/opml/OpmlWriter.kt @@ -42,13 +42,9 @@ class OpmlWriter : ExportWriter { xs.startTag(null, OpmlSymbols.OUTLINE) xs.attribute(null, OpmlSymbols.TEXT, feed!!.title) xs.attribute(null, CommonSymbols.TITLE, feed.title) - if (feed.type != null) { - xs.attribute(null, OpmlSymbols.TYPE, feed.type) - } + if (feed.type != null) xs.attribute(null, OpmlSymbols.TYPE, feed.type) xs.attribute(null, OpmlSymbols.XMLURL, feed.download_url) - if (feed.link != null) { - xs.attribute(null, OpmlSymbols.HTMLURL, feed.link) - } + if (feed.link != null) xs.attribute(null, OpmlSymbols.HTMLURL, feed.link) xs.endTag(null, OpmlSymbols.OUTLINE) } xs.endTag(null, CommonSymbols.BODY) diff --git a/app/src/main/java/ac/mdiq/podcini/storage/model/download/DownloadError.kt b/app/src/main/java/ac/mdiq/podcini/storage/model/download/DownloadError.kt index 062b78ef..891f3835 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/model/download/DownloadError.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/model/download/DownloadError.kt @@ -1,10 +1,8 @@ package ac.mdiq.podcini.storage.model.download /** Utility class for Download Errors. */ -enum class DownloadError( - /** Get machine-readable code. */ - @JvmField val code: Int -) { +/** Get machine-readable code. */ +enum class DownloadError(@JvmField val code: Int) { SUCCESS(0), ERROR_PARSER_EXCEPTION(1), ERROR_UNSUPPORTED_TYPE(2), @@ -34,9 +32,7 @@ enum class DownloadError( @JvmStatic fun fromCode(code: Int): DownloadError { for (reason in entries) { - if (reason.code == code) { - return reason - } + if (reason.code == code) return reason } throw IllegalArgumentException("unknown code: $code") } diff --git a/app/src/main/java/ac/mdiq/podcini/storage/model/download/DownloadResult.kt b/app/src/main/java/ac/mdiq/podcini/storage/model/download/DownloadResult.kt index 42ea7832..7fb3280d 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/model/download/DownloadResult.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/model/download/DownloadResult.kt @@ -40,15 +40,10 @@ class DownloadResult( * Constructor for creating new completed downloads. */ constructor(feedfile: FeedFile, title: String, reason: DownloadError, successful: Boolean, reasonDetailed: String - ) : this(0, title, feedfile.id, FeedMedia.FEEDFILETYPE_FEEDMEDIA, successful, reason, Date(), - reasonDetailed) + ) : this(0, title, feedfile.id, FeedMedia.FEEDFILETYPE_FEEDMEDIA, successful, reason, Date(), reasonDetailed) override fun toString(): String { - return ("DownloadStatus [id=" + id + ", title=" + title + ", reason=" - + reason + ", reasonDetailed=" + reasonDetailed - + ", successful=" + isSuccessful + ", completionDate=" - + completionDate + ", feedfileId=" + feedfileId - + ", feedfileType=" + feedfileType + "]") + return ("DownloadStatus [id=$id, title=$title, reason=$reason, reasonDetailed=$reasonDetailed, successful=$isSuccessful, completionDate=$completionDate, feedfileId=$feedfileId, feedfileType=$feedfileType]") } fun getCompletionDate(): Date { diff --git a/app/src/main/java/ac/mdiq/podcini/storage/model/feed/EmbeddedChapterImage.kt b/app/src/main/java/ac/mdiq/podcini/storage/model/feed/EmbeddedChapterImage.kt index 1a14ce42..56ae0c2a 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/model/feed/EmbeddedChapterImage.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/model/feed/EmbeddedChapterImage.kt @@ -21,12 +21,10 @@ class EmbeddedChapterImage(@JvmField val media: Playable, private val imageUrl: } override fun equals(o: Any?): Boolean { - if (this === o) { - return true - } - if (o == null || javaClass != o.javaClass) { - return false - } + if (this === o) return true + + if (o == null || javaClass != o.javaClass) return false + val that = o as EmbeddedChapterImage return TextUtils.equals(imageUrl, that.imageUrl) } @@ -49,12 +47,7 @@ class EmbeddedChapterImage(@JvmField val media: Playable, private val imageUrl: fun getModelFor(media: Playable, chapter: Int): Any? { val imageUrl = media.getChapters()[chapter].imageUrl - return if (imageUrl != null && isEmbeddedChapterImage( - imageUrl)) { - EmbeddedChapterImage(media, imageUrl) - } else { - imageUrl - } + return if (imageUrl != null && isEmbeddedChapterImage(imageUrl)) EmbeddedChapterImage(media, imageUrl) else imageUrl } } } diff --git a/app/src/main/java/ac/mdiq/podcini/storage/model/feed/Feed.kt b/app/src/main/java/ac/mdiq/podcini/storage/model/feed/Feed.kt index 4f326a1b..b266071d 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/model/feed/Feed.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/model/feed/Feed.kt @@ -135,11 +135,9 @@ class Feed : FeedFile { this.isPaged = paged this.nextPageLink = nextPageLink this.items = mutableListOf() - if (filter != null) { - this.itemFilter = FeedItemFilter(filter) - } else { - this.itemFilter = FeedItemFilter() - } + if (filter != null) this.itemFilter = FeedItemFilter(filter) + else this.itemFilter = FeedItemFilter() + this.sortOrder = sortOrder this.lastUpdateFailed = lastUpdateFailed } @@ -230,61 +228,32 @@ class Feed : FeedFile { * of the feed. */ get() = when { - !feedIdentifier.isNullOrEmpty() -> { - feedIdentifier - } - !download_url.isNullOrEmpty() -> { - download_url - } - !feedTitle.isNullOrEmpty() -> { - feedTitle - } - else -> { - link - } + !feedIdentifier.isNullOrEmpty() -> feedIdentifier + !download_url.isNullOrEmpty() -> download_url + !feedTitle.isNullOrEmpty() -> feedTitle + else -> link } override fun getHumanReadableIdentifier(): String? { return when { - !customTitle.isNullOrEmpty() -> { - customTitle - } - !feedTitle.isNullOrEmpty() -> { - feedTitle - } - else -> { - download_url - } + !customTitle.isNullOrEmpty() -> customTitle + !feedTitle.isNullOrEmpty() -> feedTitle + else -> download_url } } fun updateFromOther(other: Feed) { // don't update feed's download_url, we do that manually if redirected // see PodciniHttpClient - if (other.imageUrl != null) { - this.imageUrl = other.imageUrl - } - if (other.feedTitle != null) { - feedTitle = other.feedTitle - } - if (other.feedIdentifier != null) { - feedIdentifier = other.feedIdentifier - } - if (other.link != null) { - link = other.link - } - if (other.description != null) { - description = other.description - } - if (other.language != null) { - language = other.language - } - if (other.author != null) { - author = other.author - } - if (other.paymentLinks.isNotEmpty()) { - paymentLinks = other.paymentLinks - } + if (other.imageUrl != null) this.imageUrl = other.imageUrl + if (other.feedTitle != null) feedTitle = other.feedTitle + if (other.feedIdentifier != null) feedIdentifier = other.feedIdentifier + if (other.link != null) link = other.link + if (other.description != null) description = other.description + if (other.language != null) language = other.language + if (other.author != null) author = other.author + if (other.paymentLinks.isNotEmpty()) paymentLinks = other.paymentLinks + // this feed's nextPage might already point to a higher page, so we only update the nextPage value // if this feed is not paged and the other feed is. if (!this.isPaged && other.isPaged) { @@ -294,53 +263,35 @@ class Feed : FeedFile { } fun compareWithOther(other: Feed): Boolean { - if (super.compareWithOther(other)) { - return true - } + if (super.compareWithOther(other)) return true + if (other.imageUrl != null) { - if (imageUrl == null || !TextUtils.equals(imageUrl, other.imageUrl)) { - return true - } - } - if (!TextUtils.equals(feedTitle, other.feedTitle)) { - return true + if (imageUrl == null || !TextUtils.equals(imageUrl, other.imageUrl)) return true } + if (!TextUtils.equals(feedTitle, other.feedTitle)) return true + if (other.feedIdentifier != null) { - if (feedIdentifier == null || feedIdentifier != other.feedIdentifier) { - return true - } + if (feedIdentifier == null || feedIdentifier != other.feedIdentifier) return true } if (other.link != null) { - if (link == null || link != other.link) { - return true - } + if (link == null || link != other.link) return true } if (other.description != null) { - if (description == null || description != other.description) { - return true - } + if (description == null || description != other.description) return true } if (other.language != null) { - if (language == null || language != other.language) { - return true - } + if (language == null || language != other.language) return true } if (other.author != null) { - if (author == null || author != other.author) { - return true - } + if (author == null || author != other.author) return true } if (other.paymentLinks.isNotEmpty()) { - if (paymentLinks.isEmpty() || paymentLinks != other.paymentLinks) { - return true - } - } - if (other.isPaged && !this.isPaged) { - return true - } - if (!TextUtils.equals(other.nextPageLink, this.nextPageLink)) { - return true + if (paymentLinks.isEmpty() || paymentLinks != other.paymentLinks) return true } + if (other.isPaged && !this.isPaged) return true + + if (!TextUtils.equals(other.nextPageLink, this.nextPageLink)) return true + return false } @@ -374,11 +325,8 @@ class Feed : FeedFile { } fun setCustomTitle(customTitle: String?) { - if (customTitle == null || customTitle == feedTitle) { - this.customTitle = null - } else { - this.customTitle = customTitle - } + if (customTitle == null || customTitle == feedTitle) this.customTitle = null + else this.customTitle = customTitle } fun addPayment(funding: FeedFunding) { @@ -389,9 +337,7 @@ class Feed : FeedFile { get() = super.id set(id) { super.id = id - if (preferences != null) { - preferences!!.feedID = id - } + if (preferences != null) preferences!!.feedID = id } fun setItemFilter(properties: Array?) { diff --git a/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedCounter.kt b/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedCounter.kt index 642a1564..b83ceaa5 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedCounter.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedCounter.kt @@ -10,9 +10,7 @@ enum class FeedCounter(val id: Int) { companion object { fun fromOrdinal(id: Int): FeedCounter { for (counter in entries) { - if (counter.id == id) { - return counter - } + if (counter.id == id) return counter } return SHOW_NONE } diff --git a/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedFile.kt b/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedFile.kt index f98511a5..8acada15 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedFile.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedFile.kt @@ -9,8 +9,8 @@ import java.io.Serializable */ abstract class FeedFile @JvmOverloads constructor(@JvmField var file_url: String? = null, @JvmField var download_url: String? = null, - private var downloaded: Boolean = false -) : FeedComponent(), Serializable { + private var downloaded: Boolean = false) + : FeedComponent(), Serializable { /** * Creates a new FeedFile object. @@ -46,12 +46,9 @@ abstract class FeedFile @JvmOverloads constructor(@JvmField var file_url: String * @return true if attribute values are different, false otherwise */ fun compareWithOther(other: FeedFile): Boolean { - if (super.compareWithOther(other)) { - return true - } - if (!TextUtils.equals(download_url, other.download_url)) { - return true - } + if (super.compareWithOther(other)) return true + if (!TextUtils.equals(download_url, other.download_url)) return true + return false } @@ -77,9 +74,7 @@ abstract class FeedFile @JvmOverloads constructor(@JvmField var file_url: String */ open fun setFile_url(file_url: String?) { this.file_url = file_url - if (file_url == null) { - downloaded = false - } + if (file_url == null) downloaded = false } fun isDownloaded(): Boolean { diff --git a/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedFilter.kt b/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedFilter.kt index 7f61103c..404aa9b7 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedFilter.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedFilter.kt @@ -10,8 +10,8 @@ class FeedFilter // We're storing the strings and not the parsed terms because // 2. We don't know if we'll actually be asked to parse anything anyways. @JvmOverloads constructor(val includeFilterRaw: String? = "", val excludeFilterRaw: String? = "", - val minimalDurationFilter: Int = -1 -) : Serializable { + val minimalDurationFilter: Int = -1) + : Serializable { /** * Parses the text in to a list of single words or quoted strings. * Example: "One "Two Three"" returns ["One", "Two Three"] @@ -36,18 +36,14 @@ class FeedFilter // We're storing the strings and not the parsed terms because val includeTerms = parseTerms(includeFilterRaw) val excludeTerms = parseTerms(excludeFilterRaw) - if (includeTerms.isEmpty() && excludeTerms.isEmpty() && minimalDurationFilter <= -1) { - // nothing has been specified, so include everything - return true - } + // nothing has been specified, so include everything + if (includeTerms.isEmpty() && excludeTerms.isEmpty() && minimalDurationFilter <= -1) return true // Check if the episode is long enough if minimal duration filter is on if (hasMinimalDurationFilter() && item.media != null) { val durationInMs = item.media!!.getDuration() // Minimal Duration is stored in seconds - if (durationInMs > 0 && durationInMs / 1000 < minimalDurationFilter) { - return false - } + if (durationInMs > 0 && durationInMs / 1000 < minimalDurationFilter) return false } // check using lowercase so the users don't have to worry about case. @@ -56,29 +52,21 @@ class FeedFilter // We're storing the strings and not the parsed terms because // if it's explicitly excluded, it shouldn't be autodownloaded // even if it has include terms for (term in excludeTerms) { - if (title.contains(term.trim { it <= ' ' }.lowercase(Locale.getDefault()))) { - return false - } + if (title.contains(term.trim { it <= ' ' }.lowercase(Locale.getDefault()))) return false } for (term in includeTerms) { - if (title.contains(term.trim { it <= ' ' }.lowercase(Locale.getDefault()))) { - return true - } + if (title.contains(term.trim { it <= ' ' }.lowercase(Locale.getDefault()))) return true } // now's the tricky bit // if they haven't set an include filter, but they have set an exclude filter // default to including, but if they've set both, then exclude - if (!hasIncludeFilter() && hasExcludeFilter()) { - return true - } + if (!hasIncludeFilter() && hasExcludeFilter()) return true // if they only set minimal duration filter and arrived here, autodownload // should happen - if (hasMinimalDurationFilter()) { - return true - } + if (hasMinimalDurationFilter()) return true return false } diff --git a/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedFunding.kt b/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedFunding.kt index 68dc48de..d964a27f 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedFunding.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedFunding.kt @@ -12,17 +12,11 @@ class FeedFunding(@JvmField var url: String?, @JvmField var content: String?) { } override fun equals(obj: Any?): Boolean { - if (obj == null || obj.javaClass != this.javaClass) { - return false - } - + if (obj == null || obj.javaClass != this.javaClass) return false val funding = obj as FeedFunding - if (url == null && funding.url == null && content == null && funding.content == null) { - return true - } - if (url != null && url == funding.url && content != null && content == funding.content) { - return true - } + if (url == null && funding.url == null && content == null && funding.content == null) return true + if (url != null && url == funding.url && content != null && content == funding.content) return true + return false } @@ -36,32 +30,24 @@ class FeedFunding(@JvmField var url: String?, @JvmField var content: String?) { @JvmStatic fun extractPaymentLinks(payLinks: String?): ArrayList { - if (payLinks.isNullOrBlank()) { - return arrayListOf() - } + if (payLinks.isNullOrBlank()) return arrayListOf() + // old format before we started with PodcastIndex funding tag val funding = ArrayList() - if (!payLinks.contains(FUNDING_ENTRIES_SEPARATOR) - && !payLinks.contains(FUNDING_TITLE_SEPARATOR)) { + if (!payLinks.contains(FUNDING_ENTRIES_SEPARATOR) && !payLinks.contains(FUNDING_TITLE_SEPARATOR)) { funding.add(FeedFunding(payLinks, "")) return funding } val list = payLinks.split(FUNDING_ENTRIES_SEPARATOR.toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() - if (list.isEmpty()) { - return arrayListOf() - } + if (list.isEmpty()) return arrayListOf() for (str in list) { - val linkContent = str.split(FUNDING_TITLE_SEPARATOR.toRegex()).dropLastWhile { it.isEmpty() } - .toTypedArray() - if (StringUtils.isBlank(linkContent[0])) { - continue - } + val linkContent = str.split(FUNDING_TITLE_SEPARATOR.toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() + if (StringUtils.isBlank(linkContent[0])) continue + val url = linkContent[0] var title = "" - if (linkContent.size > 1 && !StringUtils.isBlank(linkContent[1])) { - title = linkContent[1] - } + if (linkContent.size > 1 && !StringUtils.isBlank(linkContent[1])) title = linkContent[1] funding.add(FeedFunding(url, title)) } return funding @@ -69,9 +55,8 @@ class FeedFunding(@JvmField var url: String?, @JvmField var content: String?) { fun getPaymentLinksAsString(fundingList: ArrayList?): String? { val result = StringBuilder() - if (fundingList == null) { - return null - } + if (fundingList == null) return null + for (fund in fundingList) { result.append(fund.url).append(FUNDING_TITLE_SEPARATOR).append(fund.content) result.append(FUNDING_ENTRIES_SEPARATOR) diff --git a/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedItem.kt b/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedItem.kt index 9d039ce8..762363b5 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedItem.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedItem.kt @@ -153,21 +153,12 @@ class FeedItem : FeedComponent, Serializable { fun updateFromOther(other: FeedItem) { super.updateFromOther(other) - if (other.imageUrl != null) { - this.imageUrl = other.imageUrl - } - if (other.title != null) { - title = other.title - } - if (other.description != null) { - description = other.description - } - if (other.link != null) { - link = other.link - } - if (other.pubDate != null && other.pubDate != pubDate) { - pubDate = other.pubDate - } + if (other.imageUrl != null) this.imageUrl = other.imageUrl + if (other.title != null) title = other.title + if (other.description != null) description = other.description + if (other.link != null) link = other.link + if (other.pubDate != null && other.pubDate != pubDate) pubDate = other.pubDate + if (other.media != null) { when { media == null -> { @@ -175,22 +166,14 @@ class FeedItem : FeedComponent, Serializable { // reset to new if feed item did link to a file before setNew() } - media!!.compareWithOther(other.media) -> { - media!!.updateFromOther(other.media) - } + media!!.compareWithOther(other.media) -> media!!.updateFromOther(other.media) } } - if (other.paymentLink != null) { - paymentLink = other.paymentLink - } + if (other.paymentLink != null) paymentLink = other.paymentLink if (other.chapters != null) { - if (!hasChapters) { - chapters = other.chapters - } - } - if (other.podcastIndexChapterUrl != null) { - podcastIndexChapterUrl = other.podcastIndexChapterUrl + if (!hasChapters) chapters = other.chapters } + if (other.podcastIndexChapterUrl != null) podcastIndexChapterUrl = other.podcastIndexChapterUrl } val identifyingValue: String? @@ -201,36 +184,21 @@ class FeedItem : FeedComponent, Serializable { * of the entry. */ get() = when { - !itemIdentifier.isNullOrEmpty() -> { - itemIdentifier - } - !title.isNullOrEmpty() -> { - title - } - media?.download_url != null -> { - media!!.download_url - } - else -> { - link - } + !itemIdentifier.isNullOrEmpty() -> itemIdentifier + !title.isNullOrEmpty() -> title + media?.download_url != null -> media!!.download_url + else -> link } @JvmName("getPubDateFunction") fun getPubDate(): Date? { - return if (pubDate != null) { - pubDate!!.clone() as Date - } else { - null - } + return pubDate?.clone() as? Date } @JvmName("setPubDateFunction") fun setPubDate(pubDate: Date?) { - if (pubDate != null) { - this.pubDate = pubDate.clone() as Date - } else { - this.pubDate = null - } + if (pubDate != null) this.pubDate = pubDate.clone() as Date + else this.pubDate = null } /** @@ -241,9 +209,7 @@ class FeedItem : FeedComponent, Serializable { @JvmName("setMediaFunction") fun setMedia(media: FeedMedia?) { this.media = media - if (media != null && media.item !== this) { - media.setItem(this) - } + if (media != null && media.item !== this) media.setItem(this) } val isNew: Boolean @@ -258,11 +224,7 @@ class FeedItem : FeedComponent, Serializable { } fun setPlayed(played: Boolean) { - playState = if (played) { - PLAYED - } else { - UNPLAYED - } + playState = if (played) PLAYED else UNPLAYED } val isInProgress: Boolean @@ -273,16 +235,11 @@ class FeedItem : FeedComponent, Serializable { * @param newDescription The new item description, content:encoded, itunes:description, etc. */ fun setDescriptionIfLonger(newDescription: String?) { - if (newDescription == null) { - return - } + if (newDescription == null) return + when { - this.description == null -> { - this.description = newDescription - } - description!!.length < newDescription.length -> { - this.description = newDescription - } + this.description == null -> this.description = newDescription + description!!.length < newDescription.length -> this.description = newDescription } } @@ -292,18 +249,10 @@ class FeedItem : FeedComponent, Serializable { val imageLocation: String? get() = when { - imageUrl != null -> { - imageUrl - } - media != null && media!!.hasEmbeddedPicture() -> { - FeedMedia.FILENAME_PREFIX_EMBEDDED_COVER + media!!.getLocalMediaUrl() - } - feed != null -> { - feed!!.imageUrl - } - else -> { - null - } + imageUrl != null -> imageUrl + media != null && media!!.hasEmbeddedPicture() -> FeedMedia.FILENAME_PREFIX_EMBEDDED_COVER + media!!.getLocalMediaUrl() + feed != null -> feed!!.imageUrl + else -> null } enum class State { diff --git a/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedItemFilter.kt b/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedItemFilter.kt index e3b9d58b..21f698c2 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedItemFilter.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedItemFilter.kt @@ -65,48 +65,20 @@ class FeedItemFilter(vararg properties: String) : Serializable { fun matches(item: FeedItem): Boolean { when { - showNew && !item.isNew -> { - return false - } - showPlayed && !item.isPlayed() -> { - return false - } - showUnplayed && item.isPlayed() -> { - return false - } - showPaused && !item.isInProgress -> { - return false - } - showNotPaused && item.isInProgress -> { - return false - } - showNew && !item.isNew -> { - return false - } - showQueued && !item.isTagged(FeedItem.TAG_QUEUE) -> { - return false - } - showNotQueued && item.isTagged(FeedItem.TAG_QUEUE) -> { - return false - } - showDownloaded && !item.isDownloaded -> { - return false - } - showNotDownloaded && item.isDownloaded -> { - return false - } - showHasMedia && !item.hasMedia() -> { - return false - } - showNoMedia && item.hasMedia() -> { - return false - } - showIsFavorite && !item.isTagged(FeedItem.TAG_FAVORITE) -> { - return false - } - showNotFavorite && item.isTagged(FeedItem.TAG_FAVORITE) -> { - return false - } + showNew && !item.isNew -> return false + showPlayed && !item.isPlayed() -> return false + showUnplayed && item.isPlayed() -> return false + showPaused && !item.isInProgress -> return false + showNotPaused && item.isInProgress -> return false + showNew && !item.isNew -> return false + showQueued && !item.isTagged(FeedItem.TAG_QUEUE) -> return false + showNotQueued && item.isTagged(FeedItem.TAG_QUEUE) -> return false + showDownloaded && !item.isDownloaded -> return false + showNotDownloaded && item.isDownloaded -> return false + showHasMedia && !item.hasMedia() -> return false + showNoMedia && item.hasMedia() -> return false + showIsFavorite && !item.isTagged(FeedItem.TAG_FAVORITE) -> return false + showNotFavorite && item.isTagged(FeedItem.TAG_FAVORITE) -> return false else -> return true } } diff --git a/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedMedia.kt b/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedMedia.kt index aa46c0fe..4be5c841 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedMedia.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedMedia.kt @@ -77,11 +77,7 @@ class FeedMedia : FeedFile, Playable { } override fun getHumanReadableIdentifier(): String? { - return if (item?.title != null) { - item!!.title - } else { - download_url - } + return if (item?.title != null) item!!.title else download_url } val mediaItem: MediaBrowserCompat.MediaItem @@ -99,12 +95,8 @@ class FeedMedia : FeedFile, Playable { if (item != null) { // getImageLocation() also loads embedded images, which we can not send to external devices when { - item!!.imageUrl != null -> { - builder.setIconUri(Uri.parse(item!!.imageUrl)) - } - item!!.feed?.imageUrl != null -> { - builder.setIconUri(Uri.parse(item!!.feed!!.imageUrl)) - } + item!!.imageUrl != null -> builder.setIconUri(Uri.parse(item!!.imageUrl)) + item!!.feed?.imageUrl != null -> builder.setIconUri(Uri.parse(item!!.feed!!.imageUrl)) } } return MediaBrowserCompat.MediaItem(builder.build(), MediaBrowserCompat.MediaItem.FLAG_PLAYABLE) @@ -119,32 +111,21 @@ class FeedMedia : FeedFile, Playable { fun updateFromOther(other: FeedMedia) { super.updateFromOther(other) - if (other.size > 0) { - size = other.size - } - if (other.duration > 0 && duration <= 0) { // Do not overwrite duration that we measured after downloading - duration = other.duration - } - if (other.mime_type != null) { - mime_type = other.mime_type - } + if (other.size > 0) size = other.size + // Do not overwrite duration that we measured after downloading + if (other.duration > 0 && duration <= 0) duration = other.duration + if (other.mime_type != null) mime_type = other.mime_type } fun compareWithOther(other: FeedMedia): Boolean { - if (super.compareWithOther(other)) { - return true - } + if (super.compareWithOther(other)) return true + if (other.mime_type != null) { - if (mime_type == null || mime_type != other.mime_type) { - return true - } - } - if (other.size > 0 && other.size != size) { - return true - } - if (other.duration > 0 && duration <= 0) { - return true + if (mime_type == null || mime_type != other.mime_type) return true } + if (other.size > 0 && other.size != size) return true + if (other.duration > 0 && duration <= 0) return true + return false } @@ -174,9 +155,7 @@ class FeedMedia : FeedFile, Playable { override fun setPosition(position: Int) { this.position = position - if (position > 0 && item != null && item!!.isNew) { - item!!.setPlayed(false) - } + if (position > 0 && item != null && item!!.isNew) item!!.setPlayed(false) } override fun getDescription(): String? { @@ -202,9 +181,7 @@ class FeedMedia : FeedFile, Playable { */ fun setItem(item: FeedItem?) { this.item = item - if (item != null && item.media !== this) { - item.setMedia(this) - } + if (item != null && item.media !== this) item.setMedia(this) } fun getPlaybackCompletionDate(): Date? { @@ -213,8 +190,7 @@ class FeedMedia : FeedFile, Playable { } fun setPlaybackCompletionDate(playbackCompletionDate: Date?) { - this.playbackCompletionDate = if (playbackCompletionDate == null - ) null else playbackCompletionDate.clone() as Date + this.playbackCompletionDate = if (playbackCompletionDate == null) null else playbackCompletionDate.clone() as Date } val isInProgress: Boolean @@ -225,9 +201,7 @@ class FeedMedia : FeedFile, Playable { } fun hasEmbeddedPicture(): Boolean { - if (hasEmbeddedPicture == null) { - checkEmbeddedPicture() - } + if (hasEmbeddedPicture == null) checkEmbeddedPicture() return hasEmbeddedPicture!! } @@ -248,22 +222,16 @@ class FeedMedia : FeedFile, Playable { } override fun writeToPreferences(prefEditor: SharedPreferences.Editor) { - if (item?.feed != null) { - prefEditor.putLong(PREF_FEED_ID, item!!.feed!!.id) - } else { - prefEditor.putLong(PREF_FEED_ID, 0L) - } + if (item?.feed != null) prefEditor.putLong(PREF_FEED_ID, item!!.feed!!.id) + else prefEditor.putLong(PREF_FEED_ID, 0L) + prefEditor.putLong(PREF_MEDIA_ID, id) } override fun getEpisodeTitle(): String { if (item == null) return "No title" - return if (item!!.title != null) { - item!!.title!! - } else { - item!!.identifyingValue?:"No title" - } + return if (item!!.title != null) item!!.title!! else item!!.identifyingValue?:"No title" } override fun getChapters(): List { @@ -324,22 +292,14 @@ class FeedMedia : FeedFile, Playable { } override fun setChapters(chapters: List) { - if (item != null) { - item!!.chapters = chapters.toMutableList() - } + if (item != null) item!!.chapters = chapters.toMutableList() } override fun getImageLocation(): String? { return when { - item != null -> { - item!!.imageLocation - } - hasEmbeddedPicture() -> { - FILENAME_PREFIX_EMBEDDED_COVER + getLocalMediaUrl() - } - else -> { - null - } + item != null -> item!!.imageLocation + hasEmbeddedPicture() -> FILENAME_PREFIX_EMBEDDED_COVER + getLocalMediaUrl() + else -> null } } @@ -349,9 +309,7 @@ class FeedMedia : FeedFile, Playable { override fun setDownloaded(downloaded: Boolean) { super.setDownloaded(downloaded) - if (item != null && downloaded && item!!.isNew) { - item!!.setPlayed(false) - } + if (item != null && downloaded && item!!.isNew) item!!.setPlayed(false) } fun checkEmbeddedPicture() { @@ -363,11 +321,7 @@ class FeedMedia : FeedFile, Playable { MediaMetadataRetrieverCompat().use { mmr -> mmr.setDataSource(getLocalMediaUrl()) val image = mmr.embeddedPicture - hasEmbeddedPicture = if (image != null) { - java.lang.Boolean.TRUE - } else { - java.lang.Boolean.FALSE - } + hasEmbeddedPicture = if (image != null) java.lang.Boolean.TRUE else java.lang.Boolean.FALSE } } catch (e: Exception) { e.printStackTrace() @@ -376,12 +330,8 @@ class FeedMedia : FeedFile, Playable { } override fun equals(o: Any?): Boolean { - if (o == null) { - return false - } - if (o is RemoteMedia) { - return o == this - } + if (o == null) return false + if (o is RemoteMedia) return o == this return super.equals(o) } diff --git a/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedPreferences.kt b/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedPreferences.kt index d070324a..d11adb9d 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedPreferences.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/model/feed/FeedPreferences.kt @@ -41,9 +41,7 @@ class FeedPreferences(@JvmField var feedID: Long, @JvmStatic fun fromCode(code: Int): AutoDeleteAction { for (action in entries) { - if (code == action.code) { - return action - } + if (code == action.code) return action } return NEVER } @@ -59,9 +57,7 @@ class FeedPreferences(@JvmField var feedID: Long, @JvmStatic fun fromCode(code: Int): NewEpisodesAction { for (action in entries) { - if (code == action.code) { - return action - } + if (code == action.code) return action } return GLOBAL } @@ -87,15 +83,10 @@ class FeedPreferences(@JvmField var feedID: Long, * @return True if the two objects are different. */ fun compareWithOther(other: FeedPreferences?): Boolean { - if (other == null) { - return true - } - if (!TextUtils.equals(username, other.username)) { - return true - } - if (!TextUtils.equals(password, other.password)) { - return true - } + if (other == null) return true + if (!TextUtils.equals(username, other.username)) return true + if (!TextUtils.equals(password, other.password)) return true + return false } diff --git a/app/src/main/java/ac/mdiq/podcini/storage/model/feed/SortOrder.kt b/app/src/main/java/ac/mdiq/podcini/storage/model/feed/SortOrder.kt index 1e8c44c4..0253d30b 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/model/feed/SortOrder.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/model/feed/SortOrder.kt @@ -41,14 +41,11 @@ enum class SortOrder(@JvmField val code: Int, @JvmField val scope: Scope) { @JvmStatic fun fromCodeString(codeStr: String?): SortOrder? { - if (codeStr.isNullOrEmpty()) { - return null - } + if (codeStr.isNullOrEmpty()) return null + val code = codeStr.toInt() for (sortOrder in entries) { - if (sortOrder.code == code) { - return sortOrder - } + if (sortOrder.code == code) return sortOrder } throw IllegalArgumentException("Unsupported code: $code") } diff --git a/app/src/main/java/ac/mdiq/podcini/storage/model/feed/SubscriptionsFilter.kt b/app/src/main/java/ac/mdiq/podcini/storage/model/feed/SubscriptionsFilter.kt index 65ba9de4..8ddc7518 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/model/feed/SubscriptionsFilter.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/model/feed/SubscriptionsFilter.kt @@ -40,9 +40,7 @@ class SubscriptionsFilter(private val properties: Array) { * Run a list of feed items through the filter. */ fun filter(items: List, feedCounters: Map): List { - if (properties.isEmpty()) { - return items - } + if (properties.isEmpty()) return items val result: MutableList = ArrayList() @@ -51,30 +49,16 @@ class SubscriptionsFilter(private val properties: Array) { // If the item does not meet a requirement, skip it. when { - showAutoDownloadEnabled && itemPreferences?.autoDownload != true -> { - continue - } - showAutoDownloadDisabled && itemPreferences?.autoDownload == true -> { - continue - } + showAutoDownloadEnabled && itemPreferences?.autoDownload != true -> continue + showAutoDownloadDisabled && itemPreferences?.autoDownload == true -> continue } - when { - showUpdatedEnabled && itemPreferences?.keepUpdated != true -> { - continue - } - showUpdatedDisabled && itemPreferences?.keepUpdated == true -> { - continue - } + showUpdatedEnabled && itemPreferences?.keepUpdated != true -> continue + showUpdatedDisabled && itemPreferences?.keepUpdated == true -> continue } - when { - showEpisodeNotificationEnabled && itemPreferences?.showEpisodeNotification != true -> { - continue - } - showEpisodeNotificationDisabled && itemPreferences?.showEpisodeNotification == true -> { - continue - } + showEpisodeNotificationEnabled && itemPreferences?.showEpisodeNotification != true -> continue + showEpisodeNotificationDisabled && itemPreferences?.showEpisodeNotification == true -> continue } // If the item reaches here, it meets all criteria (except counter > 0) @@ -83,9 +67,7 @@ class SubscriptionsFilter(private val properties: Array) { if (showIfCounterGreaterZero) { for (i in result.indices.reversed()) { - if (!feedCounters.containsKey(result[i].id) || feedCounters[result[i].id]!! <= 0) { - result.removeAt(i) - } + if (!feedCounters.containsKey(result[i].id) || feedCounters[result[i].id]!! <= 0) result.removeAt(i) } } diff --git a/app/src/main/java/ac/mdiq/podcini/storage/model/feed/VolumeAdaptionSetting.kt b/app/src/main/java/ac/mdiq/podcini/storage/model/feed/VolumeAdaptionSetting.kt index 5986e3b6..2ffc9169 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/model/feed/VolumeAdaptionSetting.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/model/feed/VolumeAdaptionSetting.kt @@ -16,9 +16,7 @@ enum class VolumeAdaptionSetting(private val value: Int, @JvmField val adaptionF @JvmStatic fun fromInteger(value: Int): VolumeAdaptionSetting { for (setting in entries) { - if (setting.value == value) { - return setting - } + if (setting.value == value) return setting } throw IllegalArgumentException("Cannot map value to VolumeAdaptionSetting: $value") } diff --git a/app/src/main/java/ac/mdiq/podcini/storage/model/playback/MediaType.kt b/app/src/main/java/ac/mdiq/podcini/storage/model/playback/MediaType.kt index cef4cd17..4dde26d9 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/model/playback/MediaType.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/model/playback/MediaType.kt @@ -9,27 +9,15 @@ enum class MediaType { "application/opus", "application/x-flac" )) - private val VIDEO_APPLICATION_MIME_STRINGS: Set = HashSet(mutableListOf( - "application/x-shockwave-flash" - )) + private val VIDEO_APPLICATION_MIME_STRINGS: Set = HashSet(mutableListOf("application/x-shockwave-flash")) fun fromMimeType(mimeType: String?): MediaType { return when { - mimeType.isNullOrEmpty() -> { - UNKNOWN - } - mimeType.startsWith("audio") -> { - AUDIO - } - mimeType.startsWith("video") -> { - VIDEO - } - AUDIO_APPLICATION_MIME_STRINGS.contains(mimeType) -> { - AUDIO - } - VIDEO_APPLICATION_MIME_STRINGS.contains(mimeType) -> { - FLASH - } + mimeType.isNullOrEmpty() -> UNKNOWN + mimeType.startsWith("audio") -> AUDIO + mimeType.startsWith("video") -> VIDEO + AUDIO_APPLICATION_MIME_STRINGS.contains(mimeType) -> AUDIO + VIDEO_APPLICATION_MIME_STRINGS.contains(mimeType) -> FLASH else -> UNKNOWN } } diff --git a/app/src/main/java/ac/mdiq/podcini/storage/model/playback/RemoteMedia.kt b/app/src/main/java/ac/mdiq/podcini/storage/model/playback/RemoteMedia.kt index 7edc0f70..01ea20fc 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/model/playback/RemoteMedia.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/model/playback/RemoteMedia.kt @@ -214,19 +214,16 @@ class RemoteMedia : Playable { } override fun equals(other: Any?): Boolean { - if (other is RemoteMedia) { - return (TextUtils.equals(streamUrl, other.streamUrl) - && TextUtils.equals(feedUrl, other.feedUrl) + if (other is RemoteMedia) + return (TextUtils.equals(streamUrl, other.streamUrl) && TextUtils.equals(feedUrl, other.feedUrl) && TextUtils.equals(itemIdentifier, other.itemIdentifier)) - } + if (other is FeedMedia) { - if (!TextUtils.equals(streamUrl, other.getStreamUrl())) { - return false - } + if (!TextUtils.equals(streamUrl, other.getStreamUrl())) return false + val fi = other.item - if (fi == null || !TextUtils.equals(itemIdentifier, fi.itemIdentifier)) { - return false - } + if (fi == null || !TextUtils.equals(itemIdentifier, fi.itemIdentifier)) return false + val feed = fi.feed return feed != null && TextUtils.equals(feedUrl, feed.download_url) } diff --git a/app/src/main/java/ac/mdiq/podcini/ui/actions/EpisodeMultiSelectActionHandler.kt b/app/src/main/java/ac/mdiq/podcini/ui/actions/EpisodeMultiSelectActionHandler.kt index b5e5506d..4522c62b 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/actions/EpisodeMultiSelectActionHandler.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/actions/EpisodeMultiSelectActionHandler.kt @@ -19,30 +19,14 @@ class EpisodeMultiSelectActionHandler(private val activity: MainActivity, privat fun handleAction(items: List) { when (actionId) { - R.id.add_to_favorite_batch -> { - markFavorite(items) - } - R.id.add_to_queue_batch -> { - queueChecked(items) - } - R.id.remove_from_queue_batch -> { - removeFromQueueChecked(items) - } - R.id.mark_read_batch -> { - markedCheckedPlayed(items) - } - R.id.mark_unread_batch -> { - markedCheckedUnplayed(items) - } - R.id.download_batch -> { - downloadChecked(items) - } - R.id.delete_batch -> { - LocalDeleteModal.showLocalFeedDeleteWarningIfNecessary(activity, items) { deleteChecked(items) } - } - else -> { - Log.e(TAG, "Unrecognized speed dial action item. Do nothing. id=$actionId") - } + R.id.add_to_favorite_batch -> markFavorite(items) + R.id.add_to_queue_batch -> queueChecked(items) + R.id.remove_from_queue_batch -> removeFromQueueChecked(items) + R.id.mark_read_batch -> markedCheckedPlayed(items) + R.id.mark_unread_batch -> markedCheckedUnplayed(items) + R.id.download_batch -> downloadChecked(items) + R.id.delete_batch -> LocalDeleteModal.showLocalFeedDeleteWarningIfNecessary(activity, items) { deleteChecked(items) } + else -> Log.e(TAG, "Unrecognized speed dial action item. Do nothing. id=$actionId") } } @@ -50,9 +34,7 @@ class EpisodeMultiSelectActionHandler(private val activity: MainActivity, privat // Check if an episode actually contains any media files before adding it to queue val toQueue = LongList(items.size) for (episode in items) { - if (episode.hasMedia()) { - toQueue.add(episode.id) - } + if (episode.hasMedia()) toQueue.add(episode.id) } DBWriter.addQueueItem(activity, true, *toQueue.toArray()) showMessage(R.plurals.added_to_queue_batch_label, toQueue.size()) @@ -86,9 +68,7 @@ class EpisodeMultiSelectActionHandler(private val activity: MainActivity, privat private fun downloadChecked(items: List) { // download the check episodes in the same order as they are currently displayed for (episode in items) { - if (episode.hasMedia() && episode.feed != null && !episode.feed!!.isLocalFeed) { - DownloadServiceInterface.get()?.download(activity, episode) - } + if (episode.hasMedia() && episode.feed != null && !episode.feed!!.isLocalFeed) DownloadServiceInterface.get()?.download(activity, episode) } showMessage(R.plurals.downloading_batch_label, items.size) } @@ -111,9 +91,7 @@ class EpisodeMultiSelectActionHandler(private val activity: MainActivity, privat if (snackbar != null) { snackbar?.setText(text) snackbar?.show() // Resets the timeout - } else { - snackbar = activity.showSnackbarAbovePlayer(text, Snackbar.LENGTH_LONG) - } + } else snackbar = activity.showSnackbarAbovePlayer(text, Snackbar.LENGTH_LONG) } } diff --git a/app/src/main/java/ac/mdiq/podcini/ui/actions/FeedMultiSelectActionHandler.kt b/app/src/main/java/ac/mdiq/podcini/ui/actions/FeedMultiSelectActionHandler.kt index 057f660b..3873c222 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/actions/FeedMultiSelectActionHandler.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/actions/FeedMultiSelectActionHandler.kt @@ -25,30 +25,16 @@ class FeedMultiSelectActionHandler(private val activity: MainActivity, private v fun handleAction(id: Int) { when (id) { - R.id.remove_feed -> { - RemoveFeedDialog.show(activity, selectedItems) - } + R.id.remove_feed -> RemoveFeedDialog.show(activity, selectedItems) // R.id.notify_new_episodes -> { // notifyNewEpisodesPrefHandler() // } - R.id.keep_updated -> { - keepUpdatedPrefHandler() - } - R.id.autodownload -> { - autoDownloadPrefHandler() - } - R.id.autoDeleteDownload -> { - autoDeleteEpisodesPrefHandler() - } - R.id.playback_speed -> { - playbackSpeedPrefHandler() - } - R.id.edit_tags -> { - editFeedPrefTags() - } - else -> { - Log.e(TAG, "Unrecognized speed dial action item. Do nothing. id=$id") - } + R.id.keep_updated -> keepUpdatedPrefHandler() + R.id.autodownload -> autoDownloadPrefHandler() + R.id.autoDeleteDownload -> autoDeleteEpisodesPrefHandler() + R.id.playback_speed -> playbackSpeedPrefHandler() + R.id.edit_tags -> editFeedPrefTags() + else -> Log.e(TAG, "Unrecognized speed dial action item. Do nothing. id=$id") } } @@ -68,9 +54,7 @@ class FeedMultiSelectActionHandler(private val activity: MainActivity, private v // } private fun autoDownloadPrefHandler() { - val preferenceSwitchDialog = PreferenceSwitchDialog(activity, - activity.getString(R.string.auto_download_settings_label), - activity.getString(R.string.auto_download_label)) + val preferenceSwitchDialog = PreferenceSwitchDialog(activity, activity.getString(R.string.auto_download_settings_label), activity.getString(R.string.auto_download_label)) preferenceSwitchDialog.setOnPreferenceChangedListener(@UnstableApi object: PreferenceSwitchDialog.OnPreferenceChangedListener { override fun preferenceChanged(enabled: Boolean) { saveFeedPreferences { feedPreferences: FeedPreferences -> feedPreferences.autoDownload = enabled } @@ -80,11 +64,9 @@ class FeedMultiSelectActionHandler(private val activity: MainActivity, private v } @UnstableApi private fun playbackSpeedPrefHandler() { - val viewBinding = - PlaybackSpeedFeedSettingDialogBinding.inflate(activity.layoutInflater) + val viewBinding = PlaybackSpeedFeedSettingDialogBinding.inflate(activity.layoutInflater) viewBinding.seekBar.setProgressChangedListener { speed: Float? -> - viewBinding.currentSpeedLabel.text = String.format( - Locale.getDefault(), "%.2fx", speed) + viewBinding.currentSpeedLabel.text = String.format(Locale.getDefault(), "%.2fx", speed) } viewBinding.useGlobalCheckbox.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean -> viewBinding.seekBar.isEnabled = !isChecked @@ -107,8 +89,7 @@ class FeedMultiSelectActionHandler(private val activity: MainActivity, private v } private fun autoDeleteEpisodesPrefHandler() { - val preferenceListDialog = PreferenceListDialog(activity, - activity.getString(R.string.auto_delete_label)) + val preferenceListDialog = PreferenceListDialog(activity, activity.getString(R.string.auto_delete_label)) val items: Array = activity.resources.getStringArray(R.array.spnAutoDeleteItems) preferenceListDialog.openDialog(items) preferenceListDialog.setOnPreferenceChangedListener(object: PreferenceListDialog.OnPreferenceChangedListener { @@ -122,9 +103,7 @@ class FeedMultiSelectActionHandler(private val activity: MainActivity, private v } private fun keepUpdatedPrefHandler() { - val preferenceSwitchDialog = PreferenceSwitchDialog(activity, - activity.getString(R.string.kept_updated), - activity.getString(R.string.keep_updated_summary)) + val preferenceSwitchDialog = PreferenceSwitchDialog(activity, activity.getString(R.string.kept_updated), activity.getString(R.string.keep_updated_summary)) preferenceSwitchDialog.setOnPreferenceChangedListener(object: PreferenceSwitchDialog.OnPreferenceChangedListener { @UnstableApi override fun preferenceChanged(keepUpdated: Boolean) { saveFeedPreferences { feedPreferences: FeedPreferences -> @@ -136,8 +115,7 @@ class FeedMultiSelectActionHandler(private val activity: MainActivity, private v } @UnstableApi private fun showMessage(@PluralsRes msgId: Int, numItems: Int) { - activity.showSnackbarAbovePlayer(activity.resources - .getQuantityString(msgId, numItems, numItems), Snackbar.LENGTH_LONG) + activity.showSnackbarAbovePlayer(activity.resources.getQuantityString(msgId, numItems, numItems), Snackbar.LENGTH_LONG) } @UnstableApi private fun saveFeedPreferences(preferencesConsumer: Consumer) { @@ -155,8 +133,7 @@ class FeedMultiSelectActionHandler(private val activity: MainActivity, private v if (feed.preferences == null) continue preferencesList.add(feed.preferences!!) } - TagSettingsDialog.newInstance(preferencesList).show(activity.supportFragmentManager, - TagSettingsDialog.TAG) + TagSettingsDialog.newInstance(preferencesList).show(activity.supportFragmentManager, TagSettingsDialog.TAG) } companion object { diff --git a/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/DeleteActionButton.kt b/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/DeleteActionButton.kt index 78a621fe..1fd4e1bb 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/DeleteActionButton.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/DeleteActionButton.kt @@ -17,16 +17,12 @@ class DeleteActionButton(item: FeedItem) : ItemActionButton(item) { } @UnstableApi override fun onClick(context: Context) { val media = item.media ?: return - showLocalFeedDeleteWarningIfNecessary(context, listOf(item)) { DBWriter.deleteFeedMediaOfItem(context, media.id) } } override val visibility: Int get() { - if (item.media != null && (item.media!!.isDownloaded() || item.feed?.isLocalFeed == true)) { - return View.VISIBLE - } - + if (item.media != null && (item.media!!.isDownloaded() || item.feed?.isLocalFeed == true)) return View.VISIBLE return View.INVISIBLE } } diff --git a/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/DownloadActionButton.kt b/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/DownloadActionButton.kt index 3c24c2f1..b04cf608 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/DownloadActionButton.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/DownloadActionButton.kt @@ -26,9 +26,7 @@ class DownloadActionButton(item: FeedItem) : ItemActionButton(item) { override fun onClick(context: Context) { val media = item.media - if (media == null || shouldNotDownload(media)) { - return - } + if (media == null || shouldNotDownload(media)) return logAction(UsageStatistics.ACTION_DOWNLOAD) @@ -37,16 +35,13 @@ class DownloadActionButton(item: FeedItem) : ItemActionButton(item) { } else { val builder = MaterialAlertDialogBuilder(context) .setTitle(R.string.confirm_mobile_download_dialog_title) - .setPositiveButton(R.string.confirm_mobile_download_dialog_download_later - ) { _: DialogInterface?, _: Int -> DownloadServiceInterface.get()?.downloadNow(context, item, false) } - .setNeutralButton(R.string.confirm_mobile_download_dialog_allow_this_time - ) { _: DialogInterface?, _: Int -> DownloadServiceInterface.get()?.downloadNow(context, item, true) } + .setPositiveButton(R.string.confirm_mobile_download_dialog_download_later) { _: DialogInterface?, _: Int -> + DownloadServiceInterface.get()?.downloadNow(context, item, false) } + .setNeutralButton(R.string.confirm_mobile_download_dialog_allow_this_time) { _: DialogInterface?, _: Int -> + DownloadServiceInterface.get()?.downloadNow(context, item, true) } .setNegativeButton(R.string.cancel_label, null) - if (isNetworkRestricted && isVpnOverWifi) { - builder.setMessage(R.string.confirm_mobile_download_dialog_message_vpn) - } else { - builder.setMessage(R.string.confirm_mobile_download_dialog_message) - } + if (isNetworkRestricted && isVpnOverWifi) builder.setMessage(R.string.confirm_mobile_download_dialog_message_vpn) + else builder.setMessage(R.string.confirm_mobile_download_dialog_message) builder.show() } diff --git a/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/ItemActionButton.kt b/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/ItemActionButton.kt index 6b3dd54c..b06c76b3 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/ItemActionButton.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/ItemActionButton.kt @@ -36,27 +36,13 @@ abstract class ItemActionButton internal constructor(@JvmField var item: FeedIte else -> DownloadServiceInterface.get()?.isDownloadingEpisode(media.download_url!!)?:false } return when { - media.getMediaType() == MediaType.FLASH -> { - VisitWebsiteActionButton(item) - } - isCurrentlyPlaying(media) -> { - PauseActionButton(item) - } - item.feed != null && item.feed!!.isLocalFeed -> { - PlayLocalActionButton(item) - } - media.isDownloaded() -> { - PlayActionButton(item) - } - isDownloadingMedia -> { - CancelDownloadActionButton(item) - } - isStreamOverDownload || item.feed == null || item.feedId == 0L -> { - StreamActionButton(item) - } - else -> { - DownloadActionButton(item) - } + media.getMediaType() == MediaType.FLASH -> VisitWebsiteActionButton(item) + isCurrentlyPlaying(media) -> PauseActionButton(item) + item.feed != null && item.feed!!.isLocalFeed -> PlayLocalActionButton(item) + media.isDownloaded() -> PlayActionButton(item) + isDownloadingMedia -> CancelDownloadActionButton(item) + isStreamOverDownload || item.feed == null || item.feedId == 0L -> StreamActionButton(item) + else -> DownloadActionButton(item) } } } diff --git a/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/MarkAsPlayedActionButton.kt b/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/MarkAsPlayedActionButton.kt index 3d9c0580..08ffbfbf 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/MarkAsPlayedActionButton.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/MarkAsPlayedActionButton.kt @@ -15,9 +15,7 @@ class MarkAsPlayedActionButton(item: FeedItem) : ItemActionButton(item) { return R.drawable.ic_check } @UnstableApi override fun onClick(context: Context) { - if (!item.isPlayed()) { - DBWriter.markItemPlayed(item, FeedItem.PLAYED, true) - } + if (!item.isPlayed()) DBWriter.markItemPlayed(item, FeedItem.PLAYED, true) } override val visibility: Int diff --git a/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/PauseActionButton.kt b/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/PauseActionButton.kt index 9d22be8e..68a705f6 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/PauseActionButton.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/PauseActionButton.kt @@ -18,8 +18,6 @@ class PauseActionButton(item: FeedItem) : ItemActionButton(item) { @UnstableApi override fun onClick(context: Context) { val media = item.media ?: return - if (isCurrentlyPlaying(media)) { - context.sendBroadcast(createIntent(context, KeyEvent.KEYCODE_MEDIA_PAUSE)) - } + if (isCurrentlyPlaying(media)) context.sendBroadcast(createIntent(context, KeyEvent.KEYCODE_MEDIA_PAUSE)) } } diff --git a/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/PlayActionButton.kt b/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/PlayActionButton.kt index 8940dacb..bf7d2b95 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/PlayActionButton.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/PlayActionButton.kt @@ -32,8 +32,6 @@ class PlayActionButton(item: FeedItem) : ItemActionButton(item) { .callEvenIfRunning(true) .start() - if (media.getMediaType() == MediaType.VIDEO) { - context.startActivity(getPlayerActivityIntent(context, MediaType.VIDEO)) - } + if (media.getMediaType() == MediaType.VIDEO) context.startActivity(getPlayerActivityIntent(context, MediaType.VIDEO)) } } diff --git a/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/PlayLocalActionButton.kt b/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/PlayLocalActionButton.kt index f0b7ecbe..87184148 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/PlayLocalActionButton.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/PlayLocalActionButton.kt @@ -22,8 +22,6 @@ class PlayLocalActionButton(item: FeedItem?) : ItemActionButton(item!!) { .callEvenIfRunning(true) .start() - if (media.getMediaType() == MediaType.VIDEO) { - context.startActivity(getPlayerActivityIntent(context, MediaType.VIDEO)) - } + if (media.getMediaType() == MediaType.VIDEO) context.startActivity(getPlayerActivityIntent(context, MediaType.VIDEO)) } } diff --git a/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/StreamActionButton.kt b/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/StreamActionButton.kt index a7959876..4ff3b8d5 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/StreamActionButton.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/actions/actionbutton/StreamActionButton.kt @@ -42,8 +42,6 @@ class StreamActionButton(item: FeedItem) : ItemActionButton(item) { .callEvenIfRunning(true) .start() - if (media.getMediaType() == MediaType.VIDEO) { - context.startActivity(getPlayerActivityIntent(context, MediaType.VIDEO)) - } + if (media.getMediaType() == MediaType.VIDEO) context.startActivity(getPlayerActivityIntent(context, MediaType.VIDEO)) } } diff --git a/app/src/main/java/ac/mdiq/podcini/ui/actions/menuhandler/FeedItemMenuHandler.kt b/app/src/main/java/ac/mdiq/podcini/ui/actions/menuhandler/FeedItemMenuHandler.kt index c246fdc0..1d6a44cf 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/actions/menuhandler/FeedItemMenuHandler.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/actions/menuhandler/FeedItemMenuHandler.kt @@ -54,8 +54,7 @@ object FeedItemMenuHandler { setItemVisibility(menu, R.id.skip_episode_item, isPlaying) setItemVisibility(menu, R.id.remove_from_queue_item, isInQueue) setItemVisibility(menu, R.id.add_to_queue_item, !isInQueue && selectedItem.media != null) - setItemVisibility(menu, R.id.visit_website_item, !(selectedItem.feed?.isLocalFeed?:false) - && ShareUtils.hasLinkToShare(selectedItem)) + setItemVisibility(menu, R.id.visit_website_item, !(selectedItem.feed?.isLocalFeed?:false) && ShareUtils.hasLinkToShare(selectedItem)) setItemVisibility(menu, R.id.share_item, !(selectedItem.feed?.isLocalFeed?:false)) setItemVisibility(menu, R.id.mark_read_item, !selectedItem.isPlayed()) setItemVisibility(menu, R.id.mark_unread_item, selectedItem.isPlayed()) @@ -131,14 +130,10 @@ object FeedItemMenuHandler { fun onMenuItemClicked(fragment: Fragment, menuItemId: Int, selectedItem: FeedItem): Boolean { val context = fragment.requireContext() when (menuItemId) { - R.id.skip_episode_item -> { - context.sendBroadcast(MediaButtonReceiver.createIntent(context, KeyEvent.KEYCODE_MEDIA_NEXT)) - } + R.id.skip_episode_item -> context.sendBroadcast(MediaButtonReceiver.createIntent(context, KeyEvent.KEYCODE_MEDIA_NEXT)) R.id.remove_item -> { - LocalDeleteModal.showLocalFeedDeleteWarningIfNecessary(context, listOf(selectedItem) - ) { - if (selectedItem.media != null) DBWriter.deleteFeedMediaOfItem(context, - selectedItem.media!!.id) + LocalDeleteModal.showLocalFeedDeleteWarningIfNecessary(context, listOf(selectedItem)) { + if (selectedItem.media != null) DBWriter.deleteFeedMediaOfItem(context, selectedItem.media!!.id) } } R.id.mark_read_item -> { @@ -168,18 +163,10 @@ object FeedItemMenuHandler { SynchronizationQueueSink.enqueueEpisodeActionIfSynchronizationIsActive(context, actionNew) } } - R.id.add_to_queue_item -> { - DBWriter.addQueueItem(context, selectedItem) - } - R.id.remove_from_queue_item -> { - DBWriter.removeQueueItem(context, true, selectedItem) - } - R.id.add_to_favorites_item -> { - DBWriter.addFavoriteItem(selectedItem) - } - R.id.remove_from_favorites_item -> { - DBWriter.removeFavoriteItem(selectedItem) - } + R.id.add_to_queue_item -> DBWriter.addQueueItem(context, selectedItem) + R.id.remove_from_queue_item -> DBWriter.removeQueueItem(context, true, selectedItem) + R.id.add_to_favorites_item -> DBWriter.addFavoriteItem(selectedItem) + R.id.remove_from_favorites_item -> DBWriter.removeFavoriteItem(selectedItem) R.id.reset_position -> { selectedItem.media?.setPosition(0) if (PlaybackPreferences.currentlyPlayingFeedMediaId == (selectedItem.media?.id ?: "")) { @@ -212,12 +199,8 @@ object FeedItemMenuHandler { * Undo is useful for Remove new flag, given there is no UI to undo it otherwise * ,i.e., there is (context) menu item for add new flag */ - fun markReadWithUndo(fragment: Fragment, item: FeedItem?, - playState: Int, showSnackbar: Boolean - ) { - if (item == null) { - return - } + fun markReadWithUndo(fragment: Fragment, item: FeedItem?, playState: Int, showSnackbar: Boolean) { + if (item == null) return Log.d(TAG, "markReadWithUndo(" + item.id + ")") // we're marking it as unplayed since the user didn't actually play it @@ -228,24 +211,15 @@ object FeedItemMenuHandler { val r = Runnable { val media: FeedMedia? = item.media val shouldAutoDelete: Boolean = if (item.feed == null) false else FeedUtil.shouldAutoDeleteItemsOnThatFeed(item.feed!!) - if (media != null && FeedItemUtil.hasAlmostEnded(media) && shouldAutoDelete) { + if (media != null && FeedItemUtil.hasAlmostEnded(media) && shouldAutoDelete) DBWriter.deleteFeedMediaOfItem(fragment.requireContext(), media.id) - } } val playStateStringRes: Int = when (playState) { - FeedItem.UNPLAYED -> if (item.playState == FeedItem.NEW) { - //was new - R.string.removed_inbox_label - } else { - //was played - R.string.marked_as_unplayed_label - } + FeedItem.UNPLAYED -> if (item.playState == FeedItem.NEW) R.string.removed_inbox_label //was new + else R.string.marked_as_unplayed_label //was played FeedItem.PLAYED -> R.string.marked_as_played_label - else -> if (item.playState == FeedItem.NEW) { - R.string.removed_inbox_label - } else { - R.string.marked_as_unplayed_label - } + else -> if (item.playState == FeedItem.NEW) R.string.removed_inbox_label + else R.string.marked_as_unplayed_label } val duration: Int = Snackbar.LENGTH_LONG diff --git a/app/src/main/java/ac/mdiq/podcini/ui/actions/menuhandler/FeedMenuHandler.kt b/app/src/main/java/ac/mdiq/podcini/ui/actions/menuhandler/FeedMenuHandler.kt index 94a32dd7..40f0fd26 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/actions/menuhandler/FeedMenuHandler.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/actions/menuhandler/FeedMenuHandler.kt @@ -20,22 +20,14 @@ object FeedMenuHandler { ): Boolean { val context = fragment.requireContext() when (menuItemId) { - R.id.rename_folder_item -> { - RenameItemDialog(fragment.activity as Activity, selectedFeed).show() - } + R.id.rename_folder_item -> RenameItemDialog(fragment.activity as Activity, selectedFeed).show() R.id.edit_tags -> { if (selectedFeed.preferences != null) TagSettingsDialog.newInstance(listOf(selectedFeed.preferences!!)) .show(fragment.childFragmentManager, TagSettingsDialog.TAG) } - R.id.rename_item -> { - RenameItemDialog(fragment.activity as Activity, selectedFeed).show() - } - R.id.remove_feed -> { - RemoveFeedDialog.show(context, selectedFeed, null) - } - else -> { - return false - } + R.id.rename_item -> RenameItemDialog(fragment.activity as Activity, selectedFeed).show() + R.id.remove_feed -> RemoveFeedDialog.show(context, selectedFeed, null) + else -> return false } return true } diff --git a/app/src/main/java/ac/mdiq/podcini/ui/actions/menuhandler/MenuItemUtils.kt b/app/src/main/java/ac/mdiq/podcini/ui/actions/menuhandler/MenuItemUtils.kt index 3372e512..9ad6b855 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/actions/menuhandler/MenuItemUtils.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/actions/menuhandler/MenuItemUtils.kt @@ -19,9 +19,7 @@ object MenuItemUtils { */ fun setOnClickListeners(menu: Menu?, listener: MenuItem.OnMenuItemClickListener?) { for (i in 0 until menu!!.size()) { - if (menu.getItem(i).subMenu != null) { - setOnClickListeners(menu.getItem(i).subMenu, listener) - } + if (menu.getItem(i).subMenu != null) setOnClickListeners(menu.getItem(i).subMenu, listener) menu.getItem(i).setOnMenuItemClickListener(listener) } } diff --git a/app/src/main/java/ac/mdiq/podcini/ui/actions/swipeactions/AddToQueueSwipeAction.kt b/app/src/main/java/ac/mdiq/podcini/ui/actions/swipeactions/AddToQueueSwipeAction.kt index 7fa84144..8e39ba55 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/actions/swipeactions/AddToQueueSwipeAction.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/actions/swipeactions/AddToQueueSwipeAction.kt @@ -27,11 +27,8 @@ class AddToQueueSwipeAction : SwipeAction { } @OptIn(UnstableApi::class) override fun performAction(item: FeedItem, fragment: Fragment, filter: FeedItemFilter) { - if (!item.isTagged(FeedItem.TAG_QUEUE)) { - DBWriter.addQueueItem(fragment.requireContext(), item) - } else { - RemoveFromQueueSwipeAction().performAction(item, fragment, filter) - } + if (!item.isTagged(FeedItem.TAG_QUEUE)) DBWriter.addQueueItem(fragment.requireContext(), item) + else RemoveFromQueueSwipeAction().performAction(item, fragment, filter) } override fun willRemove(filter: FeedItemFilter, item: FeedItem): Boolean { diff --git a/app/src/main/java/ac/mdiq/podcini/ui/actions/swipeactions/DeleteSwipeAction.kt b/app/src/main/java/ac/mdiq/podcini/ui/actions/swipeactions/DeleteSwipeAction.kt index f0baa067..a817c5f4 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/actions/swipeactions/DeleteSwipeAction.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/actions/swipeactions/DeleteSwipeAction.kt @@ -27,9 +27,8 @@ class DeleteSwipeAction : SwipeAction { } @UnstableApi override fun performAction(item: FeedItem, fragment: Fragment, filter: FeedItemFilter) { - if (!item.isDownloaded && item.feed?.isLocalFeed != true) { - return - } + if (!item.isDownloaded && item.feed?.isLocalFeed != true) return + showLocalFeedDeleteWarningIfNecessary(fragment.requireContext(), listOf(item)) { if (item.media != null) DBWriter.deleteFeedMediaOfItem(fragment.requireContext(), item.media!!.id) } diff --git a/app/src/main/java/ac/mdiq/podcini/ui/actions/swipeactions/NoActionSwipeAction.kt b/app/src/main/java/ac/mdiq/podcini/ui/actions/swipeactions/NoActionSwipeAction.kt index b7c638d8..05a6c031 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/actions/swipeactions/NoActionSwipeAction.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/actions/swipeactions/NoActionSwipeAction.kt @@ -24,8 +24,7 @@ class NoActionSwipeAction : SwipeAction { return context.getString(R.string.no_action_label) } - @UnstableApi override fun performAction(item: FeedItem, fragment: Fragment, filter: FeedItemFilter) { - } + @UnstableApi override fun performAction(item: FeedItem, fragment: Fragment, filter: FeedItemFilter) {} override fun willRemove(filter: FeedItemFilter, item: FeedItem): Boolean { return false diff --git a/app/src/main/java/ac/mdiq/podcini/ui/actions/swipeactions/RemoveFromHistorySwipeAction.kt b/app/src/main/java/ac/mdiq/podcini/ui/actions/swipeactions/RemoveFromHistorySwipeAction.kt index 6755df58..661c0fb4 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/actions/swipeactions/RemoveFromHistorySwipeAction.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/actions/swipeactions/RemoveFromHistorySwipeAction.kt @@ -36,8 +36,8 @@ class RemoveFromHistorySwipeAction : SwipeAction { (fragment.requireActivity() as MainActivity) .showSnackbarAbovePlayer(R.string.removed_history_label, Snackbar.LENGTH_LONG) - .setAction(fragment.getString(R.string.undo) - ) { if (playbackCompletionDate != null) DBWriter.addItemToPlaybackHistory(item.media, playbackCompletionDate) } + .setAction(fragment.getString(R.string.undo)) { + if (playbackCompletionDate != null) DBWriter.addItemToPlaybackHistory(item.media, playbackCompletionDate) } } override fun willRemove(filter: FeedItemFilter, item: FeedItem): Boolean { diff --git a/app/src/main/java/ac/mdiq/podcini/ui/actions/swipeactions/RemoveFromQueueSwipeAction.kt b/app/src/main/java/ac/mdiq/podcini/ui/actions/swipeactions/RemoveFromQueueSwipeAction.kt index c6e83787..69a6bbd8 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/actions/swipeactions/RemoveFromQueueSwipeAction.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/actions/swipeactions/RemoveFromQueueSwipeAction.kt @@ -35,14 +35,9 @@ class RemoveFromQueueSwipeAction : SwipeAction { DBWriter.removeQueueItem(fragment.requireActivity(), true, item) if (willRemove(filter, item)) { - (fragment.requireActivity() as MainActivity).showSnackbarAbovePlayer( - fragment.resources.getQuantityString(R.plurals.removed_from_queue_batch_label, 1, 1), - Snackbar.LENGTH_LONG) + (fragment.requireActivity() as MainActivity).showSnackbarAbovePlayer(fragment.resources.getQuantityString(R.plurals.removed_from_queue_batch_label, 1, 1), Snackbar.LENGTH_LONG) .setAction(fragment.getString(R.string.undo)) { - DBWriter.addQueueItemAt(fragment.requireActivity(), - item.id, - position, - false) + DBWriter.addQueueItemAt(fragment.requireActivity(), item.id, position, false) } } } diff --git a/app/src/main/java/ac/mdiq/podcini/ui/actions/swipeactions/StartDownloadSwipeAction.kt b/app/src/main/java/ac/mdiq/podcini/ui/actions/swipeactions/StartDownloadSwipeAction.kt index 697fac8d..8e748610 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/actions/swipeactions/StartDownloadSwipeAction.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/actions/swipeactions/StartDownloadSwipeAction.kt @@ -26,8 +26,7 @@ class StartDownloadSwipeAction : SwipeAction { override fun performAction(item: FeedItem, fragment: Fragment, filter: FeedItemFilter) { if (!item.isDownloaded && item.feed != null && !item.feed!!.isLocalFeed) { - DownloadActionButton(item) - .onClick(fragment.requireContext()) + DownloadActionButton(item).onClick(fragment.requireContext()) } } diff --git a/app/src/main/java/ac/mdiq/podcini/ui/actions/swipeactions/SwipeActions.kt b/app/src/main/java/ac/mdiq/podcini/ui/actions/swipeactions/SwipeActions.kt index d9223fb9..4f6deb8b 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/actions/swipeactions/SwipeActions.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/actions/swipeactions/SwipeActions.kt @@ -63,10 +63,7 @@ open class SwipeActions(dragDirs: Int, private val fragment: Fragment, private v private val isSwipeActionEnabled: Boolean get() = isSwipeActionEnabled(fragment.requireContext(), tag) - override fun onMove(recyclerView: RecyclerView, - viewHolder: RecyclerView.ViewHolder, - target: RecyclerView.ViewHolder - ): Boolean { + override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean { return false } @@ -98,10 +95,8 @@ open class SwipeActions(dragDirs: Int, private val fragment: Fragment, private v }) } - @UnstableApi override fun onChildDraw(c: Canvas, recyclerView: RecyclerView, - viewHolder: RecyclerView.ViewHolder, - dx: Float, dy: Float, actionState: Int, isCurrentlyActive: Boolean - ) { + @UnstableApi override fun onChildDraw(c: Canvas, recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, + dx: Float, dy: Float, actionState: Int, isCurrentlyActive: Boolean) { var dx = dx val right: SwipeAction val left: SwipeAction @@ -140,25 +135,18 @@ open class SwipeActions(dragDirs: Int, private val fragment: Fragment, private v val dir = if (dx > 0) ItemTouchHelper.RIGHT else ItemTouchHelper.LEFT swipedOutTo = if (swipeThresholdReached) dir else 0 } - } else { - swipeOutEnabled = true - } + } else swipeOutEnabled = true //add color and icon val context = fragment.requireContext() val themeColor = getColorFromAttr(context, android.R.attr.colorBackground) - val actionColor = getColorFromAttr(context, - if (dx > 0) right.getActionColor() else left.getActionColor()) - val builder = RecyclerViewSwipeDecorator.Builder( - c, recyclerView, viewHolder, dx, dy, actionState, isCurrentlyActive) + val actionColor = getColorFromAttr(context, if (dx > 0) right.getActionColor() else left.getActionColor()) + val builder = RecyclerViewSwipeDecorator.Builder(c, recyclerView, viewHolder, dx, dy, actionState, isCurrentlyActive) .addSwipeRightActionIcon(right.getActionIcon()) .addSwipeLeftActionIcon(left.getActionIcon()) .addSwipeRightBackgroundColor(getColorFromAttr(context, R.attr.background_elevated)) .addSwipeLeftBackgroundColor(getColorFromAttr(context, R.attr.background_elevated)) - .setActionIconTint( - ColorUtils.blendARGB(themeColor, - actionColor, - max(0.5, displacementPercentage.toDouble()).toFloat())) + .setActionIconTint(ColorUtils.blendARGB(themeColor, actionColor, max(0.5, displacementPercentage.toDouble()).toFloat())) builder.create().decorate() super.onChildDraw(c, recyclerView, viewHolder, dx, dy, actionState, isCurrentlyActive) @@ -186,12 +174,8 @@ open class SwipeActions(dragDirs: Int, private val fragment: Fragment, private v } override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int { - return if (!isSwipeActionEnabled) { - makeMovementFlags(getDragDirs(recyclerView, viewHolder), - 0) - } else { - super.getMovementFlags(recyclerView, viewHolder) - } + return if (!isSwipeActionEnabled) makeMovementFlags(getDragDirs(recyclerView, viewHolder), 0) + else super.getMovementFlags(recyclerView, viewHolder) } fun startDrag(holder: EpisodeItemViewHolder?) { @@ -207,10 +191,8 @@ open class SwipeActions(dragDirs: Int, private val fragment: Fragment, private v init { val actions = prefs!!.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() if (actions.size == 2) { - this.right = Stream.of(swipeActions) - .filter { a: SwipeAction -> a.getId().equals(actions[0]) }.single() - this.left = Stream.of(swipeActions) - .filter { a: SwipeAction -> a.getId().equals(actions[1]) }.single() + this.right = Stream.of(swipeActions).filter { a: SwipeAction -> a.getId().equals(actions[0]) }.single() + this.left = Stream.of(swipeActions).filter { a: SwipeAction -> a.getId().equals(actions[1]) }.single() } } diff --git a/app/src/main/java/ac/mdiq/podcini/ui/actions/swipeactions/TogglePlaybackStateSwipeAction.kt b/app/src/main/java/ac/mdiq/podcini/ui/actions/swipeactions/TogglePlaybackStateSwipeAction.kt index 210db884..878a77f5 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/actions/swipeactions/TogglePlaybackStateSwipeAction.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/actions/swipeactions/TogglePlaybackStateSwipeAction.kt @@ -30,10 +30,7 @@ class TogglePlaybackStateSwipeAction : SwipeAction { } override fun willRemove(filter: FeedItemFilter, item: FeedItem): Boolean { - return if (item.playState == FeedItem.NEW) { - filter.showPlayed || filter.showNew - } else { - filter.showUnplayed || filter.showPlayed || filter.showNew - } + return if (item.playState == FeedItem.NEW) filter.showPlayed || filter.showNew + else filter.showUnplayed || filter.showPlayed || filter.showNew } } diff --git a/app/src/main/java/ac/mdiq/podcini/ui/activity/BugReportActivity.kt b/app/src/main/java/ac/mdiq/podcini/ui/activity/BugReportActivity.kt index 1405411b..993acff4 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/activity/BugReportActivity.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/activity/BugReportActivity.kt @@ -42,11 +42,9 @@ class BugReportActivity : AppCompatActivity() { var stacktrace = "No crash report recorded" try { val crashFile = CrashReportWriter.file - if (crashFile.exists()) { - stacktrace = IOUtils.toString(FileInputStream(crashFile), Charset.forName("UTF-8")) - } else { - Log.d(TAG, stacktrace) - } + if (crashFile.exists()) stacktrace = IOUtils.toString(FileInputStream(crashFile), Charset.forName("UTF-8")) + else Log.d(TAG, stacktrace) + } catch (e: IOException) { e.printStackTrace() } @@ -59,17 +57,14 @@ class BugReportActivity : AppCompatActivity() { """.trimIndent() binding.btnOpenBugTracker.setOnClickListener { - openInBrowser( - this@BugReportActivity, "https://github.com/XilinJia/Podcini/issues") + openInBrowser(this@BugReportActivity, "https://github.com/XilinJia/Podcini/issues") } binding.btnCopyLog.setOnClickListener { val clipboard = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager val clip = ClipData.newPlainText(getString(R.string.bug_report_title), crashDetailsTextView.text) clipboard.setPrimaryClip(clip) - if (Build.VERSION.SDK_INT < 32) { - Snackbar.make(binding.root, R.string.copied_to_clipboard, Snackbar.LENGTH_SHORT).show() - } + if (Build.VERSION.SDK_INT < 32) Snackbar.make(binding.root, R.string.copied_to_clipboard, Snackbar.LENGTH_SHORT).show() } } @@ -125,7 +120,6 @@ class BugReportActivity : AppCompatActivity() { } } - companion object { private const val TAG = "BugReportActivity" } diff --git a/app/src/main/java/ac/mdiq/podcini/ui/activity/MainActivity.kt b/app/src/main/java/ac/mdiq/podcini/ui/activity/MainActivity.kt index 2713c7d6..364aff2b 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/activity/MainActivity.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/activity/MainActivity.kt @@ -195,9 +195,8 @@ class MainActivity : CastEnabledActivity() { for (workInfo in workInfos) { var downloadUrl: String? = null for (tag in workInfo.tags) { - if (tag.startsWith(DownloadServiceInterface.WORK_TAG_EPISODE_URL)) { + if (tag.startsWith(DownloadServiceInterface.WORK_TAG_EPISODE_URL)) downloadUrl = tag.substring(DownloadServiceInterface.WORK_TAG_EPISODE_URL.length) - } } if (downloadUrl == null) continue @@ -460,7 +459,6 @@ class MainActivity : CastEnabledActivity() { override fun onRestoreInstanceState(savedInstanceState: Bundle) { super.onRestoreInstanceState(savedInstanceState) - if (bottomSheet.state == BottomSheetBehavior.STATE_EXPANDED) bottomSheetCallback.onSlide(dummyView, 1.0f) } @@ -476,9 +474,7 @@ class MainActivity : CastEnabledActivity() { // MediaController implements the Player interface, so it can be // attached to the PlayerView UI component. // playerView.setPlayer(controllerFuture.get()) - }, - MoreExecutors.directExecutor() - ) + }, MoreExecutors.directExecutor()) } override fun onResume() { @@ -538,9 +534,7 @@ class MainActivity : CastEnabledActivity() { if (NavDrawerFragment.getLastNavFragment(this) == toPage || UserPreferences.DEFAULT_PAGE_REMEMBER == toPage) { if (backButtonOpensDrawer()) drawerLayout?.openDrawer(navDrawer) else super.onBackPressed() - } else { - loadFragment(toPage, null) - } + } else loadFragment(toPage, null) } } } @@ -588,12 +582,11 @@ class MainActivity : CastEnabledActivity() { if (intent.getBooleanExtra(MainActivityStarter.EXTRA_OPEN_DRAWER, false)) drawerLayout?.open() - if (intent.getBooleanExtra(MainActivityStarter.EXTRA_OPEN_DOWNLOAD_LOGS, false)) { + if (intent.getBooleanExtra(MainActivityStarter.EXTRA_OPEN_DOWNLOAD_LOGS, false)) DownloadLogFragment().show(supportFragmentManager, null) - } - if (intent.getBooleanExtra(EXTRA_REFRESH_ON_START, false)) { - runOnceOrAsk(this) - } + + if (intent.getBooleanExtra(EXTRA_REFRESH_ON_START, false)) runOnceOrAsk(this) + // to avoid handling the intent twice when the configuration changes setIntent(Intent(this@MainActivity, MainActivity::class.java)) } @@ -610,9 +603,8 @@ class MainActivity : CastEnabledActivity() { if (bottomSheet.state == BottomSheetBehavior.STATE_COLLAPSED) { s = Snackbar.make(mainView, text!!, duration) if (audioPlayerFragmentView.visibility == View.VISIBLE) s.setAnchorView(audioPlayerFragmentView) - } else { - s = Snackbar.make(binding.root, text!!, duration) - } + } else s = Snackbar.make(binding.root, text!!, duration) + s.show() return s } diff --git a/app/src/main/java/ac/mdiq/podcini/ui/activity/OnlineFeedViewActivity.kt b/app/src/main/java/ac/mdiq/podcini/ui/activity/OnlineFeedViewActivity.kt index a9a2bad4..c5e25cad 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/activity/OnlineFeedViewActivity.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/activity/OnlineFeedViewActivity.kt @@ -21,15 +21,9 @@ class OnlineFeedViewActivity : AppCompatActivity() { var feedUrl: String? = null when { - intent.hasExtra(ARG_FEEDURL) -> { - feedUrl = intent.getStringExtra(ARG_FEEDURL) - } - TextUtils.equals(intent.action, Intent.ACTION_SEND) -> { - feedUrl = intent.getStringExtra(Intent.EXTRA_TEXT) - } - TextUtils.equals(intent.action, Intent.ACTION_VIEW) -> { - feedUrl = intent.dataString - } + intent.hasExtra(ARG_FEEDURL) -> feedUrl = intent.getStringExtra(ARG_FEEDURL) + TextUtils.equals(intent.action, Intent.ACTION_SEND) -> feedUrl = intent.getStringExtra(Intent.EXTRA_TEXT) + TextUtils.equals(intent.action, Intent.ACTION_VIEW) -> feedUrl = intent.dataString } if (!feedUrl.isNullOrBlank() && !feedUrl.startsWith("http")) { @@ -45,8 +39,7 @@ class OnlineFeedViewActivity : AppCompatActivity() { Log.d(TAG, "Activity was started with url $feedUrl") val intent = MainActivity.showOnlineFeed(this, feedUrl) - intent.putExtra(MainActivity.EXTRA_STARTED_FROM_SEARCH, - getIntent().getBooleanExtra(MainActivity.EXTRA_STARTED_FROM_SEARCH, false)) + intent.putExtra(MainActivity.EXTRA_STARTED_FROM_SEARCH, getIntent().getBooleanExtra(MainActivity.EXTRA_STARTED_FROM_SEARCH, false)) startActivity(intent) finish() } diff --git a/app/src/main/java/ac/mdiq/podcini/ui/activity/OpmlImportActivity.kt b/app/src/main/java/ac/mdiq/podcini/ui/activity/OpmlImportActivity.kt index ed96f684..510df57c 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/activity/OpmlImportActivity.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/activity/OpmlImportActivity.kt @@ -67,9 +67,7 @@ class OpmlImportActivity : AppCompatActivity() { val checked = binding.feedlist.checkedItemPositions var checkedCount = 0 for (i in 0 until checked.size()) { - if (checked.valueAt(i)) { - checkedCount++ - } + if (checked.valueAt(i)) checkedCount++ } if (listAdapter != null) { if (checkedCount == listAdapter!!.count) { @@ -90,13 +88,11 @@ class OpmlImportActivity : AppCompatActivity() { Completable.fromAction { val checked = binding.feedlist.checkedItemPositions for (i in 0 until checked.size()) { - if (!checked.valueAt(i)) { - continue - } + if (!checked.valueAt(i)) continue + if (!readElements.isNullOrEmpty()) { val element = readElements!![checked.keyAt(i)] - val feed = Feed(element.xmlUrl, null, - if (element.text != null) element.text else "Unknown podcast") + val feed = Feed(element.xmlUrl, null, if (element.text != null) element.text else "Unknown podcast") feed.items = mutableListOf() DBTasks.updateFeed(this, feed, false) } @@ -124,9 +120,7 @@ class OpmlImportActivity : AppCompatActivity() { uri = Uri.parse("file://$uri") } else { val extraText = intent.getStringExtra(Intent.EXTRA_TEXT) - if (extraText != null) { - uri = Uri.parse(extraText) - } + if (extraText != null) uri = Uri.parse(extraText) } importUri(uri) } @@ -179,9 +173,7 @@ class OpmlImportActivity : AppCompatActivity() { selectAll.setVisible(true) return true } - android.R.id.home -> { - finish() - } + android.R.id.home -> finish() } return false } @@ -231,16 +223,13 @@ class OpmlImportActivity : AppCompatActivity() { binding.progressBar.visibility = View.GONE Log.d(TAG, "Parsing was successful") readElements = result - listAdapter = ArrayAdapter(this@OpmlImportActivity, - android.R.layout.simple_list_item_multiple_choice, - titleList) + listAdapter = ArrayAdapter(this@OpmlImportActivity, android.R.layout.simple_list_item_multiple_choice, titleList) binding.feedlist.adapter = listAdapter }, { e: Throwable -> Log.d(TAG, Log.getStackTraceString(e)) val message = if (e.message == null) "" else e.message!! if (message.lowercase().contains("permission")) { - val permission = ActivityCompat.checkSelfPermission(this, - Manifest.permission.READ_EXTERNAL_STORAGE) + val permission = ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) if (permission != PackageManager.PERMISSION_GRANTED) { requestPermission() return@subscribe @@ -257,8 +246,7 @@ class OpmlImportActivity : AppCompatActivity() { $details """.trimIndent() val errorMessage = SpannableString(total) - errorMessage.setSpan(ForegroundColorSpan(-0x77777778), - userReadable.length, total.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) + errorMessage.setSpan(ForegroundColorSpan(-0x77777778), userReadable.length, total.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) alert.setMessage(errorMessage) alert.setPositiveButton(android.R.string.ok) { _: DialogInterface?, _: Int -> finish() } alert.show() diff --git a/app/src/main/java/ac/mdiq/podcini/ui/activity/PreferenceActivity.kt b/app/src/main/java/ac/mdiq/podcini/ui/activity/PreferenceActivity.kt index 20176bf7..a037cd88 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/activity/PreferenceActivity.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/activity/PreferenceActivity.kt @@ -133,9 +133,7 @@ class PreferenceActivity : AppCompatActivity(), SearchPreferenceResultListener { builder.setPositiveButton(android.R.string.ok, null) builder.show() } - R.xml.preferences_notifications -> { - openScreen(screen) - } + R.xml.preferences_notifications -> openScreen(screen) else -> { val fragment = openScreen(result.resourceFile) result.highlight(fragment) diff --git a/app/src/main/java/ac/mdiq/podcini/ui/activity/SelectSubscriptionActivity.kt b/app/src/main/java/ac/mdiq/podcini/ui/activity/SelectSubscriptionActivity.kt index 5d98816a..dc128253 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/activity/SelectSubscriptionActivity.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/activity/SelectSubscriptionActivity.kt @@ -64,9 +64,7 @@ class SelectSubscriptionActivity : AppCompatActivity() { checkedPosition[0] = position } binding.shortcutBtn.setOnClickListener { - if (checkedPosition[0] != null && Intent.ACTION_CREATE_SHORTCUT == intent.action) { - getBitmapFromUrl(listItems[checkedPosition[0]!!]) - } + if (checkedPosition[0] != null && Intent.ACTION_CREATE_SHORTCUT == intent.action) getBitmapFromUrl(listItems[checkedPosition[0]!!]) } } @@ -74,9 +72,7 @@ class SelectSubscriptionActivity : AppCompatActivity() { for (item in items) { if (item == null) continue val feed: Feed = item.feed - if (!result.contains(feed)) { - result.add(feed) - } + if (!result.contains(feed)) result.add(feed) } return result } @@ -88,11 +84,8 @@ class SelectSubscriptionActivity : AppCompatActivity() { intent.putExtra(EXTRA_FEED_ID, feed.id) val id = "subscription-" + feed.id - val icon: IconCompat = if (bitmap != null) { - IconCompat.createWithAdaptiveBitmap(bitmap) - } else { - IconCompat.createWithResource(this, R.drawable.ic_subscriptions_shortcut) - } + val icon: IconCompat = if (bitmap != null) IconCompat.createWithAdaptiveBitmap(bitmap) + else IconCompat.createWithResource(this, R.drawable.ic_subscriptions_shortcut) val shortcut: ShortcutInfoCompat = ShortcutInfoCompat.Builder(this, id) .setShortLabel(feed.title?:"") @@ -112,14 +105,12 @@ class SelectSubscriptionActivity : AppCompatActivity() { .load(feed.imageUrl) .apply(RequestOptions.overrideOf(iconSize, iconSize)) .listener(object : RequestListener { - @UnstableApi override fun onLoadFailed(e: GlideException?, model: Any?, - target: Target, isFirstResource: Boolean): Boolean { + @UnstableApi override fun onLoadFailed(e: GlideException?, model: Any?, target: Target, isFirstResource: Boolean): Boolean { addShortcut(feed, null) return true } - @UnstableApi override fun onResourceReady(resource: Bitmap, model: Any, - target: Target, dataSource: DataSource, isFirstResource: Boolean): Boolean { + @UnstableApi override fun onResourceReady(resource: Bitmap, model: Any, target: Target, dataSource: DataSource, isFirstResource: Boolean): Boolean { addShortcut(feed, resource) return true } @@ -142,8 +133,7 @@ class SelectSubscriptionActivity : AppCompatActivity() { for (feed in result) { if (feed.title != null) titles.add(feed.title!!) } - val adapter: ArrayAdapter = ArrayAdapter(this, - R.layout.simple_list_item_multiple_choice_on_start, titles) + val adapter: ArrayAdapter = ArrayAdapter(this, R.layout.simple_list_item_multiple_choice_on_start, titles) binding.list.adapter = adapter }, { error: Throwable? -> Log.e(TAG, Log.getStackTraceString(error)) }) } diff --git a/app/src/main/java/ac/mdiq/podcini/ui/activity/SplashActivity.kt b/app/src/main/java/ac/mdiq/podcini/ui/activity/SplashActivity.kt index 2c931c5f..5aa7cf07 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/activity/SplashActivity.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/activity/SplashActivity.kt @@ -32,17 +32,16 @@ class SplashActivity : Activity() { } .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe( - { - val intent = Intent(this@SplashActivity, MainActivity::class.java) - startActivity(intent) - overridePendingTransition(0, 0) - finish() - }, { error: Throwable -> - error.printStackTrace() - CrashReportWriter.write(error) - Toast.makeText(this, error.localizedMessage, Toast.LENGTH_LONG).show() - finish() - }) + .subscribe({ + val intent = Intent(this@SplashActivity, MainActivity::class.java) + startActivity(intent) + overridePendingTransition(0, 0) + finish() + }, { error: Throwable -> + error.printStackTrace() + CrashReportWriter.write(error) + Toast.makeText(this, error.localizedMessage, Toast.LENGTH_LONG).show() + finish() + }) } } diff --git a/app/src/main/java/ac/mdiq/podcini/ui/activity/VideoplayerActivity.kt b/app/src/main/java/ac/mdiq/podcini/ui/activity/VideoplayerActivity.kt index 473072df..d2a94d7a 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/activity/VideoplayerActivity.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/activity/VideoplayerActivity.kt @@ -140,9 +140,7 @@ class VideoplayerActivity : CastEnabledActivity() { } public override fun onUserLeaveHint() { - if (!PictureInPictureUtil.isInPictureInPictureMode(this)) { - compatEnterPictureInPicture() - } + if (!PictureInPictureUtil.isInPictureInPictureMode(this)) compatEnterPictureInPicture() } @UnstableApi @@ -171,16 +169,12 @@ class VideoplayerActivity : CastEnabledActivity() { @Subscribe(threadMode = ThreadMode.MAIN) @Suppress("unused") fun sleepTimerUpdate(event: SleepTimerUpdatedEvent) { - if (event.isCancelled || event.wasJustEnabled()) { - supportInvalidateOptionsMenu() - } + if (event.isCancelled || event.wasJustEnabled()) supportInvalidateOptionsMenu() } @Subscribe(threadMode = ThreadMode.MAIN) fun onPlaybackServiceChanged(event: PlaybackServiceEvent) { - if (event.action == PlaybackServiceEvent.Action.SERVICE_SHUT_DOWN) { - finish() - } + if (event.action == PlaybackServiceEvent.Action.SERVICE_SHUT_DOWN) finish() } @Subscribe(threadMode = ThreadMode.MAIN) @@ -196,7 +190,6 @@ class VideoplayerActivity : CastEnabledActivity() { errorDialog.setPositiveButton(event.actionText) { _: DialogInterface?, _: Int -> event.action?.accept(this) } - errorDialog.show() } @@ -216,6 +209,7 @@ class VideoplayerActivity : CastEnabledActivity() { val media = controller.getMedia() val isFeedMedia = (media is FeedMedia) + menu.findItem(R.id.show_home_reader_view).setVisible(false) menu.findItem(R.id.open_feed_item).setVisible(isFeedMedia) // FeedMedia implies it belongs to a Feed val hasWebsiteLink = getWebsiteLinkWithFallback(media) != null @@ -273,21 +267,19 @@ class VideoplayerActivity : CastEnabledActivity() { ChaptersFragment().show(supportFragmentManager, ChaptersFragment.TAG) return true } - controller == null -> { - return false - } + controller == null -> return false else -> { val media = controller.getMedia() ?: return false val feedItem = getFeedItem(media) // some options option requires FeedItem when { item.itemId == R.id.add_to_favorites_item && feedItem != null -> { DBWriter.addFavoriteItem(feedItem) - videoEpisodeFragment.isFavorite = true + videoEpisodeFragment.isFavorite = true invalidateOptionsMenu() } item.itemId == R.id.remove_from_favorites_item && feedItem != null -> { DBWriter.removeFavoriteItem(feedItem) - videoEpisodeFragment.isFavorite = false + videoEpisodeFragment.isFavorite = false invalidateOptionsMenu() } item.itemId == R.id.disable_sleeptimer_item || item.itemId == R.id.set_sleeptimer_item -> { @@ -309,12 +301,9 @@ class VideoplayerActivity : CastEnabledActivity() { val shareDialog = ShareDialog.newInstance(feedItem) shareDialog.show(supportFragmentManager, "ShareEpisodeDialog") } - item.itemId == R.id.playback_speed -> { + item.itemId == R.id.playback_speed -> VariableSpeedDialog.newInstance(booleanArrayOf(true, true, true))?.show(supportFragmentManager, null) - } - else -> { - return false - } + else -> return false } return true } @@ -362,18 +351,15 @@ class VideoplayerActivity : CastEnabledActivity() { return true } KeyEvent.KEYCODE_PLUS, KeyEvent.KEYCODE_W -> { - audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, - AudioManager.ADJUST_RAISE, AudioManager.FLAG_SHOW_UI) + audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_RAISE, AudioManager.FLAG_SHOW_UI) return true } KeyEvent.KEYCODE_MINUS, KeyEvent.KEYCODE_S -> { - audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, - AudioManager.ADJUST_LOWER, AudioManager.FLAG_SHOW_UI) + audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_LOWER, AudioManager.FLAG_SHOW_UI) return true } KeyEvent.KEYCODE_M -> { - audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, - AudioManager.ADJUST_TOGGLE_MUTE, AudioManager.FLAG_SHOW_UI) + audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_TOGGLE_MUTE, AudioManager.FLAG_SHOW_UI) return true } } @@ -394,25 +380,16 @@ class VideoplayerActivity : CastEnabledActivity() { private fun getWebsiteLinkWithFallback(media: Playable?): String? { return when { - media == null -> { - null - } - !media.getWebsiteLink().isNullOrBlank() -> { - media.getWebsiteLink() - } - media is FeedMedia -> { - getLinkWithFallback(media.item) - } + media == null -> null + !media.getWebsiteLink().isNullOrBlank() -> media.getWebsiteLink() + media is FeedMedia -> getLinkWithFallback(media.item) else -> null } } fun getFeedItem(playable: Playable?): FeedItem? { - return if (playable is FeedMedia) { - playable.item - } else { - null - } + return if (playable is FeedMedia) playable.item + else null } } } diff --git a/app/src/main/java/ac/mdiq/podcini/ui/activity/WidgetConfigActivity.kt b/app/src/main/java/ac/mdiq/podcini/ui/activity/WidgetConfigActivity.kt index 415e1924..fd5d2f87 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/activity/WidgetConfigActivity.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/activity/WidgetConfigActivity.kt @@ -43,17 +43,12 @@ class WidgetConfigActivity : AppCompatActivity() { val configIntent = intent val extras = configIntent.extras - if (extras != null) { - appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, - AppWidgetManager.INVALID_APPWIDGET_ID) - } + if (extras != null) appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID) val resultValue = Intent() resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId) setResult(RESULT_CANCELED, resultValue) - if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) { - finish() - } + if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) finish() opacityTextView = binding.widgetOpacityTextView opacitySeekBar = binding.widgetOpacitySeekBar @@ -68,11 +63,9 @@ class WidgetConfigActivity : AppCompatActivity() { widgetPreview.setBackgroundColor(color) } - override fun onStartTrackingTouch(seekBar: SeekBar) { - } + override fun onStartTrackingTouch(seekBar: SeekBar) {} - override fun onStopTrackingTouch(seekBar: SeekBar) { - } + override fun onStopTrackingTouch(seekBar: SeekBar) {} }) wpBinding.txtNoPlaying.visibility = View.GONE diff --git a/app/src/main/java/ac/mdiq/podcini/ui/activity/appstartintent/MainActivityStarter.kt b/app/src/main/java/ac/mdiq/podcini/ui/activity/appstartintent/MainActivityStarter.kt index 96e145de..738e2653 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/activity/appstartintent/MainActivityStarter.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/activity/appstartintent/MainActivityStarter.kt @@ -21,9 +21,7 @@ class MainActivityStarter(private val context: Context) { } fun getIntent(): Intent { - if (fragmentArgs != null) { - intent.putExtra(EXTRA_FRAGMENT_ARGS, fragmentArgs) - } + if (fragmentArgs != null) intent.putExtra(EXTRA_FRAGMENT_ARGS, fragmentArgs) return intent } diff --git a/app/src/main/java/ac/mdiq/podcini/ui/adapter/ChaptersListAdapter.kt b/app/src/main/java/ac/mdiq/podcini/ui/adapter/ChaptersListAdapter.kt index 80539183..d21fa845 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/adapter/ChaptersListAdapter.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/adapter/ChaptersListAdapter.kt @@ -37,9 +37,7 @@ class ChaptersListAdapter(private val context: Context, private val callback: Ca this.media = media hasImages = false for (chapter in media.getChapters()) { - if (!chapter.imageUrl.isNullOrEmpty()) { - hasImages = true - } + if (!chapter.imageUrl.isNullOrEmpty()) hasImages = true } notifyDataSetChanged() } @@ -48,11 +46,9 @@ class ChaptersListAdapter(private val context: Context, private val callback: Ca val sc = getItem(position)?: return holder.title.text = sc.title holder.start.text = getDurationStringLong(sc.start.toInt()) - val duration = if (position + 1 < itemCount) { - media!!.getChapters()[position + 1].start - sc.start - } else { - (media?.getDuration()?:0) - sc.start - } + val duration = if (position + 1 < itemCount) media!!.getChapters()[position + 1].start - sc.start + else (media?.getDuration()?:0) - sc.start + holder.duration.text = context.getString(R.string.chapter_duration, getDurationStringLocalized(context, duration.toInt().toLong())) @@ -99,9 +95,7 @@ class ChaptersListAdapter(private val context: Context, private val callback: Ca .into(holder.image) } } - } else { - holder.image.visibility = View.GONE - } + } else holder.image.visibility = View.GONE } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ChapterHolder { diff --git a/app/src/main/java/ac/mdiq/podcini/ui/adapter/CoverLoader.kt b/app/src/main/java/ac/mdiq/podcini/ui/adapter/CoverLoader.kt index 1a3516f6..661a3640 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/adapter/CoverLoader.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/adapter/CoverLoader.kt @@ -87,10 +87,8 @@ class CoverLoader(activity: MainActivity) { builder.into(coverTarget) } - internal class CoverTarget(fallbackTitle: TextView?, - coverImage: ImageView, - private val textAndImageCombined: Boolean - ) : CustomViewTarget(coverImage) { + internal class CoverTarget(fallbackTitle: TextView?, coverImage: ImageView, private val textAndImageCombined: Boolean) + : CustomViewTarget(coverImage) { private val fallbackTitle: WeakReference = WeakReference(fallbackTitle) private val cover: WeakReference = WeakReference(coverImage) @@ -99,9 +97,7 @@ class CoverLoader(activity: MainActivity) { setTitleVisibility(fallbackTitle.get(), true) } - override fun onResourceReady(resource: Drawable, - transition: Transition? - ) { + override fun onResourceReady(resource: Drawable, transition: Transition?) { val ivCover = cover.get() ivCover!!.setImageDrawable(resource) setTitleVisibility(fallbackTitle.get(), textAndImageCombined) diff --git a/app/src/main/java/ac/mdiq/podcini/ui/adapter/DataFolderAdapter.kt b/app/src/main/java/ac/mdiq/podcini/ui/adapter/DataFolderAdapter.kt index 3c2449cf..b3ab621e 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/adapter/DataFolderAdapter.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/adapter/DataFolderAdapter.kt @@ -47,15 +47,12 @@ class DataFolderAdapter(context: Context, selectionHandler: Consumer) : holder.size.text = String.format(freeSpaceString, freeSpace, totalSpace) holder.progressBar.progress = storagePath.usagePercentage val selectListener = View.OnClickListener { _: View? -> - selectionHandler.accept( - storagePath.fullPath) + selectionHandler.accept(storagePath.fullPath) } holder.root.setOnClickListener(selectListener) holder.radioButton.setOnClickListener(selectListener) - if (storagePath.fullPath == currentPath) { - holder.radioButton.toggle() - } + if (storagePath.fullPath == currentPath) holder.radioButton.toggle() } override fun getItemCount(): Int { @@ -71,14 +68,10 @@ class DataFolderAdapter(context: Context, selectionHandler: Consumer) : val mediaDirs = context.getExternalFilesDirs(null) val entries: MutableList = ArrayList(mediaDirs.size) for (dir in mediaDirs) { - if (!isWritable(dir)) { - continue - } + if (!isWritable(dir)) continue entries.add(StoragePath(dir.absolutePath)) } - if (entries.isEmpty() && isWritable(context.filesDir)) { - entries.add(StoragePath(context.filesDir.absolutePath)) - } + if (entries.isEmpty() && isWritable(context.filesDir)) entries.add(StoragePath(context.filesDir.absolutePath)) return entries } diff --git a/app/src/main/java/ac/mdiq/podcini/ui/adapter/DownloadLogAdapter.kt b/app/src/main/java/ac/mdiq/podcini/ui/adapter/DownloadLogAdapter.kt index 1d9099d5..95e1a5d4 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/adapter/DownloadLogAdapter.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/adapter/DownloadLogAdapter.kt @@ -37,9 +37,8 @@ class DownloadLogAdapter(private val context: Activity) : BaseAdapter() { if (convertView == null) { holder = DownloadLogItemViewHolder(context, parent) holder.itemView.tag = holder - } else { - holder = convertView.tag as DownloadLogItemViewHolder - } + } else holder = convertView.tag as DownloadLogItemViewHolder + val item = getItem(position) if (item != null) bind(holder, item, position) return holder.itemView @@ -48,23 +47,15 @@ class DownloadLogAdapter(private val context: Activity) : BaseAdapter() { @UnstableApi private fun bind(holder: DownloadLogItemViewHolder, status: DownloadResult, position: Int) { var statusText: String? = "" when (status.feedfileType) { - Feed.FEEDFILETYPE_FEED -> { - statusText += context.getString(R.string.download_type_feed) - } - FeedMedia.FEEDFILETYPE_FEEDMEDIA -> { - statusText += context.getString(R.string.download_type_media) - } + Feed.FEEDFILETYPE_FEED -> statusText += context.getString(R.string.download_type_feed) + FeedMedia.FEEDFILETYPE_FEEDMEDIA -> statusText += context.getString(R.string.download_type_media) } statusText += " · " - statusText += DateUtils.getRelativeTimeSpanString(status.getCompletionDate().time, - System.currentTimeMillis(), DateUtils.MINUTE_IN_MILLIS, 0) + statusText += DateUtils.getRelativeTimeSpanString(status.getCompletionDate().time, System.currentTimeMillis(), DateUtils.MINUTE_IN_MILLIS, 0) holder.status.text = statusText - if (status.title.isNotEmpty()) { - holder.title.text = status.title - } else { - holder.title.setText(R.string.download_log_title_unknown) - } + if (status.title.isNotEmpty()) holder.title.text = status.title + else holder.title.setText(R.string.download_log_title_unknown) if (status.isSuccessful) { holder.icon.setTextColor(ThemeUtils.getColorFromAttr(context, R.attr.icon_green)) @@ -115,8 +106,7 @@ class DownloadLogAdapter(private val context: Activity) : BaseAdapter() { return@OnClickListener } if (media.item != null) DownloadActionButton(media.item!!).onClick(context) - (context as MainActivity).showSnackbarAbovePlayer( - R.string.status_downloading_label, Toast.LENGTH_SHORT) + (context as MainActivity).showSnackbarAbovePlayer(R.string.status_downloading_label, Toast.LENGTH_SHORT) }) } } @@ -127,9 +117,7 @@ class DownloadLogAdapter(private val context: Activity) : BaseAdapter() { private fun newerWasSuccessful(downloadStatusIndex: Int, feedTypeId: Int, id: Long): Boolean { for (i in 0 until downloadStatusIndex) { val status: DownloadResult = downloadLog[i] - if (status.feedfileType == feedTypeId && status.feedfileId == id && status.isSuccessful) { - return true - } + if (status.feedfileType == feedTypeId && status.feedfileId == id && status.isSuccessful) return true } return false } @@ -139,9 +127,7 @@ class DownloadLogAdapter(private val context: Activity) : BaseAdapter() { } override fun getItem(position: Int): DownloadResult? { - if (position in downloadLog.indices) { - return downloadLog[position] - } + if (position in downloadLog.indices) return downloadLog[position] return null } diff --git a/app/src/main/java/ac/mdiq/podcini/ui/adapter/EpisodeItemListAdapter.kt b/app/src/main/java/ac/mdiq/podcini/ui/adapter/EpisodeItemListAdapter.kt index 00995099..1e02458e 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/adapter/EpisodeItemListAdapter.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/adapter/EpisodeItemListAdapter.kt @@ -111,22 +111,17 @@ open class EpisodeItemListAdapter(mainActivity: MainActivity) : if (inActionMode()) { holder.secondaryActionButton.setOnClickListener(null) if (isSelected(pos)) { - holder.itemView.setBackgroundColor(-0x78000000 - + (0xffffff and ThemeUtils.getColorFromAttr(mainActivityRef.get()!!, R.attr.colorAccent))) - } else { - holder.itemView.setBackgroundResource(color.transparent) - } + holder.itemView.setBackgroundColor(-0x78000000 + (0xffffff and ThemeUtils.getColorFromAttr(mainActivityRef.get()!!, R.attr.colorAccent))) + } else holder.itemView.setBackgroundResource(color.transparent) } afterBindViewHolder(holder, pos) holder.hideSeparatorIfNecessary() } - protected open fun beforeBindViewHolder(holder: EpisodeItemViewHolder, pos: Int) { - } + protected open fun beforeBindViewHolder(holder: EpisodeItemViewHolder, pos: Int) {} - protected open fun afterBindViewHolder(holder: EpisodeItemViewHolder, pos: Int) { - } + protected open fun afterBindViewHolder(holder: EpisodeItemViewHolder, pos: Int) {} @UnstableApi override fun onViewRecycled(holder: EpisodeItemViewHolder) { super.onViewRecycled(holder) diff --git a/app/src/main/java/ac/mdiq/podcini/ui/adapter/FeedDiscoverAdapter.kt b/app/src/main/java/ac/mdiq/podcini/ui/adapter/FeedDiscoverAdapter.kt index 756cde52..465c9055 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/adapter/FeedDiscoverAdapter.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/adapter/FeedDiscoverAdapter.kt @@ -46,9 +46,7 @@ class FeedDiscoverAdapter(mainActivity: MainActivity) : BaseAdapter() { holder = Holder() holder.imageView = binding.discoveryCover convertView.tag = holder - } else { - holder = convertView.tag as Holder - } + } else holder = convertView.tag as Holder val podcast: PodcastSearchResult? = getItem(position) holder.imageView!!.contentDescription = podcast?.title diff --git a/app/src/main/java/ac/mdiq/podcini/ui/adapter/HorizontalFeedListAdapter.kt b/app/src/main/java/ac/mdiq/podcini/ui/adapter/HorizontalFeedListAdapter.kt index 94dae11f..f3b942b0 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/adapter/HorizontalFeedListAdapter.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/adapter/HorizontalFeedListAdapter.kt @@ -87,9 +87,7 @@ open class HorizontalFeedListAdapter(mainActivity: MainActivity) : } override fun getItemId(position: Int): Long { - if (position >= data.size) { - return RecyclerView.NO_ID // Dummy views - } + if (position >= data.size) return RecyclerView.NO_ID // Dummy views return data[position].id } @@ -99,9 +97,7 @@ open class HorizontalFeedListAdapter(mainActivity: MainActivity) : override fun onCreateContextMenu(contextMenu: ContextMenu, view: View, contextMenuInfo: ContextMenu.ContextMenuInfo?) { val inflater: MenuInflater = mainActivityRef.get()!!.menuInflater - if (longPressedItem == null) { - return - } + if (longPressedItem == null) return inflater.inflate(R.menu.nav_feed_context, contextMenu) contextMenu.setHeaderTitle(longPressedItem!!.title) } diff --git a/app/src/main/java/ac/mdiq/podcini/ui/adapter/NavListAdapter.kt b/app/src/main/java/ac/mdiq/podcini/ui/adapter/NavListAdapter.kt index 0dd612b6..d69979c8 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/adapter/NavListAdapter.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/adapter/NavListAdapter.kt @@ -62,9 +62,7 @@ class NavListAdapter(private val itemAccess: ItemAccess, context: Activity) : } override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String?) { - if (UserPreferences.PREF_HIDDEN_DRAWER_ITEMS == key) { - loadItems() - } + if (UserPreferences.PREF_HIDDEN_DRAWER_ITEMS == key) loadItems() } @OptIn(UnstableApi::class) private fun loadItems() { @@ -79,9 +77,7 @@ class NavListAdapter(private val itemAccess: ItemAccess, context: Activity) : // nav drawer at all. showSubscriptionList = true newTags.remove(SUBSCRIPTION_LIST_TAG) - } else { - showSubscriptionList = false - } + } else showSubscriptionList = false fragmentTags.clear() fragmentTags.addAll(newTags) @@ -113,38 +109,24 @@ class NavListAdapter(private val itemAccess: ItemAccess, context: Activity) : override fun getItemCount(): Int { var baseCount = subscriptionOffset - if (showSubscriptionList) { - baseCount += itemAccess.count - } + if (showSubscriptionList) baseCount += itemAccess.count return baseCount } override fun getItemId(position: Int): Long { val viewType = getItemViewType(position) return when (viewType) { - VIEW_TYPE_SUBSCRIPTION -> { - itemAccess.getItem(position - subscriptionOffset)?.id?:0 - } - VIEW_TYPE_NAV -> { - (-abs(fragmentTags[position].hashCode().toLong().toDouble()) - 1).toLong() // Folder IDs are >0 - } - else -> { - 0 - } + VIEW_TYPE_SUBSCRIPTION -> itemAccess.getItem(position - subscriptionOffset)?.id?:0 + VIEW_TYPE_NAV -> (-abs(fragmentTags[position].hashCode().toLong().toDouble()) - 1).toLong() // Folder IDs are >0 + else -> 0 } } override fun getItemViewType(position: Int): Int { return when { - 0 <= position && position < fragmentTags.size -> { - VIEW_TYPE_NAV - } - position < subscriptionOffset -> { - VIEW_TYPE_SECTION_DIVIDER - } - else -> { - VIEW_TYPE_SUBSCRIPTION - } + 0 <= position && position < fragmentTags.size -> VIEW_TYPE_NAV + position < subscriptionOffset -> VIEW_TYPE_SECTION_DIVIDER + else -> VIEW_TYPE_SUBSCRIPTION } } @@ -154,15 +136,9 @@ class NavListAdapter(private val itemAccess: ItemAccess, context: Activity) : override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder { val inflater = LayoutInflater.from(activity.get()) return when (viewType) { - VIEW_TYPE_NAV -> { - NavHolder(inflater.inflate(R.layout.nav_listitem, parent, false)) - } - VIEW_TYPE_SECTION_DIVIDER -> { - DividerHolder(inflater.inflate(R.layout.nav_section_item, parent, false)) - } - else -> { - FeedHolder(inflater.inflate(R.layout.nav_listitem, parent, false)) - } + VIEW_TYPE_NAV -> NavHolder(inflater.inflate(R.layout.nav_listitem, parent, false)) + VIEW_TYPE_SECTION_DIVIDER -> DividerHolder(inflater.inflate(R.layout.nav_section_item, parent, false)) + else -> FeedHolder(inflater.inflate(R.layout.nav_listitem, parent, false)) } } @@ -171,12 +147,8 @@ class NavListAdapter(private val itemAccess: ItemAccess, context: Activity) : holder.itemView.setOnCreateContextMenuListener(null) when (viewType) { - VIEW_TYPE_NAV -> { - bindNavView(getLabel(fragmentTags[position]), position, holder as NavHolder) - } - VIEW_TYPE_SECTION_DIVIDER -> { - bindSectionDivider(holder as DividerHolder) - } + VIEW_TYPE_NAV -> bindNavView(getLabel(fragmentTags[position]), position, holder as NavHolder) + VIEW_TYPE_SECTION_DIVIDER -> bindSectionDivider(holder as DividerHolder) else -> { val itemPos = position - subscriptionOffset val item = itemAccess.getItem(itemPos) @@ -192,8 +164,7 @@ class NavListAdapter(private val itemAccess: ItemAccess, context: Activity) : holder.itemView.setOnClickListener { itemAccess.onItemClick(position) } holder.itemView.setOnLongClickListener { itemAccess.onItemLongClick(position) } holder.itemView.setOnTouchListener { _: View?, e: MotionEvent -> - if (e.isFromSource(InputDevice.SOURCE_MOUSE) - && e.buttonState == MotionEvent.BUTTON_SECONDARY) { + if (e.isFromSource(InputDevice.SOURCE_MOUSE) && e.buttonState == MotionEvent.BUTTON_SECONDARY) { itemAccess.onItemLongClick(position) return@setOnTouchListener false } @@ -237,8 +208,7 @@ class NavListAdapter(private val itemAccess: ItemAccess, context: Activity) : tag == DownloadsFragment.TAG && isEnableAutodownload -> { val epCacheSize = episodeCacheSize // don't count episodes that can be reclaimed - val spaceUsed = (itemAccess.numberOfDownloadedItems - - itemAccess.reclaimableItems) + val spaceUsed = (itemAccess.numberOfDownloadedItems - itemAccess.reclaimableItems) if (epCacheSize in 1..spaceUsed) { holder.count.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, R.drawable.ic_disc_alert, 0) holder.count.visibility = View.VISIBLE @@ -277,9 +247,8 @@ class NavListAdapter(private val itemAccess: ItemAccess, context: Activity) : if (item.counter > 0) { holder.count.visibility = View.VISIBLE holder.count.text = NumberFormat.getInstance().format(item.counter.toLong()) - } else { - holder.count.visibility = View.GONE - } + } else holder.count.visibility = View.GONE + holder.title.text = item.title val padding = (activity.get()!!.resources.getDimension(R.dimen.thumbnail_length_navlist) / 2).toInt() holder.itemView.setPadding(item.layer * padding, 0, 0, 0) diff --git a/app/src/main/java/ac/mdiq/podcini/ui/adapter/OnlineFeedsAdapter.kt b/app/src/main/java/ac/mdiq/podcini/ui/adapter/OnlineFeedsAdapter.kt index 68ddd603..32e5a969 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/adapter/OnlineFeedsAdapter.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/adapter/OnlineFeedsAdapter.kt @@ -49,15 +49,14 @@ class OnlineFeedsAdapter(private val context: Context, objects: List { - viewHolder.authorView.visibility = View.INVISIBLE - } + else -> viewHolder.authorView.visibility = View.INVISIBLE } viewHolder.source.text = podcast.source + ": " + podcast.feedUrl if (podcast.count != null) { viewHolder.countView.text = podcast.count.toString() + " episodes" viewHolder.countView.visibility = View.VISIBLE } else viewHolder.countView.visibility = View.INVISIBLE + if (podcast.update != null) { viewHolder.updateView.text = podcast.update viewHolder.updateView.visibility = View.VISIBLE diff --git a/app/src/main/java/ac/mdiq/podcini/ui/adapter/QueueRecyclerAdapter.kt b/app/src/main/java/ac/mdiq/podcini/ui/adapter/QueueRecyclerAdapter.kt index aa89eb58..c42bd814 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/adapter/QueueRecyclerAdapter.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/adapter/QueueRecyclerAdapter.kt @@ -37,20 +37,15 @@ open class QueueRecyclerAdapter(mainActivity: MainActivity, private val swipeAct } else { holder.dragHandle.setVisibility(View.VISIBLE) holder.dragHandle.setOnTouchListener { _: View?, event: MotionEvent -> - if (event.actionMasked == MotionEvent.ACTION_DOWN) { - swipeActions.startDrag(holder) - } + if (event.actionMasked == MotionEvent.ACTION_DOWN) swipeActions.startDrag(holder) false } holder.coverHolder.setOnTouchListener { v1, event -> if (!inActionMode() && event.actionMasked == MotionEvent.ACTION_DOWN) { val isLtr = holder.itemView.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR val factor = (if (isLtr) 1 else -1).toFloat() - if (factor * event.x < factor * 0.5 * v1.width) { - swipeActions.startDrag(holder) - } else { - Log.d(TAG, "Ignoring drag in right half of the image") - } + if (factor * event.x < factor * 0.5 * v1.width) swipeActions.startDrag(holder) + else Log.d(TAG, "Ignoring drag in right half of the image") } false } @@ -71,12 +66,8 @@ open class QueueRecyclerAdapter(mainActivity: MainActivity, private val swipeAct if (!inActionMode()) { // menu.findItem(R.id.multi_select).setVisible(true) val keepSorted: Boolean = UserPreferences.isQueueKeepSorted - if (getItem(0)?.id === longPressedItem?.id || keepSorted) { - menu.findItem(R.id.move_to_top_item).setVisible(false) - } - if (getItem(itemCount - 1)?.id === longPressedItem?.id || keepSorted) { - menu.findItem(R.id.move_to_bottom_item).setVisible(false) - } + if (getItem(0)?.id === longPressedItem?.id || keepSorted) menu.findItem(R.id.move_to_top_item).setVisible(false) + if (getItem(itemCount - 1)?.id === longPressedItem?.id || keepSorted) menu.findItem(R.id.move_to_bottom_item).setVisible(false) } else { menu.findItem(R.id.move_to_top_item).setVisible(false) menu.findItem(R.id.move_to_bottom_item).setVisible(false) diff --git a/app/src/main/java/ac/mdiq/podcini/ui/adapter/SelectableAdapter.kt b/app/src/main/java/ac/mdiq/podcini/ui/adapter/SelectableAdapter.kt index c36d012b..51d15a7a 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/adapter/SelectableAdapter.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/adapter/SelectableAdapter.kt @@ -20,9 +20,8 @@ abstract class SelectableAdapter(private val activ private var totalNumberOfItems = COUNT_AUTOMATICALLY fun startSelectMode(pos: Int) { - if (inActionMode()) { - endSelectMode() - } + if (inActionMode()) endSelectMode() + onSelectModeListener?.onStartSelectMode() shouldSelectLazyLoadedItems = false @@ -99,11 +98,9 @@ abstract class SelectableAdapter(private val activ * @param selected true for selected state and false for unselected */ open fun setSelected(pos: Int, selected: Boolean) { - if (selected) { - selectedIds.add(getItemId(pos)) - } else { - selectedIds.remove(getItemId(pos)) - } + if (selected) selectedIds.add(getItemId(pos)) + else selectedIds.remove(getItemId(pos)) + updateTitle() } @@ -138,9 +135,7 @@ abstract class SelectableAdapter(private val activ setSelected(pos, !isSelected(pos)) notifyItemChanged(pos) - if (selectedIds.size == 0) { - endSelectMode() - } + if (selectedIds.size == 0) endSelectMode() } fun inActionMode(): Boolean { @@ -161,16 +156,12 @@ abstract class SelectableAdapter(private val activ } fun updateTitle() { - if (actionMode == null) { - return - } + if (actionMode == null) return var totalCount = itemCount var selectedCount = selectedIds.size if (totalNumberOfItems != COUNT_AUTOMATICALLY) { totalCount = totalNumberOfItems - if (shouldSelectLazyLoadedItems) { - selectedCount += (totalNumberOfItems - itemCount) - } + if (shouldSelectLazyLoadedItems) selectedCount += (totalNumberOfItems - itemCount) } actionMode!!.title = activity.resources .getQuantityString(R.plurals.num_selected_label, selectedIds.size, diff --git a/app/src/main/java/ac/mdiq/podcini/ui/adapter/SimpleIconListAdapter.kt b/app/src/main/java/ac/mdiq/podcini/ui/adapter/SimpleIconListAdapter.kt index 942ea773..b63bedc2 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/adapter/SimpleIconListAdapter.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/adapter/SimpleIconListAdapter.kt @@ -13,15 +13,12 @@ import com.bumptech.glide.request.RequestOptions /** * Displays a list of items that have a subtitle and an icon. */ -class SimpleIconListAdapter(private val context: Context, - private val listItems: List -) : ArrayAdapter(context, R.layout.simple_icon_list_item, listItems) { +class SimpleIconListAdapter(private val context: Context, private val listItems: List) + : ArrayAdapter(context, R.layout.simple_icon_list_item, listItems) { override fun getView(position: Int, view: View?, parent: ViewGroup): View { var view = view - if (view == null) { - view = View.inflate(context, R.layout.simple_icon_list_item, null) - } + if (view == null) view = View.inflate(context, R.layout.simple_icon_list_item, null) val item: ListItem = listItems[position] val binding = SimpleIconListItemBinding.bind(view!!) diff --git a/app/src/main/java/ac/mdiq/podcini/ui/adapter/SubscriptionsAdapter.kt b/app/src/main/java/ac/mdiq/podcini/ui/adapter/SubscriptionsAdapter.kt index 7b245117..58114693 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/adapter/SubscriptionsAdapter.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/adapter/SubscriptionsAdapter.kt @@ -110,9 +110,7 @@ open class SubscriptionsAdapter(mainActivity: MainActivity) : } override fun getItemId(position: Int): Long { - if (position >= listItems.size) { - return RecyclerView.NO_ID // Dummy views - } + if (position >= listItems.size) return RecyclerView.NO_ID // Dummy views return listItems[position].id } @@ -182,9 +180,7 @@ open class SubscriptionsAdapter(mainActivity: MainActivity) : count.text = NumberFormat.getInstance().format(drawerItem.counter.toLong()) + " episodes" // count.text = NumberFormat.getInstance().format(drawerItem.feed.items.size.toLong()) + " episodes" count.visibility = View.VISIBLE - } else { - count.visibility = View.VISIBLE - } + } else count.visibility = View.VISIBLE val mainActRef = mainActivityRef.get() ?: return @@ -212,11 +208,7 @@ open class SubscriptionsAdapter(mainActivity: MainActivity) : class GridDividerItemDecorator : RecyclerView.ItemDecoration() { - override fun getItemOffsets(outRect: Rect, - view: View, - parent: RecyclerView, - state: RecyclerView.State - ) { + override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) { super.getItemOffsets(outRect, view, parent, state) val context = parent.context val insetOffset = convertDpToPixel(context, 1f).toInt() diff --git a/app/src/main/java/ac/mdiq/podcini/ui/dialog/AuthenticationDialog.kt b/app/src/main/java/ac/mdiq/podcini/ui/dialog/AuthenticationDialog.kt index 991b1df3..9a5b0972 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/dialog/AuthenticationDialog.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/dialog/AuthenticationDialog.kt @@ -12,9 +12,8 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder /** * Displays a dialog with a username and password text field and an optional checkbox to save username and preferences. */ -abstract class AuthenticationDialog(context: Context, titleRes: Int, enableUsernameField: Boolean, - usernameInitialValue: String?, passwordInitialValue: String? -) : MaterialAlertDialogBuilder(context) { +abstract class AuthenticationDialog(context: Context, titleRes: Int, enableUsernameField: Boolean, usernameInitialValue: String?, passwordInitialValue: String?) + : MaterialAlertDialogBuilder(context) { var passwordHidden: Boolean = true @@ -24,12 +23,9 @@ abstract class AuthenticationDialog(context: Context, titleRes: Int, enableUsern setView(viewBinding.root) viewBinding.usernameEditText.isEnabled = enableUsernameField - if (usernameInitialValue != null) { - viewBinding.usernameEditText.setText(usernameInitialValue) - } - if (passwordInitialValue != null) { - viewBinding.passwordEditText.setText(passwordInitialValue) - } + if (usernameInitialValue != null) viewBinding.usernameEditText.setText(usernameInitialValue) + if (passwordInitialValue != null) viewBinding.passwordEditText.setText(passwordInitialValue) + viewBinding.showPasswordButton.setOnClickListener { if (passwordHidden) { viewBinding.passwordEditText.transformationMethod = HideReturnsTransformationMethod.getInstance() @@ -44,13 +40,11 @@ abstract class AuthenticationDialog(context: Context, titleRes: Int, enableUsern setOnCancelListener { onCancelled() } setNegativeButton(R.string.cancel_label) { _: DialogInterface?, _: Int -> onCancelled() } setPositiveButton(R.string.confirm_label) { _: DialogInterface?, _: Int -> - onConfirmed(viewBinding.usernameEditText.text.toString(), - viewBinding.passwordEditText.text.toString()) + onConfirmed(viewBinding.usernameEditText.text.toString(), viewBinding.passwordEditText.text.toString()) } } - protected open fun onCancelled() { - } + protected open fun onCancelled() {} protected abstract fun onConfirmed(username: String, password: String) } diff --git a/app/src/main/java/ac/mdiq/podcini/ui/dialog/ConfirmationDialog.kt b/app/src/main/java/ac/mdiq/podcini/ui/dialog/ConfirmationDialog.kt index c44c0bec..eeb42561 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/dialog/ConfirmationDialog.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/dialog/ConfirmationDialog.kt @@ -31,8 +31,8 @@ abstract class ConfirmationDialog(private val context: Context, private val titl val builder = MaterialAlertDialogBuilder(context) builder.setTitle(titleId) builder.setMessage(message) - builder.setPositiveButton(if (positiveText != 0) positiveText else R.string.confirm_label - ) { dialog: DialogInterface, _: Int -> onConfirmButtonPressed(dialog) } + builder.setPositiveButton(if (positiveText != 0) positiveText else R.string.confirm_label) { + dialog: DialogInterface, _: Int -> onConfirmButtonPressed(dialog) } builder.setNegativeButton(R.string.cancel_label) { dialog: DialogInterface, _: Int -> onCancelButtonPressed(dialog) } diff --git a/app/src/main/java/ac/mdiq/podcini/ui/dialog/DownloadLogDetailsDialog.kt b/app/src/main/java/ac/mdiq/podcini/ui/dialog/DownloadLogDetailsDialog.kt index 22b6956e..fc329004 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/dialog/DownloadLogDetailsDialog.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/dialog/DownloadLogDetailsDialog.kt @@ -23,22 +23,16 @@ class DownloadLogDetailsDialog(context: Context, status: DownloadResult) : Mater when (status.feedfileType) { FeedMedia.FEEDFILETYPE_FEEDMEDIA -> { val media = DBReader.getFeedMedia(status.feedfileId) - if (media != null) { - url = media.download_url?:"" - } + if (media != null) url = media.download_url?:"" } Feed.FEEDFILETYPE_FEED -> { val feed = DBReader.getFeed(status.feedfileId) - if (feed != null) { - url = feed.download_url?:"" - } + if (feed != null) url = feed.download_url?:"" } } var message = context.getString(R.string.download_successful) - if (!status.isSuccessful) { - message = status.reasonDetailed - } + if (!status.isSuccessful) message = status.reasonDetailed val messageFull = context.getString(R.string.download_log_details_message, context.getString(from(status.reason)), message, url) @@ -49,9 +43,7 @@ class DownloadLogDetailsDialog(context: Context, status: DownloadResult) : Mater val clipboard = getContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager val clip = ClipData.newPlainText(context.getString(R.string.download_error_details), messageFull) clipboard.setPrimaryClip(clip) - if (Build.VERSION.SDK_INT < 32) { - EventBus.getDefault().post(MessageEvent(context.getString(R.string.copied_to_clipboard))) - } + if (Build.VERSION.SDK_INT < 32) EventBus.getDefault().post(MessageEvent(context.getString(R.string.copied_to_clipboard))) } } diff --git a/app/src/main/java/ac/mdiq/podcini/ui/dialog/DrawerPreferencesDialog.kt b/app/src/main/java/ac/mdiq/podcini/ui/dialog/DrawerPreferencesDialog.kt index 88900d88..858b9f35 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/dialog/DrawerPreferencesDialog.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/dialog/DrawerPreferencesDialog.kt @@ -19,18 +19,13 @@ object DrawerPreferencesDialog { val checked = BooleanArray(NavDrawerFragment.NAV_DRAWER_TAGS.size) for (i in NavDrawerFragment.NAV_DRAWER_TAGS.indices) { val tag = NavDrawerFragment.NAV_DRAWER_TAGS[i] - if (!hiddenDrawerItems.contains(tag)) { - checked[i] = true - } + if (!hiddenDrawerItems.contains(tag)) checked[i] = true } val builder = MaterialAlertDialogBuilder(context) builder.setTitle(R.string.drawer_preferences) builder.setMultiChoiceItems(navTitles, checked) { _: DialogInterface?, which: Int, isChecked: Boolean -> - if (isChecked) { - hiddenDrawerItems.remove(NavDrawerFragment.NAV_DRAWER_TAGS[which]) - } else { - hiddenDrawerItems.add(NavDrawerFragment.NAV_DRAWER_TAGS[which]) - } + if (isChecked) hiddenDrawerItems.remove(NavDrawerFragment.NAV_DRAWER_TAGS[which]) + else hiddenDrawerItems.add(NavDrawerFragment.NAV_DRAWER_TAGS[which]) } builder.setPositiveButton(R.string.confirm_label) { _: DialogInterface?, _: Int -> UserPreferences.hiddenDrawerItems = hiddenDrawerItems diff --git a/app/src/main/java/ac/mdiq/podcini/ui/dialog/EpisodeFilterDialog.kt b/app/src/main/java/ac/mdiq/podcini/ui/dialog/EpisodeFilterDialog.kt index 7c345250..70e51c41 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/dialog/EpisodeFilterDialog.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/dialog/EpisodeFilterDialog.kt @@ -33,9 +33,7 @@ abstract class EpisodeFilterDialog(context: Context, filter: FeedFilter) : // Store minimal duration in seconds, show in minutes viewBinding.episodeFilterDurationText .setText((filter.minimalDurationFilter / 60).toString()) - } else { - viewBinding.episodeFilterDurationText.isEnabled = false - } + } else viewBinding.episodeFilterDurationText.isEnabled = false if (filter.excludeOnly()) { termList = filter.getExcludeFilter().toMutableList() @@ -48,8 +46,7 @@ abstract class EpisodeFilterDialog(context: Context, filter: FeedFilter) : setNegativeButton(R.string.cancel_label, null) setPositiveButton(R.string.confirm_label) { dialog: DialogInterface, which: Int -> - this.onConfirmClick(dialog, - which) + this.onConfirmClick(dialog, which) } } @@ -69,9 +66,8 @@ abstract class EpisodeFilterDialog(context: Context, filter: FeedFilter) : viewBinding.termsRecycler.adapter = adapter viewBinding.termsTextInput.setEndIconOnClickListener { val newWord = viewBinding.termsTextInput.editText!!.text.toString().replace("\"", "").trim { it <= ' ' } - if (newWord.isEmpty() || termList.contains(newWord)) { - return@setEndIconOnClickListener - } + if (newWord.isEmpty() || termList.contains(newWord)) return@setEndIconOnClickListener + termList.add(newWord) viewBinding.termsTextInput.editText!!.setText("") adapter.notifyDataSetChanged() @@ -92,11 +88,9 @@ abstract class EpisodeFilterDialog(context: Context, filter: FeedFilter) : } var excludeFilter = "" var includeFilter = "" - if (viewBinding.includeRadio.isChecked) { - includeFilter = toFilterString(termList) - } else { - excludeFilter = toFilterString(termList) - } + if (viewBinding.includeRadio.isChecked) includeFilter = toFilterString(termList) + else excludeFilter = toFilterString(termList) + onConfirmed(FeedFilter(includeFilter, excludeFilter, minimalDuration)) } diff --git a/app/src/main/java/ac/mdiq/podcini/ui/dialog/ItemFilterDialog.kt b/app/src/main/java/ac/mdiq/podcini/ui/dialog/ItemFilterDialog.kt index 2ebd2243..8fb0dd8f 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/dialog/ItemFilterDialog.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/dialog/ItemFilterDialog.kt @@ -53,9 +53,7 @@ abstract class ItemFilterDialog : BottomSheetDialogFragment() { binding.resetFiltermenu.setOnClickListener { onFilterChanged(emptySet()) for (i in 0 until rows.childCount) { - if (rows.getChildAt(i) is MaterialButtonToggleGroup) { - (rows.getChildAt(i) as MaterialButtonToggleGroup).clearChecked() - } + if (rows.getChildAt(i) is MaterialButtonToggleGroup) (rows.getChildAt(i) as MaterialButtonToggleGroup).clearChecked() } } @@ -63,9 +61,7 @@ abstract class ItemFilterDialog : BottomSheetDialogFragment() { for (filterId in filter.values) { if (filterId.isNotEmpty()) { val button = layout.findViewWithTag