Skip to content

Commit 24fcb57

Browse files
authored
Adding a minimum swipe length. Fixes #14 (#22)
1 parent db4088d commit 24fcb57

5 files changed

Lines changed: 124 additions & 39 deletions

File tree

app/src/main/java/com/dessalines/thumbkey/db/AppDb.kt

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import androidx.lifecycle.ViewModel
99
import androidx.lifecycle.ViewModelProvider
1010
import androidx.lifecycle.viewModelScope
1111
import androidx.room.*
12+
import androidx.room.migration.Migration
1213
import androidx.sqlite.db.SupportSQLiteDatabase
1314
import kotlinx.coroutines.launch
1415
import java.util.concurrent.Executors
@@ -23,6 +24,7 @@ const val DEFAULT_THEME = 0
2324
const val DEFAULT_THEME_COLOR = 0
2425
const val DEFAULT_VIBRATE_ON_TAP = 1
2526
const val DEFAULT_SOUND_ON_TAP = 0
27+
const val DEFAULT_MIN_SWIPE_LENGTH = 40
2628

2729
const val UPDATE_APP_CHANGELOG_UNVIEWED = "UPDATE AppSettings SET viewed_changelog = 0"
2830

@@ -83,7 +85,12 @@ data class AppSettings(
8385
name = "viewed_changelog",
8486
defaultValue = "0"
8587
)
86-
val viewedChangelog: Int
88+
val viewedChangelog: Int,
89+
@ColumnInfo(
90+
name = "min_swipe_length",
91+
defaultValue = DEFAULT_MIN_SWIPE_LENGTH.toString()
92+
)
93+
val minSwipeLength: Int
8794
)
8895

8996
@Dao
@@ -117,8 +124,16 @@ class AppSettingsRepository(private val appSettingsDao: AppSettingsDao) {
117124
}
118125
}
119126

