From 2e4c0b37da242761312d02aeb75ba3563bc939ba Mon Sep 17 00:00:00 2001 From: Matt Chowning Date: Thu, 3 Nov 2022 10:45:32 -0400 Subject: [PATCH 1/5] Merge pull request #509 from joaomgcd/tasker_plugin_new_action Tasker plugin new action --- CHANGELOG.md | 3 +- modules/features/taskerplugin/build.gradle | 1 + .../taskerplugin/base/ActivityConfigBase.kt | 22 +++- .../taskerplugin/base/ComposableBase.kt | 34 ++++-- .../taskerplugin/base/ViewModelBase.kt | 35 +++++- .../taskerplugin/base/hilt/HiltEntryPoints.kt | 15 +++ .../ActionHelperControlPlayback.kt | 3 + .../ActionRunnerControlPlayback.kt | 43 +++++++ .../controlplayback/InputControlPlayback.kt | 12 +- .../config/ActivityConfigControlPlayback.kt | 81 ++++++------- .../config/ComposableConfigControlPlayback.kt | 54 --------- .../config/ViewModelConfigControlPlayback.kt | 107 ++++++++---------- .../playplaylist/ActionHelperPlayPlaylist.kt | 6 +- .../config/ActivityConfigPlayPlaylist.kt | 35 ++++-- .../config/ComposableConfigPlayPlaylist.kt | 23 ---- .../config/ViewModelConfigPlayPlaylist.kt | 24 ++-- .../src/main/res/drawable/content_cut.xml | 9 ++ .../src/main/res/drawable/speedometer.xml | 10 ++ .../src/main/res/values/strings.xml | 9 ++ .../pocketcasts/models/db/dao/PlaylistDao.kt | 4 + .../repositories/playback/PlaybackManager.kt | 5 + .../repositories/podcast/PlaylistManager.kt | 2 + .../podcast/PlaylistManagerImpl.kt | 4 + 23 files changed, 311 insertions(+), 230 deletions(-) delete mode 100644 modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/controlplayback/config/ComposableConfigControlPlayback.kt delete mode 100644 modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/playplaylist/config/ComposableConfigPlayPlaylist.kt create mode 100644 modules/features/taskerplugin/src/main/res/drawable/content_cut.xml create mode 100644 modules/features/taskerplugin/src/main/res/drawable/speedometer.xml diff --git a/CHANGELOG.md b/CHANGELOG.md index 5956ec0d758..0f8180cd540 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ 7.27 ----- - + * Added ability to set playback effects in Tasker "Control Playback" action. + ([#415](https://github.com/Automattic/pocket-casts-android/pull/509)). 7.26 ----- diff --git a/modules/features/taskerplugin/build.gradle b/modules/features/taskerplugin/build.gradle index cd0b54db207..af3e6780c8c 100644 --- a/modules/features/taskerplugin/build.gradle +++ b/modules/features/taskerplugin/build.gradle @@ -17,5 +17,6 @@ dependencies { implementation project(':modules:services:model') implementation project(':modules:services:views') implementation project(':modules:services:images') + implementation project(':modules:services:preferences') implementation 'com.joaomgcd:taskerpluginlibrary:0.4.3' } diff --git a/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/base/ActivityConfigBase.kt b/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/base/ActivityConfigBase.kt index 34376ef832c..0e8d0a3cfcd 100644 --- a/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/base/ActivityConfigBase.kt +++ b/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/base/ActivityConfigBase.kt @@ -3,7 +3,7 @@ package au.com.shiftyjelly.pocketcasts.taskerplugin.base import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent -import androidx.compose.runtime.Composable +import androidx.compose.material.Text import au.com.shiftyjelly.pocketcasts.compose.AppThemeWithBackground import au.com.shiftyjelly.pocketcasts.taskerplugin.base.hilt.appTheme @@ -14,10 +14,24 @@ abstract class ActivityConfigBase> : ComponentA viewModel.onCreate({ finish() }, { intent }, { code, data -> setResult(code, data) }) setContent { AppThemeWithBackground(themeType = appTheme.activeTheme) { - Content() + val taskerVariables = viewModel.taskerVariables + val inputs = viewModel.inputFields.map { field -> + TaskerInputFieldState.Content( + field.valueState, + field.labelResId, + field.iconResId, + field.shouldAskForState, + { field.value = it }, + taskerVariables, + field.getPossibleValues() + ) { + Text(field.getValueDescription(it)) + } + } + ComposableTaskerInputFieldList(inputs) { + viewModel.finishForTasker() + } } } } - @Composable - protected abstract fun Content() } diff --git a/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/base/ComposableBase.kt b/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/base/ComposableBase.kt index cc3a81c4304..df81e2d955e 100644 --- a/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/base/ComposableBase.kt +++ b/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/base/ComposableBase.kt @@ -1,5 +1,6 @@ package au.com.shiftyjelly.pocketcasts.taskerplugin.base +import androidx.annotation.DrawableRes import androidx.annotation.StringRes import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row @@ -18,6 +19,7 @@ import androidx.compose.material.MaterialTheme import androidx.compose.material.OutlinedTextField import androidx.compose.material.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -36,14 +38,19 @@ import au.com.shiftyjelly.pocketcasts.compose.AppTheme import au.com.shiftyjelly.pocketcasts.compose.theme import au.com.shiftyjelly.pocketcasts.localization.R import au.com.shiftyjelly.pocketcasts.ui.theme.Theme +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow class TaskerInputFieldState(val content: Content) { data class Content constructor( - val value: String?, + val value: StateFlow, @StringRes val labelResId: Int, + @DrawableRes val iconResId: Int, + val shouldShow: StateFlow, val onTextChange: (String) -> Unit, val taskerVariables: List, - val possibleItems: List? = null, + val possibleItems: Flow>? = null, val itemToString: (T?) -> String = { it?.toString() ?: "" }, val itemContent: @Composable (T) -> Unit = { Text(text = itemToString(it)) } ) @@ -68,19 +75,27 @@ fun ComposableTaskerInputField(content: TaskerInputFieldState.Content) { Box { Row { - val possibleItems = content.possibleItems + val possibleItems = content.possibleItems?.collectAsState(initial = null)?.value val hasSuggestedItems = !possibleItems.isNullOrEmpty() val hasTaskerVariables = content.taskerVariables.isNotEmpty() OutlinedTextField( modifier = Modifier.weight(1f), - value = content.value ?: "", + value = content.value.collectAsState().value ?: "", label = { Text(text = stringResource(id = content.labelResId)) }, keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = { finishSelecting() }), onValueChange = { content.onTextChange(it) }, + leadingIcon = { + Icon( + painter = painterResource(content.iconResId), + contentDescription = stringResource(content.labelResId), + tint = MaterialTheme.theme.colors.primaryIcon01, + modifier = Modifier.padding(end = 16.dp, start = 16.dp) + ) + }, trailingIcon = if (!hasSuggestedItems && !hasTaskerVariables) null else { { Row { @@ -151,9 +166,12 @@ private fun ComposableTaskerInputFieldPreview() { AppTheme(Theme.ThemeType.CLASSIC_LIGHT) { ComposableTaskerInputField( TaskerInputFieldState.Content( - "some value", R.string.archive, {}, + MutableStateFlow("some value"), R.string.archive, + au.com.shiftyjelly.pocketcasts.images.R.drawable.widget_play, + MutableStateFlow(true), + {}, listOf("%test"), - listOf("Hi", "Hello") + MutableStateFlow(listOf("Hi", "Hello")) ) ) } @@ -172,7 +190,9 @@ fun ComposableTaskerInputFieldList( LazyColumn { fieldContents.forEach { content -> item { - ComposableTaskerInputField(content) + if (content.shouldShow.collectAsState().value) { + ComposableTaskerInputField(content) + } } } } diff --git a/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/base/ViewModelBase.kt b/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/base/ViewModelBase.kt index 344bd6a7d0b..a980a6793e1 100644 --- a/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/base/ViewModelBase.kt +++ b/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/base/ViewModelBase.kt @@ -2,12 +2,15 @@ package au.com.shiftyjelly.pocketcasts.taskerplugin.base import android.app.Application import android.content.Intent +import androidx.annotation.DrawableRes +import androidx.annotation.StringRes import androidx.lifecycle.AndroidViewModel -import au.com.shiftyjelly.pocketcasts.taskerplugin.controlplayback.InputControlPlayback import com.joaomgcd.taskerpluginlibrary.action.TaskerPluginRunnerActionNoOutput import com.joaomgcd.taskerpluginlibrary.config.TaskerPluginConfig import com.joaomgcd.taskerpluginlibrary.config.TaskerPluginConfigHelperNoOutput import com.joaomgcd.taskerpluginlibrary.input.TaskerInput +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow abstract class ViewModelBase>>(application: Application) : AndroidViewModel(application), TaskerPluginConfig { override val context get() = getApplication() @@ -15,6 +18,35 @@ abstract class ViewModelBase constructor(@StringRes val labelResId: Int, @DrawableRes val iconResId: Int, val valueGetter: TInput.() -> String?, val valueSetter: TInput.(String?) -> Unit) { + protected abstract val askFor: Boolean + val shouldAskForState by lazy { MutableStateFlow(askFor) } + fun updateAskForState() { + shouldAskForState.tryEmit(askFor) + } + + val valueState by lazy { + MutableStateFlow(input?.let(valueGetter)) + } + var value: String? = null + set(value) { + input?.let { valueSetter(it, value) } + valueState.tryEmit(value) + } + + open fun getPossibleValues(): Flow>? = null + + @Suppress("UNCHECKED_CAST") + fun getValueDescription(possibleValue: Any?): String = tryOrNull { getValueDescriptionSpecific(possibleValue as? T?) } ?: "" + protected open fun getValueDescriptionSpecific(possibleValue: T?) = possibleValue?.toString() + } + abstract val inputFields: List> + private var taskerInput get() = TaskerInput(input ?: taskerHelper.inputClass.newInstance()) set(value) { @@ -24,7 +56,6 @@ abstract class ViewModelBase get() = taskerInput - fun getDescription(command: InputControlPlayback.PlaybackCommand) = command.getDescription(context) override fun assignFromInput(input: TaskerInput) { taskerInput = input } diff --git a/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/base/hilt/HiltEntryPoints.kt b/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/base/hilt/HiltEntryPoints.kt index cee6ba027c7..73aeb50541a 100644 --- a/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/base/hilt/HiltEntryPoints.kt +++ b/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/base/hilt/HiltEntryPoints.kt @@ -1,9 +1,11 @@ package au.com.shiftyjelly.pocketcasts.taskerplugin.base.hilt import android.content.Context +import au.com.shiftyjelly.pocketcasts.preferences.Settings import au.com.shiftyjelly.pocketcasts.repositories.playback.PlaybackManager import au.com.shiftyjelly.pocketcasts.repositories.podcast.EpisodeManager import au.com.shiftyjelly.pocketcasts.repositories.podcast.PlaylistManager +import au.com.shiftyjelly.pocketcasts.repositories.podcast.PodcastManager import au.com.shiftyjelly.pocketcasts.ui.theme.Theme import dagger.hilt.EntryPoint import dagger.hilt.InstallIn @@ -33,7 +35,20 @@ interface EpisodeManagerEntryPoint { fun getEpisodeManager(): EpisodeManager } +@InstallIn(SingletonComponent::class) +@EntryPoint +interface SettingsEntryPoint { + fun getSettings(): Settings +} +@InstallIn(SingletonComponent::class) +@EntryPoint +interface PodcastManagerEntryPoint { + fun getPodcastManager(): PodcastManager +} + val Context.appTheme get() = EntryPointAccessors.fromApplication(applicationContext, ThemeEntryPoint::class.java).getTheme() val Context.playbackManager get() = EntryPointAccessors.fromApplication(applicationContext, PlaybackManagerEntryPoint::class.java).getPlaybackManager() val Context.playlistManager get() = EntryPointAccessors.fromApplication(applicationContext, PlaylistManagerEntryPoint::class.java).getPlaylistManager() val Context.episodeManager get() = EntryPointAccessors.fromApplication(applicationContext, EpisodeManagerEntryPoint::class.java).getEpisodeManager() +val Context.podcastManager get() = EntryPointAccessors.fromApplication(applicationContext, PodcastManagerEntryPoint::class.java).getPodcastManager() +val Context.settings get() = EntryPointAccessors.fromApplication(applicationContext, SettingsEntryPoint::class.java).getSettings() diff --git a/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/controlplayback/ActionHelperControlPlayback.kt b/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/controlplayback/ActionHelperControlPlayback.kt index 7c14207a67f..a112c528bb2 100644 --- a/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/controlplayback/ActionHelperControlPlayback.kt +++ b/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/controlplayback/ActionHelperControlPlayback.kt @@ -22,6 +22,9 @@ class ActionHelperControlPlayback(config: TaskerPluginConfig addField(R.string.time_to_skip_to_seconds, inputControlPlayback.skipToSeconds) InputControlPlayback.PlaybackCommand.SkipForward -> addField(R.string.skip_forward, inputControlPlayback.skipSeconds) InputControlPlayback.PlaybackCommand.SkipBack -> addField(R.string.skip_back, inputControlPlayback.skipSeconds) + InputControlPlayback.PlaybackCommand.SetPlaybackSpeed -> addField(R.string.set_playback_speed, inputControlPlayback.playbackSpeed) + InputControlPlayback.PlaybackCommand.SetTrimSilenceMode -> addField(R.string.set_trim_silence_mode, inputControlPlayback.trimSilenceMode) + InputControlPlayback.PlaybackCommand.SetVolumeBoost -> addField(R.string.set_volume_boost, inputControlPlayback.volumeBoostEnabled) InputControlPlayback.PlaybackCommand.PlayNextInQueue, InputControlPlayback.PlaybackCommand.SkipToNextChapter, InputControlPlayback.PlaybackCommand.SkipToPreviousChapter -> blurbBuilder.append(commandEnum.getDescription(context)) // these don't have extra arguments so just write the command name diff --git a/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/controlplayback/ActionRunnerControlPlayback.kt b/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/controlplayback/ActionRunnerControlPlayback.kt index aa63f186b20..68b25effe42 100644 --- a/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/controlplayback/ActionRunnerControlPlayback.kt +++ b/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/controlplayback/ActionRunnerControlPlayback.kt @@ -2,20 +2,28 @@ package au.com.shiftyjelly.pocketcasts.taskerplugin.controlplayback import android.content.Context import au.com.shiftyjelly.pocketcasts.localization.R +import au.com.shiftyjelly.pocketcasts.models.to.PlaybackEffects +import au.com.shiftyjelly.pocketcasts.repositories.extensions.saveToGlobalSettings import au.com.shiftyjelly.pocketcasts.repositories.playback.PlaybackManager import au.com.shiftyjelly.pocketcasts.taskerplugin.base.hilt.playbackManager +import au.com.shiftyjelly.pocketcasts.taskerplugin.base.hilt.podcastManager +import au.com.shiftyjelly.pocketcasts.taskerplugin.base.hilt.settings import au.com.shiftyjelly.pocketcasts.taskerplugin.base.nullIfEmpty import com.joaomgcd.taskerpluginlibrary.action.TaskerPluginRunnerActionNoOutput import com.joaomgcd.taskerpluginlibrary.input.TaskerInput import com.joaomgcd.taskerpluginlibrary.runner.TaskerPluginResult import com.joaomgcd.taskerpluginlibrary.runner.TaskerPluginResultError import com.joaomgcd.taskerpluginlibrary.runner.TaskerPluginResultSucess +import kotlin.math.round private const val ERROR_NO_COMMAND_PROVIDED = 1 private const val ERROR_INVALIUD_COMMAND_PROVIDED = 2 private const val ERROR_INVALID_CHAPTER_TO_SKIP_TO_PROVIDED = 3 private const val ERROR_INVALID_TIME_TO_SKIP_TO_PROVIDED = 4 private const val ERROR_INVALID_TIME_TO_SKIP_PROVIDED = 5 +private const val ERROR_INVALID_PLAYBACK_SPEED_PROVIDED = 6 +private const val ERROR_INVALID_TRIM_SILENCE_MODE_PROVIDED = 7 +private const val ERROR_INVALID_VOLUME_BOOST_VALUE_PROVIDED = 8 class ActionRunnerControlPlayback : TaskerPluginRunnerActionNoOutput() { @@ -44,8 +52,43 @@ class ActionRunnerControlPlayback : TaskerPluginRunnerActionNoOutput playbackManager.playNextInQueue(PlaybackManager.PlaybackSource.TASKER) + InputControlPlayback.PlaybackCommand.SetPlaybackSpeed -> { + val speed = input.regular.playbackSpeed?.toDoubleOrNull() ?: return TaskerPluginResultError(ERROR_INVALID_PLAYBACK_SPEED_PROVIDED, context.getString(R.string.playback_speed_not_valid, input.regular.playbackSpeed)) + + val clippedToRangeSpeed = speed.coerceIn(0.5, 3.0) + val roundedSpeed = round(clippedToRangeSpeed * 10.0) / 10.0 + context.updateEffects { playbackSpeed = roundedSpeed } + } + InputControlPlayback.PlaybackCommand.SetTrimSilenceMode -> { + val trimSilenceMode = input.regular.trimSilenceModeEnum ?: return TaskerPluginResultError(ERROR_INVALID_TRIM_SILENCE_MODE_PROVIDED, context.getString(R.string.trim_silence_mode_not_valid, input.regular.trimSilenceMode)) + + context.updateEffects { trimMode = trimSilenceMode } + } + InputControlPlayback.PlaybackCommand.SetVolumeBoost -> { + val volumeBoostEnabled = input.regular.volumeBoostEnabled?.toBooleanStrictOrNull() ?: return TaskerPluginResultError(ERROR_INVALID_VOLUME_BOOST_VALUE_PROVIDED, context.getString(R.string.volume_boost_enabled_not_valid, input.regular.volumeBoostEnabled)) + + context.updateEffects { isVolumeBoosted = volumeBoostEnabled } + } } return TaskerPluginResultSucess() } + + private fun Context.updateEffects(updater: PlaybackEffects.() -> Unit) { + val currentPodcast = playbackManager.getCurrentPodcast() ?: return + + val overrideGlobalEffects = currentPodcast.overrideGlobalEffects + val playbackEffects: PlaybackEffects = if (overrideGlobalEffects) { + currentPodcast.playbackEffects + } else { + settings.getGlobalPlaybackEffects() + } + playbackEffects.updater() + if (overrideGlobalEffects) { + podcastManager.updateEffects(currentPodcast, playbackEffects) + } else { + playbackEffects.saveToGlobalSettings(settings) + } + playbackManager.updatePlayerEffects(playbackEffects) + } } diff --git a/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/controlplayback/InputControlPlayback.kt b/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/controlplayback/InputControlPlayback.kt index dd25c5edfa9..9032b1b74f4 100644 --- a/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/controlplayback/InputControlPlayback.kt +++ b/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/controlplayback/InputControlPlayback.kt @@ -3,6 +3,7 @@ package au.com.shiftyjelly.pocketcasts.taskerplugin.controlplayback import android.content.Context import androidx.annotation.StringRes import au.com.shiftyjelly.pocketcasts.localization.R +import au.com.shiftyjelly.pocketcasts.models.type.TrimMode import au.com.shiftyjelly.pocketcasts.taskerplugin.base.tryOrNull import com.joaomgcd.taskerpluginlibrary.input.TaskerInputField import com.joaomgcd.taskerpluginlibrary.input.TaskerInputRoot @@ -12,10 +13,14 @@ class InputControlPlayback @JvmOverloads constructor( @field:TaskerInputField("command") var command: String? = null, @field:TaskerInputField("skipToChapter") var chapterToSkipTo: String? = null, @field:TaskerInputField("skipToSeconds") var skipToSeconds: String? = null, - @field:TaskerInputField("skipSeconds") var skipSeconds: String? = null + @field:TaskerInputField("skipSeconds") var skipSeconds: String? = null, + @field:TaskerInputField("playbackSpeed") var playbackSpeed: String? = null, + @field:TaskerInputField("trimSilenceMode") var trimSilenceMode: String? = null, + @field:TaskerInputField("volumeBoostEnabled") var volumeBoostEnabled: String? = null ) { val commandEnum get() = tryOrNull { command?.let { PlaybackCommand.valueOf(it) } } + val trimSilenceModeEnum get() = tryOrNull { trimSilenceMode?.let { TrimMode.valueOf(it) } } enum class PlaybackCommand(@StringRes val descriptionResId: Int) { PlayNextInQueue(R.string.play_next_in_queue), @@ -24,7 +29,10 @@ class InputControlPlayback @JvmOverloads constructor( SkipToNextChapter(R.string.skip_to_next_chapter), SkipToPreviousChapter(R.string.skip_to_previous_chapter), SkipToChapter(R.string.skip_to_chapter), - SkipToTime(R.string.skip_to_time); + SkipToTime(R.string.skip_to_time), + SetPlaybackSpeed(R.string.set_playback_speed), + SetTrimSilenceMode(R.string.set_trim_silence_mode), + SetVolumeBoost(R.string.set_volume_boost); fun getDescription(context: Context) = context.getString(descriptionResId) } diff --git a/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/controlplayback/config/ActivityConfigControlPlayback.kt b/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/controlplayback/config/ActivityConfigControlPlayback.kt index 5ac62e7af07..03ba6a79c4c 100644 --- a/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/controlplayback/config/ActivityConfigControlPlayback.kt +++ b/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/controlplayback/config/ActivityConfigControlPlayback.kt @@ -1,64 +1,47 @@ package au.com.shiftyjelly.pocketcasts.taskerplugin.controlplayback.config import androidx.activity.viewModels -import androidx.compose.material.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState +import androidx.compose.ui.tooling.preview.Preview +import au.com.shiftyjelly.pocketcasts.compose.AppTheme +import au.com.shiftyjelly.pocketcasts.localization.R import au.com.shiftyjelly.pocketcasts.taskerplugin.base.ActivityConfigBase +import au.com.shiftyjelly.pocketcasts.taskerplugin.base.ComposableTaskerInputFieldList import au.com.shiftyjelly.pocketcasts.taskerplugin.base.TaskerInputFieldState +import au.com.shiftyjelly.pocketcasts.taskerplugin.controlplayback.InputControlPlayback +import au.com.shiftyjelly.pocketcasts.ui.theme.Theme import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.flow.MutableStateFlow @AndroidEntryPoint class ActivityConfigControlPlayback : ActivityConfigBase() { override val viewModel: ViewModelConfigControlPlayback by viewModels() +} - @Composable - override fun Content() { - val taskerVariables = viewModel.taskerVariables - val commandContent = TaskerInputFieldState.Content( - viewModel.commandState.collectAsState().value, - au.com.shiftyjelly.pocketcasts.localization.R.string.playback_command, - { viewModel.command = it }, - taskerVariables, - viewModel.availableCommands.toList() - ) { - Text(viewModel.getDescription(it)) - } - val chapterToSkipToContent = if (viewModel.shouldAskForChapter.collectAsState().value) { - TaskerInputFieldState.Content( - viewModel.chapterToSkipTo.collectAsState().value, - au.com.shiftyjelly.pocketcasts.localization.R.string.chapter_to_skip_to, - { viewModel.setChapterToSkipTo(it) }, - taskerVariables - ) - } else { - null - } - val timeToSkipToContent = if (viewModel.showAskForTimeToSkipTo.collectAsState().value) { - TaskerInputFieldState.Content( - viewModel.timeToSkipTo.collectAsState().value, - au.com.shiftyjelly.pocketcasts.localization.R.string.time_to_skip_to_seconds, - { viewModel.setTimeToSkipTo(it) }, - taskerVariables - ) - } else { - null - } - val timeToSkipContent = if (viewModel.showAskForTimeToSkip.collectAsState().value) { - TaskerInputFieldState.Content( - viewModel.timeToSkip.collectAsState().value, - au.com.shiftyjelly.pocketcasts.localization.R.string.time_to_skip_seconds, - { viewModel.setTimeToSkip(it) }, - taskerVariables +@Preview(showBackground = true) +@Composable +private fun ComposableConfigControlPlaybackPreview() { + AppTheme(Theme.ThemeType.CLASSIC_LIGHT) { + ComposableTaskerInputFieldList( + listOf( + TaskerInputFieldState.Content( + MutableStateFlow(InputControlPlayback.PlaybackCommand.SkipToTime.name), + R.string.playback_command, + au.com.shiftyjelly.pocketcasts.images.R.drawable.filter_play, + MutableStateFlow(true), + {}, + listOf("%test"), + MutableStateFlow(InputControlPlayback.PlaybackCommand.values().toList()) + ), + TaskerInputFieldState.Content( + MutableStateFlow("60"), + R.string.time_to_skip_to_seconds, + au.com.shiftyjelly.pocketcasts.images.R.drawable.filter_time, + MutableStateFlow(true), + {}, + listOf("%test") + ) ) - } else { - null - } - ComposableConfigControlPlayback( - commandContent, - chapterToSkipToContent, - timeToSkipToContent, - timeToSkipContent - ) { viewModel.finishForTasker() } + ) {} } } diff --git a/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/controlplayback/config/ComposableConfigControlPlayback.kt b/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/controlplayback/config/ComposableConfigControlPlayback.kt deleted file mode 100644 index fff0342569e..00000000000 --- a/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/controlplayback/config/ComposableConfigControlPlayback.kt +++ /dev/null @@ -1,54 +0,0 @@ -package au.com.shiftyjelly.pocketcasts.taskerplugin.controlplayback.config - -import androidx.compose.runtime.Composable -import androidx.compose.ui.tooling.preview.Preview -import au.com.shiftyjelly.pocketcasts.compose.AppTheme -import au.com.shiftyjelly.pocketcasts.taskerplugin.base.ComposableTaskerInputFieldList -import au.com.shiftyjelly.pocketcasts.taskerplugin.base.TaskerInputFieldState -import au.com.shiftyjelly.pocketcasts.taskerplugin.controlplayback.InputControlPlayback -import au.com.shiftyjelly.pocketcasts.ui.theme.Theme - -@Composable -fun ComposableConfigControlPlayback( - inputCommandContent: TaskerInputFieldState.Content, - inputChapterToSkipToContent: TaskerInputFieldState.Content?, - inputTimeToSkipToContent: TaskerInputFieldState.Content?, - inputTimeToSkipContent: TaskerInputFieldState.Content?, - onFinish: () -> Unit -) { - val inputList = mutableListOf>(inputCommandContent) - inputChapterToSkipToContent?.let { inputList.add(it) } - inputTimeToSkipToContent?.let { inputList.add(it) } - inputTimeToSkipContent?.let { inputList.add(it) } - ComposableTaskerInputFieldList(inputList, onFinish) -} - -@Preview(showBackground = true) -@Composable -private fun ComposableConfigControlPlaybackPreview() { - AppTheme(Theme.ThemeType.CLASSIC_LIGHT) { - ComposableConfigControlPlayback( - TaskerInputFieldState.Content( - InputControlPlayback.PlaybackCommand.SkipToTime.name, - au.com.shiftyjelly.pocketcasts.localization.R.string.playback_command, - {}, listOf("%test"), - InputControlPlayback.PlaybackCommand.values().toList() - ), - TaskerInputFieldState.Content( - "1", - au.com.shiftyjelly.pocketcasts.localization.R.string.chapter_to_skip_to, - {}, listOf("%test") - ), - TaskerInputFieldState.Content( - "60", - au.com.shiftyjelly.pocketcasts.localization.R.string.time_to_skip_to_seconds, - {}, listOf("%test") - ), - TaskerInputFieldState.Content( - "60", - au.com.shiftyjelly.pocketcasts.localization.R.string.time_to_skip_seconds, - {}, listOf("%test") - ) - ) {} - } -} diff --git a/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/controlplayback/config/ViewModelConfigControlPlayback.kt b/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/controlplayback/config/ViewModelConfigControlPlayback.kt index 9d408754467..960ff58d3a0 100644 --- a/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/controlplayback/config/ViewModelConfigControlPlayback.kt +++ b/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/controlplayback/config/ViewModelConfigControlPlayback.kt @@ -1,6 +1,10 @@ package au.com.shiftyjelly.pocketcasts.taskerplugin.controlplayback.config import android.app.Application +import androidx.annotation.DrawableRes +import androidx.annotation.StringRes +import au.com.shiftyjelly.pocketcasts.models.type.TrimMode +import au.com.shiftyjelly.pocketcasts.taskerplugin.R import au.com.shiftyjelly.pocketcasts.taskerplugin.base.ViewModelBase import au.com.shiftyjelly.pocketcasts.taskerplugin.controlplayback.ActionHelperControlPlayback import au.com.shiftyjelly.pocketcasts.taskerplugin.controlplayback.InputControlPlayback @@ -8,6 +12,8 @@ import com.joaomgcd.taskerpluginlibrary.config.TaskerPluginConfig import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import javax.inject.Inject +import au.com.shiftyjelly.pocketcasts.images.R as IR +import au.com.shiftyjelly.pocketcasts.localization.R as LR @HiltViewModel class ViewModelConfigControlPlayback @Inject constructor( @@ -16,76 +22,53 @@ class ViewModelConfigControlPlayback @Inject constructor( override val helperClass get() = ActionHelperControlPlayback::class.java /** - * A field that only appears depending on the type of the playback command. For example, the field "Time to Skip To" will only appear if the command is "Skip To Time" - * @param showForCommands the types of playback commands that makes this field appear + * A field that only appears depending on the type of the playback command. For example, the field "Time to Skip To" will only appear if the command is "Skip To Time". A field can also always appear if it doesn't depend on a command type + * @param showForCommands the types of playback commands that makes this field appear. If empty, will always show field * @param valueGetter how to get the value of this input field from the Tasker input * @param valueSetter how to set a newly assigned value of this field to the Tasker input */ - inner class OptionalField constructor(val showForCommands: List, valueGetter: (InputControlPlayback?) -> String?, val valueSetter: (String?) -> Unit) { - constructor(showForCommand: InputControlPlayback.PlaybackCommand, valueGetter: (InputControlPlayback?) -> String?, valueSetter: (String?) -> Unit) : this(listOf(showForCommand), valueGetter, valueSetter) + private open inner class InputField constructor(@StringRes labelResId: Int, @DrawableRes iconResId: Int, private val showForCommands: List, valueGetter: InputControlPlayback.() -> String?, valueSetter: InputControlPlayback.(String?) -> Unit) : InputFieldBase(labelResId, iconResId, valueGetter, valueSetter) { + constructor(@StringRes labelResId: Int, @DrawableRes iconResId: Int, showForCommand: InputControlPlayback.PlaybackCommand, valueGetter: InputControlPlayback.() -> String?, valueSetter: InputControlPlayback.(String?) -> Unit) : this(labelResId, iconResId, listOf(showForCommand), valueGetter, valueSetter) + constructor(@StringRes labelResId: Int, @DrawableRes iconResId: Int, valueGetter: InputControlPlayback.() -> String?, valueSetter: InputControlPlayback.(String?) -> Unit) : this(labelResId, iconResId, listOf(), valueGetter, valueSetter) - private val askFor get() = showForCommands.contains(input?.commandEnum) - val shouldAskForState by lazy { MutableStateFlow(askFor) } - fun updateAskForState() { - shouldAskForState.tryEmit(askFor) - } - - val valueState by lazy { MutableStateFlow(valueGetter(input)) } - var value: String? = null - set(value) { - valueSetter(value) - valueState.tryEmit(value) - } + override val askFor get() = showForCommands.isEmpty() || showForCommands.contains(input?.commandEnum) } - /** - * When adding new optional fields here make sure to add them to the [optionalFields] list below so that everything is correctly updated - */ - private val optionalFieldChapterToSkipTo by lazy { OptionalField(InputControlPlayback.PlaybackCommand.SkipToChapter, { input?.chapterToSkipTo }, { input?.chapterToSkipTo = it }) } - private val optionalFieldTimeToSkipTo by lazy { OptionalField(InputControlPlayback.PlaybackCommand.SkipToTime, { input?.skipToSeconds }, { input?.skipToSeconds = it }) } - private val optionalFieldTimeToSkip by lazy { OptionalField(listOf(InputControlPlayback.PlaybackCommand.SkipForward, InputControlPlayback.PlaybackCommand.SkipBack), { input?.skipSeconds }, { input?.skipSeconds = it }) } - private val optionalFields = listOf( - optionalFieldChapterToSkipTo, - optionalFieldTimeToSkipTo, - optionalFieldTimeToSkip - ) - - val commandState by lazy { - MutableStateFlow( - input?.command - ) + private val inputFieldCommand = object : InputField(LR.string.playback_command, IR.drawable.filter_play, { command }, { setCommand(it) }) { + override fun getPossibleValues() = MutableStateFlow(InputControlPlayback.PlaybackCommand.values().toList()) + override fun getValueDescriptionSpecific(possibleValue: InputControlPlayback.PlaybackCommand?) = possibleValue?.getDescription(context) } - var command: String? - get() = input?.command - set(value) { - input?.command = value - commandState.tryEmit(value) - optionalFields.forEach { it.updateAskForState() } - } + override val inputFields: List> = listOf( + inputFieldCommand, + InputField(LR.string.chapter_to_skip_to, IR.drawable.filter_bullet, InputControlPlayback.PlaybackCommand.SkipToChapter, { chapterToSkipTo }, { chapterToSkipTo = it }), + InputField(LR.string.time_to_skip_to_seconds, IR.drawable.filter_time, InputControlPlayback.PlaybackCommand.SkipToTime, { skipToSeconds }, { skipToSeconds = it }), + InputField(LR.string.time_to_skip_seconds, IR.drawable.filter_time, listOf(InputControlPlayback.PlaybackCommand.SkipForward, InputControlPlayback.PlaybackCommand.SkipBack), { skipSeconds }, { skipSeconds = it }), + object : InputField(LR.string.playback_speed_between_values, R.drawable.speedometer, InputControlPlayback.PlaybackCommand.SetPlaybackSpeed, { playbackSpeed }, { playbackSpeed = it }) { + override fun getPossibleValues() = MutableStateFlow((5..30).map { it / 10.0 }) + }, + object : InputField(LR.string.trim_silence_mode, R.drawable.content_cut, InputControlPlayback.PlaybackCommand.SetTrimSilenceMode, { trimSilenceMode }, { trimSilenceMode = it }) { + override fun getPossibleValues() = MutableStateFlow(TrimMode.values().toList()) + override fun getValueDescriptionSpecific(possibleValue: TrimMode?): String? { + if (possibleValue == null) return null - val availableCommands get() = InputControlPlayback.PlaybackCommand.values() - - /*Chapter To skip to*/ - val shouldAskForChapter get() = optionalFieldChapterToSkipTo.shouldAskForState - val chapterToSkipTo get() = optionalFieldChapterToSkipTo.valueState - fun setChapterToSkipTo(value: String) { - optionalFieldChapterToSkipTo.value = value - } - /*End chapter To skip to*/ - - /*Time To skip to*/ - val showAskForTimeToSkipTo get() = optionalFieldTimeToSkipTo.shouldAskForState - val timeToSkipTo get() = optionalFieldTimeToSkipTo.valueState - fun setTimeToSkipTo(value: String) { - optionalFieldTimeToSkipTo.value = value - } - /*End time To skip to*/ + return context.getString( + when (possibleValue) { + TrimMode.OFF -> LR.string.off + TrimMode.LOW -> LR.string.player_effects_trim_mild + TrimMode.MEDIUM -> LR.string.player_effects_trim_medium + TrimMode.HIGH -> LR.string.player_effects_trim_mad_max + } + ) + } + }, + object : InputField(LR.string.set_volume_boost, IR.drawable.filter_volume, InputControlPlayback.PlaybackCommand.SetVolumeBoost, { volumeBoostEnabled }, { volumeBoostEnabled = it }) { + override fun getPossibleValues() = MutableStateFlow(listOf(true, false)) + } + ) - /*Time To skip */ - val showAskForTimeToSkip get() = optionalFieldTimeToSkip.shouldAskForState - val timeToSkip get() = optionalFieldTimeToSkip.valueState - fun setTimeToSkip(value: String) { - optionalFieldTimeToSkip.value = value + fun setCommand(value: String?) { + input?.command = value + inputFieldCommand.valueState.tryEmit(value) + inputFields.forEach { it.updateAskForState() } } - /*End time To skip to*/ } diff --git a/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/playplaylist/ActionHelperPlayPlaylist.kt b/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/playplaylist/ActionHelperPlayPlaylist.kt index 8138adadd09..02d74e1ac15 100644 --- a/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/playplaylist/ActionHelperPlayPlaylist.kt +++ b/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/playplaylist/ActionHelperPlayPlaylist.kt @@ -10,8 +10,6 @@ class ActionHelperPlayPlaylist(config: TaskerPluginConfig) : blurbBuilder.append("${context.getString(au.com.shiftyjelly.pocketcasts.localization.R.string.filters_filter_name)}: ${input.regular.title}") } - override val addDefaultStringBlurb: Boolean - get() = false - override val inputClass: Class - get() = InputPlayPlaylist::class.java + override val addDefaultStringBlurb get() = false + override val inputClass get() = InputPlayPlaylist::class.java } diff --git a/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/playplaylist/config/ActivityConfigPlayPlaylist.kt b/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/playplaylist/config/ActivityConfigPlayPlaylist.kt index 2d080596f86..540f6ef051b 100644 --- a/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/playplaylist/config/ActivityConfigPlayPlaylist.kt +++ b/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/playplaylist/config/ActivityConfigPlayPlaylist.kt @@ -2,26 +2,37 @@ package au.com.shiftyjelly.pocketcasts.taskerplugin.playplaylist.config import androidx.activity.viewModels import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.rxjava2.subscribeAsState +import androidx.compose.ui.tooling.preview.Preview +import au.com.shiftyjelly.pocketcasts.compose.AppTheme +import au.com.shiftyjelly.pocketcasts.localization.R import au.com.shiftyjelly.pocketcasts.taskerplugin.base.ActivityConfigBase +import au.com.shiftyjelly.pocketcasts.taskerplugin.base.ComposableTaskerInputFieldList import au.com.shiftyjelly.pocketcasts.taskerplugin.base.TaskerInputFieldState +import au.com.shiftyjelly.pocketcasts.ui.theme.Theme import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.flow.MutableStateFlow @AndroidEntryPoint class ActivityConfigPlayPlaylist : ActivityConfigBase() { override val viewModel: ViewModelConfigPlayPlaylist by viewModels() +} - @Composable - override fun Content() { - ComposableConfigPlayPlaylist( - TaskerInputFieldState.Content( - viewModel.titleState.collectAsState().value, - au.com.shiftyjelly.pocketcasts.localization.R.string.filters_filter_name, - { viewModel.title = it }, - viewModel.taskerVariables, - viewModel.playlists.subscribeAsState(listOf()).value.map { it.title } +@Preview(showBackground = true) +@Composable +private fun ComposableConfigPlayPlaylistPreview() { + AppTheme(Theme.ThemeType.CLASSIC_LIGHT) { + ComposableTaskerInputFieldList( + listOf( + TaskerInputFieldState.Content( + MutableStateFlow("New Release"), + R.string.filters_filter_name, + au.com.shiftyjelly.pocketcasts.images.R.drawable.filter_bullet, + MutableStateFlow(true), + {}, + listOf("%test"), + MutableStateFlow(listOf("New Releases", "Up Next")) + ) ) - ) { viewModel.finishForTasker() } + ) {} } } diff --git a/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/playplaylist/config/ComposableConfigPlayPlaylist.kt b/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/playplaylist/config/ComposableConfigPlayPlaylist.kt deleted file mode 100644 index e5550d574b7..00000000000 --- a/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/playplaylist/config/ComposableConfigPlayPlaylist.kt +++ /dev/null @@ -1,23 +0,0 @@ -package au.com.shiftyjelly.pocketcasts.taskerplugin.playplaylist.config - -import androidx.compose.runtime.Composable -import androidx.compose.ui.tooling.preview.Preview -import au.com.shiftyjelly.pocketcasts.compose.AppTheme -import au.com.shiftyjelly.pocketcasts.taskerplugin.base.ComposableTaskerInputFieldList -import au.com.shiftyjelly.pocketcasts.taskerplugin.base.TaskerInputFieldState -import au.com.shiftyjelly.pocketcasts.ui.theme.Theme - -@Composable -fun ComposableConfigPlayPlaylist(content: TaskerInputFieldState.Content, onFinish: () -> Unit) { - ComposableTaskerInputFieldList(listOf(content), onFinish) -} - -@Preview(showBackground = true) -@Composable -private fun ComposableConfigPlayPlaylistPreview() { - AppTheme(Theme.ThemeType.CLASSIC_LIGHT) { - ComposableConfigPlayPlaylist( - TaskerInputFieldState.Content("New Release", au.com.shiftyjelly.pocketcasts.localization.R.string.filters_filter_name, {}, listOf("%test"), listOf("New Releases", "Up Next")), {} - ) - } -} diff --git a/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/playplaylist/config/ViewModelConfigPlayPlaylist.kt b/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/playplaylist/config/ViewModelConfigPlayPlaylist.kt index 4449d028d3b..c7ca82110eb 100644 --- a/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/playplaylist/config/ViewModelConfigPlayPlaylist.kt +++ b/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/playplaylist/config/ViewModelConfigPlayPlaylist.kt @@ -1,29 +1,33 @@ package au.com.shiftyjelly.pocketcasts.taskerplugin.playplaylist.config import android.app.Application +import androidx.annotation.DrawableRes +import androidx.annotation.StringRes +import au.com.shiftyjelly.pocketcasts.localization.R import au.com.shiftyjelly.pocketcasts.taskerplugin.base.ViewModelBase import au.com.shiftyjelly.pocketcasts.taskerplugin.base.hilt.playlistManager import au.com.shiftyjelly.pocketcasts.taskerplugin.playplaylist.ActionHelperPlayPlaylist import au.com.shiftyjelly.pocketcasts.taskerplugin.playplaylist.InputPlayPlaylist import com.joaomgcd.taskerpluginlibrary.config.TaskerPluginConfig import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map import javax.inject.Inject @HiltViewModel class ViewModelConfigPlayPlaylist @Inject constructor( application: Application ) : ViewModelBase(application), TaskerPluginConfig { + override val helperClass get() = ActionHelperPlayPlaylist::class.java - val titleState by lazy { MutableStateFlow(input?.title) } - - var title: String? = null - set(value) { - input?.title = value - titleState.tryEmit(value) + private inner class InputField constructor(@StringRes labelResId: Int, @DrawableRes iconResId: Int, valueGetter: InputPlayPlaylist.() -> String?, valueSetter: InputPlayPlaylist.(String?) -> Unit) : InputFieldBase(labelResId, iconResId, valueGetter, valueSetter) { + override val askFor get() = true + override fun getPossibleValues(): Flow>? { + return context.playlistManager.findAllFlow().map { playlist -> playlist.map { it.title } } } - override val helperClass: Class - get() = ActionHelperPlayPlaylist::class.java + } - val playlists get() = context.playlistManager.observeAll() + override val inputFields: List> = listOf( + InputField(R.string.filters_filter_name, au.com.shiftyjelly.pocketcasts.images.R.drawable.filter_bullet, { title }, { title = it }) + ) } diff --git a/modules/features/taskerplugin/src/main/res/drawable/content_cut.xml b/modules/features/taskerplugin/src/main/res/drawable/content_cut.xml new file mode 100644 index 00000000000..e8f4ef734db --- /dev/null +++ b/modules/features/taskerplugin/src/main/res/drawable/content_cut.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/modules/features/taskerplugin/src/main/res/drawable/speedometer.xml b/modules/features/taskerplugin/src/main/res/drawable/speedometer.xml new file mode 100644 index 00000000000..3c1fe4ad749 --- /dev/null +++ b/modules/features/taskerplugin/src/main/res/drawable/speedometer.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/modules/services/localization/src/main/res/values/strings.xml b/modules/services/localization/src/main/res/values/strings.xml index 62737007138..5d912a20e8b 100644 --- a/modules/services/localization/src/main/res/values/strings.xml +++ b/modules/services/localization/src/main/res/values/strings.xml @@ -1409,6 +1409,15 @@ Time To Skip (Seconds) Time to skip to %1$s not valid Time to skip %1$s not valid + Playback Speed %1$s not valid Pocket Casts Play Filter Pocket Casts Control Playback + Set Playback Speed + Playback Speed (between 0.5 and 3) + Set Trim Silence Mode + Trim Silence Mode + Trim Silence Mode %1$s not valid + Set Volume Boost + Volume Boost Enabled + Volume Boost Enabled value must be \'true\' or \'false\', was %1$s diff --git a/modules/services/model/src/main/java/au/com/shiftyjelly/pocketcasts/models/db/dao/PlaylistDao.kt b/modules/services/model/src/main/java/au/com/shiftyjelly/pocketcasts/models/db/dao/PlaylistDao.kt index 89e3ce8790f..0188f303514 100644 --- a/modules/services/model/src/main/java/au/com/shiftyjelly/pocketcasts/models/db/dao/PlaylistDao.kt +++ b/modules/services/model/src/main/java/au/com/shiftyjelly/pocketcasts/models/db/dao/PlaylistDao.kt @@ -10,6 +10,7 @@ import androidx.room.Update import au.com.shiftyjelly.pocketcasts.models.entity.Playlist import io.reactivex.Flowable import io.reactivex.Maybe +import kotlinx.coroutines.flow.Flow @Dao abstract class PlaylistDao { @@ -23,6 +24,9 @@ abstract class PlaylistDao { @Query("SELECT * FROM filters WHERE manual = 0 AND deleted = 0 AND draft = 0 ORDER BY sortPosition ASC") abstract suspend fun findAllSuspend(): List + @Query("SELECT * FROM filters WHERE manual = 0 AND deleted = 0 AND draft = 0 ORDER BY sortPosition ASC") + abstract fun findAllState(): Flow> + @Query("SELECT * FROM filters WHERE manual = 0 AND deleted = 0 AND draft = 0 ORDER BY sortPosition ASC") abstract fun observeAll(): Flowable> diff --git a/modules/services/repositories/src/main/java/au/com/shiftyjelly/pocketcasts/repositories/playback/PlaybackManager.kt b/modules/services/repositories/src/main/java/au/com/shiftyjelly/pocketcasts/repositories/playback/PlaybackManager.kt index 0c3ae9191f3..5c66aa162ca 100644 --- a/modules/services/repositories/src/main/java/au/com/shiftyjelly/pocketcasts/repositories/playback/PlaybackManager.kt +++ b/modules/services/repositories/src/main/java/au/com/shiftyjelly/pocketcasts/repositories/playback/PlaybackManager.kt @@ -195,6 +195,11 @@ open class PlaybackManager @Inject constructor( return upNextQueue.currentEpisode } + fun getCurrentPodcast(): Podcast? { + val currentEpisode = getCurrentEpisode() as? Episode ?: return null + return currentEpisode.podcastUuid.let { podcastManager.findPodcastByUuid(it) } + } + private suspend fun autoLoadEpisode(autoPlay: Boolean): Playable? { val nextEpisode = getCurrentEpisode() if (nextEpisode != null) { diff --git a/modules/services/repositories/src/main/java/au/com/shiftyjelly/pocketcasts/repositories/podcast/PlaylistManager.kt b/modules/services/repositories/src/main/java/au/com/shiftyjelly/pocketcasts/repositories/podcast/PlaylistManager.kt index 7f053685d0f..cf7a3949b5f 100644 --- a/modules/services/repositories/src/main/java/au/com/shiftyjelly/pocketcasts/repositories/podcast/PlaylistManager.kt +++ b/modules/services/repositories/src/main/java/au/com/shiftyjelly/pocketcasts/repositories/podcast/PlaylistManager.kt @@ -6,10 +6,12 @@ import au.com.shiftyjelly.pocketcasts.repositories.playback.PlaybackManager import io.reactivex.Completable import io.reactivex.Flowable import io.reactivex.Maybe +import kotlinx.coroutines.flow.Flow interface PlaylistManager { fun findAll(): List suspend fun findAllSuspend(): List + fun findAllFlow(): Flow> fun observeAll(): Flowable> fun findById(id: Long): Playlist? diff --git a/modules/services/repositories/src/main/java/au/com/shiftyjelly/pocketcasts/repositories/podcast/PlaylistManagerImpl.kt b/modules/services/repositories/src/main/java/au/com/shiftyjelly/pocketcasts/repositories/podcast/PlaylistManagerImpl.kt index 44e8065c5d4..4b52de6fb07 100644 --- a/modules/services/repositories/src/main/java/au/com/shiftyjelly/pocketcasts/repositories/podcast/PlaylistManagerImpl.kt +++ b/modules/services/repositories/src/main/java/au/com/shiftyjelly/pocketcasts/repositories/podcast/PlaylistManagerImpl.kt @@ -19,6 +19,7 @@ import io.reactivex.Flowable import io.reactivex.Maybe import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.launch import timber.log.Timber import java.util.Calendar @@ -108,6 +109,9 @@ class PlaylistManagerImpl @Inject constructor( override suspend fun findAllSuspend(): List { return playlistDao.findAllSuspend() } + override fun findAllFlow(): Flow> { + return playlistDao.findAllState() + } override fun count(): Int { return playlistDao.count() From 536021376709bb562b28013d6a6676fdf8a5abad Mon Sep 17 00:00:00 2001 From: Matt Chowning Date: Fri, 4 Nov 2022 09:35:57 -0400 Subject: [PATCH 2/5] Merge pull request #543 from joaomgcd/tasker_plugin_fix_for_minify Fixed crashes with Tasker plugin actions when using minified code --- CHANGELOG.md | 6 ++++-- .../pocketcasts/taskerplugin/base/ViewModelBase.kt | 4 ++-- .../config/ViewModelConfigControlPlayback.kt | 2 +- .../playplaylist/config/ViewModelConfigPlayPlaylist.kt | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f8180cd540..a600aa612a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,16 @@ 7.27 ----- * Added ability to set playback effects in Tasker "Control Playback" action. - ([#415](https://github.com/Automattic/pocket-casts-android/pull/509)). + ([#509](https://github.com/Automattic/pocket-casts-android/pull/509)). + * Fixed crashes with Tasker plugin actions when using minified code. + ([#543](https://github.com/Automattic/pocket-casts-android/pull/543)). 7.26 ----- * New Features: * Added Tasker integration with "Play Filter" and "Control Playback" actions. - ([#415](https://github.com/Automattic/pocket-casts-android/pull/431)). + ([#431](https://github.com/Automattic/pocket-casts-android/pull/431)). * Import OPML from a URL ([#482](https://github.com/Automattic/pocket-casts-android/pull/482)). * Redesign of the fullscreen player share option diff --git a/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/base/ViewModelBase.kt b/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/base/ViewModelBase.kt index a980a6793e1..d0a77067f79 100644 --- a/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/base/ViewModelBase.kt +++ b/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/base/ViewModelBase.kt @@ -14,8 +14,8 @@ import kotlinx.coroutines.flow.MutableStateFlow abstract class ViewModelBase>>(application: Application) : AndroidViewModel(application), TaskerPluginConfig { override val context get() = getApplication() - abstract val helperClass: Class - private val taskerHelper by lazy { helperClass.getConstructor(TaskerPluginConfig::class.java).newInstance(this) } + abstract fun getNewHelper(pluginConfig: TaskerPluginConfig): THelper + private val taskerHelper by lazy { getNewHelper(this) } protected var input: TInput? = null /** diff --git a/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/controlplayback/config/ViewModelConfigControlPlayback.kt b/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/controlplayback/config/ViewModelConfigControlPlayback.kt index 960ff58d3a0..7308ec0f196 100644 --- a/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/controlplayback/config/ViewModelConfigControlPlayback.kt +++ b/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/controlplayback/config/ViewModelConfigControlPlayback.kt @@ -19,7 +19,7 @@ import au.com.shiftyjelly.pocketcasts.localization.R as LR class ViewModelConfigControlPlayback @Inject constructor( application: Application ) : ViewModelBase(application), TaskerPluginConfig { - override val helperClass get() = ActionHelperControlPlayback::class.java + override fun getNewHelper(pluginConfig: TaskerPluginConfig) = ActionHelperControlPlayback(pluginConfig) /** * A field that only appears depending on the type of the playback command. For example, the field "Time to Skip To" will only appear if the command is "Skip To Time". A field can also always appear if it doesn't depend on a command type diff --git a/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/playplaylist/config/ViewModelConfigPlayPlaylist.kt b/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/playplaylist/config/ViewModelConfigPlayPlaylist.kt index c7ca82110eb..5a68bffa8e6 100644 --- a/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/playplaylist/config/ViewModelConfigPlayPlaylist.kt +++ b/modules/features/taskerplugin/src/main/java/au/com/shiftyjelly/pocketcasts/taskerplugin/playplaylist/config/ViewModelConfigPlayPlaylist.kt @@ -18,7 +18,7 @@ import javax.inject.Inject class ViewModelConfigPlayPlaylist @Inject constructor( application: Application ) : ViewModelBase(application), TaskerPluginConfig { - override val helperClass get() = ActionHelperPlayPlaylist::class.java + override fun getNewHelper(pluginConfig: TaskerPluginConfig) = ActionHelperPlayPlaylist(pluginConfig) private inner class InputField constructor(@StringRes labelResId: Int, @DrawableRes iconResId: Int, valueGetter: InputPlayPlaylist.() -> String?, valueSetter: InputPlayPlaylist.(String?) -> Unit) : InputFieldBase(labelResId, iconResId, valueGetter, valueSetter) { override val askFor get() = true From 6e354f5370db35c0961ea68c182db6141a2e073d Mon Sep 17 00:00:00 2001 From: Ashita Agrawal Date: Sat, 5 Nov 2022 10:40:59 +0530 Subject: [PATCH 3/5] Merge pull request #545 from VGJohn/auto-subscribe-fix Fix for auto subscribe enabled in main app --- .../au/com/shiftyjelly/pocketcasts/preferences/SettingsImpl.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/services/preferences/src/main/java/au/com/shiftyjelly/pocketcasts/preferences/SettingsImpl.kt b/modules/services/preferences/src/main/java/au/com/shiftyjelly/pocketcasts/preferences/SettingsImpl.kt index bbcd21c2c62..d89d361cb25 100644 --- a/modules/services/preferences/src/main/java/au/com/shiftyjelly/pocketcasts/preferences/SettingsImpl.kt +++ b/modules/services/preferences/src/main/java/au/com/shiftyjelly/pocketcasts/preferences/SettingsImpl.kt @@ -492,7 +492,7 @@ class SettingsImpl @Inject constructor( } override fun getAutoSubscribeToPlayed(): Boolean { - return getBoolean(Settings.PREFERENCE_AUTO_SUBSCRIBE_ON_PLAY, true) + return getBoolean(Settings.PREFERENCE_AUTO_SUBSCRIBE_ON_PLAY, false) } override fun getAutoShowPlayed(): Boolean { From cc471655d5a20568487d37d0a11767cbea493f90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Dias?= Date: Fri, 4 Nov 2022 14:27:13 +0530 Subject: [PATCH 4/5] Update change log --- CHANGELOG.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a600aa612a8..346e5e8637d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,6 @@ 7.27 ----- - * Added ability to set playback effects in Tasker "Control Playback" action. - ([#509](https://github.com/Automattic/pocket-casts-android/pull/509)). - * Fixed crashes with Tasker plugin actions when using minified code. - ([#543](https://github.com/Automattic/pocket-casts-android/pull/543)). + 7.26 ----- @@ -30,6 +27,12 @@ ([#432](https://github.com/Automattic/pocket-casts-android/pull/432)). * Fixed full screen video player not closing the first time in landscape mode ([#464](https://github.com/Automattic/pocket-casts-android/pull/464)). + * Added ability to set playback effects in Tasker "Control Playback" action. + ([#509](https://github.com/Automattic/pocket-casts-android/pull/509)). + * Fixed crashes with Tasker plugin actions when using minified code. + ([#543](https://github.com/Automattic/pocket-casts-android/pull/543)). + * Fixed auto subscribe issue. + ([#545](https://github.com/Automattic/pocket-casts-android/pull/545)). 7.25 ----- From fed3914b6d3d499223169f94a004bfa5b62eda9a Mon Sep 17 00:00:00 2001 From: ashiagr Date: Sat, 5 Nov 2022 11:36:36 +0530 Subject: [PATCH 5/5] Bump version number --- version.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.properties b/version.properties index 66a245f7f51..5c95670f167 100644 --- a/version.properties +++ b/version.properties @@ -1,3 +1,3 @@ # Version Information for Vanilla / Release builds -versionName=7.26-rc-3 -versionCode=9047 +versionName=7.26-rc-4 +versionCode=9048