Skip to content

Commit aa8bc27

Browse files
authored
Merge branch 'trunk' into feat/CMM-1148-Create-stats-Top-card
2 parents b2166af + ebfb41e commit aa8bc27

File tree

16 files changed

+255
-332
lines changed

16 files changed

+255
-332
lines changed

Gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ gem 'nokogiri'
88

99
### Fastlane Plugins
1010

11+
gem 'fastlane-plugin-firebase_app_distribution', '~> 0.10'
1112
gem 'fastlane-plugin-sentry'
1213
gem 'fastlane-plugin-wpmreleasetoolkit', '~> 13.8'
1314
# gem 'fastlane-plugin-wpmreleasetoolkit', path: '../../release-toolkit'

Gemfile.lock

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,9 @@ GEM
169169
xcodeproj (>= 1.13.0, < 2.0.0)
170170
xcpretty (~> 0.4.1)
171171
xcpretty-travis-formatter (>= 0.0.3, < 2.0.0)
172+
fastlane-plugin-firebase_app_distribution (0.10.1)
173+
google-apis-firebaseappdistribution_v1 (~> 0.3.0)
174+
google-apis-firebaseappdistribution_v1alpha (~> 0.2.0)
172175
fastlane-plugin-sentry (1.29.0)
173176
os (~> 1.1, >= 1.1.4)
174177
fastlane-plugin-wpmreleasetoolkit (13.8.1)
@@ -204,6 +207,10 @@ GEM
204207
representable (~> 3.0)
205208
retriable (>= 2.0, < 4.a)
206209
rexml
210+
google-apis-firebaseappdistribution_v1 (0.3.0)
211+
google-apis-core (>= 0.11.0, < 2.a)
212+
google-apis-firebaseappdistribution_v1alpha (0.2.0)
213+
google-apis-core (>= 0.11.0, < 2.a)
207214
google-apis-iamcredentials_v1 (0.17.0)
208215
google-apis-core (>= 0.11.0, < 2.a)
209216
google-apis-playcustomapp_v1 (0.13.0)
@@ -358,6 +365,7 @@ PLATFORMS
358365
DEPENDENCIES
359366
danger-dangermattic (~> 1.2)
360367
fastlane (~> 2)
368+
fastlane-plugin-firebase_app_distribution (~> 0.10)
361369
fastlane-plugin-sentry
362370
fastlane-plugin-wpmreleasetoolkit (~> 13.8)
363371
nokogiri

