Skip to content

Commit 796f4b3

Browse files
authored
Single tap infrared (#992)
**Background** When pressing infrared buttons anywhere - the signal will be send not once. FW added new request which allows one-time infrared signal send **Changes** - Change EmulateApi with new one-time send **Test plan** - Build firmware from flipperdevices/flipperzero-firmware#4000 - Open flipper app - Open some infrared key - Press key once and see emulating on flipper now shorter - Repeat this step for Infrared Remote Controls
1 parent c2c5394 commit 796f4b3

File tree

15 files changed

+125
-39
lines changed

15 files changed

+125
-39
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- [Feature] Add count subfolders for new file manager
99
- [Feature] Add file downloading for new file manager
1010
- [Feature] Add move-to to new file manager
11+
- [Feature] Single tap for infrared remotes
1112
- [Refactor] Move rename and file create to separated modules
1213
- [Refactor] Improve and refactor new FileManager Editor
1314
- [FIX] Migrate url host from metric.flipperdevices.com to metric.flipp.dev

components/bridge/api/src/main/java/com/flipperdevices/bridge/api/utils/Constants.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ object Constants {
3333
majorVersion = 0,
3434
minorVersion = 21
3535
)
36+
val API_SUPPORTED_INFRARED_PRESS_RELEASE = SemVer(
37+
majorVersion = 0,
38+
minorVersion = 25
39+
)
3640
val API_SUPPORTED_GET_REQUEST = API_SUPPORTED_FLIPPER_ERROR
3741
const val LAGS_FLIPPER_DETECT_TIMEOUT_MS = 10 * 1000L // 10 seconds
3842

components/infrared/impl/src/main/kotlin/com/flipperdevices/infrared/impl/composable/components/ComposableInfraredRemotes.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ private fun KeyScreenState.Ready.toEmulateConfigs(): ImmutableList<EmulateConfig
116116
keyType = FlipperKeyType.INFRARED,
117117
keyPath = this.flipperKey.path,
118118
args = name,
119-
index = index
119+
index = index,
120120
)
121121
}.toImmutableList()
122122
}

components/keyemulate/api/src/main/kotlin/com/flipperdevices/keyemulate/api/EmulateHelper.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@ interface EmulateHelper {
1919

2020
suspend fun stopEmulate(
2121
scope: CoroutineScope,
22-
requestApi: FlipperRequestApi
22+
requestApi: FlipperRequestApi,
23+
isPressRelease: Boolean = false
2324
)
2425

2526
suspend fun stopEmulateForce(
26-
requestApi: FlipperRequestApi
27+
requestApi: FlipperRequestApi,
28+
isPressRelease: Boolean = false
2729
)
2830
}

