Merge pull request 'feat: pick a location from the contact picker' (!30) from feat/location-from-contacts into release/v2.8.0
Reviewed-on: #30
This commit was merged in pull request #30.
This commit is contained in:
@@ -461,6 +461,21 @@ private fun EventEditContent(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pick a postal address from contacts: the same one-shot picker, scoped to
|
||||||
|
// address rows, dropping the chosen contact's formatted address into the
|
||||||
|
// location field. Same no-permission guarantee as the guest picker above.
|
||||||
|
val pickContactAddress = rememberLauncherForActivityResult(
|
||||||
|
ActivityResultContracts.StartActivityForResult(),
|
||||||
|
) { result ->
|
||||||
|
if (result.resultCode == Activity.RESULT_OK) {
|
||||||
|
result.data?.data?.let { uri ->
|
||||||
|
readContactAddress(context, uri)?.let { address ->
|
||||||
|
viewModel.setLocation(address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val selectedCalendar = state.calendars.firstOrNull { it.id == form.calendarId }
|
val selectedCalendar = state.calendars.firstOrNull { it.id == form.calendarId }
|
||||||
// The accent ties the form to the detail screen's design language: the
|
// The accent ties the form to the detail screen's design language: the
|
||||||
// bar under the title takes the target calendar's colour.
|
// bar under the title takes the target calendar's colour.
|
||||||
@@ -592,11 +607,39 @@ private fun EventEditContent(
|
|||||||
icon = Icons.Default.Place,
|
icon = Icons.Default.Place,
|
||||||
iconContentDescription = stringResource(R.string.event_detail_location),
|
iconContentDescription = stringResource(R.string.event_detail_location),
|
||||||
) {
|
) {
|
||||||
InlineField(
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
value = form.location,
|
InlineField(
|
||||||
onValueChange = viewModel::setLocation,
|
value = form.location,
|
||||||
placeholder = stringResource(R.string.event_detail_location),
|
onValueChange = viewModel::setLocation,
|
||||||
)
|
placeholder = stringResource(R.string.event_detail_location),
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.padding(vertical = 4.dp),
|
||||||
|
)
|
||||||
|
IconButton(
|
||||||
|
onClick = {
|
||||||
|
runCatching {
|
||||||
|
pickContactAddress.launch(
|
||||||
|
Intent(
|
||||||
|
Intent.ACTION_PICK,
|
||||||
|
ContactsContract.CommonDataKinds.StructuredPostal
|
||||||
|
.CONTENT_URI,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modifier = Modifier.size(40.dp),
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Contacts,
|
||||||
|
contentDescription = stringResource(
|
||||||
|
R.string.event_edit_location_from_contacts,
|
||||||
|
),
|
||||||
|
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
modifier = Modifier.size(22.dp),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1578,6 +1621,27 @@ private fun readContactEmail(context: Context, uri: Uri): Pair<String, String>?
|
|||||||
email.takeIf { it.isNotEmpty() }?.let { it to name }
|
email.takeIf { it.isNotEmpty() }?.let { it to name }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read the formatted postal address from a contact-pick result URI. No
|
||||||
|
* READ_CONTACTS needed: ACTION_PICK grants this URI temporary read access.
|
||||||
|
* The provider's formatted address is multi-line; collapse it to one line so
|
||||||
|
* it sits cleanly in the single-line location field.
|
||||||
|
*/
|
||||||
|
private fun readContactAddress(context: Context, uri: Uri): String? =
|
||||||
|
context.contentResolver.query(
|
||||||
|
uri,
|
||||||
|
arrayOf(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS),
|
||||||
|
null, null, null,
|
||||||
|
)?.use { cursor ->
|
||||||
|
if (!cursor.moveToFirst()) return@use null
|
||||||
|
cursor.getString(0).orEmpty()
|
||||||
|
.lines()
|
||||||
|
.map { it.trim() }
|
||||||
|
.filter { it.isNotEmpty() }
|
||||||
|
.joinToString(", ")
|
||||||
|
.takeIf { it.isNotEmpty() }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun fieldLabel(field: EventFormField): Int = when (field) {
|
private fun fieldLabel(field: EventFormField): Int = when (field) {
|
||||||
EventFormField.Location -> R.string.event_detail_location
|
EventFormField.Location -> R.string.event_detail_location
|
||||||
|
|||||||
@@ -81,6 +81,7 @@
|
|||||||
<string name="event_edit_add_guest">Gast hinzufügen</string>
|
<string name="event_edit_add_guest">Gast hinzufügen</string>
|
||||||
<string name="event_edit_add_guest_hint">Gast per E-Mail hinzufügen…</string>
|
<string name="event_edit_add_guest_hint">Gast per E-Mail hinzufügen…</string>
|
||||||
<string name="event_edit_add_guest_from_contacts">Aus Kontakten hinzufügen</string>
|
<string name="event_edit_add_guest_from_contacts">Aus Kontakten hinzufügen</string>
|
||||||
|
<string name="event_edit_location_from_contacts">Adresse aus Kontakten wählen</string>
|
||||||
<string name="event_edit_remove_guest">Gast entfernen</string>
|
<string name="event_edit_remove_guest">Gast entfernen</string>
|
||||||
<string name="event_edit_attendee_required">Erforderlich</string>
|
<string name="event_edit_attendee_required">Erforderlich</string>
|
||||||
<string name="event_edit_attendee_optional">Optional</string>
|
<string name="event_edit_attendee_optional">Optional</string>
|
||||||
|
|||||||
@@ -82,6 +82,7 @@
|
|||||||
<string name="event_edit_add_guest">Add guest</string>
|
<string name="event_edit_add_guest">Add guest</string>
|
||||||
<string name="event_edit_add_guest_hint">Add a guest by email…</string>
|
<string name="event_edit_add_guest_hint">Add a guest by email…</string>
|
||||||
<string name="event_edit_add_guest_from_contacts">Add from contacts</string>
|
<string name="event_edit_add_guest_from_contacts">Add from contacts</string>
|
||||||
|
<string name="event_edit_location_from_contacts">Pick address from contacts</string>
|
||||||
<string name="event_edit_remove_guest">Remove guest</string>
|
<string name="event_edit_remove_guest">Remove guest</string>
|
||||||
<string name="event_edit_attendee_required">Required</string>
|
<string name="event_edit_attendee_required">Required</string>
|
||||||
<string name="event_edit_attendee_optional">Optional</string>
|
<string name="event_edit_attendee_optional">Optional</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user