mirror of
https://github.com/LiveFastEatTrashRaccoon/RaccoonForLemmy.git
synced 2025-02-09 10:28:41 +01:00
enhancement: reorderable instance selector (#1045)
This commit is contained in:
parent
136cefaf2a
commit
38eadde947
@ -76,28 +76,30 @@ class SelectInstanceBottomSheet : Screen {
|
||||
var instanceToDelete by remember { mutableStateOf<String?>(null) }
|
||||
|
||||
LaunchedEffect(model) {
|
||||
model.effects.onEach { evt ->
|
||||
when (evt) {
|
||||
SelectInstanceMviModel.Effect.CloseDialog -> {
|
||||
changeInstanceDialogOpen = false
|
||||
}
|
||||
model.effects
|
||||
.onEach { evt ->
|
||||
when (evt) {
|
||||
SelectInstanceMviModel.Effect.CloseDialog -> {
|
||||
changeInstanceDialogOpen = false
|
||||
}
|
||||
|
||||
is SelectInstanceMviModel.Effect.Confirm -> {
|
||||
notificationCenter.send(NotificationCenterEvent.InstanceSelected(evt.instance))
|
||||
navigationCoordinator.hideBottomSheet()
|
||||
is SelectInstanceMviModel.Effect.Confirm -> {
|
||||
notificationCenter.send(NotificationCenterEvent.InstanceSelected(evt.instance))
|
||||
navigationCoordinator.hideBottomSheet()
|
||||
}
|
||||
}
|
||||
}
|
||||
}.launchIn(this)
|
||||
}.launchIn(this)
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier =
|
||||
Modifier.padding(
|
||||
top = Spacing.s,
|
||||
start = Spacing.s,
|
||||
end = Spacing.s,
|
||||
bottom = Spacing.m,
|
||||
).fillMaxHeight(0.6f),
|
||||
Modifier
|
||||
.padding(
|
||||
top = Spacing.s,
|
||||
start = Spacing.s,
|
||||
end = Spacing.s,
|
||||
bottom = Spacing.m,
|
||||
).fillMaxHeight(0.6f),
|
||||
verticalArrangement = Arrangement.spacedBy(Spacing.s),
|
||||
) {
|
||||
Box(
|
||||
@ -158,15 +160,19 @@ class SelectInstanceBottomSheet : Screen {
|
||||
shadowElevation = elevation,
|
||||
) {
|
||||
SelectInstanceItem(
|
||||
modifier = Modifier.draggableHandle(),
|
||||
instance = instance,
|
||||
isActive = isActive,
|
||||
onDragStarted =
|
||||
rememberCallback(model) {
|
||||
model.reduce(SelectInstanceMviModel.Intent.HapticIndication)
|
||||
},
|
||||
onClick =
|
||||
rememberCallback(model) {
|
||||
model.reduce(
|
||||
SelectInstanceMviModel.Intent.SelectInstance(instance),
|
||||
)
|
||||
},
|
||||
reorderableScope = this,
|
||||
options =
|
||||
buildList {
|
||||
if (!isActive) {
|
||||
|
@ -8,13 +8,24 @@ interface SelectInstanceMviModel :
|
||||
MviModel<SelectInstanceMviModel.Intent, SelectInstanceMviModel.State, SelectInstanceMviModel.Effect>,
|
||||
ScreenModel {
|
||||
sealed interface Intent {
|
||||
data class SelectInstance(val value: String) : Intent
|
||||
data class SelectInstance(
|
||||
val value: String,
|
||||
) : Intent
|
||||
|
||||
data class DeleteInstance(val value: String) : Intent
|
||||
data class DeleteInstance(
|
||||
val value: String,
|
||||
) : Intent
|
||||
|
||||
data class ChangeInstanceName(val value: String) : Intent
|
||||
data class ChangeInstanceName(
|
||||
val value: String,
|
||||
) : Intent
|
||||
|
||||
data class SwapIntances(val from: Int, val to: Int) : Intent
|
||||
data object HapticIndication : Intent
|
||||
|
||||
data class SwapIntances(
|
||||
val from: Int,
|
||||
val to: Int,
|
||||
) : Intent
|
||||
|
||||
data object SubmitChangeInstanceDialog : Intent
|
||||
}
|
||||
@ -30,6 +41,8 @@ interface SelectInstanceMviModel :
|
||||
sealed interface Effect {
|
||||
data object CloseDialog : Effect
|
||||
|
||||
data class Confirm(val instance: String) : Effect
|
||||
data class Confirm(
|
||||
val instance: String,
|
||||
) : Effect
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import cafe.adriel.voyager.core.model.screenModelScope
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.repository.InstanceSelectionRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.ValidationError
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.vibrate.HapticFeedback
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.ApiConfigurationRepository
|
||||
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.CommunityRepository
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
@ -18,22 +19,27 @@ class SelectInstanceViewModel(
|
||||
private val instanceRepository: InstanceSelectionRepository,
|
||||
private val communityRepository: CommunityRepository,
|
||||
private val apiConfigurationRepository: ApiConfigurationRepository,
|
||||
) : SelectInstanceMviModel,
|
||||
DefaultMviModel<SelectInstanceMviModel.Intent, SelectInstanceMviModel.State, SelectInstanceMviModel.Effect>(
|
||||
private val hapticFeedback: HapticFeedback,
|
||||
) : DefaultMviModel<SelectInstanceMviModel.Intent, SelectInstanceMviModel.State, SelectInstanceMviModel.Effect>(
|
||||
initialState = SelectInstanceMviModel.State(),
|
||||
) {
|
||||
),
|
||||
SelectInstanceMviModel {
|
||||
private val saveOperationChannel = Channel<List<String>>()
|
||||
|
||||
init {
|
||||
screenModelScope.launch {
|
||||
apiConfigurationRepository.instance.onEach { instance ->
|
||||
updateState { it.copy(currentInstance = instance) }
|
||||
}.launchIn(this)
|
||||
apiConfigurationRepository.instance
|
||||
.onEach { instance ->
|
||||
updateState { it.copy(currentInstance = instance) }
|
||||
}.launchIn(this)
|
||||
|
||||
@OptIn(FlowPreview::class)
|
||||
saveOperationChannel.receiveAsFlow().debounce(500).onEach { newInstances ->
|
||||
instanceRepository.updateAll(newInstances)
|
||||
}.launchIn(this)
|
||||
saveOperationChannel
|
||||
.receiveAsFlow()
|
||||
.debounce(500)
|
||||
.onEach { newInstances ->
|
||||
instanceRepository.updateAll(newInstances)
|
||||
}.launchIn(this)
|
||||
}
|
||||
|
||||
if (uiState.value.instances.isEmpty()) {
|
||||
@ -59,6 +65,7 @@ class SelectInstanceViewModel(
|
||||
is SelectInstanceMviModel.Intent.SubmitChangeInstanceDialog -> submitChangeInstance()
|
||||
is SelectInstanceMviModel.Intent.DeleteInstance -> deleteInstance(intent.value)
|
||||
is SelectInstanceMviModel.Intent.SwapIntances -> swapInstances(intent.from, intent.to)
|
||||
SelectInstanceMviModel.Intent.HapticIndication -> hapticFeedback.vibrate()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,13 +33,16 @@ import com.github.diegoberaldin.raccoonforlemmy.core.commonui.lemmyui.Option
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.lemmyui.OptionId
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.onClick
|
||||
import com.github.diegoberaldin.raccoonforlemmy.core.utils.toLocalDp
|
||||
import sh.calvin.reorderable.ReorderableCollectionItemScope
|
||||
|
||||
@Composable
|
||||
internal fun SelectInstanceItem(
|
||||
modifier: Modifier = Modifier,
|
||||
reorderableScope: ReorderableCollectionItemScope,
|
||||
instance: String,
|
||||
isActive: Boolean = false,
|
||||
onClick: (() -> Unit)? = null,
|
||||
onDragStarted: (() -> Unit)? = null,
|
||||
options: List<Option> = emptyList(),
|
||||
onOptionSelected: ((OptionId) -> Unit)? = null,
|
||||
) {
|
||||
@ -84,10 +87,17 @@ internal fun SelectInstanceItem(
|
||||
Modifier
|
||||
.size(IconSize.m)
|
||||
.padding(Spacing.xs)
|
||||
.onGloballyPositioned {
|
||||
.then(
|
||||
with(reorderableScope) {
|
||||
Modifier.draggableHandle(
|
||||
onDragStarted = {
|
||||
onDragStarted?.invoke()
|
||||
},
|
||||
)
|
||||
},
|
||||
).onGloballyPositioned {
|
||||
optionsOffset = it.positionInParent()
|
||||
}
|
||||
.onClick(
|
||||
}.onClick(
|
||||
onClick = {
|
||||
optionsMenuOpen = true
|
||||
},
|
||||
|
@ -11,6 +11,7 @@ val selectInstanceModule =
|
||||
instanceRepository = get(),
|
||||
communityRepository = get(),
|
||||
apiConfigurationRepository = get(),
|
||||
hapticFeedback = get(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user