WordPress/src/main/java/org/wordpress/android/ui/mediapicker/MediaPickerFragment.kt

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ import org.wordpress.android.util.SnackbarItem
6969
import org.wordpress.android.util.SnackbarItem.Action
7070
import org.wordpress.android.util.SnackbarItem.Info
7171
import org.wordpress.android.util.SnackbarSequencer
72-
import org.wordpress.android.util.ActivityUtils
7372
import org.wordpress.android.util.UriWrapper
7473
import org.wordpress.android.util.WPLinkMovementMethod
7574
import org.wordpress.android.util.WPMediaUtils
@@ -477,9 +476,6 @@ class MediaPickerFragment : Fragment(), MenuProvider {
477476
is PhotoListUiModel.Empty -> {
478477
setupAdapter(listOf())
479478
actionableEmptyView.updateLayoutForSearch(uiModel.isSearching, 0)
480-
if (uiModel.isSearching) {
481-
ActivityUtils.hideKeyboardForced(actionableEmptyView)
482-
}
483479
actionableEmptyView.title.text = uiHelpers.getTextOfUiString(requireContext(), uiModel.title)
484480

485481
actionableEmptyView.subtitle.applyOrHide(uiModel.htmlSubtitle) { htmlSubtitle ->
@@ -492,18 +488,6 @@ class MediaPickerFragment : Fragment(), MenuProvider {
492488
)
493489
actionableEmptyView.subtitle.movementMethod = WPLinkMovementMethod.getInstance()
494490
}
495-
actionableEmptyView.image.applyOrHide(uiModel.image) { image ->
496-
this.setImageResource(image)
497-
}
498-
actionableEmptyView.bottomImage.applyOrHide(uiModel.bottomImage) { bottomImage ->
499-
this.setImageResource(bottomImage)
500-
if (uiModel.bottomImageDescription != null) {
501-
this.contentDescription = uiHelpers.getTextOfUiString(
502-
requireContext(),
503-
uiModel.bottomImageDescription
504-
).toString()
505-
}
506-
}
507491
actionableEmptyView.button.applyOrHide(uiModel.retryAction) { action ->
508492
this.setText(R.string.retry)
509493
this.setOnClickListener {

WordPress/src/main/java/org/wordpress/android/ui/mediapicker/MediaPickerViewModel.kt

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -193,9 +193,6 @@ class MediaPickerViewModel @Inject constructor(
193193
PhotoListUiModel.Empty(
194194
title = domainModel.emptyState.title,
195195
htmlSubtitle = domainModel.emptyState.htmlSubtitle,
196-
image = domainModel.emptyState.image,
197-
bottomImage = domainModel.emptyState.bottomImage,
198-
bottomImageDescription = domainModel.emptyState.bottomImageDescription,
199196
isSearching = isSearching == true,
200197
retryAction = if (isSearching == true) null else this::retry
201198
)
@@ -733,9 +730,6 @@ class MediaPickerViewModel @Inject constructor(
733730
data class Empty(
734731
val title: UiString,
735732
val htmlSubtitle: UiString? = null,
736-
val image: Int? = null,
737-
val bottomImage: Int? = null,
738-
val bottomImageDescription: UiString? = null,
739733
val isSearching: Boolean = false,
740734
val retryAction: (() -> Unit)? = null
741735
) : PhotoListUiModel()

WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.kt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,12 @@ import androidx.core.content.ContextCompat
2828
import androidx.core.os.BundleCompat
2929
import androidx.core.text.HtmlCompat
3030
import androidx.core.view.isVisible
31+
import androidx.lifecycle.Lifecycle
3132
import androidx.lifecycle.ViewModelProvider
3233
import androidx.lifecycle.lifecycleScope
34+
import androidx.lifecycle.repeatOnLifecycle
3335
import androidx.recyclerview.widget.RecyclerView
36+
import kotlinx.coroutines.launch
3437
import com.google.android.material.R as MaterialR
3538
import com.google.android.material.dialog.MaterialAlertDialogBuilder
3639
import com.google.android.material.snackbar.Snackbar
@@ -236,6 +239,7 @@ class ReaderPostListFragment : ViewPagerFragment(), OnPostSelectedListener, OnFo
236239
private var postSearchAdapterPos = 0
237240
private var siteSearchAdapterPos = 0
238241
private var searchTabsPos = NO_POSITION
242+
private var pendingScrollToBlogId: Long? = null
239243

240244
private var isFilterableScreen = false
241245
private var isFiltered = false
@@ -537,6 +541,14 @@ class ReaderPostListFragment : ViewPagerFragment(), OnPostSelectedListener, OnFo
537541
) { readerData: FollowStatusChanged ->
538542
setFollowStatusForBlog(readerData)
539543
}
544+
545+
viewLifecycleOwner.lifecycleScope.launch {
546+
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
547+
postListViewModel.scrollToSiteId.collect { blogId ->
548+
pendingScrollToBlogId = blogId
549+
}
550+
}
551+
}
540552
}
541553

542554
private fun toggleJetpackBannerIfEnabled(showIfEnabled: Boolean, animateOnScroll: Boolean) {
@@ -1993,6 +2005,10 @@ class ReaderPostListFragment : ViewPagerFragment(), OnPostSelectedListener, OnFo
19932005
AppLog.d(AppLog.T.READER, "reader post list > restoring position")
19942006
recyclerView.scrollRecycleViewToPosition(restorePosition)
19952007
}
2008+
pendingScrollToBlogId?.let { blogId ->
2009+
scrollToFirstPostFromBlog(blogId)
2010+
pendingScrollToBlogId = null
2011+
}
19962012
if (isSearching && !isSearchTabsShowing()) {
19972013
showSearchTabs()
19982014
} else if (isSearching) {
@@ -2216,6 +2232,17 @@ class ReaderPostListFragment : ViewPagerFragment(), OnPostSelectedListener, OnFo
22162232
}
22172233
}
22182234

2235+
/*
2236+
* scroll to the first post from the specified blog
2237+
*/
2238+
private fun scrollToFirstPostFromBlog(blogId: Long) {
2239+
if (!hasPostAdapter()) return
2240+
val position = getPostAdapter().getPositionOfFirstPostFromBlog(blogId)
2241+
if (position > -1) {
2242+
recyclerView.scrollRecycleViewToPosition(position)
2243+
}
2244+
}
2245+
22192246
/*
22202247
* same as above but clears posts before refreshing
22212248
*/

WordPress/src/main/java/org/wordpress/android/ui/reader/adapters/ReaderPostAdapter.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,24 @@ public boolean isEmpty() {
755755
return (mPosts == null || mPosts.size() == 0);
756756
}
757757

758+
/**
759+
* Returns the adapter position of the first post from the specified blog, or -1 if not found.
760+
*/
761+
public int getPositionOfFirstPostFromBlog(long blogId) {
762+
if (mPosts == null) return -1;
763+
for (int i = 0; i < mPosts.size(); i++) {
764+
if (mPosts.get(i).blogId == blogId) {
765+
int adapterPosition = i + getItemPositionOffset();
766+
// Account for gap marker if it appears before this position
767+
if (mGapMarkerPosition > -1 && adapterPosition >= mGapMarkerPosition) {
768+
adapterPosition++;
769+
}
770+
return adapterPosition;
771+
}
772+
}
773+
return -1;
774+
}
775+
758776
private boolean isBookmarksList() {
759777
return (getPostListType() == ReaderPostListType.TAG_FOLLOWED
760778
&& (mCurrentTag != null && mCurrentTag.isBookmarked()));

WordPress/src/main/java/org/wordpress/android/ui/reader/discover/ReaderPostCardActionsHandler.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ import androidx.lifecycle.LiveData
55
import androidx.lifecycle.MediatorLiveData
66
import kotlinx.coroutines.CoroutineDispatcher
77
import kotlinx.coroutines.CoroutineScope
8+
import kotlinx.coroutines.flow.MutableSharedFlow
9+
import kotlinx.coroutines.flow.SharedFlow
10+
import kotlinx.coroutines.flow.asSharedFlow
811
import kotlinx.coroutines.flow.flowOn
912
import kotlinx.coroutines.launch
1013
import kotlinx.coroutines.withContext
@@ -125,6 +128,12 @@ class ReaderPostCardActionsHandler @Inject constructor(
125128
private val _refreshPosts = MediatorLiveData<Event<Unit>>()
126129
val refreshPosts: LiveData<Event<Unit>> = _refreshPosts
127130

131+
// Emits a blog ID to scroll to after undo block action. This provides visual feedback
132+
// to the user that the undo was successful by scrolling to show the restored posts.
133+
// The event is consumed by ReaderPostListFragment after posts are refreshed.
134+
private val _scrollToSiteId = MutableSharedFlow<Long>()
135+
val scrollToSiteId: SharedFlow<Long> = _scrollToSiteId.asSharedFlow()
136+
128137
init {
129138
dispatcher.register(siteNotificationsUseCase)
130139
}
@@ -437,8 +446,10 @@ class ReaderPostCardActionsHandler @Inject constructor(
437446
UiStringRes(R.string.undo),
438447
{
439448
coroutineScope.launch {
449+
val blogId = it.blockedBlogData.blogId
440450
undoBlockBlogUseCase.undoBlockBlog(it.blockedBlogData, source)
441451
_refreshPosts.postValue(Event(Unit))
452+
_scrollToSiteId.emit(blogId)
442453
_snackbarEvents.postValue(
443454
Event(
444455
SnackbarMessageHolder(

WordPress/src/main/java/org/wordpress/android/ui/reader/viewmodels/ReaderPostListViewModel.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ class ReaderPostListViewModel @Inject constructor(
7171
private val _updateFollowStatus = MediatorLiveData<FollowStatusChanged>()
7272
val updateFollowStatus: LiveData<FollowStatusChanged> = _updateFollowStatus
7373

74+
val scrollToSiteId = readerPostCardActionsHandler.scrollToSiteId
75+
7476
fun start(readerViewModel: ReaderViewModel?) {
7577
this.readerViewModel = readerViewModel
7678

0 commit comments

Comments
 (0)