Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import io.github.sds100.keymapper.base.actions.ChooseActionScreen
import io.github.sds100.keymapper.base.actions.ChooseActionViewModel
import io.github.sds100.keymapper.base.actions.ConfigCreateNotificationViewModel
import io.github.sds100.keymapper.base.actions.ConfigShellCommandViewModel
import io.github.sds100.keymapper.base.actions.CreateNotificationActionScreen
import io.github.sds100.keymapper.base.actions.ShellCommandActionScreen
import io.github.sds100.keymapper.base.actions.uielement.InteractUiElementScreen
import io.github.sds100.keymapper.base.actions.uielement.InteractUiElementViewModel
Expand Down Expand Up @@ -89,6 +91,19 @@ fun BaseMainNavHost(
)
}

composable<NavDestination.ConfigNotificationAction> { backStackEntry ->
val viewModel: ConfigCreateNotificationViewModel = hiltViewModel()

backStackEntry.handleRouteArgs<NavDestination.ConfigNotificationAction> { destination ->
destination.actionJson?.let { viewModel.loadAction(Json.decodeFromString(it)) }
}

CreateNotificationActionScreen(
modifier = Modifier.fillMaxSize(),
viewModel = viewModel,
)
}

composable<NavDestination.ChooseConstraint> {
val viewModel: ChooseConstraintViewModel = hiltViewModel()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -871,6 +871,20 @@ sealed class ActionData : Comparable<ActionData> {
override val id: ActionId = ActionId.DISMISS_ALL_NOTIFICATIONS
}

@Serializable
data class CreateNotification(
val title: String,
val text: String,
val timeoutMs: Long?,
) : ActionData() {
override val id: ActionId = ActionId.CREATE_NOTIFICATION

override fun compareTo(other: ActionData) = when (other) {
is CreateNotification -> title.compareTo(other.title)
else -> super.compareTo(other)
}
}

@Serializable
data object AnswerCall : ActionData() {
override val id: ActionId = ActionId.ANSWER_PHONE_CALL
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ object ActionDataEntityMapper {

ActionEntity.Type.INTERACT_UI_ELEMENT -> ActionId.INTERACT_UI_ELEMENT
ActionEntity.Type.SHELL_COMMAND -> ActionId.SHELL_COMMAND
ActionEntity.Type.CREATE_NOTIFICATION -> ActionId.CREATE_NOTIFICATION
}

return when (actionId) {
Expand Down Expand Up @@ -556,6 +557,22 @@ object ActionDataEntityMapper {
ActionId.SHOW_POWER_MENU -> ActionData.ShowPowerMenu
ActionId.DISMISS_MOST_RECENT_NOTIFICATION -> ActionData.DismissLastNotification
ActionId.DISMISS_ALL_NOTIFICATIONS -> ActionData.DismissAllNotifications
ActionId.CREATE_NOTIFICATION -> {
val title = entity.extras.getData(ActionEntity.EXTRA_NOTIFICATION_TITLE).valueOrNull()
?: return null

val text = entity.data.takeIf { it.isNotBlank() }
?: return null

val timeoutMs = entity.extras.getData(ActionEntity.EXTRA_NOTIFICATION_TIMEOUT).valueOrNull()
?.toLongOrNull()

ActionData.CreateNotification(
title = title,
text = text,
timeoutMs = timeoutMs,
)
}
ActionId.ANSWER_PHONE_CALL -> ActionData.AnswerCall
ActionId.END_PHONE_CALL -> ActionData.EndCall
ActionId.DEVICE_CONTROLS -> ActionData.DeviceControls
Expand Down Expand Up @@ -749,6 +766,7 @@ object ActionDataEntityMapper {
is ActionData.Sound -> ActionEntity.Type.SOUND
is ActionData.InteractUiElement -> ActionEntity.Type.INTERACT_UI_ELEMENT
is ActionData.ShellCommand -> ActionEntity.Type.SHELL_COMMAND
is ActionData.CreateNotification -> ActionEntity.Type.CREATE_NOTIFICATION
else -> ActionEntity.Type.SYSTEM_ACTION
}

Expand Down Expand Up @@ -819,6 +837,7 @@ object ActionDataEntityMapper {
data.command.toByteArray(),
Base64.DEFAULT,
).trim() // Trim to remove trailing newline added by Base64.DEFAULT
is ActionData.CreateNotification -> data.text
is ActionData.HttpRequest -> SYSTEM_ACTION_ID_MAP[data.id]!!
is ActionData.ControlMediaForApp.Rewind -> SYSTEM_ACTION_ID_MAP[data.id]!!
is ActionData.ControlMediaForApp.Stop -> SYSTEM_ACTION_ID_MAP[data.id]!!
Expand Down Expand Up @@ -1105,6 +1124,13 @@ object ActionDataEntityMapper {
EntityExtra(ActionEntity.EXTRA_SHELL_COMMAND_TIMEOUT, data.timeoutMillis.toString()),
)

is ActionData.CreateNotification -> buildList {
add(EntityExtra(ActionEntity.EXTRA_NOTIFICATION_TITLE, data.title))
data.timeoutMs?.let {
add(EntityExtra(ActionEntity.EXTRA_NOTIFICATION_TIMEOUT, it.toString()))
}
}

else -> emptyList()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ enum class ActionId {

DISMISS_MOST_RECENT_NOTIFICATION,
DISMISS_ALL_NOTIFICATIONS,
CREATE_NOTIFICATION,

ANSWER_PHONE_CALL,
END_PHONE_CALL,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ object ActionUtils {

ActionId.DISMISS_MOST_RECENT_NOTIFICATION -> ActionCategory.NOTIFICATIONS
ActionId.DISMISS_ALL_NOTIFICATIONS -> ActionCategory.NOTIFICATIONS
ActionId.CREATE_NOTIFICATION -> ActionCategory.NOTIFICATIONS
ActionId.DEVICE_CONTROLS -> ActionCategory.APPS

ActionId.INTERACT_UI_ELEMENT -> ActionCategory.APPS
Expand Down Expand Up @@ -373,6 +374,7 @@ object ActionUtils {
ActionId.DISMISS_MOST_RECENT_NOTIFICATION ->
R.string.action_dismiss_most_recent_notification
ActionId.DISMISS_ALL_NOTIFICATIONS -> R.string.action_dismiss_all_notifications
ActionId.CREATE_NOTIFICATION -> R.string.action_create_notification
ActionId.ANSWER_PHONE_CALL -> R.string.action_answer_call
ActionId.END_PHONE_CALL -> R.string.action_end_call
ActionId.SEND_SMS -> R.string.action_send_sms
Expand Down Expand Up @@ -500,6 +502,7 @@ object ActionUtils {
ActionId.SOUND -> R.drawable.ic_outline_volume_up_24
ActionId.DISMISS_MOST_RECENT_NOTIFICATION -> R.drawable.ic_baseline_clear_all_24
ActionId.DISMISS_ALL_NOTIFICATIONS -> R.drawable.ic_baseline_clear_all_24
ActionId.CREATE_NOTIFICATION -> R.drawable.ic_notification_play
ActionId.ANSWER_PHONE_CALL -> R.drawable.ic_outline_call_24
ActionId.END_PHONE_CALL -> R.drawable.ic_outline_call_end_24
ActionId.SEND_SMS -> R.drawable.ic_outline_message_24
Expand Down Expand Up @@ -744,6 +747,8 @@ object ActionUtils {
ActionId.DISMISS_MOST_RECENT_NOTIFICATION,
-> return listOf(Permission.NOTIFICATION_LISTENER)

ActionId.CREATE_NOTIFICATION -> return listOf(Permission.POST_NOTIFICATIONS)

ActionId.ANSWER_PHONE_CALL,
ActionId.END_PHONE_CALL,
-> return listOf(Permission.ANSWER_PHONE_CALL)
Expand Down Expand Up @@ -882,6 +887,7 @@ object ActionUtils {
ActionId.SOUND -> Icons.AutoMirrored.Outlined.VolumeUp
ActionId.DISMISS_MOST_RECENT_NOTIFICATION -> Icons.Outlined.ClearAll
ActionId.DISMISS_ALL_NOTIFICATIONS -> Icons.Outlined.ClearAll
ActionId.CREATE_NOTIFICATION -> Icons.AutoMirrored.Outlined.Message
ActionId.ANSWER_PHONE_CALL -> Icons.Outlined.Call
ActionId.END_PHONE_CALL -> Icons.Outlined.CallEnd
ActionId.DEVICE_CONTROLS -> KeyMapperIcons.HomeIotDevice
Expand Down Expand Up @@ -934,6 +940,7 @@ fun ActionData.isEditable(): Boolean = when (this) {
is ActionData.ComposeSms,
is ActionData.HttpRequest,
is ActionData.ShellCommand,
is ActionData.CreateNotification,
is ActionData.InteractUiElement,
is ActionData.MoveCursor,
-> true
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package io.github.sds100.keymapper.base.actions

import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import io.github.sds100.keymapper.base.utils.navigation.NavigationProvider
import io.github.sds100.keymapper.base.utils.navigation.navigate
import javax.inject.Inject

data class CreateNotificationActionState(
val title: String = "",
val text: String = "",
val timeoutEnabled: Boolean = false,
/**
* UI works with seconds for user-friendliness
*/
val timeoutSeconds: Int = 30,
)

@HiltViewModel
class ConfigCreateNotificationViewModel @Inject constructor(
private val navigationProvider: NavigationProvider,
private val createActionDelegate: CreateActionDelegate,
) : ViewModel() {

var state: CreateNotificationActionState by mutableStateOf(CreateNotificationActionState())
private set

fun loadAction(action: ActionData.CreateNotification) {
state = state.copy(
title = action.title,
text = action.text,
timeoutEnabled = action.timeoutMs != null,
timeoutSeconds = (action.timeoutMs ?: 30000) / 1000,
)
}

fun onTitleChanged(newTitle: String) {
state = state.copy(title = newTitle)
}

fun onTextChanged(newText: String) {
state = state.copy(text = newText)
}

fun onTimeoutEnabledChanged(enabled: Boolean) {
state = state.copy(timeoutEnabled = enabled)
}

fun onTimeoutChanged(newTimeoutSeconds: Int) {
state = state.copy(timeoutSeconds = newTimeoutSeconds)
}

fun onDoneClick() {
if (state.title.isBlank() || state.text.isBlank()) {
return
}

val timeoutMs = if (state.timeoutEnabled) {
state.timeoutSeconds * 1000L
} else {
null
}

val action = ActionData.CreateNotification(
title = state.title,
text = state.text,
timeoutMs = timeoutMs,
)

createActionDelegate.actionResult.value = action
navigationProvider.navigate(io.github.sds100.keymapper.base.utils.navigation.NavDestination.Pop)
}

fun onCancelClick() {
navigationProvider.navigate(io.github.sds100.keymapper.base.utils.navigation.NavDestination.Pop)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -884,6 +884,18 @@ class CreateActionDelegate(
ActionId.DISABLE_DND_MODE -> return ActionData.DoNotDisturb.Disable
ActionId.DISMISS_MOST_RECENT_NOTIFICATION -> return ActionData.DismissLastNotification
ActionId.DISMISS_ALL_NOTIFICATIONS -> return ActionData.DismissAllNotifications
ActionId.CREATE_NOTIFICATION -> {
val oldAction = oldData as? ActionData.CreateNotification

return navigate(
"config_create_notification_action",
NavDestination.ConfigNotificationAction(
oldAction?.let {
Json.encodeToString(oldAction)
},
),
)
}
ActionId.ANSWER_PHONE_CALL -> return ActionData.AnswerCall
ActionId.END_PHONE_CALL -> return ActionData.EndCall
ActionId.DEVICE_CONTROLS -> return ActionData.DeviceControls
Expand Down
Loading