Merge pull request #5411 from vector-im/feature/mna/PSF-735-sharing-options-view

#5395: Location sharing options view
This commit is contained in:
Maxime NATUREL 2022-03-09 16:10:46 +01:00 committed by GitHub
commit f12afe0ef0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 475 additions and 69 deletions

1
changelog.d/5395.feature Normal file
View file

@ -0,0 +1 @@
Add a custom view to display a picker for share location options

View file

@ -139,4 +139,8 @@
<color name="vctr_presence_indicator_offline_light">@color/palette_gray_100</color>
<color name="vctr_presence_indicator_offline_dark">@color/palette_gray_450</color>
<!-- Location sharing colors -->
<attr name="vctr_live_location" format="color" />
<color name="vctr_live_location_light">@color/palette_prune</color>
<color name="vctr_live_location_dark">@color/palette_prune</color>
</resources>

View file

@ -70,4 +70,7 @@
<item name="ftue_auth_profile_picture_height" format="float" type="dimen">0.15</item>
<item name="ftue_auth_profile_picture_icon_height" format="float" type="dimen">0.05</item>
<!-- Location sharing -->
<dimen name="location_sharing_option_default_padding">10dp</dimen>
</resources>

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="LocationSharingOptionView">
<attr name="locShareIcon" format="reference" />
<attr name="locShareIconBackground" format="reference" />
<attr name="locShareIconBackgroundTint" format="color" />
<attr name="locShareIconPadding" format="dimension" />
<attr name="locShareIconDescription" format="string" />
<attr name="locShareTitle" format="string" />
</declare-styleable>
</resources>

View file

@ -145,6 +145,8 @@
<item name="android:actionButtonStyle">@style/Widget.Vector.ActionButton</item>
<!-- Location sharing -->
<item name="vctr_live_location">@color/vctr_live_location_dark</item>
</style>
<style name="Theme.Vector.Dark" parent="Base.Theme.Vector.Dark" />

View file

@ -146,6 +146,8 @@
<item name="android:actionButtonStyle">@style/Widget.Vector.ActionButton</item>
<!-- Location sharing -->
<item name="vctr_live_location">@color/vctr_live_location_light</item>
</style>
<style name="Theme.Vector.Light" parent="Base.Theme.Vector.Light" />

View file

@ -23,6 +23,7 @@ import android.view.ViewGroup
import android.widget.EditText
import android.widget.ImageView
import androidx.annotation.AttrRes
import androidx.annotation.ColorInt
import androidx.annotation.DrawableRes
import androidx.appcompat.widget.SearchView
import androidx.core.content.ContextCompat
@ -70,6 +71,15 @@ fun View.setAttributeTintedBackground(@DrawableRes drawableRes: Int, @AttrRes ti
background = drawable
}
fun View.tintBackground(@ColorInt tintColor: Int) {
val bkg = background?.let {
val backgroundDrawable = DrawableCompat.wrap(background)
DrawableCompat.setTint(backgroundDrawable, tintColor)
backgroundDrawable
}
background = bkg
}
fun ImageView.setAttributeTintedImageResource(@DrawableRes drawableRes: Int, @AttrRes tint: Int) {
val drawable = ContextCompat.getDrawable(context, drawableRes)!!
DrawableCompat.setTint(drawable, ThemeUtils.getColor(context, tint))

View file

@ -19,7 +19,9 @@ package im.vector.app.features.home.room.detail.timeline.helper
import android.content.Context
import android.graphics.drawable.Drawable
import android.graphics.drawable.LayerDrawable
import androidx.annotation.ColorInt
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.DrawableCompat
import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.transition.Transition
import im.vector.app.R
@ -37,7 +39,8 @@ class LocationPinProvider @Inject constructor(
private val context: Context,
private val activeSessionHolder: ActiveSessionHolder,
private val dimensionConverter: DimensionConverter,
private val avatarRenderer: AvatarRenderer
private val avatarRenderer: AvatarRenderer,
private val matrixItemColorProvider: MatrixItemColorProvider
) {
private val cache = mutableMapOf<String, Drawable>()
@ -61,35 +64,42 @@ class LocationPinProvider @Inject constructor(
return
}
activeSessionHolder.getActiveSession().getUser(userId)?.toMatrixItem()?.let {
val size = dimensionConverter.dpToPx(44)
avatarRenderer.render(glideRequests, it, object : CustomTarget<Drawable>(size, size) {
override fun onResourceReady(resource: Drawable, transition: Transition<in Drawable>?) {
Timber.d("## Location: onResourceReady")
val pinDrawable = createPinDrawable(resource)
cache[userId] = pinDrawable
callback(pinDrawable)
}
activeSessionHolder
.getActiveSession()
.getUser(userId)
?.toMatrixItem()
?.let { userItem ->
val size = dimensionConverter.dpToPx(44)
val bgTintColor = matrixItemColorProvider.getColor(userItem)
avatarRenderer.render(glideRequests, userItem, object : CustomTarget<Drawable>(size, size) {
override fun onResourceReady(resource: Drawable, transition: Transition<in Drawable>?) {
Timber.d("## Location: onResourceReady")
val pinDrawable = createPinDrawable(resource, bgTintColor)
cache[userId] = pinDrawable
callback(pinDrawable)
}
override fun onLoadCleared(placeholder: Drawable?) {
// Is it possible? Put placeholder instead?
// FIXME The doc says it has to be implemented and should free resources
Timber.d("## Location: onLoadCleared")
}
override fun onLoadCleared(placeholder: Drawable?) {
// Is it possible? Put placeholder instead?
// FIXME The doc says it has to be implemented and should free resources
Timber.d("## Location: onLoadCleared")
}
override fun onLoadFailed(errorDrawable: Drawable?) {
Timber.w("## Location: onLoadFailed")
errorDrawable ?: return
val pinDrawable = createPinDrawable(errorDrawable)
cache[userId] = pinDrawable
callback(pinDrawable)
override fun onLoadFailed(errorDrawable: Drawable?) {
Timber.w("## Location: onLoadFailed")
errorDrawable ?: return
val pinDrawable = createPinDrawable(errorDrawable, bgTintColor)
cache[userId] = pinDrawable
callback(pinDrawable)
}
})
}
})
}
}
private fun createPinDrawable(drawable: Drawable): Drawable {
private fun createPinDrawable(drawable: Drawable, @ColorInt bgTintColor: Int): Drawable {
val bgUserPin = ContextCompat.getDrawable(context, R.drawable.bg_map_user_pin)!!
// use mutate on drawable to avoid sharing the color when we have multiple different user pins
DrawableCompat.setTint(bgUserPin.mutate(), bgTintColor)
val layerDrawable = LayerDrawable(arrayOf(bgUserPin, drawable))
val horizontalInset = dimensionConverter.dpToPx(4)
val topInset = dimensionConverter.dpToPx(4)

View file

@ -30,6 +30,10 @@ import im.vector.app.R
import im.vector.app.core.extensions.exhaustive
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentLocationSharingBinding
import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.home.room.detail.timeline.helper.MatrixItemColorProvider
import im.vector.app.features.location.option.LocationSharingOption
import org.matrix.android.sdk.api.util.MatrixItem
import java.lang.ref.WeakReference
import javax.inject.Inject
@ -37,7 +41,9 @@ import javax.inject.Inject
* We should consider using SupportMapFragment for a out of the box lifecycle handling
*/
class LocationSharingFragment @Inject constructor(
private val urlMapProvider: UrlMapProvider
private val urlMapProvider: UrlMapProvider,
private val avatarRenderer: AvatarRenderer,
private val matrixItemColorProvider: MatrixItemColorProvider
) : VectorBaseFragment<FragmentLocationSharingBinding>() {
private val viewModel: LocationSharingViewModel by fragmentViewModel()
@ -45,6 +51,8 @@ class LocationSharingFragment @Inject constructor(
// Keep a ref to handle properly the onDestroy callback
private var mapView: WeakReference<MapView>? = null
private var hasRenderedUserAvatar = false
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLocationSharingBinding {
return FragmentLocationSharingBinding.inflate(inflater, container, false)
}
@ -59,9 +67,7 @@ class LocationSharingFragment @Inject constructor(
views.mapView.initialize(urlMapProvider.getMapUrl())
}
views.shareLocationContainer.debouncedClicks {
viewModel.handle(LocationSharingAction.OnShareLocation)
}
initOptionsPicker()
viewModel.observeViewEvents {
when (it) {
@ -107,6 +113,12 @@ class LocationSharingFragment @Inject constructor(
super.onDestroy()
}
override fun invalidate() = withState(viewModel) { state ->
views.mapView.render(state.toMapState())
views.shareLocationGpsLoading.isGone = state.lastKnownLocation != null
updateUserAvatar(state.userItem)
}
private fun handleLocationNotAvailableError() {
MaterialAlertDialogBuilder(requireActivity())
.setTitle(R.string.location_not_available_dialog_title)
@ -118,8 +130,28 @@ class LocationSharingFragment @Inject constructor(
.show()
}
override fun invalidate() = withState(viewModel) { state ->
views.mapView.render(state.toMapState())
views.shareLocationGpsLoading.isGone = state.lastKnownLocation != null
private fun initOptionsPicker() {
// TODO
// change the options dynamically depending on the current chosen location
views.shareLocationOptionsPicker.render(LocationSharingOption.USER_CURRENT)
views.shareLocationOptionsPicker.optionPinned.debouncedClicks {
// TODO
}
views.shareLocationOptionsPicker.optionUserCurrent.debouncedClicks {
viewModel.handle(LocationSharingAction.OnShareLocation)
}
views.shareLocationOptionsPicker.optionUserLive.debouncedClicks {
// TODO
}
}
private fun updateUserAvatar(userItem: MatrixItem.UserItem?) {
userItem?.takeUnless { hasRenderedUserAvatar }
?.let {
hasRenderedUserAvatar = true
avatarRenderer.render(it, views.shareLocationOptionsPicker.optionUserCurrent.iconView)
val tintColor = matrixItemColorProvider.getColor(it)
views.shareLocationOptionsPicker.optionUserCurrent.setIconBackgroundTint(tintColor)
}
}
}

View file

@ -26,6 +26,7 @@ import im.vector.app.core.extensions.exhaustive
import im.vector.app.core.platform.VectorViewModel
import im.vector.app.features.home.room.detail.timeline.helper.LocationPinProvider
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.util.toMatrixItem
class LocationSharingViewModel @AssistedInject constructor(
@Assisted private val initialState: LocationSharingViewState,
@ -45,9 +46,14 @@ class LocationSharingViewModel @AssistedInject constructor(
init {
locationTracker.start(this)
setUserItem()
createPin()
}
private fun setUserItem() {
setState { copy(userItem = session.getUser(session.myUserId)?.toMatrixItem()) }
}
private fun createPin() {
locationPinProvider.create(session.myUserId) {
setState {

View file

@ -20,6 +20,7 @@ import android.graphics.drawable.Drawable
import androidx.annotation.StringRes
import com.airbnb.mvrx.MavericksState
import im.vector.app.R
import org.matrix.android.sdk.api.util.MatrixItem
enum class LocationSharingMode(@StringRes val titleRes: Int) {
STATIC_SHARING(R.string.location_activity_title_static_sharing),
@ -29,6 +30,7 @@ enum class LocationSharingMode(@StringRes val titleRes: Int) {
data class LocationSharingViewState(
val roomId: String,
val mode: LocationSharingMode,
val userItem: MatrixItem.UserItem? = null,
val lastKnownLocation: LocationData? = null,
val pinDrawable: Drawable? = null
) : MavericksState {

View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2022 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.app.features.location.option
enum class LocationSharingOption {
/**
* Current user's location.
*/
USER_CURRENT,
/**
* User's location during a certain amount of time.
*/
USER_LIVE,
/**
* Static location pinned by the user.
*/
PINNED
}

View file

@ -0,0 +1,86 @@
/*
* Copyright (c) 2022 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.app.features.location.option
import android.content.Context
import android.util.AttributeSet
import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import im.vector.app.R
import im.vector.app.databinding.ViewLocationSharingOptionPickerBinding
/**
* Custom view to display the location sharing option picker.
*/
class LocationSharingOptionPickerView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr) {
val optionPinned: LocationSharingOptionView
get() = binding.locationSharingOptionPinned
val optionUserCurrent: LocationSharingOptionView
get() = binding.locationSharingOptionUserCurrent
val optionUserLive: LocationSharingOptionView
get() = binding.locationSharingOptionUserLive
private val divider1: View
get() = binding.locationSharingOptionsDivider1
private val divider2: View
get() = binding.locationSharingOptionsDivider2
private val binding = ViewLocationSharingOptionPickerBinding.inflate(
LayoutInflater.from(context),
this
)
init {
applyBackground()
}
fun render(vararg options: LocationSharingOption) {
val optionsNumber = options.toSet().size
val isPinnedVisible = options.contains(LocationSharingOption.PINNED)
val isUserCurrentVisible = options.contains(LocationSharingOption.USER_CURRENT)
val isUserLiveVisible = options.contains(LocationSharingOption.USER_LIVE)
optionPinned.isVisible = isPinnedVisible
divider1.isVisible = isPinnedVisible && optionsNumber > 1
optionUserCurrent.isVisible = isUserCurrentVisible
divider2.isVisible = isUserCurrentVisible && isUserLiveVisible
optionUserLive.isVisible = isUserLiveVisible
}
private fun applyBackground() {
val outValue = TypedValue()
context.theme.resolveAttribute(
R.attr.colorSurface,
outValue,
true
)
binding.root.background = ContextCompat.getDrawable(
context,
outValue.resourceId
)
}
}

View file

@ -0,0 +1,91 @@
/*
* Copyright (c) 2022 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.app.features.location.option
import android.content.Context
import android.content.res.TypedArray
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.ImageView
import androidx.annotation.ColorInt
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.core.view.setPadding
import im.vector.app.R
import im.vector.app.core.extensions.tintBackground
import im.vector.app.databinding.ViewLocationSharingOptionBinding
/**
* Custom view to display a location sharing option.
*/
class LocationSharingOptionView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr) {
val iconView: ImageView
get() = binding.shareLocationOptionIcon
private val binding = ViewLocationSharingOptionBinding.inflate(
LayoutInflater.from(context),
this
)
init {
context.theme.obtainStyledAttributes(
attrs,
R.styleable.LocationSharingOptionView,
0,
0
).run {
try {
setIcon(this)
setTitle(this)
} finally {
recycle()
}
}
}
fun setIconBackgroundTint(@ColorInt color: Int) {
binding.shareLocationOptionIcon.tintBackground(color)
}
private fun setIcon(typedArray: TypedArray) {
val icon = typedArray.getDrawable(R.styleable.LocationSharingOptionView_locShareIcon)
val background = typedArray.getDrawable(R.styleable.LocationSharingOptionView_locShareIconBackground)
val backgroundTint = typedArray.getColor(
R.styleable.LocationSharingOptionView_locShareIconBackgroundTint,
ContextCompat.getColor(context, android.R.color.transparent)
)
val padding = typedArray.getDimensionPixelOffset(
R.styleable.LocationSharingOptionView_locShareIconPadding,
context.resources.getDimensionPixelOffset(R.dimen.location_sharing_option_default_padding)
)
val description = typedArray.getString(R.styleable.LocationSharingOptionView_locShareIconDescription)
iconView.setImageDrawable(icon)
iconView.background = background
iconView.tintBackground(backgroundTint)
iconView.setPadding(padding)
iconView.contentDescription = description
}
private fun setTitle(typedArray: TypedArray) {
val title = typedArray.getString(R.styleable.LocationSharingOptionView_locShareTitle)
binding.shareLocationOptionTitle.text = title
}
}

View file

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="30dp"
android:height="16dp"
android:viewportWidth="30"
android:viewportHeight="16">
<path
android:pathData="M4.6144,14.8367C4.9699,14.4812 5.0048,13.9165 4.6841,13.533C2.007,10.2772 2.007,5.5504 4.6771,2.2877C4.9978,1.8973 4.9699,1.3256 4.6144,0.97C4.2031,0.5587 3.5198,0.5866 3.1503,1.0398C-0.1054,5.0206 -0.1054,10.7792 3.1503,14.767C3.5129,15.2202 4.1961,15.255 4.6144,14.8367ZM7.424,12.0271C7.7656,11.6855 7.8004,11.1487 7.5146,10.7513C6.3085,9.0502 6.3085,6.7635 7.5146,5.0624C7.7935,4.665 7.7656,4.1282 7.424,3.7866L7.417,3.7796C6.9987,3.3613 6.2876,3.3892 5.946,3.8703C4.21,6.2685 4.21,9.5382 5.946,11.9435C6.2945,12.4245 6.9987,12.4524 7.424,12.0271ZM15.3488,1.3771C12.6508,1.3771 10.4686,3.6186 10.4686,6.3901C10.4686,9.3764 13.5501,13.4943 14.819,15.0626C15.0978,15.4064 15.6068,15.4064 15.8856,15.0626C17.1475,13.4943 20.229,9.3764 20.229,6.3901C20.229,3.6186 18.0468,1.3771 15.3488,1.3771ZM15.3488,8.1805C14.3867,8.1805 13.6059,7.3784 13.6059,6.3901C13.6059,5.4018 14.3867,4.5997 15.3488,4.5997C16.3109,4.5997 17.0917,5.4018 17.0917,6.3901C17.0917,7.3784 16.3109,8.1805 15.3488,8.1805ZM25.3431,13.533C25.0224,13.9165 25.0573,14.4812 25.4128,14.8367C25.8311,15.255 26.5144,15.2202 26.8769,14.767C30.1327,10.7792 30.1327,5.0206 26.8769,1.0398C26.5074,0.5866 25.8242,0.5587 25.4128,0.97C25.0573,1.3256 25.0294,1.8973 25.3501,2.2877C28.0203,5.5504 28.0203,10.2772 25.3431,13.533ZM22.5126,10.7513C22.2268,11.1487 22.2616,11.6855 22.6033,12.0271C23.0285,12.4524 23.7327,12.4245 24.0813,11.9435C25.8172,9.5382 25.8172,6.2685 24.0813,3.8703C23.7396,3.3892 23.0285,3.3613 22.6102,3.7796L22.6033,3.7866C22.2616,4.1282 22.2338,4.665 22.5126,5.0624C23.7187,6.7635 23.7187,9.0502 22.5126,10.7513Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
</vector>

View file

@ -9,52 +9,26 @@
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@id/shareLocationContainer"
app:layout_constraintBottom_toTopOf="@id/shareLocationOptionsPicker"
app:layout_constraintTop_toTopOf="parent"
app:mapbox_renderTextureMode="true"
tools:background="#4F00" />
<androidx.constraintlayout.helper.widget.Flow
android:id="@+id/shareLocationContainer"
<im.vector.app.features.location.option.LocationSharingOptionPickerView
android:id="@+id/shareLocationOptionsPicker"
android:layout_width="0dp"
android:layout_height="72dp"
android:background="?android:colorBackground"
android:paddingStart="@dimen/layout_horizontal_margin"
android:paddingEnd="@dimen/layout_horizontal_margin"
app:constraint_referenced_ids="shareLocationImageView,shareLocationText"
app:flow_horizontalBias="0"
app:flow_horizontalGap="8dp"
app:flow_horizontalStyle="packed"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<ImageView
android:id="@+id/shareLocationImageView"
android:layout_width="40dp"
android:layout_height="40dp"
android:background="@drawable/circle"
android:backgroundTint="?colorPrimary"
android:contentDescription="@string/a11y_location_share_icon"
android:padding="10dp"
android:src="@drawable/ic_attachment_location_white" />
<TextView
android:id="@+id/shareLocationText"
style="@style/TextAppearance.Vector.Subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/location_share"
android:textColor="?colorPrimary"
android:textStyle="bold" />
<ProgressBar
android:id="@+id/shareLocationGpsLoading"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginEnd="@dimen/layout_horizontal_margin"
app:layout_constraintBottom_toBottomOf="@id/shareLocationContainer"
app:layout_constraintEnd_toEndOf="@id/shareLocationContainer"
app:layout_constraintTop_toTopOf="@id/shareLocationContainer" />
android:layout_marginBottom="@dimen/layout_vertical_margin"
app:layout_constraintBottom_toBottomOf="@id/shareLocationOptionsPicker"
app:layout_constraintEnd_toEndOf="@id/shareLocationOptionsPicker" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
<androidx.constraintlayout.helper.widget.Flow
android:id="@+id/shareLocationOptionContainer"
android:layout_width="0dp"
android:layout_height="72dp"
android:background="?selectableItemBackground"
android:duplicateParentState="true"
android:paddingStart="@dimen/layout_horizontal_margin"
android:paddingEnd="@dimen/layout_horizontal_margin"
app:constraint_referenced_ids="shareLocationOptionIcon,shareLocationOptionTitle"
app:flow_horizontalBias="0"
app:flow_horizontalGap="8dp"
app:flow_horizontalStyle="packed"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<ImageView
android:id="@+id/shareLocationOptionIcon"
android:layout_width="40dp"
android:layout_height="40dp"
android:contentDescription="@string/a11y_location_share_option_pinned_icon"
tools:background="@drawable/circle"
tools:backgroundTint="?colorPrimary"
tools:padding="11dp"
tools:src="@drawable/ic_attachment_location_white" />
<TextView
android:id="@+id/shareLocationOptionTitle"
style="@style/TextAppearance.Vector.Subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?vctr_content_primary"
tools:text="@string/location_share_option_pinned" />
</merge>

View file

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
<im.vector.app.features.location.option.LocationSharingOptionView
android:id="@+id/locationSharingOptionPinned"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@id/locationSharingOptionUserCurrent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:locShareIcon="@drawable/ic_attachment_location_white"
app:locShareIconBackground="@drawable/circle"
app:locShareIconBackgroundTint="?colorPrimary"
app:locShareIconDescription="@string/a11y_location_share_option_pinned_icon"
app:locShareIconPadding="11dp"
app:locShareTitle="@string/location_share_option_pinned" />
<View
android:id="@+id/locationSharingOptionsDivider1"
android:layout_width="0dp"
android:layout_height="1dp"
android:alpha="0.15"
android:background="?vctr_content_secondary"
app:layout_constraintBottom_toTopOf="@id/locationSharingOptionUserCurrent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/locationSharingOptionPinned" />
<im.vector.app.features.location.option.LocationSharingOptionView
android:id="@+id/locationSharingOptionUserCurrent"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@id/locationSharingOptionUserLive"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/locationSharingOptionPinned"
app:locShareIconBackground="@drawable/circle"
app:locShareIconBackgroundTint="?colorPrimary"
app:locShareIconDescription="@string/a11y_location_share_option_user_current_icon"
app:locShareIconPadding="3dp"
app:locShareTitle="@string/location_share_option_user_current" />
<View
android:id="@+id/locationSharingOptionsDivider2"
android:layout_width="0dp"
android:layout_height="1dp"
android:alpha="0.15"
android:background="?vctr_content_secondary"
app:layout_constraintBottom_toTopOf="@id/locationSharingOptionUserLive"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/locationSharingOptionUserCurrent" />
<im.vector.app.features.location.option.LocationSharingOptionView
android:id="@+id/locationSharingOptionUserLive"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/locationSharingOptionUserCurrent"
app:locShareIcon="@drawable/ic_attachment_location_live_white"
app:locShareIconBackground="@drawable/circle"
app:locShareIconBackgroundTint="?vctr_live_location"
app:locShareIconDescription="@string/a11y_location_share_option_user_live_icon"
app:locShareIconPadding="3dp"
app:locShareTitle="@string/location_share_option_user_live" />
</merge>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<resources xmlns:tools="http://schemas.android.com/tools">
<string name="notice_room_invite_no_invitee">%s\'s invitation</string>
<string name="notice_room_invite_no_invitee_by_you">Your invitation</string>
<string name="notice_room_created">%1$s created the room</string>
@ -2924,9 +2924,17 @@
<!-- Location -->
<string name="location_activity_title_static_sharing">Share location</string>
<string name="location_activity_title_preview">Location</string>
<string name="a11y_location_share_icon">Share location</string>
<!-- TODO delete -->
<string name="a11y_location_share_icon" tools:ignore="UnusedResources">Share location</string>
<string name="a11y_static_map_image">Map</string>
<string name="location_share">Share location</string>
<!-- TODO delete -->
<string name="location_share" tools:ignore="UnusedResources">Share location</string>
<string name="location_share_option_user_current">Share my current location</string>
<string name="a11y_location_share_option_user_current_icon">Share my current location</string>
<string name="location_share_option_user_live">Share live location</string>
<string name="a11y_location_share_option_user_live_icon">Share live location</string>
<string name="location_share_option_pinned">Share this location</string>
<string name="a11y_location_share_option_pinned_icon">Share this location</string>
<string name="location_not_available_dialog_title">${app_name} could not access your location</string>
<string name="location_not_available_dialog_content">${app_name} could not access your location. Please try again later.</string>
<string name="location_share_external">Open with</string>