feat: ui haptics
This commit is contained in:
@@ -9,6 +9,7 @@
|
|||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
|
||||||
<uses-permission android:name="android.permission.NFC" />
|
<uses-permission android:name="android.permission.NFC" />
|
||||||
|
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||||
|
|
||||||
<uses-feature android:name="android.hardware.camera" android:required="false" />
|
<uses-feature android:name="android.hardware.camera" android:required="false" />
|
||||||
<uses-feature android:name="android.hardware.nfc" android:required="false" />
|
<uses-feature android:name="android.hardware.nfc" android:required="false" />
|
||||||
|
|||||||
@@ -58,10 +58,14 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import com.bitcointxoko.gudariwallet.LocalAppStrings
|
import com.bitcointxoko.gudariwallet.LocalAppStrings
|
||||||
import com.bitcointxoko.gudariwallet.ui.ReceiveState
|
import com.bitcointxoko.gudariwallet.ui.ReceiveState
|
||||||
|
import com.bitcointxoko.gudariwallet.ui.SendState
|
||||||
import com.bitcointxoko.gudariwallet.ui.WalletViewModel
|
import com.bitcointxoko.gudariwallet.ui.WalletViewModel
|
||||||
import com.bitcointxoko.gudariwallet.ui.components.UnitWheelPicker
|
import com.bitcointxoko.gudariwallet.ui.components.UnitWheelPicker
|
||||||
import com.bitcointxoko.gudariwallet.ui.nfc.NfcViewModel
|
import com.bitcointxoko.gudariwallet.ui.nfc.NfcViewModel
|
||||||
|
import com.bitcointxoko.gudariwallet.util.buildUpTaps
|
||||||
|
import com.bitcointxoko.gudariwallet.util.doubleTap
|
||||||
import com.bitcointxoko.gudariwallet.util.fiatLabel
|
import com.bitcointxoko.gudariwallet.util.fiatLabel
|
||||||
|
import com.bitcointxoko.gudariwallet.util.heavyClick
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -107,6 +111,14 @@ fun ReceiveScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(receiveState) {
|
||||||
|
when (receiveState) {
|
||||||
|
is ReceiveState.PaymentReceived -> context.buildUpTaps()
|
||||||
|
// is SendState.Error -> context.errorBuzz()
|
||||||
|
else -> Unit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Box(modifier = Modifier.fillMaxSize()) {
|
Box(modifier = Modifier.fillMaxSize()) {
|
||||||
if (receiveState !is ReceiveState.InvoiceReady) {
|
if (receiveState !is ReceiveState.InvoiceReady) {
|
||||||
Column(
|
Column(
|
||||||
|
|||||||
@@ -31,8 +31,10 @@ import com.bitcointxoko.gudariwallet.ui.WalletViewModel
|
|||||||
import com.bitcointxoko.gudariwallet.ui.nfc.NfcViewModel
|
import com.bitcointxoko.gudariwallet.ui.nfc.NfcViewModel
|
||||||
import com.bitcointxoko.gudariwallet.ui.receive.AmountDisplay
|
import com.bitcointxoko.gudariwallet.ui.receive.AmountDisplay
|
||||||
import com.bitcointxoko.gudariwallet.util.SendInputDetector
|
import com.bitcointxoko.gudariwallet.util.SendInputDetector
|
||||||
|
import com.bitcointxoko.gudariwallet.util.doubleTap
|
||||||
import com.bitcointxoko.gudariwallet.util.feePpm
|
import com.bitcointxoko.gudariwallet.util.feePpm
|
||||||
import com.bitcointxoko.gudariwallet.util.fiatLabel
|
import com.bitcointxoko.gudariwallet.util.fiatLabel
|
||||||
|
import com.bitcointxoko.gudariwallet.util.heavyClick
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@@ -82,6 +84,16 @@ fun SendScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(sendState) {
|
||||||
|
when (sendState) {
|
||||||
|
is SendState.Bolt11Decoded,
|
||||||
|
is SendState.LnurlInvoiceReady -> context.doubleTap()
|
||||||
|
is SendState.PaymentSent -> context.heavyClick()
|
||||||
|
// is SendState.Error -> context.errorBuzz()
|
||||||
|
else -> Unit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package com.bitcointxoko.gudariwallet.util
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.*
|
||||||
|
|
||||||
|
fun Context.heavyClick() {
|
||||||
|
val vibrator = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
|
(getSystemService(VibratorManager::class.java)).defaultVibrator
|
||||||
|
} else {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
|
||||||
|
}
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
|
vibrator.vibrate(VibrationEffect.createPredefined(VibrationEffect.EFFECT_HEAVY_CLICK))
|
||||||
|
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
vibrator.vibrate(VibrationEffect.createOneShot(50L, VibrationEffect.DEFAULT_AMPLITUDE))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.doubleTap() {
|
||||||
|
val vibrator = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
|
(getSystemService(VibratorManager::class.java)).defaultVibrator
|
||||||
|
} else {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
|
||||||
|
}
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
|
vibrator.vibrate(VibrationEffect.createPredefined(VibrationEffect.EFFECT_DOUBLE_CLICK))
|
||||||
|
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
vibrator.vibrate(VibrationEffect.createOneShot(50L, VibrationEffect.DEFAULT_AMPLITUDE))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.buildUpTaps() {
|
||||||
|
val vibrator = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
|
(getSystemService(VibratorManager::class.java)).defaultVibrator
|
||||||
|
} else {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
// Timings: off, on, off, on, off, on, off, FINAL ON
|
||||||
|
val timings = longArrayOf(0, 30, 80, 30, 50, 30, 20, 60)
|
||||||
|
val amplitudes = intArrayOf(0, 60, 0, 90, 0, 140, 0, 255)
|
||||||
|
// ^gap ^tap ^gap ^tap ^gap ^tap ^gap ^THUD
|
||||||
|
|
||||||
|
vibrator.vibrate(VibrationEffect.createWaveform(timings, amplitudes, -1))
|
||||||
|
} else {
|
||||||
|
// Legacy fallback — simple triple-tap
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
vibrator.vibrate(longArrayOf(0, 40, 60, 40, 40, 80), -1)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user