Skip to content

Commit adfdc06

Browse files
Merge pull request #14544 from woocommerce/issue/WOOMOB-1126-app-passwords-network
[Jetpack Performance] Add local feature flag and enable app passwords for all endpoints
2 parents c58946a + 586a357 commit adfdc06

File tree

31 files changed

+383
-403
lines changed

31 files changed

+383
-403
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.woocommerce.android.wear.di
2+
3+
import dagger.Binds
4+
import dagger.Module
5+
import dagger.hilt.InstallIn
6+
import dagger.hilt.components.SingletonComponent
7+
import org.wordpress.android.fluxc.network.rest.wpapi.applicationpasswords.ApplicationPasswordsConfiguration
8+
import javax.inject.Inject
9+
10+
@Module
11+
@InstallIn(SingletonComponent::class)
12+
interface ApplicationPasswordsModule {
13+
@Binds
14+
fun bindApplicationPasswordsConfiguration(
15+
configuration: WooWearApplicationPasswordsConfiguration
16+
): ApplicationPasswordsConfiguration
17+
}
18+
19+
class WooWearApplicationPasswordsConfiguration @Inject constructor() : ApplicationPasswordsConfiguration {
20+
override val applicationName: String = ""
21+
22+
override fun isEnabledForDirectAccess(): Boolean = false
23+
override suspend fun isEnabledForJetpackAccess(): Boolean = false
24+
}

WooCommerce/src/main/kotlin/com/woocommerce/android/AppPrefs.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,8 @@ object AppPrefs {
134134
CUSTOM_FIELDS_TOP_BANNER_DISMISSED,
135135
BLAZE_CAMPAIGN_SELECTED_OBJECTIVE,
136136
BLAZE_CAMPAIGN_OBJECTIVE_SWITCH_CHECKED,
137-
IS_SITE_WPCOM_SUSPENDED
137+
IS_SITE_WPCOM_SUSPENDED,
138+
JETPACK_APP_PASSWORDS_ENABLED
138139
}
139140

140141
/**
@@ -301,6 +302,10 @@ object AppPrefs {
301302
get() = getBoolean(DeletablePrefKey.GATEWAY_MIGRATED, false)
302303
set(value) = setBoolean(DeletablePrefKey.GATEWAY_MIGRATED, value)
303304

305+
var jetpackAppPasswordsEnabled: Boolean
306+
get() = getBoolean(DeletablePrefKey.JETPACK_APP_PASSWORDS_ENABLED, true)
307+
set(value) = setBoolean(DeletablePrefKey.JETPACK_APP_PASSWORDS_ENABLED, value)
308+
304309
fun getProductSortingChoice(currentSiteId: Int) = getString(getProductSortingKey(currentSiteId)).orNullIfEmpty()
305310

306311
fun setProductSortingChoice(currentSiteId: Int, value: String) {

WooCommerce/src/main/kotlin/com/woocommerce/android/AppPrefsWrapper.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ open class AppPrefsWrapper @Inject constructor() {
4242
open var orderSummaryMigrated by AppPrefs::orderSummaryMigrated
4343
open var gatewayMigrated by AppPrefs::gatewayMigrated
4444

45+
var jetpackAppPasswordsEnabled by AppPrefs::jetpackAppPasswordsEnabled
46+
4547
fun getAppInstallationDate() = AppPrefs.installationDate
4648

4749
fun getReceiptUrl(localSiteId: Int, remoteSiteId: Long, selfHostedSiteId: Long, orderId: Long) =
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.woocommerce.android.applicationpasswords
2+
3+
import com.woocommerce.android.AppPrefsWrapper
4+
import com.woocommerce.android.BuildConfig
5+
import com.woocommerce.android.util.DeviceInfo
6+
import com.woocommerce.android.util.FeatureFlag.APP_PASSWORDS_FOR_JETPACK_SITES
7+
import jakarta.inject.Inject
8+
import org.wordpress.android.fluxc.network.rest.wpapi.applicationpasswords.ApplicationPasswordsConfiguration
9+
10+
class WooApplicationPasswordsConfiguration @Inject constructor(
11+
private val appPrefs: AppPrefsWrapper
12+
) : ApplicationPasswordsConfiguration {
13+
override val applicationName: String =
14+
"${BuildConfig.APPLICATION_ID}.app-client.${DeviceInfo.name.replace(' ', '-')}"
15+
16+
override suspend fun isEnabledForJetpackAccess(): Boolean =
17+
APP_PASSWORDS_FOR_JETPACK_SITES.isEnabled() && appPrefs.jetpackAppPasswordsEnabled
18+
}

WooCommerce/src/main/kotlin/com/woocommerce/android/config/FirebaseRemoteConfigRepository.kt

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ class FirebaseRemoteConfigRepository @Inject constructor(
2121
companion object {
2222
private const val DEBUG_INTERVAL = 10L
2323
private const val RELEASE_INTERVAL = 31200L
24-
25-
const val KEY_ENABLE_JETPACK_APP_PASSWORDS_EXPERIMENT = "wcandroid_enable_jetpack_app_passwords_experiment_2"
2624
}
2725

2826
private val minimumFetchIntervalInSeconds =
@@ -37,11 +35,7 @@ class FirebaseRemoteConfigRepository @Inject constructor(
3735
private val _fetchStatus = MutableStateFlow(RemoteConfigFetchStatus.Pending)
3836
override val fetchStatus: Flow<RemoteConfigFetchStatus> = _fetchStatus.asStateFlow()
3937

40-
private val defaultValues by lazy {
41-
mapOf(
42-
KEY_ENABLE_JETPACK_APP_PASSWORDS_EXPERIMENT to false.toString()
43-
)
44-
}
38+
private val defaultValues = emptyMap<String, String>()
4539

4640
init {
4741
remoteConfig.apply {
@@ -73,8 +67,4 @@ class FirebaseRemoteConfigRepository @Inject constructor(
7367
@VisibleForTesting
7468
fun observeStringRemoteValue(key: String) = changesTrigger
7569
.map { remoteConfig.getString(key) }
76-
77-
override fun isJetpackAppPasswordsExperimentEnabled(): Boolean {
78-
return remoteConfig.getBoolean(KEY_ENABLE_JETPACK_APP_PASSWORDS_EXPERIMENT)
79-
}
8070
}

WooCommerce/src/main/kotlin/com/woocommerce/android/config/RemoteConfigRepository.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ import kotlinx.coroutines.flow.Flow
55
interface RemoteConfigRepository {
66
val fetchStatus: Flow<RemoteConfigFetchStatus>
77
fun fetchRemoteConfig()
8-
9-
fun isJetpackAppPasswordsExperimentEnabled(): Boolean
108
}
119

1210
enum class RemoteConfigFetchStatus {
Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
package com.woocommerce.android.di
22

3-
import com.woocommerce.android.BuildConfig
43
import com.woocommerce.android.applicationpasswords.ApplicationPasswordsNotifier
5-
import com.woocommerce.android.util.DeviceInfo
4+
import com.woocommerce.android.applicationpasswords.WooApplicationPasswordsConfiguration
65
import dagger.Binds
76
import dagger.Module
8-
import dagger.Provides
97
import dagger.hilt.InstallIn
108
import dagger.hilt.components.SingletonComponent
11-
import org.wordpress.android.fluxc.module.ApplicationPasswordsClientId
9+
import org.wordpress.android.fluxc.network.rest.wpapi.applicationpasswords.ApplicationPasswordsConfiguration
1210
import org.wordpress.android.fluxc.network.rest.wpapi.applicationpasswords.ApplicationPasswordsListener
1311

1412
@Module
@@ -19,10 +17,8 @@ interface ApplicationPasswordsModule {
1917
notifier: ApplicationPasswordsNotifier
2018
): ApplicationPasswordsListener
2119

22-
companion object {
23-
@Provides
24-
@ApplicationPasswordsClientId
25-
fun providesApplicationPasswordClientId() =
26-
"${BuildConfig.APPLICATION_ID}.app-client.${DeviceInfo.name.replace(' ', '-')}"
27-
}
20+
@Binds
21+
fun bindApplicationPasswordsConfiguration(
22+
configuration: WooApplicationPasswordsConfiguration
23+
): ApplicationPasswordsConfiguration
2824
}

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/login/sitecredentials/LoginSiteCredentialsViewModel.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ import kotlinx.coroutines.flow.map
3737
import kotlinx.coroutines.flow.onEach
3838
import kotlinx.coroutines.launch
3939
import org.wordpress.android.fluxc.model.SiteModel
40-
import org.wordpress.android.fluxc.module.ApplicationPasswordsClientId
4140
import org.wordpress.android.fluxc.network.rest.wpapi.Nonce.CookieNonceErrorType.INVALID_CREDENTIALS
41+
import org.wordpress.android.fluxc.network.rest.wpapi.applicationpasswords.ApplicationPasswordsConfiguration
4242
import org.wordpress.android.fluxc.store.SiteStore.SiteError
4343
import org.wordpress.android.login.LoginAnalyticsListener
4444
import org.wordpress.android.util.UrlUtils
@@ -55,7 +55,7 @@ class LoginSiteCredentialsViewModel @Inject constructor(
5555
private val analyticsTracker: AnalyticsTrackerWrapper,
5656
private val appPrefs: AppPrefsWrapper,
5757
private val resourceProvider: ResourceProvider,
58-
@ApplicationPasswordsClientId private val applicationPasswordsClientId: String
58+
private val applicationPasswordsConfiguration: ApplicationPasswordsConfiguration
5959
) : ScopedViewModel(savedStateHandle) {
6060
companion object {
6161
const val SITE_ADDRESS_KEY = "site-address"
@@ -82,7 +82,9 @@ class LoginSiteCredentialsViewModel @Inject constructor(
8282

8383
private val SiteModel?.fullAuthorizationUrl: String?
8484
get() = this?.applicationPasswordsAuthorizeUrl
85-
?.let { url -> "$url?app_name=$applicationPasswordsClientId&success_url=$REDIRECTION_URL" }
85+
?.let { url ->
86+
"$url?app_name=${applicationPasswordsConfiguration.applicationName}&success_url=$REDIRECTION_URL"
87+
}
8688

8789
val viewState = combine(
8890
flowOf(siteAddress.removeSchemeAndSuffix()),

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/orders/list/OrderListItemDataSource.kt

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package com.woocommerce.android.ui.orders.list
22

33
import com.woocommerce.android.R
4-
import com.woocommerce.android.config.RemoteConfigRepository
54
import com.woocommerce.android.extensions.getBillingName
65
import com.woocommerce.android.model.TimeGroup
76
import com.woocommerce.android.model.TimeGroup.GROUP_FUTURE
@@ -45,8 +44,7 @@ class OrderListItemDataSource @Inject constructor(
4544
private val networkStatus: NetworkStatus,
4645
private val fetcher: FetchOrdersRepository,
4746
private val resourceProvider: ResourceProvider,
48-
private val dateUtils: DateUtils,
49-
private val remoteConfigRepository: RemoteConfigRepository
47+
private val dateUtils: DateUtils
5048
) : ListItemDataSourceInterface<WCOrderListDescriptor, OrderListItemIdentifier, OrderListItemUIType> {
5149
override fun getItemsAndFetchIfNecessary(
5250
listDescriptor: WCOrderListDescriptor,
@@ -195,8 +193,7 @@ class OrderListItemDataSource @Inject constructor(
195193
override fun fetchList(listDescriptor: WCOrderListDescriptor, offset: Long) {
196194
val fetchOrderListPayload = FetchOrderListPayload(
197195
listDescriptor = listDescriptor,
198-
offset = offset,
199-
useAppPasswordsForJetpackSites = remoteConfigRepository.isJetpackAppPasswordsExperimentEnabled()
196+
offset = offset
200197
)
201198
dispatcher.dispatch(WCOrderActionBuilder.newFetchOrderListAction(fetchOrderListPayload))
202199
}

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/prefs/BetaFeaturesFragment.kt

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.woocommerce.android.ui.prefs
33
import android.os.Bundle
44
import android.view.View
55
import android.widget.CompoundButton
6+
import androidx.core.view.isVisible
67
import androidx.fragment.app.Fragment
78
import com.google.android.material.snackbar.BaseTransientBottomBar
89
import com.google.android.material.snackbar.Snackbar
@@ -11,16 +12,23 @@ import com.woocommerce.android.R
1112
import com.woocommerce.android.analytics.AnalyticsEvent.PRODUCT_ADDONS_BETA_FEATURES_SWITCH_TOGGLED
1213
import com.woocommerce.android.analytics.AnalyticsTracker
1314
import com.woocommerce.android.databinding.FragmentSettingsBetaBinding
15+
import com.woocommerce.android.tools.SelectedSite
16+
import com.woocommerce.android.tools.SiteConnectionType
1417
import com.woocommerce.android.ui.prefs.MainSettingsFragment.AppSettingsListener
1518
import com.woocommerce.android.util.AnalyticsUtils
19+
import com.woocommerce.android.util.FeatureFlag
1620
import dagger.hilt.android.AndroidEntryPoint
21+
import javax.inject.Inject
1722

1823
@AndroidEntryPoint
1924
class BetaFeaturesFragment : Fragment(R.layout.fragment_settings_beta) {
2025
companion object {
2126
const val TAG = "beta-features"
2227
}
2328

29+
@Inject
30+
lateinit var selectedSite: SelectedSite
31+
2432
private val settingsListener by lazy {
2533
activity as? AppSettingsListener
2634
}
@@ -30,6 +38,7 @@ class BetaFeaturesFragment : Fragment(R.layout.fragment_settings_beta) {
3038

3139
with(FragmentSettingsBetaBinding.bind(view)) {
3240
bindProductAddonsToggle()
41+
bindJetpackAppPasswordsToggle()
3342
}
3443
}
3544

@@ -49,11 +58,22 @@ class BetaFeaturesFragment : Fragment(R.layout.fragment_settings_beta) {
4958
}
5059
}
5160

61+
private fun FragmentSettingsBetaBinding.bindJetpackAppPasswordsToggle() {
62+
// TODO check the remote feature flag state once available
63+
val isJetpackSite = selectedSite.connectionType != SiteConnectionType.ApplicationPasswords
64+
jetpackAppPasswordsToggle.isVisible = FeatureFlag.APP_PASSWORDS_FOR_JETPACK_SITES.isEnabled() && isJetpackSite
65+
66+
jetpackAppPasswordsToggle.isChecked = AppPrefs.jetpackAppPasswordsEnabled
67+
jetpackAppPasswordsToggle.setOnCheckedChangeListener { _, isChecked ->
68+
AppPrefs.jetpackAppPasswordsEnabled = isChecked
69+
}
70+
}
71+
5272
override fun onResume() {
5373
super.onResume()
5474
AnalyticsTracker.trackViewShown(this)
5575

56-
activity?.setTitle(R.string.beta_features)
76+
activity?.setTitle(R.string.experimental_features)
5777
}
5878

5979
private fun FragmentSettingsBetaBinding.handleToggleChangeFailure(switch: CompoundButton, isChecked: Boolean) {

0 commit comments

Comments
 (0)