From 600ec673ce32571b19d6494173843e1313547032 Mon Sep 17 00:00:00 2001 From: Matthew Kevins Date: Tue, 13 Feb 2024 14:11:03 +1000 Subject: [PATCH 01/11] Import block_share icon from Figma designs --- WordPress/src/main/res/drawable/block_share.xml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 WordPress/src/main/res/drawable/block_share.xml diff --git a/WordPress/src/main/res/drawable/block_share.xml b/WordPress/src/main/res/drawable/block_share.xml new file mode 100644 index 000000000000..808524561c95 --- /dev/null +++ b/WordPress/src/main/res/drawable/block_share.xml @@ -0,0 +1,15 @@ + + + + From 7c635c4a8740fdf8dd1b92c987bc4874e2d391b6 Mon Sep 17 00:00:00 2001 From: Matthew Kevins Date: Tue, 13 Feb 2024 14:12:44 +1000 Subject: [PATCH 02/11] Fix broken vector path after import Note: the vector path had to be manually edited after import. The lines in the top arrow were not joined, and it left a small gap at the top corner. --- WordPress/src/main/res/drawable/block_share.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/src/main/res/drawable/block_share.xml b/WordPress/src/main/res/drawable/block_share.xml index 808524561c95..7cd1f17043f0 100644 --- a/WordPress/src/main/res/drawable/block_share.xml +++ b/WordPress/src/main/res/drawable/block_share.xml @@ -4,7 +4,7 @@ android:viewportWidth="24" android:viewportHeight="24"> From ed9e6eda91a1fa3befd1e71fe78acebea8b12b4d Mon Sep 17 00:00:00 2001 From: Matthew Kevins Date: Tue, 13 Feb 2024 14:46:33 +1000 Subject: [PATCH 03/11] Use share icon from the Figma design --- .../android/ui/notifications/adapters/NotesAdapter.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/notifications/adapters/NotesAdapter.kt b/WordPress/src/main/java/org/wordpress/android/ui/notifications/adapters/NotesAdapter.kt index af54aee9c8a5..8aac5864d84f 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/notifications/adapters/NotesAdapter.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/notifications/adapters/NotesAdapter.kt @@ -278,8 +278,7 @@ class NotesAdapter( NoteType.NewPost, NoteType.Reblog, NoteType.Like -> { - // TODO: Use the icon from the Figma design - actionIcon.setImageResource(R.drawable.gb_ic_share) + actionIcon.setImageResource(R.drawable.block_share) actionIcon.isVisible = true actionIcon.setOnClickListener { // TODO: handle tap on comment's inline action icon (the share icon) From 7bb2105d8ab04b9c7eea40de23a88112e1e60ab9 Mon Sep 17 00:00:00 2001 From: Matthew Kevins Date: Tue, 13 Feb 2024 17:28:01 +1000 Subject: [PATCH 04/11] Update notification model to include more types --- .../wordpress/android/models/NoteExtensions.kt | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/models/NoteExtensions.kt b/WordPress/src/main/java/org/wordpress/android/models/NoteExtensions.kt index 47b9159e7530..6685cfffb715 100644 --- a/WordPress/src/main/java/org/wordpress/android/models/NoteExtensions.kt +++ b/WordPress/src/main/java/org/wordpress/android/models/NoteExtensions.kt @@ -1,15 +1,28 @@ package org.wordpress.android.models +import org.wordpress.android.models.Notification.PostNotification.Like +import org.wordpress.android.models.Notification.PostNotification.Reblog +import org.wordpress.android.models.Notification.PostNotification.NewPost + val Note.type get() = NoteType.from(rawType) sealed class Notification { - data class Like(val url: String, val title: String): Notification() + sealed class PostNotification: Notification() { + abstract val url: String + abstract val title: String + data class Like(override val url: String, override val title: String): PostNotification() + data class Reblog(override val url: String, override val title: String): PostNotification() + data class NewPost(override val url: String, override val title: String): PostNotification() + } + data object Comment: Notification() data object Unknown: Notification() companion object { fun from(rawNote: Note) = when(rawNote.type) { - NoteType.Like -> Like(url= rawNote.url, title = rawNote.title) + NoteType.Like -> Like(url = rawNote.url, title = rawNote.title) + NoteType.Reblog -> Reblog(url= rawNote.url, title = rawNote.title) + NoteType.NewPost -> NewPost(url= rawNote.url, title = rawNote.title) else -> Unknown } } From ca979517726703c2a953e41b5272eb8b23fca014 Mon Sep 17 00:00:00 2001 From: Matthew Kevins Date: Tue, 13 Feb 2024 17:28:51 +1000 Subject: [PATCH 05/11] Implement inline action event in notification view model --- .../android/ui/notifications/NotificationsListViewModel.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsListViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsListViewModel.kt index 74fb7d442821..db426415cfd3 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsListViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsListViewModel.kt @@ -8,6 +8,7 @@ import kotlinx.coroutines.CoroutineDispatcher import org.greenrobot.eventbus.EventBus import org.wordpress.android.datasets.NotificationsTable import org.wordpress.android.models.Note +import org.wordpress.android.models.Notification.PostNotification import org.wordpress.android.modules.UI_THREAD import org.wordpress.android.push.GCMMessageHandler import org.wordpress.android.ui.jetpackoverlay.JetpackFeatureRemovalOverlayUtil @@ -76,4 +77,8 @@ class NotificationsListViewModel @Inject constructor( EventBus.getDefault().post(NotificationsChanged()) } } + + sealed class InlineActionEvent { + data class SharePostButtonTapped(val notification: PostNotification): InlineActionEvent() + } } From acf46866de74c71363f0972f21d1ddd16903f0fa Mon Sep 17 00:00:00 2001 From: Matthew Kevins Date: Tue, 13 Feb 2024 17:30:03 +1000 Subject: [PATCH 06/11] Add flow for inline action events --- .../android/ui/notifications/NotificationsListViewModel.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsListViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsListViewModel.kt index db426415cfd3..6299411f80d2 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsListViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsListViewModel.kt @@ -5,6 +5,7 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.MutableSharedFlow import org.greenrobot.eventbus.EventBus import org.wordpress.android.datasets.NotificationsTable import org.wordpress.android.models.Note @@ -37,6 +38,8 @@ class NotificationsListViewModel @Inject constructor( private val _showJetpackOverlay = MutableLiveData>() val showJetpackOverlay: LiveData> = _showJetpackOverlay + val inlineActionEvents = MutableSharedFlow() + val isNotificationsPermissionsWarningDismissed get() = appPrefsWrapper.notificationPermissionsWarningDismissed From d458cc2e265d1dc1789d12638a68f51c0bcda14e Mon Sep 17 00:00:00 2001 From: Matthew Kevins Date: Tue, 13 Feb 2024 17:30:49 +1000 Subject: [PATCH 07/11] Move inline action bind function to inner class This also wires up the post comment actions --- .../ui/notifications/adapters/NotesAdapter.kt | 67 +++++++++++-------- 1 file changed, 40 insertions(+), 27 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/notifications/adapters/NotesAdapter.kt b/WordPress/src/main/java/org/wordpress/android/ui/notifications/adapters/NotesAdapter.kt index 8aac5864d84f..72aaa615a6c0 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/notifications/adapters/NotesAdapter.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/notifications/adapters/NotesAdapter.kt @@ -19,16 +19,23 @@ import androidx.core.text.BidiFormatter import androidx.core.view.ViewCompat import androidx.core.view.isVisible import androidx.recyclerview.widget.RecyclerView +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.launch import org.wordpress.android.R import org.wordpress.android.WordPress import org.wordpress.android.datasets.NotificationsTable import org.wordpress.android.models.Note import org.wordpress.android.models.Note.NoteTimeGroup import org.wordpress.android.models.Note.TimeStampComparator -import org.wordpress.android.models.NoteType -import org.wordpress.android.models.type +import org.wordpress.android.models.Notification +import org.wordpress.android.models.Notification.Comment +import org.wordpress.android.models.Notification.PostNotification +import org.wordpress.android.models.Notification.Unknown import org.wordpress.android.ui.comments.CommentUtils import org.wordpress.android.ui.notifications.NotificationsListFragmentPage.OnNoteClickListener +import org.wordpress.android.ui.notifications.NotificationsListViewModel.InlineActionEvent import org.wordpress.android.ui.notifications.adapters.NotesAdapter.NoteViewHolder import org.wordpress.android.ui.notifications.blocks.NoteBlockClickableSpan import org.wordpress.android.ui.notifications.utils.NotificationsUtilsWrapper @@ -40,7 +47,8 @@ import javax.inject.Inject class NotesAdapter( context: Context, dataLoadedListener: DataLoadedListener, - onLoadMoreListener: OnLoadMoreListener? + onLoadMoreListener: OnLoadMoreListener?, + private val inlineActionEvents: MutableSharedFlow, ) : RecyclerView.Adapter() { private val avatarSize: Int private val textIndentSize: Int @@ -265,30 +273,6 @@ class NotesAdapter( private fun Note.shouldShowMultipleAvatars() = isFollowType || isLikeType || isCommentLikeType - @Suppress("ForbiddenComment") - private fun NoteViewHolder.bindInlineActionIconsForNote(note: Note) { - when (note.type) { - NoteType.Comment -> { - actionIcon.setImageResource(R.drawable.star_empty) - actionIcon.isVisible = true - actionIcon.setOnClickListener { - // TODO: handle tap on comment's inline action icon (the star) - } - } - NoteType.NewPost, - NoteType.Reblog, - NoteType.Like -> { - actionIcon.setImageResource(R.drawable.block_share) - actionIcon.isVisible = true - actionIcon.setOnClickListener { - // TODO: handle tap on comment's inline action icon (the share icon) - } - } - else -> { - actionIcon.isVisible = false - } - } - } private fun handleMaxLines(subject: TextView, detail: TextView) { subject.viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener { @@ -351,6 +335,8 @@ class NotesAdapter( val unreadNotificationView: View val actionIcon: ImageView + val coroutineScope = CoroutineScope(Dispatchers.Main) + init { contentView = checkNotNull(view.findViewById(R.id.note_content_container)) headerText = checkNotNull(view.findViewById(R.id.header_text)) @@ -369,6 +355,33 @@ class NotesAdapter( actionIcon = checkNotNull(view.findViewById(R.id.action)) contentView.setOnClickListener(onClickListener) } + + @Suppress("ForbiddenComment") + fun bindInlineActionIconsForNote(note: Note) = Notification.from(note).let { notification -> + when (notification) { + Comment -> { + actionIcon.setImageResource(R.drawable.star_empty) + actionIcon.isVisible = true + actionIcon.setOnClickListener { + // TODO: handle tap on comment's inline action icon (the star) + } + } + is PostNotification -> { + actionIcon.setImageResource(R.drawable.block_share) + actionIcon.isVisible = true + actionIcon.setOnClickListener { + coroutineScope.launch { + inlineActionEvents.emit( + InlineActionEvent.SharePostButtonTapped(notification) + ) + } + } + } + is Unknown -> { + actionIcon.isVisible = false + } + } + } } private val onClickListener = View.OnClickListener { view -> From 4ae77e5001949cbf71d23859c28727f2c80ac6ec Mon Sep 17 00:00:00 2001 From: Matthew Kevins Date: Tue, 13 Feb 2024 17:31:40 +1000 Subject: [PATCH 08/11] Wire up notification inline actions in fragment page --- .../NotificationsListFragmentPage.kt | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsListFragmentPage.kt b/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsListFragmentPage.kt index 35fc491b89d4..1948ca3ccf90 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsListFragmentPage.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/notifications/NotificationsListFragmentPage.kt @@ -10,11 +10,15 @@ import android.view.animation.Animation.AnimationListener import androidx.annotation.StringRes import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels -import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.flowWithLifecycle +import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView.OnScrollListener import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode.MAIN @@ -45,6 +49,8 @@ import org.wordpress.android.ui.notifications.NotificationsListFragment.Companio import org.wordpress.android.ui.notifications.NotificationsListFragment.Companion.TabPosition.Follow import org.wordpress.android.ui.notifications.NotificationsListFragment.Companion.TabPosition.Like import org.wordpress.android.ui.notifications.NotificationsListFragment.Companion.TabPosition.Unread +import org.wordpress.android.ui.notifications.NotificationsListViewModel.InlineActionEvent +import org.wordpress.android.ui.notifications.NotificationsListViewModel.InlineActionEvent.SharePostButtonTapped import org.wordpress.android.ui.notifications.adapters.NotesAdapter import org.wordpress.android.ui.notifications.adapters.NotesAdapter.DataLoadedListener import org.wordpress.android.ui.notifications.adapters.NotesAdapter.FILTERS @@ -404,12 +410,27 @@ class NotificationsListFragmentPage : ViewPagerFragment(R.layout.notifications_l } private fun createOrGetNotesAdapter(): NotesAdapter { - return notesAdapter ?: NotesAdapter(requireActivity(), this, null).apply { + return notesAdapter ?: NotesAdapter( requireActivity(), this, null, + inlineActionEvents = viewModel.inlineActionEvents).apply { notesAdapter = this this.setOnNoteClickListener(mOnNoteClickListener) + viewModel.inlineActionEvents.flowWithLifecycle(viewLifecycleOwner.lifecycle, Lifecycle.State.STARTED) + .onEach(::handleInlineActionEvent) + .launchIn(viewLifecycleOwner.lifecycleScope) } } + private fun handleInlineActionEvent(actionEvent: InlineActionEvent) { + when (actionEvent) { + is SharePostButtonTapped -> actionEvent.notification.let { postNotification -> + context?.let { + ActivityLauncher.openShareIntent(it, postNotification.url, postNotification.title) + } + } + } + } + + /** * Mark notifications as read in CURRENT tab, use filteredNotes instead of notes */ From e73b37c9eff9f8b7548b2127e6c965068811eac1 Mon Sep 17 00:00:00 2001 From: Matthew Kevins Date: Tue, 13 Feb 2024 17:36:43 +1000 Subject: [PATCH 09/11] Eliminate code duplication in ReaderActivityLauncher --- .../android/ui/reader/ReaderActivityLauncher.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderActivityLauncher.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderActivityLauncher.java index 2aea5b62e6e1..a827e3d6cd6d 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderActivityLauncher.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderActivityLauncher.java @@ -403,13 +403,7 @@ public static void openPost(Context context, ReaderPost post) { public static void sharePost(Context context, ReaderPost post) throws ActivityNotFoundException { String url = (post.hasShortUrl() ? post.getShortUrl() : post.getUrl()); - - Intent intent = new Intent(Intent.ACTION_SEND); - intent.setType("text/plain"); - intent.putExtra(Intent.EXTRA_TEXT, url); - intent.putExtra(Intent.EXTRA_SUBJECT, post.getTitle()); - - context.startActivity(Intent.createChooser(intent, context.getString(R.string.share_link))); + ActivityLauncher.openShareIntent(context, url, post.getTitle()); } public static void openUrl(Context context, String url, OpenUrlType openUrlType) { From 5b5fc310156fc9385cf173ae9489ca0eabb5d802 Mon Sep 17 00:00:00 2001 From: Antonis Lilis Date: Tue, 13 Feb 2024 11:31:33 +0200 Subject: [PATCH 10/11] Removes unused import --- .../org/wordpress/android/ui/reader/ReaderActivityLauncher.java | 1 - 1 file changed, 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderActivityLauncher.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderActivityLauncher.java index a827e3d6cd6d..32b2261e2527 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderActivityLauncher.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderActivityLauncher.java @@ -13,7 +13,6 @@ import androidx.core.app.ActivityOptionsCompat; import androidx.fragment.app.Fragment; -import org.wordpress.android.R; import org.wordpress.android.analytics.AnalyticsTracker; import org.wordpress.android.models.ReaderPost; import org.wordpress.android.models.ReaderTag; From 69a3392c00e80fbf38b7c9b0bab2a74da7574e07 Mon Sep 17 00:00:00 2001 From: Matthew Kevins Date: Wed, 14 Feb 2024 08:03:03 +1000 Subject: [PATCH 11/11] Fix inline action share icon in dark mode --- WordPress/src/main/res/layout/notifications_list_item.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/WordPress/src/main/res/layout/notifications_list_item.xml b/WordPress/src/main/res/layout/notifications_list_item.xml index 69e97762df13..716a1fb35d00 100644 --- a/WordPress/src/main/res/layout/notifications_list_item.xml +++ b/WordPress/src/main/res/layout/notifications_list_item.xml @@ -69,6 +69,7 @@ app:layout_constraintBottom_toBottomOf="@+id/note_avatar" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="@+id/note_avatar" + app:tint="?attr/wpColorOnSurfaceMedium" tools:src="@drawable/star_empty" />