Skip to content

Commit 6e8a630

Browse files
authored
Add support for Google Maps waypoint names (#324)
And make point list on result screen expandable. Fixes: #317
1 parent e7178fd commit 6e8a630

File tree

44 files changed

+623
-665
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+623
-665
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ Maps etc.)** and retrieve the coordinates from:
112112
- or the whole web page with running JavaScript.
113113

114114
If you don’t allow connecting to the map service, then Geo Share creates a geo:
115-
link with a search term instead of coordinates or it stops, depending on the
115+
link with a search term instead of coordinates, or it stops, depending on the
116116
particular link.
117117

118118
To permanently allow or deny connecting to the map service instead of always

app/src/androidTest/java/page/ooooo/geoshare/BaseActivityBehaviorTest.kt

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -174,17 +174,20 @@ abstract class BaseActivityBehaviorTest {
174174
}
175175
onElement {
176176
if (viewIdResourceName == "geoShareResultSuccessLastPointName") {
177-
val expectedName = expectedPoints.lastOrNull()?.name?.replace('+', ' ')
177+
val expectedName = expectedPoints.lastOrNull()?.cleanName
178178
if (!expectedName.isNullOrEmpty()) {
179179
assertTrue(
180-
"Expected ${textAsString()} to contain '$expectedName'",
180+
"""Expected "${textAsString()}" to contain "$expectedName"""",
181181
textAsString()?.contains(expectedName) == true,
182182
)
183183
} else if (expectedPoints.size > 1) {
184-
assertEquals("point ${expectedPoints.size}", textAsString())
184+
assertTrue(
185+
"""Expected "${textAsString()}" to equal "Last point" or "Dernier point""""",
186+
textAsString() in setOf("Last point", "Dernier point"),
187+
)
185188
} else {
186189
assertTrue(
187-
"Expected ${textAsString()} to equal 'Coordinates' (or a translation)",
190+
@Suppress("SpellCheckingInspection") """Expected "${textAsString()}" to equal "Coordinates" or "Coordonnées""""",
188191
textAsString() in setOf(
189192
"Coordinates", @Suppress("SpellCheckingInspection") "Coordonnées"
190193
),
@@ -206,6 +209,19 @@ abstract class BaseActivityBehaviorTest {
206209
}
207210
}
208211
}
212+
if (expectedPoints.size > 1) {
213+
onElement {
214+
if (viewIdResourceName == "geoShareExpandablePaneHeadline") {
215+
assertTrue(
216+
"""Expected "${textAsString()}" to contain "${expectedPoints.size}"""",
217+
textAsString()?.contains(expectedPoints.size.toString()) == true,
218+
)
219+
true
220+
} else {
221+
false
222+
}
223+
}
224+
}
209225
}
210226

211227
protected fun assertConversionSucceeded(

app/src/androidTest/java/page/ooooo/geoshare/ConversionActivityBehaviorTest.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ class ConversionActivityBehaviorTest : BaseActivityBehaviorTest() {
4848
assertConversionSucceeded(WGS84Point(31.23044166868017, 121.47099209401793, z = 11.0))
4949

5050
// Open copy menu
51-
onElement { viewIdResourceName == "geoShareResultSuccessCopyMenuButton" }.click()
51+
onElement { viewIdResourceName == "geoShareResultSuccessLastPointMenu" }.click()
5252

5353
// Shows copy link in GCJ-02
5454
onElement {
@@ -478,7 +478,7 @@ class ConversionActivityBehaviorTest : BaseActivityBehaviorTest() {
478478
assertConversionSucceeded(persistentListOf(WGS84Point(52.5067296, 13.2599309, 11.0)))
479479

480480
// Open copy menu
481-
onElement { viewIdResourceName == "geoShareResultSuccessCopyMenuButton" }.click()
481+
onElement { viewIdResourceName == "geoShareResultSuccessLastPointMenu" }.click()
482482

483483
// Swipe the sheet to reveal "Copy Magic Earth link"
484484
onElement { viewIdResourceName == "geoShareConversionSheet" }.swipe(Direction.UP, 1f)

app/src/androidTest/java/page/ooooo/geoshare/inputs/GoogleMapsInputBehaviorTest.kt

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,15 @@ class GoogleMapsInputBehaviorTest : BaseInputBehaviorTest() {
6969

7070
// Directions
7171
testUri(
72-
WGS84Point(
73-
52.4807739,
74-
13.4300356,
75-
z = 16.0,
76-
name = @Suppress("SpellCheckingInspection") "Reuterstraße 1, Berlin-Neukölln, Germany"
72+
persistentListOf(
73+
WGS84Point(name = @Suppress("SpellCheckingInspection") "Hermannstraß 1, 12049 Berlin, Germany"),
74+
WGS84Point(name = @Suppress("SpellCheckingInspection") "Weserstr. 1, 12047 Berlin, Germany"),
75+
WGS84Point(
76+
52.4807739,
77+
13.4300356,
78+
z = 16.0,
79+
name = @Suppress("SpellCheckingInspection") "Reuterstraße 1, Berlin-Neukölln, Germany"
80+
),
7781
),
7882
@Suppress("SpellCheckingInspection")
7983
"https://www.google.com/maps/dir/Hermannstra%C3%9Fe+1,+12049+Berlin,+Germany/Weserstr.+1,+12047+Berlin,+Germany/Reuterstra%C3%9Fe+1,+Berlin-Neuk%C3%B6lln,+Germany/@52.4844406,13.4217121,16z/data=!3m1!4b1!4m20!4m19!1m5!1m1!1s0x47a84fb831937021:0x28d6914e5ca0f9f5!2m2!1d13.4236883!2d52.4858222!1m5!1m1!1s0x47a84fb7098f1d89:0x74c8a84ad2981e9f!2m2!1d13.4255518!2d52.4881038!1m5!1m1!1s0x47a84fbb7c0791d7:0xf6e39aaedab8b2d9!2m2!1d13.4300356!2d52.4807739!3e2",

app/src/main/java/page/ooooo/geoshare/data/local/preferences/UserPreferences.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ interface UserPreference<T> {
7171
)
7272
}
7373

74-
abstract class SingleKeyPreference<T>() : UserPreference<T> {
74+
abstract class SingleKeyPreference<T> : UserPreference<T> {
7575
abstract val key: Preferences.Key<String>
7676
abstract val default: T
7777

app/src/main/java/page/ooooo/geoshare/lib/extensions/ListExtensions.kt

Lines changed: 0 additions & 7 deletions
This file was deleted.

app/src/main/java/page/ooooo/geoshare/lib/inputs/BaiduMapInput.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ object BaiduMapInput : Input {
5757
.drop(1)
5858
.filterNot { it.startsWith('@') }
5959
.map { NaivePoint(0.0, 0.0, name = it) }
60-
.map { points.add(it) }
60+
.forEach { points.add(it) }
6161
}
6262
}
6363
}

app/src/main/java/page/ooooo/geoshare/lib/inputs/GoogleMapsInput.kt

Lines changed: 55 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import page.ooooo.geoshare.R
88
import page.ooooo.geoshare.lib.ILog
99
import page.ooooo.geoshare.lib.Uri
1010
import page.ooooo.geoshare.lib.extensions.doubleGroupOrNull
11-
import page.ooooo.geoshare.lib.extensions.forEachReversed
1211
import page.ooooo.geoshare.lib.extensions.groupOrNull
1312
import page.ooooo.geoshare.lib.extensions.matchEntire
1413
import page.ooooo.geoshare.lib.extensions.toLatLonPoint
@@ -45,18 +44,23 @@ object GoogleMapsInput : Input.HasShortUri, Input.HasHtml, Input.HasWeb {
4544
uri.run {
4645
// Try query parameters for all URLs
4746

48-
listOf("destination", "q", "query", "ll", "viewpoint", "center")
49-
.firstNotNullOfOrNull { key -> LAT_LON_PATTERN.matchEntire(queryParams[key]) }
50-
?.toLatLonPoint()
51-
?.also { points.add(it) }
52-
53-
listOf("destination", "q", "query")
54-
.firstNotNullOfOrNull { key -> Q_PARAM_PATTERN.matchEntire(queryParams[key]) }
55-
?.groupOrNull()
56-
?.also { defaultName = it }
57-
5847
Z_PATTERN.matchEntire(queryParams["zoom"])?.doubleGroupOrNull()?.also { defaultZ = it }
5948

49+
listOf("origin", "destination", "q", "query", "ll", "viewpoint", "center").forEach { key ->
50+
(LAT_LON_PATTERN.matchEntire(queryParams[key])?.toLatLonPoint()
51+
?: Q_PARAM_PATTERN.matchEntire(queryParams[key])?.groupOrNull()?.let { NaivePoint(name = it) })
52+
?.let {
53+
points.add(it)
54+
if (key != "origin") {
55+
if (!it.hasCoordinates()) {
56+
// Go to HTML parsing if needed
57+
htmlUriString = uri.toString()
58+
}
59+
return@run
60+
}
61+
}
62+
}
63+
6064
// Parse path parts
6165

6266
val partsThatSupportUriParsing = setOf("dir", "place", "search")
@@ -65,55 +69,59 @@ object GoogleMapsInput : Input.HasShortUri, Input.HasHtml, Input.HasWeb {
6569
val firstPart = parts.firstOrNull()
6670
if (firstPart in partsThatSupportUriParsing || firstPart?.startsWith('@') == true) {
6771
// Iterate path parts in reverse order
68-
var centerCoords: Pair<Double, Double>? = null
6972
val pointPattern = Regex("""$LAT,$LON.*""")
70-
parts.dropWhile { it in partsThatSupportUriParsing }.forEachReversed { part ->
73+
parts.dropWhile { it in partsThatSupportUriParsing }.forEach { part ->
7174
if (part.startsWith("data=")) {
7275
// Data
7376
// /data=...!3d44.4490541!4d26.0888398...
74-
Regex("""!3d$LAT!4d$LON""").find(part)?.toLatLonPoint()?.also { points.add(it) }
77+
Regex("""!3d$LAT!4d$LON""").find(part)?.toLatLonPoint()?.also {
78+
// Overwrite coordinates of previously found points with /data= but copy last point name
79+
points.lastOrNull().let { lastPoint ->
80+
points.clear()
81+
points.add(it.copy(name = lastPoint?.name))
82+
}
83+
} ?:
7584
// /data=...!1d13.4236883!2d52.4858222...!1d13.4255518!2d52.4881038...
76-
points.addAll((Regex("""!1d$LON!2d$LAT""").findAll(part)).mapNotNull { it.toLonLatPoint() })
77-
} else if (part.startsWith('@') && centerCoords == null) {
85+
Regex("""!1d$LON!2d$LAT""").findAll(part).mapNotNull { it.toLonLatPoint() }
86+
.toList().takeIf { it.isNotEmpty() }?.let {
87+
if (it.size == points.size) {
88+
// Overwrite coordinates of previously found points with /data= but keep names
89+
points.forEachIndexed { i, point ->
90+
points[i] = point.copy(lat = it[i].lat, lon = it[i].lon)
91+
}
92+
} else {
93+
// Overwrite coordinates of previously found points with /data= including names
94+
points.clear()
95+
points.addAll(it)
96+
}
97+
}
98+
} else if (part.startsWith('@')) {
7899
// Center
79100
// /@52.5067296,13.2599309,6z
80-
Regex("""@$LAT,$LON(?:,${Z}z)?.*""").matchEntire(part)?.toLatLonZPoint()?.let { point ->
81-
if (point.lat != null && point.lon != null) {
82-
centerCoords = point.lat to point.lon
101+
Regex("""@$LAT,$LON(?:,${Z}z)?.*""").matchEntire(part)?.toLatLonZPoint()?.also { point ->
102+
val lastPoint = points.lastOrNull()
103+
if (lastPoint == null) {
104+
// Use center coordinates if we haven't already found a point
105+
points.add(point)
106+
} else if (lastPoint.lat == null && lastPoint.lon == null) {
107+
// Use center coordinates with the name of the last found point
108+
points[points.size - 1] = point.copy(name = lastPoint.name)
109+
} else {
110+
// Don't use center coordinates if we've already found a point with coordinate
83111
}
84112
defaultZ = point.z
85113
}
86-
} else {
114+
} else if (part.isNotEmpty()) {
87115
// Coordinates
88116
// /52.492611,13.431726
89-
part
90-
.takeIf { points.isEmpty() } // Only if a point hasn't already been found, e.g. in /data
91-
?.let { pointPattern.matchEntire(it) }
92-
?.toLatLonPoint()
93-
?.also { points.add(it) }
117+
pointPattern.matchEntire(part)?.toLatLonPoint()?.also { points.add(it) }
94118
// Name
95119
// /Central+Park
96-
?: part
97-
.takeIf { defaultName == null } // Use the last name-like path part
98-
?.let { Q_PATH_PATTERN.matchEntire(part) }
99-
?.groupOrNull()
100-
?.also { defaultName = it }
101-
}
102-
// Once we have a point, name, and z, we can stop iterating path parts
103-
if (points.isNotEmpty() && defaultName != null && defaultZ != null) {
104-
return@forEachReversed
120+
?: points.add(NaivePoint(name = part))
105121
}
106122
}
107-
if (points.isEmpty()) {
108-
if (centerCoords != null) {
109-
// Use the center point only if we haven't found another point
110-
points.add(NaivePoint(centerCoords.first, centerCoords.second))
111-
} else if (firstPart in partsThatSupportHtmlParsing) {
112-
// Go to HTML parsing if needed
113-
htmlUriString = uri.toString()
114-
}
115-
}
116-
} else if (firstPart in partsThatSupportHtmlParsing) {
123+
}
124+
if (points.lastOrNull()?.hasCoordinates() != true && firstPart in partsThatSupportHtmlParsing) {
117125
// Go to HTML parsing if needed
118126
htmlUriString = uri.toString()
119127
}
@@ -158,9 +166,9 @@ object GoogleMapsInput : Input.HasShortUri, Input.HasHtml, Input.HasWeb {
158166
}
159167
if (defaultPoint == null && !genericMetaTagFound) {
160168
// When the HTML contains a generic "Google Maps" META tag instead of a specific one like
161-
// "Berlin - Germany", then it seems that the APP_INITIALIZATION_STATE contains coordinates of the
162-
// IP address that the HTTP request came from, instead of correct coordinates. So let's ignore the
163-
// coordinates.
169+
// "Berlin - Germany", then it seems that the APP_INITIALIZATION_STATE doesn't contain correct
170+
// coordinates. It contains coordinates of the IP address that the HTTP request came from. So let's
171+
// ignore these coordinates.
164172
defaultPointAppInitStatePattern.find(line)?.toLonLatPoint()?.let {
165173
log.d("GoogleMapsInput", "HTML Pattern: Default point pattern 2 matched line $line")
166174
defaultPoint = it

app/src/main/java/page/ooooo/geoshare/lib/outputs/CoordinatesOutput.kt

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,6 @@ object CoordinatesOutput : Output {
9292
override fun getText(points: ImmutableList<Point>, i: Int?, uriQuote: UriQuote) =
9393
points.getOrNull(i)?.let { point -> formatDegMinSecString(point) }
9494

95-
@Composable
96-
override fun getName(points: ImmutableList<Point>, i: Int?, uriQuote: UriQuote) = name(points, i)
97-
9895
override fun getPointsActions(): List<BasicAction> = listOf(
9996
CopyDecCoordsAction(),
10097
CopyDegMinSecCoordsAction(),
@@ -137,13 +134,4 @@ object CoordinatesOutput : Output {
137134
}
138135
}
139136
}
140-
141-
@Composable
142-
private fun name(points: ImmutableList<Point>, i: Int?): String? =
143-
points.getOrNull(i)?.let { point ->
144-
point.name.takeUnless { it.isNullOrEmpty() }?.replace('+', ' ')
145-
?: points.size.takeIf { it > 1 }?.let { size ->
146-
stringResource(R.string.conversion_succeeded_point_number, if (i == null) size else i + 1)
147-
}
148-
}
149137
}

app/src/main/java/page/ooooo/geoshare/lib/outputs/GeoUriOutput.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ object GeoUriOutput : Output {
166166
apps.filter { it.type == AndroidTools.AppType.GEO_URI }
167167
.map { it.packageName to ShareGeoUriWithAppAction(it.packageName) }
168168

169-
override fun getChipActions() = listOf(CopyGeoUriAction())
169+
override fun getLastPointChipActions() = listOf(CopyGeoUriAction())
170170

171171
override fun getChooserAction() = ShareGeoUriAction()
172172

0 commit comments

Comments
 (0)