Skip to content

Commit

Permalink
Merge branch 'trunk' into issue/17837-enable-jetpack-install-full-plu…
Browse files Browse the repository at this point in the history
…gin-ff
  • Loading branch information
RenanLukas committed Feb 19, 2023
2 parents b31c029 + 629e760 commit cc0dcd7
Show file tree
Hide file tree
Showing 18 changed files with 545 additions and 35 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.wordpress.android.ui.jpfullplugininstall

import org.wordpress.android.fluxc.model.SiteModel
import org.wordpress.android.ui.prefs.AppPrefsWrapper
import org.wordpress.android.util.config.JetpackInstallFullPluginFeatureConfig
import org.wordpress.android.util.extensions.isJetpackConnectedWithoutFullPlugin
import javax.inject.Inject

class GetShowJetpackFullPluginInstallOnboardingUseCase @Inject constructor(
private val jetpackInstallFullPluginFeatureConfig: JetpackInstallFullPluginFeatureConfig,
private val appPrefsWrapper: AppPrefsWrapper,
) {
fun execute(siteModel: SiteModel): Boolean =
siteModel.id != 0 &&
jetpackInstallFullPluginFeatureConfig.isEnabled() &&
appPrefsWrapper.getShouldShowJetpackInstallOnboarding(siteModel.id) &&
siteModel.isJetpackConnectedWithoutFullPlugin()
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ class JetpackFullPluginInstallActivity : AppCompatActivity() {
observeActionEvents()
}

override fun onBackPressed() {
viewModel.onBackPressed()
}

@Composable
private fun JetpackFullPluginInstallScreen() {
val uiState by viewModel.uiState.collectAsState()
Expand All @@ -53,22 +57,33 @@ class JetpackFullPluginInstallActivity : AppCompatActivity() {
},
) {
when (this) {
is UiState.Initial -> InitialState(
uiState = this,
onContinueClick = viewModel::onContinueClick,
)
is UiState.Installing -> InstallingState(
uiState = this,
)
is UiState.Done -> DoneState(
uiState = this,
onDoneClick = viewModel::onDoneClick,
)
is UiState.Error -> ErrorState(
uiState = this,
onRetryClick = viewModel::onRetryClick,
onContactSupportClick = viewModel::onContactSupportClick,
)
is UiState.Initial -> {
InitialState(
uiState = this,
onContinueClick = viewModel::onContinueClick,
)
viewModel.onInitialShown()
}
is UiState.Installing -> {
InstallingState(
uiState = this,
)
viewModel.onInstallingShown()
}
is UiState.Done -> {
DoneState(
uiState = this,
onDoneClick = viewModel::onDoneClick,
)
}
is UiState.Error -> {
ErrorState(
uiState = this,
onRetryClick = viewModel::onRetryClick,
onContactSupportClick = viewModel::onContactSupportClick,
)
viewModel.onErrorShown()
}
}
}
}
Expand All @@ -89,6 +104,7 @@ class JetpackFullPluginInstallActivity : AppCompatActivity() {
)
}
is ActionEvent.Dismiss -> {
ActivityLauncher.showMainActivity(this)
finish()
}
}.exhaustive
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package org.wordpress.android.ui.jpfullplugininstall.install

import org.wordpress.android.analytics.AnalyticsTracker.Stat
import org.wordpress.android.util.analytics.AnalyticsTrackerWrapper
import javax.inject.Inject

class JetpackFullPluginInstallAnalyticsTracker @Inject constructor(
private val analyticsTracker: AnalyticsTrackerWrapper
) {
fun trackScreenShown(status: Status) {
analyticsTracker.track(
Stat.JETPACK_INSTALL_FULL_PLUGIN_FLOW_VIEWED,
mapOf(KEY_STATUS_PARAMETER to status.trackingValue)
)
}

fun trackCancelButtonClicked(status: Status) {
analyticsTracker.track(
Stat.JETPACK_INSTALL_FULL_PLUGIN_FLOW_CANCEL_TAPPED,
mapOf(KEY_STATUS_PARAMETER to status.trackingValue)
)
}

fun trackInstallButtonClicked() = analyticsTracker.track(
Stat.JETPACK_INSTALL_FULL_PLUGIN_FLOW_INSTALL_TAPPED, emptyMap()
)

fun trackRetryButtonClicked() = analyticsTracker.track(
Stat.JETPACK_INSTALL_FULL_PLUGIN_FLOW_RETRY_TAPPED, emptyMap()
)

fun trackJetpackInstallationSuccess() = analyticsTracker.track(
Stat.JETPACK_INSTALL_FULL_PLUGIN_FLOW_SUCCESS, emptyMap()
)

fun trackDoneButtonClicked() = analyticsTracker.track(
Stat.JETPACK_INSTALL_FULL_PLUGIN_FLOW_DONE_TAPPED, emptyMap()
)

sealed class Status(val trackingValue: String) {
object Initial : Status("initial")
object Loading : Status("loading")
object Error : Status("error")
}
}

