/
YamlSwipe.kt
146 lines (132 loc) · 6.27 KB
/
YamlSwipe.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package maestro.orchestra.yaml
import com.fasterxml.jackson.annotation.JsonFormat
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.core.TreeNode
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JsonDeserializer
import com.fasterxml.jackson.databind.MapperFeature
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
import com.fasterxml.jackson.databind.json.JsonMapper
import maestro.SwipeDirection
import maestro.directionValueOfOrNull
@JsonDeserialize(using = YamlSwipeDeserializer::class)
interface YamlSwipe {
val duration: Long
val label: String?
}
data class YamlSwipeDirection(
val direction: SwipeDirection, override val duration: Long = DEFAULT_DURATION_IN_MILLIS,
override val label: String? = null
) : YamlSwipe
data class YamlCoordinateSwipe(val start: String, val end: String, override val duration: Long = DEFAULT_DURATION_IN_MILLIS, override val label: String? = null) : YamlSwipe
data class YamlRelativeCoordinateSwipe(val start: String, val end: String, override val duration: Long = DEFAULT_DURATION_IN_MILLIS, override val label: String? = null) : YamlSwipe
@JsonDeserialize(`as` = YamlSwipeElement::class)
data class YamlSwipeElement(
@JsonFormat(with = [JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES])
val direction: SwipeDirection,
val from: YamlElementSelectorUnion,
override val duration: Long = DEFAULT_DURATION_IN_MILLIS,
override val label: String? = null
) : YamlSwipe
private const val DEFAULT_DURATION_IN_MILLIS = 400L
class YamlSwipeDeserializer : JsonDeserializer<YamlSwipe>() {
override fun deserialize(parser: JsonParser, ctxt: DeserializationContext): YamlSwipe {
val mapper = (parser.codec as ObjectMapper)
val root: TreeNode = mapper.readTree(parser)
val input = root.fieldNames().asSequence().toList()
val duration = getDuration(root)
val label = getLabel(root)
when {
input.contains("start") || input.contains("end") -> {
check(root.get("direction") == null) { "You cannot provide direction with start/end swipe." }
check(root.get("start") != null && root.get("end") != null) {
"You need to provide both start and end coordinates, to swipe with coordinates"
}
return resolveCoordinateSwipe(root, duration, label)
}
input.contains("direction") -> {
check(root.get("start") == null && root.get("end") == null) {
"You cannot provide start/end coordinates with directional swipe"
}
val direction = root.get("direction").toString().replace("\"", "")
check(directionValueOfOrNull<SwipeDirection>(direction) != null) {
"Invalid direction provided to directional swipe: $direction. Direction can be either:\n" +
"1. RIGHT or right\n" +
"2. LEFT or left\n" +
"3. UP or up\n" +
"4. DOWN or down"
}
val isDirectionalSwipe = input == listOf("direction", "duration") || input == listOf("direction")
return if (isDirectionalSwipe) {
YamlSwipeDirection(SwipeDirection.valueOf(direction.uppercase()), duration, label)
} else {
mapper.convertValue(root, YamlSwipeElement::class.java)
}
}
else -> {
throw IllegalArgumentException(
"Swipe command takes either: \n" +
"\t1. direction: Direction based swipe with: \"RIGHT\", \"LEFT\", \"UP\", or \"DOWN\" or \n" +
"\t2. start and end: Coordinates based swipe with: \"start\" and \"end\" coordinates \n" +
"\t3. direction and element to swipe directionally on element\n" +
"It seems you provided invalid input with: $input"
)
}
}
}
private fun resolveCoordinateSwipe(root: TreeNode, duration: Long, label: String?): YamlSwipe {
when {
isRelativeSwipe(root) -> {
val start = root.path("start").toString().replace("\"", "")
val end = root.path("end").toString().replace("\"", "")
check(start.contains("%") && end.contains("%")) {
"You need to provide start and end coordinates with %, Found: (${start}, ${end})"
}
val startPoints = start
.replace("%", "")
.split(",")
.map { it.trim().toInt() }
val endPoints = end
.replace("%", "")
.split(",")
.map { it.trim().toInt() }
check(startPoints[0] in 0..100 && startPoints[1] in 0..100) {
"Invalid start point: $start should be between 0 to 100"
}
check(endPoints[0] in 0..100 && endPoints[1] in 0..100) {
"Invalid start point: $end should be between 0 to 100"
}
return YamlRelativeCoordinateSwipe(
start,
end,
duration,
label,
)
}
else -> return YamlCoordinateSwipe(
root.path("start").toString().replace("\"", ""),
root.path("end").toString().replace("\"", ""),
duration,
label,
)
}
}
private fun isRelativeSwipe(root: TreeNode): Boolean {
return root.get("start").toString().contains("%") || root.get("end").toString().contains("%")
}
private fun getDuration(root: TreeNode): Long {
return if (root.path("duration").isMissingNode) {
DEFAULT_DURATION_IN_MILLIS
} else {
root.path("duration").toString().replace("\"", "").toLong()
}
}
private fun getLabel(root: TreeNode): String? {
return if (root.path("label").isMissingNode) {
null
} else {
root.path("label").toString()
}
}
}