Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for styling lines and shapes in Select One from Map questions #6083

Merged
merged 23 commits into from
Apr 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
d182ce6
Reworked the MappableSelectItem class to introduce diffrent types of …
grzesiek2010 Apr 10, 2024
78c06ad
Factored out toColorInt ext method to make using in other places easier
grzesiek2010 Apr 11, 2024
ee23c55
Support setting custom fill color for polygons
grzesiek2010 Apr 11, 2024
826bfeb
Added tests
grzesiek2010 Apr 11, 2024
859e372
Support setting custom stroke color for lines
grzesiek2010 Apr 11, 2024
77c9b13
Added tests
grzesiek2010 Apr 11, 2024
6324d53
Support setting custom stroke color for polygons
grzesiek2010 Apr 11, 2024
15cc891
Added tests
grzesiek2010 Apr 11, 2024
1403c0f
Support setting custom stroke width for polygons
grzesiek2010 Apr 11, 2024
ce555d8
Added tests
grzesiek2010 Apr 11, 2024
ed57ec4
Support setting custom stroke width for lines
grzesiek2010 Apr 11, 2024
492ff94
Added tests
grzesiek2010 Apr 11, 2024
e9c037a
Improved using map consts
grzesiek2010 Apr 11, 2024
64ee991
Removed unused parameter
grzesiek2010 Apr 11, 2024
2101968
Adjust line width used in mapbox
grzesiek2010 Apr 11, 2024
a9a3209
Improved reading properties
grzesiek2010 Apr 11, 2024
1c3923c
Code improvements in SelectionSummarySheet
grzesiek2010 Apr 15, 2024
661a60a
Improved catching exceptions
grzesiek2010 Apr 15, 2024
39fc910
Improved shorthandToLonghandHexColor method
grzesiek2010 Apr 15, 2024
ff090ab
Added consts for property names
grzesiek2010 Apr 15, 2024
4e891de
Make using stroke width in mapbox clear
grzesiek2010 Apr 15, 2024
e86f531
Improved using DEFAULT_STROKE_COLOR
grzesiek2010 Apr 15, 2024
aea9dd2
Code improvements
grzesiek2010 Apr 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.odk.collect.androidshared.utils

import android.graphics.Color
import androidx.annotation.ColorInt

@ColorInt
fun String.toColorInt() = try {
var sanitizedColor = if (this.startsWith("#")) {
this
} else {
"#$this"
}

if (sanitizedColor.length == 4) {
sanitizedColor = shorthandToLonghandHexColor(sanitizedColor)
}

Color.parseColor(sanitizedColor)
} catch (e: IllegalArgumentException) {
null
}

