Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import io.github.sds100.keymapper.base.utils.ui.compose.SimpleListItemGroup
import io.github.sds100.keymapper.base.utils.ui.compose.SimpleListItemModel
import io.github.sds100.keymapper.base.utils.ui.showDialog
import io.github.sds100.keymapper.common.utils.Orientation
import io.github.sds100.keymapper.common.utils.PhysicalOrientation
import io.github.sds100.keymapper.common.utils.State
import io.github.sds100.keymapper.system.camera.CameraLens
import javax.inject.Inject
Expand Down Expand Up @@ -131,6 +132,8 @@ class ChooseConstraintViewModel @Inject constructor(

ConstraintId.SCREEN_OFF -> returnResult.emit(ConstraintData.ScreenOff)

ConstraintId.SCREEN_ORIENTATION -> onSelectScreenOrientationConstraint()

ConstraintId.ORIENTATION_PORTRAIT ->
returnResult.emit(ConstraintData.OrientationPortrait)

Expand All @@ -157,6 +160,36 @@ class ChooseConstraintViewModel @Inject constructor(
ConstraintData.OrientationCustom(orientation = Orientation.ORIENTATION_270),
)

ConstraintId.PHYSICAL_ORIENTATION -> onSelectPhysicalOrientationConstraint()

ConstraintId.PHYSICAL_ORIENTATION_PORTRAIT ->
returnResult.emit(
ConstraintData.PhysicalOrientationConstraint(
physicalOrientation = PhysicalOrientation.PORTRAIT,
),
)

ConstraintId.PHYSICAL_ORIENTATION_LANDSCAPE ->
returnResult.emit(
ConstraintData.PhysicalOrientationConstraint(
physicalOrientation = PhysicalOrientation.LANDSCAPE,
),
)

ConstraintId.PHYSICAL_ORIENTATION_PORTRAIT_INVERTED ->
returnResult.emit(
ConstraintData.PhysicalOrientationConstraint(
physicalOrientation = PhysicalOrientation.PORTRAIT_INVERTED,
),
)

ConstraintId.PHYSICAL_ORIENTATION_LANDSCAPE_INVERTED ->
returnResult.emit(
ConstraintData.PhysicalOrientationConstraint(
physicalOrientation = PhysicalOrientation.LANDSCAPE_INVERTED,
),
)

ConstraintId.FLASHLIGHT_ON -> {
val lens = chooseFlashlightLens() ?: return@launch
returnResult.emit(ConstraintData.FlashlightOn(lens = lens))
Expand Down Expand Up @@ -251,8 +284,76 @@ class ChooseConstraintViewModel @Inject constructor(
return cameraLens
}

private suspend fun onSelectScreenOrientationConstraint() {
val items = listOf(
ConstraintId.ORIENTATION_PORTRAIT to
getString(R.string.constraint_choose_orientation_portrait),
ConstraintId.ORIENTATION_LANDSCAPE to
getString(R.string.constraint_choose_orientation_landscape),
ConstraintId.ORIENTATION_0 to getString(R.string.constraint_choose_orientation_0),
ConstraintId.ORIENTATION_90 to getString(R.string.constraint_choose_orientation_90),
ConstraintId.ORIENTATION_180 to getString(R.string.constraint_choose_orientation_180),
ConstraintId.ORIENTATION_270 to getString(R.string.constraint_choose_orientation_270),
)

val dialog = DialogModel.SingleChoice(items)
val selectedOrientation = showDialog("choose_screen_orientation", dialog) ?: return

val constraintData = when (selectedOrientation) {
ConstraintId.ORIENTATION_PORTRAIT -> ConstraintData.OrientationPortrait
ConstraintId.ORIENTATION_LANDSCAPE -> ConstraintData.OrientationLandscape
ConstraintId.ORIENTATION_0 ->
ConstraintData.OrientationCustom(orientation = Orientation.ORIENTATION_0)
ConstraintId.ORIENTATION_90 ->
ConstraintData.OrientationCustom(orientation = Orientation.ORIENTATION_90)
ConstraintId.ORIENTATION_180 ->
ConstraintData.OrientationCustom(orientation = Orientation.ORIENTATION_180)
ConstraintId.ORIENTATION_270 ->
ConstraintData.OrientationCustom(orientation = Orientation.ORIENTATION_270)
else -> return
}

returnResult.emit(constraintData)
}

private suspend fun onSelectPhysicalOrientationConstraint() {
val items = listOf(
PhysicalOrientation.PORTRAIT to
getString(R.string.constraint_choose_physical_orientation_portrait),
PhysicalOrientation.LANDSCAPE to
getString(R.string.constraint_choose_physical_orientation_landscape),
PhysicalOrientation.PORTRAIT_INVERTED to
getString(R.string.constraint_choose_physical_orientation_portrait_inverted),
PhysicalOrientation.LANDSCAPE_INVERTED to
getString(R.string.constraint_choose_physical_orientation_landscape_inverted),
)

val dialog = DialogModel.SingleChoice(items)
val selectedOrientation = showDialog("choose_physical_orientation", dialog) ?: return

returnResult.emit(
ConstraintData.PhysicalOrientationConstraint(physicalOrientation = selectedOrientation),
)
}

private fun buildListGroups(): List<SimpleListItemGroup> = buildList {
val listItems = buildListItems(ConstraintId.entries)
// Filter out individual orientation constraints - show only the consolidated ones
val filteredConstraints = ConstraintId.entries.filter { constraintId ->
constraintId !in listOf(
ConstraintId.ORIENTATION_PORTRAIT,
ConstraintId.ORIENTATION_LANDSCAPE,
ConstraintId.ORIENTATION_0,
ConstraintId.ORIENTATION_90,
ConstraintId.ORIENTATION_180,
ConstraintId.ORIENTATION_270,
ConstraintId.PHYSICAL_ORIENTATION_PORTRAIT,
ConstraintId.PHYSICAL_ORIENTATION_LANDSCAPE,
ConstraintId.PHYSICAL_ORIENTATION_PORTRAIT_INVERTED,
ConstraintId.PHYSICAL_ORIENTATION_LANDSCAPE_INVERTED,
)
}

val listItems = buildListItems(filteredConstraints)

for (category in CATEGORY_ORDER) {
val header = getString(ConstraintUtils.getCategoryLabel(category))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.github.sds100.keymapper.base.constraints

import io.github.sds100.keymapper.common.utils.Orientation
import io.github.sds100.keymapper.common.utils.PhysicalOrientation
import io.github.sds100.keymapper.common.utils.getKey
import io.github.sds100.keymapper.common.utils.valueOrNull
import io.github.sds100.keymapper.data.entities.ConstraintEntity
Expand Down Expand Up @@ -87,6 +88,18 @@ sealed class ConstraintData {
}
}

@Serializable
data class PhysicalOrientationConstraint(
val physicalOrientation: PhysicalOrientation,
) : ConstraintData() {
override val id: ConstraintId = when (physicalOrientation) {
PhysicalOrientation.PORTRAIT -> ConstraintId.PHYSICAL_ORIENTATION_PORTRAIT
PhysicalOrientation.LANDSCAPE -> ConstraintId.PHYSICAL_ORIENTATION_LANDSCAPE
PhysicalOrientation.PORTRAIT_INVERTED -> ConstraintId.PHYSICAL_ORIENTATION_PORTRAIT_INVERTED
PhysicalOrientation.LANDSCAPE_INVERTED -> ConstraintId.PHYSICAL_ORIENTATION_LANDSCAPE_INVERTED
}
}

@Serializable
data class FlashlightOn(val lens: CameraLens) : ConstraintData() {
override val id: ConstraintId = ConstraintId.FLASHLIGHT_ON
Expand Down Expand Up @@ -316,6 +329,15 @@ object ConstraintEntityMapper {
ConstraintEntity.ORIENTATION_PORTRAIT -> ConstraintData.OrientationPortrait
ConstraintEntity.ORIENTATION_LANDSCAPE -> ConstraintData.OrientationLandscape

ConstraintEntity.PHYSICAL_ORIENTATION_PORTRAIT ->
ConstraintData.PhysicalOrientationConstraint(PhysicalOrientation.PORTRAIT)
ConstraintEntity.PHYSICAL_ORIENTATION_LANDSCAPE ->
ConstraintData.PhysicalOrientationConstraint(PhysicalOrientation.LANDSCAPE)
ConstraintEntity.PHYSICAL_ORIENTATION_PORTRAIT_INVERTED ->
ConstraintData.PhysicalOrientationConstraint(PhysicalOrientation.PORTRAIT_INVERTED)
ConstraintEntity.PHYSICAL_ORIENTATION_LANDSCAPE_INVERTED ->
ConstraintData.PhysicalOrientationConstraint(PhysicalOrientation.LANDSCAPE_INVERTED)

ConstraintEntity.SCREEN_OFF -> ConstraintData.ScreenOff
ConstraintEntity.SCREEN_ON -> ConstraintData.ScreenOn

Expand Down Expand Up @@ -499,6 +521,25 @@ object ConstraintEntityMapper {
ConstraintEntity.ORIENTATION_PORTRAIT,
)

is ConstraintData.PhysicalOrientationConstraint -> when (constraint.data.physicalOrientation) {
PhysicalOrientation.PORTRAIT -> ConstraintEntity(
uid = constraint.uid,
ConstraintEntity.PHYSICAL_ORIENTATION_PORTRAIT,
)
PhysicalOrientation.LANDSCAPE -> ConstraintEntity(
uid = constraint.uid,
ConstraintEntity.PHYSICAL_ORIENTATION_LANDSCAPE,
)
PhysicalOrientation.PORTRAIT_INVERTED -> ConstraintEntity(
uid = constraint.uid,
ConstraintEntity.PHYSICAL_ORIENTATION_PORTRAIT_INVERTED,
)
PhysicalOrientation.LANDSCAPE_INVERTED -> ConstraintEntity(
uid = constraint.uid,
ConstraintEntity.PHYSICAL_ORIENTATION_LANDSCAPE_INVERTED,
)
}

is ConstraintData.ScreenOff -> ConstraintEntity(
uid = constraint.uid,
ConstraintEntity.SCREEN_OFF,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ enum class ConstraintDependency {
CONNECTED_BT_DEVICES,
SCREEN_STATE,
DISPLAY_ORIENTATION,
PHYSICAL_ORIENTATION,
FLASHLIGHT_STATE,
WIFI_SSID,
WIFI_STATE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,20 @@ enum class ConstraintId {
SCREEN_ON,
SCREEN_OFF,

SCREEN_ORIENTATION,
ORIENTATION_PORTRAIT,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot rename all these to DISPLAY_ORIENTATION_*. Do not add constraintids for general SCREEN_ORIENTATION and PHYSICAL_ORIENTATION. Refactor the ChooseConstraintViewModel to still only show the 2 orientation list items, and no more.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in f1a7566. Renamed all orientation constraints to DISPLAY_ORIENTATION_*. Removed SCREEN_ORIENTATION and PHYSICAL_ORIENTATION ConstraintIds. The ChooseConstraintViewModel now uses synthetic list item IDs (display_orientation, physical_orientation) for the consolidated items in the UI, while still showing only the 2 orientation entries.

ORIENTATION_LANDSCAPE,
ORIENTATION_0,
ORIENTATION_90,
ORIENTATION_180,
ORIENTATION_270,

PHYSICAL_ORIENTATION,
PHYSICAL_ORIENTATION_PORTRAIT,
PHYSICAL_ORIENTATION_LANDSCAPE,
PHYSICAL_ORIENTATION_PORTRAIT_INVERTED,
PHYSICAL_ORIENTATION_LANDSCAPE_INVERTED,

FLASHLIGHT_ON,
FLASHLIGHT_OFF,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.media.AudioManager
import android.os.Build
import io.github.sds100.keymapper.base.system.accessibility.IAccessibilityService
import io.github.sds100.keymapper.common.utils.Orientation
import io.github.sds100.keymapper.common.utils.PhysicalOrientation
import io.github.sds100.keymapper.common.utils.firstBlocking
import io.github.sds100.keymapper.system.bluetooth.BluetoothDeviceInfo
import io.github.sds100.keymapper.system.camera.CameraAdapter
Expand Down Expand Up @@ -43,6 +44,7 @@ class LazyConstraintSnapshot(
devicesAdapter.connectedBluetoothDevices.value
}
private val orientation: Orientation by lazy { displayAdapter.cachedOrientation }
private val physicalOrientation: PhysicalOrientation by lazy { displayAdapter.cachedPhysicalOrientation }
private val isScreenOn: Boolean by lazy { displayAdapter.isScreenOn.firstBlocking() }
private val appsPlayingMedia: List<String> by lazy {
mediaAdapter.getActiveMediaSessionPackages()
Expand Down Expand Up @@ -117,6 +119,9 @@ class LazyConstraintSnapshot(
orientation == Orientation.ORIENTATION_0 ||
orientation == Orientation.ORIENTATION_180

is ConstraintData.PhysicalOrientationConstraint ->
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Just call it ConstraintData.PhysicalOrientation

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in f1a7566. Renamed ConstraintData.PhysicalOrientationConstraint to ConstraintData.PhysicalOrientation.

physicalOrientation == constraint.data.physicalOrientation

is ConstraintData.ScreenOff -> !isScreenOn
is ConstraintData.ScreenOn -> isScreenOn
is ConstraintData.FlashlightOff -> !cameraAdapter.isFlashlightOn(constraint.data.lens)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import io.github.sds100.keymapper.base.R
import io.github.sds100.keymapper.base.utils.ui.ResourceProvider
import io.github.sds100.keymapper.base.utils.ui.compose.ComposeIconInfo
import io.github.sds100.keymapper.common.utils.Orientation
import io.github.sds100.keymapper.common.utils.PhysicalOrientation
import io.github.sds100.keymapper.common.utils.TimeUtils
import io.github.sds100.keymapper.common.utils.handle
import io.github.sds100.keymapper.common.utils.valueIfFailure
Expand Down Expand Up @@ -82,6 +83,21 @@ class ConstraintUiHelper(
is ConstraintData.OrientationPortrait ->
getString(R.string.constraint_choose_orientation_portrait)

is ConstraintData.PhysicalOrientationConstraint -> {
val resId = when (constraint.data.physicalOrientation) {
PhysicalOrientation.PORTRAIT ->
R.string.constraint_choose_physical_orientation_portrait
PhysicalOrientation.LANDSCAPE ->
R.string.constraint_choose_physical_orientation_landscape
PhysicalOrientation.PORTRAIT_INVERTED ->
R.string.constraint_choose_physical_orientation_portrait_inverted
PhysicalOrientation.LANDSCAPE_INVERTED ->
R.string.constraint_choose_physical_orientation_landscape_inverted
}

getString(resId)
}

is ConstraintData.ScreenOff ->
getString(R.string.constraint_screen_off_description)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,18 @@ object ConstraintUtils {

ConstraintId.SCREEN_ON,
ConstraintId.SCREEN_OFF,
ConstraintId.SCREEN_ORIENTATION,
ConstraintId.ORIENTATION_PORTRAIT,
ConstraintId.ORIENTATION_LANDSCAPE,
ConstraintId.ORIENTATION_0,
ConstraintId.ORIENTATION_90,
ConstraintId.ORIENTATION_180,
ConstraintId.ORIENTATION_270,
ConstraintId.PHYSICAL_ORIENTATION,
ConstraintId.PHYSICAL_ORIENTATION_PORTRAIT,
ConstraintId.PHYSICAL_ORIENTATION_LANDSCAPE,
ConstraintId.PHYSICAL_ORIENTATION_PORTRAIT_INVERTED,
ConstraintId.PHYSICAL_ORIENTATION_LANDSCAPE_INVERTED,
-> ConstraintCategory.DISPLAY

ConstraintId.FLASHLIGHT_ON,
Expand Down Expand Up @@ -127,6 +133,7 @@ object ConstraintUtils {
Icons.Outlined.BluetoothDisabled,
)

ConstraintId.SCREEN_ORIENTATION,
ConstraintId.ORIENTATION_0,
ConstraintId.ORIENTATION_180,
-> ComposeIconInfo.Vector(Icons.Outlined.StayCurrentPortrait)
Expand All @@ -142,6 +149,15 @@ object ConstraintUtils {
Icons.Outlined.StayCurrentPortrait,
)

ConstraintId.PHYSICAL_ORIENTATION,
ConstraintId.PHYSICAL_ORIENTATION_PORTRAIT,
ConstraintId.PHYSICAL_ORIENTATION_PORTRAIT_INVERTED,
-> ComposeIconInfo.Vector(Icons.Outlined.StayCurrentPortrait)

ConstraintId.PHYSICAL_ORIENTATION_LANDSCAPE,
ConstraintId.PHYSICAL_ORIENTATION_LANDSCAPE_INVERTED,
-> ComposeIconInfo.Vector(Icons.Outlined.StayCurrentLandscape)

ConstraintId.SCREEN_OFF -> ComposeIconInfo.Vector(Icons.Outlined.MobileOff)
ConstraintId.SCREEN_ON -> ComposeIconInfo.Vector(Icons.Outlined.StayCurrentPortrait)

Expand Down Expand Up @@ -194,12 +210,22 @@ object ConstraintUtils {
R.string.constraint_choose_bluetooth_device_disconnected
ConstraintId.SCREEN_ON -> R.string.constraint_choose_screen_on_description
ConstraintId.SCREEN_OFF -> R.string.constraint_choose_screen_off_description
ConstraintId.SCREEN_ORIENTATION -> R.string.constraint_choose_screen_orientation
ConstraintId.ORIENTATION_PORTRAIT -> R.string.constraint_choose_orientation_portrait
ConstraintId.ORIENTATION_LANDSCAPE -> R.string.constraint_choose_orientation_landscape
ConstraintId.ORIENTATION_0 -> R.string.constraint_choose_orientation_0
ConstraintId.ORIENTATION_90 -> R.string.constraint_choose_orientation_90
ConstraintId.ORIENTATION_180 -> R.string.constraint_choose_orientation_180
ConstraintId.ORIENTATION_270 -> R.string.constraint_choose_orientation_270
ConstraintId.PHYSICAL_ORIENTATION -> R.string.constraint_choose_physical_orientation
ConstraintId.PHYSICAL_ORIENTATION_PORTRAIT ->
R.string.constraint_choose_physical_orientation_portrait
ConstraintId.PHYSICAL_ORIENTATION_LANDSCAPE ->
R.string.constraint_choose_physical_orientation_landscape
ConstraintId.PHYSICAL_ORIENTATION_PORTRAIT_INVERTED ->
R.string.constraint_choose_physical_orientation_portrait_inverted
ConstraintId.PHYSICAL_ORIENTATION_LANDSCAPE_INVERTED ->
R.string.constraint_choose_physical_orientation_landscape_inverted
ConstraintId.FLASHLIGHT_ON -> R.string.constraint_flashlight_on
ConstraintId.FLASHLIGHT_OFF -> R.string.constraint_flashlight_off
ConstraintId.WIFI_ON -> R.string.constraint_wifi_on
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ class DetectConstraintsUseCaseImpl @AssistedInject constructor(
ConstraintDependency.SCREEN_STATE -> displayAdapter.isScreenOn.map { dependency }
ConstraintDependency.DISPLAY_ORIENTATION ->
displayAdapter.orientation.map { dependency }
ConstraintDependency.PHYSICAL_ORIENTATION ->
displayAdapter.physicalOrientation.map { dependency }
ConstraintDependency.FLASHLIGHT_STATE -> merge(
cameraAdapter.isFlashlightOnFlow(CameraLens.FRONT),
cameraAdapter.isFlashlightOnFlow(CameraLens.BACK),
Expand Down
6 changes: 6 additions & 0 deletions base/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,12 @@
<string name="constraint_choose_orientation_270">Landscape (270°)</string>
<string name="constraint_choose_orientation_portrait">Portrait (any)</string>
<string name="constraint_choose_orientation_landscape">Landscape (any)</string>
<string name="constraint_choose_screen_orientation">Screen orientation</string>
<string name="constraint_choose_physical_orientation">Physical orientation</string>
<string name="constraint_choose_physical_orientation_portrait">Physical: Portrait</string>
<string name="constraint_choose_physical_orientation_landscape">Physical: Landscape</string>
<string name="constraint_choose_physical_orientation_portrait_inverted">Physical: Portrait (upside down)</string>
<string name="constraint_choose_physical_orientation_landscape_inverted">Physical: Landscape (inverted)</string>
<string name="constraint_choose_app_playing_media">App playing media</string>
<string name="constraint_choose_app_not_playing_media">App not playing media</string>
<string name="constraint_choose_media_playing">Media is playing</string>
Expand Down
Loading