components/keyemulate/api/src/main/kotlin/com/flipperdevices/keyemulate/model/EmulateConfig.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,17 @@ import com.flipperdevices.bridge.dao.api.model.FlipperKeyType
77
/*
88
Override equals and hashCode to compare emulate key, because emulate time not important
99
*/
10+
/**
11+
* @param isPressRelease one-time emulate for infrared-only
12+
*/
1013
@Immutable
1114
data class EmulateConfig(
1215
val keyType: FlipperKeyType,
1316
val keyPath: FlipperFilePath,
1417
val minEmulateTime: Long? = null,
1518
val args: String? = null,
16-
val index: Int? = null
19+
val index: Int? = null,
20+
val isPressRelease: Boolean = false
1721
) {
1822
override fun equals(other: Any?): Boolean {
1923
if (this === other) return true

components/keyemulate/impl/src/main/java/com/flipperdevices/keyemulate/composable/ComposableInfraredSendButton.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ private fun ComposableActiveStateEmulateInternal(
7979

8080
val buttonActiveModifier = Modifier.onScrollHoldPress(
8181
onTap = {
82-
emulateViewModel.onSinglePress(emulateConfig)
82+
emulateViewModel.onSinglePress(emulateConfig.copy(isPressRelease = true))
8383
},
8484
onLongPressStart = {
8585
emulateViewModel.onStartEmulate(emulateConfig)

components/keyemulate/impl/src/main/java/com/flipperdevices/keyemulate/helpers/EmulateHelperImpl.kt

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ class EmulateHelperImpl @Inject constructor(
8080

8181
override suspend fun stopEmulate(
8282
scope: CoroutineScope,
83-
requestApi: FlipperRequestApi
83+
requestApi: FlipperRequestApi,
84+
isPressRelease: Boolean
8485
) = withLock(mutex, "schedule_stop") {
8586
if (stopJob != null) {
8687
info { "Return from #stopEmulate because stop already in progress" }
@@ -111,17 +112,21 @@ class EmulateHelperImpl @Inject constructor(
111112
}
112113

113114
override suspend fun stopEmulateForce(
114-
requestApi: FlipperRequestApi
115+
requestApi: FlipperRequestApi,
116+
isPressRelease: Boolean
115117
) = withLock(mutex, "force_stop") {
116118
if (stopJob != null) {
117119
stopJob?.cancelAndJoin()
118120
stopJob = null
119121
}
120-
stopEmulateInternal(requestApi)
122+
stopEmulateInternal(requestApi, isPressRelease)
121123
}
122124

123-
private suspend fun stopEmulateInternal(requestApi: FlipperRequestApi) {
124-
stopEmulateHelper.onStop(requestApi)
125+
private suspend fun stopEmulateInternal(
126+
requestApi: FlipperRequestApi,
127+
isPressRelease: Boolean = false
128+
) {
129+
stopEmulateHelper.onStop(requestApi, isPressRelease)
125130
currentKeyEmulating.emit(null)
126131
}
127132
}

components/keyemulate/impl/src/main/java/com/flipperdevices/keyemulate/helpers/StartEmulateHelper.kt

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import com.flipperdevices.keyemulate.model.EmulateConfig
1919
import com.flipperdevices.keyemulate.model.FlipperAppError
2020
import com.flipperdevices.protobuf.Flipper
2121
import com.flipperdevices.protobuf.app.Application
22+
import com.flipperdevices.protobuf.app.appButtonPressReleaseRequest
2223
import com.flipperdevices.protobuf.app.appButtonPressRequest
2324
import com.flipperdevices.protobuf.app.appLoadFileRequest
2425
import com.flipperdevices.protobuf.main
@@ -32,6 +33,7 @@ private const val APP_RETRY_COUNT = 3
3233
private const val APP_RETRY_SLEEP_TIME_MS = 1 * 1000L // 1 second
3334

3435
interface StartEmulateHelper {
36+
@Suppress("LongParameterList")
3537
suspend fun onStart(
3638
scope: CoroutineScope,
3739
serviceApi: FlipperServiceApi,
@@ -97,13 +99,17 @@ class StartEmulateHelperImpl @Inject constructor(
9799
val indexEmulateSupported =
98100
serviceApi.flipperVersionApi.isSupported(Constants.API_SUPPORTED_INFRARED_EMULATE)
99101

102+
val isPressReleaseSupported =
103+
serviceApi.flipperVersionApi.isSupported(Constants.API_SUPPORTED_INFRARED_PRESS_RELEASE)
104+
100105
info { "Support emulate by index: $indexEmulateSupported" }
101106

102107
return processButtonPress(
103108
config = config,
104109
onResultTime = onResultTime,
105110
serviceApi = serviceApi,
106-
isIndexEmulateSupport = indexEmulateSupported
111+
isIndexEmulateSupport = indexEmulateSupported,
112+
isPressReleaseSupported = isPressReleaseSupported
107113
)
108114
}
109115

@@ -115,6 +121,7 @@ class StartEmulateHelperImpl @Inject constructor(
115121
private suspend fun processButtonPress(
116122
config: EmulateConfig,
117123
isIndexEmulateSupport: Boolean,
124+
isPressReleaseSupported: Boolean,
118125
onResultTime: (Long) -> Unit,
119126
serviceApi: FlipperServiceApi
120127
): Boolean {
@@ -125,7 +132,17 @@ class StartEmulateHelperImpl @Inject constructor(
125132
val appButtonPressResponse = serviceApi.requestApi.request(
126133
flowOf(
127134
main {
128-
appButtonPressRequest = getAppButtonPressRequest(config, isIndexEmulateSupport)
135+
if (config.isPressRelease && isPressReleaseSupported) {
136+
appButtonPressReleaseRequest = getAppButtonPressReleaseRequest(
137+
config,
138+
isIndexEmulateSupport
139+
)
140+
} else {
141+
appButtonPressRequest = getAppButtonPressRequest(
142+
config,
143+
isIndexEmulateSupport
144+
)
145+
}
129146
}.wrapToRequest(FlipperRequestPriority.FOREGROUND)
130147
)
131148
)
@@ -164,6 +181,29 @@ class StartEmulateHelperImpl @Inject constructor(
164181
}
165182
}
166183

184+
private fun getAppButtonPressReleaseRequest(
185+
config: EmulateConfig,
186+
isIndexEmulateSupport: Boolean,
187+
): Application.AppButtonPressReleaseRequest {
188+
return when (config.keyType) {
189+
FlipperKeyType.INFRARED -> if (isIndexEmulateSupport) {
190+
val indexArgs = config.index ?: error("Index args is null")
191+
info { "#getAppButtonPressReleaseRequest by index with $config" }
192+
appButtonPressReleaseRequest {
193+
index = indexArgs
194+
}
195+
} else {
196+
val configArgs = config.args ?: error("Config args is null")
197+
info { "#getAppButtonPressReleaseRequest by args with $config" }
198+
appButtonPressReleaseRequest {
199+
args = configArgs
200+
}
201+
}
202+
203+
else -> error("#getAppButtonPressReleaseRequest Unknown button press request with config $config")
204+
}
205+
}
206+
167207
private fun getAppButtonPressRequest(
168208
config: EmulateConfig,
169209
isIndexEmulateSupport: Boolean,
@@ -183,6 +223,7 @@ class StartEmulateHelperImpl @Inject constructor(
183223
args = configArgs
184224
}
185225
}
226+
186227
else -> error("Unknown button press request with config $config")
187228
}
188229
}

components/keyemulate/impl/src/main/java/com/flipperdevices/keyemulate/helpers/StopEmulateHelper.kt

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,29 @@ import kotlinx.coroutines.flow.flowOf
1414
import javax.inject.Inject
1515

1616
interface StopEmulateHelper {
17-
suspend fun onStop(requestApi: FlipperRequestApi)
17+
suspend fun onStop(
18+
requestApi: FlipperRequestApi,
19+
isPressRelease: Boolean = false
20+
)
1821
}
1922

2023
@ContributesBinding(AppGraph::class, StopEmulateHelper::class)
2124
class StopEmulateHelperImpl @Inject constructor() : StopEmulateHelper, LogTagProvider {
2225
override val TAG = "StopEmulateHelper"
2326

24-
override suspend fun onStop(requestApi: FlipperRequestApi) {
27+
override suspend fun onStop(requestApi: FlipperRequestApi, isPressRelease: Boolean) {
2528
info { "stopEmulateInternal" }
2629

27-
val appButtonResponse = requestApi.request(
28-
flowOf(
29-
main {
30-
appButtonReleaseRequest = appButtonReleaseRequest { }
31-
}.wrapToRequest(FlipperRequestPriority.FOREGROUND)
30+
if (!isPressRelease) {
31+
val appButtonResponse = requestApi.request(
32+
flowOf(
33+
main {
34+
appButtonReleaseRequest = appButtonReleaseRequest { }
35+
}.wrapToRequest(FlipperRequestPriority.FOREGROUND)
36+
)
3237
)
33-
)
34-
info { "App button stop response: $appButtonResponse" }
38+
info { "App button stop response: $appButtonResponse" }
39+
}
3540

3641
val appExitResponse = requestApi.request(
3742
flowOf(

0 commit comments

Comments
 (0)