6.12.6 commit
This commit is contained in:
parent
974bea78cf
commit
6b29cc3f5d
|
@ -31,8 +31,8 @@ android {
|
|||
testApplicationId "ac.mdiq.podcini.tests"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
versionCode 3020283
|
||||
versionName "6.12.5"
|
||||
versionCode 3020284
|
||||
versionName "6.12.6"
|
||||
|
||||
applicationId "ac.mdiq.podcini.R"
|
||||
def commit = ""
|
||||
|
|
|
@ -247,7 +247,7 @@ import kotlin.math.min
|
|||
// only push downloaded items
|
||||
val pausedItems = getEpisodes(0, Int.MAX_VALUE, EpisodeFilter(EpisodeFilter.States.paused.name), EpisodeSortOrder.DATE_NEW_OLD)
|
||||
val readItems = getEpisodes(0, Int.MAX_VALUE, EpisodeFilter(EpisodeFilter.States.played.name), EpisodeSortOrder.DATE_NEW_OLD)
|
||||
val favoriteItems = getEpisodes(0, Int.MAX_VALUE, EpisodeFilter(EpisodeFilter.States.is_favorite.name), EpisodeSortOrder.DATE_NEW_OLD)
|
||||
val favoriteItems = getEpisodes(0, Int.MAX_VALUE, EpisodeFilter(EpisodeFilter.States.favorite.name), EpisodeSortOrder.DATE_NEW_OLD)
|
||||
val comItems = mutableSetOf<Episode>()
|
||||
comItems.addAll(pausedItems)
|
||||
comItems.addAll(readItems)
|
||||
|
|
|
@ -959,7 +959,7 @@ class ImportExportPreferencesFragment : PreferenceFragmentCompat() {
|
|||
val queuedEpisodeActions: MutableList<EpisodeAction> = mutableListOf()
|
||||
val pausedItems = getEpisodes(0, Int.MAX_VALUE, EpisodeFilter(EpisodeFilter.States.paused.name), EpisodeSortOrder.DATE_NEW_OLD)
|
||||
val readItems = getEpisodes(0, Int.MAX_VALUE, EpisodeFilter(EpisodeFilter.States.played.name), EpisodeSortOrder.DATE_NEW_OLD)
|
||||
val favoriteItems = getEpisodes(0, Int.MAX_VALUE, EpisodeFilter(EpisodeFilter.States.is_favorite.name), EpisodeSortOrder.DATE_NEW_OLD)
|
||||
val favoriteItems = getEpisodes(0, Int.MAX_VALUE, EpisodeFilter(EpisodeFilter.States.favorite.name), EpisodeSortOrder.DATE_NEW_OLD)
|
||||
val comItems = mutableSetOf<Episode>()
|
||||
comItems.addAll(pausedItems)
|
||||
comItems.addAll(readItems)
|
||||
|
@ -1018,7 +1018,7 @@ class ImportExportPreferencesFragment : PreferenceFragmentCompat() {
|
|||
val favTemplate = IOUtils.toString(favTemplateStream, UTF_8)
|
||||
val feedTemplateStream = context.assets.open(FEED_TEMPLATE)
|
||||
val feedTemplate = IOUtils.toString(feedTemplateStream, UTF_8)
|
||||
val allFavorites = getEpisodes(0, Int.MAX_VALUE, EpisodeFilter(EpisodeFilter.States.is_favorite.name), EpisodeSortOrder.DATE_NEW_OLD)
|
||||
val allFavorites = getEpisodes(0, Int.MAX_VALUE, EpisodeFilter(EpisodeFilter.States.favorite.name), EpisodeSortOrder.DATE_NEW_OLD)
|
||||
val favoritesByFeed = buildFeedMap(allFavorites)
|
||||
writer!!.append(templateParts[0])
|
||||
for (feedId in favoritesByFeed.keys) {
|
||||
|
|
|
@ -19,6 +19,9 @@ import ac.mdiq.podcini.util.EventFlow
|
|||
import ac.mdiq.podcini.util.FlowEvent
|
||||
import android.util.Log
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import kotlinx.coroutines.Job
|
||||
import java.util.*
|
||||
|
@ -30,12 +33,6 @@ object Queues {
|
|||
BACK, FRONT, AFTER_CURRENTLY_PLAYING, RANDOM
|
||||
}
|
||||
|
||||
var isQueueLocked: Boolean
|
||||
get() = appPrefs.getBoolean(UserPreferences.Prefs.prefQueueLocked.name, false)
|
||||
set(locked) {
|
||||
appPrefs.edit().putBoolean(UserPreferences.Prefs.prefQueueLocked.name, locked).apply()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the queue is in keep sorted mode.
|
||||
* Enables/disables the keep sorted mode of the queue.
|
||||
|
@ -66,8 +63,7 @@ object Queues {
|
|||
var enqueueLocation: EnqueueLocation
|
||||
get() {
|
||||
val valStr = appPrefs.getString(UserPreferences.Prefs.prefEnqueueLocation.name, EnqueueLocation.BACK.name)
|
||||
try {
|
||||
return EnqueueLocation.valueOf(valStr!!)
|
||||
try { return EnqueueLocation.valueOf(valStr!!)
|
||||
} catch (t: Throwable) {
|
||||
// should never happen but just in case
|
||||
Log.e(TAG, "getEnqueueLocation: invalid value '$valStr' Use default.", t)
|
||||
|
|
|
@ -2,20 +2,21 @@ package ac.mdiq.podcini.storage.model
|
|||
|
||||
import ac.mdiq.podcini.R
|
||||
import ac.mdiq.podcini.storage.database.Queues.inAnyQueue
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
import java.io.Serializable
|
||||
|
||||
class EpisodeFilter(vararg properties_: String) : Serializable {
|
||||
val properties: HashSet<String> = setOf(*properties_).filter { it.isNotEmpty() }.map {it.trim()}.toHashSet()
|
||||
|
||||
val showPlayed: Boolean = properties.contains(States.played.name)
|
||||
val showUnplayed: Boolean = properties.contains(States.unplayed.name)
|
||||
val showNew: Boolean = properties.contains(States.new.name)
|
||||
// val showPlayed: Boolean = properties.contains(States.played.name)
|
||||
// val showUnplayed: Boolean = properties.contains(States.unplayed.name)
|
||||
// val showNew: Boolean = properties.contains(States.new.name)
|
||||
val showQueued: Boolean = properties.contains(States.queued.name)
|
||||
val showNotQueued: Boolean = properties.contains(States.not_queued.name)
|
||||
val showDownloaded: Boolean = properties.contains(States.downloaded.name)
|
||||
val showNotDownloaded: Boolean = properties.contains(States.not_downloaded.name)
|
||||
val showIsFavorite: Boolean = properties.contains(States.is_favorite.name)
|
||||
val showNotFavorite: Boolean = properties.contains(States.not_favorite.name)
|
||||
// val showIsFavorite: Boolean = properties.contains(States.is_favorite.name)
|
||||
// val showNotFavorite: Boolean = properties.contains(States.not_favorite.name)
|
||||
|
||||
constructor(properties: String) : this(*(properties.split(",").toTypedArray()))
|
||||
|
||||
|
@ -30,11 +31,11 @@ class EpisodeFilter(vararg properties_: String) : Serializable {
|
|||
|
||||
fun queryString(): String {
|
||||
val statements: MutableList<String> = mutableListOf()
|
||||
when {
|
||||
showPlayed -> statements.add("playState >= ${PlayState.PLAYED.code}")
|
||||
showUnplayed -> statements.add(" playState < ${PlayState.PLAYED.code} ") // Match "New" items (read = -1) as well
|
||||
showNew -> statements.add("playState == -1 ")
|
||||
}
|
||||
// when {
|
||||
//// showPlayed -> statements.add("playState >= ${PlayState.PLAYED.code}")
|
||||
//// showUnplayed -> statements.add(" playState < ${PlayState.PLAYED.code} ") // Match "New" items (read = -1) as well
|
||||
//// showNew -> statements.add("playState == -1 ")
|
||||
// }
|
||||
|
||||
val mediaTypeQuerys = mutableListOf<String>()
|
||||
if (properties.contains(States.unknown.name)) mediaTypeQuerys.add(" media == nil OR media.mimeType == nil OR media.mimeType == '' ")
|
||||
|
@ -118,10 +119,10 @@ class EpisodeFilter(vararg properties_: String) : Serializable {
|
|||
properties.contains(States.has_comments.name) -> statements.add(" comment != '' ")
|
||||
properties.contains(States.no_comments.name) -> statements.add(" comment == '' ")
|
||||
}
|
||||
when {
|
||||
showIsFavorite -> statements.add("rating == ${Rating.FAVORITE.code} ")
|
||||
showNotFavorite -> statements.add("rating != ${Rating.FAVORITE.code} ")
|
||||
}
|
||||
// when {
|
||||
// showIsFavorite -> statements.add("rating == ${Rating.FAVORITE.code} ")
|
||||
// showNotFavorite -> statements.add("rating != ${Rating.FAVORITE.code} ")
|
||||
// }
|
||||
|
||||
if (statements.isEmpty()) return "id > 0"
|
||||
val query = StringBuilder(" (" + statements[0])
|
||||
|
@ -130,6 +131,7 @@ class EpisodeFilter(vararg properties_: String) : Serializable {
|
|||
query.append(r)
|
||||
}
|
||||
query.append(") ")
|
||||
Logd("EpisodeFilter", "queryString: $query")
|
||||
return query.toString()
|
||||
}
|
||||
|
||||
|
@ -154,8 +156,8 @@ class EpisodeFilter(vararg properties_: String) : Serializable {
|
|||
audio_app,
|
||||
paused,
|
||||
not_paused,
|
||||
is_favorite,
|
||||
not_favorite,
|
||||
// is_favorite,
|
||||
// not_favorite,
|
||||
has_media,
|
||||
no_media,
|
||||
has_comments,
|
||||
|
|
|
@ -28,6 +28,7 @@ import ac.mdiq.podcini.ui.fragment.*
|
|||
import ac.mdiq.podcini.ui.utils.LocalDeleteModal.deleteEpisodesWarnLocal
|
||||
import ac.mdiq.podcini.util.EventFlow
|
||||
import ac.mdiq.podcini.util.FlowEvent
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.util.TypedValue
|
||||
|
@ -92,6 +93,7 @@ open class SwipeActions(private val fragment: Fragment, private val tag: String)
|
|||
// EventFlow.postEvent(FlowEvent.SwipeActionsChangedEvent())
|
||||
// }
|
||||
// })
|
||||
Logd("SwipeActions", "showDialog()")
|
||||
val composeView = ComposeView(fragment.requireContext()).apply {
|
||||
setContent {
|
||||
val showDialog = remember { mutableStateOf(true) }
|
||||
|
@ -101,6 +103,7 @@ open class SwipeActions(private val fragment: Fragment, private val tag: String)
|
|||
(fragment.view as? ViewGroup)?.removeView(this@apply)
|
||||
}) {
|
||||
actions = getPrefs(this@SwipeActions.tag)
|
||||
// TODO: remove the need of event
|
||||
EventFlow.postEvent(FlowEvent.SwipeActionsChangedEvent())
|
||||
}
|
||||
}
|
||||
|
@ -149,7 +152,8 @@ open class SwipeActions(private val fragment: Fragment, private val tag: String)
|
|||
}
|
||||
|
||||
override fun willRemove(filter: EpisodeFilter, item: Episode): Boolean {
|
||||
return filter.showQueued || filter.showNew
|
||||
return false
|
||||
// return filter.showQueued || filter.showNew
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -208,7 +212,8 @@ open class SwipeActions(private val fragment: Fragment, private val tag: String)
|
|||
}
|
||||
|
||||
override fun willRemove(filter: EpisodeFilter, item: Episode): Boolean {
|
||||
return filter.showQueued || filter.showNew
|
||||
return false
|
||||
// return filter.showQueued || filter.showNew
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -274,7 +279,8 @@ open class SwipeActions(private val fragment: Fragment, private val tag: String)
|
|||
}
|
||||
|
||||
override fun willRemove(filter: EpisodeFilter, item: Episode): Boolean {
|
||||
return filter.showIsFavorite || filter.showNotFavorite
|
||||
return false
|
||||
// return filter.showIsFavorite || filter.showNotFavorite
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -479,8 +485,9 @@ open class SwipeActions(private val fragment: Fragment, private val tag: String)
|
|||
}
|
||||
|
||||
override fun willRemove(filter: EpisodeFilter, item: Episode): Boolean {
|
||||
return if (item.playState == PlayState.NEW.code) filter.showPlayed || filter.showNew
|
||||
else filter.showUnplayed || filter.showPlayed || filter.showNew
|
||||
return false
|
||||
// return if (item.playState == PlayState.NEW.code) filter.showPlayed || filter.showNew
|
||||
// else filter.showUnplayed || filter.showPlayed || filter.showNew
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -55,8 +55,7 @@ import android.view.Gravity
|
|||
import androidx.compose.animation.core.Animatable
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.gestures.detectHorizontalDragGestures
|
||||
import androidx.compose.foundation.gestures.detectTapGestures
|
||||
import androidx.compose.foundation.gestures.*
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
|
@ -77,6 +76,7 @@ import androidx.compose.ui.graphics.vector.ImageVector
|
|||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.input.pointer.util.VelocityTracker
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
|
@ -410,10 +410,10 @@ fun ShelveDialog(selected: List<Episode>, onDismissRequest: () -> Unit) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun EpisodeLazyColumn(activity: MainActivity, vms: List<EpisodeVM>, feed: Feed? = null,
|
||||
fun EpisodeLazyColumn(activity: MainActivity, vms: MutableList<EpisodeVM>, feed: Feed? = null,
|
||||
isDraggable: Boolean = false, dragCB: ((Int, Int)->Unit)? = null,
|
||||
refreshCB: (()->Unit)? = null, leftSwipeCB: ((Episode) -> Unit)? = null, rightSwipeCB: ((Episode) -> Unit)? = null,
|
||||
actionButton_: ((Episode)-> EpisodeActionButton)? = null) {
|
||||
val TAG = "EpisodeLazyColumn"
|
||||
|
@ -457,10 +457,7 @@ fun EpisodeLazyColumn(activity: MainActivity, vms: List<EpisodeVM>, feed: Feed?
|
|||
Text(stringResource(R.string.feed_delete_reason_msg))
|
||||
BasicTextField(value = textState, onValueChange = { textState = it },
|
||||
textStyle = TextStyle(fontSize = 16.sp, color = textColor),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(100.dp)
|
||||
.padding(start = 10.dp, end = 10.dp, bottom = 10.dp)
|
||||
modifier = Modifier.fillMaxWidth().height(100.dp).padding(start = 10.dp, end = 10.dp, bottom = 10.dp)
|
||||
.border(1.dp, MaterialTheme.colorScheme.primary, MaterialTheme.shapes.small)
|
||||
)
|
||||
Button(onClick = {
|
||||
|
@ -649,19 +646,26 @@ fun EpisodeLazyColumn(activity: MainActivity, vms: List<EpisodeVM>, feed: Feed?
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun MainRow(vm: EpisodeVM, index: Int) {
|
||||
fun MainRow(vm: EpisodeVM, index: Int, isBeingDragged: Boolean, yOffset: Float, onDragStart: () -> Unit, onDrag: (Float) -> Unit, onDragEnd: () -> Unit) {
|
||||
val textColor = MaterialTheme.colorScheme.onSurface
|
||||
fun toggleSelected() {
|
||||
vm.isSelected = !vm.isSelected
|
||||
if (vm.isSelected) selected.add(vms[index].episode)
|
||||
else selected.remove(vms[index].episode)
|
||||
}
|
||||
Row(Modifier.background(if (vm.isSelected) MaterialTheme.colorScheme.secondaryContainer else MaterialTheme.colorScheme.surface)) {
|
||||
if (false) {
|
||||
val density = LocalDensity.current
|
||||
Row(Modifier.background(if (vm.isSelected) MaterialTheme.colorScheme.secondaryContainer else MaterialTheme.colorScheme.surface)
|
||||
.offset(y = with(density) { yOffset.toDp() })) {
|
||||
if (isDraggable) {
|
||||
val typedValue = TypedValue()
|
||||
LocalContext.current.theme.resolveAttribute(R.attr.dragview_background, typedValue, true)
|
||||
context.theme.resolveAttribute(R.attr.dragview_background, typedValue, true)
|
||||
Icon(imageVector = ImageVector.vectorResource(typedValue.resourceId), tint = textColor, contentDescription = "drag handle",
|
||||
modifier = Modifier.width(16.dp).align(Alignment.CenterVertically))
|
||||
modifier = Modifier.width(50.dp).align(Alignment.CenterVertically).padding(start = 10.dp, end = 15.dp)
|
||||
.draggable(orientation = Orientation.Vertical,
|
||||
state = rememberDraggableState { delta -> onDrag(delta) },
|
||||
onDragStarted = { onDragStart() },
|
||||
onDragStopped = { onDragEnd() }
|
||||
))
|
||||
}
|
||||
ConstraintLayout(modifier = Modifier.width(56.dp).height(56.dp)) {
|
||||
val (imgvCover, checkMark) = createRefs()
|
||||
|
@ -727,7 +731,7 @@ fun EpisodeLazyColumn(activity: MainActivity, vms: List<EpisodeVM>, feed: Feed?
|
|||
val durText = remember { DurationConverter.getDurationStringLong(dur) }
|
||||
val dateSizeText = " · " + formatAbbrev(curContext, vm.episode.getPubDate()) + " · " + durText + " · " +
|
||||
if ((vm.episode.media?.size ?: 0) > 0) Formatter.formatShortFileSize(curContext, vm.episode.media?.size ?: 0) else ""
|
||||
Text(dateSizeText, color = textColor, style = MaterialTheme.typography.bodyMedium)
|
||||
Text(dateSizeText, color = textColor, style = MaterialTheme.typography.bodyMedium, maxLines = 1, overflow = TextOverflow.Ellipsis)
|
||||
}
|
||||
Text(vm.episode.title ?: "", color = textColor, maxLines = 2, overflow = TextOverflow.Ellipsis)
|
||||
}
|
||||
|
@ -774,7 +778,7 @@ fun EpisodeLazyColumn(activity: MainActivity, vms: List<EpisodeVM>, feed: Feed?
|
|||
val dur = remember { vm.episode.media?.getDuration() ?: 0 }
|
||||
val durText = remember { DurationConverter.getDurationStringLong(dur) }
|
||||
vm.prog = if (dur > 0 && pos >= 0 && dur >= pos) 1.0f * pos / dur else 0f
|
||||
Logd(TAG, "$index vm.prog: ${vm.prog}")
|
||||
// Logd(TAG, "$index vm.prog: ${vm.prog}")
|
||||
Row {
|
||||
Text(DurationConverter.getDurationStringLong(vm.positionState), color = textColor, style = MaterialTheme.typography.bodySmall)
|
||||
LinearProgressIndicator(progress = { vm.prog }, modifier = Modifier.weight(1f).height(4.dp).align(Alignment.CenterVertically))
|
||||
|
@ -789,6 +793,13 @@ fun EpisodeLazyColumn(activity: MainActivity, vms: List<EpisodeVM>, feed: Feed?
|
|||
refreshCB?.invoke()
|
||||
refreshing = false
|
||||
}) {
|
||||
fun <T> MutableList<T>.move(fromIndex: Int, toIndex: Int) {
|
||||
if (fromIndex != toIndex && fromIndex in indices && toIndex in indices) {
|
||||
val item = removeAt(fromIndex)
|
||||
add(toIndex, item)
|
||||
}
|
||||
}
|
||||
val rowHeightPx = with(LocalDensity.current) { 56.dp.toPx() }
|
||||
LazyColumn(state = lazyListState, modifier = Modifier.padding(start = 10.dp, end = 10.dp, top = 10.dp, bottom = 10.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
itemsIndexed(vms, key = { _, vm -> vm.episode.id}) { index, vm ->
|
||||
vm.startMonitoring()
|
||||
|
@ -801,7 +812,6 @@ fun EpisodeLazyColumn(activity: MainActivity, vms: List<EpisodeVM>, feed: Feed?
|
|||
val velocityTracker = remember { VelocityTracker() }
|
||||
val offsetX = remember { Animatable(0f) }
|
||||
Box(modifier = Modifier.fillMaxWidth().pointerInput(Unit) {
|
||||
Logd(TAG, "top box")
|
||||
detectHorizontalDragGestures(onDragStart = { velocityTracker.resetTracking() },
|
||||
onHorizontalDrag = { change, dragAmount ->
|
||||
Logd(TAG, "onHorizontalDrag $dragAmount")
|
||||
|
@ -829,7 +839,25 @@ fun EpisodeLazyColumn(activity: MainActivity, vms: List<EpisodeVM>, feed: Feed?
|
|||
Logd(TAG, "LaunchedEffect $index ${vm.isSelected} ${selected.size}")
|
||||
}
|
||||
Column {
|
||||
MainRow(vm, index)
|
||||
var yOffset by remember { mutableStateOf(0f) }
|
||||
var draggedIndex by remember { mutableStateOf<Int?>(null) }
|
||||
MainRow(vm, index, isBeingDragged = draggedIndex == index,
|
||||
yOffset = if (draggedIndex == index) yOffset else 0f,
|
||||
onDragStart = { draggedIndex = index },
|
||||
onDrag = { delta -> yOffset += delta },
|
||||
onDragEnd = {
|
||||
draggedIndex?.let { startIndex ->
|
||||
val newIndex = (startIndex + (yOffset / rowHeightPx).toInt()).coerceIn(0, vms.lastIndex)
|
||||
Logd(TAG, "onDragEnd draggedIndex: $draggedIndex newIndex: $newIndex")
|
||||
if (newIndex != startIndex) {
|
||||
dragCB?.invoke(startIndex, newIndex)
|
||||
val item = vms.removeAt(startIndex)
|
||||
vms.add(newIndex, item)
|
||||
}
|
||||
}
|
||||
draggedIndex = null
|
||||
yOffset = 0f
|
||||
})
|
||||
ProgressRow(vm, index)
|
||||
}
|
||||
}
|
||||
|
@ -842,9 +870,7 @@ fun EpisodeLazyColumn(activity: MainActivity, vms: List<EpisodeVM>, feed: Feed?
|
|||
modifier = Modifier.width(35.dp).height(35.dp).padding(end = 10.dp)
|
||||
.clickable(onClick = {
|
||||
selected.clear()
|
||||
for (i in 0..longPressIndex) {
|
||||
selected.add(vms[i].episode)
|
||||
}
|
||||
for (i in 0..longPressIndex) selected.add(vms[i].episode)
|
||||
selectedSize = selected.size
|
||||
Logd(TAG, "selectedIds: ${selected.size}")
|
||||
}))
|
||||
|
@ -852,9 +878,7 @@ fun EpisodeLazyColumn(activity: MainActivity, vms: List<EpisodeVM>, feed: Feed?
|
|||
modifier = Modifier.width(35.dp).height(35.dp).padding(end = 10.dp)
|
||||
.clickable(onClick = {
|
||||
selected.clear()
|
||||
for (i in longPressIndex..<vms.size) {
|
||||
selected.add(vms[i].episode)
|
||||
}
|
||||
for (i in longPressIndex..<vms.size) selected.add(vms[i].episode)
|
||||
selectedSize = selected.size
|
||||
Logd(TAG, "selectedIds: ${selected.size}")
|
||||
}))
|
||||
|
@ -863,9 +887,7 @@ fun EpisodeLazyColumn(activity: MainActivity, vms: List<EpisodeVM>, feed: Feed?
|
|||
.clickable(onClick = {
|
||||
if (selectedSize != vms.size) {
|
||||
selected.clear()
|
||||
for (vm in vms) {
|
||||
selected.add(vm.episode)
|
||||
}
|
||||
for (vm in vms) selected.add(vm.episode)
|
||||
selectAllRes = R.drawable.ic_select_none
|
||||
} else {
|
||||
selected.clear()
|
||||
|
@ -924,8 +946,7 @@ fun ConfirmAddYoutubeEpisode(sharedUrls: List<String>, showDialog: Boolean, onDi
|
|||
}) {
|
||||
Text("Confirm")
|
||||
}
|
||||
} else CircularProgressIndicator(progress = { 0.6f }, strokeWidth = 4.dp,
|
||||
modifier = Modifier.padding(start = 20.dp, end = 20.dp).width(30.dp).height(30.dp))
|
||||
} else CircularProgressIndicator(progress = { 0.6f }, strokeWidth = 4.dp, modifier = Modifier.padding(start = 20.dp, end = 20.dp).width(30.dp).height(30.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -936,7 +957,6 @@ fun ConfirmAddYoutubeEpisode(sharedUrls: List<String>, showDialog: Boolean, onDi
|
|||
fun EpisodesFilterDialog(filter: EpisodeFilter? = null, filtersDisabled: MutableSet<EpisodeFilter.EpisodesFilterGroup> = mutableSetOf(),
|
||||
onDismissRequest: () -> Unit, onFilterChanged: (Set<String>) -> Unit) {
|
||||
val filterValues: MutableSet<String> = mutableSetOf()
|
||||
|
||||
Dialog(properties = DialogProperties(usePlatformDefaultWidth = false), onDismissRequest = { onDismissRequest() }) {
|
||||
val dialogWindowProvider = LocalView.current.parent as? DialogWindowProvider
|
||||
dialogWindowProvider?.window?.let { window ->
|
||||
|
@ -1001,21 +1021,74 @@ fun EpisodesFilterDialog(filter: EpisodeFilter? = null, filtersDisabled: Mutable
|
|||
}
|
||||
} else {
|
||||
Column(modifier = Modifier.padding(start = 5.dp, bottom = 2.dp).fillMaxWidth()) {
|
||||
Text(stringResource(item.nameRes) + " :", fontWeight = FontWeight.Bold, style = MaterialTheme.typography.headlineSmall, color = textColor)
|
||||
NonlazyGrid(columns = 3, itemCount = item.values.size) { index ->
|
||||
var selected by remember { mutableStateOf(false) }
|
||||
if (selectNone) selected = false
|
||||
val selectedList = remember { MutableList(item.values.size) { mutableStateOf(false)} }
|
||||
var expandRow by remember { mutableStateOf(false) }
|
||||
Row {
|
||||
Text(stringResource(item.nameRes) + ".. :", fontWeight = FontWeight.Bold, style = MaterialTheme.typography.headlineSmall, color = textColor, modifier = Modifier.clickable {
|
||||
expandRow = !expandRow
|
||||
})
|
||||
var lowerSelected by remember { mutableStateOf(false) }
|
||||
var higherSelected by remember { mutableStateOf(false) }
|
||||
Spacer(Modifier.weight(1f))
|
||||
if (expandRow) Text("<<<", color = if (lowerSelected) Color.Green else textColor, style = MaterialTheme.typography.headlineSmall, modifier = Modifier.clickable {
|
||||
val hIndex = selectedList.indexOfLast { it.value }
|
||||
if (hIndex < 0) return@clickable
|
||||
if (!lowerSelected) {
|
||||
for (i in 0..hIndex) selectedList[i].value = true
|
||||
} else {
|
||||
for (i in 0..hIndex) selectedList[i].value = false
|
||||
selectedList[hIndex].value = true
|
||||
}
|
||||
lowerSelected = !lowerSelected
|
||||
for (i in item.values.indices) {
|
||||
if (selectedList[i].value) filterValues.add(item.values[i].filterId)
|
||||
else filterValues.remove(item.values[i].filterId)
|
||||
}
|
||||
onFilterChanged(filterValues)
|
||||
})
|
||||
Spacer(Modifier.weight(1f))
|
||||
if (expandRow) Text("X", color = textColor, style = MaterialTheme.typography.headlineSmall, modifier = Modifier.clickable {
|
||||
lowerSelected = false
|
||||
higherSelected = false
|
||||
for (i in item.values.indices) {
|
||||
selectedList[i].value = false
|
||||
filterValues.remove(item.values[i].filterId)
|
||||
}
|
||||
onFilterChanged(filterValues)
|
||||
})
|
||||
Spacer(Modifier.weight(1f))
|
||||
if (expandRow) Text(">>>", color = if (higherSelected) Color.Green else textColor, style = MaterialTheme.typography.headlineSmall, modifier = Modifier.clickable {
|
||||
val lIndex = selectedList.indexOfFirst { it.value }
|
||||
if (lIndex < 0) return@clickable
|
||||
if (!higherSelected) {
|
||||
for (i in lIndex..item.values.size - 1) selectedList[i].value = true
|
||||
} else {
|
||||
for (i in lIndex..item.values.size - 1) selectedList[i].value = false
|
||||
selectedList[lIndex].value = true
|
||||
}
|
||||
higherSelected = !higherSelected
|
||||
for (i in item.values.indices) {
|
||||
if (selectedList[i].value) filterValues.add(item.values[i].filterId)
|
||||
else filterValues.remove(item.values[i].filterId)
|
||||
}
|
||||
onFilterChanged(filterValues)
|
||||
})
|
||||
Spacer(Modifier.weight(1f))
|
||||
}
|
||||
if (expandRow) NonlazyGrid(columns = 3, itemCount = item.values.size) { index ->
|
||||
if (selectNone) selectedList[index].value = false
|
||||
LaunchedEffect(Unit) {
|
||||
if (filter != null) {
|
||||
if (item.values[index].filterId in filter.properties) selected = true
|
||||
if (item.values[index].filterId in filter.properties) selectedList[index].value = true
|
||||
}
|
||||
}
|
||||
OutlinedButton(modifier = Modifier.padding(0.dp).heightIn(min = 20.dp).widthIn(min = 20.dp).wrapContentWidth(),
|
||||
border = BorderStroke(2.dp, if (selected) Color.Green else textColor),
|
||||
OutlinedButton(
|
||||
modifier = Modifier.padding(0.dp).heightIn(min = 20.dp).widthIn(min = 20.dp).wrapContentWidth(),
|
||||
border = BorderStroke(2.dp, if (selectedList[index].value) Color.Green else textColor),
|
||||
onClick = {
|
||||
selectNone = false
|
||||
selected = !selected
|
||||
if (selected) filterValues.add(item.values[index].filterId)
|
||||
selectedList[index].value = !selectedList[index].value
|
||||
if (selectedList[index].value) filterValues.add(item.values[index].filterId)
|
||||
else filterValues.remove(item.values[index].filterId)
|
||||
onFilterChanged(filterValues)
|
||||
},
|
||||
|
|
|
@ -92,11 +92,11 @@ abstract class BaseEpisodesFragment : Fragment(), Toolbar.OnMenuItemClickListene
|
|||
EpisodeLazyColumn(
|
||||
activity as MainActivity, vms = vms,
|
||||
leftSwipeCB = {
|
||||
if (leftActionState.value == NoActionSwipeAction()) swipeActions.showDialog()
|
||||
if (leftActionState.value is NoActionSwipeAction) swipeActions.showDialog()
|
||||
else leftActionState.value.performAction(it, this@BaseEpisodesFragment, swipeActions.filter ?: EpisodeFilter())
|
||||
},
|
||||
rightSwipeCB = {
|
||||
if (rightActionState.value == NoActionSwipeAction()) swipeActions.showDialog()
|
||||
if (rightActionState.value is NoActionSwipeAction) swipeActions.showDialog()
|
||||
else rightActionState.value.performAction(it, this@BaseEpisodesFragment, swipeActions.filter ?: EpisodeFilter())
|
||||
},
|
||||
)
|
||||
|
|
|
@ -111,11 +111,11 @@ import java.util.*
|
|||
InforBar(infoBarText, leftAction = leftActionState, rightAction = rightActionState, actionConfig = {swipeActions.showDialog()})
|
||||
EpisodeLazyColumn(activity as MainActivity, vms = vms,
|
||||
leftSwipeCB = {
|
||||
if (leftActionState.value == NoActionSwipeAction()) swipeActions.showDialog()
|
||||
if (leftActionState.value is NoActionSwipeAction) swipeActions.showDialog()
|
||||
else leftActionState.value.performAction(it, this@DownloadsFragment, swipeActions.filter ?: EpisodeFilter())
|
||||
},
|
||||
rightSwipeCB = {
|
||||
if (rightActionState.value == NoActionSwipeAction()) swipeActions.showDialog()
|
||||
if (rightActionState.value is NoActionSwipeAction) swipeActions.showDialog()
|
||||
else rightActionState.value.performAction(it, this@DownloadsFragment, swipeActions.filter ?: EpisodeFilter())
|
||||
},
|
||||
actionButton_ = { DeleteActionButton(it) })
|
||||
|
|
|
@ -190,11 +190,12 @@ import java.util.concurrent.Semaphore
|
|||
EpisodeLazyColumn(activity as MainActivity, vms = vms, feed = feed,
|
||||
refreshCB = { FeedUpdateManager.runOnceOrAsk(requireContext(), feed) },
|
||||
leftSwipeCB = {
|
||||
if (leftActionState.value == NoActionSwipeAction()) swipeActions.showDialog()
|
||||
if (leftActionState.value is NoActionSwipeAction) swipeActions.showDialog()
|
||||
else leftActionState.value.performAction(it, this@FeedEpisodesFragment, swipeActions.filter ?: EpisodeFilter())
|
||||
},
|
||||
rightSwipeCB = {
|
||||
if (rightActionState.value == NoActionSwipeAction()) swipeActions.showDialog()
|
||||
Logd(TAG, "rightActionState: ${rightActionState.value.getId()}")
|
||||
if (rightActionState.value is NoActionSwipeAction) swipeActions.showDialog()
|
||||
else rightActionState.value.performAction(it, this@FeedEpisodesFragment, swipeActions.filter ?: EpisodeFilter())
|
||||
},
|
||||
)
|
||||
|
@ -402,7 +403,7 @@ import java.util.concurrent.Semaphore
|
|||
}
|
||||
when (item.itemId) {
|
||||
R.id.visit_website_item -> if (feed!!.link != null) IntentUtils.openInBrowser(requireContext(), feed!!.link!!)
|
||||
R.id.share_feed -> ShareUtils.shareFeedLink(requireContext(), feed!!)
|
||||
R.id.share_feed -> ShareUtils.shareFeedLinkNew(requireContext(), feed!!)
|
||||
R.id.refresh_feed -> FeedUpdateManager.runOnceOrAsk(requireContext(), feed)
|
||||
R.id.refresh_complete_item -> {
|
||||
Thread {
|
||||
|
|
|
@ -347,7 +347,7 @@ class FeedInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
override fun onMenuItemClick(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
R.id.visit_website_item -> if (feed.link != null) IntentUtils.openInBrowser(requireContext(), feed.link!!)
|
||||
R.id.share_item -> ShareUtils.shareFeedLink(requireContext(), feed)
|
||||
R.id.share_item -> ShareUtils.shareFeedLinkNew(requireContext(), feed)
|
||||
R.id.reconnect_local_folder -> {
|
||||
val alert = MaterialAlertDialogBuilder(requireContext())
|
||||
alert.setMessage(R.string.reconnect_local_folder_warning)
|
||||
|
|
|
@ -11,9 +11,10 @@ import ac.mdiq.podcini.playback.service.PlaybackService
|
|||
import ac.mdiq.podcini.playback.service.PlaybackService.Companion.mediaBrowser
|
||||
import ac.mdiq.podcini.playback.service.PlaybackService.Companion.playbackService
|
||||
import ac.mdiq.podcini.preferences.UserPreferences
|
||||
import ac.mdiq.podcini.preferences.UserPreferences.appPrefs
|
||||
import ac.mdiq.podcini.storage.database.Queues.clearQueue
|
||||
import ac.mdiq.podcini.storage.database.Queues.isQueueKeepSorted
|
||||
import ac.mdiq.podcini.storage.database.Queues.isQueueLocked
|
||||
import ac.mdiq.podcini.storage.database.Queues.moveInQueue
|
||||
import ac.mdiq.podcini.storage.database.Queues.queueKeepSortedOrder
|
||||
import ac.mdiq.podcini.storage.database.RealmDB.realm
|
||||
import ac.mdiq.podcini.storage.database.RealmDB.runOnIOScope
|
||||
|
@ -33,7 +34,6 @@ import ac.mdiq.podcini.ui.activity.MainActivity
|
|||
import ac.mdiq.podcini.ui.compose.*
|
||||
import ac.mdiq.podcini.ui.dialog.ConfirmationDialog
|
||||
import ac.mdiq.podcini.ui.dialog.EpisodeSortDialog
|
||||
import ac.mdiq.podcini.ui.utils.EmptyViewHandler
|
||||
import ac.mdiq.podcini.util.EventFlow
|
||||
import ac.mdiq.podcini.util.FlowEvent
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
|
@ -88,7 +88,7 @@ import kotlin.math.max
|
|||
private var _binding: ComposeFragmentBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private lateinit var emptyViewHandler: EmptyViewHandler
|
||||
// private lateinit var emptyViewHandler: EmptyViewHandler
|
||||
private lateinit var toolbar: MaterialToolbar
|
||||
private lateinit var swipeActions: SwipeActions
|
||||
private lateinit var swipeActionsBin: SwipeActions
|
||||
|
@ -102,6 +102,8 @@ import kotlin.math.max
|
|||
private var leftActionStateBin = mutableStateOf<SwipeAction>(NoActionSwipeAction())
|
||||
private var rightActionStateBin = mutableStateOf<SwipeAction>(NoActionSwipeAction())
|
||||
|
||||
var isQueueLocked = appPrefs.getBoolean(UserPreferences.Prefs.prefQueueLocked.name, true)
|
||||
|
||||
private lateinit var spinnerLayout: View
|
||||
private lateinit var queueNames: Array<String>
|
||||
private lateinit var spinnerTexts: MutableList<String>
|
||||
|
@ -115,7 +117,7 @@ import kotlin.math.max
|
|||
|
||||
private var showBin by mutableStateOf(false)
|
||||
|
||||
// private var dragDropEnabled: Boolean = !(isQueueKeepSorted || isQueueLocked)
|
||||
private var dragDropEnabled by mutableStateOf(!(isQueueKeepSorted || isQueueLocked))
|
||||
|
||||
private lateinit var browserFuture: ListenableFuture<MediaBrowser>
|
||||
|
||||
|
@ -190,11 +192,11 @@ import kotlin.math.max
|
|||
Column {
|
||||
InforBar(infoBarText, leftAction = leftActionStateBin, rightAction = rightActionStateBin, actionConfig = { swipeActionsBin.showDialog() })
|
||||
val leftCB = { episode: Episode ->
|
||||
if (leftActionStateBin.value == NoActionSwipeAction()) swipeActionsBin.showDialog()
|
||||
if (leftActionStateBin.value is NoActionSwipeAction) swipeActionsBin.showDialog()
|
||||
else leftActionStateBin.value.performAction(episode, this@QueuesFragment, swipeActionsBin.filter ?: EpisodeFilter())
|
||||
}
|
||||
val rightCB = { episode: Episode ->
|
||||
if (rightActionStateBin.value == NoActionSwipeAction()) swipeActionsBin.showDialog()
|
||||
if (rightActionStateBin.value is NoActionSwipeAction) swipeActionsBin.showDialog()
|
||||
else rightActionStateBin.value.performAction(episode, this@QueuesFragment, swipeActionsBin.filter ?: EpisodeFilter())
|
||||
}
|
||||
EpisodeLazyColumn(activity as MainActivity, vms = vms, leftSwipeCB = { leftCB(it) }, rightSwipeCB = { rightCB(it) })
|
||||
|
@ -203,14 +205,16 @@ import kotlin.math.max
|
|||
Column {
|
||||
InforBar(infoBarText, leftAction = leftActionState, rightAction = rightActionState, actionConfig = { swipeActions.showDialog() })
|
||||
val leftCB = { episode: Episode ->
|
||||
if (leftActionState.value == NoActionSwipeAction()) swipeActions.showDialog()
|
||||
if (leftActionState.value is NoActionSwipeAction) swipeActions.showDialog()
|
||||
else leftActionState.value.performAction(episode, this@QueuesFragment, swipeActions.filter ?: EpisodeFilter())
|
||||
}
|
||||
val rightCB = { episode: Episode ->
|
||||
if (rightActionState.value == NoActionSwipeAction()) swipeActions.showDialog()
|
||||
if (rightActionState.value is NoActionSwipeAction) swipeActions.showDialog()
|
||||
else rightActionState.value.performAction(episode, this@QueuesFragment, swipeActions.filter ?: EpisodeFilter())
|
||||
}
|
||||
EpisodeLazyColumn(activity as MainActivity, vms = vms, leftSwipeCB = { leftCB(it) }, rightSwipeCB = { rightCB(it) })
|
||||
EpisodeLazyColumn(activity as MainActivity, vms = vms,
|
||||
isDraggable = dragDropEnabled, dragCB = { iFrom, iTo -> moveInQueue(iFrom, iTo, true) },
|
||||
leftSwipeCB = { leftCB(it) }, rightSwipeCB = { rightCB(it) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -219,13 +223,6 @@ import kotlin.math.max
|
|||
lifecycle.addObserver(swipeActions)
|
||||
refreshSwipeTelltale()
|
||||
|
||||
emptyViewHandler = EmptyViewHandler(requireContext())
|
||||
// emptyViewHandler.attachToRecyclerView(recyclerView)
|
||||
emptyViewHandler.setIcon(R.drawable.ic_playlist_play)
|
||||
emptyViewHandler.setTitle(R.string.no_items_header_label)
|
||||
emptyViewHandler.setMessage(R.string.no_items_label)
|
||||
// emptyViewHandler.updateAdapter(adapter)
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
|
@ -612,10 +609,10 @@ import kotlin.math.max
|
|||
|
||||
@UnstableApi private fun toggleQueueLock() {
|
||||
val isLocked: Boolean = isQueueLocked
|
||||
if (isLocked) setQueueLocked(false)
|
||||
if (isLocked) setQueueLock(false)
|
||||
else {
|
||||
val shouldShowLockWarning: Boolean = prefs!!.getBoolean(PREF_SHOW_LOCK_WARNING, true)
|
||||
if (!shouldShowLockWarning) setQueueLocked(true)
|
||||
if (!shouldShowLockWarning) setQueueLock(true)
|
||||
else {
|
||||
val builder = MaterialAlertDialogBuilder(requireContext())
|
||||
builder.setTitle(R.string.lock_queue)
|
||||
|
@ -628,7 +625,7 @@ import kotlin.math.max
|
|||
|
||||
builder.setPositiveButton(R.string.lock_queue) { _: DialogInterface?, _: Int ->
|
||||
prefs!!.edit().putBoolean(PREF_SHOW_LOCK_WARNING, !checkDoNotShowAgain.isChecked).apply()
|
||||
setQueueLocked(true)
|
||||
setQueueLock(true)
|
||||
}
|
||||
builder.setNegativeButton(R.string.cancel_label, null)
|
||||
builder.show()
|
||||
|
@ -636,8 +633,10 @@ import kotlin.math.max
|
|||
}
|
||||
}
|
||||
|
||||
@UnstableApi private fun setQueueLocked(locked: Boolean) {
|
||||
@UnstableApi private fun setQueueLock(locked: Boolean) {
|
||||
isQueueLocked = locked
|
||||
appPrefs.edit().putBoolean(UserPreferences.Prefs.prefQueueLocked.name, locked).apply()
|
||||
dragDropEnabled = !(isQueueKeepSorted || isQueueLocked)
|
||||
refreshMenuItems()
|
||||
// adapter?.updateDragDropEnabled()
|
||||
|
||||
|
@ -677,7 +676,7 @@ import kotlin.math.max
|
|||
loadItemsRunning = true
|
||||
Logd(TAG, "loadCurQueue() called ${curQueue.name}")
|
||||
while (curQueue.name.isEmpty()) runBlocking { delay(100) }
|
||||
if (queueItems.isNotEmpty()) emptyViewHandler.hide()
|
||||
// if (queueItems.isNotEmpty()) emptyViewHandler.hide()
|
||||
queueItems.clear()
|
||||
vms.clear()
|
||||
if (showBin) queueItems.addAll(realm.query(Episode::class, "id IN $0", curQueue.idsBinList)
|
||||
|
@ -748,7 +747,6 @@ import kotlin.math.max
|
|||
val TAG = QueuesFragment::class.simpleName ?: "Anonymous"
|
||||
|
||||
private const val KEY_UP_ARROW = "up_arrow"
|
||||
|
||||
private const val PREFS = "QueueFragment"
|
||||
private const val PREF_SHOW_LOCK_WARNING = "show_lock_warning"
|
||||
|
||||
|
|
|
@ -36,10 +36,7 @@ import androidx.compose.foundation.combinedClickable
|
|||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
@ -272,19 +269,30 @@ class SearchFragment : Fragment() {
|
|||
@Composable
|
||||
fun CriteriaList() {
|
||||
val textColor = MaterialTheme.colorScheme.onSurface
|
||||
NonlazyGrid(columns = 2, itemCount = SearchBy.entries.size) { index ->
|
||||
val c = SearchBy.entries[index]
|
||||
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(start = 10.dp, end = 10.dp)) {
|
||||
var isChecked by remember { mutableStateOf(true) }
|
||||
Checkbox(
|
||||
checked = isChecked,
|
||||
onCheckedChange = { newValue ->
|
||||
c.selected = newValue
|
||||
isChecked = newValue
|
||||
}
|
||||
)
|
||||
Spacer(modifier = Modifier.width(2.dp))
|
||||
Text(stringResource(c.nameRes), color = textColor)
|
||||
var showGrid by remember { mutableStateOf(false) }
|
||||
Column {
|
||||
Row {
|
||||
Button(onClick = {showGrid = !showGrid}) {
|
||||
Text(stringResource(R.string.show_criteria))
|
||||
}
|
||||
Button(onClick = { searchOnline() }) {
|
||||
Text(stringResource(R.string.search_online))
|
||||
}
|
||||
}
|
||||
if (showGrid) NonlazyGrid(columns = 2, itemCount = SearchBy.entries.size) { index ->
|
||||
val c = SearchBy.entries[index]
|
||||
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(start = 10.dp, end = 10.dp)) {
|
||||
var isChecked by remember { mutableStateOf(true) }
|
||||
Checkbox(
|
||||
checked = isChecked,
|
||||
onCheckedChange = { newValue ->
|
||||
c.selected = newValue
|
||||
isChecked = newValue
|
||||
}
|
||||
)
|
||||
Spacer(modifier = Modifier.width(2.dp))
|
||||
Text(stringResource(c.nameRes), color = textColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1155,21 +1155,73 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
}
|
||||
} else {
|
||||
Column(modifier = Modifier.padding(start = 5.dp, bottom = 2.dp).fillMaxWidth()) {
|
||||
Text(stringResource(item.nameRes) + " :", fontWeight = FontWeight.Bold, style = MaterialTheme.typography.headlineSmall, color = textColor)
|
||||
NonlazyGrid(columns = 3, itemCount = item.values.size) { index ->
|
||||
var selected by remember { mutableStateOf(false) }
|
||||
if (selectNone) selected = false
|
||||
val selectedList = remember { MutableList(item.values.size) { mutableStateOf(false)} }
|
||||
var expandRow by remember { mutableStateOf(false) }
|
||||
Row {
|
||||
Text(stringResource(item.nameRes) + ".. :", fontWeight = FontWeight.Bold, style = MaterialTheme.typography.headlineSmall, color = textColor, modifier = Modifier.clickable {
|
||||
expandRow = !expandRow
|
||||
})
|
||||
var lowerSelected by remember { mutableStateOf(false) }
|
||||
var higherSelected by remember { mutableStateOf(false) }
|
||||
Spacer(Modifier.weight(1f))
|
||||
if (expandRow) Text("<<<", color = if (lowerSelected) Color.Green else textColor, style = MaterialTheme.typography.headlineSmall, modifier = Modifier.clickable {
|
||||
val hIndex = selectedList.indexOfLast { it.value }
|
||||
if (hIndex < 0) return@clickable
|
||||
if (!lowerSelected) {
|
||||
for (i in 0..hIndex) selectedList[i].value = true
|
||||
} else {
|
||||
for (i in 0..hIndex) selectedList[i].value = false
|
||||
selectedList[hIndex].value = true
|
||||
}
|
||||
lowerSelected = !lowerSelected
|
||||
for (i in item.values.indices) {
|
||||
if (selectedList[i].value) filterValues.add(item.values[i].filterId)
|
||||
else filterValues.remove(item.values[i].filterId)
|
||||
}
|
||||
onFilterChanged(filterValues)
|
||||
})
|
||||
Spacer(Modifier.weight(1f))
|
||||
if (expandRow) Text("X", color = textColor, style = MaterialTheme.typography.headlineSmall, modifier = Modifier.clickable {
|
||||
lowerSelected = false
|
||||
higherSelected = false
|
||||
for (i in item.values.indices) {
|
||||
selectedList[i].value = false
|
||||
filterValues.remove(item.values[i].filterId)
|
||||
}
|
||||
onFilterChanged(filterValues)
|
||||
})
|
||||
Spacer(Modifier.weight(1f))
|
||||
if (expandRow) Text(">>>", color = if (higherSelected) Color.Green else textColor, style = MaterialTheme.typography.headlineSmall, modifier = Modifier.clickable {
|
||||
val lIndex = selectedList.indexOfFirst { it.value }
|
||||
if (lIndex < 0) return@clickable
|
||||
if (!higherSelected) {
|
||||
for (i in lIndex..item.values.size - 1) selectedList[i].value = true
|
||||
} else {
|
||||
for (i in lIndex..item.values.size - 1) selectedList[i].value = false
|
||||
selectedList[lIndex].value = true
|
||||
}
|
||||
higherSelected = !higherSelected
|
||||
for (i in item.values.indices) {
|
||||
if (selectedList[i].value) filterValues.add(item.values[i].filterId)
|
||||
else filterValues.remove(item.values[i].filterId)
|
||||
}
|
||||
onFilterChanged(filterValues)
|
||||
})
|
||||
Spacer(Modifier.weight(1f))
|
||||
}
|
||||
if (expandRow) NonlazyGrid(columns = 3, itemCount = item.values.size) { index ->
|
||||
if (selectNone) selectedList[index].value = false
|
||||
LaunchedEffect(Unit) {
|
||||
if (filter != null) {
|
||||
if (item.values[index].filterId in filter.properties) selected = true
|
||||
if (item.values[index].filterId in filter.properties) selectedList[index].value = true
|
||||
}
|
||||
}
|
||||
OutlinedButton(modifier = Modifier.padding(0.dp).heightIn(min = 20.dp).widthIn(min = 20.dp).wrapContentWidth(),
|
||||
border = BorderStroke(2.dp, if (selected) Color.Green else textColor),
|
||||
border = BorderStroke(2.dp, if (selectedList[index].value) Color.Green else textColor),
|
||||
onClick = {
|
||||
selectNone = false
|
||||
selected = !selected
|
||||
if (selected) filterValues.add(item.values[index].filterId)
|
||||
selectedList[index].value = !selectedList[index].value
|
||||
if (selectedList[index].value) filterValues.add(item.values[index].filterId)
|
||||
else filterValues.remove(item.values[index].filterId)
|
||||
onFilterChanged(filterValues)
|
||||
},
|
||||
|
|
|
@ -47,6 +47,10 @@ object ShareUtils {
|
|||
shareLink(context, text)
|
||||
}
|
||||
|
||||
fun shareFeedLinkNew(context: Context, feed: Feed) {
|
||||
shareLink(context, feed.downloadUrl?:"")
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun hasLinkToShare(item: Episode?): Boolean {
|
||||
return item?.getLinkWithFallback() != null
|
||||
|
|
|
@ -419,6 +419,7 @@
|
|||
<string name="duration">Duration</string>
|
||||
<string name="episode_title">Episode title</string>
|
||||
<string name="feed_title">Podcast title</string>
|
||||
<string name="show_criteria">Show criteria</string>
|
||||
<string name="title">Title</string>
|
||||
<string name="author">Author</string>
|
||||
<string name="random">Random</string>
|
||||
|
|
13
changelog.md
13
changelog.md
|
@ -1,3 +1,16 @@
|
|||
# 6.12.6
|
||||
|
||||
* in SearchFragment, made search criteria options are togglable, and added back search online option
|
||||
* further enhanced filtering routines
|
||||
* categories with multi-selections are expandable/collapsable
|
||||
* once expanded, added three icons: <<<, X, >>>
|
||||
* tapping on <<< will select all lower items, >>> all higher items, X to clear selection in the category
|
||||
* manual sorting of Queues is back.
|
||||
* The way to enable/disable it, uncheck/check "Lock queue" in menu
|
||||
* if "Lock queue" doesn't appear, top "Sort" in the menu and then, uncheck "Keep sorted" in the popup
|
||||
* in episodes lists, swipe dialog shows up when the swipe has not been configured
|
||||
* changed the info shared from FeedInfo and FeedEpisodes, now it shares simply the download url of the feed
|
||||
|
||||
# 6.12.5
|
||||
|
||||
* fixed a long-standing issue in the play apk where rewind/forward buttons don't work during cast
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
Version 6.12.6
|
||||
|
||||
* in SearchFragment, made search criteria options are togglable, and added back search online option
|
||||
* further enhanced filtering routines
|
||||
* categories with multi-selections are expandable/collapsable
|
||||
* once expanded, added three icons: <<<, X, >>>
|
||||
* tapping on <<< will select all lower items, >>> all higher items, X to clear selection in the category
|
||||
* manual sorting of Queues is back.
|
||||
* The way to enable/disable it, uncheck/check "Lock queue" in menu
|
||||
* if "Lock queue" doesn't appear, top "Sort" in the menu and then, uncheck "Keep sorted" in the popup
|
||||
* in episodes lists, swipe dialog shows up when the swipe has not been configured
|
||||
* changed the info shared from FeedInfo and FeedEpisodes, now it shares simply the download url of the feed
|
Loading…
Reference in New Issue