From 18f85ad533e2f7dcd89a5d07441015cb4f80374b Mon Sep 17 00:00:00 2001 From: Konstantin Ivanov <54908981+konstantiniiv@users.noreply.github.com> Date: Mon, 18 Nov 2024 14:38:03 +0100 Subject: [PATCH] DROID-2797 Date as an object | Vault default settings (#1801) --- .../features/sets/dv/TestObjectSetSetup.kt | 13 +- .../anytypeio/anytype/di/main/DataModule.kt | 18 +- .../anytypeio/anytype/di/main/DeviceModule.kt | 2 +- .../anytypeio/anytype/di/main/UtilModule.kt | 11 +- .../anytype/core_models/Constants.kt | 17 +- .../core_models/settings/VaultSettings.kt | 4 +- .../data/auth/repo/UserSettingsCache.kt | 3 + .../auth/repo/UserSettingsDataRepository.kt | 14 ++ device/build.gradle | 2 + .../providers/AppDefaultDateFormatProvider.kt | 48 +++++ .../device/providers}/DateProviderImpl.kt | 12 +- .../{ => providers}/DefaultLocalProvider.kt | 2 +- .../anytype}/DateProviderImplTest.kt | 23 ++- .../domain/config/UserSettingsRepository.kt | 3 + .../anytype/domain/misc/DateProvider.kt | 4 +- .../domain/vault/ObserveVaultSettings.kt | 7 +- .../provider/MembershipProviderTest.kt | 3 +- persistence/build.gradle | 1 + .../repo/DefaultUserSettingsCache.kt | 71 +++++-- persistence/src/main/proto/preferences.proto | 2 + .../persistence/UserSettingsCacheTest.kt | 191 +++++++++++++++++- .../history/VersionHistoryVMFactory.kt | 6 - .../history/VersionHistoryViewModel.kt | 26 +-- .../membership/provider/MembershipProvider.kt | 3 +- .../CollectionCreateAndAddObjectTest.kt | 3 - .../history/VersionHistoryViewModelTest.kt | 26 +-- .../objects/CreateDVObjectTest.kt | 6 +- .../sets/main/ObjectSetViewModelTestSetup.kt | 14 +- 28 files changed, 432 insertions(+), 103 deletions(-) create mode 100644 device/src/main/java/com/anytypeio/anytype/device/providers/AppDefaultDateFormatProvider.kt rename {presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/collection => device/src/main/java/com/anytypeio/anytype/device/providers}/DateProviderImpl.kt (95%) rename device/src/main/java/com/anytypeio/anytype/device/{ => providers}/DefaultLocalProvider.kt (91%) rename {presentation/src/test/java/com/anytypeio/anytype/presentation/widgets/collection => device/src/test/java/com/anytypeio/anytype}/DateProviderImplTest.kt (92%) diff --git a/app/src/androidTest/java/com/anytypeio/anytype/features/sets/dv/TestObjectSetSetup.kt b/app/src/androidTest/java/com/anytypeio/anytype/features/sets/dv/TestObjectSetSetup.kt index febd9daded..0d5d3abcde 100644 --- a/app/src/androidTest/java/com/anytypeio/anytype/features/sets/dv/TestObjectSetSetup.kt +++ b/app/src/androidTest/java/com/anytypeio/anytype/features/sets/dv/TestObjectSetSetup.kt @@ -13,6 +13,7 @@ import com.anytypeio.anytype.core_models.Relation import com.anytypeio.anytype.core_models.SearchResult import com.anytypeio.anytype.core_models.SubscriptionEvent import com.anytypeio.anytype.core_models.primitives.SpaceId +import com.anytypeio.anytype.device.providers.DateProviderImpl import com.anytypeio.anytype.domain.auth.interactor.ClearLastOpenedObject import com.anytypeio.anytype.domain.auth.repo.AuthRepository import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers @@ -32,6 +33,7 @@ import com.anytypeio.anytype.domain.event.interactor.InterceptEvents import com.anytypeio.anytype.domain.event.interactor.SpaceSyncAndP2PStatusProvider import com.anytypeio.anytype.domain.launch.GetDefaultObjectType import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer +import com.anytypeio.anytype.domain.misc.LocaleProvider import com.anytypeio.anytype.domain.misc.UrlBuilder import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider import com.anytypeio.anytype.domain.networkmode.GetNetworkMode @@ -71,16 +73,18 @@ import com.anytypeio.anytype.presentation.sets.subscription.DefaultDataViewSubsc import com.anytypeio.anytype.presentation.sets.viewer.ViewerDelegate import com.anytypeio.anytype.presentation.templates.ObjectTypeTemplatesContainer import com.anytypeio.anytype.presentation.util.Dispatcher -import com.anytypeio.anytype.presentation.widgets.collection.DateProviderImpl import com.anytypeio.anytype.test_utils.MockDataFactory import java.time.ZoneId +import java.util.Locale import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.test.StandardTestDispatcher import org.mockito.Mock +import org.mockito.Mockito import org.mockito.MockitoAnnotations import org.mockito.kotlin.any import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock import org.mockito.kotlin.stub abstract class TestObjectSetSetup { @@ -224,7 +228,10 @@ abstract class TestObjectSetSetup { private val delegator = Delegator.Default() - private val dateProvider = DateProviderImpl(ZoneId.systemDefault()) + @Mock + lateinit var localeProvider : LocaleProvider + + private val dateProvider = DateProviderImpl(ZoneId.systemDefault(), localeProvider) open fun setup() { MockitoAnnotations.openMocks(this) @@ -312,6 +319,8 @@ abstract class TestObjectSetSetup { spaceSyncAndP2PStatusProvider = spaceSyncAndP2PStatusProvider, clearLastOpenedObject = clearLastOpenedObject ) + + Mockito.`when`(localeProvider.locale()).thenReturn(Locale.getDefault()) } fun stubInterceptEvents() { diff --git a/app/src/main/java/com/anytypeio/anytype/di/main/DataModule.kt b/app/src/main/java/com/anytypeio/anytype/di/main/DataModule.kt index 8eab1a5e8e..388d2debf2 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/main/DataModule.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/main/DataModule.kt @@ -50,6 +50,9 @@ import com.anytypeio.anytype.middleware.service.MiddlewareService import com.anytypeio.anytype.middleware.service.MiddlewareServiceImplementation import com.anytypeio.anytype.persistence.db.AnytypeDatabase import com.anytypeio.anytype.persistence.networkmode.NetworkModeProvider +import com.anytypeio.anytype.device.providers.AppDefaultDateFormatProvider +import com.anytypeio.anytype.device.providers.AppDefaultDateFormatProviderImpl +import com.anytypeio.anytype.domain.misc.LocaleProvider import com.anytypeio.anytype.persistence.repo.DefaultAuthCache import com.anytypeio.anytype.persistence.repo.DefaultDebugSettingsCache import com.anytypeio.anytype.persistence.repo.DefaultUserSettingsCache @@ -280,10 +283,12 @@ object DataModule { @Singleton fun provideUserSettingsCache( @Named("default") prefs: SharedPreferences, - context: Context + context: Context, + appDefaultDateFormatProvider: AppDefaultDateFormatProvider ): UserSettingsCache = DefaultUserSettingsCache( prefs = prefs, - context = context + context = context, + appDefaultDateFormatProvider = appDefaultDateFormatProvider ) @JvmStatic @@ -334,6 +339,15 @@ object DataModule { context: Context ): UriFileProvider = DefaultUriFileProvider(context) + @JvmStatic + @Provides + @Singleton + fun provideAppDefaultDateFormatProvider( + localeProvider: LocaleProvider + ): AppDefaultDateFormatProvider = AppDefaultDateFormatProviderImpl( + localeProvider = localeProvider + ) + @Module interface Bindings { diff --git a/app/src/main/java/com/anytypeio/anytype/di/main/DeviceModule.kt b/app/src/main/java/com/anytypeio/anytype/di/main/DeviceModule.kt index a2c413ce01..1438b7c965 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/main/DeviceModule.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/main/DeviceModule.kt @@ -3,7 +3,7 @@ package com.anytypeio.anytype.di.main import android.content.Context import com.anytypeio.anytype.data.auth.other.DataDownloader import com.anytypeio.anytype.data.auth.other.Device -import com.anytypeio.anytype.device.DefaultLocalProvider +import com.anytypeio.anytype.device.providers.DefaultLocalProvider import com.anytypeio.anytype.device.SharedFileUploader import com.anytypeio.anytype.device.base.AndroidDevice import com.anytypeio.anytype.device.download.AndroidDeviceDownloader diff --git a/app/src/main/java/com/anytypeio/anytype/di/main/UtilModule.kt b/app/src/main/java/com/anytypeio/anytype/di/main/UtilModule.kt index e81480cc4a..d62a7691dd 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/main/UtilModule.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/main/UtilModule.kt @@ -13,18 +13,19 @@ import com.anytypeio.anytype.core_utils.tools.DefaultUrlValidator import com.anytypeio.anytype.core_utils.tools.FeatureToggles import com.anytypeio.anytype.core_utils.tools.ThreadInfo import com.anytypeio.anytype.core_utils.tools.UrlValidator +import com.anytypeio.anytype.device.providers.DateProviderImpl import com.anytypeio.anytype.domain.config.Gateway import com.anytypeio.anytype.domain.debugging.DebugConfig import com.anytypeio.anytype.domain.debugging.Logger import com.anytypeio.anytype.domain.misc.DateProvider import com.anytypeio.anytype.domain.misc.DateTypeNameProvider +import com.anytypeio.anytype.domain.misc.LocaleProvider import com.anytypeio.anytype.domain.misc.UrlBuilder import com.anytypeio.anytype.middleware.interactor.MiddlewareProtobufLogger import com.anytypeio.anytype.middleware.interactor.ProtobufConverterProvider import com.anytypeio.anytype.other.BasicLogger import com.anytypeio.anytype.other.DefaultDateTypeNameProvider import com.anytypeio.anytype.other.DefaultDebugConfig -import com.anytypeio.anytype.presentation.widgets.collection.DateProviderImpl import dagger.Binds import dagger.Module import dagger.Provides @@ -55,8 +56,12 @@ object UtilModule { @JvmStatic @Provides @Singleton - fun provideDateProvider(): DateProvider = - DateProviderImpl(defaultZoneId = ZoneId.systemDefault() + fun provideDateProvider( + localeProvider: LocaleProvider + ): DateProvider = + DateProviderImpl( + defaultZoneId = ZoneId.systemDefault(), + localeProvider = localeProvider ) @Module diff --git a/core-models/src/main/java/com/anytypeio/anytype/core_models/Constants.kt b/core-models/src/main/java/com/anytypeio/anytype/core_models/Constants.kt index 5caf0f9ddc..4d39e378eb 100644 --- a/core-models/src/main/java/com/anytypeio/anytype/core_models/Constants.kt +++ b/core-models/src/main/java/com/anytypeio/anytype/core_models/Constants.kt @@ -1,4 +1,19 @@ package com.anytypeio.anytype.core_models const val NO_VALUE = "" -const val EMPTY_QUERY = "" \ No newline at end of file +const val EMPTY_QUERY = "" + +/** + * The default date format pattern to use if retrieval fails. + */ +const val FALLBACK_DATE_PATTERN = "dd/MM/yyyy" + +/** + * The default value for relative dates. + */ +const val DEFAULT_RELATIVE_DATES = true + +/** + * The default value for showing the introduce vault. + */ +const val DEFAULT_SHOW_INTRODUCE_VAULT = true \ No newline at end of file diff --git a/core-models/src/main/java/com/anytypeio/anytype/core_models/settings/VaultSettings.kt b/core-models/src/main/java/com/anytypeio/anytype/core_models/settings/VaultSettings.kt index e10cb82839..40a0eee3d4 100644 --- a/core-models/src/main/java/com/anytypeio/anytype/core_models/settings/VaultSettings.kt +++ b/core-models/src/main/java/com/anytypeio/anytype/core_models/settings/VaultSettings.kt @@ -4,5 +4,7 @@ import com.anytypeio.anytype.core_models.Id data class VaultSettings( val showIntroduceVault: Boolean, - val orderOfSpaces: List = emptyList() + val orderOfSpaces: List = emptyList(), + val isRelativeDates: Boolean, + val dateFormat: String ) \ No newline at end of file diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/UserSettingsCache.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/UserSettingsCache.kt index e86801f5b1..52b63f6a45 100644 --- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/UserSettingsCache.kt +++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/UserSettingsCache.kt @@ -46,4 +46,7 @@ interface UserSettingsCache { suspend fun getAllContentSort(space: SpaceId): Pair? suspend fun setAllContentSort(space: SpaceId, sort: Id, isAsc: Boolean) + + suspend fun setRelativeDates(account: Account, enabled: Boolean) + suspend fun setDateFormat(account: Account, format: String) } \ No newline at end of file diff --git a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/UserSettingsDataRepository.kt b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/UserSettingsDataRepository.kt index 036412c489..68d85ac188 100644 --- a/data/src/main/java/com/anytypeio/anytype/data/auth/repo/UserSettingsDataRepository.kt +++ b/data/src/main/java/com/anytypeio/anytype/data/auth/repo/UserSettingsDataRepository.kt @@ -117,4 +117,18 @@ class UserSettingsDataRepository(private val cache: UserSettingsCache) : UserSet override suspend fun setAllContentSort(space: SpaceId, sort: Id, isAsc: Boolean) { cache.setAllContentSort(space, sort, isAsc) } + + override suspend fun setRelativeDates( + account: Account, + enabled: Boolean + ) { + cache.setRelativeDates(account, enabled) + } + + override suspend fun setDateFormat( + account: Account, + format: String + ) { + cache.setDateFormat(account, format) + } } \ No newline at end of file diff --git a/device/build.gradle b/device/build.gradle index be7c4daa21..dcfef8b92c 100644 --- a/device/build.gradle +++ b/device/build.gradle @@ -8,6 +8,7 @@ dependencies { implementation project(':data') implementation project(':domain') implementation project(':localization') + implementation project(':core-models') implementation libs.kotlin implementation libs.coroutinesAndroid @@ -19,6 +20,7 @@ dependencies { testImplementation libs.kotlinTest testImplementation libs.androidXTestCore testImplementation libs.robolectric + testImplementation libs.mockitoKotlin compileOnly libs.javaxInject } diff --git a/device/src/main/java/com/anytypeio/anytype/device/providers/AppDefaultDateFormatProvider.kt b/device/src/main/java/com/anytypeio/anytype/device/providers/AppDefaultDateFormatProvider.kt new file mode 100644 index 0000000000..7677886408 --- /dev/null +++ b/device/src/main/java/com/anytypeio/anytype/device/providers/AppDefaultDateFormatProvider.kt @@ -0,0 +1,48 @@ +package com.anytypeio.anytype.device.providers + +import com.anytypeio.anytype.core_models.FALLBACK_DATE_PATTERN +import com.anytypeio.anytype.domain.misc.LocaleProvider +import java.text.DateFormat +import java.text.SimpleDateFormat +import javax.inject.Inject +import timber.log.Timber + +/** + * Interface for providing the default date format pattern as a [String]. + */ +interface AppDefaultDateFormatProvider { + + /** + * Retrieves the default date format pattern based on the current locale. + * + * @return A date format pattern [String], e.g., "MM/dd/yyyy". + */ + fun provide(): String +} + +class AppDefaultDateFormatProviderImpl @Inject constructor( + private val localeProvider: LocaleProvider +) : AppDefaultDateFormatProvider { + + /** + * Provides the default date format pattern based on the current locale. + * + * @return The date format pattern as a [String]. If unable to retrieve the pattern, + * returns the [FALLBACK_DATE_PATTERN]. + */ + override fun provide(): String { + return try { + val locale = localeProvider.locale() + val dateFormat = DateFormat.getDateInstance(DateFormat.SHORT, locale) + if (dateFormat is SimpleDateFormat) { + dateFormat.toPattern() + } else { + Timber.e("DateFormat instance is not a SimpleDateFormat for locale: %s", locale) + FALLBACK_DATE_PATTERN + } + } catch (e: Exception) { + Timber.e(e, "Error while getting date format for locale") + FALLBACK_DATE_PATTERN + } + } +} \ No newline at end of file diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/collection/DateProviderImpl.kt b/device/src/main/java/com/anytypeio/anytype/device/providers/DateProviderImpl.kt similarity index 95% rename from presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/collection/DateProviderImpl.kt rename to device/src/main/java/com/anytypeio/anytype/device/providers/DateProviderImpl.kt index f088125a00..4937837884 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/widgets/collection/DateProviderImpl.kt +++ b/device/src/main/java/com/anytypeio/anytype/device/providers/DateProviderImpl.kt @@ -1,10 +1,11 @@ -package com.anytypeio.anytype.presentation.widgets.collection +package com.anytypeio.anytype.device.providers import android.text.format.DateUtils import com.anytypeio.anytype.core_models.TimeInMillis import com.anytypeio.anytype.core_models.TimeInSeconds import com.anytypeio.anytype.domain.misc.DateProvider import com.anytypeio.anytype.domain.misc.DateType +import com.anytypeio.anytype.domain.misc.LocaleProvider import java.text.DateFormat import java.text.SimpleDateFormat import java.time.Instant @@ -14,12 +15,12 @@ import java.time.ZoneId import java.time.ZoneOffset import java.time.temporal.ChronoUnit import java.util.Date -import java.util.Locale import javax.inject.Inject import timber.log.Timber class DateProviderImpl @Inject constructor( - private val defaultZoneId: ZoneId + private val defaultZoneId: ZoneId, + private val localeProvider: LocaleProvider ) : DateProvider { override fun calculateDateType(date: TimeInSeconds): DateType { @@ -132,8 +133,9 @@ class DateProviderImpl @Inject constructor( } } - override fun formatToDateString(timestamp: Long, pattern: String, locale: Locale): String { + override fun formatToDateString(timestamp: Long, pattern: String): String { try { + val locale = localeProvider.locale() val formatter = SimpleDateFormat(pattern, locale) return formatter.format(Date(timestamp)) } catch (e: Exception) { @@ -144,11 +146,11 @@ class DateProviderImpl @Inject constructor( override fun formatTimestampToDateAndTime( timestamp: TimeInMillis, - locale: Locale, dateStyle: Int, timeStyle: Int ): Pair { return try { + val locale = localeProvider.locale() val datePattern = (DateFormat.getDateInstance(dateStyle, locale) as SimpleDateFormat).toPattern() val timePattern = (DateFormat.getTimeInstance(timeStyle, locale) as SimpleDateFormat).toPattern() val dateFormatter = SimpleDateFormat(datePattern, locale) diff --git a/device/src/main/java/com/anytypeio/anytype/device/DefaultLocalProvider.kt b/device/src/main/java/com/anytypeio/anytype/device/providers/DefaultLocalProvider.kt similarity index 91% rename from device/src/main/java/com/anytypeio/anytype/device/DefaultLocalProvider.kt rename to device/src/main/java/com/anytypeio/anytype/device/providers/DefaultLocalProvider.kt index bb60ae5842..90b952056a 100644 --- a/device/src/main/java/com/anytypeio/anytype/device/DefaultLocalProvider.kt +++ b/device/src/main/java/com/anytypeio/anytype/device/providers/DefaultLocalProvider.kt @@ -1,4 +1,4 @@ -package com.anytypeio.anytype.device +package com.anytypeio.anytype.device.providers import android.content.Context import androidx.core.os.ConfigurationCompat diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/widgets/collection/DateProviderImplTest.kt b/device/src/test/java/com/anytypeio/anytype/DateProviderImplTest.kt similarity index 92% rename from presentation/src/test/java/com/anytypeio/anytype/presentation/widgets/collection/DateProviderImplTest.kt rename to device/src/test/java/com/anytypeio/anytype/DateProviderImplTest.kt index 5048e37469..ddd6457ed5 100644 --- a/presentation/src/test/java/com/anytypeio/anytype/presentation/widgets/collection/DateProviderImplTest.kt +++ b/device/src/test/java/com/anytypeio/anytype/DateProviderImplTest.kt @@ -1,13 +1,30 @@ -package com.anytypeio.anytype.presentation.widgets.collection +package com.anytypeio.anytype +import com.anytypeio.anytype.device.providers.DateProviderImpl +import com.anytypeio.anytype.domain.misc.DateProvider +import com.anytypeio.anytype.domain.misc.LocaleProvider import java.time.ZoneId +import java.util.Locale import org.junit.Assert.* - +import org.junit.Before import org.junit.Test +import org.mockito.Mock +import org.mockito.Mockito +import org.mockito.MockitoAnnotations class DateProviderImplTest { - val dateProviderImpl = DateProviderImpl(ZoneId.systemDefault()) + @Mock + lateinit var localeProvider: LocaleProvider + + lateinit var dateProviderImpl: DateProvider + + @Before + fun setUp() { + MockitoAnnotations.openMocks(this) + dateProviderImpl = DateProviderImpl(ZoneId.systemDefault(), localeProvider) + Mockito.`when`(localeProvider.locale()).thenReturn(Locale.getDefault()) + } @Test fun adjustToStartOfDayInUserTimeZoneWithPastStart() { diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/config/UserSettingsRepository.kt b/domain/src/main/java/com/anytypeio/anytype/domain/config/UserSettingsRepository.kt index d7a5d4f3ce..bbf6708220 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/config/UserSettingsRepository.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/config/UserSettingsRepository.kt @@ -50,4 +50,7 @@ interface UserSettingsRepository { suspend fun setAllContentSort(space: SpaceId, sort: Id, isAsc: Boolean) suspend fun clear() + + suspend fun setRelativeDates(account: Account, enabled: Boolean) + suspend fun setDateFormat(account: Account, format: String) } \ No newline at end of file diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/misc/DateProvider.kt b/domain/src/main/java/com/anytypeio/anytype/domain/misc/DateProvider.kt index 4b92ce837c..239401a049 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/misc/DateProvider.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/misc/DateProvider.kt @@ -4,7 +4,6 @@ import com.anytypeio.anytype.core_models.TimeInMillis import com.anytypeio.anytype.core_models.TimeInSeconds import java.text.DateFormat import java.time.ZoneId -import java.util.Locale /** @@ -21,10 +20,9 @@ interface DateProvider { fun getTimestampForWeekAgoAtStartOfDay(): TimeInSeconds fun adjustToStartOfDayInUserTimeZone(timestamp: TimeInSeconds): TimeInMillis fun adjustFromStartOfDayInUserTimeZoneToUTC(timestamp: TimeInMillis, zoneId: ZoneId): TimeInSeconds - fun formatToDateString(timestamp: Long, pattern: String, locale: Locale): String + fun formatToDateString(timestamp: Long, pattern: String): String fun formatTimestampToDateAndTime( timestamp: TimeInMillis, - locale: Locale, dateStyle: Int = DateFormat.MEDIUM, timeStyle: Int = DateFormat.SHORT ): Pair diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/vault/ObserveVaultSettings.kt b/domain/src/main/java/com/anytypeio/anytype/domain/vault/ObserveVaultSettings.kt index c029bb19b2..96c1e5c185 100644 --- a/domain/src/main/java/com/anytypeio/anytype/domain/vault/ObserveVaultSettings.kt +++ b/domain/src/main/java/com/anytypeio/anytype/domain/vault/ObserveVaultSettings.kt @@ -1,5 +1,7 @@ package com.anytypeio.anytype.domain.vault +import com.anytypeio.anytype.core_models.FALLBACK_DATE_PATTERN +import com.anytypeio.anytype.core_models.DEFAULT_RELATIVE_DATES import com.anytypeio.anytype.core_models.settings.VaultSettings import com.anytypeio.anytype.domain.auth.repo.AuthRepository import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers @@ -7,7 +9,6 @@ import com.anytypeio.anytype.domain.base.FlowInteractor import com.anytypeio.anytype.domain.config.UserSettingsRepository import com.anytypeio.anytype.domain.debugging.Logger import javax.inject.Inject -import kotlin.math.log import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.emitAll @@ -29,7 +30,9 @@ class ObserveVaultSettings @Inject constructor( emit( VaultSettings( showIntroduceVault = false, - orderOfSpaces = emptyList() + orderOfSpaces = emptyList(), + isRelativeDates = DEFAULT_RELATIVE_DATES, + dateFormat = FALLBACK_DATE_PATTERN ) ) } diff --git a/payments/src/test/java/com/anytypeio/anytype/payments/provider/MembershipProviderTest.kt b/payments/src/test/java/com/anytypeio/anytype/payments/provider/MembershipProviderTest.kt index 73ebddef64..e028597387 100644 --- a/payments/src/test/java/com/anytypeio/anytype/payments/provider/MembershipProviderTest.kt +++ b/payments/src/test/java/com/anytypeio/anytype/payments/provider/MembershipProviderTest.kt @@ -98,8 +98,7 @@ class MembershipProviderTest { whenever( dateProvider.formatToDateString( dateEnds, - DATE_FORMAT, - localeProvider.locale() + DATE_FORMAT ) ).thenReturn("01-01-1970") val command = Command.Membership.GetTiers( diff --git a/persistence/build.gradle b/persistence/build.gradle index 04acbb76b7..d950695cc8 100644 --- a/persistence/build.gradle +++ b/persistence/build.gradle @@ -10,6 +10,7 @@ dependencies { implementation project(':data') implementation project(':core-models') + implementation project(':device') implementation libs.kotlin implementation libs.coroutinesAndroid diff --git a/persistence/src/main/java/com/anytypeio/anytype/persistence/repo/DefaultUserSettingsCache.kt b/persistence/src/main/java/com/anytypeio/anytype/persistence/repo/DefaultUserSettingsCache.kt index d7a73e594a..c2ff6612a8 100644 --- a/persistence/src/main/java/com/anytypeio/anytype/persistence/repo/DefaultUserSettingsCache.kt +++ b/persistence/src/main/java/com/anytypeio/anytype/persistence/repo/DefaultUserSettingsCache.kt @@ -5,6 +5,8 @@ import android.content.SharedPreferences import androidx.datastore.core.DataStore import androidx.datastore.dataStore import com.anytypeio.anytype.core_models.Account +import com.anytypeio.anytype.core_models.DEFAULT_RELATIVE_DATES +import com.anytypeio.anytype.core_models.DEFAULT_SHOW_INTRODUCE_VAULT import com.anytypeio.anytype.core_models.GlobalSearchHistory import com.anytypeio.anytype.core_models.Id import com.anytypeio.anytype.core_models.NO_VALUE @@ -15,6 +17,7 @@ import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.core_models.primitives.TypeId import com.anytypeio.anytype.core_models.settings.VaultSettings import com.anytypeio.anytype.data.auth.repo.UserSettingsCache +import com.anytypeio.anytype.device.providers.AppDefaultDateFormatProvider import com.anytypeio.anytype.persistence.AllContentSettings import com.anytypeio.anytype.persistence.GlobalSearchHistoryProto import com.anytypeio.anytype.persistence.SpacePreference @@ -38,9 +41,20 @@ import kotlinx.coroutines.flow.map class DefaultUserSettingsCache( private val prefs: SharedPreferences, - private val context: Context + private val context: Context, + private val appDefaultDateFormatProvider: AppDefaultDateFormatProvider ) : UserSettingsCache { + //region Vault default settings + fun initialVaultSettings(): VaultPreference { + return VaultPreference( + showIntroduceVault = DEFAULT_SHOW_INTRODUCE_VAULT, + isRelativeDates = DEFAULT_RELATIVE_DATES, + dateFormat = appDefaultDateFormatProvider.provide() + ) + } + //endregion + private val Context.spacePrefsStore: DataStore by dataStore( fileName = SPACE_PREFERENCE_FILENAME, serializer = SpacePrefSerializer @@ -398,13 +412,13 @@ class DefaultUserSettingsCache( .map { prefs -> val curr = prefs.preferences.getOrDefault( key = account.id, - defaultValue = VaultPreference( - showIntroduceVault = true - ) + defaultValue = initialVaultSettings() ) VaultSettings( orderOfSpaces = curr.orderOfSpaces, - showIntroduceVault = curr.showIntroduceVault + showIntroduceVault = curr.showIntroduceVault, + isRelativeDates = curr.isRelativeDates, + dateFormat = curr.dateFormat ?: appDefaultDateFormatProvider.provide() ) } .first() @@ -416,13 +430,13 @@ class DefaultUserSettingsCache( .map { prefs -> val curr = prefs.preferences.getOrDefault( key = account.id, - defaultValue = VaultPreference( - showIntroduceVault = true - ) + defaultValue = initialVaultSettings() ) VaultSettings( orderOfSpaces = curr.orderOfSpaces, - showIntroduceVault = curr.showIntroduceVault + showIntroduceVault = curr.showIntroduceVault, + isRelativeDates = curr.isRelativeDates, + dateFormat = curr.dateFormat ?: appDefaultDateFormatProvider.provide() ) } } @@ -431,9 +445,7 @@ class DefaultUserSettingsCache( context.vaultPrefsStore.updateData { existingPreferences -> val curr = existingPreferences.preferences.getOrDefault( key = account.id, - defaultValue = VaultPreference( - showIntroduceVault = true - ) + defaultValue = initialVaultSettings() ) existingPreferences.copy( preferences = existingPreferences.preferences + mapOf( @@ -458,6 +470,41 @@ class DefaultUserSettingsCache( } } + override suspend fun setRelativeDates(account: Account, enabled: Boolean) { + context.vaultPrefsStore.updateData { existingPreferences -> + val curr = existingPreferences.preferences.getOrDefault( + key = account.id, + defaultValue = initialVaultSettings() + ) + existingPreferences.copy( + preferences = existingPreferences.preferences + mapOf( + account.id to curr.copy( + isRelativeDates = enabled + ) + ) + ) + } + } + + override suspend fun setDateFormat( + account: Account, + format: String + ) { + context.vaultPrefsStore.updateData { existingPreferences -> + val curr = existingPreferences.preferences.getOrDefault( + key = account.id, + defaultValue = initialVaultSettings() + ) + existingPreferences.copy( + preferences = existingPreferences.preferences + mapOf( + account.id to curr.copy( + dateFormat = format + ) + ) + ) + } + } + override suspend fun getAllContentSort(space: SpaceId): Pair? { val flow = context.spacePrefsStore.data val first = flow.first() diff --git a/persistence/src/main/proto/preferences.proto b/persistence/src/main/proto/preferences.proto index 5c896b7576..ec28c517a8 100644 --- a/persistence/src/main/proto/preferences.proto +++ b/persistence/src/main/proto/preferences.proto @@ -16,6 +16,8 @@ message VaultPreferences { message VaultPreference { repeated string orderOfSpaces = 1; bool showIntroduceVault = 2; + bool isRelativeDates = 3; + optional string dateFormat = 4; } message SpacePreference { diff --git a/persistence/src/test/java/com/anytypeio/anytype/persistence/UserSettingsCacheTest.kt b/persistence/src/test/java/com/anytypeio/anytype/persistence/UserSettingsCacheTest.kt index 4048a499be..82c7772d27 100644 --- a/persistence/src/test/java/com/anytypeio/anytype/persistence/UserSettingsCacheTest.kt +++ b/persistence/src/test/java/com/anytypeio/anytype/persistence/UserSettingsCacheTest.kt @@ -3,17 +3,27 @@ package com.anytypeio.anytype.persistence import android.content.Context import androidx.arch.core.executor.testing.InstantTaskExecutorRule import androidx.test.core.app.ApplicationProvider +import com.anytypeio.anytype.core_models.Account +import com.anytypeio.anytype.core_models.DEFAULT_RELATIVE_DATES +import com.anytypeio.anytype.core_models.DEFAULT_SHOW_INTRODUCE_VAULT import com.anytypeio.anytype.core_models.GlobalSearchHistory import com.anytypeio.anytype.core_models.Wallpaper import com.anytypeio.anytype.core_models.primitives.SpaceId import com.anytypeio.anytype.core_models.primitives.TypeId +import com.anytypeio.anytype.core_models.settings.VaultSettings +import com.anytypeio.anytype.device.providers.AppDefaultDateFormatProvider import com.anytypeio.anytype.persistence.repo.DefaultUserSettingsCache import com.anytypeio.anytype.test_utils.MockDataFactory import kotlin.test.assertEquals import kotlinx.coroutines.test.runTest +import net.bytebuddy.utility.RandomString +import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito +import org.mockito.MockitoAnnotations import org.robolectric.RobolectricTestRunner import org.robolectric.RuntimeEnvironment import org.robolectric.annotation.Config @@ -30,12 +40,21 @@ class UserSettingsCacheTest { Context.MODE_PRIVATE ) + @Mock + lateinit var dateFormatProvider: AppDefaultDateFormatProvider + + @Before + fun setUp() { + MockitoAnnotations.openMocks(this) + } + @Test fun `should save and return default wallpaper`() = runTest { val cache = DefaultUserSettingsCache( prefs = defaultPrefs, - context = ApplicationProvider.getApplicationContext() + context = ApplicationProvider.getApplicationContext(), + appDefaultDateFormatProvider = dateFormatProvider ) val space = MockDataFactory.randomUuid() @@ -59,7 +78,8 @@ class UserSettingsCacheTest { val cache = DefaultUserSettingsCache( prefs = defaultPrefs, - context = ApplicationProvider.getApplicationContext() + context = ApplicationProvider.getApplicationContext(), + appDefaultDateFormatProvider = dateFormatProvider ) val space = MockDataFactory.randomUuid() @@ -86,7 +106,8 @@ class UserSettingsCacheTest { val cache = DefaultUserSettingsCache( prefs = defaultPrefs, - context = ApplicationProvider.getApplicationContext() + context = ApplicationProvider.getApplicationContext(), + appDefaultDateFormatProvider = dateFormatProvider ) val space = "" @@ -114,7 +135,8 @@ class UserSettingsCacheTest { val cache = DefaultUserSettingsCache( prefs = defaultPrefs, - context = ApplicationProvider.getApplicationContext() + context = ApplicationProvider.getApplicationContext(), + appDefaultDateFormatProvider = dateFormatProvider ) val space = MockDataFactory.randomUuid() @@ -141,7 +163,8 @@ class UserSettingsCacheTest { val cache = DefaultUserSettingsCache( prefs = defaultPrefs, - context = ApplicationProvider.getApplicationContext() + context = ApplicationProvider.getApplicationContext(), + appDefaultDateFormatProvider = dateFormatProvider ) val space = MockDataFactory.randomUuid() @@ -168,7 +191,8 @@ class UserSettingsCacheTest { val cache = DefaultUserSettingsCache( prefs = defaultPrefs, - context = ApplicationProvider.getApplicationContext() + context = ApplicationProvider.getApplicationContext(), + appDefaultDateFormatProvider = dateFormatProvider ) val space = MockDataFactory.randomUuid() @@ -187,7 +211,8 @@ class UserSettingsCacheTest { val cache = DefaultUserSettingsCache( prefs = defaultPrefs, - context = ApplicationProvider.getApplicationContext() + context = ApplicationProvider.getApplicationContext(), + appDefaultDateFormatProvider = dateFormatProvider ) val space = SpaceId(MockDataFactory.randomUuid()) @@ -220,7 +245,8 @@ class UserSettingsCacheTest { val cache = DefaultUserSettingsCache( prefs = defaultPrefs, - context = ApplicationProvider.getApplicationContext() + context = ApplicationProvider.getApplicationContext(), + appDefaultDateFormatProvider = dateFormatProvider ) val space1 = SpaceId(MockDataFactory.randomUuid()) @@ -277,7 +303,8 @@ class UserSettingsCacheTest { val cache = DefaultUserSettingsCache( prefs = defaultPrefs, - context = ApplicationProvider.getApplicationContext() + context = ApplicationProvider.getApplicationContext(), + appDefaultDateFormatProvider = dateFormatProvider ) val space = SpaceId(MockDataFactory.randomUuid()) @@ -314,4 +341,150 @@ class UserSettingsCacheTest { actual = cache.getGlobalSearchHistory(space) ) } + + @Test + fun `should return default vault settings with default params`() = runTest { + + val cache = DefaultUserSettingsCache( + prefs = defaultPrefs, + context = ApplicationProvider.getApplicationContext(), + appDefaultDateFormatProvider = dateFormatProvider + ) + + val dateFormat = "MM/dd/yyyy - ${RandomString.make()}" + + Mockito.`when`(dateFormatProvider.provide()).thenReturn(dateFormat) + + val account = Account( + id = MockDataFactory.randomUuid(), + ) + + val vaultSettings = cache.getVaultSettings(account = account) + + val expected = VaultSettings( + showIntroduceVault = DEFAULT_SHOW_INTRODUCE_VAULT, + dateFormat = dateFormat, + isRelativeDates = DEFAULT_RELATIVE_DATES + ) + + assertEquals( + expected = expected, + actual = vaultSettings + ) + } + + @Test + fun `should return updated vault date format settings`() = runTest { + + val cache = DefaultUserSettingsCache( + prefs = defaultPrefs, + context = ApplicationProvider.getApplicationContext(), + appDefaultDateFormatProvider = dateFormatProvider + ) + + val dateFormat = "MM/dd/yyyy - ${RandomString.make()}" + val updatedDateFormat = "yyyy-MM-dd - ${RandomString.make()}" + + Mockito.`when`(dateFormatProvider.provide()).thenReturn(dateFormat) + + val account = Account( + id = MockDataFactory.randomUuid(), + ) + + cache.setDateFormat( + account = account, + format = updatedDateFormat + ) + + val vaultSettings = cache.getVaultSettings(account = account) + + val expected = VaultSettings( + showIntroduceVault = DEFAULT_SHOW_INTRODUCE_VAULT, + dateFormat = updatedDateFormat, + isRelativeDates = DEFAULT_RELATIVE_DATES + ) + + assertEquals( + expected = expected, + actual = vaultSettings + ) + } + + @Test + fun `should return updated vault relative dates settings`() = runTest { + + val cache = DefaultUserSettingsCache( + prefs = defaultPrefs, + context = ApplicationProvider.getApplicationContext(), + appDefaultDateFormatProvider = dateFormatProvider + ) + + val dateFormat = "MM/dd/yyyy - ${RandomString.make()}" + + Mockito.`when`(dateFormatProvider.provide()).thenReturn(dateFormat) + + val account = Account( + id = MockDataFactory.randomUuid(), + ) + + cache.setRelativeDates( + account = account, + enabled = false + ) + + val vaultSettings = cache.getVaultSettings(account = account) + + val expected = VaultSettings( + showIntroduceVault = DEFAULT_SHOW_INTRODUCE_VAULT, + dateFormat = dateFormat, + isRelativeDates = false + ) + + assertEquals( + expected = expected, + actual = vaultSettings + ) + } + + @Test + fun `should return updated vault relative dates settings and keep date format settings`() = runTest { + + val cache = DefaultUserSettingsCache( + prefs = defaultPrefs, + context = ApplicationProvider.getApplicationContext(), + appDefaultDateFormatProvider = dateFormatProvider + ) + + val dateFormat = "MM/dd/yyyy - ${RandomString.make()}" + val updatedDateFormat = "yyyy-MM-dd - ${RandomString.make()}" + + Mockito.`when`(dateFormatProvider.provide()).thenReturn(dateFormat) + + val account = Account( + id = MockDataFactory.randomUuid(), + ) + + cache.setDateFormat( + account = account, + format = updatedDateFormat + ) + + cache.setRelativeDates( + account = account, + enabled = false + ) + + val vaultSettings = cache.getVaultSettings(account = account) + + val expected = VaultSettings( + showIntroduceVault = DEFAULT_SHOW_INTRODUCE_VAULT, + dateFormat = updatedDateFormat, + isRelativeDates = false + ) + + assertEquals( + expected = expected, + actual = vaultSettings + ) + } } \ No newline at end of file diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/history/VersionHistoryVMFactory.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/history/VersionHistoryVMFactory.kt index bd5b184738..85183ff058 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/history/VersionHistoryVMFactory.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/history/VersionHistoryVMFactory.kt @@ -7,11 +7,9 @@ import com.anytypeio.anytype.domain.history.GetVersions import com.anytypeio.anytype.domain.history.SetVersion import com.anytypeio.anytype.domain.history.ShowVersion import com.anytypeio.anytype.domain.misc.DateProvider -import com.anytypeio.anytype.domain.misc.LocaleProvider import com.anytypeio.anytype.domain.misc.UrlBuilder import com.anytypeio.anytype.domain.objects.StoreOfRelations import com.anytypeio.anytype.domain.search.SearchObjects -import com.anytypeio.anytype.presentation.editor.cover.CoverImageHashProvider import com.anytypeio.anytype.presentation.editor.render.DefaultBlockViewRenderer import com.anytypeio.anytype.presentation.history.VersionHistoryViewModel.VmParams import com.anytypeio.anytype.presentation.sets.state.ObjectStateReducer @@ -22,14 +20,12 @@ class VersionHistoryVMFactory @Inject constructor( private val getVersions: GetVersions, private val objectSearch: SearchObjects, private val dateProvider: DateProvider, - private val localeProvider: LocaleProvider, private val analytics: Analytics, private val urlBuilder: UrlBuilder, private val showVersion: ShowVersion, private val setVersion: SetVersion, private val renderer: DefaultBlockViewRenderer, private val setStateReducer: ObjectStateReducer, - private val coverImageHashProvider: CoverImageHashProvider, private val storeOfRelations: StoreOfRelations ) : ViewModelProvider.Factory { @@ -40,14 +36,12 @@ class VersionHistoryVMFactory @Inject constructor( getVersions = getVersions, objectSearch = objectSearch, dateProvider = dateProvider, - localeProvider = localeProvider, analytics = analytics, urlBuilder = urlBuilder, showVersion = showVersion, renderer = renderer, setVersion = setVersion, setStateReducer = setStateReducer, - coverImageHashProvider = coverImageHashProvider, storeOfRelations = storeOfRelations ) as T } diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/history/VersionHistoryViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/history/VersionHistoryViewModel.kt index 0e0c04f682..b54b1da75d 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/history/VersionHistoryViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/history/VersionHistoryViewModel.kt @@ -21,7 +21,6 @@ import com.anytypeio.anytype.domain.history.GetVersions import com.anytypeio.anytype.domain.history.SetVersion import com.anytypeio.anytype.domain.history.ShowVersion import com.anytypeio.anytype.domain.misc.DateProvider -import com.anytypeio.anytype.domain.misc.LocaleProvider import com.anytypeio.anytype.domain.misc.UrlBuilder import com.anytypeio.anytype.domain.objects.StoreOfRelations import com.anytypeio.anytype.domain.search.SearchObjects @@ -39,7 +38,6 @@ import com.anytypeio.anytype.presentation.history.VersionHistoryGroup.GroupTitle import com.anytypeio.anytype.presentation.mapper.objectIcon import com.anytypeio.anytype.presentation.mapper.toViewerColumns import com.anytypeio.anytype.presentation.objects.ObjectIcon -import com.anytypeio.anytype.presentation.profile.profileIcon import com.anytypeio.anytype.presentation.relations.ObjectSetConfig import com.anytypeio.anytype.presentation.relations.getRelationFormat import com.anytypeio.anytype.presentation.search.ObjectSearchConstants @@ -50,7 +48,6 @@ import com.anytypeio.anytype.presentation.sets.viewerByIdOrFirst import java.time.Instant import java.time.LocalDate import java.time.ZoneId -import java.util.Locale import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow @@ -67,13 +64,11 @@ class VersionHistoryViewModel( private val getVersions: GetVersions, private val objectSearch: SearchObjects, private val dateProvider: DateProvider, - private val localeProvider: LocaleProvider, private val urlBuilder: UrlBuilder, private val showVersion: ShowVersion, private val setVersion: SetVersion, private val renderer: DefaultBlockViewRenderer, private val setStateReducer: ObjectStateReducer, - private val coverImageHashProvider: CoverImageHashProvider, private val storeOfRelations: StoreOfRelations ) : ViewModel(), BlockViewRenderer by renderer { @@ -326,16 +321,13 @@ class VersionHistoryViewModel( spaceMembers: List, ): List { - val locale = localeProvider.locale() - // Sort versions by timestamp (DESC) and group by day val versionsByDay = versions .sortedByDescending { it.timestamp.time } .groupBy { version -> val formattedDate = dateProvider.formatToDateString( timestamp = (version.timestamp.inMillis), - pattern = GROUP_BY_DAY_FORMAT, - locale = locale + pattern = GROUP_BY_DAY_FORMAT ) formattedDate } @@ -361,13 +353,12 @@ class VersionHistoryViewModel( spaceMemberVersions.lastOrNull()?.lastOrNull() ?: return@mapNotNull null val groupItems = spaceMemberVersions.toGroupItems( - spaceMembers = spaceMembers, - locale = locale + spaceMembers = spaceMembers ) VersionHistoryGroup( id = spaceMemberOldestVersion.id, - title = getGroupTitle(spaceMemberLatestVersion.timestamp, locale), + title = getGroupTitle(spaceMemberLatestVersion.timestamp), icons = groupItems.distinctBy { it.spaceMember }.mapNotNull { it.icon }, items = groupItems ) @@ -428,7 +419,7 @@ class VersionHistoryViewModel( return groupedBySpaceMember } - private fun getGroupTitle(timestamp: TimeInSeconds, locale: Locale): GroupTitle { + private fun getGroupTitle(timestamp: TimeInSeconds): GroupTitle { val dateInstant = Instant.ofEpochSecond(timestamp.time) val givenDate = dateInstant.atZone(ZoneId.systemDefault()).toLocalDate() val currentDate = LocalDate.now() @@ -453,8 +444,7 @@ class VersionHistoryViewModel( GroupTitle.Date( dateProvider.formatToDateString( timestamp = timestamp.inMillis, - pattern = pattern, - locale = locale + pattern = pattern ) ) } @@ -462,8 +452,7 @@ class VersionHistoryViewModel( } private fun List>.toGroupItems( - spaceMembers: List, - locale: Locale + spaceMembers: List ): List { return mapNotNull { versions -> val latestVersion = versions.firstOrNull() ?: return@mapNotNull null @@ -474,8 +463,7 @@ class VersionHistoryViewModel( val icon = spaceMember.objectIcon(urlBuilder) val (latestVersionDate, latestVersionTime) = dateProvider.formatTimestampToDateAndTime( - timestamp = latestVersion.timestamp.inMillis, - locale = locale + timestamp = latestVersion.timestamp.inMillis ) VersionHistoryGroup.Item( diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/membership/provider/MembershipProvider.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/membership/provider/MembershipProvider.kt index 803ebeb649..9ab0a2d13d 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/membership/provider/MembershipProvider.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/membership/provider/MembershipProvider.kt @@ -117,8 +117,7 @@ interface MembershipProvider { ): MembershipStatus { val formattedDateEnds = dateProvider.formatToDateString( timestamp = membership.dateEnds, - pattern = DATE_FORMAT, - locale = localeProvider.locale() + pattern = DATE_FORMAT ) return MembershipStatus( activeTier = TierId(membership.tier), diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/collections/CollectionCreateAndAddObjectTest.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/collections/CollectionCreateAndAddObjectTest.kt index 7c82093b25..fde16a6380 100644 --- a/presentation/src/test/java/com/anytypeio/anytype/presentation/collections/CollectionCreateAndAddObjectTest.kt +++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/collections/CollectionCreateAndAddObjectTest.kt @@ -39,9 +39,6 @@ class CollectionCreateAndAddObjectTest: ObjectSetViewModelTestSetup() { private lateinit var viewModel: ObjectSetViewModel private lateinit var mockObjectCollection: MockCollection - @Mock - lateinit var dateProvider: DateProvider - @get:Rule val timberTestRule: TimberTestRule = TimberTestRule.builder() .minPriority(Log.DEBUG) diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/history/VersionHistoryViewModelTest.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/history/VersionHistoryViewModelTest.kt index 866cc78e7d..7b3cff5447 100644 --- a/presentation/src/test/java/com/anytypeio/anytype/presentation/history/VersionHistoryViewModelTest.kt +++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/history/VersionHistoryViewModelTest.kt @@ -27,7 +27,6 @@ import com.anytypeio.anytype.presentation.history.VersionHistoryViewModel.Compan import com.anytypeio.anytype.presentation.objects.ObjectIcon import com.anytypeio.anytype.presentation.search.ObjectSearchConstants import com.anytypeio.anytype.presentation.sets.state.DefaultObjectStateReducer -import com.anytypeio.anytype.presentation.widgets.collection.DateProviderImpl import java.time.ZoneId import java.util.Locale import kotlin.test.assertEquals @@ -40,7 +39,6 @@ import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.setMain import net.bytebuddy.utility.RandomString import org.junit.Before -import org.junit.Test import org.mockito.Mock import org.mockito.MockedStatic import org.mockito.Mockito @@ -85,7 +83,8 @@ class VersionHistoryViewModelTest { @Mock lateinit var objectSearch: SearchObjects - private val dateProvider: DateProvider = DateProviderImpl(ZoneId.systemDefault()) + @Mock + lateinit var dateProvider: DateProvider @Mock lateinit var localeProvider: LocaleProvider @@ -290,27 +289,26 @@ class VersionHistoryViewModelTest { val (date0, time0) = dateProvider.formatTimestampToDateAndTime( timestamp = versions[0].timestamp.inMillis, - locale = locale ) val (date1, time1) = dateProvider.formatTimestampToDateAndTime( timestamp = versions[1].timestamp.inMillis, - locale = locale + ) val (date2, time2) = dateProvider.formatTimestampToDateAndTime( timestamp = versions[2].timestamp.inMillis, - locale = locale + ) val (date3, time3) = dateProvider.formatTimestampToDateAndTime( timestamp = versions[3].timestamp.inMillis, - locale = locale + ) val (date4, time4) = dateProvider.formatTimestampToDateAndTime( timestamp = versions[4].timestamp.inMillis, - locale = locale + ) val (date6, time6) = dateProvider.formatTimestampToDateAndTime( timestamp = versions[6].timestamp.inMillis, - locale = locale + ) val viewStateFlow = vm.viewState.testIn(backgroundScope) @@ -325,7 +323,6 @@ class VersionHistoryViewModelTest { title = VersionHistoryGroup.GroupTitle.Date( dateProvider.formatToDateString( timestamp = versionsNew[8].timestamp.inMillis, - locale = locale, pattern = GROUP_DATE_FORMAT_OTHER_YEAR ) ), @@ -334,7 +331,7 @@ class VersionHistoryViewModelTest { items = buildList { val versionsNew8Format = dateProvider.formatTimestampToDateAndTime( timestamp = versionsNew[8].timestamp.inMillis, - locale = locale + ) add( VersionHistoryGroup.Item( @@ -350,7 +347,6 @@ class VersionHistoryViewModelTest { ) val versionsNew7Format = dateProvider.formatTimestampToDateAndTime( timestamp = versionsNew[7].timestamp.inMillis, - locale = locale ) add( VersionHistoryGroup.Item( @@ -366,7 +362,6 @@ class VersionHistoryViewModelTest { ) val versionsNew6Format = dateProvider.formatTimestampToDateAndTime( timestamp = versionsNew[6].timestamp.inMillis, - locale = locale ) add( VersionHistoryGroup.Item( @@ -382,7 +377,6 @@ class VersionHistoryViewModelTest { ) val versionsNew4Format = dateProvider.formatTimestampToDateAndTime( timestamp = versionsNew[4].timestamp.inMillis, - locale = locale ) add( VersionHistoryGroup.Item( @@ -406,7 +400,6 @@ class VersionHistoryViewModelTest { title = VersionHistoryGroup.GroupTitle.Date(dateProvider.formatToDateString( timestamp = versions[0].timestamp.inMillis, pattern = GROUP_DATE_FORMAT_OTHER_YEAR, - locale = locale )), icons = listOf(ObjectIcon.None, ObjectIcon.None, ObjectIcon.None), items = buildList { @@ -467,7 +460,6 @@ class VersionHistoryViewModelTest { title = VersionHistoryGroup.GroupTitle.Date( dateProvider.formatToDateString( timestamp = versions[4].timestamp.inMillis, - locale = locale, pattern = GROUP_DATE_FORMAT_OTHER_YEAR ) ), @@ -546,7 +538,6 @@ class VersionHistoryViewModelTest { getVersions = getVersions, objectSearch = objectSearch, dateProvider = dateProvider, - localeProvider = localeProvider, vmParams = vmParams, urlBuilder = urlBuilder, renderer = renderer, @@ -554,7 +545,6 @@ class VersionHistoryViewModelTest { showVersion = showVersion, setStateReducer = DefaultObjectStateReducer(), storeOfRelations = storeOfRelations, - coverImageHashProvider = coverImageHashProvider ) } } \ No newline at end of file diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/objects/CreateDVObjectTest.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/objects/CreateDVObjectTest.kt index 18d6bfb59d..5121511b58 100644 --- a/presentation/src/test/java/com/anytypeio/anytype/presentation/objects/CreateDVObjectTest.kt +++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/objects/CreateDVObjectTest.kt @@ -15,7 +15,6 @@ import com.anytypeio.anytype.core_models.StubRelationObject import com.anytypeio.anytype.core_models.ext.DAYS_IN_MONTH import com.anytypeio.anytype.core_models.ext.DAYS_IN_WEEK import com.anytypeio.anytype.core_models.ext.SECONDS_IN_DAY -import com.anytypeio.anytype.domain.misc.DateProvider import com.anytypeio.anytype.presentation.sets.main.ObjectSetViewModelTestSetup import com.anytypeio.anytype.presentation.sets.prefillNewObjectDetails import com.anytypeio.anytype.presentation.sets.resolveSetByRelationPrefilledObjectData @@ -28,7 +27,6 @@ import net.bytebuddy.utility.RandomString import org.junit.Before import org.junit.Rule import org.junit.Test -import org.mockito.Mock import org.mockito.kotlin.doReturn import org.mockito.kotlin.mock import org.mockito.kotlin.stub @@ -36,9 +34,6 @@ import org.mockito.kotlin.stub @OptIn(ExperimentalCoroutinesApi::class) class CreateDVObjectTest : ObjectSetViewModelTestSetup() { - @Mock - lateinit var dateProvider: DateProvider - private val timestamp = 1703775402L private val spaceId = "spaceId-${MockDataFactory.randomString()}" private val filterDate = StubRelationObject( @@ -54,6 +49,7 @@ class CreateDVObjectTest : ObjectSetViewModelTestSetup() { @Before fun setup() = runTest { + //MockitoAnnotations.openMocks(this) dateProvider = mock(verboseLogging = true) storeOfRelations.merge(listOf(filterDate)) dateProvider.stub { diff --git a/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetViewModelTestSetup.kt b/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetViewModelTestSetup.kt index d1d0ba9281..739d907071 100644 --- a/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetViewModelTestSetup.kt +++ b/presentation/src/test/java/com/anytypeio/anytype/presentation/sets/main/ObjectSetViewModelTestSetup.kt @@ -39,6 +39,8 @@ import com.anytypeio.anytype.domain.event.interactor.SpaceSyncAndP2PStatusProvid import com.anytypeio.anytype.domain.launch.GetDefaultObjectType import com.anytypeio.anytype.domain.library.StoreSearchByIdsParams import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer +import com.anytypeio.anytype.domain.misc.DateProvider +import com.anytypeio.anytype.domain.misc.LocaleProvider import com.anytypeio.anytype.domain.misc.UrlBuilder import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider import com.anytypeio.anytype.domain.networkmode.GetNetworkMode @@ -84,9 +86,8 @@ import com.anytypeio.anytype.presentation.sets.viewer.ViewerDelegate import com.anytypeio.anytype.presentation.templates.ObjectTypeTemplatesContainer import com.anytypeio.anytype.presentation.util.DefaultCoroutineTestRule import com.anytypeio.anytype.presentation.util.Dispatcher -import com.anytypeio.anytype.presentation.widgets.collection.DateProviderImpl import com.anytypeio.anytype.test_utils.MockDataFactory -import java.time.ZoneId +import java.util.Locale import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.emptyFlow @@ -211,6 +212,12 @@ open class ObjectSetViewModelTestSetup { @Mock lateinit var spaceSyncAndP2PStatusProvider: SpaceSyncAndP2PStatusProvider + @Mock + lateinit var localeProvider : LocaleProvider + + @Mock + lateinit var dateProvider: DateProvider + var permissions: UserPermissionProvider = UserPermissionProviderStub() lateinit var spaceConfig: Config @@ -257,6 +264,7 @@ open class ObjectSetViewModelTestSetup { ) dataViewSubscription = DefaultDataViewSubscription(dataViewSubscriptionContainer) storeOfObjectTypes = DefaultStoreOfObjectTypes() + Mockito.`when`(localeProvider.locale()).thenReturn(Locale.getDefault()) return ObjectSetViewModel( openObjectSet = openObjectSet, closeBlock = closeBlock, @@ -293,7 +301,7 @@ open class ObjectSetViewModelTestSetup { getObjectTypes = getObjectTypes, storelessSubscriptionContainer = storelessSubscriptionContainer, dispatchers = dispatchers, - dateProvider = DateProviderImpl(ZoneId.systemDefault()), + dateProvider = dateProvider, vmParams = ObjectSetViewModel.Params( ctx = root, space = SpaceId(defaultSpace)