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

DROID-2773 Merge branch 'release/0-32-0' into droid-2773-tech-implement-debugaccountselecttrace

This commit is contained in:
konstantiniiv 2024-08-27 19:55:34 +02:00
commit 4fbf029d42
10 changed files with 712 additions and 633 deletions

View file

@ -47,7 +47,7 @@ android {
buildConfigField "boolean", "USE_NEW_WINDOW_INSET_API", "true"
buildConfigField "boolean", "USE_EDGE_TO_EDGE", "true"
buildConfigField "boolean", "LOG_FROM_MW_LIBRARY", localProperties.getProperty("LOG_FROM_MW_LIBRARY", "false")
buildConfigField "boolean", "LOG_MW_INTERACTION", localProperties.getProperty("LOG_MW_INTERACTION", "false")
buildConfigField "boolean", "LOG_MW_INTERACTION", localProperties.getProperty("LOG_MW_INTERACTION", "true")
buildConfigField "boolean", "LOG_DASHBOARD_REDUCER", localProperties.getProperty("LOG_DASHBOARD_REDUCER", "false")
buildConfigField "boolean", "LOG_EDITOR_VIEWMODEL_EVENTS", localProperties.getProperty("LOG_EDITOR_VIEWMODEL_EVENTS", "false")
buildConfigField "boolean", "LOG_EDITOR_CONTROL_PANEL", localProperties.getProperty("LOG_EDITOR_CONTROL_PANEL", "false")

View file

@ -1,4 +1,4 @@
version.versionMajor=0
version.versionMinor=32
version.versionPatch=34
version.versionPatch=35
version.useDatedVersionName=false

View file

@ -3,9 +3,7 @@ package com.anytypeio.anytype.ui.onboarding.screens.signin
import android.content.res.Configuration
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
@ -31,6 +29,7 @@ import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.OffsetMapping
import androidx.compose.ui.text.input.TransformedText
import androidx.compose.ui.text.input.VisualTransformation
@ -43,7 +42,6 @@ import com.anytypeio.anytype.core_ui.ColorButtonRegular
import com.anytypeio.anytype.core_ui.MnemonicPhrasePaletteColors
import com.anytypeio.anytype.core_ui.OnBoardingTextPrimaryColor
import com.anytypeio.anytype.core_ui.foundation.noRippleClickable
import com.anytypeio.anytype.core_ui.foundation.noRippleThrottledClickable
import com.anytypeio.anytype.core_ui.views.ButtonSize
import com.anytypeio.anytype.core_ui.views.ConditionLogin
import com.anytypeio.anytype.core_ui.views.OnBoardingButtonPrimary
@ -53,7 +51,6 @@ import com.anytypeio.anytype.core_utils.ext.toast
import com.anytypeio.anytype.presentation.onboarding.login.OnboardingMnemonicLoginViewModel
import com.anytypeio.anytype.presentation.onboarding.login.OnboardingMnemonicLoginViewModel.SetupState
import com.anytypeio.anytype.ui.onboarding.OnboardingMnemonicInput
import timber.log.Timber
@Composable
fun RecoveryScreenWrapper(
@ -137,7 +134,9 @@ fun RecoveryScreen(
singleLine = false,
placeholder = stringResource(id = R.string.onboarding_type_your_key),
keyboardOptions = KeyboardOptions(
imeAction = ImeAction.Done
imeAction = ImeAction.Done,
autoCorrect = false,
keyboardType = KeyboardType.Password
),
keyboardActions = KeyboardActions(
onDone = {

View file

@ -5,6 +5,8 @@ import com.anytypeio.anytype.core_utils.tools.FeatureToggles
import com.google.gson.Gson
import timber.log.Timber
import javax.inject.Inject
import kotlin.time.Duration
import kotlin.time.DurationUnit
interface MiddlewareProtobufLogger {
@ -12,6 +14,8 @@ interface MiddlewareProtobufLogger {
fun logResponse(any: Any)
fun logResponse(any: Any, time: Duration?)
fun logEvent(any: Any)
class Impl @Inject constructor(
@ -31,6 +35,12 @@ interface MiddlewareProtobufLogger {
}
}
override fun logResponse(any: Any, time: Duration?) {
Timber.d("response -> ${any.toLogMessage()} [${time.format()}ms] ")
}
private fun Duration?.format(): Long? = this?.toLong(DurationUnit.MILLISECONDS)
override fun logEvent(any: Any) {
if (featureToggles.isLogMiddlewareInteraction) {
if (featureToggles.excludeThreadStatusLogging) {

View file

@ -43,6 +43,7 @@ import com.anytypeio.anytype.domain.misc.AppActionManager
import com.anytypeio.anytype.domain.misc.DeepLinkResolver
import com.anytypeio.anytype.domain.misc.Reducer
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.multiplayer.SpaceViewSubscriptionContainer
import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider
import com.anytypeio.anytype.domain.`object`.GetObject
import com.anytypeio.anytype.domain.`object`.OpenObject
@ -176,7 +177,8 @@ class HomeScreenViewModel(
private val deepLinkToObjectDelegate: DeepLinkToObjectDelegate,
private val analyticSpaceHelperDelegate: AnalyticSpaceHelperDelegate,
private val coverImageHashProvider: CoverImageHashProvider,
private val storeOfRelations: StoreOfRelations
private val storeOfRelations: StoreOfRelations,
private val spaceViewSubscriptionContainer: SpaceViewSubscriptionContainer
) : NavigationViewModel<HomeScreenViewModel.Navigation>(),
Reducer<ObjectView, Payload>,
WidgetActiveViewStateHolder by widgetActiveViewStateHolder,
@ -401,6 +403,7 @@ class HomeScreenViewModel(
urlBuilder = urlBuilder,
objectWatcher = objectWatcher,
getSpaceView = getSpaceView,
spaceViewCache = spaceViewSubscriptionContainer,
onRequestCache = {
currentlyDisplayedViews.find { view ->
view.id == widget.id
@ -419,6 +422,7 @@ class HomeScreenViewModel(
isSessionActive = isSessionActive,
objectWatcher = objectWatcher,
getSpaceView = getSpaceView,
spaceViewCache = spaceViewSubscriptionContainer,
onRequestCache = {
currentlyDisplayedViews.find { view ->
view.id == widget.id
@ -1702,7 +1706,8 @@ class HomeScreenViewModel(
private val deepLinkToObjectDelegate: DeepLinkToObjectDelegate,
private val analyticSpaceHelperDelegate: AnalyticSpaceHelperDelegate,
private val coverImageHashProvider: CoverImageHashProvider,
private val storeOfRelations: StoreOfRelations
private val storeOfRelations: StoreOfRelations,
private val spaceViewSubscriptionContainer: SpaceViewSubscriptionContainer
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T = HomeScreenViewModel(
@ -1744,7 +1749,8 @@ class HomeScreenViewModel(
deepLinkToObjectDelegate = deepLinkToObjectDelegate,
analyticSpaceHelperDelegate = analyticSpaceHelperDelegate,
coverImageHashProvider = coverImageHashProvider,
storeOfRelations = storeOfRelations
storeOfRelations = storeOfRelations,
spaceViewSubscriptionContainer = spaceViewSubscriptionContainer
) as T
}

View file

@ -8,10 +8,12 @@ import com.anytypeio.anytype.core_models.ObjectView
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_models.RelationFormat
import com.anytypeio.anytype.core_models.Relations
import com.anytypeio.anytype.core_models.primitives.SpaceId
import com.anytypeio.anytype.domain.library.StoreSearchByIdsParams
import com.anytypeio.anytype.domain.library.StoreSearchParams
import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.multiplayer.SpaceViewSubscriptionContainer
import com.anytypeio.anytype.domain.objects.ObjectWatcher
import com.anytypeio.anytype.domain.spaces.GetSpaceView
import com.anytypeio.anytype.presentation.search.ObjectSearchConstants
@ -34,6 +36,7 @@ class ListWidgetContainer(
private val isWidgetCollapsed: Flow<Boolean>,
private val objectWatcher: ObjectWatcher,
private val getSpaceView: GetSpaceView,
private val spaceViewCache: SpaceViewSubscriptionContainer,
isSessionActive: Flow<Boolean>,
onRequestCache: () -> WidgetView.ListOfObjects? = { null }
) : WidgetContainer {
@ -103,9 +106,7 @@ class ListWidgetContainer(
}
}
BundledWidgetSourceIds.RECENT -> {
val spaceView = getSpaceView.async(
GetSpaceView.Params.BySpaceViewId(widget.config.spaceView)
).getOrNull()
val spaceView = getSpaceView()
val spaceViewCreationDate = spaceView
?.getValue<Double?>(Relations.CREATED_DATE)
?.toLong()
@ -163,6 +164,12 @@ class ListWidgetContainer(
spaceCreationDateInSeconds = spaceCreationDateInSeconds
)
private suspend fun getSpaceView() : ObjectWrapper? {
return spaceViewCache.get(SpaceId(widget.config.space)) ?: getSpaceView.async(
GetSpaceView.Params.BySpaceViewId(widget.config.spaceView)
).getOrNull()
}
private fun resolveType() = when (subscription) {
BundledWidgetSourceIds.RECENT -> WidgetView.ListOfObjects.Type.Recent
BundledWidgetSourceIds.RECENT_LOCAL -> WidgetView.ListOfObjects.Type.RecentLocal

View file

@ -4,9 +4,11 @@ import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.ObjectTypeIds
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_models.Relations
import com.anytypeio.anytype.core_models.primitives.SpaceId
import com.anytypeio.anytype.domain.library.StoreSearchByIdsParams
import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.multiplayer.SpaceViewSubscriptionContainer
import com.anytypeio.anytype.domain.objects.ObjectWatcher
import com.anytypeio.anytype.domain.spaces.GetSpaceView
import com.anytypeio.anytype.presentation.search.ObjectSearchConstants
@ -14,8 +16,11 @@ import com.anytypeio.anytype.presentation.widgets.WidgetConfig.isValidObject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.emitAll
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.take
@ -31,6 +36,7 @@ class TreeWidgetContainer(
private val isWidgetCollapsed: Flow<Boolean>,
private val objectWatcher: ObjectWatcher,
private val getSpaceView: GetSpaceView,
private val spaceViewCache: SpaceViewSubscriptionContainer,
isSessionActive: Flow<Boolean>,
onRequestCache: () -> WidgetView.Tree? = { null }
) : WidgetContainer {
@ -71,91 +77,131 @@ class TreeWidgetContainer(
}.flatMapLatest { (paths, isWidgetCollapsed) ->
when (val source = widget.source) {
is Widget.Source.Bundled -> {
fetchRootLevelBundledSourceObjects().map { rootLevelObjects ->
rootLevelObjects.map { it.id }
}.flatMapLatest { rootLevelObjects ->
if (isWidgetCollapsed) {
flowOf(
WidgetView.Tree(
id = widget.id,
source = widget.source,
isExpanded = false,
elements = emptyList(),
isLoading = false
)
)
} else {
fetchRootLevelBundledSourceObjects().map { rootLevelObjects ->
rootLevelObjects.map { it.id }
}.flatMapLatest { rootLevelObjects ->
container.subscribe(
StoreSearchByIdsParams(
subscription = widget.id,
keys = keys,
targets = getBundledSubscriptionTargets(
paths = paths,
links = rootLevelObjects
)
)
).map { data ->
rootLevelObjects to data
}
}.map { (rootLevelLinks, objectWrappers) ->
val valid = objectWrappers.filter { obj -> isValidObject(obj) }
val data = valid.associateBy { r -> r.id }
mutex.withLock {
with(nodes) {
clear()
putAll(valid.associate { obj -> obj.id to obj.links })
}
}
WidgetView.Tree(
id = widget.id,
source = widget.source,
isExpanded = true,
elements = buildTree(
links = rootLevelLinks,
level = ROOT_INDENT,
expanded = paths,
path = widget.id + SEPARATOR + widget.source.id + SEPARATOR,
data = data,
rootLimit = rootLevelLimit
)
)
}.onStart {
if (paths.isEmpty()) {
emit(
WidgetView.Tree(
id = widget.id,
source = widget.source,
isExpanded = true,
elements = emptyList(),
isLoading = true
)
)
}
}
}
}
is Widget.Source.Default -> {
if (isWidgetCollapsed) {
flowOf(
WidgetView.Tree(
id = widget.id,
source = widget.source,
isExpanded = false,
elements = emptyList(),
isLoading = false
)
)
} else {
container.subscribe(
StoreSearchByIdsParams(
subscription = widget.id,
keys = keys,
targets = if (!isWidgetCollapsed) {
getBundledSubscriptionTargets(
paths = paths,
links = rootLevelObjects
)
} else {
emptyList()
}
)
).map { data ->
rootLevelObjects to data
}
}.map { (rootLevelLinks, objectWrappers) ->
val valid = objectWrappers.filter { obj -> isValidObject(obj) }
val data = valid.associateBy { r -> r.id }
mutex.withLock {
with(nodes) {
clear()
putAll(valid.associate { obj -> obj.id to obj.links })
}
}
WidgetView.Tree(
id = widget.id,
source = widget.source,
isExpanded = !isWidgetCollapsed,
elements = buildTree(
links = rootLevelLinks,
level = ROOT_INDENT,
expanded = paths,
path = widget.id + SEPARATOR + widget.source.id + SEPARATOR,
data = data,
rootLimit = rootLevelLimit
)
)
}
}
is Widget.Source.Default -> {
container.subscribe(
StoreSearchByIdsParams(
subscription = widget.id,
keys = keys,
targets = if (!isWidgetCollapsed) {
getDefaultSubscriptionTargets(
targets = getDefaultSubscriptionTargets(
paths = paths,
source = source
)
} else {
emptyList()
)
).map { results ->
val valid = results.filter { obj -> isValidObject(obj) }
val data = valid.associateBy { r -> r.id }
mutex.withLock {
with(nodes) {
clear()
putAll(valid.associate { obj -> obj.id to obj.links })
}
}
)
).map { results ->
val valid = results.filter { obj -> isValidObject(obj) }
val data = valid.associateBy { r -> r.id }
mutex.withLock {
with(nodes) {
clear()
putAll(valid.associate { obj -> obj.id to obj.links })
WidgetView.Tree(
id = widget.id,
source = widget.source,
isExpanded = true,
elements = buildTree(
links = source.obj.links,
level = ROOT_INDENT,
expanded = paths,
path = widget.id + SEPARATOR + widget.source.id + SEPARATOR,
data = data,
rootLimit = WidgetConfig.NO_LIMIT
)
)
}.onStart {
if (paths.isEmpty()) {
emit(
WidgetView.Tree(
id = widget.id,
source = widget.source,
isExpanded = true,
elements = emptyList(),
isLoading = true
)
)
}
}
WidgetView.Tree(
id = widget.id,
source = widget.source,
isExpanded = !isWidgetCollapsed,
elements = buildTree(
links = source.obj.links,
level = ROOT_INDENT,
expanded = paths,
path = widget.id + SEPARATOR + widget.source.id + SEPARATOR,
data = data,
rootLimit = WidgetConfig.NO_LIMIT
)
)
}
}
}
}
private suspend fun fetchRootLevelBundledSourceObjects(): Flow<List<ObjectWrapper.Basic>> {
private fun fetchRootLevelBundledSourceObjects(): Flow<List<ObjectWrapper.Basic>> {
return when (widget.source.id) {
BundledWidgetSourceIds.FAVORITE -> {
objectWatcher
@ -178,24 +224,26 @@ class TreeWidgetContainer(
}
}
BundledWidgetSourceIds.RECENT -> {
val spaceView = getSpaceView.async(
GetSpaceView.Params.BySpaceViewId(widget.config.spaceView)
).getOrNull()
val spaceViewCreationDate = spaceView
?.getValue<Double?>(Relations.CREATED_DATE)
?.toLong()
container.subscribe(
ListWidgetContainer.params(
subscription = widget.source.id,
spaces = buildList {
add(widget.config.space)
add(widget.config.techSpace)
},
keys = keys,
limit = rootLevelLimit,
spaceCreationDateInSeconds = spaceViewCreationDate
flow {
val spaceView = getSpaceView()
val spaceViewCreationDate = spaceView
?.getValue<Double?>(Relations.CREATED_DATE)
?.toLong()
emitAll(
container.subscribe(
ListWidgetContainer.params(
subscription = widget.source.id,
spaces = buildList {
add(widget.config.space)
add(widget.config.techSpace)
},
keys = keys,
limit = rootLevelLimit,
spaceCreationDateInSeconds = spaceViewCreationDate
)
)
)
)
}
}
else -> {
container.subscribe(
@ -213,6 +261,12 @@ class TreeWidgetContainer(
}
}
private suspend fun getSpaceView() : ObjectWrapper? {
return spaceViewCache.get(SpaceId(widget.config.space)) ?: getSpaceView.async(
GetSpaceView.Params.BySpaceViewId(widget.config.spaceView)
).getOrNull()
}
private suspend fun getDefaultSubscriptionTargets(
paths: List<TreePath>,
source: Widget.Source.Default

View file

@ -43,6 +43,7 @@ import com.anytypeio.anytype.domain.library.StoreSearchParams
import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer
import com.anytypeio.anytype.domain.misc.AppActionManager
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.multiplayer.SpaceViewSubscriptionContainer
import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider
import com.anytypeio.anytype.domain.`object`.GetObject
import com.anytypeio.anytype.domain.`object`.OpenObject
@ -223,6 +224,9 @@ class HomeScreenViewModelTest {
@Mock
lateinit var storeOfRelations: StoreOfRelations
@Mock
lateinit var spaceViewSubscriptionContainer: SpaceViewSubscriptionContainer
lateinit var userPermissionProvider: UserPermissionProvider
private val objectPayloadDispatcher = Dispatcher.Default<Payload>()
@ -2907,7 +2911,8 @@ class HomeScreenViewModelTest {
deepLinkToObjectDelegate = deepLinkToObjectDelegate,
analyticSpaceHelperDelegate = analyticSpaceHelperDelegate,
coverImageHashProvider = coverImageHashProvider,
storeOfRelations = storeOfRelations
storeOfRelations = storeOfRelations,
spaceViewSubscriptionContainer = spaceViewSubscriptionContainer
)
companion object {

View file

@ -11,6 +11,7 @@ import com.anytypeio.anytype.domain.config.Gateway
import com.anytypeio.anytype.domain.library.StoreSearchByIdsParams
import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.multiplayer.SpaceViewSubscriptionContainer
import com.anytypeio.anytype.domain.objects.ObjectWatcher
import com.anytypeio.anytype.domain.spaces.GetSpaceView
import com.anytypeio.anytype.presentation.objects.ObjectIcon
@ -56,6 +57,9 @@ class TreeWidgetContainerTest {
@Mock
lateinit var getSpaceView: GetSpaceView
@Mock
lateinit var spaceViewSubscriptionContainer: SpaceViewSubscriptionContainer
val dispatchers = AppCoroutineDispatchers(
io = coroutineTestRule.dispatcher,
main = coroutineTestRule.dispatcher,
@ -105,7 +109,8 @@ class TreeWidgetContainerTest {
urlBuilder = urlBuilder,
isSessionActive = flowOf(true),
objectWatcher = objectWatcher,
getSpaceView = getSpaceView
getSpaceView = getSpaceView,
spaceViewCache = spaceViewSubscriptionContainer
)
stubObjectSearch(
@ -180,7 +185,8 @@ class TreeWidgetContainerTest {
urlBuilder = urlBuilder,
isSessionActive = flowOf(true),
objectWatcher = objectWatcher,
getSpaceView = getSpaceView
getSpaceView = getSpaceView,
spaceViewCache = spaceViewSubscriptionContainer
)
stubObjectSearch(
@ -270,7 +276,8 @@ class TreeWidgetContainerTest {
urlBuilder = urlBuilder,
isSessionActive = flowOf(true),
objectWatcher = objectWatcher,
getSpaceView = getSpaceView
getSpaceView = getSpaceView,
spaceViewCache = spaceViewSubscriptionContainer
)
stubObjectSearch(
@ -415,7 +422,8 @@ class TreeWidgetContainerTest {
urlBuilder = urlBuilder,
isSessionActive = flowOf(true),
objectWatcher = objectWatcher,
getSpaceView = getSpaceView
getSpaceView = getSpaceView,
spaceViewCache = spaceViewSubscriptionContainer
)
stubObjectSearch(
@ -477,7 +485,8 @@ class TreeWidgetContainerTest {
urlBuilder = urlBuilder,
isSessionActive = flowOf(true),
objectWatcher = objectWatcher,
getSpaceView = getSpaceView
getSpaceView = getSpaceView,
spaceViewCache = spaceViewSubscriptionContainer
)
stubObjectSearch(