Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import com.woocommerce.android.datastore.DataStoreType.ANALYTICS_UI_CACHE
import com.woocommerce.android.datastore.DataStoreType.COUPONS
import com.woocommerce.android.datastore.DataStoreType.DASHBOARD_STATS
import com.woocommerce.android.datastore.DataStoreType.LAST_UPDATE
import com.woocommerce.android.datastore.DataStoreType.SHIPPING_LABEL_ADDRESS
import com.woocommerce.android.datastore.DataStoreType.SHIPPING_LABEL_CONFIGURATION
import com.woocommerce.android.datastore.DataStoreType.TOP_PERFORMER_PRODUCTS
import com.woocommerce.android.datastore.DataStoreType.TRACKER
Expand Down Expand Up @@ -179,4 +180,24 @@ class DataStoreModule {
},
scope = CoroutineScope(appCoroutineScope.coroutineContext + Dispatchers.IO)
)

@Provides
@Singleton
@DataStoreQualifier(SHIPPING_LABEL_ADDRESS)
fun provideShippingLabelAddressDataStore(
appContext: Context,
crashLogging: CrashLogging,
@AppCoroutineScope appCoroutineScope: CoroutineScope
) = PreferenceDataStoreFactory.create(
produceFile = {
appContext.preferencesDataStoreFile("shipping_label_address")
},
corruptionHandler = ReplaceFileCorruptionHandler {
crashLogging.recordEvent(
"Corrupted data store. DataStore Type: ${SHIPPING_LABEL_ADDRESS.name}"
)
emptyPreferences()
},
scope = CoroutineScope(appCoroutineScope.coroutineContext + Dispatchers.IO)
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ enum class DataStoreType {
TOP_PERFORMER_PRODUCTS,
COUPONS,
LAST_UPDATE,
SHIPPING_LABEL_CONFIGURATION
SHIPPING_LABEL_CONFIGURATION,
SHIPPING_LABEL_ADDRESS
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
package com.woocommerce.android.ui.orders.wooshippinglabels

import com.woocommerce.android.ui.orders.wooshippinglabels.datasource.ShippingLabelsDataStore
import com.woocommerce.android.ui.orders.wooshippinglabels.datasource.WooShippingConfigurationDataStore
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.transformLatest
import javax.inject.Inject

class ObserveStoreOptions @Inject constructor(
val dataStore: ShippingLabelsDataStore,
val fetchAccountSettings: FetchAccountSettings,
private val configurationDataStore: WooShippingConfigurationDataStore,
private val fetchAccountSettings: FetchAccountSettings,
) {
private var isFirstValue = true

@OptIn(ExperimentalCoroutinesApi::class)
// We will use data store as the source of truth and after the first emission we will refresh the values async.
operator fun invoke() = dataStore.observeStoreOptions().transformLatest { options ->
operator fun invoke() = configurationDataStore.observeStoreOptions().transformLatest { options ->
when {
isFirstValue && options == null -> {
// If there is no cached data, refresh the store options before emitting any value
isFirstValue = false
if (fetchAccountSettings().isFailure) {
// We will use null as not available
emit(null)
Expand All @@ -25,6 +26,7 @@ class ObserveStoreOptions @Inject constructor(

isFirstValue && options != null -> {
// If there is cached data, emit cached values and refresh the store options async
isFirstValue = false
emit(options)
if (fetchAccountSettings().isFailure) {
emit(null)
Expand All @@ -33,6 +35,5 @@ class ObserveStoreOptions @Inject constructor(

else -> emit(options)
}
isFirstValue = false
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ import com.woocommerce.android.extensions.appendWithIfNotEmpty
import com.woocommerce.android.model.Address
import com.woocommerce.android.ui.compose.animations.SkeletonView
import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground
import com.woocommerce.android.ui.orders.wooshippinglabels.address.AddressSectionLandscape
import com.woocommerce.android.ui.orders.wooshippinglabels.address.AddressSectionPortrait
import com.woocommerce.android.ui.orders.wooshippinglabels.address.getShipFrom
import com.woocommerce.android.ui.orders.wooshippinglabels.address.getShipTo
import com.woocommerce.android.ui.orders.wooshippinglabels.models.OriginShippingAddress
import com.woocommerce.android.util.StringUtils
import kotlinx.coroutines.launch
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground
import com.woocommerce.android.ui.orders.wooshippinglabels.WooShippingLabelCreationViewModel.PackageSelectionState
import com.woocommerce.android.ui.orders.wooshippinglabels.WooShippingLabelCreationViewModel.PackageSelectionState.DataAvailable
import com.woocommerce.android.ui.orders.wooshippinglabels.WooShippingLabelCreationViewModel.PackageSelectionState.NotSelected
import com.woocommerce.android.ui.orders.wooshippinglabels.address.getShipFrom
import com.woocommerce.android.ui.orders.wooshippinglabels.address.getShipTo
import com.woocommerce.android.ui.orders.wooshippinglabels.models.OriginShippingAddress
import com.woocommerce.android.ui.orders.wooshippinglabels.packages.ui.PackageData
import com.woocommerce.android.ui.orders.wooshippinglabels.rates.ui.ShippingRateUI
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import com.woocommerce.android.model.Order
import com.woocommerce.android.ui.orders.details.OrderDetailRepository
import com.woocommerce.android.ui.orders.wooshippinglabels.WooShippingLabelCreationViewModel.PackageSelectionState.DataAvailable
import com.woocommerce.android.ui.orders.wooshippinglabels.WooShippingLabelCreationViewModel.PackageSelectionState.NotSelected
import com.woocommerce.android.ui.orders.wooshippinglabels.address.ObserveOriginAddresses
import com.woocommerce.android.ui.orders.wooshippinglabels.models.OriginShippingAddress
import com.woocommerce.android.ui.orders.wooshippinglabels.models.ShippableItemModel
import com.woocommerce.android.ui.orders.wooshippinglabels.models.StoreOptionsModel
Expand Down Expand Up @@ -205,7 +206,7 @@ class WooShippingLabelCreationViewModel @Inject constructor(

private suspend fun getShippingAddresses() {
order.combine(observeOriginAddresses()) { order, originAddresses ->
if (order != null && originAddresses.isNotEmpty()) {
if (order != null && !originAddresses.isNullOrEmpty()) {
val selectedOriginAddress = getSelectedOriginAddress(originAddresses)
WooShippingAddresses(
shipFrom = selectedOriginAddress,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.woocommerce.android.ui.orders.wooshippinglabels
package com.woocommerce.android.ui.orders.wooshippinglabels.address

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.IntrinsicSize
Expand Down Expand Up @@ -30,12 +30,17 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.constraintlayout.compose.ConstraintLayout
import androidx.constraintlayout.compose.Dimension
import com.woocommerce.android.R
import com.woocommerce.android.model.Address
import com.woocommerce.android.model.AmbiguousLocation
import com.woocommerce.android.model.Location
import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground
import com.woocommerce.android.ui.orders.wooshippinglabels.RoundedCornerBoxWithBorder
import com.woocommerce.android.ui.orders.wooshippinglabels.VerticalDivider
import com.woocommerce.android.ui.orders.wooshippinglabels.WooShippingAddresses
import com.woocommerce.android.ui.orders.wooshippinglabels.models.OriginShippingAddress
import com.woocommerce.android.ui.orders.wooshippinglabels.toShippingFromString

@Composable
@Suppress("DestructuringDeclarationWithTooManyEntries", "UnusedParameter")
Expand Down Expand Up @@ -87,7 +92,7 @@ internal fun AddressSectionPortrait(
top.linkTo(shipFromLabel.top)
start.linkTo(shipFromLabel.end)
end.linkTo(endBarrier)
width = androidx.constraintlayout.compose.Dimension.fillToConstraints
width = Dimension.fillToConstraints
}
.padding(
top = dimensionResource(R.dimen.major_100),
Expand Down Expand Up @@ -160,7 +165,7 @@ internal fun AddressSectionPortrait(
top.linkTo(shipToLabel.top)
start.linkTo(barrier)
end.linkTo(shipToEdit.start)
width = androidx.constraintlayout.compose.Dimension.fillToConstraints
width = Dimension.fillToConstraints
}
.padding(
top = dimensionResource(R.dimen.major_100),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.woocommerce.android.ui.orders.wooshippinglabels.address

import com.woocommerce.android.tools.SelectedSite
import com.woocommerce.android.ui.orders.wooshippinglabels.models.OriginShippingAddress
import com.woocommerce.android.ui.orders.wooshippinglabels.networking.WooShippingLabelRepository
import javax.inject.Inject

class FetchOriginAddresses @Inject constructor(
private val shippingRepository: WooShippingLabelRepository,
private val selectedSite: SelectedSite
) {
suspend operator fun invoke(): Result<List<OriginShippingAddress>> {
return selectedSite.getOrNull()?.let {
val response = shippingRepository.fetchOriginAddresses(it)
val result = response.model
when {
response.isError.not() && !result.isNullOrEmpty() -> {
Result.success(result)
}

else -> {
val message =
response.error?.message ?: if (result.isNullOrEmpty()) "Empty result" else "Unknown error"
Result.failure(Exception(message))
}
}
} ?: Result.failure(Exception("No site selected"))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.woocommerce.android.ui.orders.wooshippinglabels.address

import com.woocommerce.android.ui.orders.wooshippinglabels.datasource.WooShippingAddressDataStore
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.transformLatest
import javax.inject.Inject

class ObserveOriginAddresses @Inject constructor(
private val addressDataStore: WooShippingAddressDataStore,
private val fetchOriginAddresses: FetchOriginAddresses
) {
private var isFirstValue = true

@OptIn(ExperimentalCoroutinesApi::class)
// We will use data store as the source of truth and after the first emission we will refresh the values async.
operator fun invoke() = addressDataStore.observeOriginAddresses().transformLatest { addresses ->
when {
isFirstValue && addresses == null -> {
// If there is no cached data, refresh the origin addresses before emitting any value
isFirstValue = false
if (fetchOriginAddresses().isFailure) {
// We will use null as not available
emit(null)
}
}

isFirstValue && addresses != null -> {
// If there is cached data, emit cached values and refresh the origin addresses async
isFirstValue = false
emit(addresses)
if (fetchOriginAddresses().isFailure) {
emit(null)
}
}

else -> emit(addresses)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.woocommerce.android.ui.orders.wooshippinglabels.datasource

import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.stringPreferencesKey
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.woocommerce.android.datastore.DataStoreQualifier
import com.woocommerce.android.datastore.DataStoreType
import com.woocommerce.android.tools.SelectedSite
import com.woocommerce.android.ui.orders.wooshippinglabels.models.OriginShippingAddress
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import javax.inject.Inject

class WooShippingAddressDataStore @Inject constructor(
@DataStoreQualifier(DataStoreType.SHIPPING_LABEL_ADDRESS) private val dataStore: DataStore<Preferences>,
private val gson: Gson,
private val selectedSite: SelectedSite
) {
private fun getOriginAddressesKey() = "${selectedSite.getOrNull()?.siteId ?: ""}OriginAddresses"

fun observeOriginAddresses(): Flow<List<OriginShippingAddress>?> {
val typeToken = object : TypeToken<List<OriginShippingAddress>>() {}.type
return dataStore.data.map { prefs ->
val storeOptions = prefs[stringPreferencesKey(getOriginAddressesKey())]
runCatching {
gson.fromJson<List<OriginShippingAddress>>(storeOptions, typeToken)
}.getOrNull()
}
}

suspend fun saveOriginAddresses(addresses: List<OriginShippingAddress>) {
dataStore.edit { preferences ->
preferences[stringPreferencesKey(getOriginAddressesKey())] = gson.toJson(addresses)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import javax.inject.Inject

class ShippingLabelsDataStore @Inject constructor(
class WooShippingConfigurationDataStore @Inject constructor(
@DataStoreQualifier(DataStoreType.SHIPPING_LABEL_CONFIGURATION) private val dataStore: DataStore<Preferences>,
private val gson: Gson,
private val selectedSite: SelectedSite
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,21 @@ data class ShippingRatePurchaseResponseDTO(
val deliveryDateGuaranteed: Boolean,
val deliveryDate: String?
)

data class OriginAddressDTO(
val id: String? = null,
@SerializedName("address_1") val address: String? = null,
@SerializedName("address_2") val address2: String? = null,
val city: String? = null,
val company: String? = null,
val country: String? = null,
val name: String? = null,
val phone: String? = null,
val postcode: String? = null,
val state: String? = null,
val email: String? = null,
@SerializedName("first_name") val firstName: String? = null,
@SerializedName("last_name") val lastName: String? = null,
@SerializedName("is_verified") val isVerified: Boolean = false,
@SerializedName("default_address") val defaultAddress: Boolean = false,
)
Loading
Loading