Open location links in the browser instead of maps (#357)

Bump to 2.22.1.
This commit is contained in:
2026-10-02 18:18:23 +02:00
parent 5f07adef2f
commit 630b8e2cd7
4 changed files with 34 additions and 9 deletions
+6
View File
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [2.22.1] — 2026-10-02
### Fixed
- **Links in an event's location open in the browser.** Tapping a location that holds a URL, such as a video-call link, opened it in a maps app; maps is now only used for plain addresses ([#357]).
## [2.22.0] — 2026-10-01
### Added
@@ -1817,3 +1822,4 @@ automatically, with zero telemetry and no internet permission.
[#322]: https://codeberg.org/jlmakiola/calendula/issues/322
[#331]: https://codeberg.org/jlmakiola/calendula/issues/331
[#336]: https://codeberg.org/jlmakiola/calendula/issues/336
[#357]: https://codeberg.org/jlmakiola/calendula/issues/357
+2 -2
View File
@@ -28,8 +28,8 @@ android {
// which builds this version and then creates the matching vX.Y.Z tag +
// release itself (versionCode is pinned to MAJOR*10000 + MINOR*100 +
// PATCH from versionName, e.g. 2.7.2 -> 20702). See docs/RELEASING.md.
versionCode = 22200
versionName = "2.22.0"
versionCode = 22201
versionName = "2.22.1"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
@@ -534,7 +534,7 @@ private fun EventDetailContent(
)
}
// Location (conditional, tap → maps).
// Location (conditional, tap → link if it holds a URL, else maps).
instance.location?.takeIf { it.isNotBlank() }?.let { location ->
val context = LocalContext.current
val locationLabel = stringResource(R.string.event_detail_location)
@@ -553,7 +553,7 @@ private fun EventDetailContent(
label = locationLabel,
text = location,
copy = copyField,
onTap = { openInMaps(context, location) },
onTap = { openLocation(context, location) },
)
.padding(vertical = 2.dp),
)
@@ -846,19 +846,22 @@ private fun foreignTimeZone(
)
}
private val urlRegex = Regex("""https?://\S+""")
/** Strip trailing punctuation that commonly abuts a URL in prose. */
private fun String.trimUrlPunctuation(): String =
trimEnd('.', ',', ';', ':', '!', '?', ')', ']', '"', '\'')
/** Wrap http(s) URLs in [text] as tappable links tinted [linkColor]. */
@Composable
private fun linkifyUrls(text: String, linkColor: Color): AnnotatedString = remember(text, linkColor) {
val regex = Regex("""https?://\S+""")
val styles = TextLinkStyles(
style = SpanStyle(color = linkColor, textDecoration = TextDecoration.Underline),
)
buildAnnotatedString {
append(text)
for (match in regex.findAll(text)) {
// Trim trailing punctuation that commonly abuts a URL in prose.
val raw = match.value
val url = raw.trimEnd('.', ',', ';', ':', '!', '?', ')', ']', '"', '\'')
for (match in urlRegex.findAll(text)) {
val url = match.value.trimUrlPunctuation()
val end = match.range.first + url.length
addLink(LinkAnnotation.Url(url, styles), match.range.first, end)
}
@@ -915,6 +918,20 @@ private fun formatWhen(
private fun Instant.toJavaLocalDateTime(zid: ZoneId): java.time.LocalDateTime =
java.time.LocalDateTime.ofInstant(java.time.Instant.ofEpochMilli(toEpochMilliseconds()), zid)
/** Open the first URL in [location] (e.g. a meeting link), otherwise search it in maps. */
private fun openLocation(context: Context, location: String) {
val url = urlRegex.find(location)?.value?.trimUrlPunctuation()
if (url == null) {
openInMaps(context, location)
return
}
try {
context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url)))
} catch (e: ActivityNotFoundException) {
// No app handles the link — nothing sensible to do; swallow.
}
}
/** Open a maps intent for [query]; fall back to a web maps URL if no app handles geo:. */
private fun openInMaps(context: Context, query: String) {
val encoded = Uri.encode(query)
@@ -0,0 +1,2 @@
Fixed
• Links in an event's location open in the browser. Tapping a video-call link in the location opened a maps app instead.