private const val KEY_STATUS_PARAMETER = "status"
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,88 @@ package org.wordpress.android.ui.jpfullplugininstall.install

import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import org.wordpress.android.fluxc.Dispatcher
import org.wordpress.android.fluxc.generated.PluginActionBuilder
import org.wordpress.android.fluxc.generated.SiteActionBuilder
import org.wordpress.android.fluxc.store.PluginStore
import org.wordpress.android.fluxc.store.PluginStore.InstallSitePluginPayload
import org.wordpress.android.fluxc.store.PluginStore.OnSitePluginConfigured
import org.wordpress.android.fluxc.store.PluginStore.OnSitePluginInstalled
import org.wordpress.android.fluxc.store.SiteStore.OnSiteChanged
import org.wordpress.android.modules.BG_THREAD
import org.wordpress.android.ui.accounts.HelpActivity
import org.wordpress.android.ui.jpfullplugininstall.install.JetpackFullPluginInstallAnalyticsTracker.Status
import org.wordpress.android.ui.mysite.SelectedSiteRepository
import org.wordpress.android.util.AppLog
import org.wordpress.android.viewmodel.ScopedViewModel
import javax.inject.Inject
import javax.inject.Named

@HiltViewModel
@Suppress("UnusedPrivateMember")
class JetpackFullPluginInstallViewModel @Inject constructor(
private val uiStateMapper: JetpackFullPluginInstallUiStateMapper,
private val selectedSiteRepository: SelectedSiteRepository,
@Named(BG_THREAD) private val bgDispatcher: CoroutineDispatcher,
// adding pluginStore seems needed to allow the events Subscribe to work
private val pluginStore: PluginStore,
private val dispatcher: Dispatcher,
private val analyticsTracker: JetpackFullPluginInstallAnalyticsTracker,
) : ScopedViewModel(bgDispatcher) {
private val _uiState = MutableStateFlow<UiState>(uiStateMapper.mapInitial())
val uiState = _uiState.asStateFlow()

private val _actionEvents = MutableSharedFlow<ActionEvent>()
val actionEvents = _actionEvents

init {
dispatcher.register(this)
}

override fun onCleared() {
super.onCleared()
dispatcher.unregister(this)
}

fun onInitialShown() {
analyticsTracker.trackScreenShown(Status.Initial)
}

fun onInstallingShown() {
analyticsTracker.trackScreenShown(Status.Loading)
}

fun onErrorShown() {
analyticsTracker.trackScreenShown(Status.Error)
}

fun onContinueClick() {
analyticsTracker.trackInstallButtonClicked()
postUiState(uiStateMapper.mapInstalling())
installJetpackPlugin()
}

fun onBackPressed() {
dismissScreen()
}

fun onDismissScreenClick() {
postActionEvent(ActionEvent.Dismiss)
dismissScreen()
}

fun onDoneClick() {
analyticsTracker.trackDoneButtonClicked()
postActionEvent(ActionEvent.Dismiss)
}

fun onRetryClick() {
analyticsTracker.trackRetryButtonClicked()
postUiState(uiStateMapper.mapInstalling())
installJetpackPlugin()
}
Expand All @@ -53,20 +97,84 @@ class JetpackFullPluginInstallViewModel @Inject constructor(
)
}

@Suppress("MagicNumber")
@Suppress("unused")
@Subscribe(threadMode = ThreadMode.MAIN)
fun onSitePluginInstalled(event: OnSitePluginInstalled) {
if (event.isError) {
AppLog.d(
AppLog.T.PLUGINS,
"Error trying to install the full Jetpack plugin: ${event.error.type} - ${event.error.message}"
)
}

// Refresh the site regardless any event error if possible
event.site?.let {
dispatcher.dispatch(SiteActionBuilder.newFetchSiteAction(it))
} ?: postUiState(uiStateMapper.mapError())
}

@Suppress("unused")
@Subscribe(threadMode = ThreadMode.MAIN)
fun onSitePluginConfigured(event: OnSitePluginConfigured) {
if (event.isError) {
AppLog.d(
AppLog.T.PLUGINS,
"Error trying to configure the full Jetpack plugin: ${event.error.type} - ${event.error.message}"
)
}

// Refresh the site regardless any event error if possible
event.site?.let {
dispatcher.dispatch(SiteActionBuilder.newFetchSiteAction(it))
} ?: postUiState(uiStateMapper.mapError())
}

@Suppress("unused")
@Subscribe(threadMode = ThreadMode.MAIN)
fun onSiteChanged(event: OnSiteChanged) {
val success = if (event.isError) {
AppLog.d(
AppLog.T.PLUGINS,
"Error trying to update site while installing the full " +
"Jetpack plugin: ${event.error.type} - ${event.error.message}"
)
false
} else {
// Check if the final goal (JP installed and active) is matched
val selectedSite = selectedSiteRepository.getSelectedSite()
selectedSite?.let {
it.isJetpackInstalled && it.isJetpackConnected
} ?: false
}

if (success) {
analyticsTracker.trackJetpackInstallationSuccess()
postUiState(uiStateMapper.mapDone())
} else {
postUiState(uiStateMapper.mapError())
}
}

private fun installJetpackPlugin() {
// TODO replace mock with endpoint call and update unit tests
launch {
delay(2000L)
val success = true
if (success) {
postUiState(uiStateMapper.mapDone())
} else {
postUiState(uiStateMapper.mapError())
}
val selectedSite = selectedSiteRepository.getSelectedSite()
selectedSite?.let {
val payload = InstallSitePluginPayload(it, "jetpack")
dispatcher.dispatch(PluginActionBuilder.newInstallJpForIndividualPluginSiteAction(payload))
}
}

private fun dismissScreen() {
when (uiState.value) {
is UiState.Initial -> Status.Initial
is UiState.Installing -> Status.Loading
is UiState.Error -> Status.Error
else -> null
}?.let { status ->
analyticsTracker.trackCancelButtonClicked(status)
}
postActionEvent(ActionEvent.Dismiss)
}

private fun postUiState(uiState: UiState) {
launch {
_uiState.update { uiState }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import org.wordpress.android.ui.jpfullplugininstall.onboarding.JetpackFullPlugin
import org.wordpress.android.ui.jpfullplugininstall.onboarding.JetpackFullPluginInstallOnboardingViewModel.ActionEvent.OpenInstallJetpackFullPlugin
import org.wordpress.android.ui.jpfullplugininstall.onboarding.JetpackFullPluginInstallOnboardingViewModel.ActionEvent.OpenTermsAndConditions
import org.wordpress.android.ui.mysite.SelectedSiteRepository
import org.wordpress.android.ui.prefs.AppPrefsWrapper
import org.wordpress.android.viewmodel.ScopedViewModel
import javax.inject.Inject
import javax.inject.Named
Expand All @@ -23,6 +24,7 @@ class JetpackFullPluginInstallOnboardingViewModel @Inject constructor(
private val uiStateMapper: JetpackFullPluginInstallOnboardingUiStateMapper,
private val selectedSiteRepository: SelectedSiteRepository,
private val analyticsTracker: JetpackFullPluginInstallOnboardingAnalyticsTracker,
private val appPrefsWrapper: AppPrefsWrapper,
@Named(BG_THREAD) private val bgDispatcher: CoroutineDispatcher,
) : ScopedViewModel(bgDispatcher) {
private val _uiState = MutableStateFlow<UiState>(UiState.None)
Expand All @@ -32,6 +34,7 @@ class JetpackFullPluginInstallOnboardingViewModel @Inject constructor(
val actionEvents = _actionEvents

fun onScreenShown() {
updateOnboardingShownForCurrentSite()
analyticsTracker.trackScreenShown()
postUiState(uiStateMapper.mapLoaded())
}
Expand Down Expand Up @@ -59,6 +62,12 @@ class JetpackFullPluginInstallOnboardingViewModel @Inject constructor(
postActionEvent(Dismiss)
}

private fun updateOnboardingShownForCurrentSite() {
selectedSiteRepository.getSelectedSite()?.id?.let {
appPrefsWrapper.setShouldShowJetpackInstallOnboarding(it, false)
}
}

private fun postUiState(uiState: UiState) {
launch {
_uiState.update { uiState }
Expand Down
Loading

0 comments on commit cc0dcd7

Please sign in to comment.