private fun shorthandToLonghandHexColor(shorthandColor: String): String {
return shorthandColor.substring(1).fold("#") { accum, char ->
"$accum$char$char"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package org.odk.collect.androidshared.utils

import androidx.test.ext.junit.runners.AndroidJUnit4
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.equalTo
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class ColorUtilsTest {
@Test
fun `return null when color is empty`() {
assertThat("".toColorInt(), equalTo(null))
}

@Test
fun `return null when color is blank`() {
assertThat(" ".toColorInt(), equalTo(null))
}

@Test
fun `return null when color is invalid`() {
assertThat("qwerty".toColorInt(), equalTo(null))
}

@Test
fun `return color int for valid hex color with # prefix`() {
assertThat("#aaccee".toColorInt(), equalTo(-5583634))
}

@Test
fun `return color int for valid hex color without # prefix`() {
assertThat("aaccee".toColorInt(), equalTo(-5583634))
}

@Test
fun `return color int for valid shorthand hex color with # prefix`() {
assertThat("#ace".toColorInt(), equalTo(-5583634))
}

@Test
fun `return color int for valid shorthand hex color without # prefix`() {
assertThat("ace".toColorInt(), equalTo(-5583634))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package org.odk.collect.android.support
import android.os.Handler
import android.os.Looper
import androidx.fragment.app.Fragment
import org.odk.collect.maps.LineDescription
import org.odk.collect.maps.MapFragment
import org.odk.collect.maps.MapPoint
import org.odk.collect.maps.PolygonDescription
import org.odk.collect.maps.markers.MarkerDescription
import org.odk.collect.maps.markers.MarkerIconDescription

Expand Down Expand Up @@ -57,16 +59,12 @@ class FakeClickableMapFragment : Fragment(), MapFragment {
return MapPoint(0.0, 0.0)
}

override fun addPolyLine(
points: MutableIterable<MapPoint>,
closed: Boolean,
draggable: Boolean
): Int {
override fun addPolyLine(lineDescription: LineDescription): Int {
return -1
}

override fun addPolygon(points: MutableIterable<MapPoint>): Int {
return addPolyLine(points, closed = true, draggable = false)
override fun addPolygon(polygonDescription: PolygonDescription): Int {
return -1
}

override fun appendPointToPolyLine(featureId: Int, point: MapPoint) {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,12 +115,12 @@ class FormMapViewModel(
)

val info = "$instanceLastStatusChangeDate\n${dateFormat.format(instance.deletedDate)}"
MappableSelectItem(
MappableSelectItem.MappableSelectPoint(
instance.dbId,
listOf(MapPoint(latitude, longitude)),
getDrawableIdForStatus(instance.status, false),
getDrawableIdForStatus(instance.status, true),
instance.displayName,
point = MapPoint(latitude, longitude),
smallIcon = getDrawableIdForStatus(instance.status, false),
largeIcon = getDrawableIdForStatus(instance.status, true),
info = info
)
} else if (!instance.canEditWhenComplete() && listOf(
Expand All @@ -130,12 +130,12 @@ class FormMapViewModel(
).contains(instance.status)
) {
val info = "$instanceLastStatusChangeDate\n${resources.getString(org.odk.collect.strings.R.string.cannot_edit_completed_form)}"
MappableSelectItem(
MappableSelectItem.MappableSelectPoint(
instance.dbId,
listOf(MapPoint(latitude, longitude)),
getDrawableIdForStatus(instance.status, false),
getDrawableIdForStatus(instance.status, true),
instance.displayName,
point = MapPoint(latitude, longitude),
smallIcon = getDrawableIdForStatus(instance.status, false),
largeIcon = getDrawableIdForStatus(instance.status, true),
info = info
)
} else {
Expand All @@ -146,12 +146,12 @@ class FormMapViewModel(
createViewAction()
}

MappableSelectItem(
MappableSelectItem.MappableSelectPoint(
instance.dbId,
listOf(MapPoint(latitude, longitude)),
getDrawableIdForStatus(instance.status, false),
getDrawableIdForStatus(instance.status, true),
instance.displayName,
point = MapPoint(latitude, longitude),
smallIcon = getDrawableIdForStatus(instance.status, false),
largeIcon = getDrawableIdForStatus(instance.status, true),
info = instanceLastStatusChangeDate,
action = action,
status = instanceStatusToMappableSelectionItemStatus(instance)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ internal class SelectChoicesMapData(
prompt: FormEntryPrompt
): List<MappableSelectItem> {
return selectChoices.foldIndexed(emptyList()) { index, list, selectChoice ->
val geometry = selectChoice.getChild("geometry")
val geometry = selectChoice.getChild(GEOMETRY)

if (geometry != null) {
try {
Expand All @@ -153,26 +153,57 @@ internal class SelectChoicesMapData(
IconifiedText(null, "${it.first}: ${it.second}")
}

val markerColor =
selectChoice.additionalChildren.firstOrNull { it.first == "marker-color" }?.second
val markerSymbol =
selectChoice.additionalChildren.firstOrNull { it.first == "marker-symbol" }?.second

list + MappableSelectItem(
index.toLong(),
points,
if (markerSymbol == null) org.odk.collect.icons.R.drawable.ic_map_marker_with_hole_small else org.odk.collect.icons.R.drawable.ic_map_marker_small,
if (markerSymbol == null) org.odk.collect.icons.R.drawable.ic_map_marker_with_hole_big else org.odk.collect.icons.R.drawable.ic_map_marker_big,
prompt.getSelectChoiceText(selectChoice),
properties,
selectChoice.index == selectedIndex,
markerColor,
markerSymbol,
action = IconifiedText(
org.odk.collect.icons.R.drawable.ic_save,
resources.getString(org.odk.collect.strings.R.string.select_item)
if (points.size == 1) {
val markerColor =
getPropertyValue(selectChoice, MARKER_COLOR)
val markerSymbol =
getPropertyValue(selectChoice, MARKER_SYMBOL)

list + MappableSelectItem.MappableSelectPoint(
index.toLong(),
prompt.getSelectChoiceText(selectChoice),
properties,
selectChoice.index == selectedIndex,
point = points[0],
smallIcon = if (markerSymbol == null) org.odk.collect.icons.R.drawable.ic_map_marker_with_hole_small else org.odk.collect.icons.R.drawable.ic_map_marker_small,
largeIcon = if (markerSymbol == null) org.odk.collect.icons.R.drawable.ic_map_marker_with_hole_big else org.odk.collect.icons.R.drawable.ic_map_marker_big,
color = markerColor,
symbol = markerSymbol,
action = IconifiedText(
org.odk.collect.icons.R.drawable.ic_save,
resources.getString(org.odk.collect.strings.R.string.select_item)
)
)
)
} else if (points.first() != points.last()) {
list + MappableSelectItem.MappableSelectLine(
index.toLong(),
prompt.getSelectChoiceText(selectChoice),
properties,
selectChoice.index == selectedIndex,
points = points,
action = IconifiedText(
org.odk.collect.icons.R.drawable.ic_save,
resources.getString(org.odk.collect.strings.R.string.select_item)
),
strokeWidth = getPropertyValue(selectChoice, STROKE_WIDTH),
strokeColor = getPropertyValue(selectChoice, STROKE)
)
} else {
list + MappableSelectItem.MappableSelectPolygon(
index.toLong(),
prompt.getSelectChoiceText(selectChoice),
properties,
selectChoice.index == selectedIndex,
points = points,
action = IconifiedText(
org.odk.collect.icons.R.drawable.ic_save,
resources.getString(org.odk.collect.strings.R.string.select_item)
),
strokeWidth = getPropertyValue(selectChoice, STROKE_WIDTH),
strokeColor = getPropertyValue(selectChoice, STROKE),
fillColor = getPropertyValue(selectChoice, FILL)
)
}
} else {
list
}
Expand All @@ -188,6 +219,10 @@ internal class SelectChoicesMapData(
}
}

private fun getPropertyValue(selectChoice: SelectChoice, propertyName: String): String? {
return selectChoice.additionalChildren.firstOrNull { it.first == propertyName }?.second
}

override fun isLoading(): NonNullLiveData<Boolean> {
return isLoading
}
Expand All @@ -207,4 +242,13 @@ internal class SelectChoicesMapData(
override fun getMappableItems(): LiveData<List<MappableSelectItem>?> {
return items
}

companion object PropertyNames {
const val GEOMETRY = "geometry"
const val MARKER_COLOR = "marker-color"
const val MARKER_SYMBOL = "marker-symbol"
const val STROKE = "stroke"
const val STROKE_WIDTH = "stroke-width"
const val FILL = "fill"
}
}
Loading