add info bars and thematic icons

This commit is contained in:
Xilin Jia 2024-03-17 11:53:15 +00:00
parent de261e2825
commit 063af37362
30 changed files with 176 additions and 124 deletions

View File

@ -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 {

View File

@ -193,7 +193,7 @@ class UITestUtils(private val context: Context) {
adapter.setCompleteFeed(*hostedFeeds.toTypedArray<Feed>())
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))
}

View File

@ -10,14 +10,14 @@ import org.greenrobot.eventbus.Subscribe
*
*/
class FeedItemEventListener {
private val events: MutableList<ac.mdiq.podcini.util.event.FeedItemEvent> = ArrayList()
private val events: MutableList<FeedItemEvent> = ArrayList()
@Subscribe
fun onEvent(event: ac.mdiq.podcini.util.event.FeedItemEvent) {
fun onEvent(event: FeedItemEvent) {
events.add(event)
}
fun getEvents(): List<ac.mdiq.podcini.util.event.FeedItemEvent> {
fun getEvents(): List<FeedItemEvent> {
return events
}

View File

@ -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

View File

@ -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

View File

@ -74,8 +74,7 @@ class SubscriptionsFilter(private val properties: Array<String>) {
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)
}
}

View File

@ -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)

View File

@ -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()) {

View File

@ -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)

View File

@ -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)

View File

@ -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()

View File

@ -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")

View File

@ -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<String>? = HashSet()
private var items: MutableList<FeedItem> = 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

View File

@ -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) {

View File

@ -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

View File

@ -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()
}

View File

@ -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
}

View File

@ -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<String> = 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<String> = 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())
}
}
}

View File

@ -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

View File

@ -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)

View File

@ -0,0 +1,3 @@
package ac.mdiq.podcini.util.event
class FeedTagsChangedEvent

View File

@ -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"/>
<path
android:pathData="M21,15l-4,4l-4,-4m4,4v-14"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="?attr/colorPrimary"
android:strokeColor="?attr/action_icon_color"
android:strokeLineCap="round"/>
</vector>

View File

@ -1,5 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
<vector android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M20,12l-1.41,-1.41L13,16.17V4h-2v12.17l-5.58,-5.59L4,12l8,8 8,-8z"/>
<path android:fillColor="?attr/action_icon_color" android:pathData="M20,12l-1.41,-1.41L13,16.17V4h-2v12.17l-5.58,-5.59L4,12l8,8 8,-8z"/>
</vector>

View File

@ -1,5 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
<vector android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M4,12l1.41,1.41L11,7.83V20h2V7.83l5.58,5.59L20,12l-8,-8 -8,8z"/>
<path android:fillColor="?attr/action_icon_color" android:pathData="M4,12l1.41,1.41L11,7.83V20h2V7.83l5.58,5.59L20,12l-8,-8 -8,8z"/>
</vector>

View File

@ -22,11 +22,11 @@
app:navigationIcon="?homeAsUpIndicator" />
<LinearLayout
android:id="@+id/feeds_filtered_message"
android:id="@+id/feeds_info_message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="60dp"
android:paddingEnd="0dp"
android:paddingStart="20dp"
android:paddingEnd="20dp"
android:paddingVertical="4dp"
android:layout_marginTop="-12dp"
android:background="?android:attr/selectableItemBackground"
@ -39,10 +39,23 @@
android:src="@drawable/ic_info" />
<TextView
android:layout_width="match_parent"
android:id="@+id/feeds_filtered_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:text="@string/subscriptions_are_filtered" />
android:text="@string/filtered_label" />
<View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
<TextView
android:id="@+id/count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="12sp"
android:text="12 Podcasts" />
</LinearLayout>

View File

@ -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">
<com.google.android.material.appbar.AppBarLayout
@ -19,6 +19,18 @@
app:navigationContentDescription="@string/toolbar_back_button_content_description"
app:navigationIcon="?homeAsUpIndicator" />
<TextView
android:id="@+id/info_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/toolbar"
android:textSize="12sp"
android:layout_marginTop="-12dp"
android:layout_marginLeft="60dp"
android:layout_marginStart="60dp"
android:layout_marginBottom="8dp"
tools:text="12 Episodes - Size: 40 MB" />
</com.google.android.material.appbar.AppBarLayout>
<ac.mdiq.podcini.ui.view.EpisodeItemListRecyclerView

View File

@ -8,11 +8,6 @@
custom:showAsAction="collapseActionView">
</item>
<!-- <item-->
<!-- android:id="@+id/remove_inbox_item"-->
<!-- custom:showAsAction="collapseActionView"-->
<!-- android:title="@string/remove_inbox_label" />-->
<item
android:id="@+id/mark_read_item"
custom:showAsAction="collapseActionView"

View File

@ -5,11 +5,6 @@
android:menuCategory="container"
android:title="@string/skip_episode_label" />
<!-- <item-->
<!-- android:id="@+id/remove_inbox_item"-->
<!-- android:menuCategory="container"-->
<!-- android:title="@string/remove_inbox_label" />-->
<item
android:id="@+id/mark_read_item"
android:menuCategory="container"

View File

@ -78,4 +78,11 @@
* select all above or below are put to action bar together with select all
* operations are only on the selected (single or multiple)
* popup menus for single item operation are disabled
* in podcast view, the title bar no longer scrolls off screen
* in podcast view, the title bar no longer scrolls off screen
## 4.2.6
* corrected action icons for themes
* revealed info bar in Downloads view
* revealed info bar in Subscriptions view
* reset tags list in Subscriptions when new tag is added

View File

@ -0,0 +1,7 @@
Version 4.2.6 brings several changes:
* corrected action icons for themes
* revealed info bar in Downloads view
* revealed info bar in Subscriptions view
* reset tags list in Subscriptions when new tag is added