11package com.jamesfrench.nothingcalculator
22
3+ import android.os.Build
4+ import android.os.VibrationEffect
5+ import androidx.annotation.RequiresApi
36import androidx.compose.animation.animateColorAsState
47import androidx.compose.animation.core.EaseIn
58import androidx.compose.animation.core.EaseOut
@@ -21,8 +24,11 @@ import androidx.compose.foundation.layout.wrapContentHeight
2124import androidx.compose.foundation.shape.RoundedCornerShape
2225import androidx.compose.material3.Text
2326import androidx.compose.runtime.Composable
27+ import androidx.compose.runtime.LaunchedEffect
2428import androidx.compose.runtime.getValue
29+ import androidx.compose.runtime.mutableStateOf
2530import androidx.compose.runtime.remember
31+ import androidx.compose.runtime.setValue
2632import androidx.compose.ui.Alignment
2733import androidx.compose.ui.Modifier
2834import androidx.compose.ui.draw.drawBehind
@@ -31,6 +37,7 @@ import androidx.compose.ui.geometry.Offset
3137import androidx.compose.ui.geometry.Size
3238import androidx.compose.ui.graphics.Color
3339import androidx.compose.ui.hapticfeedback.HapticFeedbackType
40+ import androidx.compose.ui.platform.LocalContext
3441import androidx.compose.ui.platform.LocalHapticFeedback
3542import androidx.compose.ui.res.stringResource
3643import androidx.compose.ui.text.font.FontFamily
@@ -46,38 +53,39 @@ import com.jamesfrench.nothingcalculator.ui.theme.SqueezedDeepWhite
4653import com.jamesfrench.nothingcalculator.ui.theme.SqueezedNothingRed
4754import com.jamesfrench.nothingcalculator.ui.theme.ndot77
4855import com.jamesfrench.nothingcalculator.ui.theme.notosans
56+ import android.os.Vibrator
4957
50- data class KeysValue (val symbol : Any , val category : String , val background : Color , val font : FontFamily , val weight : Float , val value : Any = symbol)
58+ data class KeysValue (val symbol : Any , val category : String , val background : Color , val font : FontFamily , val weight : Float , val number_of_pulses : Int , val value : Any = symbol)
5159
5260private val KeysValues = listOf (
5361 listOf (
54- KeysValue (" (" , " number" , NothingRed , ndot77, 1f , " (" ),
55- KeysValue (" %" , " suffix" ,NothingRed , ndot77, 1f ),
56- KeysValue (" ÷" , " operator" ,NothingRed , ndot77, 1f , " /" ),
57- KeysValue (" ×" , " operator" ,NothingRed , ndot77, 1f , " *" )
62+ KeysValue (" (" , " number" , NothingRed , ndot77, 1f , 1 , " (" ),
63+ KeysValue (" %" , " suffix" ,NothingRed , ndot77, 1f , 1 ),
64+ KeysValue (" ÷" , " operator" ,NothingRed , ndot77, 1f , 1 , " /" ),
65+ KeysValue (" ×" , " operator" ,NothingRed , ndot77, 1f , 1 , " *" )
5866 ),
5967 listOf (
60- KeysValue (" 7" , " number" ,ContrastedGray , notosans, 1f ),
61- KeysValue (" 8" , " number" ,ContrastedGray , notosans, 1f ),
62- KeysValue (" 9" , " number" ,ContrastedGray , notosans, 1f ),
63- KeysValue (" –" , " negative" ,NothingRed , ndot77, 1f , " -" )
68+ KeysValue (" 7" , " number" ,ContrastedGray , notosans, 1f , 1 ),
69+ KeysValue (" 8" , " number" ,ContrastedGray , notosans, 1f , 1 ),
70+ KeysValue (" 9" , " number" ,ContrastedGray , notosans, 1f , 1 ),
71+ KeysValue (" –" , " negative" ,NothingRed , ndot77, 1f , 1 , " -" )
6472 ),
6573 listOf (
66- KeysValue (" 4" , " number" ,ContrastedGray , notosans, 1f ),
67- KeysValue (" 5" , " number" ,ContrastedGray , notosans, 1f ),
68- KeysValue (" 6" , " number" ,ContrastedGray , notosans, 1f ),
69- KeysValue (" +" , " operator" ,NothingRed , ndot77, 1f )
74+ KeysValue (" 4" , " number" ,ContrastedGray , notosans, 1f , 1 ),
75+ KeysValue (" 5" , " number" ,ContrastedGray , notosans, 1f , 1 ),
76+ KeysValue (" 6" , " number" ,ContrastedGray , notosans, 1f , 1 ),
77+ KeysValue (" +" , " operator" ,NothingRed , ndot77, 1f , 1 )
7078 ),
7179 listOf (
72- KeysValue (" 1" , " number" ,ContrastedGray , notosans, 1f ),
73- KeysValue (" 2" , " number" ,ContrastedGray , notosans, 1f ),
74- KeysValue (" 3" , " number" ,ContrastedGray , notosans, 1f ),
75- KeysValue (R .string.decimal, " number" ,NothingRed , ndot77, 1f , " ." )
80+ KeysValue (" 1" , " number" ,ContrastedGray , notosans, 1f , 1 ),
81+ KeysValue (" 2" , " number" ,ContrastedGray , notosans, 1f , 1 ),
82+ KeysValue (" 3" , " number" ,ContrastedGray , notosans, 1f , 1 ),
83+ KeysValue (R .string.decimal, " number" ,NothingRed , ndot77, 1f , 1 , " ." )
7684 ),
7785 listOf (
78- KeysValue (" 0" , " number" ,ContrastedGray , notosans, 2f ),
79- KeysValue (" <" , " del" ,DeepWhite , ndot77, 1f ),
80- KeysValue (" =" , " equal" ,NothingRed , ndot77, 1f )
86+ KeysValue (" 0" , " number" ,ContrastedGray , notosans, 2f , 1 ),
87+ KeysValue (" <" , " del" ,DeepWhite , ndot77, 1f , 1 ),
88+ KeysValue (" =" , " equal" ,NothingRed , ndot77, 1f , 3 )
8189 )
8290)
8391
@@ -92,8 +100,9 @@ fun squeezedColor(color: Color): Color {
92100 return squeezedColor
93101}
94102
103+ @RequiresApi(Build .VERSION_CODES .O )
95104@Composable
96- fun Key (viewModel : SharedViewModel , text : String , value : String , category : String , background : Color , foreground : Color , font : FontFamily , modifier : Modifier = Modifier ) {
105+ fun Key (viewModel : SharedViewModel , text : String , value : String , category : String , background : Color , foreground : Color , font : FontFamily , number_of_pulses : Int , modifier : Modifier = Modifier ) {
97106 val haptic = LocalHapticFeedback .current
98107 val interactionSource = remember { MutableInteractionSource () }
99108 val isPressed = interactionSource.collectIsPressedAsState().value
@@ -116,6 +125,31 @@ fun Key(viewModel: SharedViewModel, text: String, value: String, category: Strin
116125 tween(150 , easing = EaseIn )
117126 )
118127
128+ var hapticEngine by remember { mutableStateOf<VibrationEffect ?>(null ) }
129+ val context = LocalContext .current
130+
131+ // https://medium.com/@jpmtech/haptics-in-jetpack-compose-06ac8adaf985
132+ // May change the code when i'm a bit more advanced in programming apps
133+ LaunchedEffect (key1 = Unit ) {
134+ val numberOfPulses = number_of_pulses // Number of increasing haptic pulses
135+ val pulseDuration = 20L // Duration of each pulse in milliseconds
136+ val spaceBetweenPulses = 20L // Duration of space between pulses in milliseconds
137+ val maxAmplitude = 255 // Maximum amplitude for the last pulse
138+
139+ val timings = LongArray (numberOfPulses * 2 ) // Double the size for on/off
140+ val amplitudes = IntArray (numberOfPulses * 2 )
141+
142+ for (i in 0 until numberOfPulses) {
143+ val amplitude = (maxAmplitude * (i + 1 ) / numberOfPulses) // Calculate increasing amplitude
144+ timings[i * 2 ] = spaceBetweenPulses // Space before the pulse
145+ timings[i * 2 + 1 ] = pulseDuration // Duration of the pulse
146+ amplitudes[i * 2 ] = 0 // Amplitude of the space
147+ amplitudes[i * 2 + 1 ] = amplitude // Amplitude of the pulse
148+ }
149+
150+ hapticEngine = VibrationEffect .createWaveform(timings, amplitudes, - 1 )
151+ }
152+
119153 Box (
120154 modifier = modifier
121155 .drawBehind {
@@ -136,7 +170,11 @@ fun Key(viewModel: SharedViewModel, text: String, value: String, category: Strin
136170 onClickLabel = null ,
137171 role = null ,
138172 onClick = {
139- haptic.performHapticFeedback(HapticFeedbackType .LongPress )
173+ // haptic.performHapticFeedback(HapticFeedbackType.LongPress)
174+ hapticEngine?.let {
175+ val vibrator = context.getSystemService(Vibrator ::class .java)
176+ vibrator.vibrate(it)
177+ }
140178 viewModel.keyPressed(value)
141179 }
142180 ),
@@ -194,6 +232,7 @@ fun KeysRows(viewModel: SharedViewModel, number: Int) {
194232 key.background,
195233 if (key.background == DeepWhite ) DeepBlack else DeepWhite ,
196234 key.font,
235+ key.number_of_pulses,
197236 modifier = Modifier
198237 .weight(key.weight)
199238 .aspectRatio(1f * key.weight)
0 commit comments