Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue/11799 show announcement on app upgrade #11804

Merged
merged 12 commits into from
May 6, 2020
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
import org.wordpress.android.ui.uploads.UploadActionUseCase;
import org.wordpress.android.ui.uploads.UploadUtils;
import org.wordpress.android.ui.uploads.UploadUtilsWrapper;
import org.wordpress.android.ui.whatsnew.FeatureAnnouncementDialogFragment;
import org.wordpress.android.util.AniUtils;
import org.wordpress.android.util.AppLog;
import org.wordpress.android.util.AppLog.T;
Expand Down Expand Up @@ -417,6 +418,11 @@ private void initViewModel() {
}
});

mViewModel.getOnFeatureAnnouncementRequested().observe(this, action -> {
new FeatureAnnouncementDialogFragment()
.show(getSupportFragmentManager(), FeatureAnnouncementDialogFragment.TAG);
});

mFloatingActionButton.setOnClickListener(v -> {
mViewModel.onFabClicked(hasFullAccessToContent());
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,12 @@ public enum UndeletablePrefKey implements PrefKey {

// used to indicate that we do not need to show the main FAB tooltip
IS_MAIN_FAB_TOOLTIP_DISABLED,

// version of the last shown feature announcement
FEATURE_ANNOUNCEMENT_SHOWN_VERSION,

// last app version code feature announcement was shown for
LAST_FEATURE_ANNOUNCEMENT_APP_VERSION_CODE,
}

private static SharedPreferences prefs() {
Expand Down Expand Up @@ -1092,6 +1098,22 @@ private static List<String> getPostWithHWAccelerationOff() {
return Arrays.asList(idsAsString.split(","));
}

public static void setFeatureAnnouncementShownVersion(int version) {
setInt(UndeletablePrefKey.FEATURE_ANNOUNCEMENT_SHOWN_VERSION, version);
}

public static int getFeatureAnnouncementShownVersion() {
return getInt(UndeletablePrefKey.FEATURE_ANNOUNCEMENT_SHOWN_VERSION, -1);
}

public static int getLastFeatureAnnouncementAppVersionCode() {
return getInt(UndeletablePrefKey.LAST_FEATURE_ANNOUNCEMENT_APP_VERSION_CODE);
}

public static void setLastFeatureAnnouncementAppVersionCode(int version) {
setInt(UndeletablePrefKey.LAST_FEATURE_ANNOUNCEMENT_APP_VERSION_CODE, version);
}

/*
* adds a local site ID to the top of list of recently chosen sites
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ class AppPrefsWrapper @Inject constructor() {
get() = AppPrefs.getNewsCardShownVersion()
set(version) = AppPrefs.setNewsCardShownVersion(version)

var featureAnnouncementShownVersion: Int
get() = AppPrefs.getFeatureAnnouncementShownVersion()
set(version) = AppPrefs.setFeatureAnnouncementShownVersion(version)

var lastFeatureAnnouncementAppVersionCode: Int
get() = AppPrefs.getLastFeatureAnnouncementAppVersionCode()
set(version) = AppPrefs.setLastFeatureAnnouncementAppVersionCode(version)

var avatarVersion: Int
get() = AppPrefs.getAvatarVersion()
set(version) = AppPrefs.setAvatarVersion(version)
Expand Down Expand Up @@ -122,6 +130,8 @@ class AppPrefsWrapper @Inject constructor() {
fun getLastReaderKnownUserId() = AppPrefs.getLastReaderKnownUserId()
fun setLastReaderKnownUserId(userId: Long) = AppPrefs.setLastReaderKnownUserId(userId)

fun getLastAppVersionCode() = AppPrefs.getLastAppVersionCode()

companion object {
private const val LIGHT_MODE_ID = 0
private const val DARK_MODE_ID = 1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import androidx.annotation.DrawableRes

data class FeatureAnnouncement(
val version: String,
val versionCode: Int,
val detailsUrl: String,
val features: List<FeatureAnnouncementItem>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import javax.inject.Inject

class FeatureAnnouncementProvider @Inject constructor() {
private val localFeatureAnnouncement = FeatureAnnouncement(
"14.7", "https://wordpress.com/blog/2020/04/20/earth-day-live/", listOf(
"14.7", 857, "https://wordpress.com/blog/2020/04/20/earth-day-live/", listOf(
FeatureAnnouncementItem(
"Super Publishing",
"Publish amazing articles using the power of your mind! Concentrate" +
Expand All @@ -27,7 +27,11 @@ class FeatureAnnouncementProvider @Inject constructor() {
)
)

fun getLatestFeatureAnnouncement(): FeatureAnnouncement {
fun getLatestFeatureAnnouncement(): FeatureAnnouncement? {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure it's worth nor how much work it can be (so feel free to just say you will never consider doing 😊), but since we are possibly considering expanding the announcements one day to include some of the previous one and to avoid this (sometimes tricky) nullable, maybe we could consider to use a list of FeatureAnnouncement (eventually ordered by app version code or being empty)...wdyt?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added the getFeatureAnnouncements(): List<FeatureAnnouncement> method in upcoming PR, but it's not really solving the nullability of the announcement, it just moves the check upstream.

return localFeatureAnnouncement
}

fun isFeatureAnnouncementAvailable(): Boolean {
return getLatestFeatureAnnouncement() != null
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.wordpress.android.util

import org.wordpress.android.BuildConfig
import javax.inject.Inject

class BuildConfigWrapper @Inject constructor() {
fun getAppVersionCode(): Int {
return BuildConfig.VERSION_CODE
}

fun isFeatureAnnouncementEnabled(): Boolean {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we are introducing the wrapper, wdyt if we use it in AppSettingsFragment.java Line 172 also?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added the check to AppSettingsFragment in upcoming PR :)

return BuildConfig.FEATURE_ANNOUNCEMENT_AVAILABLE
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,17 @@ import org.wordpress.android.ui.main.MainActionListItem.ActionType.NO_ACTION
import org.wordpress.android.ui.main.MainActionListItem.CreateAction
import org.wordpress.android.ui.main.MainFabUiState
import org.wordpress.android.ui.prefs.AppPrefsWrapper
import org.wordpress.android.ui.whatsnew.FeatureAnnouncementProvider
import org.wordpress.android.util.BuildConfigWrapper
import org.wordpress.android.viewmodel.Event
import org.wordpress.android.viewmodel.SingleLiveEvent
import javax.inject.Inject

class WPMainActivityViewModel @Inject constructor(private val appPrefsWrapper: AppPrefsWrapper) : ViewModel() {
class WPMainActivityViewModel @Inject constructor(
private val featureAnnouncementProvider: FeatureAnnouncementProvider,
private val buildConfigWrapper: BuildConfigWrapper,
private val appPrefsWrapper: AppPrefsWrapper
) : ViewModel() {
private var isStarted = false

private val _fabUiState = MutableLiveData<MainFabUiState>()
Expand All @@ -34,36 +40,49 @@ class WPMainActivityViewModel @Inject constructor(private val appPrefsWrapper: A
private val _startLoginFlow = MutableLiveData<Event<Boolean>>()
val startLoginFlow: LiveData<Event<Boolean>> = _startLoginFlow

private val _onFeatureAnnouncementRequested = SingleLiveEvent<Unit>()
val onFeatureAnnouncementRequested: LiveData<Unit> = _onFeatureAnnouncementRequested

fun start(isFabVisible: Boolean, hasFullAccessToContent: Boolean) {
if (isStarted) return
isStarted = true

setMainFabUiState(isFabVisible, hasFullAccessToContent)

loadMainActions()

if (buildConfigWrapper.isFeatureAnnouncementEnabled()) {
checkForFeatureAnnouncements()
}
}

private fun loadMainActions() {
val actionsList = ArrayList<MainActionListItem>()

actionsList.add(CreateAction(
actionType = NO_ACTION,
iconRes = 0,
labelRes = R.string.my_site_bottom_sheet_title,
onClickAction = null
))
actionsList.add(CreateAction(
actionType = CREATE_NEW_POST,
iconRes = R.drawable.ic_posts_white_24dp,
labelRes = R.string.my_site_bottom_sheet_add_post,
onClickAction = ::onCreateActionClicked
))
actionsList.add(CreateAction(
actionType = CREATE_NEW_PAGE,
iconRes = R.drawable.ic_pages_white_24dp,
labelRes = R.string.my_site_bottom_sheet_add_page,
onClickAction = ::onCreateActionClicked
))
actionsList.add(
CreateAction(
actionType = NO_ACTION,
iconRes = 0,
labelRes = R.string.my_site_bottom_sheet_title,
onClickAction = null
)
)
actionsList.add(
CreateAction(
actionType = CREATE_NEW_POST,
iconRes = R.drawable.ic_posts_white_24dp,
labelRes = R.string.my_site_bottom_sheet_add_post,
onClickAction = ::onCreateActionClicked
)
)
actionsList.add(
CreateAction(
actionType = CREATE_NEW_PAGE,
iconRes = R.drawable.ic_pages_white_24dp,
labelRes = R.string.my_site_bottom_sheet_add_page,
onClickAction = ::onCreateActionClicked
)
)

_mainActions.postValue(actionsList)
}
Expand Down Expand Up @@ -130,9 +149,9 @@ class WPMainActivityViewModel @Inject constructor(private val appPrefsWrapper: A

private fun setMainFabUiState(isFabVisible: Boolean, hasFullAccessToContent: Boolean) {
val newState = MainFabUiState(
isFabVisible = isFabVisible,
isFabTooltipVisible = if (appPrefsWrapper.isMainFabTooltipDisabled()) false else isFabVisible,
CreateContentMessageId = getCreateContentMessageId(hasFullAccessToContent)
isFabVisible = isFabVisible,
isFabTooltipVisible = if (appPrefsWrapper.isMainFabTooltipDisabled()) false else isFabVisible,
CreateContentMessageId = getCreateContentMessageId(hasFullAccessToContent)
)

_fabUiState.value = newState
Expand All @@ -144,4 +163,30 @@ class WPMainActivityViewModel @Inject constructor(private val appPrefsWrapper: A
else
R.string.create_post_page_fab_tooltip_contributors
}

private fun checkForFeatureAnnouncements() {
val currentVersionCode = buildConfigWrapper.getAppVersionCode()
val previousVersionCode = appPrefsWrapper.lastFeatureAnnouncementAppVersionCode

// only proceed to feature announcement logic if we are upgrading the app
if (previousVersionCode != 0 && previousVersionCode < currentVersionCode) {
if (canShowFeatureAnnouncement()) {
appPrefsWrapper.featureAnnouncementShownVersion =
featureAnnouncementProvider.getLatestFeatureAnnouncement()?.versionCode!!
appPrefsWrapper.lastFeatureAnnouncementAppVersionCode = currentVersionCode
_onFeatureAnnouncementRequested.call()
}
// else {
// // request feature announcement from endpoint to be used on next app start
// }
} else {
appPrefsWrapper.lastFeatureAnnouncementAppVersionCode = currentVersionCode
}
}

private fun canShowFeatureAnnouncement(): Boolean {
return featureAnnouncementProvider.isFeatureAnnouncementAvailable() &&
appPrefsWrapper.featureAnnouncementShownVersion <
featureAnnouncementProvider.getLatestFeatureAnnouncement()?.versionCode!!
}
}
Loading