[a11y] Make more items focusable (#4605)
* Fix settings entry point not available when there is no avatar on the account. Fixes #4599. * Use Ktx extension `String.toUri()` * Allow screen reader to focus on the user avatar to allow editing it. * Fix import order
This commit is contained in:
parent
ec88cbe0e5
commit
e2e58749f5
15 changed files with 48 additions and 24 deletions
|
|
@ -8,6 +8,7 @@
|
||||||
package io.element.android.features.call.impl.utils
|
package io.element.android.features.call.impl.utils
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import androidx.core.net.toUri
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class CallIntentDataParser @Inject constructor() {
|
class CallIntentDataParser @Inject constructor() {
|
||||||
|
|
@ -17,7 +18,7 @@ class CallIntentDataParser @Inject constructor() {
|
||||||
)
|
)
|
||||||
|
|
||||||
fun parse(data: String?): String? {
|
fun parse(data: String?): String? {
|
||||||
val parsedUrl = data?.let { Uri.parse(data) } ?: return null
|
val parsedUrl = data?.toUri() ?: return null
|
||||||
val scheme = parsedUrl.scheme
|
val scheme = parsedUrl.scheme
|
||||||
return when {
|
return when {
|
||||||
scheme in validHttpSchemes -> parsedUrl
|
scheme in validHttpSchemes -> parsedUrl
|
||||||
|
|
@ -37,7 +38,7 @@ class CallIntentDataParser @Inject constructor() {
|
||||||
private fun Uri.getUrlParameter(): Uri? {
|
private fun Uri.getUrlParameter(): Uri? {
|
||||||
return getQueryParameter("url")
|
return getQueryParameter("url")
|
||||||
?.let { urlParameter ->
|
?.let { urlParameter ->
|
||||||
Uri.parse(urlParameter).takeIf { uri ->
|
urlParameter.toUri().takeIf { uri ->
|
||||||
uri.scheme in validHttpSchemes && !uri.host.isNullOrBlank()
|
uri.scheme in validHttpSchemes && !uri.host.isNullOrBlank()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,11 @@ package io.element.android.features.login.impl.util
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import androidx.core.net.toUri
|
||||||
import io.element.android.appconfig.AuthenticationConfig
|
import io.element.android.appconfig.AuthenticationConfig
|
||||||
import io.element.android.libraries.core.data.tryOrNull
|
import io.element.android.libraries.core.data.tryOrNull
|
||||||
|
|
||||||
fun openLearnMorePage(context: Context) {
|
fun openLearnMorePage(context: Context) {
|
||||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(AuthenticationConfig.SLIDING_SYNC_READ_MORE_URL))
|
val intent = Intent(Intent.ACTION_VIEW, AuthenticationConfig.SLIDING_SYNC_READ_MORE_URL.toUri())
|
||||||
tryOrNull { context.startActivity(intent) }
|
tryOrNull { context.startActivity(intent) }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
package io.element.android.features.login.impl.web
|
package io.element.android.features.login.impl.web
|
||||||
|
|
||||||
import android.net.Uri
|
import androidx.core.net.toUri
|
||||||
import com.squareup.anvil.annotations.ContributesBinding
|
import com.squareup.anvil.annotations.ContributesBinding
|
||||||
import io.element.android.appconfig.AuthenticationConfig
|
import io.element.android.appconfig.AuthenticationConfig
|
||||||
import io.element.android.features.login.impl.resolver.network.WellknownAPI
|
import io.element.android.features.login.impl.resolver.network.WellknownAPI
|
||||||
|
|
@ -43,7 +43,7 @@ class DefaultWebClientUrlForAuthenticationRetriever @Inject constructor(
|
||||||
}
|
}
|
||||||
val registrationHelperUrl = result.registrationHelperUrl
|
val registrationHelperUrl = result.registrationHelperUrl
|
||||||
return if (registrationHelperUrl != null) {
|
return if (registrationHelperUrl != null) {
|
||||||
Uri.parse(registrationHelperUrl)
|
registrationHelperUrl.toUri()
|
||||||
.buildUpon()
|
.buildUpon()
|
||||||
.appendQueryParameter("hs_url", homeServerUrl)
|
.appendQueryParameter("hs_url", homeServerUrl)
|
||||||
.build()
|
.build()
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ class EditUserProfilePresenter @AssistedInject constructor(
|
||||||
@Composable
|
@Composable
|
||||||
override fun present(): EditUserProfileState {
|
override fun present(): EditUserProfileState {
|
||||||
val cameraPermissionState = cameraPermissionPresenter.present()
|
val cameraPermissionState = cameraPermissionPresenter.present()
|
||||||
var userAvatarUri by rememberSaveable { mutableStateOf(matrixUser.avatarUrl?.let { Uri.parse(it) }) }
|
var userAvatarUri by rememberSaveable { mutableStateOf(matrixUser.avatarUrl?.toUri()) }
|
||||||
var userDisplayName by rememberSaveable { mutableStateOf(matrixUser.displayName) }
|
var userDisplayName by rememberSaveable { mutableStateOf(matrixUser.displayName) }
|
||||||
val cameraPhotoPicker = mediaPickerProvider.registerCameraPhotoPicker(
|
val cameraPhotoPicker = mediaPickerProvider.registerCameraPhotoPicker(
|
||||||
onResult = { uri ->
|
onResult = { uri ->
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ package io.element.android.features.roomdetails.impl.edit
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||||
|
import androidx.core.net.toUri
|
||||||
import io.element.android.libraries.architecture.AsyncAction
|
import io.element.android.libraries.architecture.AsyncAction
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.matrix.ui.media.AvatarAction
|
import io.element.android.libraries.matrix.ui.media.AvatarAction
|
||||||
|
|
@ -22,7 +23,7 @@ open class RoomDetailsEditStateProvider : PreviewParameterProvider<RoomDetailsEd
|
||||||
aRoomDetailsEditState(),
|
aRoomDetailsEditState(),
|
||||||
aRoomDetailsEditState(roomTopic = ""),
|
aRoomDetailsEditState(roomTopic = ""),
|
||||||
aRoomDetailsEditState(roomRawName = ""),
|
aRoomDetailsEditState(roomRawName = ""),
|
||||||
aRoomDetailsEditState(roomAvatarUrl = Uri.parse("example://uri")),
|
aRoomDetailsEditState(roomAvatarUrl = "example://uri".toUri()),
|
||||||
aRoomDetailsEditState(canChangeName = true, canChangeTopic = false, canChangeAvatar = true, saveButtonEnabled = false),
|
aRoomDetailsEditState(canChangeName = true, canChangeTopic = false, canChangeAvatar = true, saveButtonEnabled = false),
|
||||||
aRoomDetailsEditState(canChangeName = false, canChangeTopic = true, canChangeAvatar = false, saveButtonEnabled = false),
|
aRoomDetailsEditState(canChangeName = false, canChangeTopic = true, canChangeAvatar = false, saveButtonEnabled = false),
|
||||||
aRoomDetailsEditState(saveAction = AsyncAction.Loading),
|
aRoomDetailsEditState(saveAction = AsyncAction.Loading),
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,12 @@ package io.element.android.libraries.androidutils.browser
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.ActivityNotFoundException
|
import android.content.ActivityNotFoundException
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.Browser
|
import android.provider.Browser
|
||||||
import androidx.browser.customtabs.CustomTabColorSchemeParams
|
import androidx.browser.customtabs.CustomTabColorSchemeParams
|
||||||
import androidx.browser.customtabs.CustomTabsIntent
|
import androidx.browser.customtabs.CustomTabsIntent
|
||||||
import androidx.browser.customtabs.CustomTabsSession
|
import androidx.browser.customtabs.CustomTabsSession
|
||||||
|
import androidx.core.net.toUri
|
||||||
import io.element.android.libraries.androidutils.system.openUrlInExternalApp
|
import io.element.android.libraries.androidutils.system.openUrlInExternalApp
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
|
|
@ -58,7 +58,7 @@ fun Activity.openUrlInChromeCustomTab(
|
||||||
putString("Accept-Language", Locale.getDefault().toLanguageTag())
|
putString("Accept-Language", Locale.getDefault().toLanguageTag())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
.launchUrl(this, Uri.parse(url))
|
.launchUrl(this, url.toUri())
|
||||||
} catch (activityNotFoundException: ActivityNotFoundException) {
|
} catch (activityNotFoundException: ActivityNotFoundException) {
|
||||||
openUrlInExternalApp(url)
|
openUrlInExternalApp(url)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import android.widget.Toast
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.core.content.pm.PackageInfoCompat
|
import androidx.core.content.pm.PackageInfoCompat
|
||||||
|
import androidx.core.net.toUri
|
||||||
import io.element.android.libraries.androidutils.R
|
import io.element.android.libraries.androidutils.R
|
||||||
import io.element.android.libraries.androidutils.compat.getApplicationInfoCompat
|
import io.element.android.libraries.androidutils.compat.getApplicationInfoCompat
|
||||||
import io.element.android.libraries.core.mimetype.MimeTypes
|
import io.element.android.libraries.core.mimetype.MimeTypes
|
||||||
|
|
@ -121,7 +122,7 @@ fun Context.startInstallFromSourceIntent(
|
||||||
noActivityFoundMessage: String = getString(R.string.error_no_compatible_app_found),
|
noActivityFoundMessage: String = getString(R.string.error_no_compatible_app_found),
|
||||||
) {
|
) {
|
||||||
val intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES)
|
val intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES)
|
||||||
.setData(Uri.parse("package:$packageName"))
|
.setData("package:$packageName".toUri())
|
||||||
try {
|
try {
|
||||||
activityResultLauncher.launch(intent)
|
activityResultLauncher.launch(intent)
|
||||||
} catch (activityNotFoundException: ActivityNotFoundException) {
|
} catch (activityNotFoundException: ActivityNotFoundException) {
|
||||||
|
|
@ -165,7 +166,7 @@ fun Context.openUrlInExternalApp(
|
||||||
url: String,
|
url: String,
|
||||||
errorMessage: String = getString(R.string.error_no_compatible_app_found),
|
errorMessage: String = getString(R.string.error_no_compatible_app_found),
|
||||||
) {
|
) {
|
||||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
|
val intent = Intent(Intent.ACTION_VIEW, url.toUri())
|
||||||
if (this !is Activity) {
|
if (this !is Activity) {
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,8 @@
|
||||||
package io.element.android.libraries.androidutils.uri
|
package io.element.android.libraries.androidutils.uri
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import androidx.core.net.toUri
|
||||||
|
|
||||||
const val IGNORED_SCHEMA = "ignored"
|
const val IGNORED_SCHEMA = "ignored"
|
||||||
|
|
||||||
fun createIgnoredUri(path: String): Uri = Uri.parse("$IGNORED_SCHEMA://$path")
|
fun createIgnoredUri(path: String): Uri = "$IGNORED_SCHEMA://$path".toUri()
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.platform.LocalInspectionMode
|
import androidx.compose.ui.platform.LocalInspectionMode
|
||||||
import androidx.compose.ui.semantics.clearAndSetSemantics
|
import androidx.compose.ui.semantics.clearAndSetSemantics
|
||||||
|
import androidx.compose.ui.semantics.contentDescription
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
|
|
@ -59,6 +60,7 @@ fun Avatar(
|
||||||
avatarData = avatarData,
|
avatarData = avatarData,
|
||||||
forcedAvatarSize = forcedAvatarSize,
|
forcedAvatarSize = forcedAvatarSize,
|
||||||
modifier = commonModifier,
|
modifier = commonModifier,
|
||||||
|
contentDescription = contentDescription,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
ImageAvatar(
|
ImageAvatar(
|
||||||
|
|
@ -103,11 +105,13 @@ private fun ImageAvatar(
|
||||||
InitialsAvatar(
|
InitialsAvatar(
|
||||||
avatarData = avatarData,
|
avatarData = avatarData,
|
||||||
forcedAvatarSize = forcedAvatarSize,
|
forcedAvatarSize = forcedAvatarSize,
|
||||||
|
contentDescription = contentDescription,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
else -> InitialsAvatar(
|
else -> InitialsAvatar(
|
||||||
avatarData = avatarData,
|
avatarData = avatarData,
|
||||||
forcedAvatarSize = forcedAvatarSize,
|
forcedAvatarSize = forcedAvatarSize,
|
||||||
|
contentDescription = contentDescription,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -118,6 +122,7 @@ private fun ImageAvatar(
|
||||||
private fun InitialsAvatar(
|
private fun InitialsAvatar(
|
||||||
avatarData: AvatarData,
|
avatarData: AvatarData,
|
||||||
forcedAvatarSize: Dp?,
|
forcedAvatarSize: Dp?,
|
||||||
|
contentDescription: String?,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val avatarColors = AvatarColorsProvider.provide(avatarData.id)
|
val avatarColors = AvatarColorsProvider.provide(avatarData.id)
|
||||||
|
|
@ -130,7 +135,11 @@ private fun InitialsAvatar(
|
||||||
val lineHeight = originalFont.lineHeight * ratio
|
val lineHeight = originalFont.lineHeight * ratio
|
||||||
Text(
|
Text(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.clearAndSetSemantics {}
|
.clearAndSetSemantics {
|
||||||
|
contentDescription?.let {
|
||||||
|
this.contentDescription = it
|
||||||
|
}
|
||||||
|
}
|
||||||
.align(Alignment.Center),
|
.align(Alignment.Center),
|
||||||
text = avatarData.initial,
|
text = avatarData.initial,
|
||||||
style = originalFont.copy(fontSize = fontSize, lineHeight = lineHeight, letterSpacing = 0.sp),
|
style = originalFont.copy(fontSize = fontSize, lineHeight = lineHeight, letterSpacing = 0.sp),
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ package io.element.android.libraries.fullscreenintent.impl
|
||||||
|
|
||||||
import android.content.ActivityNotFoundException
|
import android.content.ActivityNotFoundException
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
|
@ -17,6 +16,7 @@ import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.core.app.NotificationManagerCompat
|
import androidx.core.app.NotificationManagerCompat
|
||||||
|
import androidx.core.net.toUri
|
||||||
import androidx.datastore.preferences.core.booleanPreferencesKey
|
import androidx.datastore.preferences.core.booleanPreferencesKey
|
||||||
import androidx.datastore.preferences.core.edit
|
import androidx.datastore.preferences.core.edit
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
|
|
@ -77,7 +77,7 @@ class FullScreenIntentPermissionsPresenter @Inject constructor(
|
||||||
try {
|
try {
|
||||||
val intent = Intent(
|
val intent = Intent(
|
||||||
Settings.ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT,
|
Settings.ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT,
|
||||||
Uri.parse("package:${buildMeta.applicationId}")
|
"package:${buildMeta.applicationId}".toUri()
|
||||||
)
|
)
|
||||||
externalIntentLauncher.launch(intent)
|
externalIntentLauncher.launch(intent)
|
||||||
} catch (e: ActivityNotFoundException) {
|
} catch (e: ActivityNotFoundException) {
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
package io.element.android.libraries.matrix.impl.permalink
|
package io.element.android.libraries.matrix.impl.permalink
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import androidx.core.net.toUri
|
||||||
import com.squareup.anvil.annotations.ContributesBinding
|
import com.squareup.anvil.annotations.ContributesBinding
|
||||||
import io.element.android.appconfig.MatrixConfiguration
|
import io.element.android.appconfig.MatrixConfiguration
|
||||||
import io.element.android.libraries.core.extensions.replacePrefix
|
import io.element.android.libraries.core.extensions.replacePrefix
|
||||||
|
|
@ -43,7 +44,7 @@ class DefaultMatrixToConverter @Inject constructor() : MatrixToConverter {
|
||||||
// Web or client url
|
// Web or client url
|
||||||
SUPPORTED_PATHS.any { it in uriString } -> {
|
SUPPORTED_PATHS.any { it in uriString } -> {
|
||||||
val path = SUPPORTED_PATHS.first { it in uriString }
|
val path = SUPPORTED_PATHS.first { it in uriString }
|
||||||
Uri.parse(baseUrl + uriString.substringAfter(path))
|
(baseUrl + uriString.substringAfter(path)).toUri()
|
||||||
}
|
}
|
||||||
// URL is not supported
|
// URL is not supported
|
||||||
else -> null
|
else -> null
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.impl.permalink
|
package io.element.android.libraries.matrix.impl.permalink
|
||||||
|
|
||||||
import android.net.Uri
|
import androidx.core.net.toUri
|
||||||
import com.squareup.anvil.annotations.ContributesBinding
|
import com.squareup.anvil.annotations.ContributesBinding
|
||||||
import io.element.android.libraries.di.AppScope
|
import io.element.android.libraries.di.AppScope
|
||||||
import io.element.android.libraries.matrix.api.core.EventId
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
|
|
@ -38,7 +38,7 @@ class DefaultPermalinkParser @Inject constructor(
|
||||||
* https://github.com/matrix-org/matrix-doc/blob/master/proposals/1704-matrix.to-permalinks.md
|
* https://github.com/matrix-org/matrix-doc/blob/master/proposals/1704-matrix.to-permalinks.md
|
||||||
*/
|
*/
|
||||||
override fun parse(uriString: String): PermalinkData {
|
override fun parse(uriString: String): PermalinkData {
|
||||||
val uri = Uri.parse(uriString)
|
val uri = uriString.toUri()
|
||||||
// the client or element-based domain permalinks (e.g. https://app.element.io/#/user/@chagai95:matrix.org) don't have the
|
// the client or element-based domain permalinks (e.g. https://app.element.io/#/user/@chagai95:matrix.org) don't have the
|
||||||
// mxid in the first param (like matrix.to does - https://matrix.to/#/@chagai95:matrix.org) but rather in the second after /user/ so /user/mxid
|
// mxid in the first param (like matrix.to does - https://matrix.to/#/@chagai95:matrix.org) but rather in the second after /user/ so /user/mxid
|
||||||
// so convert URI to matrix.to to simplify parsing process
|
// so convert URI to matrix.to to simplify parsing process
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,13 @@ import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.semantics.clearAndSetSemantics
|
||||||
|
import androidx.compose.ui.semantics.contentDescription
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.core.net.toUri
|
||||||
import io.element.android.compound.theme.ElementTheme
|
import io.element.android.compound.theme.ElementTheme
|
||||||
import io.element.android.compound.tokens.generated.CompoundIcons
|
import io.element.android.compound.tokens.generated.CompoundIcons
|
||||||
import io.element.android.libraries.designsystem.components.avatar.Avatar
|
import io.element.android.libraries.designsystem.components.avatar.Avatar
|
||||||
|
|
@ -36,6 +40,7 @@ import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
import io.element.android.libraries.designsystem.theme.components.Icon
|
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||||
import io.element.android.libraries.testtags.TestTags
|
import io.element.android.libraries.testtags.TestTags
|
||||||
import io.element.android.libraries.testtags.testTag
|
import io.element.android.libraries.testtags.testTag
|
||||||
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun EditableAvatarView(
|
fun EditableAvatarView(
|
||||||
|
|
@ -50,6 +55,7 @@ fun EditableAvatarView(
|
||||||
modifier = modifier.fillMaxWidth(),
|
modifier = modifier.fillMaxWidth(),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
) {
|
) {
|
||||||
|
val a11yAvatar = stringResource(CommonStrings.a11y_avatar)
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(avatarSize.dp)
|
.size(avatarSize.dp)
|
||||||
|
|
@ -59,6 +65,9 @@ fun EditableAvatarView(
|
||||||
indication = ripple(bounded = false),
|
indication = ripple(bounded = false),
|
||||||
)
|
)
|
||||||
.testTag(TestTags.editAvatar)
|
.testTag(TestTags.editAvatar)
|
||||||
|
.clearAndSetSemantics {
|
||||||
|
contentDescription = a11yAvatar
|
||||||
|
},
|
||||||
) {
|
) {
|
||||||
when (avatarUrl?.scheme) {
|
when (avatarUrl?.scheme) {
|
||||||
null, "mxc" -> {
|
null, "mxc" -> {
|
||||||
|
|
@ -112,7 +121,7 @@ open class EditableAvatarViewUriProvider : PreviewParameterProvider<Uri?> {
|
||||||
override val values: Sequence<Uri?>
|
override val values: Sequence<Uri?>
|
||||||
get() = sequenceOf(
|
get() = sequenceOf(
|
||||||
null,
|
null,
|
||||||
Uri.parse("mxc://matrix.org/123456"),
|
"mxc://matrix.org/123456".toUri(),
|
||||||
Uri.parse("https://example.com/avatar.jpg"),
|
"https://example.com/avatar.jpg".toUri(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,10 @@ package io.element.android.libraries.oidc.impl.customtab
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
|
||||||
import androidx.browser.customtabs.CustomTabsClient
|
import androidx.browser.customtabs.CustomTabsClient
|
||||||
import androidx.browser.customtabs.CustomTabsServiceConnection
|
import androidx.browser.customtabs.CustomTabsServiceConnection
|
||||||
import androidx.browser.customtabs.CustomTabsSession
|
import androidx.browser.customtabs.CustomTabsSession
|
||||||
|
import androidx.core.net.toUri
|
||||||
import io.element.android.libraries.androidutils.browser.openUrlInChromeCustomTab
|
import io.element.android.libraries.androidutils.browser.openUrlInChromeCustomTab
|
||||||
import io.element.android.libraries.di.ApplicationContext
|
import io.element.android.libraries.di.ApplicationContext
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
@ -55,7 +55,7 @@ class CustomTabHandler @Inject constructor(
|
||||||
customTabsSession = customTabsClient?.newSession(null)
|
customTabsSession = customTabsClient?.newSession(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
customTabsSession?.mayLaunchUrl(Uri.parse(url), null, null)
|
customTabsSession?.mayLaunchUrl(url.toUri(), null, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun disposeCustomTab() {
|
fun disposeCustomTab() {
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
package io.element.android.libraries.push.impl.notifications.model
|
package io.element.android.libraries.push.impl.notifications.model
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import androidx.core.net.toUri
|
||||||
import io.element.android.libraries.matrix.api.core.EventId
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.matrix.api.core.SessionId
|
import io.element.android.libraries.matrix.api.core.SessionId
|
||||||
|
|
@ -52,7 +53,7 @@ data class NotifiableMessageEvent(
|
||||||
// Example of value:
|
// Example of value:
|
||||||
// content://io.element.android.x.debug.notifications.fileprovider/downloads/temp/notif/matrix.org/XGItzSDOnSyXjYtOPfiKexDJ
|
// content://io.element.android.x.debug.notifications.fileprovider/downloads/temp/notif/matrix.org/XGItzSDOnSyXjYtOPfiKexDJ
|
||||||
val imageUri: Uri?
|
val imageUri: Uri?
|
||||||
get() = imageUriString?.let { Uri.parse(it) }
|
get() = imageUriString?.toUri()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue