From 063af373628d90aa410f5cda6ef41dde2c6edc59 Mon Sep 17 00:00:00 2001 From: Xilin Jia <6257601+XilinJia@users.noreply.github.com> Date: Sun, 17 Mar 2024 11:53:15 +0000 Subject: [PATCH] add info bars and thematic icons --- app/build.gradle | 4 +- .../java/ac/test/podcini/ui/UITestUtils.kt | 2 +- .../util/event/FeedItemEventListener.kt | 6 +- .../PlaybackServiceNotificationBuilder.kt | 3 +- .../java/ac/mdiq/podcini/storage/DBTasks.kt | 5 +- .../storage/model/feed/SubscriptionsFilter.kt | 3 +- .../mdiq/podcini/ui/activity/MainActivity.kt | 4 +- .../ui/adapter/EpisodeItemListAdapter.kt | 16 ---- .../adapter/SubscriptionsRecyclerAdapter.kt | 18 ---- .../ui/dialog/SubscriptionsFilterDialog.kt | 3 +- .../podcini/ui/dialog/TagSettingsDialog.kt | 3 + .../podcini/ui/fragment/ChaptersFragment.kt | 1 - .../ui/fragment/CompletedDownloadsFragment.kt | 45 +++++++--- .../mdiq/podcini/ui/fragment/ItemFragment.kt | 8 +- .../podcini/ui/fragment/ItemPagerFragment.kt | 3 +- .../podcini/ui/fragment/NavDrawerFragment.kt | 3 +- .../mdiq/podcini/ui/fragment/QueueFragment.kt | 3 +- .../ui/fragment/SubscriptionFragment.kt | 86 ++++++++++++------- .../actions/FeedMultiSelectActionHandler.kt | 3 + .../mdiq/podcini/ui/view/ShownotesWebView.kt | 3 +- .../util/event/FeedTagsChangedEvent.kt | 3 + app/src/main/res/drawable/arrows_sort.xml | 4 +- .../drawable/baseline_arrow_downward_24.xml | 4 +- .../res/drawable/baseline_arrow_upward_24.xml | 4 +- .../res/layout/fragment_subscriptions.xml | 23 +++-- .../main/res/layout/simple_list_fragment.xml | 14 ++- app/src/main/res/menu/feeditem_options.xml | 5 -- .../main/res/menu/feeditemlist_context.xml | 5 -- changelog.md | 9 +- .../android/en-US/changelogs/3020109.txt | 7 ++ 30 files changed, 176 insertions(+), 124 deletions(-) create mode 100644 app/src/main/java/ac/mdiq/podcini/util/event/FeedTagsChangedEvent.kt create mode 100644 fastlane/metadata/android/en-US/changelogs/3020109.txt diff --git a/app/build.gradle b/app/build.gradle index 7a1ac1d5..4d55a4a7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -149,8 +149,8 @@ android { // Version code schema (not used): // "1.2.3-beta4" -> 1020304 // "1.2.3" -> 1020395 - versionCode 3020108 - versionName "4.2.5" + versionCode 3020109 + versionName "4.2.6" def commit = "" try { diff --git a/app/src/androidTest/java/ac/test/podcini/ui/UITestUtils.kt b/app/src/androidTest/java/ac/test/podcini/ui/UITestUtils.kt index 479a633f..143f67ec 100644 --- a/app/src/androidTest/java/ac/test/podcini/ui/UITestUtils.kt +++ b/app/src/androidTest/java/ac/test/podcini/ui/UITestUtils.kt @@ -193,7 +193,7 @@ class UITestUtils(private val context: Context) { adapter.setCompleteFeed(*hostedFeeds.toTypedArray()) adapter.setQueue(queue) adapter.close() - EventBus.getDefault().post(ac.mdiq.podcini.util.event.FeedListUpdateEvent(hostedFeeds)) + EventBus.getDefault().post(FeedListUpdateEvent(hostedFeeds)) EventBus.getDefault().post(setQueue(queue)) } diff --git a/app/src/androidTest/java/ac/test/podcini/util/event/FeedItemEventListener.kt b/app/src/androidTest/java/ac/test/podcini/util/event/FeedItemEventListener.kt index f5ea50e0..bd3a8b6e 100644 --- a/app/src/androidTest/java/ac/test/podcini/util/event/FeedItemEventListener.kt +++ b/app/src/androidTest/java/ac/test/podcini/util/event/FeedItemEventListener.kt @@ -10,14 +10,14 @@ import org.greenrobot.eventbus.Subscribe * */ class FeedItemEventListener { - private val events: MutableList = ArrayList() + private val events: MutableList = ArrayList() @Subscribe - fun onEvent(event: ac.mdiq.podcini.util.event.FeedItemEvent) { + fun onEvent(event: FeedItemEvent) { events.add(event) } - fun getEvents(): List { + fun getEvents(): List { return events } diff --git a/app/src/main/java/ac/mdiq/podcini/service/playback/PlaybackServiceNotificationBuilder.kt b/app/src/main/java/ac/mdiq/podcini/service/playback/PlaybackServiceNotificationBuilder.kt index 23242a4e..79c5de95 100644 --- a/app/src/main/java/ac/mdiq/podcini/service/playback/PlaybackServiceNotificationBuilder.kt +++ b/app/src/main/java/ac/mdiq/podcini/service/playback/PlaybackServiceNotificationBuilder.kt @@ -25,6 +25,7 @@ import ac.mdiq.podcini.ui.gui.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 import java.util.concurrent.ExecutionException @@ -52,7 +53,7 @@ class PlaybackServiceNotificationBuilder(private val context: Context) { fun updatePosition(position: Int, speed: Float) { val converter = TimeSpeedConverter(speed) - this.position = ac.mdiq.podcini.util.Converter.getDurationStringLong(converter.convert(position)) + this.position = Converter.getDurationStringLong(converter.convert(position)) } val isIconCached: Boolean 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 071cd313..e11f4a67 100644 --- a/app/src/main/java/ac/mdiq/podcini/storage/DBTasks.kt +++ b/app/src/main/java/ac/mdiq/podcini/storage/DBTasks.kt @@ -25,6 +25,7 @@ import ac.mdiq.podcini.storage.database.PodDBAdapter import ac.mdiq.podcini.storage.database.PodDBAdapter.Companion.getInstance import ac.mdiq.podcini.storage.database.mapper.FeedCursorMapper.convert import ac.mdiq.podcini.preferences.UserPreferences.newEpisodesAction +import ac.mdiq.podcini.util.event.FeedListUpdateEvent import org.greenrobot.eventbus.EventBus import java.util.* import java.util.concurrent.* @@ -352,9 +353,9 @@ import java.util.concurrent.* adapter.close() if (savedFeed != null) { - EventBus.getDefault().post(ac.mdiq.podcini.util.event.FeedListUpdateEvent(savedFeed)) + EventBus.getDefault().post(FeedListUpdateEvent(savedFeed)) } else { - EventBus.getDefault().post(ac.mdiq.podcini.util.event.FeedListUpdateEvent(emptyList())) + EventBus.getDefault().post(FeedListUpdateEvent(emptyList())) } return resultFeed 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 ee37a2cf..f2144b52 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 @@ -74,8 +74,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) { + if (!feedCounters.containsKey(result[i].id) || feedCounters[result[i].id]!! <= 0) { result.removeAt(i) } } 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 a3f7315e..6f8dba45 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 @@ -24,6 +24,7 @@ import ac.mdiq.podcini.ui.fragment.* import ac.mdiq.podcini.ui.statistics.StatisticsFragment import ac.mdiq.podcini.ui.view.LockableBottomSheetBehavior import ac.mdiq.podcini.util.event.EpisodeDownloadEvent +import ac.mdiq.podcini.util.event.FeedUpdateRunningEvent import android.Manifest import android.annotation.SuppressLint import android.content.Context @@ -73,7 +74,6 @@ import kotlin.math.min */ @UnstableApi class MainActivity : CastEnabledActivity() { -// some device doesn't have a drawer private var drawerLayout: DrawerLayout? = null private lateinit var binding: MainActivityBinding @@ -183,7 +183,7 @@ class MainActivity : CastEnabledActivity() { } } } - EventBus.getDefault().postSticky(ac.mdiq.podcini.util.event.FeedUpdateRunningEvent(isRefreshingFeeds)) + EventBus.getDefault().postSticky(FeedUpdateRunningEvent(isRefreshingFeeds)) } WorkManager.getInstance(this) .getWorkInfosByTagLiveData(DownloadServiceInterface.WORK_TAG) 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 eb5d3505..6136d816 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 @@ -89,22 +89,6 @@ open class EpisodeItemListAdapter(mainActivity: MainActivity) : } } -// holder.infoCard.setOnClickListener { -// if (inActionMode()) { -// toggleSelection(holder.bindingAdapterPosition) -// } else { -// longPressedItem = item -// longPressedPosition = holder.bindingAdapterPosition -// it.showContextMenu() -// } -// } - -// holder.infoCard.setOnCreateContextMenuListener(this) -// holder.infoCard.setOnLongClickListener { -// longPressedItem = item -// longPressedPosition = holder.bindingAdapterPosition -// false -// } holder.coverHolder.setOnClickListener { val activity: MainActivity? = mainActivityRef.get() if (!inActionMode()) { diff --git a/app/src/main/java/ac/mdiq/podcini/ui/adapter/SubscriptionsRecyclerAdapter.kt b/app/src/main/java/ac/mdiq/podcini/ui/adapter/SubscriptionsRecyclerAdapter.kt index 171f96a4..a6461a53 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/adapter/SubscriptionsRecyclerAdapter.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/adapter/SubscriptionsRecyclerAdapter.kt @@ -85,24 +85,6 @@ open class SubscriptionsRecyclerAdapter(mainActivity: MainActivity) : true } -// holder.infoCard.setOnClickListener { -// if (inActionMode()) { -// holder.selectCheckbox.setChecked(!isSelected(holder.bindingAdapterPosition)) -// } else { -// longPressedPosition = holder.bindingAdapterPosition -// selectedItem = drawerItem -// it.showContextMenu() -// } -// } -// holder.infoCard.setOnCreateContextMenuListener(this) -// holder.infoCard.setOnLongClickListener { -// if (!inActionMode()) { -// longPressedPosition = holder.bindingAdapterPosition -// selectedItem = drawerItem -// } -// false -// } - holder.itemView.setOnTouchListener { _: View?, e: MotionEvent -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (e.isFromSource(InputDevice.SOURCE_MOUSE) diff --git a/app/src/main/java/ac/mdiq/podcini/ui/dialog/SubscriptionsFilterDialog.kt b/app/src/main/java/ac/mdiq/podcini/ui/dialog/SubscriptionsFilterDialog.kt index 604d318d..f2fe302c 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/dialog/SubscriptionsFilterDialog.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/dialog/SubscriptionsFilterDialog.kt @@ -35,8 +35,7 @@ class SubscriptionsFilterDialog : BottomSheetDialogFragment() { for (item in SubscriptionsFilterGroup.entries) { val binding = FilterDialogRowBinding.inflate(inflater) binding.root.addOnButtonCheckedListener { _: MaterialButtonToggleGroup?, _: Int, _: Boolean -> - updateFilter( - filterValues) + updateFilter(filterValues) } binding.buttonGroup.weightSum = item.values.size.toFloat() binding.filterButton1.setText(item.values[0].displayName) diff --git a/app/src/main/java/ac/mdiq/podcini/ui/dialog/TagSettingsDialog.kt b/app/src/main/java/ac/mdiq/podcini/ui/dialog/TagSettingsDialog.kt index b288c20d..cf8bae01 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/dialog/TagSettingsDialog.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/dialog/TagSettingsDialog.kt @@ -7,6 +7,7 @@ import ac.mdiq.podcini.storage.DBWriter import ac.mdiq.podcini.storage.model.feed.FeedPreferences import ac.mdiq.podcini.ui.adapter.SimpleChipAdapter import ac.mdiq.podcini.ui.view.ItemOffsetDecoration +import ac.mdiq.podcini.util.event.FeedTagsChangedEvent import android.app.Dialog import android.content.DialogInterface import android.os.Bundle @@ -21,6 +22,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder import io.reactivex.Observable import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.schedulers.Schedulers +import org.greenrobot.eventbus.EventBus import java.io.Serializable class TagSettingsDialog : DialogFragment() { @@ -79,6 +81,7 @@ class TagSettingsDialog : DialogFragment() { addTag(viewBinding.newTagEditText.text.toString().trim { it <= ' ' }) updatePreferencesTags(feedPreferencesList, commonTags) DBReader.buildTags() + EventBus.getDefault().post(FeedTagsChangedEvent()) } dialog.setNegativeButton(R.string.cancel_label, null) return dialog.create() diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/ChaptersFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/ChaptersFragment.kt index f5cbe9ee..7fce5ff0 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/ChaptersFragment.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/ChaptersFragment.kt @@ -64,7 +64,6 @@ class ChaptersFragment : AppCompatDialogFragment() { fun onCreateView(inflater: LayoutInflater): View { val viewBinding = SimpleListFragmentBinding.inflate(inflater) -// val root = inflater.inflate(R.layout.simple_list_fragment, null, false) viewBinding.toolbar.visibility = View.GONE Log.d(TAG, "fragment onCreateView") diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/CompletedDownloadsFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/CompletedDownloadsFragment.kt index fbe3d4f0..09cd4e21 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/CompletedDownloadsFragment.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/CompletedDownloadsFragment.kt @@ -15,6 +15,7 @@ import com.leinardi.android.speeddial.SpeedDialView import ac.mdiq.podcini.R import ac.mdiq.podcini.databinding.MultiSelectSpeedDialBinding import ac.mdiq.podcini.databinding.SimpleListFragmentBinding +import ac.mdiq.podcini.feed.util.PlaybackSpeedUtils import ac.mdiq.podcini.ui.adapter.EpisodeItemListAdapter import ac.mdiq.podcini.ui.adapter.SelectableAdapter import ac.mdiq.podcini.ui.adapter.actionbutton.DeleteActionButton @@ -37,6 +38,9 @@ import ac.mdiq.podcini.ui.view.EmptyViewHandler import ac.mdiq.podcini.ui.view.EpisodeItemListRecyclerView import ac.mdiq.podcini.ui.view.LiftOnScrollListener import ac.mdiq.podcini.ui.view.viewholder.EpisodeItemViewHolder +import ac.mdiq.podcini.util.Converter +import ac.mdiq.podcini.util.event.FeedItemEvent +import android.widget.TextView import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.SimpleItemAnimator import io.reactivex.Observable @@ -46,6 +50,9 @@ import io.reactivex.schedulers.Schedulers import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode +import java.util.* +import kotlin.collections.ArrayList +import kotlin.collections.HashSet /** * Displays all completed downloads and provides a button to delete them. @@ -53,7 +60,8 @@ import org.greenrobot.eventbus.ThreadMode class CompletedDownloadsFragment : Fragment(), SelectableAdapter.OnSelectModeListener, Toolbar.OnMenuItemClickListener { private var runningDownloads: Set? = HashSet() private var items: MutableList = mutableListOf() - + + private lateinit var infoBar: TextView private lateinit var adapter: CompletedDownloadsListAdapter private lateinit var toolbar: MaterialToolbar private lateinit var recyclerView: EpisodeItemListRecyclerView @@ -69,11 +77,10 @@ class CompletedDownloadsFragment : Fragment(), SelectableAdapter.OnSelectModeLis @UnstableApi override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { - val viewBinding = SimpleListFragmentBinding.inflate(inflater) -// val root: View = inflater.inflate(R.layout.simple_list_fragment, container, false) + val binding = SimpleListFragmentBinding.inflate(inflater) Log.d(TAG, "fragment onCreateView") - toolbar = viewBinding.toolbar + toolbar = binding.toolbar toolbar.setTitle(R.string.downloads_label) toolbar.inflateMenu(R.menu.downloads_completed) toolbar.setOnMenuItemClickListener(this) @@ -88,12 +95,12 @@ class CompletedDownloadsFragment : Fragment(), SelectableAdapter.OnSelectModeLis } (activity as MainActivity).setupToolbarToggle(toolbar, displayUpArrow) - recyclerView = viewBinding.recyclerView + recyclerView = binding.recyclerView recyclerView.setRecycledViewPool((activity as MainActivity).recycledViewPool) adapter = CompletedDownloadsListAdapter(activity as MainActivity) adapter.setOnSelectModeListener(this) recyclerView.adapter = adapter - recyclerView.addOnScrollListener(LiftOnScrollListener(viewBinding.appbar)) + recyclerView.addOnScrollListener(LiftOnScrollListener(binding.appbar)) swipeActions = SwipeActions(this, TAG).attachTo(recyclerView) swipeActions.setFilter(FeedItemFilter(FeedItemFilter.DOWNLOADED)) @@ -102,10 +109,12 @@ class CompletedDownloadsFragment : Fragment(), SelectableAdapter.OnSelectModeLis animator.supportsChangeAnimations = false } - progressBar = viewBinding.progLoading + progressBar = binding.progLoading progressBar.visibility = View.VISIBLE - val multiSelectDial = MultiSelectSpeedDialBinding.bind(viewBinding.root) + infoBar = binding.infoBar + + val multiSelectDial = MultiSelectSpeedDialBinding.bind(binding.root) speedDialView = multiSelectDial.fabSD speedDialView.overlayLayout = multiSelectDial.fabSDOverlay speedDialView.inflate(R.menu.episodes_apply_action_speeddial) @@ -113,7 +122,6 @@ class CompletedDownloadsFragment : Fragment(), SelectableAdapter.OnSelectModeLis speedDialView.removeActionItemById(R.id.mark_read_batch) speedDialView.removeActionItemById(R.id.mark_unread_batch) speedDialView.removeActionItemById(R.id.remove_from_queue_batch) -// speedDialView.removeActionItemById(R.id.remove_all_inbox_item) speedDialView.setOnChangeListener(object : SpeedDialView.OnChangeListener { override fun onMainActionSelected(): Boolean { return false @@ -144,7 +152,7 @@ class CompletedDownloadsFragment : Fragment(), SelectableAdapter.OnSelectModeLis loadItems() - return viewBinding.root + return binding.root } override fun onSaveInstanceState(outState: Bundle) { @@ -227,7 +235,7 @@ class CompletedDownloadsFragment : Fragment(), SelectableAdapter.OnSelectModeLis } @Subscribe(threadMode = ThreadMode.MAIN) - fun onEventMainThread(event: ac.mdiq.podcini.util.event.FeedItemEvent) { + fun onEventMainThread(event: FeedItemEvent) { Log.d(TAG, "onEventMainThread() called with: event = [$event]") var i = 0 @@ -252,6 +260,7 @@ class CompletedDownloadsFragment : Fragment(), SelectableAdapter.OnSelectModeLis adapter.setDummyViews(0) adapter.updateItems(items) } + refreshInfoBar() } @UnstableApi @Subscribe(threadMode = ThreadMode.MAIN) @@ -264,6 +273,7 @@ class CompletedDownloadsFragment : Fragment(), SelectableAdapter.OnSelectModeLis break } } + refreshInfoBar() } @Subscribe(threadMode = ThreadMode.MAIN) @@ -312,6 +322,7 @@ class CompletedDownloadsFragment : Fragment(), SelectableAdapter.OnSelectModeLis adapter.setDummyViews(0) progressBar.visibility = View.GONE adapter.updateItems(result) + refreshInfoBar() }, { error: Throwable? -> adapter.setDummyViews(0) adapter.updateItems(emptyList()) @@ -319,6 +330,18 @@ class CompletedDownloadsFragment : Fragment(), SelectableAdapter.OnSelectModeLis }) } + private fun refreshInfoBar() { + var info = String.format(Locale.getDefault(), "%d%s", items.size, getString(R.string.episodes_suffix)) + if (items.isNotEmpty()) { + var sizeMB: Long = 0 + for (item in items) { + sizeMB += item.media?.size?:0 + } + info += " • " + getString(R.string.size) + " : " + (sizeMB / 1000000) + " MB" + } + infoBar.text = info + } + override fun onStartSelectMode() { swipeActions.detach() speedDialView.visibility = View.VISIBLE diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/ItemFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/ItemFragment.kt index cb6dc842..ead2cdd4 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/ItemFragment.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/ItemFragment.kt @@ -17,9 +17,11 @@ import ac.mdiq.podcini.ui.common.CircularProgressBar import ac.mdiq.podcini.ui.common.ThemeUtils import ac.mdiq.podcini.ui.gui.ShownotesCleaner import ac.mdiq.podcini.ui.view.ShownotesWebView +import ac.mdiq.podcini.util.Converter import ac.mdiq.podcini.util.DateFormatter import ac.mdiq.podcini.util.PlaybackStatus import ac.mdiq.podcini.util.event.EpisodeDownloadEvent +import ac.mdiq.podcini.util.event.FeedItemEvent import ac.mdiq.podcini.util.event.UnreadItemsUpdateEvent import android.os.Build import android.os.Bundle @@ -277,9 +279,9 @@ class ItemFragment : Fragment() { } else { noMediaLabel.visibility = View.GONE if (media.getDuration() > 0) { - txtvDuration.text = ac.mdiq.podcini.util.Converter.getDurationStringLong(media.getDuration()) + txtvDuration.text = Converter.getDurationStringLong(media.getDuration()) txtvDuration.setContentDescription( - ac.mdiq.podcini.util.Converter.getDurationStringLocalized(requireContext(), media.getDuration().toLong())) + Converter.getDurationStringLocalized(requireContext(), media.getDuration().toLong())) } if (item != null) { actionButton1 = if (PlaybackStatus.isCurrentlyPlaying(media)) { @@ -329,7 +331,7 @@ class ItemFragment : Fragment() { } @UnstableApi @Subscribe(threadMode = ThreadMode.MAIN) - fun onEventMainThread(event: ac.mdiq.podcini.util.event.FeedItemEvent) { + fun onEventMainThread(event: FeedItemEvent) { Log.d(TAG, "onEventMainThread() called with: event = [$event]") if (this.item == null) return for (item in event.items) { diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/ItemPagerFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/ItemPagerFragment.kt index 0997bea1..f6cd8f99 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/ItemPagerFragment.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/ItemPagerFragment.kt @@ -6,6 +6,7 @@ import ac.mdiq.podcini.storage.DBReader import ac.mdiq.podcini.storage.model.feed.FeedItem import ac.mdiq.podcini.ui.activity.MainActivity import ac.mdiq.podcini.ui.menuhandler.FeedItemMenuHandler +import ac.mdiq.podcini.util.event.FeedItemEvent import android.os.Bundle import android.util.Log import android.view.LayoutInflater @@ -128,7 +129,7 @@ class ItemPagerFragment : Fragment(), Toolbar.OnMenuItemClickListener { } @UnstableApi @Subscribe(threadMode = ThreadMode.MAIN) - fun onEventMainThread(event: ac.mdiq.podcini.util.event.FeedItemEvent) { + fun onEventMainThread(event: FeedItemEvent) { for (item in event.items) { if (this.item != null && this.item!!.id == item.id) { this.item = item diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/NavDrawerFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/NavDrawerFragment.kt index 2aa01040..9106ff2b 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/NavDrawerFragment.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/NavDrawerFragment.kt @@ -15,6 +15,7 @@ import ac.mdiq.podcini.ui.common.ThemeUtils import ac.mdiq.podcini.ui.dialog.* import ac.mdiq.podcini.ui.menuhandler.MenuItemUtils import ac.mdiq.podcini.ui.statistics.StatisticsFragment +import ac.mdiq.podcini.util.event.FeedListUpdateEvent import android.R.attr import android.app.Activity import android.content.Context @@ -197,7 +198,7 @@ class NavDrawerFragment : Fragment(), SharedPreferences.OnSharedPreferenceChange @Subscribe(threadMode = ThreadMode.MAIN) - fun onFeedListChanged(event: ac.mdiq.podcini.util.event.FeedListUpdateEvent?) { + fun onFeedListChanged(event: FeedListUpdateEvent?) { loadData() } diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/QueueFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/QueueFragment.kt index 66b6ebeb..94e66f56 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/QueueFragment.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/QueueFragment.kt @@ -49,6 +49,7 @@ import ac.mdiq.podcini.ui.view.EmptyViewHandler import ac.mdiq.podcini.ui.view.EpisodeItemListRecyclerView import ac.mdiq.podcini.ui.view.LiftOnScrollListener import ac.mdiq.podcini.ui.view.viewholder.EpisodeItemViewHolder +import ac.mdiq.podcini.util.Converter import io.reactivex.Observable import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.Disposable @@ -456,7 +457,7 @@ class QueueFragment : Fragment(), Toolbar.OnMenuItemClickListener, SelectableAda } info += " • " info += getString(R.string.time_left_label) - info += ac.mdiq.podcini.util.Converter.getDurationStringLocalized(requireActivity(), timeLeft) + info += Converter.getDurationStringLocalized(requireActivity(), timeLeft) } infoBar.text = info } diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/SubscriptionFragment.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/SubscriptionFragment.kt index d1048f5b..ccb4bf07 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/SubscriptionFragment.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/SubscriptionFragment.kt @@ -19,6 +19,8 @@ import ac.mdiq.podcini.ui.menuhandler.MenuItemUtils import ac.mdiq.podcini.ui.view.EmptyViewHandler import ac.mdiq.podcini.ui.view.LiftOnScrollListener import ac.mdiq.podcini.util.event.FeedListUpdateEvent +import ac.mdiq.podcini.util.event.FeedTagsChangedEvent +import ac.mdiq.podcini.util.event.FeedUpdateRunningEvent import ac.mdiq.podcini.util.event.UnreadItemsUpdateEvent import android.content.Context import android.content.SharedPreferences @@ -26,10 +28,7 @@ import android.os.Bundle import android.util.Log import android.view.* import android.view.inputmethod.EditorInfo -import android.widget.AdapterView -import android.widget.ArrayAdapter -import android.widget.LinearLayout -import android.widget.ProgressBar +import android.widget.* import androidx.appcompat.widget.Toolbar import androidx.fragment.app.Fragment import androidx.media3.common.util.UnstableApi @@ -53,17 +52,19 @@ import java.util.* * Fragment for displaying feed subscriptions */ class SubscriptionFragment : Fragment(), Toolbar.OnMenuItemClickListener, SelectableAdapter.OnSelectModeListener { + private lateinit var subscriptionRecycler: RecyclerView private lateinit var subscriptionAdapter: SubscriptionsRecyclerAdapter private lateinit var emptyView: EmptyViewHandler - private lateinit var feedsFilteredMsg: LinearLayout + private lateinit var feedsInfoMsg: LinearLayout + private lateinit var feedsFilteredMsg: TextView + private lateinit var feedCount: TextView private lateinit var toolbar: MaterialToolbar private lateinit var swipeRefreshLayout: SwipeRefreshLayout private lateinit var progressBar: ProgressBar private lateinit var prefs: SharedPreferences private lateinit var speedDialView: SpeedDialView - private val tags: MutableList = mutableListOf() private var tagFilterIndex = 1 private var displayedFolder: String = "" private var displayUpArrow = false @@ -81,10 +82,10 @@ class SubscriptionFragment : Fragment(), Toolbar.OnMenuItemClickListener, Select @UnstableApi override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - val viewBinding = FragmentSubscriptionsBinding.inflate(inflater) + val binding = FragmentSubscriptionsBinding.inflate(inflater) Log.d(TAG, "fragment onCreateView") - toolbar = viewBinding.toolbar + toolbar = binding.toolbar toolbar.setOnMenuItemClickListener(this) toolbar.setOnLongClickListener { subscriptionRecycler.scrollToPosition(5) @@ -103,10 +104,10 @@ class SubscriptionFragment : Fragment(), Toolbar.OnMenuItemClickListener, Select toolbar.title = displayedFolder } - subscriptionRecycler = viewBinding.subscriptionsGrid + subscriptionRecycler = binding.subscriptionsGrid subscriptionRecycler.addItemDecoration(SubscriptionsRecyclerAdapter.GridDividerItemDecorator()) registerForContextMenu(subscriptionRecycler) - subscriptionRecycler.addOnScrollListener(LiftOnScrollListener(viewBinding.appbar)) + subscriptionRecycler.addOnScrollListener(LiftOnScrollListener(binding.appbar)) subscriptionAdapter = object : SubscriptionsRecyclerAdapter(activity as MainActivity) { override fun onCreateContextMenu(menu: ContextMenu, v: View, menuInfo: ContextMenu.ContextMenuInfo?) { super.onCreateContextMenu(menu, v, menuInfo) @@ -123,14 +124,13 @@ class SubscriptionFragment : Fragment(), Toolbar.OnMenuItemClickListener, Select subscriptionRecycler.adapter = subscriptionAdapter setupEmptyView() - tags.add("Untagged") - tags.add("All") - tags.addAll(DBReader.getTags()) - val adapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item, tags) - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) - val catSpinner = viewBinding.categorySpinner - catSpinner.setAdapter(adapter) - catSpinner.setSelection(adapter.getPosition("All")) + resetTags() + + val catAdapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item, tags) + catAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) + val catSpinner = binding.categorySpinner + catSpinner.setAdapter(catAdapter) + catSpinner.setSelection(catAdapter.getPosition("All")) catSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { override fun onItemSelected(parent: AdapterView<*>?, view: View, position: Int, id: Long) { tagFilterIndex = position @@ -140,7 +140,7 @@ class SubscriptionFragment : Fragment(), Toolbar.OnMenuItemClickListener, Select override fun onNothingSelected(parent: AdapterView<*>?) {} } - val searchBox = viewBinding.searchBox + val searchBox = binding.searchBox searchBox.setOnEditorActionListener { _, actionId, _ -> if (actionId == EditorInfo.IME_ACTION_SEARCH) { val text = searchBox.text.toString().lowercase(Locale.getDefault()) @@ -155,29 +155,32 @@ class SubscriptionFragment : Fragment(), Toolbar.OnMenuItemClickListener, Select } } - progressBar = viewBinding.progressBar + progressBar = binding.progressBar progressBar.visibility = View.VISIBLE - val subscriptionAddButton: FloatingActionButton = viewBinding.subscriptionsAdd + val subscriptionAddButton: FloatingActionButton = binding.subscriptionsAdd subscriptionAddButton.setOnClickListener { if (activity is MainActivity) { (activity as MainActivity).loadChildFragment(AddFeedFragment()) } } - feedsFilteredMsg = viewBinding.feedsFilteredMessage - feedsFilteredMsg.setOnClickListener { - SubscriptionsFilterDialog().show( - childFragmentManager, "filter") - } + feedsInfoMsg = binding.feedsInfoMessage +// feedsInfoMsg.setOnClickListener { +// SubscriptionsFilterDialog().show( +// childFragmentManager, "filter") +// } + feedsFilteredMsg = binding.feedsFilteredMessage + feedCount = binding.count + feedCount.text = feedListFiltered.size.toString() + " / " + feedList.size.toString() - swipeRefreshLayout = viewBinding.swipeRefresh + swipeRefreshLayout = binding.swipeRefresh swipeRefreshLayout.setDistanceToTriggerSync(resources.getInteger(R.integer.swipe_refresh_distance)) swipeRefreshLayout.setOnRefreshListener { FeedUpdateManager.runOnceOrAsk(requireContext()) } - val speedDialBinding = MultiSelectSpeedDialBinding.bind(viewBinding.root) + val speedDialBinding = MultiSelectSpeedDialBinding.bind(binding.root) speedDialView = speedDialBinding.fabSD speedDialView.overlayLayout = speedDialBinding.fabSDOverlay @@ -199,7 +202,7 @@ class SubscriptionFragment : Fragment(), Toolbar.OnMenuItemClickListener, Select EventBus.getDefault().register(this) loadSubscriptions() - return viewBinding.root + return binding.root } override fun onDestroyView() { @@ -215,29 +218,31 @@ class SubscriptionFragment : Fragment(), Toolbar.OnMenuItemClickListener, Select fun filterOnTag() { when (tagFilterIndex) { -// All feeds 1 -> { +// All feeds feedListFiltered = feedList } -// feeds without tag 0 -> { +// feeds without tag feedListFiltered = feedList.filter { val tags = it.feed.preferences?.getTags() tags.isNullOrEmpty() || (tags.size == 1 && tags.toList()[0] == "#root") } } -// feeds with the chosen tag else -> { +// feeds with the chosen tag val tag = tags[tagFilterIndex] feedListFiltered = feedList.filter { it.feed.preferences?.getTags()?.contains(tag) ?: false } } } + feedCount.text = feedListFiltered.size.toString() + " / " + feedList.size.toString() subscriptionAdapter.setItems(feedListFiltered) } + @Subscribe(sticky = true, threadMode = ThreadMode.MAIN) - fun onEventMainThread(event: ac.mdiq.podcini.util.event.FeedUpdateRunningEvent) { + fun onEventMainThread(event: FeedUpdateRunningEvent) { swipeRefreshLayout.isRefreshing = event.isFeedUpdateRunning } @@ -297,6 +302,7 @@ class SubscriptionFragment : Fragment(), Toolbar.OnMenuItemClickListener, Select filterOnTag() progressBar.visibility = View.GONE subscriptionAdapter.setItems(feedListFiltered) + feedCount.text = feedListFiltered.size.toString() + " / " + feedList.size.toString() emptyView.updateVisibility() }, { error: Throwable? -> Log.e(TAG, Log.getStackTraceString(error)) @@ -332,6 +338,11 @@ class SubscriptionFragment : Fragment(), Toolbar.OnMenuItemClickListener, Select loadSubscriptions() } + @Subscribe(threadMode = ThreadMode.MAIN) + fun onFeedTagsChanged(event: FeedTagsChangedEvent?) { + resetTags() + } + override fun onEndSelectMode() { speedDialView.close() speedDialView.visibility = View.GONE @@ -353,6 +364,8 @@ class SubscriptionFragment : Fragment(), Toolbar.OnMenuItemClickListener, Select private const val KEY_UP_ARROW = "up_arrow" private const val ARGUMENT_FOLDER = "folder" + private val tags: MutableList = mutableListOf() + fun newInstance(folderTitle: String?): SubscriptionFragment { val fragment = SubscriptionFragment() val args = Bundle() @@ -360,5 +373,12 @@ class SubscriptionFragment : Fragment(), Toolbar.OnMenuItemClickListener, Select fragment.arguments = args return fragment } + + fun resetTags() { + tags.clear() + tags.add("Untagged") + tags.add("All") + tags.addAll(DBReader.getTags()) + } } } diff --git a/app/src/main/java/ac/mdiq/podcini/ui/fragment/actions/FeedMultiSelectActionHandler.kt b/app/src/main/java/ac/mdiq/podcini/ui/fragment/actions/FeedMultiSelectActionHandler.kt index 317e6393..f524e1b1 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/fragment/actions/FeedMultiSelectActionHandler.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/fragment/actions/FeedMultiSelectActionHandler.kt @@ -17,7 +17,10 @@ import ac.mdiq.podcini.ui.fragment.preferences.dialog.PreferenceListDialog import ac.mdiq.podcini.ui.fragment.preferences.dialog.PreferenceSwitchDialog import ac.mdiq.podcini.storage.model.feed.Feed import ac.mdiq.podcini.storage.model.feed.FeedPreferences +import ac.mdiq.podcini.ui.fragment.SubscriptionFragment +import ac.mdiq.podcini.util.event.FeedTagsChangedEvent import androidx.media3.common.util.UnstableApi +import org.greenrobot.eventbus.EventBus import java.util.* @UnstableApi diff --git a/app/src/main/java/ac/mdiq/podcini/ui/view/ShownotesWebView.kt b/app/src/main/java/ac/mdiq/podcini/ui/view/ShownotesWebView.kt index 380bf143..6820d703 100644 --- a/app/src/main/java/ac/mdiq/podcini/ui/view/ShownotesWebView.kt +++ b/app/src/main/java/ac/mdiq/podcini/ui/view/ShownotesWebView.kt @@ -26,6 +26,7 @@ import ac.mdiq.podcini.util.IntentUtils import ac.mdiq.podcini.util.NetworkUtils import ac.mdiq.podcini.util.ShareUtils import ac.mdiq.podcini.ui.gui.ShownotesCleaner +import ac.mdiq.podcini.util.Converter import androidx.media3.common.util.UnstableApi import kotlin.math.max @@ -151,7 +152,7 @@ class ShownotesWebView : WebView, View.OnLongClickListener { if (ShownotesCleaner.isTimecodeLink(selectedUrl)) { menu.add(Menu.NONE, R.id.go_to_position_item, Menu.NONE, R.string.go_to_position_label) - menu.setHeaderTitle(ac.mdiq.podcini.util.Converter.getDurationStringLong(ShownotesCleaner.getTimecodeLinkTime(selectedUrl))) + menu.setHeaderTitle(Converter.getDurationStringLong(ShownotesCleaner.getTimecodeLinkTime(selectedUrl))) } else { val uri = Uri.parse(selectedUrl) val intent = Intent(Intent.ACTION_VIEW, uri) diff --git a/app/src/main/java/ac/mdiq/podcini/util/event/FeedTagsChangedEvent.kt b/app/src/main/java/ac/mdiq/podcini/util/event/FeedTagsChangedEvent.kt new file mode 100644 index 00000000..10445bad --- /dev/null +++ b/app/src/main/java/ac/mdiq/podcini/util/event/FeedTagsChangedEvent.kt @@ -0,0 +1,3 @@ +package ac.mdiq.podcini.util.event + +class FeedTagsChangedEvent \ No newline at end of file diff --git a/app/src/main/res/drawable/arrows_sort.xml b/app/src/main/res/drawable/arrows_sort.xml index 6ece9d2a..2b859b65 100644 --- a/app/src/main/res/drawable/arrows_sort.xml +++ b/app/src/main/res/drawable/arrows_sort.xml @@ -8,13 +8,13 @@ android:strokeLineJoin="round" android:strokeWidth="2" android:fillColor="#00000000" - android:strokeColor="?attr/colorPrimary" + android:strokeColor="?attr/action_icon_color" android:strokeLineCap="round"/> diff --git a/app/src/main/res/drawable/baseline_arrow_downward_24.xml b/app/src/main/res/drawable/baseline_arrow_downward_24.xml index dcfb7840..499223e5 100644 --- a/app/src/main/res/drawable/baseline_arrow_downward_24.xml +++ b/app/src/main/res/drawable/baseline_arrow_downward_24.xml @@ -1,5 +1,5 @@ - - + diff --git a/app/src/main/res/drawable/baseline_arrow_upward_24.xml b/app/src/main/res/drawable/baseline_arrow_upward_24.xml index 46d5d587..2b2c71a3 100644 --- a/app/src/main/res/drawable/baseline_arrow_upward_24.xml +++ b/app/src/main/res/drawable/baseline_arrow_upward_24.xml @@ -1,5 +1,5 @@ - - + diff --git a/app/src/main/res/layout/fragment_subscriptions.xml b/app/src/main/res/layout/fragment_subscriptions.xml index c5d60fb8..ff37dd58 100644 --- a/app/src/main/res/layout/fragment_subscriptions.xml +++ b/app/src/main/res/layout/fragment_subscriptions.xml @@ -22,11 +22,11 @@ app:navigationIcon="?homeAsUpIndicator" /> + android:text="@string/filtered_label" /> + + + + diff --git a/app/src/main/res/layout/simple_list_fragment.xml b/app/src/main/res/layout/simple_list_fragment.xml index bf203ce0..6678590d 100644 --- a/app/src/main/res/layout/simple_list_fragment.xml +++ b/app/src/main/res/layout/simple_list_fragment.xml @@ -3,7 +3,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" - android:layout_height="match_parent" + android:layout_height="match_parent" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/simple_list_fragment"> + + - - - - - - - - - -