mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-22 09:25:49 +03:00
Threads notification badge UI
This commit is contained in:
parent
0241d66f8e
commit
d1bb96cec0
8 changed files with 183 additions and 14 deletions
4
library/ui-styles/src/main/res/values-v23/dimens.xml
Normal file
4
library/ui-styles/src/main/res/values-v23/dimens.xml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<dimen name="menu_item_ripple_size">28dp</dimen>
|
||||
</resources>
|
|
@ -41,4 +41,8 @@
|
|||
<!-- Navigation Drawer -->
|
||||
<dimen name="navigation_drawer_max_width">320dp</dimen>
|
||||
|
||||
<dimen name="menu_item_icon_size">24dp</dimen>
|
||||
<dimen name="menu_item_size">48dp</dimen>
|
||||
<dimen name="menu_item_ripple_size">48dp</dimen>
|
||||
|
||||
</resources>
|
|
@ -680,17 +680,17 @@ class RoomDetailViewModel @AssistedInject constructor(
|
|||
}
|
||||
} else {
|
||||
when (itemId) {
|
||||
R.id.timeline_setting -> true
|
||||
R.id.invite -> state.canInvite
|
||||
R.id.open_matrix_apps -> true
|
||||
R.id.voice_call -> state.isWebRTCCallOptionAvailable()
|
||||
R.id.video_call -> state.isWebRTCCallOptionAvailable() || state.jitsiState.confId == null || state.jitsiState.hasJoined
|
||||
R.id.timeline_setting -> true
|
||||
R.id.invite -> state.canInvite
|
||||
R.id.open_matrix_apps -> true
|
||||
R.id.voice_call -> state.isWebRTCCallOptionAvailable()
|
||||
R.id.video_call -> state.isWebRTCCallOptionAvailable() || state.jitsiState.confId == null || state.jitsiState.hasJoined
|
||||
// Show Join conference button only if there is an active conf id not joined. Otherwise fallback to default video disabled. ^
|
||||
R.id.join_conference -> !state.isWebRTCCallOptionAvailable() && state.jitsiState.confId != null && !state.jitsiState.hasJoined
|
||||
R.id.search -> true
|
||||
R.id.threads -> BuildConfig.THREADING_ENABLED
|
||||
R.id.dev_tools -> vectorPreferences.developerMode()
|
||||
else -> false
|
||||
R.id.join_conference -> !state.isWebRTCCallOptionAvailable() && state.jitsiState.confId != null && !state.jitsiState.hasJoined
|
||||
R.id.search -> true
|
||||
R.id.menu_timeline_thread_list -> BuildConfig.THREADING_ENABLED
|
||||
R.id.dev_tools -> vectorPreferences.developerMode()
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,12 +36,14 @@ import android.view.MenuItem
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.graphics.drawable.DrawableCompat
|
||||
import androidx.core.net.toUri
|
||||
import androidx.core.text.buildSpannedString
|
||||
import androidx.core.text.toSpannable
|
||||
|
@ -61,6 +63,7 @@ import com.airbnb.epoxy.OnModelBuildFinishedListener
|
|||
import com.airbnb.epoxy.addGlidePreloader
|
||||
import com.airbnb.epoxy.glidePreloader
|
||||
import com.airbnb.mvrx.Mavericks
|
||||
import com.airbnb.mvrx.activityViewModel
|
||||
import com.airbnb.mvrx.args
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
|
@ -133,6 +136,7 @@ import im.vector.app.features.command.Command
|
|||
import im.vector.app.features.crypto.keysbackup.restore.KeysBackupRestoreActivity
|
||||
import im.vector.app.features.crypto.verification.VerificationBottomSheet
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.home.UnreadMessagesSharedViewModel
|
||||
import im.vector.app.features.home.room.detail.arguments.TimelineArgs
|
||||
import im.vector.app.features.home.room.detail.composer.SendMode
|
||||
import im.vector.app.features.home.room.detail.composer.TextComposerAction
|
||||
|
@ -285,6 +289,7 @@ class TimelineFragment @Inject constructor(
|
|||
|
||||
private val roomDetailViewModel: RoomDetailViewModel by fragmentViewModel()
|
||||
private val textComposerViewModel: TextComposerViewModel by fragmentViewModel()
|
||||
|
||||
private val debouncer = Debouncer(createUIHandler())
|
||||
|
||||
private lateinit var scrollOnNewMessageCallback: ScrollOnNewMessageCallback
|
||||
|
@ -907,6 +912,13 @@ class TimelineFragment @Inject constructor(
|
|||
(joinConfItem.actionView as? JoinConferenceView)?.onJoinClicked = {
|
||||
roomDetailViewModel.handle(RoomDetailAction.JoinJitsiCall)
|
||||
}
|
||||
|
||||
// Custom thread notification menu item
|
||||
menu.findItem(R.id.menu_timeline_thread_list)?.let { menuItem ->
|
||||
menuItem.actionView.setOnClickListener {
|
||||
onOptionsItemSelected(menuItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||
|
@ -946,6 +958,10 @@ class TimelineFragment @Inject constructor(
|
|||
actionView.findViewById<TextView>(R.id.cart_badge).setTextOrHide("$widgetsCount")
|
||||
matrixAppsMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS)
|
||||
}
|
||||
|
||||
// Handle custom threads badge notification
|
||||
updateMenuThreadNotificationBadge(menu, state)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -971,7 +987,7 @@ class TimelineFragment @Inject constructor(
|
|||
callActionsHandler.onVideoCallClicked()
|
||||
true
|
||||
}
|
||||
R.id.threads -> {
|
||||
R.id.menu_timeline_thread_list -> {
|
||||
navigateToThreadList()
|
||||
true
|
||||
}
|
||||
|
@ -1007,6 +1023,29 @@ class TimelineFragment @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update menu thread notification badge appropriately
|
||||
*/
|
||||
private fun updateMenuThreadNotificationBadge(menu: Menu, state: RoomDetailViewState) {
|
||||
val menuThreadList = menu.findItem(R.id.menu_timeline_thread_list).actionView
|
||||
val badgeFrameLayout = menuThreadList.findViewById<FrameLayout>(R.id.threadNotificationBadgeFrameLayout)
|
||||
val badgeTextView = menuThreadList.findViewById<TextView>(R.id.threadNotificationBadgeTextView)
|
||||
|
||||
val unreadThreadMessages = 18 + state.pushCounter
|
||||
|
||||
val userIsMentioned = true
|
||||
if (unreadThreadMessages > 0) {
|
||||
badgeFrameLayout.isVisible = true
|
||||
badgeTextView.text = unreadThreadMessages.toString()
|
||||
val badgeDrawable = DrawableCompat.wrap(badgeFrameLayout.background)
|
||||
val color = ContextCompat.getColor(requireContext(), if (userIsMentioned) R.color.palette_vermilion else R.color.palette_gray_200)
|
||||
DrawableCompat.setTint(badgeDrawable, color)
|
||||
badgeFrameLayout.background = badgeDrawable
|
||||
} else {
|
||||
badgeFrameLayout.isVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* View and highlight the original root thread message in the main timeline
|
||||
*/
|
||||
|
|
12
vector/src/main/res/drawable/notification_badge.xml
Normal file
12
vector/src/main/res/drawable/notification_badge.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- "background shadow" -->
|
||||
<!-- background color -->
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<corners android:radius="15dp"/>
|
||||
<solid android:color="?vctr_content_secondary"/>
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
</layer-list>
|
|
@ -0,0 +1,58 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout 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="@dimen/menu_item_size"
|
||||
android:layout_height="@dimen/menu_item_size">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="@dimen/menu_item_ripple_size"
|
||||
android:layout_height="@dimen/menu_item_ripple_size"
|
||||
android:layout_gravity="center"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/menu_item_icon_size"
|
||||
android:layout_height="@dimen/menu_item_icon_size"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/ic_thread_menu_item"
|
||||
tools:ignore="ContentDescription"
|
||||
app:tint="?colorPrimary" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/threadNotificationBadgeFrameLayout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="15dp"
|
||||
android:minWidth="15dp"
|
||||
android:paddingStart="2dp"
|
||||
android:paddingEnd="2dp"
|
||||
android:layout_gravity="top|end"
|
||||
android:layout_marginTop="1dp"
|
||||
android:backgroundTint="@color/palette_gray_200"
|
||||
android:background="@drawable/notification_badge"
|
||||
android:visibility="visible"
|
||||
tools:visibility="visible">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/threadNotificationBadgeTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingEnd="2dp"
|
||||
android:paddingStart="2dp"
|
||||
android:gravity="center"
|
||||
android:layout_gravity="center"
|
||||
android:textColor="@color/palette_white"
|
||||
android:maxLength="3"
|
||||
android:textStyle="bold"
|
||||
android:textSize="10sp"
|
||||
tools:text="99" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -0,0 +1,53 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/notificationConstraintLayout"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/notificationImageView"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:src="@drawable/ic_thread_menu_item" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/notificationBadgeImageView"
|
||||
app:layout_constraintEnd_toEndOf="@+id/notificationImageView"
|
||||
app:layout_constraintTop_toTopOf="@+id/notificationImageView"
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
android:src="@drawable/notification_badge"
|
||||
android:visibility="gone"
|
||||
tools:ignore="ContentDescription"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/notificationBadgeTextView"
|
||||
style="@style/Widget.Vector.TextView.Subtitle"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/notificationBadgeImageView"
|
||||
app:layout_constraintEnd_toEndOf="@+id/notificationBadgeImageView"
|
||||
app:layout_constraintStart_toStartOf="@+id/notificationBadgeImageView"
|
||||
app:layout_constraintTop_toTopOf="@+id/notificationBadgeImageView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:textSize="11sp"
|
||||
android:visibility="gone"
|
||||
tools:text="8"
|
||||
tools:visibility="visible" />
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -38,14 +38,13 @@
|
|||
tools:visible="true" />
|
||||
|
||||
<item
|
||||
android:id="@+id/threads"
|
||||
android:icon="@drawable/ic_thread_menu_item"
|
||||
android:id="@+id/menu_timeline_thread_list"
|
||||
android:title="@string/action_view_threads"
|
||||
android:visible="false"
|
||||
app:iconTint="?colorPrimary"
|
||||
app:actionLayout="@layout/view_thread_notification_badge"
|
||||
app:showAsAction="always"
|
||||
tools:visible="true" />
|
||||
|
||||
<item
|
||||
android:id="@+id/join_conference"
|
||||
android:title="@string/join"
|
||||
|
|
Loading…
Reference in a new issue