diff --git a/app/build.gradle b/app/build.gradle index f0364133..26cdd278 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -31,8 +31,8 @@ android { testApplicationId "ac.mdiq.podcini.tests" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - versionCode 3020279 - versionName "6.12.1" + versionCode 3020280 + versionName "6.12.2" applicationId "ac.mdiq.podcini.R" def commit = "" diff --git a/app/src/main/kotlin/ac/mdiq/podcini/playback/ServiceStatusHandler.kt b/app/src/main/kotlin/ac/mdiq/podcini/playback/ServiceStatusHandler.kt index 33d67b71..1f485b40 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/playback/ServiceStatusHandler.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/playback/ServiceStatusHandler.kt @@ -45,7 +45,7 @@ abstract class ServiceStatusHandler(private val activity: FragmentActivity) { Logd(TAG, "statusUpdate onReceive doing updates") MediaPlayerBase.status = info.playerStatus prevStatus = MediaPlayerBase.status - curMedia = info.playable +// curMedia = info.playable handleStatus() } } else { @@ -177,7 +177,7 @@ abstract class ServiceStatusHandler(private val activity: FragmentActivity) { Logd(TAG, "Querying service info") if (playbackService != null && PlaybackService.mPlayerInfo != null) { MediaPlayerBase.status = PlaybackService.mPlayerInfo!!.playerStatus - curMedia = PlaybackService.mPlayerInfo!!.playable +// curMedia = PlaybackService.mPlayerInfo!!.playable // make sure that new media is loaded if it's available mediaInfoLoaded = false handleStatus() diff --git a/app/src/main/kotlin/ac/mdiq/podcini/playback/base/MediaPlayerBase.kt b/app/src/main/kotlin/ac/mdiq/podcini/playback/base/MediaPlayerBase.kt index 0773ec2d..28848580 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/playback/base/MediaPlayerBase.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/playback/base/MediaPlayerBase.kt @@ -271,11 +271,13 @@ abstract class MediaPlayerBase protected constructor(protected val context: Cont Log.d(TAG, "${this.javaClass.simpleName}: Setting player status to $newStatus") this.oldStatus = status status = newStatus - if (newMedia != null) setPlayable(newMedia) - if (newMedia != null && newStatus != PlayerStatus.INDETERMINATE) { - when { - oldStatus == PlayerStatus.PLAYING && newStatus != PlayerStatus.PLAYING -> callback.onPlaybackPause(newMedia, position) - oldStatus != PlayerStatus.PLAYING && newStatus == PlayerStatus.PLAYING -> callback.onPlaybackStart(newMedia, position) + if (newMedia != null) { + setPlayable(newMedia) + if (newStatus != PlayerStatus.INDETERMINATE) { + when { + oldStatus == PlayerStatus.PLAYING && newStatus != PlayerStatus.PLAYING -> callback.onPlaybackPause(newMedia, position) + oldStatus != PlayerStatus.PLAYING && newStatus == PlayerStatus.PLAYING -> callback.onPlaybackStart(newMedia, position) + } } } callback.statusChanged(MediaPlayerInfo(oldStatus, status, curMedia)) diff --git a/app/src/main/kotlin/ac/mdiq/podcini/playback/service/PlaybackService.kt b/app/src/main/kotlin/ac/mdiq/podcini/playback/service/PlaybackService.kt index 567fdfb5..167cbb70 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/playback/service/PlaybackService.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/playback/service/PlaybackService.kt @@ -389,15 +389,23 @@ class PlaybackService : MediaLibraryService() { } } if (item != null) { +// fun shouldSkipKeepEpisode(): Boolean { +// return appPrefs.getBoolean(UserPreferences.Prefs.prefSkipKeepsEpisode.name, true) +// } +// fun shouldFavoriteKeepEpisode(): Boolean { +// return appPrefs.getBoolean(UserPreferences.Prefs.prefFavoriteKeepsEpisode.name, true) +// } runOnIOScope { - if (ended || smartMarkAsPlayed || autoSkipped || (skipped && !shouldSkipKeepEpisode())) { + val shouldSkipKeepEpisode = appPrefs.getBoolean(UserPreferences.Prefs.prefSkipKeepsEpisode.name, true) + val shouldFavoriteKeepEpisode = appPrefs.getBoolean(UserPreferences.Prefs.prefFavoriteKeepsEpisode.name, true) + if (ended || smartMarkAsPlayed || autoSkipped || (skipped && !shouldSkipKeepEpisode)) { Logd(TAG, "onPostPlayback ended: $ended smartMarkAsPlayed: $smartMarkAsPlayed autoSkipped: $autoSkipped skipped: $skipped") // only mark the item as played if we're not keeping it anyways item = setPlayStateSync(PlayState.PLAYED.code, ended || (skipped && smartMarkAsPlayed), item!!) val action = item?.feed?.preferences?.autoDeleteAction val shouldAutoDelete = (action == AutoDeleteAction.ALWAYS || (action == AutoDeleteAction.GLOBAL && item?.feed != null && shouldAutoDeleteItem(item!!.feed!!))) - if (playable is EpisodeMedia && shouldAutoDelete && (item?.isFavorite != true || !shouldFavoriteKeepEpisode())) { + if (playable is EpisodeMedia && shouldAutoDelete && (item?.isFavorite != true || !shouldFavoriteKeepEpisode)) { item = deleteMediaSync(this@PlaybackService, item!!) if (shouldDeleteRemoveFromQueue()) removeFromQueueSync(null, item!!) } @@ -407,14 +415,6 @@ class PlaybackService : MediaLibraryService() { } } - fun shouldSkipKeepEpisode(): Boolean { - return appPrefs.getBoolean(UserPreferences.Prefs.prefSkipKeepsEpisode.name, true) - } - - fun shouldFavoriteKeepEpisode(): Boolean { - return appPrefs.getBoolean(UserPreferences.Prefs.prefFavoriteKeepsEpisode.name, true) - } - override fun onPlaybackStart(playable: Playable, position: Int) { Logd(TAG, "onPlaybackStart position: $position") taskManager.startWidgetUpdater() @@ -747,12 +747,10 @@ class PlaybackService : MediaLibraryService() { override fun onDestroy() { Logd(TAG, "Service is about to be destroyed") - playbackService = null isRunning = false currentMediaType = MediaType.UNKNOWN castStateListener.destroy() - currentitem = null LocalMediaPlayer.cleanup() @@ -1967,8 +1965,8 @@ class PlaybackService : MediaLibraryService() { } override fun onIsPlayingChanged(isPlaying: Boolean) { // val stat = if (isPlaying) PlayerStatus.PLAYING else PlayerStatus.PAUSED -// TODO: test - val stat = if (isPlaying) PlayerStatus.PLAYING else PlayerStatus.INDETERMINATE +// TODO: test: changing PAUSED to STOPPED or INDETERMINATE makes resume not possible if interrupted + val stat = if (isPlaying) PlayerStatus.PLAYING else PlayerStatus.PAUSED setPlayerStatus(stat, curMedia) Logd(TAG, "onIsPlayingChanged $isPlaying") } diff --git a/app/src/main/kotlin/ac/mdiq/podcini/storage/model/EpisodeFilter.kt b/app/src/main/kotlin/ac/mdiq/podcini/storage/model/EpisodeFilter.kt index cf6af9f1..830173eb 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/storage/model/EpisodeFilter.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/storage/model/EpisodeFilter.kt @@ -20,6 +20,8 @@ class EpisodeFilter(vararg properties: String) : Serializable { val showNotAutoDownloadable: Boolean = hasProperty(States.not_auto_downloadable.name) val showHasMedia: Boolean = hasProperty(States.has_media.name) val showNoMedia: Boolean = hasProperty(States.no_media.name) + val showHasComments: Boolean = hasProperty(States.has_comments.name) + val showNoComments: Boolean = hasProperty(States.no_comments.name) val showIsFavorite: Boolean = hasProperty(States.is_favorite.name) val showNotFavorite: Boolean = hasProperty(States.not_favorite.name) @@ -48,6 +50,8 @@ class EpisodeFilter(vararg properties: String) : Serializable { showNotAutoDownloadable && item.isAutoDownloadEnabled -> return false showHasMedia && item.media == null -> return false showNoMedia && item.media != null -> return false + showHasComments && item.comment.isEmpty() -> return false + showNoComments && item.comment.isNotEmpty() -> return false showIsFavorite && !item.isFavorite -> return false showNotFavorite && item.isFavorite -> return false showQueued && !inAnyQueue(item) -> return false @@ -69,7 +73,7 @@ class EpisodeFilter(vararg properties: String) : Serializable { val statements: MutableList = ArrayList() when { showPlayed -> statements.add("playState >= ${PlayState.PLAYED.code}") - showUnplayed -> statements.add(" playState < ${PlayState.PLAYED.code}> ") // Match "New" items (read = -1) as well + showUnplayed -> statements.add(" playState < ${PlayState.PLAYED.code} ") // Match "New" items (read = -1) as well showNew -> statements.add("playState == -1 ") } when { @@ -93,8 +97,12 @@ class EpisodeFilter(vararg properties: String) : Serializable { showNoMedia -> statements.add("media == nil ") } when { - showIsFavorite -> statements.add("isFavorite == true ") - showNotFavorite -> statements.add("isFavorite == false ") + showHasComments -> statements.add(" comment != '' ") + showNoComments -> statements.add(" comment == '' ") + } + when { + showIsFavorite -> statements.add("rating == ${Rating.FAVORITE.code} ") + showNotFavorite -> statements.add("rating != ${Rating.FAVORITE.code} ") } if (statements.isEmpty()) return "id > 0" @@ -120,6 +128,8 @@ class EpisodeFilter(vararg properties: String) : Serializable { not_favorite, has_media, no_media, + has_comments, + no_comments, queued, not_queued, downloaded, diff --git a/app/src/main/kotlin/ac/mdiq/podcini/storage/model/FeedFilter.kt b/app/src/main/kotlin/ac/mdiq/podcini/storage/model/FeedFilter.kt index e8aa2989..accad8a4 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/storage/model/FeedFilter.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/storage/model/FeedFilter.kt @@ -11,6 +11,8 @@ class FeedFilter(vararg properties: String) : Serializable { val showNotKeepUpdated: Boolean = hasProperty(States.not_keepUpdated.name) val showGlobalPlaySpeed: Boolean = hasProperty(States.global_playSpeed.name) val showCustomPlaySpeed: Boolean = hasProperty(States.custom_playSpeed.name) + val showHasComments: Boolean = hasProperty(States.has_comments.name) + val showNoComments: Boolean = hasProperty(States.no_comments.name) val showHasSkips: Boolean = hasProperty(States.has_skips.name) val showNoSkips: Boolean = hasProperty(States.no_skips.name) val showAlwaysAutoDelete: Boolean = hasProperty(States.always_auto_delete.name) @@ -36,6 +38,8 @@ class FeedFilter(vararg properties: String) : Serializable { showNotKeepUpdated && feed.preferences?.keepUpdated != false -> return false showGlobalPlaySpeed && feed.preferences?.playSpeed != SPEED_USE_GLOBAL -> return false showCustomPlaySpeed && feed.preferences?.playSpeed == SPEED_USE_GLOBAL -> return false + showHasComments && feed.comment.isEmpty() -> return false + showNoComments && feed.comment.isEmpty() -> return false showHasSkips && feed.preferences?.introSkip == 0 && feed.preferences?.endingSkip == 0 -> return false showNoSkips && (feed.preferences?.introSkip != 0 || feed.preferences?.endingSkip != 0) -> return false showAlwaysAutoDelete && feed.preferences?.autoDeleteAction != FeedPreferences.AutoDeleteAction.ALWAYS -> return false @@ -60,6 +64,10 @@ class FeedFilter(vararg properties: String) : Serializable { showHasSkips -> statements.add(" preferences.introSkip != 0 OR preferences.endingSkip != 0 ") showNoSkips -> statements.add(" preferences.introSkip == 0 AND preferences.endingSkip == 0 ") } + when { + showHasComments -> statements.add(" comment != '' ") + showNoComments -> statements.add(" comment == '' ") + } when { showAlwaysAutoDelete -> statements.add(" preferences.autoDelete == ${FeedPreferences.AutoDeleteAction.ALWAYS.code} ") showNeverAutoDelete -> statements.add(" preferences.playSpeed == ${FeedPreferences.AutoDeleteAction.NEVER.code} ") @@ -89,6 +97,8 @@ class FeedFilter(vararg properties: String) : Serializable { custom_playSpeed, has_skips, no_skips, + has_comments, + no_comments, // global_auto_delete, always_auto_delete, never_auto_delete, diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/dialog/EpisodeFilterDialog.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/dialog/EpisodeFilterDialog.kt index f7bbb19e..feb737b3 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/dialog/EpisodeFilterDialog.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/dialog/EpisodeFilterDialog.kt @@ -1,92 +1,99 @@ package ac.mdiq.podcini.ui.dialog import ac.mdiq.podcini.R -import ac.mdiq.podcini.databinding.FilterDialogBinding -import ac.mdiq.podcini.databinding.FilterDialogRowBinding import ac.mdiq.podcini.storage.model.EpisodeFilter +import ac.mdiq.podcini.storage.model.FeedFilter +import ac.mdiq.podcini.ui.compose.CustomTheme import ac.mdiq.podcini.ui.fragment.SubscriptionsFragment.Companion.TAG +import ac.mdiq.podcini.ui.fragment.SubscriptionsFragment.FeedFilterDialog.FeedFilterGroup.ItemProperties import ac.mdiq.podcini.util.Logd import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.Button -import android.widget.LinearLayout +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.layout.* +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedButton +import androidx.compose.material3.Text +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp import com.google.android.material.bottomsheet.BottomSheetDialogFragment -import com.google.android.material.button.MaterialButtonToggleGroup abstract class EpisodeFilterDialog : BottomSheetDialogFragment() { - private lateinit var rows: LinearLayout - private var _binding: FilterDialogBinding? = null - private val binding get() = _binding!! var filter: EpisodeFilter? = null - private val buttonMap: MutableMap = mutableMapOf() val filtersDisabled: MutableSet = mutableSetOf() - - private val newFilterValues: Set - get() { - val newFilterValues: MutableSet = HashSet() - for (i in 0 until rows.childCount) { - if (rows.getChildAt(i) !is MaterialButtonToggleGroup) continue - val group = rows.getChildAt(i) as MaterialButtonToggleGroup - if (group.checkedButtonId == View.NO_ID) continue - val tag = group.findViewById(group.checkedButtonId).tag as? String ?: continue - newFilterValues.add(tag) - } - return newFilterValues - } + private val filterValues: MutableSet = mutableSetOf() override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - val layout = inflater.inflate(R.layout.filter_dialog, container, false) - _binding = FilterDialogBinding.bind(layout) - rows = binding.filterRows - Logd("EpisodeFilterDialog", "fragment onCreateView") - - //add filter rows - for (item in FeedItemFilterGroup.entries) { -// Logd("EpisodeFilterDialog", "FeedItemFilterGroup: ${item.values[0].filterId} ${item.values[1].filterId}") - if (item in filtersDisabled) continue - - val rBinding = FilterDialogRowBinding.inflate(inflater) - rBinding.filterButton1.setOnClickListener { onFilterChanged(newFilterValues) } - rBinding.filterButton2.setOnClickListener { onFilterChanged(newFilterValues) } - - rBinding.filterButton1.setText(item.values[0].displayName) - rBinding.filterButton1.tag = item.values[0].filterId - buttonMap[item.values[0].filterId] = rBinding.filterButton1 - rBinding.filterButton2.setText(item.values[1].displayName) - rBinding.filterButton2.tag = item.values[1].filterId - buttonMap[item.values[1].filterId] = rBinding.filterButton2 - rBinding.filterButton1.maxLines = 3 - rBinding.filterButton1.isSingleLine = false - rBinding.filterButton2.maxLines = 3 - rBinding.filterButton2.isSingleLine = false - rows.addView(rBinding.root, rows.childCount - 1) - } - - binding.confirmFiltermenu.setOnClickListener { dismiss() } - 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 (filter != null) { - for (filterId in filter!!.values) { - if (filterId.isNotEmpty()) { - val button = buttonMap[filterId] - if (button != null) (button.parent as MaterialButtonToggleGroup).check(button.id) + val composeView = ComposeView(requireContext()).apply { + setContent { + CustomTheme(requireContext()) { + MainView() + } + } + } + return composeView + } + + @Composable + fun MainView() { + val textColor = MaterialTheme.colorScheme.onSurface + Column { + for (item in FeedItemFilterGroup.entries) { + if (item in filtersDisabled) continue + Row(modifier = Modifier.padding(2.dp).fillMaxWidth(), horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically) { + var selectedIndex by remember { mutableStateOf(-1) } + LaunchedEffect(Unit) { + if (filter != null) { + if (item.values[0].filterId in filter!!.values) selectedIndex = 0 + else if (item.values[1].filterId in filter!!.values) selectedIndex = 1 + } + } + OutlinedButton(modifier = Modifier.padding(2.dp), border = BorderStroke(2.dp, if (selectedIndex != 0) textColor else Color.Green), + onClick = { + if (selectedIndex != 0) { + selectedIndex = 0 + filterValues.add(item.values[0].filterId) + filterValues.remove(item.values[1].filterId) + } else { + selectedIndex = -1 + filterValues.remove(item.values[0].filterId) + } + onFilterChanged(filterValues) + }, + ) { + Text(text = stringResource(item.values[0].displayName), color = textColor) + } + Spacer(Modifier.width(5.dp)) + OutlinedButton(modifier = Modifier.padding(2.dp), border = BorderStroke(2.dp, if (selectedIndex != 1) textColor else Color.Green), + onClick = { + if (selectedIndex != 1) { + selectedIndex = 1 + filterValues.add(item.values[1].filterId) + filterValues.remove(item.values[0].filterId) + } else { + selectedIndex = -1 + filterValues.remove(item.values[1].filterId) + } + onFilterChanged(filterValues) + }, + ) { + Text(text = stringResource(item.values[1].displayName), color = textColor) + } } } } - return layout } override fun onDestroyView() { Logd(TAG, "onDestroyView") - _binding = null super.onDestroyView() } @@ -97,6 +104,7 @@ abstract class EpisodeFilterDialog : BottomSheetDialogFragment() { PAUSED(ItemProperties(R.string.hide_paused_episodes_label, EpisodeFilter.States.paused.name), ItemProperties(R.string.not_paused, EpisodeFilter.States.not_paused.name)), FAVORITE(ItemProperties(R.string.hide_is_favorite_label, EpisodeFilter.States.is_favorite.name), ItemProperties(R.string.not_favorite, EpisodeFilter.States.not_favorite.name)), MEDIA(ItemProperties(R.string.has_media, EpisodeFilter.States.has_media.name), ItemProperties(R.string.no_media, EpisodeFilter.States.no_media.name)), + OPINION(ItemProperties(R.string.has_comments, EpisodeFilter.States.has_comments.name), ItemProperties(R.string.no_comments, EpisodeFilter.States.no_comments.name)), QUEUED(ItemProperties(R.string.queued_label, EpisodeFilter.States.queued.name), ItemProperties(R.string.not_queued_label, EpisodeFilter.States.not_queued.name)), DOWNLOADED(ItemProperties(R.string.downloaded_label, EpisodeFilter.States.downloaded.name), ItemProperties(R.string.not_downloaded_label, EpisodeFilter.States.not_downloaded.name)), AUTO_DOWNLOADABLE(ItemProperties(R.string.auto_downloadable_label, EpisodeFilter.States.auto_downloadable.name), ItemProperties(R.string.not_auto_downloadable_label, EpisodeFilter.States.not_auto_downloadable.name)); diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/AudioPlayerFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/AudioPlayerFragment.kt index b2f9d905..cd42ac02 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/AudioPlayerFragment.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/AudioPlayerFragment.kt @@ -6,6 +6,7 @@ import ac.mdiq.podcini.playback.PlaybackServiceStarter import ac.mdiq.podcini.playback.ServiceStatusHandler import ac.mdiq.podcini.playback.base.InTheatre.curEpisode import ac.mdiq.podcini.playback.base.InTheatre.curMedia +import ac.mdiq.podcini.playback.base.InTheatre.isCurrentlyPlaying import ac.mdiq.podcini.playback.base.MediaPlayerBase.Companion.status import ac.mdiq.podcini.playback.base.PlayerStatus import ac.mdiq.podcini.playback.base.VideoMode @@ -510,7 +511,7 @@ class AudioPlayerFragment : Fragment() { fun onPositionUpdate(event: FlowEvent.PlaybackPositionEvent) { Logd(TAG, "onPositionUpdate") if (!playButInit && playButRes == R.drawable.ic_play_48dp && curMedia is EpisodeMedia) { - playButRes = R.drawable.ic_pause + if (isCurrentlyPlaying(curMedia as? EpisodeMedia)) playButRes = R.drawable.ic_pause playButInit = true } @@ -753,14 +754,15 @@ class AudioPlayerFragment : Fragment() { Logd(TAG, "loadMediaInfo() curMedia: ${curMedia?.getIdentifier()}") val actMain = (activity as MainActivity) var i = 0 - while (curMedia == null && i++ < 6) runBlocking { delay(500) } +// while (curMedia == null && i++ < 6) runBlocking { delay(500) } if (curMedia == null) { if (actMain.isPlayerVisible()) actMain.setPlayerVisible(false) return } + if (!actMain.isPlayerVisible()) actMain.setPlayerVisible(true) if (!loadItemsRunning) { loadItemsRunning = true - if (!actMain.isPlayerVisible()) actMain.setPlayerVisible(true) +// if (!actMain.isPlayerVisible()) actMain.setPlayerVisible(true) val curMediaChanged = currentMedia == null || curMedia?.getIdentifier() != currentMedia?.getIdentifier() if (curMedia?.getIdentifier() != currentMedia?.getIdentifier()) updateUi(curMedia!!) if (!isCollapsed && curMediaChanged) { diff --git a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/SubscriptionsFragment.kt b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/SubscriptionsFragment.kt index b330259e..39fd4073 100644 --- a/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/SubscriptionsFragment.kt +++ b/app/src/main/kotlin/ac/mdiq/podcini/ui/fragment/SubscriptionsFragment.kt @@ -72,6 +72,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -650,7 +651,7 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener { Dialog(onDismissRequest = onDismissRequest) { Surface(shape = RoundedCornerShape(16.dp)) { Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp)) { - for (rating in Rating.entries) { + for (rating in Rating.entries.reversed()) { Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(4.dp).clickable { for (item in selected) Feeds.setRating(item, rating.code) onDismissRequest() @@ -1105,77 +1106,72 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener { } class FeedFilterDialog : BottomSheetDialogFragment() { - private lateinit var rows: LinearLayout - private var _binding: FilterDialogBinding? = null - private val binding get() = _binding!! - var filter: FeedFilter? = null - private val buttonMap: MutableMap = mutableMapOf() - - private val newFilterValues: Set - get() { - val newFilterValues: MutableSet = HashSet() - for (i in 0 until rows.childCount) { - if (rows.getChildAt(i) !is MaterialButtonToggleGroup) continue - val group = rows.getChildAt(i) as MaterialButtonToggleGroup - if (group.checkedButtonId == View.NO_ID) continue - val tag = group.findViewById(group.checkedButtonId).tag as? String ?: continue - newFilterValues.add(tag) - } - return newFilterValues - } + private val filterValues: MutableSet = mutableSetOf() override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - val layout = inflater.inflate(R.layout.filter_dialog, container, false) - _binding = FilterDialogBinding.bind(layout) - rows = binding.filterRows - Logd("FeedFilterDialog", "fragment onCreateView") - - //add filter rows - for (item in FeedFilterGroup.entries) { -// Logd("EpisodeFilterDialog", "FeedItemFilterGroup: ${item.values[0].filterId} ${item.values[1].filterId}") - val rBinding = FilterDialogRowBinding.inflate(inflater) -// rowBinding.root.addOnButtonCheckedListener { _: MaterialButtonToggleGroup?, _: Int, _: Boolean -> -// onFilterChanged(newFilterValues) -// } - rBinding.filterButton1.setOnClickListener { onFilterChanged(newFilterValues) } - rBinding.filterButton2.setOnClickListener { onFilterChanged(newFilterValues) } - - rBinding.filterButton1.setText(item.values[0].displayName) - rBinding.filterButton1.tag = item.values[0].filterId - buttonMap[item.values[0].filterId] = rBinding.filterButton1 - rBinding.filterButton2.setText(item.values[1].displayName) - rBinding.filterButton2.tag = item.values[1].filterId - buttonMap[item.values[1].filterId] = rBinding.filterButton2 - rBinding.filterButton1.maxLines = 3 - rBinding.filterButton1.isSingleLine = false - rBinding.filterButton2.maxLines = 3 - rBinding.filterButton2.isSingleLine = false - rows.addView(rBinding.root, rows.childCount - 1) - } - - binding.confirmFiltermenu.setOnClickListener { dismiss() } - 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 (filter != null) { - for (filterId in filter!!.values) { - if (filterId.isNotEmpty()) { - val button = buttonMap[filterId] - if (button != null) (button.parent as MaterialButtonToggleGroup).check(button.id) + val composeView = ComposeView(requireContext()).apply { + setContent { + CustomTheme(requireContext()) { + MainView() + } + } + } + return composeView + } + + @Composable + fun MainView() { + val textColor = MaterialTheme.colorScheme.onSurface + Column { + for (item in FeedFilterGroup.entries) { + Row(modifier = Modifier.padding(2.dp).fillMaxWidth(), horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically) { + var selectedIndex by remember { mutableStateOf(-1) } + LaunchedEffect(Unit) { + if (filter != null) { + if (item.values[0].filterId in filter!!.values) selectedIndex = 0 + else if (item.values[1].filterId in filter!!.values) selectedIndex = 1 + } + } + OutlinedButton(modifier = Modifier.padding(2.dp), border = BorderStroke(2.dp, if (selectedIndex != 0) textColor else Color.Green), + onClick = { + if (selectedIndex != 0) { + selectedIndex = 0 + filterValues.add(item.values[0].filterId) + filterValues.remove(item.values[1].filterId) + } else { + selectedIndex = -1 + filterValues.remove(item.values[0].filterId) + } + onFilterChanged(filterValues) + }, + ) { + Text(text = stringResource(item.values[0].displayName), color = textColor) + } + Spacer(Modifier.width(5.dp)) + OutlinedButton(modifier = Modifier.padding(2.dp), border = BorderStroke(2.dp, if (selectedIndex != 1) textColor else Color.Green), + onClick = { + if (selectedIndex != 1) { + selectedIndex = 1 + filterValues.add(item.values[1].filterId) + filterValues.remove(item.values[0].filterId) + } else { + selectedIndex = -1 + filterValues.remove(item.values[1].filterId) + } + onFilterChanged(filterValues) + }, + ) { + Text(text = stringResource(item.values[1].displayName), color = textColor) + } } } } - return layout } override fun onDestroyView() { Logd(TAG, "onDestroyView") - _binding = null +// _binding = null super.onDestroyView() } @@ -1188,6 +1184,7 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener { enum class FeedFilterGroup(vararg values: ItemProperties) { KEEP_UPDATED(ItemProperties(R.string.keep_updated, FeedFilter.States.keepUpdated.name), ItemProperties(R.string.not_keep_updated, FeedFilter.States.not_keepUpdated.name)), PLAY_SPEED(ItemProperties(R.string.global_speed, FeedFilter.States.global_playSpeed.name), ItemProperties(R.string.custom_speed, FeedFilter.States.custom_playSpeed.name)), + OPINION(ItemProperties(R.string.has_comments, FeedFilter.States.has_comments.name), ItemProperties(R.string.no_comments, FeedFilter.States.no_comments.name)), SKIPS(ItemProperties(R.string.has_skips, FeedFilter.States.has_skips.name), ItemProperties(R.string.no_skips, FeedFilter.States.no_skips.name)), AUTO_DELETE(ItemProperties(R.string.always_auto_delete, FeedFilter.States.always_auto_delete.name), ItemProperties(R.string.never_auto_delete, FeedFilter.States.never_auto_delete.name)), AUTO_DOWNLOAD(ItemProperties(R.string.auto_download, FeedFilter.States.autoDownload.name), ItemProperties(R.string.not_auto_download, FeedFilter.States.not_autoDownload.name)); diff --git a/app/src/main/res/layout/filter_dialog.xml b/app/src/main/res/layout/filter_dialog.xml deleted file mode 100644 index 93e8809e..00000000 --- a/app/src/main/res/layout/filter_dialog.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/filter_dialog_row.xml b/app/src/main/res/layout/filter_dialog_row.xml deleted file mode 100644 index 81185a1d..00000000 --- a/app/src/main/res/layout/filter_dialog_row.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - -