From bd955eec32daad8ece75cad4d3311815b7faba8b Mon Sep 17 00:00:00 2001 From: Taras Smakula <tarassmakula@gmail.com> Date: Tue, 14 Nov 2023 17:30:51 +0200 Subject: [PATCH] Add blur for circles --- .../feature/circles/CirclesDataSource.kt | 42 +++++++++++++++++-- .../feature/circles/CirclesFragment.kt | 3 ++ .../feature/circles/CirclesViewModel.kt | 8 +++- .../circles/list/CirclesListAdapter.kt | 6 ++- .../feature/circles/list/CirclesViewHolder.kt | 18 ++++---- .../circles/mapping/RoomSummaryMapping.kt | 5 ++- .../org/futo/circles/model/CircleListItem.kt | 1 + .../res/layout/list_item_invited_circle.xml | 17 ++++++++ 8 files changed, 84 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/org/futo/circles/feature/circles/CirclesDataSource.kt b/app/src/main/java/org/futo/circles/feature/circles/CirclesDataSource.kt index 184b79801..ad3c3d1a1 100644 --- a/app/src/main/java/org/futo/circles/feature/circles/CirclesDataSource.kt +++ b/app/src/main/java/org/futo/circles/feature/circles/CirclesDataSource.kt @@ -2,9 +2,12 @@ package org.futo.circles.feature.circles import androidx.lifecycle.asFlow import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.update import kotlinx.coroutines.withContext +import org.futo.circles.core.extensions.getKnownUsersFlow import org.futo.circles.core.feature.workspace.SharedCircleDataSource import org.futo.circles.core.feature.workspace.SpacesTreeAccountDataSource import org.futo.circles.core.model.CIRCLES_SPACE_ACCOUNT_DATA_KEY @@ -25,18 +28,34 @@ class CirclesDataSource @Inject constructor( private val sharedCircleDataSource: SharedCircleDataSource ) { + private val roomIdsToUnblurProfile = MutableStateFlow<Set<String>>(emptySet()) + fun getCirclesFlow() = combine( MatrixSessionProvider.getSessionOrThrow().roomService() .getRoomSummariesLive(roomSummaryQueryParams { excludeType = null }) .asFlow(), + MatrixSessionProvider.getSessionOrThrow().getKnownUsersFlow(), + roomIdsToUnblurProfile, MatrixSessionProvider.getSessionOrThrow().roomService().getChangeMembershipsLive().asFlow() - ) { roomSummaries, _ -> - withContext(Dispatchers.IO) { buildCirclesList(roomSummaries) } + ) { roomSummaries, knownUsers, roomIdsToUnblur, _ -> + withContext(Dispatchers.IO) { + buildCirclesList( + roomSummaries, + knownUsers.map { it.userId }.toSet(), + roomIdsToUnblur + ) + } }.distinctUntilChanged() - private fun buildCirclesList(list: List<RoomSummary>): List<CircleListItem> { + private fun buildCirclesList( + list: List<RoomSummary>, + knownUsersIds: Set<String>, + roomIdsToUnblur: Set<String> + ): List<CircleListItem> { val invites = - list.filter { isInviteToCircleTimeline(it) }.map { it.toInviteCircleListItem() } + list.filter { isInviteToCircleTimeline(it) }.map { it.toInviteCircleListItem( + shouldBlurIconFor(it, knownUsersIds, roomIdsToUnblur) + ) } val joinedCirclesSpaceIds = getJoinedCirclesIds() val joinedCircles = list.filter { isJoinedCircle(it, joinedCirclesSpaceIds) } @@ -88,4 +107,19 @@ class CirclesDataSource @Inject constructor( addAll(items) } } + + private fun shouldBlurIconFor( + roomSummary: RoomSummary, + knownUserIds: Set<String>, + roomIdsToUnblur: Set<String> + ): Boolean { + val isKnownUser = knownUserIds.contains(roomSummary.inviterId) + val isRoomUnbluredByUser = roomIdsToUnblur.contains(roomSummary.roomId) + val hasIcon = roomSummary.avatarUrl.isNotEmpty() + return !isKnownUser && !isRoomUnbluredByUser && hasIcon + } + + fun unblurProfileImageFor(id: String) { + roomIdsToUnblurProfile.update { set -> set.toMutableSet().apply { add(id) } } + } } \ No newline at end of file diff --git a/app/src/main/java/org/futo/circles/feature/circles/CirclesFragment.kt b/app/src/main/java/org/futo/circles/feature/circles/CirclesFragment.kt index 73b29c4ea..079fe7cad 100644 --- a/app/src/main/java/org/futo/circles/feature/circles/CirclesFragment.kt +++ b/app/src/main/java/org/futo/circles/feature/circles/CirclesFragment.kt @@ -81,6 +81,9 @@ class CirclesFragment : Fragment(org.futo.circles.core.R.layout.fragment_rooms), onRoomClicked = { roomListItem -> onRoomListItemClicked(roomListItem) }, onInviteClicked = { roomListItem, isAccepted -> onInviteClicked(roomListItem, isAccepted) + }, + onUnblurProfileIconClicked = { roomListItem -> + viewModel.unblurProfileIcon(roomListItem) } ).also { listAdapter = it } bindToFab(binding.fbAddRoom) diff --git a/app/src/main/java/org/futo/circles/feature/circles/CirclesViewModel.kt b/app/src/main/java/org/futo/circles/feature/circles/CirclesViewModel.kt index abd3ae344..bf1bfeb1e 100644 --- a/app/src/main/java/org/futo/circles/feature/circles/CirclesViewModel.kt +++ b/app/src/main/java/org/futo/circles/feature/circles/CirclesViewModel.kt @@ -15,12 +15,14 @@ import org.futo.circles.core.feature.room.invite.InviteRequestsDataSource import org.futo.circles.core.model.LoadingData import org.futo.circles.core.provider.MatrixSessionProvider import org.futo.circles.core.utils.getTimelineRoomFor +import org.futo.circles.model.CircleListItem +import org.futo.circles.model.GroupListItem import org.matrix.android.sdk.api.session.getRoomSummary import javax.inject.Inject @HiltViewModel class CirclesViewModel @Inject constructor( - dataSource: CirclesDataSource, + private val dataSource: CirclesDataSource, private val inviteRequestsDataSource: InviteRequestsDataSource, private val createRoomDataSource: CreateRoomDataSource ) : ViewModel() { @@ -55,4 +57,8 @@ class CirclesViewModel @Inject constructor( } } + fun unblurProfileIcon(roomListItem: CircleListItem) { + dataSource.unblurProfileImageFor(roomListItem.id) + } + } \ No newline at end of file diff --git a/app/src/main/java/org/futo/circles/feature/circles/list/CirclesListAdapter.kt b/app/src/main/java/org/futo/circles/feature/circles/list/CirclesListAdapter.kt index 4d123814b..bd1d6fa24 100644 --- a/app/src/main/java/org/futo/circles/feature/circles/list/CirclesListAdapter.kt +++ b/app/src/main/java/org/futo/circles/feature/circles/list/CirclesListAdapter.kt @@ -12,7 +12,8 @@ enum class CirclesListItemViewType { JoinedCircle, InvitedCircle, Header } class CirclesListAdapter( private val onRoomClicked: (CircleListItem) -> Unit, - private val onInviteClicked: (CircleListItem, Boolean) -> Unit + private val onInviteClicked: (CircleListItem, Boolean) -> Unit, + private val onUnblurProfileIconClicked: (CircleListItem) -> Unit ) : BaseRvAdapter<CircleListItem, CirclesViewHolder>(PayloadIdEntityCallback { old, new -> if (new is JoinedCircleListItem && old is JoinedCircleListItem) { CircleListItemPayload( @@ -44,6 +45,9 @@ class CirclesListAdapter( parent = parent, onInviteClicked = { position, isAccepted -> onInviteClicked(getItem(position), isAccepted) + }, + onShowProfileIconClicked = { position -> + onUnblurProfileIconClicked(getItem(position)) } ) diff --git a/app/src/main/java/org/futo/circles/feature/circles/list/CirclesViewHolder.kt b/app/src/main/java/org/futo/circles/feature/circles/list/CirclesViewHolder.kt index 85495bd21..c5ac09278 100644 --- a/app/src/main/java/org/futo/circles/feature/circles/list/CirclesViewHolder.kt +++ b/app/src/main/java/org/futo/circles/feature/circles/list/CirclesViewHolder.kt @@ -2,7 +2,6 @@ package org.futo.circles.feature.circles.list import android.view.View import android.view.ViewGroup -import android.widget.ImageView import android.widget.TextView import androidx.recyclerview.widget.RecyclerView import org.futo.circles.R @@ -23,10 +22,6 @@ import org.futo.circles.model.JoinedCircleListItem abstract class CirclesViewHolder(view: View) : RecyclerView.ViewHolder(view) { abstract fun bind(data: CircleListItem) - protected fun setIcon(groupIcon: ImageView, avatarUrl: String?, title: String) { - groupIcon.loadProfileIcon(avatarUrl, title) - } - protected fun setTitle(titleView: TextView, title: String) { titleView.text = title } @@ -50,7 +45,7 @@ class JoinedCircleViewHolder( if (data !is JoinedCircleListItem) return with(binding) { - setIcon(ivCircle, data.info.avatarUrl, data.info.title) + ivCircle.loadProfileIcon(data.info.avatarUrl, data.info.title) setTitle(tvCircleTitle, data.info.title) setFollowingCount(data.followingCount) setFollowedByCount(data.followedByCount) @@ -89,7 +84,8 @@ class JoinedCircleViewHolder( class InvitedCircleViewHolder( parent: ViewGroup, - onInviteClicked: (Int, Boolean) -> Unit + onInviteClicked: (Int, Boolean) -> Unit, + onShowProfileIconClicked: (Int) -> Unit ) : CirclesViewHolder(inflate(parent, ListItemInvitedCircleBinding::inflate)) { private companion object : ViewBindingHolder @@ -99,13 +95,19 @@ class InvitedCircleViewHolder( init { onClick(binding.btnAccept) { position -> onInviteClicked(position, true) } onClick(binding.btnDecline) { position -> onInviteClicked(position, false) } + onClick(binding.ivCircle) { position -> onShowProfileIconClicked(position) } } override fun bind(data: CircleListItem) { if (data !is InvitedCircleListItem) return with(binding) { - setIcon(ivCircle, data.info.avatarUrl, data.info.title) + tvShowProfileImage.setIsVisible(data.shouldBlurIcon) + ivCircle.loadProfileIcon( + data.info.avatarUrl, + data.info.title, + applyBlur = data.shouldBlurIcon + ) setTitle(tvCircleTitle, data.info.title) binding.tvInvitedBy.text = context.getString( diff --git a/app/src/main/java/org/futo/circles/mapping/RoomSummaryMapping.kt b/app/src/main/java/org/futo/circles/mapping/RoomSummaryMapping.kt index d29d694aa..724e2c14e 100644 --- a/app/src/main/java/org/futo/circles/mapping/RoomSummaryMapping.kt +++ b/app/src/main/java/org/futo/circles/mapping/RoomSummaryMapping.kt @@ -47,10 +47,11 @@ fun RoomSummary.toJoinedCircleListItem(isShared: Boolean = false) = JoinedCircle knockRequestsCount = getKnocksCount(getTimelineRoomFor(roomId)?.roomId ?: "") ) -fun RoomSummary.toInviteCircleListItem() = InvitedCircleListItem( +fun RoomSummary.toInviteCircleListItem(shouldBlurIcon: Boolean) = InvitedCircleListItem( id = roomId, info = toRoomInfo(), - inviterName = getInviterName() + inviterName = getInviterName(), + shouldBlurIcon = shouldBlurIcon ) private fun RoomSummary.getFollowersCount(): Int = diff --git a/app/src/main/java/org/futo/circles/model/CircleListItem.kt b/app/src/main/java/org/futo/circles/model/CircleListItem.kt index e847980f2..b11467fed 100644 --- a/app/src/main/java/org/futo/circles/model/CircleListItem.kt +++ b/app/src/main/java/org/futo/circles/model/CircleListItem.kt @@ -38,5 +38,6 @@ data class InvitedCircleListItem( override val id: String, override val info: RoomInfo, val inviterName: String, + val shouldBlurIcon: Boolean ) : CircleRoomListItem(id, info, Membership.INVITE) diff --git a/app/src/main/res/layout/list_item_invited_circle.xml b/app/src/main/res/layout/list_item_invited_circle.xml index 3f6dec433..cc1d80790 100644 --- a/app/src/main/res/layout/list_item_invited_circle.xml +++ b/app/src/main/res/layout/list_item_invited_circle.xml @@ -24,6 +24,23 @@ app:strokeWidth="1dp" tools:src="@color/blue" /> + <TextView + android:id="@+id/tvShowProfileImage" + style="@style/body" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:drawablePadding="-4dp" + android:text="@string/show" + android:textColor="@color/white" + android:visibility="gone" + app:drawableTint="@color/white" + app:drawableTopCompat="@drawable/ic_seen" + app:layout_constraintBottom_toBottomOf="@id/ivCircle" + app:layout_constraintEnd_toEndOf="@id/ivCircle" + app:layout_constraintStart_toStartOf="@id/ivCircle" + app:layout_constraintTop_toTopOf="@id/ivCircle" + tools:visibility="visible" /> + <TextView android:id="@+id/tvCircleTitle" -- GitLab