1
0
Fork 0
mirror of https://github.com/anyproto/anytype-kotlin.git synced 2025-06-08 05:47:05 +09:00

DROID-2797 Date as an object | Vault default settings (#1801)

This commit is contained in:
Konstantin Ivanov 2024-11-18 14:38:03 +01:00 committed by GitHub
parent 5c16df81ec
commit 18f85ad533
Signed by: github
GPG key ID: B5690EEEBB952194
28 changed files with 432 additions and 103 deletions

View file

@ -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<Action>()
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() {

View file

@ -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 {

View file

@ -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

View file

@ -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

View file

@ -1,4 +1,19 @@
package com.anytypeio.anytype.core_models
const val NO_VALUE = ""
const val EMPTY_QUERY = ""
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

View file

@ -4,5 +4,7 @@ import com.anytypeio.anytype.core_models.Id
data class VaultSettings(
val showIntroduceVault: Boolean,
val orderOfSpaces: List<Id> = emptyList()
val orderOfSpaces: List<Id> = emptyList(),
val isRelativeDates: Boolean,
val dateFormat: String
)

View file

@ -46,4 +46,7 @@ interface UserSettingsCache {
suspend fun getAllContentSort(space: SpaceId): Pair<Id, Boolean>?
suspend fun setAllContentSort(space: SpaceId, sort: Id, isAsc: Boolean)
suspend fun setRelativeDates(account: Account, enabled: Boolean)
suspend fun setDateFormat(account: Account, format: String)
}

View file

@ -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)
}
}

View file

@ -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
}

View file

@ -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
}
}
}

View file

@ -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<String, String> {
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)

View file

@ -1,4 +1,4 @@
package com.anytypeio.anytype.device
package com.anytypeio.anytype.device.providers
import android.content.Context
import androidx.core.os.ConfigurationCompat

View file

@ -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() {

View file

@ -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)
}

View file

@ -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<String, String>

View file

@ -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
)
)
}

View file

@ -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(

View file

@ -10,6 +10,7 @@ dependencies {
implementation project(':data')
implementation project(':core-models')
implementation project(':device')
implementation libs.kotlin
implementation libs.coroutinesAndroid

View file

@ -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<SpacePreferences> 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<Id, Boolean>? {
val flow = context.spacePrefsStore.data
val first = flow.first()

View file

@ -16,6 +16,8 @@ message VaultPreferences {
message VaultPreference {
repeated string orderOfSpaces = 1;
bool showIntroduceVault = 2;
bool isRelativeDates = 3;
optional string dateFormat = 4;
}
message SpacePreference {

View file

@ -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
)
}
}

View file

@ -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
}

View file

@ -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<ObjectWrapper.Basic>,
): List<VersionHistoryGroup> {
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<List<Version>>.toGroupItems(
spaceMembers: List<ObjectWrapper.Basic>,
locale: Locale
spaceMembers: List<ObjectWrapper.Basic>
): List<VersionHistoryGroup.Item> {
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(

View file

@ -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),

View file

@ -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)

View file

@ -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
)
}
}

View file

@ -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 {

View file

@ -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)