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

DROID-2726 Version history | Show relation values (#1474)

This commit is contained in:
Konstantin Ivanov 2024-08-12 10:32:42 +02:00 committed by GitHub
parent c593cceeb8
commit 78570899e1
Signed by: github
GPG key ID: B5690EEEBB952194
7 changed files with 201 additions and 38 deletions

View file

@ -39,6 +39,7 @@ import com.anytypeio.anytype.ui.linking.BacklinkOrAddToObjectFragment
import com.anytypeio.anytype.ui.moving.OnMoveToAction
import com.anytypeio.anytype.ui.relations.ObjectRelationListFragment
import com.google.android.material.snackbar.Snackbar
import timber.log.Timber
abstract class ObjectMenuBaseFragment :
BaseBottomSheetFragment<FragmentObjectMenuBinding>(),
@ -177,6 +178,8 @@ abstract class ObjectMenuBaseFragment :
spaceId = space
)
)
}.onFailure {
Timber.e(it, "Failed to open history screen")
}
}
}

View file

@ -25,13 +25,19 @@ import com.anytypeio.anytype.core_ui.features.history.VersionHistoryPreviewScree
import com.anytypeio.anytype.core_ui.features.history.VersionHistoryScreen
import com.anytypeio.anytype.core_ui.tools.ClipboardInterceptor
import com.anytypeio.anytype.core_utils.ext.argString
import com.anytypeio.anytype.core_utils.ext.safeNavigate
import com.anytypeio.anytype.core_utils.ext.setupBottomSheetBehavior
import com.anytypeio.anytype.core_utils.ext.subscribe
import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetComposeFragment
import com.anytypeio.anytype.di.common.componentManager
import com.anytypeio.anytype.presentation.history.VersionGroupNavigation
import com.anytypeio.anytype.presentation.history.VersionHistoryVMFactory
import com.anytypeio.anytype.presentation.history.VersionHistoryViewModel
import com.anytypeio.anytype.presentation.history.VersionHistoryViewModel.Command
import com.anytypeio.anytype.presentation.relations.value.tagstatus.RelationContext
import com.anytypeio.anytype.ui.relations.RelationDateValueFragment
import com.anytypeio.anytype.ui.relations.RelationTextValueFragment
import com.anytypeio.anytype.ui.relations.value.ObjectValueFragment
import com.anytypeio.anytype.ui.relations.value.TagOrStatusValueFragment
import com.google.accompanist.navigation.material.BottomSheetNavigator
import com.google.accompanist.navigation.material.ExperimentalMaterialNavigationApi
import com.google.accompanist.navigation.material.ModalBottomSheetLayout
@ -61,6 +67,9 @@ class VersionHistoryFragment : BaseBottomSheetComposeFragment() {
onDragListener = { _, _ -> false },
lifecycle = lifecycle,
dragAndDropSelector = DragAndDropAdapterDelegate(),
onClickListener = {
vm.proceedWithClick(it)
}
)
@OptIn(ExperimentalMaterialNavigationApi::class)
@ -95,15 +104,15 @@ class VersionHistoryFragment : BaseBottomSheetComposeFragment() {
private fun NavigationGraph(navController: NavHostController) {
NavHost(
navController = navController,
startDestination = VersionGroupNavigation.Main.route
startDestination = Command.Main.route
) {
composable(VersionGroupNavigation.Main.route) {
composable(Command.Main.route) {
VersionHistoryScreen(
state = vm.viewState.collectAsStateWithLifecycle().value,
onItemClick = vm::onGroupItemClicked
)
}
bottomSheet(VersionGroupNavigation.VersionPreview.route) {
bottomSheet(Command.VersionPreview.route) {
VersionHistoryPreviewScreen(
state = vm.previewViewState.collectAsStateWithLifecycle().value,
editorAdapter = editorAdapter,
@ -118,20 +127,86 @@ class VersionHistoryFragment : BaseBottomSheetComposeFragment() {
super.onViewCreated(view, savedInstanceState)
setupBottomSheetBehavior(DEFAULT_PADDING_TOP)
subscribe(vm.navigation){ navigation ->
when(navigation){
is VersionGroupNavigation.VersionPreview -> {
navComposeController.navigate(VersionGroupNavigation.VersionPreview.route)
}
VersionGroupNavigation.Main -> {
navComposeController.popBackStack()
}
VersionGroupNavigation.ExitToObject -> {
findNavController().popBackStack(R.id.objectMenuScreen, true)
}
when (navigation) {
is Command.VersionPreview -> navigateToVersionPreview()
Command.Main -> navComposeController.popBackStack()
Command.ExitToObject -> exitToObjectMenu()
is Command.RelationMultiSelect -> navigateToRelationMultiSelect(navigation)
is Command.RelationDate -> navigateToRelationDate(navigation)
is Command.RelationObject -> navigateToRelationObject(navigation)
is Command.RelationText -> navigateToRelationText(navigation)
}
}
}
private fun navigateToVersionPreview() {
navComposeController.navigate(Command.VersionPreview.route)
}
private fun exitToObjectMenu() {
findNavController().popBackStack(R.id.objectMenuScreen, true)
}
private fun navigateToRelationMultiSelect(navigation: Command.RelationMultiSelect) {
val relationContext = if (navigation.isSet) RelationContext.OBJECT_SET else RelationContext.OBJECT
val bundle = TagOrStatusValueFragment.args(
ctx = ctx,
space = spaceId,
obj = ctx,
relation = navigation.relationKey.key,
isLocked = true,
context = relationContext
)
findNavController().safeNavigate(
R.id.versionHistoryScreen,
R.id.nav_relations,
bundle
)
}
private fun navigateToRelationDate(navigation: Command.RelationDate) {
val relationContext = if (navigation.isSet) RelationDateValueFragment.FLOW_SET_OR_COLLECTION else RelationDateValueFragment.FLOW_DEFAULT
val fr = RelationDateValueFragment.new(
ctx = ctx,
space = spaceId,
relationKey = navigation.relationKey.key,
objectId = ctx,
flow = relationContext,
isLocked = true
)
fr.showChildFragment()
}
private fun navigateToRelationObject(navigation: Command.RelationObject) {
val relationContext = if (navigation.isSet) RelationContext.OBJECT_SET else RelationContext.OBJECT
findNavController().safeNavigate(
R.id.versionHistoryScreen,
R.id.objectValueScreen,
ObjectValueFragment.args(
ctx = ctx,
space = spaceId,
obj = ctx,
relation = navigation.relationKey.key,
isLocked = true,
relationContext = relationContext
)
)
}
private fun navigateToRelationText(navigation: Command.RelationText) {
val relationContext =
if (navigation.isSet) RelationTextValueFragment.FLOW_SET_OR_COLLECTION else RelationTextValueFragment.FLOW_DEFAULT
val fr = RelationTextValueFragment.new(
ctx = ctx,
space = spaceId,
relationKey = navigation.relationKey.key,
objectId = ctx,
flow = relationContext,
isLocked = true
)
fr.showChildFragment()
}
override fun onStart() {
super.onStart()
vm.onStart()

View file

@ -73,6 +73,11 @@
android:id="@+id/objectValueScreen"
android:name="com.anytypeio.anytype.ui.relations.value.ObjectValueFragment"
android:label="Relation-Object-Value-Screen" />
<dialog
android:id="@+id/versionHistoryScreen"
android:name="com.anytypeio.anytype.ui.history.VersionHistoryFragment"
android:label="Object-Version_history-Screen"/>
</navigation>
<include app:graph="@navigation/nav_editor_modal" />
@ -136,6 +141,10 @@
android:id="@+id/objectValueScreen"
android:name="com.anytypeio.anytype.ui.relations.value.ObjectValueFragment"
android:label="Relation-Object-Value-Screen" />
<dialog
android:id="@+id/versionHistoryScreen"
android:name="com.anytypeio.anytype.ui.history.VersionHistoryFragment"
android:label="Set-Version_history-Screen"/>
</navigation>
<fragment
@ -248,10 +257,6 @@
android:id="@+id/galleryInstallationScreen"
android:name="com.anytypeio.anytype.ui.gallery.GalleryInstallationFragment" />
<dialog
android:id="@+id/versionHistoryScreen"
android:name="com.anytypeio.anytype.ui.history.VersionHistoryFragment" />
<fragment
android:id="@+id/splashScreen"
android:name="com.anytypeio.anytype.ui.splash.SplashFragment"

View file

@ -90,6 +90,10 @@ fun VersionHistoryPreviewScreen(
AndroidView(
factory = { context ->
RecyclerView(context).apply {
layoutParams = RecyclerView.LayoutParams(
RecyclerView.LayoutParams.MATCH_PARENT,
RecyclerView.LayoutParams.MATCH_PARENT
)
layoutManager = LinearLayoutManager(context)
adapter = editorAdapter
}

View file

@ -89,8 +89,7 @@ fun RelationsViewContent(
LazyColumn(
state = lazyListState,
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.fillMaxSize()
) {
itemsIndexed(
items = state.items,

View file

@ -6,8 +6,12 @@ import com.anytypeio.anytype.analytics.base.Analytics
import com.anytypeio.anytype.core_models.Event
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_models.Relation
import com.anytypeio.anytype.core_models.RelationFormat
import com.anytypeio.anytype.core_models.ext.asMap
import com.anytypeio.anytype.core_models.history.Version
import com.anytypeio.anytype.core_models.isDataView
import com.anytypeio.anytype.core_models.primitives.RelationKey
import com.anytypeio.anytype.core_models.primitives.SpaceId
import com.anytypeio.anytype.core_models.primitives.TimeInSeconds
import com.anytypeio.anytype.domain.base.fold
@ -21,11 +25,13 @@ import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.search.SearchObjects
import com.anytypeio.anytype.presentation.editor.Editor.Mode
import com.anytypeio.anytype.presentation.editor.EditorViewModel.Companion.INITIAL_INDENT
import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
import com.anytypeio.anytype.presentation.editor.render.BlockViewRenderer
import com.anytypeio.anytype.presentation.editor.render.DefaultBlockViewRenderer
import com.anytypeio.anytype.presentation.history.VersionHistoryGroup.GroupTitle
import com.anytypeio.anytype.presentation.objects.ObjectIcon
import com.anytypeio.anytype.presentation.relations.getRelationFormat
import com.anytypeio.anytype.presentation.search.ObjectSearchConstants
import java.time.Instant
import java.time.LocalDate
@ -54,7 +60,7 @@ class VersionHistoryViewModel(
private val _previewViewState =
MutableStateFlow<VersionHistoryPreviewScreen>(VersionHistoryPreviewScreen.Hidden)
val previewViewState = _previewViewState
val navigation = MutableSharedFlow<VersionGroupNavigation>(0)
val navigation = MutableSharedFlow<Command>(0)
init {
Timber.d("VersionHistoryViewModel created")
@ -68,30 +74,82 @@ class VersionHistoryViewModel(
fun onGroupItemClicked(item: VersionHistoryGroup.Item) {
viewModelScope.launch {
_previewViewState.value = VersionHistoryPreviewScreen.Loading
navigation.emit(VersionGroupNavigation.VersionPreview)
navigation.emit(Command.VersionPreview)
proceedShowVersion(item = item)
}
}
fun proceedWithClick(click: ListenerType) {
Timber.d("Click: $click")
viewModelScope.launch {
when (click) {
is ListenerType.Relation.Featured -> {
proceedWithRelationValueNavigation(
relation = RelationKey(click.relation.key),
relationFormat = click.relation.getRelationFormat()
)
}
is ListenerType.Relation.Related -> {
if (click.value is BlockView.Relation.Related) {
proceedWithRelationValueNavigation(
relation = RelationKey(click.value.view.key),
relationFormat = click.value.view.getRelationFormat()
)
}
}
else -> {}
}
}
}
private suspend fun proceedWithRelationValueNavigation(
relation: RelationKey,
relationFormat: Relation.Format
) {
val currentState = (_previewViewState.value as? VersionHistoryPreviewScreen.Success) ?: return
val isSet = currentState.isSet
when (relationFormat) {
RelationFormat.SHORT_TEXT,
RelationFormat.LONG_TEXT,
RelationFormat.URL,
RelationFormat.PHONE,
RelationFormat.NUMBER,
RelationFormat.EMAIL -> navigation.emit(Command.RelationText(relation, isSet))
RelationFormat.DATE -> navigation.emit(Command.RelationDate(relation, isSet))
Relation.Format.TAG,
Relation.Format.STATUS -> navigation.emit(Command.RelationMultiSelect(relation, isSet))
Relation.Format.OBJECT,
Relation.Format.FILE -> navigation.emit(Command.RelationObject(relation, isSet))
else -> {
Timber.d("No interaction allowed with this relation with format:$relationFormat")
}
}
}
fun proceedWithHidePreview() {
_previewViewState.value = VersionHistoryPreviewScreen.Hidden
viewModelScope.launch {
navigation.emit(VersionGroupNavigation.Main)
navigation.emit(Command.Main)
}
}
fun proceedWithRestore() {
val currentVersionId = (_previewViewState.value as? VersionHistoryPreviewScreen.Success)?.versionId ?: return
val currentVersionId =
(_previewViewState.value as? VersionHistoryPreviewScreen.Success)?.versionId ?: return
viewModelScope.launch {
val params = SetVersion.Params(
objectId = vmParams.objectId,
versionId = currentVersionId
)
objectId = vmParams.objectId,
versionId = currentVersionId
)
setVersion.async(params).fold(
onSuccess = {
Timber.d("Version restored")
_previewViewState.value = VersionHistoryPreviewScreen.Hidden
navigation.emit(VersionGroupNavigation.ExitToObject)
navigation.emit(Command.ExitToObject)
},
onFailure = {
Timber.e(it, "Error while restoring version")
@ -265,9 +323,11 @@ class VersionHistoryViewModel(
currentDate -> {
GroupTitle.Today
}
currentDate.minusDays(1) -> {
GroupTitle.Yesterday
}
else -> {
val pattern = if (givenYear == currentYear) {
GROUP_DATE_FORMAT_CURRENT_YEAR
@ -342,6 +402,7 @@ class VersionHistoryViewModel(
val event = payload.events
.filterIsInstance<Event.Command.ShowObject>()
.first()
val obj = ObjectWrapper.Basic(event.details.details[vmParams.objectId]?.map.orEmpty())
val root = event.blocks.first { it.id == vmParams.objectId }
val blocks = event.blocks.asMap().render(
mode = Mode.Read,
@ -361,7 +422,8 @@ class VersionHistoryViewModel(
blocks = blocks,
dateFormatted = item.dateFormatted,
timeFormatted = item.timeFormatted,
icon = item.icon
icon = item.icon,
isSet = obj.layout.isDataView()
)
}
}
@ -374,8 +436,14 @@ class VersionHistoryViewModel(
val spaceId: SpaceId
)
sealed class Command {
data class OpenVersion(val versionId: Id) : Command()
sealed class Command(val route: String) {
data object Main : Command("main")
data object VersionPreview : Command("version preview")
data object ExitToObject : Command("")
data class RelationMultiSelect(val relationKey: RelationKey, val isSet: Boolean) : Command("relation_select")
data class RelationObject(val relationKey: RelationKey, val isSet: Boolean) : Command("relation_object")
data class RelationDate(val relationKey: RelationKey, val isSet: Boolean) : Command("relation_date")
data class RelationText(val relationKey: RelationKey, val isSet: Boolean) : Command("relation_text")
}
companion object {
@ -403,7 +471,8 @@ sealed class VersionHistoryPreviewScreen {
val blocks: List<BlockView>,
val dateFormatted: String,
val timeFormatted: String,
val icon: ObjectIcon?
val icon: ObjectIcon?,
val isSet: Boolean
) :
VersionHistoryPreviewScreen()
@ -433,10 +502,4 @@ data class VersionHistoryGroup(
data object Yesterday : GroupTitle()
data class Date(val date: String) : GroupTitle()
}
}
sealed class VersionGroupNavigation(val route: String) {
data object Main : VersionGroupNavigation("main")
data object VersionPreview : VersionGroupNavigation("version preview")
data object ExitToObject : VersionGroupNavigation("")
}

View file

@ -281,4 +281,18 @@ suspend fun getNotIncludedRecommendedRelations(
val relationLinkKeys = relationLinks.map { it.key }.toSet()
return storeOfRelations.getById(recommendedRelations)
.filterNot { recommended -> recommended.key in relationLinkKeys }
}
fun ObjectRelationView.getRelationFormat(): RelationFormat = when (this) {
is ObjectRelationView.Object -> RelationFormat.OBJECT
is ObjectRelationView.File -> RelationFormat.FILE
is ObjectRelationView.Default -> format
is ObjectRelationView.Status -> RelationFormat.STATUS
is ObjectRelationView.Tags -> RelationFormat.TAG
is ObjectRelationView.Checkbox -> RelationFormat.CHECKBOX
is ObjectRelationView.Links.Backlinks -> RelationFormat.OBJECT
is ObjectRelationView.Links.From -> RelationFormat.OBJECT
is ObjectRelationView.ObjectType.Base -> RelationFormat.OBJECT
is ObjectRelationView.ObjectType.Deleted -> RelationFormat.OBJECT
is ObjectRelationView.Source -> RelationFormat.OBJECT
}