Skip to content

Commit 46381b2

Browse files
authored
Merge pull request #20956 from wordpress-mobile/merge/25.0-final-into-trunk
Merge 25.0 final into trunk
2 parents e56dcc8 + 6454d7f commit 46381b2

File tree

114 files changed

+4358
-3098
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

114 files changed

+4358
-3098
lines changed

WordPress/build.gradle

+1
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ android {
154154
buildConfigField "boolean", "READER_TAGS_FEED", "false"
155155
buildConfigField "boolean", "READER_ANNOUNCEMENT_CARD", "false"
156156
buildConfigField "boolean", "VOICE_TO_CONTENT", "false"
157+
buildConfigField "boolean", "READER_FLOATING_BUTTON", "false"
157158

158159
// Override these constants in jetpack product flavor to enable/ disable features
159160
buildConfigField "boolean", "ENABLE_SITE_CREATION", "true"

WordPress/src/main/java/org/wordpress/android/inappupdate/InAppUpdateAnalyticsTracker.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class InAppUpdateAnalyticsTracker @Inject constructor(
2121
}
2222

2323
fun trackAppRestartToCompleteUpdate() {
24-
tracker.track(AnalyticsTracker.Stat.IN_APP_UPDATE_COMPLETED_WITH_APP_RESTART)
24+
tracker.track(AnalyticsTracker.Stat.IN_APP_UPDATE_COMPLETED_WITH_APP_RESTART_BY_USER)
2525
}
2626

2727
private fun createPropertyMap(updateType: Int): Map<String, String> {

WordPress/src/main/java/org/wordpress/android/inappupdate/InAppUpdateManagerImpl.kt

+16-2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ import com.google.android.play.core.install.model.UpdateAvailability.DEVELOPER_T
2222
import com.google.android.play.core.install.model.UpdateAvailability.UPDATE_AVAILABLE
2323
import com.google.android.play.core.install.model.UpdateAvailability.UPDATE_NOT_AVAILABLE
2424
import dagger.hilt.android.qualifiers.ApplicationContext
25+
import kotlinx.coroutines.CoroutineScope
26+
import kotlinx.coroutines.Dispatchers
27+
import kotlinx.coroutines.delay
28+
import kotlinx.coroutines.launch
2529
import org.wordpress.android.inappupdate.IInAppUpdateManager.Companion.APP_UPDATE_FLEXIBLE_REQUEST_CODE
2630
import org.wordpress.android.inappupdate.IInAppUpdateManager.Companion.APP_UPDATE_IMMEDIATE_REQUEST_CODE
2731

@@ -33,6 +37,7 @@ import javax.inject.Singleton
3337
@Suppress("TooManyFunctions")
3438
class InAppUpdateManagerImpl(
3539
@ApplicationContext private val applicationContext: Context,
40+
private val coroutineScope: CoroutineScope,
3641
private val appUpdateManager: AppUpdateManager,
3742
private val remoteConfigWrapper: RemoteConfigWrapper,
3843
private val buildConfigWrapper: BuildConfigWrapper,
@@ -51,8 +56,16 @@ class InAppUpdateManagerImpl(
5156
}
5257

5358
override fun completeAppUpdate() {
54-
inAppUpdateAnalyticsTracker.trackAppRestartToCompleteUpdate()
55-
appUpdateManager.completeUpdate()
59+
coroutineScope.launch(Dispatchers.Main) {
60+
// Track the app restart to complete update
61+
inAppUpdateAnalyticsTracker.trackAppRestartToCompleteUpdate()
62+
63+
// Delay so the event above can be logged
64+
delay(RESTART_DELAY_IN_MILLIS)
65+
66+
// Complete the update
67+
appUpdateManager.completeUpdate()
68+
}
5669
}
5770

5871
override fun cancelAppUpdate(updateType: Int) {
@@ -226,5 +239,6 @@ class InAppUpdateManagerImpl(
226239
private const val TAG = "AppUpdateChecker"
227240
private const val PREF_NAME = "in_app_update_prefs"
228241
private const val KEY_LAST_APP_UPDATE_CHECK_VERSION = "last_app_update_check_version"
242+
private const val RESTART_DELAY_IN_MILLIS = 500L
229243
}
230244
}

WordPress/src/main/java/org/wordpress/android/modules/ApplicationModule.java

+6
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,17 @@
3939
import org.wordpress.android.viewmodel.helpers.ConnectionStatus;
4040
import org.wordpress.android.viewmodel.helpers.ConnectionStatusLiveData;
4141

42+
import javax.inject.Named;
43+
4244
import dagger.Binds;
4345
import dagger.Module;
4446
import dagger.Provides;
4547
import dagger.android.AndroidInjectionModule;
4648
import dagger.hilt.InstallIn;
4749
import dagger.hilt.android.qualifiers.ApplicationContext;
4850
import dagger.hilt.components.SingletonComponent;
51+
import kotlinx.coroutines.CoroutineScope;
52+
import static org.wordpress.android.modules.ThreadModuleKt.APPLICATION_SCOPE;
4953

5054
@InstallIn(SingletonComponent.class)
5155
@Module(includes = AndroidInjectionModule.class)
@@ -98,6 +102,7 @@ public static AppUpdateManager provideAppUpdateManager(@ApplicationContext Conte
98102
@Provides
99103
public static IInAppUpdateManager provideInAppUpdateManager(
100104
@ApplicationContext Context context,
105+
@Named(APPLICATION_SCOPE) CoroutineScope appScope,
101106
AppUpdateManager appUpdateManager,
102107
RemoteConfigWrapper remoteConfigWrapper,
103108
BuildConfigWrapper buildConfigWrapper,
@@ -108,6 +113,7 @@ public static IInAppUpdateManager provideInAppUpdateManager(
108113
return inAppUpdatesFeatureConfig.isEnabled()
109114
? new InAppUpdateManagerImpl(
110115
context,
116+
appScope,
111117
appUpdateManager,
112118
remoteConfigWrapper,
113119
buildConfigWrapper,

WordPress/src/main/java/org/wordpress/android/ui/main/WPMainActivity.java

+16-7
Original file line numberDiff line numberDiff line change
@@ -752,14 +752,17 @@ private void initViewModel() {
752752
.show(getSupportFragmentManager(), FeatureAnnouncementDialogFragment.TAG);
753753
});
754754

755-
mFloatingActionButton.setOnClickListener(v -> mViewModel.onFabClicked(getSelectedSite()));
755+
mFloatingActionButton.setOnClickListener(v -> {
756+
PageType selectedPage = getSelectedPage();
757+
if (selectedPage != null) mViewModel.onFabClicked(getSelectedSite(), selectedPage);
758+
});
756759

757760
mFloatingActionButton.setOnLongClickListener(v -> {
758761
if (v.isHapticFeedbackEnabled()) {
759762
v.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
760763
}
761764

762-
int messageId = mViewModel.getCreateContentMessageId(getSelectedSite());
765+
int messageId = mViewModel.getCreateContentMessageId(getSelectedSite(), getSelectedPage());
763766

764767
Toast.makeText(v.getContext(), messageId, Toast.LENGTH_SHORT).show();
765768
return true;
@@ -831,7 +834,7 @@ private void initViewModel() {
831834
// initialized with the most restrictive rights case. This is OK and will be frequently checked
832835
// to normalize the UI state whenever mSelectedSite changes.
833836
// It also means that the ViewModel must accept a nullable SiteModel.
834-
mViewModel.start(getSelectedSite());
837+
mViewModel.start(getSelectedSite(), mBottomNav.getCurrentSelectedPage());
835838
}
836839

837840
private void triggerCreatePageFlow(ActionType actionType) {
@@ -1177,8 +1180,8 @@ protected void onResume() {
11771180

11781181
mViewModel.onResume(
11791182
getSelectedSite(),
1180-
mSelectedSiteRepository.hasSelectedSite() && mBottomNav != null
1181-
&& mBottomNav.getCurrentSelectedPage() == PageType.MY_SITE
1183+
mSelectedSiteRepository.hasSelectedSite(),
1184+
getSelectedPage()
11821185
);
11831186

11841187
if (AppReviewManager.INSTANCE.shouldShowInAppReviewsPrompt()) {
@@ -1267,8 +1270,9 @@ public void onPageChanged(int position) {
12671270
}
12681271

12691272
mViewModel.onPageChanged(
1270-
mSiteStore.hasSite() && pageType == PageType.MY_SITE,
1271-
getSelectedSite()
1273+
getSelectedSite(),
1274+
mSiteStore.hasSite(),
1275+
pageType
12721276
);
12731277
}
12741278

@@ -1987,4 +1991,9 @@ private void showOpenPageMessageIfNeeded() {
19871991
}
19881992
}
19891993
}
1994+
1995+
@Nullable
1996+
private PageType getSelectedPage() {
1997+
return mBottomNav != null ? mBottomNav.getCurrentSelectedPage() : null;
1998+
}
19901999
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package org.wordpress.android.ui.main.analytics
2+
3+
import org.wordpress.android.analytics.AnalyticsTracker
4+
import org.wordpress.android.ui.main.MainActionListItem
5+
import org.wordpress.android.ui.main.WPMainNavigationView
6+
import org.wordpress.android.ui.mysite.cards.dashboard.bloggingprompts.BloggingPromptAttribution
7+
import org.wordpress.android.util.analytics.AnalyticsTrackerWrapper
8+
import java.util.Locale
9+
import javax.inject.Inject
10+
11+
class MainCreateSheetTracker @Inject constructor(
12+
private val analyticsTracker: AnalyticsTrackerWrapper,
13+
) {
14+
fun trackActionTapped(page: WPMainNavigationView.PageType, actionType: MainActionListItem.ActionType) {
15+
val stat = when (page) {
16+
WPMainNavigationView.PageType.MY_SITE -> AnalyticsTracker.Stat.MY_SITE_CREATE_SHEET_ACTION_TAPPED
17+
WPMainNavigationView.PageType.READER -> AnalyticsTracker.Stat.READER_CREATE_SHEET_ACTION_TAPPED
18+
else -> return
19+
}
20+
val properties = mapOf("action" to actionType.name.lowercase(Locale.ROOT))
21+
analyticsTracker.track(stat, properties)
22+
}
23+
24+
fun trackAnswerPromptActionTapped(page: WPMainNavigationView.PageType, attribution: BloggingPromptAttribution) {
25+
val properties = mapOf("attribution" to attribution.value).filterValues { it.isNotBlank() }
26+
val stat = when (page) {
27+
WPMainNavigationView.PageType.MY_SITE -> AnalyticsTracker.Stat.MY_SITE_CREATE_SHEET_ANSWER_PROMPT_TAPPED
28+
WPMainNavigationView.PageType.READER -> AnalyticsTracker.Stat.READER_CREATE_SHEET_ANSWER_PROMPT_TAPPED
29+
else -> return
30+
}
31+
analyticsTracker.track(stat, properties)
32+
}
33+
34+
fun trackHelpPromptActionTapped(page: WPMainNavigationView.PageType) {
35+
val stat = when (page) {
36+
WPMainNavigationView.PageType.MY_SITE -> AnalyticsTracker.Stat.MY_SITE_CREATE_SHEET_PROMPT_HELP_TAPPED
37+
WPMainNavigationView.PageType.READER -> AnalyticsTracker.Stat.READER_CREATE_SHEET_PROMPT_HELP_TAPPED
38+
else -> return
39+
}
40+
analyticsTracker.track(stat)
41+
}
42+
43+
fun trackSheetShown(page: WPMainNavigationView.PageType) {
44+
val stat = when (page) {
45+
WPMainNavigationView.PageType.MY_SITE -> AnalyticsTracker.Stat.MY_SITE_CREATE_SHEET_SHOWN
46+
WPMainNavigationView.PageType.READER -> AnalyticsTracker.Stat.READER_CREATE_SHEET_SHOWN
47+
else -> return
48+
}
49+
analyticsTracker.track(stat)
50+
}
51+
52+
fun trackFabShown(page: WPMainNavigationView.PageType) {
53+
val stat = when (page) {
54+
WPMainNavigationView.PageType.MY_SITE -> AnalyticsTracker.Stat.MY_SITE_CREATE_FAB_SHOWN
55+
WPMainNavigationView.PageType.READER -> AnalyticsTracker.Stat.READER_CREATE_FAB_SHOWN
56+
else -> return
57+
}
58+
analyticsTracker.track(stat)
59+
}
60+
61+
fun trackCreateActionsSheetCard(actions: List<MainActionListItem>) {
62+
if (actions.any { it is MainActionListItem.AnswerBloggingPromptAction }) {
63+
analyticsTracker.track(AnalyticsTracker.Stat.BLOGGING_PROMPTS_CREATE_SHEET_CARD_VIEWED)
64+
}
65+
}
66+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package org.wordpress.android.ui.main.utils
2+
3+
import org.wordpress.android.fluxc.model.SiteModel
4+
import org.wordpress.android.ui.bloggingprompts.BloggingPromptsSettingsHelper
5+
import org.wordpress.android.ui.main.WPMainNavigationView.PageType
6+
import org.wordpress.android.ui.voicetocontent.VoiceToContentFeatureUtils
7+
import org.wordpress.android.util.BuildConfigWrapper
8+
import org.wordpress.android.util.SiteUtilsWrapper
9+
import org.wordpress.android.util.config.ReaderFloatingButtonFeatureConfig
10+
import javax.inject.Inject
11+
12+
class MainCreateSheetHelper @Inject constructor(
13+
private val voiceToContentFeatureUtils: VoiceToContentFeatureUtils,
14+
private val readerFloatingButtonFeatureConfig: ReaderFloatingButtonFeatureConfig,
15+
private val bloggingPromptsSettingsHelper: BloggingPromptsSettingsHelper,
16+
private val buildConfig: BuildConfigWrapper,
17+
private val siteUtils: SiteUtilsWrapper,
18+
) {
19+
fun shouldShowFabForPage(page: PageType?): Boolean {
20+
val enabledForPage = page == PageType.MY_SITE ||
21+
(page == PageType.READER && readerFloatingButtonFeatureConfig.isEnabled())
22+
return buildConfig.isCreateFabEnabled && enabledForPage
23+
}
24+
25+
@Suppress("FunctionOnlyReturningConstant")
26+
fun canCreatePost(): Boolean = true // for completeness
27+
28+
fun canCreatePage(site: SiteModel?, page: PageType?): Boolean {
29+
return siteUtils.hasFullAccessToContent(site) && page == PageType.MY_SITE
30+
}
31+
32+
fun canCreatePostFromAudio(site: SiteModel?): Boolean {
33+
return voiceToContentFeatureUtils.isVoiceToContentEnabled() && siteUtils.hasFullAccessToContent(site)
34+
}
35+
36+
suspend fun canCreatePromptAnswer(): Boolean = bloggingPromptsSettingsHelper.shouldShowPromptsFeature()
37+
}

WordPress/src/main/java/org/wordpress/android/ui/posts/EditPostActivity.kt

+6-1
Original file line numberDiff line numberDiff line change
@@ -3813,7 +3813,12 @@ class EditPostActivity : LocaleAwareActivity(), EditorFragmentActivity, EditorIm
38133813
@Subscribe(threadMode = ThreadMode.MAIN)
38143814
fun onPostUploaded(event: OnPostUploaded) {
38153815
val post: PostModel? = event.post
3816-
if (post != null && post.id == editPostRepository.id) {
3816+
3817+
// Check if editPostRepository is initialized
3818+
val editPostRepositoryInitialized = this::editPostRepository.isInitialized
3819+
val editPostId = if (editPostRepositoryInitialized) editPostRepository.getPost()?.id else null
3820+
3821+
if (post != null && post.id == editPostId) {
38173822
if (!isRemotePreviewingFromEditor) {
38183823
// We are not remote previewing a post: show snackbar and update post status if needed
38193824
val snackbarAttachView = findViewById<View>(R.id.editor_activity)

WordPress/src/main/java/org/wordpress/android/util/SiteUtilsWrapper.kt

+1
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,5 @@ class SiteUtilsWrapper @Inject constructor(private val appContext: Context) {
2727
fun getSiteIconUrlOfResourceSize(site: SiteModel, @DimenRes sizeRes: Int): String {
2828
return SiteUtils.getSiteIconUrl(site, appContext.resources.getDimensionPixelSize(sizeRes))
2929
}
30+
fun hasFullAccessToContent(site: SiteModel?): Boolean = SiteUtils.hasFullAccessToContent(site)
3031
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package org.wordpress.android.util.config
2+
3+
import org.wordpress.android.BuildConfig
4+
import org.wordpress.android.annotation.Feature
5+
import javax.inject.Inject
6+
7+
private const val READER_FLOATING_BUTTON_REMOTE_FIELD = "reader_floating_button"
8+
9+
@Feature(READER_FLOATING_BUTTON_REMOTE_FIELD, false)
10+
class ReaderFloatingButtonFeatureConfig @Inject constructor(
11+
appConfig: AppConfig
12+
) : FeatureConfig(
13+
appConfig,
14+
BuildConfig.READER_FLOATING_BUTTON,
15+
READER_FLOATING_BUTTON_REMOTE_FIELD
16+
)

0 commit comments

Comments
 (0)