127+
val MIGRATION_1_2 = object : Migration(1, 2) {
128+
override fun migrate(database: SupportSQLiteDatabase) {
129+
database.execSQL(
130+
"alter table AppSettings add column min_swipe_length INTEGER NOT NULL default $DEFAULT_MIN_SWIPE_LENGTH"
131+
)
132+
}
133+
}
134+
120135
@Database(
121-
version = 1,
136+
version = 2,
122137
entities = [AppSettings::class],
123138
exportSchema = true
124139
)
@@ -141,9 +156,9 @@ abstract class AppDB : RoomDatabase() {
141156
"thumbkey"
142157
)
143158
.allowMainThreadQueries()
144-
// .addMigrations(
145-
// MIGRATION_1_2,
146-
// )
159+
.addMigrations(
160+
MIGRATION_1_2
161+
)
147162
// Necessary because it can't insert data on creation
148163
.addCallback(object : Callback() {
149164
override fun onOpen(db: SupportSQLiteDatabase) {

app/src/main/java/com/dessalines/thumbkey/ui/components/keyboard/KeyboardKey.kt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,13 @@ fun KeyboardKey(
5959
vibrateOnTap: Boolean,
6060
soundOnTap: Boolean,
6161
keySize: Int,
62+
minSwipeLength: Int,
6263
onToggleShiftMode: (enable: Boolean) -> Unit,
6364
onToggleNumericMode: (enable: Boolean) -> Unit
6465
) {
65-
val id = key.toString() + animationHelperSpeed + animationSpeed + keySize
66+
// Necessary for swipe settings to get updated correctly
67+
val id = key.toString() + animationHelperSpeed + animationSpeed + autoCapitalize + vibrateOnTap + soundOnTap + keySize + minSwipeLength
68+
6669
val ctx = LocalContext.current
6770
val ime = ctx as IMEService
6871
val scope = rememberCoroutineScope()
@@ -147,10 +150,9 @@ fun KeyboardKey(
147150
offsetY += y
148151
},
149152
onDragEnd = {
150-
val swipeDirection = swipeDirection(offsetX, offsetY)
153+
val swipeDirection = swipeDirection(offsetX, offsetY, minSwipeLength)
154+
val action = key.swipes?.get(swipeDirection)?.action ?: key.center.action
151155

152-
val swipeKey = key.swipes?.get(swipeDirection)
153-
val action = swipeKey?.action ?: run { key.center.action }
154156
performKeyAction(
155157
action = action,
156158
ime = ime,

app/src/main/java/com/dessalines/thumbkey/ui/components/keyboard/KeyboardScreen.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import com.dessalines.thumbkey.db.DEFAULT_ANIMATION_SPEED
1515
import com.dessalines.thumbkey.db.DEFAULT_AUTO_CAPITALIZE
1616
import com.dessalines.thumbkey.db.DEFAULT_KEYBOARD_LAYOUT
1717
import com.dessalines.thumbkey.db.DEFAULT_KEY_SIZE
18+
import com.dessalines.thumbkey.db.DEFAULT_MIN_SWIPE_LENGTH
1819
import com.dessalines.thumbkey.db.DEFAULT_POSITION
1920
import com.dessalines.thumbkey.db.DEFAULT_SOUND_ON_TAP
2021
import com.dessalines.thumbkey.db.DEFAULT_VIBRATE_ON_TAP
@@ -76,6 +77,7 @@ fun KeyboardScreen(settings: AppSettings?) {
7677
?: DEFAULT_ANIMATION_SPEED,
7778
animationHelperSpeed = settings?.animationHelperSpeed
7879
?: DEFAULT_ANIMATION_HELPER_SPEED,
80+
minSwipeLength = settings?.minSwipeLength ?: DEFAULT_MIN_SWIPE_LENGTH,
7981
onToggleShiftMode = { enable ->
8082
if (mode !== KeyboardMode.NUMERIC) {
8183
mode = if (enable) {

app/src/main/java/com/dessalines/thumbkey/ui/components/settings/lookandfeel/LookAndFeelActivity.kt

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import com.dessalines.thumbkey.db.DEFAULT_ANIMATION_SPEED
3737
import com.dessalines.thumbkey.db.DEFAULT_AUTO_CAPITALIZE
3838
import com.dessalines.thumbkey.db.DEFAULT_KEYBOARD_LAYOUT
3939
import com.dessalines.thumbkey.db.DEFAULT_KEY_SIZE
40+
import com.dessalines.thumbkey.db.DEFAULT_MIN_SWIPE_LENGTH
4041
import com.dessalines.thumbkey.db.DEFAULT_SOUND_ON_TAP
4142
import com.dessalines.thumbkey.db.DEFAULT_THEME
4243
import com.dessalines.thumbkey.db.DEFAULT_THEME_COLOR
@@ -67,6 +68,9 @@ fun LookAndFeelActivity(
6768
val animationHelperSpeedState = rememberFloatSettingState(
6869
(settings?.animationHelperSpeed ?: DEFAULT_ANIMATION_HELPER_SPEED).toFloat()
6970
)
71+
val minSwipeLengthState = rememberFloatSettingState(
72+
(settings?.minSwipeLength ?: DEFAULT_MIN_SWIPE_LENGTH).toFloat()
73+
)
7074
val positionState = rememberIntSettingState(
7175
settings?.position ?: com.dessalines.thumbkey.db.DEFAULT_POSITION
7276
)
@@ -120,6 +124,7 @@ fun LookAndFeelActivity(
120124
keySizeState,
121125
animationSpeedState,
122126
animationHelperSpeedState,
127+
minSwipeLengthState,
123128
positionState,
124129
vibrateOnTapState,
125130
soundOnTapState,
@@ -148,6 +153,7 @@ fun LookAndFeelActivity(
148153
keySizeState,
149154
animationSpeedState,
150155
animationHelperSpeedState,
156+
minSwipeLengthState,
151157
positionState,
152158
autoCapitalizeState,
153159
vibrateOnTapState,
@@ -176,6 +182,7 @@ fun LookAndFeelActivity(
176182
keySizeState,
177183
animationSpeedState,
178184
animationHelperSpeedState,
185+
minSwipeLengthState,
179186
positionState,
180187
autoCapitalizeState,
181188
vibrateOnTapState,
@@ -204,6 +211,7 @@ fun LookAndFeelActivity(
204211
keySizeState,
205212
animationSpeedState,
206213
animationHelperSpeedState,
214+
minSwipeLengthState,
207215
positionState,
208216
autoCapitalizeState,
209217
vibrateOnTapState,
@@ -231,6 +239,7 @@ fun LookAndFeelActivity(
231239
keySizeState,
232240
animationSpeedState,
233241
animationHelperSpeedState,
242+
minSwipeLengthState,
234243
positionState,
235244
autoCapitalizeState,
236245
vibrateOnTapState,
@@ -258,6 +267,7 @@ fun LookAndFeelActivity(
258267
keySizeState,
259268
animationSpeedState,
260269
animationHelperSpeedState,
270+
minSwipeLengthState,
261271
positionState,
262272
autoCapitalizeState,
263273
vibrateOnTapState,
@@ -285,6 +295,7 @@ fun LookAndFeelActivity(
285295
keySizeState,
286296
animationSpeedState,
287297
animationHelperSpeedState,
298+
minSwipeLengthState,
288299
positionState,
289300
autoCapitalizeState,
290301
vibrateOnTapState,
@@ -313,6 +324,36 @@ fun LookAndFeelActivity(
313324
keySizeState,
314325
animationSpeedState,
315326
animationHelperSpeedState,
327+
minSwipeLengthState,
328+
positionState,
329+
autoCapitalizeState,
330+
vibrateOnTapState,
331+
soundOnTapState,
332+
keyboardLayoutState,
333+
themeState,
334+
themeColorState
335+
)
336+
}
337+
)
338+
SettingsSlider(
339+
valueRange = 0f..200f,
340+
state = minSwipeLengthState,
341+
icon = {
342+
Icon(
343+
imageVector = Icons.Outlined.Swipe,
344+
contentDescription = "TODO"
345+
)
346+
},
347+
title = {
348+
Text(text = "Minimum Swipe Length: ${minSwipeLengthState.value.toInt()}")
349+
},
350+
onValueChangeFinished = {
351+
updateAppSettings(
352+
appSettingsViewModel,
353+
keySizeState,
354+
animationSpeedState,
355+
animationHelperSpeedState,
356+
minSwipeLengthState,
316357
positionState,
317358
autoCapitalizeState,
318359
vibrateOnTapState,
@@ -341,6 +382,7 @@ fun LookAndFeelActivity(
341382
keySizeState,
342383
animationSpeedState,
343384
animationHelperSpeedState,
385+
minSwipeLengthState,
344386
positionState,
345387
autoCapitalizeState,
346388
vibrateOnTapState,
@@ -369,6 +411,7 @@ fun LookAndFeelActivity(
369411
keySizeState,
370412
animationSpeedState,
371413
animationHelperSpeedState,
414+
minSwipeLengthState,
372415
positionState,
373416
autoCapitalizeState,
374417
vibrateOnTapState,
@@ -398,6 +441,7 @@ private fun updateAppSettings(
398441
keySizeState: SettingValueState<Float>,
399442
animationSpeedState: SettingValueState<Float>,
400443
animationHelperSpeedState: SettingValueState<Float>,
444+
minSwipeLengthState: SettingValueState<Float>,
401445
positionState: SettingValueState<Int>,
402446
autoCapitalizeState: SettingValueState<Boolean>,
403447
vibrateOnTapState: SettingValueState<Boolean>,
@@ -412,6 +456,7 @@ private fun updateAppSettings(
412456
keySize = keySizeState.value.toInt(),
413457
animationSpeed = animationSpeedState.value.toInt(),
414458
animationHelperSpeed = animationHelperSpeedState.value.toInt(),
459+
minSwipeLength = minSwipeLengthState.value.toInt(),
415460
position = positionState.value,
416461
autoCapitalize = autoCapitalizeState.value.compareTo(false),
417462
vibrateOnTap = vibrateOnTapState.value.compareTo(false),

app/src/main/java/com/dessalines/thumbkey/utils/Utils.kt

Lines changed: 51 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ import kotlinx.coroutines.CoroutineScope
3333
import kotlinx.coroutines.delay
3434
import kotlinx.coroutines.launch
3535
import kotlin.math.atan2
36+
import kotlin.math.pow
37+
import kotlin.math.sqrt
3638

3739
const val TAG = "com.thumbkey"
3840

@@ -73,39 +75,58 @@ fun keyboardPositionToAlignment(position: KeyboardPosition): Alignment {
7375
}
7476
}
7577

76-
fun swipeDirection(x: Float, y: Float): SwipeDirection {
77-
val angleDir = (atan2(x.toDouble(), y.toDouble()) / Math.PI * 180)
78-
val angle = if (angleDir < 0) {
79-
360 + angleDir
80-
} else {
81-
angleDir
82-
}
78+
/**
79+
* If this doesn't meet the minimum swipe length, it returns null
80+
*/
81+
fun swipeDirection(x: Float, y: Float, minSwipeLength: Int): SwipeDirection? {
82+
val xD = x.toDouble()
83+
val yD = y.toDouble()
8384

84-
return when (angle) {
85-
in 22.5..67.5 -> {
86-
SwipeDirection.BOTTOM_RIGHT
87-
}
88-
in 67.5..112.5 -> {
89-
SwipeDirection.RIGHT
90-
}
91-
in 112.5..157.5 -> {
92-
SwipeDirection.TOP_RIGHT
93-
}
94-
in 157.5..202.5 -> {
95-
SwipeDirection.TOP
96-
}
97-
in 202.5..247.5 -> {
98-
SwipeDirection.TOP_LEFT
99-
}
100-
in 247.5..292.5 -> {
101-
SwipeDirection.LEFT
102-
}
103-
in 292.5..337.5 -> {
104-
SwipeDirection.BOTTOM_LEFT
85+
val swipeLength = sqrt(xD.pow(2) + yD.pow(2))
86+
87+
if (swipeLength > minSwipeLength) {
88+
val angleDir = (atan2(xD, yD) / Math.PI * 180)
89+
val angle = if (angleDir < 0) {
90+
360 + angleDir
91+
} else {
92+
angleDir
10593
}
106-
else -> {
107-
SwipeDirection.BOTTOM
94+
95+
return when (angle) {
96+
in 22.5..67.5 -> {
97+
SwipeDirection.BOTTOM_RIGHT
98+
}
99+
100+
in 67.5..112.5 -> {
101+
SwipeDirection.RIGHT
102+
}
103+
104+
in 112.5..157.5 -> {
105+
SwipeDirection.TOP_RIGHT
106+
}
107+
108+
in 157.5..202.5 -> {
109+
SwipeDirection.TOP
110+
}
111+
112+
in 202.5..247.5 -> {
113+
SwipeDirection.TOP_LEFT
114+
}
115+
116+
in 247.5..292.5 -> {
117+
SwipeDirection.LEFT
118+
}
119+
120+
in 292.5..337.5 -> {
121+
SwipeDirection.BOTTOM_LEFT
122+
}
123+
124+
else -> {
125+
SwipeDirection.BOTTOM
126+
}
108127
}
128+
} else {
129+
return null
109130
}
110131
}
111132

0 commit comments

Comments
 (0)