diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 1817fa400d..deaa02d2c7 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -55,6 +55,9 @@ jobs:
-Pcom.anytype.ci=true \
-Dorg.gradle.unsafe.configuration-cache=false"
+ - name: Prepare Android Manifest for APKs
+ run: ./scripts/release/apk.sh
+
- name: Build release APKS
run: ./gradlew :app:assembleRelease
diff --git a/Makefile b/Makefile
index 29ce2c0d3f..3f6f0c72e6 100644
--- a/Makefile
+++ b/Makefile
@@ -8,7 +8,7 @@ enable_dated_version_name:
./gradlew -q :app:enableDatedVersionName
distribute_debug:
- ./gradlew bundleDebug appDistributionUploadDebug
+ ./gradlew assembleDebug appDistributionUploadDebug
pr_check: compile_android_test_sources test_debug_all
@@ -47,4 +47,7 @@ clean_protos:
update_mw: download_mw_artefacts normalize_mw_imports clean_protos
# Update mw from custom build (download only library, you have to update your proto files manually)
-update_mw_custom: download_mw_artefacts_custom
\ No newline at end of file
+update_mw_custom: download_mw_artefacts_custom
+
+prepare_app_manifest_for_release_apk:
+ ./scripts/release/apk.sh
diff --git a/analytics/src/main/java/com/anytypeio/anytype/analytics/base/EventsDictionary.kt b/analytics/src/main/java/com/anytypeio/anytype/analytics/base/EventsDictionary.kt
index 3b8843eb6b..03e2939466 100644
--- a/analytics/src/main/java/com/anytypeio/anytype/analytics/base/EventsDictionary.kt
+++ b/analytics/src/main/java/com/anytypeio/anytype/analytics/base/EventsDictionary.kt
@@ -191,6 +191,8 @@ object EventsDictionary {
const val CLICK_ONBOARDING_TOOLTIP_TYPE_CLOSE = "Close"
// Sharing spaces
+
+ const val clickQuote = "ClickQuote"
const val shareSpace = "ShareSpace"
const val screenSettingsSpaceShare = "ScreenSettingsSpaceShare"
const val screenStopShare = "ScreenStopShare"
@@ -232,6 +234,14 @@ object EventsDictionary {
const val clickDateCalendarView = "ClickDateCalendarView"
const val objectListSort = "ObjectListSort"
+ //ObjectType
+ const val screenObjectType = "ScreenType"
+ const val editType = "EditType"
+ const val changeRecommendedLayout = "ChangeRecommendedLayout"
+ const val changeTypeSort = "ChangeTypeSort"
+ const val screenTemplate = "ScreenTemplate"
+
+
const val searchBacklink = "SearchBacklink"
object SharingSpacesTypes {
diff --git a/app/build.gradle b/app/build.gradle
index 8787b8b41b..4c27f63cf3 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -112,7 +112,7 @@ android {
buildConfigField("String", "AMPLITUDE_KEY", apikeyProperties['amplitude.debug'])
//signingConfig signingConfigs.debug
firebaseAppDistribution {
- artifactType = "AAB"
+ artifactType = "APK"
groups = "anytype-q&a, product-review, nightly"
serviceCredentialsFile = "$rootDir/scripts/distribution/anytype-debug-service-account-key.json"
}
@@ -143,7 +143,7 @@ android {
// Configures multiple APKs based on ABI.
abi {
// Enables building multiple APKs per ABI.
- enable true
+ enable false
reset()
include "armeabi-v7a", "arm64-v8a"
universalApk true
@@ -177,6 +177,8 @@ dependencies {
implementation project(':gallery-experience')
implementation project(':feature-all-content')
implementation project(':feature-date')
+ implementation project(':feature-object-type')
+ implementation project(':feature-properties')
//Compile time dependencies
ksp libs.daggerCompiler
@@ -224,7 +226,7 @@ dependencies {
implementation libs.composeAccompanistNavigation
implementation libs.preference
implementation libs.activityCompose
- implementation libs.composeReorderable
+ implementation libs.composeReorderableLegacy
implementation libs.room
implementation libs.appUpdater
diff --git a/app/gradle.properties b/app/gradle.properties
index b6e8f5a1a9..71fd3854a2 100644
--- a/app/gradle.properties
+++ b/app/gradle.properties
@@ -1,4 +1,4 @@
version.versionMajor=0
-version.versionMinor=36
+version.versionMinor=37
version.versionPatch=0
version.useDatedVersionName=false
\ No newline at end of file
diff --git a/app/src/androidTest/java/com/anytypeio/anytype/features/editor/LayoutTesting.kt b/app/src/androidTest/java/com/anytypeio/anytype/features/editor/LayoutTesting.kt
index 602a433f33..5997f37aa2 100644
--- a/app/src/androidTest/java/com/anytypeio/anytype/features/editor/LayoutTesting.kt
+++ b/app/src/androidTest/java/com/anytypeio/anytype/features/editor/LayoutTesting.kt
@@ -14,6 +14,7 @@ import com.anytypeio.anytype.presentation.MockBlockContentFactory
import com.anytypeio.anytype.presentation.MockBlockFactory
import com.anytypeio.anytype.presentation.editor.cover.CoverColor
import com.anytypeio.anytype.core_models.ObjectViewDetails
+import com.anytypeio.anytype.core_models.Relations
import com.anytypeio.anytype.test_utils.MockDataFactory
import com.anytypeio.anytype.test_utils.utils.checkHasText
import com.anytypeio.anytype.test_utils.utils.checkIsDisplayed
@@ -85,7 +86,7 @@ class LayoutTesting : EditorTestSetup() {
root to
mapOf(
"iconEmoji" to DefaultDocumentEmojiIconProvider.DOCUMENT_SET.random(),
- "layout" to ObjectType.Layout.TODO.code.toDouble()
+ Relations.LAYOUT to ObjectType.Layout.TODO.code.toDouble()
)
)
)
@@ -135,7 +136,7 @@ class LayoutTesting : EditorTestSetup() {
root to
mapOf(
"iconEmoji" to DefaultDocumentEmojiIconProvider.DOCUMENT_SET.random(),
- "layout" to ObjectType.Layout.TODO.code.toDouble()
+ Relations.LAYOUT to ObjectType.Layout.TODO.code.toDouble()
)
)
)
@@ -180,7 +181,7 @@ class LayoutTesting : EditorTestSetup() {
root to
mapOf(
"iconEmoji" to DefaultDocumentEmojiIconProvider.DOCUMENT_SET.random(),
- "layout" to ObjectType.Layout.TODO.code.toDouble(),
+ Relations.LAYOUT to ObjectType.Layout.TODO.code.toDouble(),
"coverType" to CoverType.COLOR.code.toDouble(),
"coverId" to CoverColor.BLUE.code,
)
@@ -226,7 +227,7 @@ class LayoutTesting : EditorTestSetup() {
root to
mapOf(
"iconEmoji" to DefaultDocumentEmojiIconProvider.DOCUMENT_SET.random(),
- "layout" to ObjectType.Layout.PROFILE.code.toDouble()
+ Relations.LAYOUT to ObjectType.Layout.PROFILE.code.toDouble()
)
)
)
@@ -270,7 +271,7 @@ class LayoutTesting : EditorTestSetup() {
root to
mapOf(
"iconEmoji" to DefaultDocumentEmojiIconProvider.DOCUMENT_SET.random(),
- "layout" to ObjectType.Layout.PROFILE.code.toDouble(),
+ Relations.LAYOUT to ObjectType.Layout.PROFILE.code.toDouble(),
"coverType" to CoverType.COLOR.code.toDouble(),
"coverId" to CoverColor.BLUE.code,
)
@@ -316,7 +317,7 @@ class LayoutTesting : EditorTestSetup() {
root to
mapOf(
"iconEmoji" to DefaultDocumentEmojiIconProvider.DOCUMENT_SET.random(),
- "layout" to ObjectType.Layout.BASIC.code.toDouble()
+ Relations.LAYOUT to ObjectType.Layout.BASIC.code.toDouble()
)
)
)
@@ -360,7 +361,7 @@ class LayoutTesting : EditorTestSetup() {
root to
mapOf(
"iconEmoji" to DefaultDocumentEmojiIconProvider.DOCUMENT_SET.random(),
- "layout" to ObjectType.Layout.BASIC.code.toDouble(),
+ Relations.LAYOUT to ObjectType.Layout.BASIC.code.toDouble(),
"coverType" to CoverType.COLOR.code.toDouble(),
"coverId" to CoverColor.BLUE.code,
)
diff --git a/app/src/androidTest/java/com/anytypeio/anytype/features/editor/ProfileTesting.kt b/app/src/androidTest/java/com/anytypeio/anytype/features/editor/ProfileTesting.kt
index ce5e2e3a7d..391bf35c05 100644
--- a/app/src/androidTest/java/com/anytypeio/anytype/features/editor/ProfileTesting.kt
+++ b/app/src/androidTest/java/com/anytypeio/anytype/features/editor/ProfileTesting.kt
@@ -14,6 +14,7 @@ import com.anytypeio.anytype.features.editor.base.EditorTestSetup
import com.anytypeio.anytype.presentation.MockBlockContentFactory.StubTextContent
import com.anytypeio.anytype.presentation.editor.cover.CoverColor
import com.anytypeio.anytype.core_models.ObjectViewDetails
+import com.anytypeio.anytype.core_models.Relations
import com.anytypeio.anytype.test_utils.MockDataFactory
import com.anytypeio.anytype.test_utils.utils.checkHasText
import com.anytypeio.anytype.test_utils.utils.checkIsDisplayed
@@ -182,7 +183,7 @@ class ProfileTesting : EditorTestSetup() {
root to
mapOf(
"iconImage" to "anyimage",
- "layout" to ObjectType.Layout.PROFILE.code.toDouble(),
+ Relations.LAYOUT to ObjectType.Layout.PROFILE.code.toDouble(),
"coverType" to CoverType.COLOR.code.toDouble(),
"coverId" to CoverColor.BLUE.code,
)
@@ -195,7 +196,7 @@ class ProfileTesting : EditorTestSetup() {
mapOf(
root to
mapOf(
- "layout" to ObjectType.Layout.PROFILE.code.toDouble(),
+ Relations.LAYOUT to ObjectType.Layout.PROFILE.code.toDouble(),
"coverType" to CoverType.COLOR.code.toDouble(),
"coverId" to CoverColor.BLUE.code,
)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index c35facb7c0..25535540d3 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -11,6 +11,9 @@
+
+
+
@@ -50,6 +53,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/java/com/anytypeio/anytype/app/Notifications.kt b/app/src/main/java/com/anytypeio/anytype/app/Notifications.kt
index 0b4735a503..01626c1c89 100644
--- a/app/src/main/java/com/anytypeio/anytype/app/Notifications.kt
+++ b/app/src/main/java/com/anytypeio/anytype/app/Notifications.kt
@@ -83,11 +83,14 @@ class AnytypeNotificationService @Inject constructor(
)
}
is NotificationPayload.ParticipantRemove -> {
+ val placeholder = context.resources.getString(R.string.untitled)
val body = context.resources.getString(
- R.string.multiplayer_notification_member_removed_from_space
+ R.string.multiplayer_notification_member_removed_from_space,
+ payload.spaceName.ifEmpty { placeholder }
)
val title = context.resources.getString(
- R.string.multiplayer_notification_member_removed_from_space_title
+ R.string.multiplayer_notification_member_removed_from_space_title,
+ payload.spaceName.ifEmpty { placeholder }
)
showBasicNotification(
tag = notification.id,
@@ -143,7 +146,7 @@ class AnytypeNotificationService @Inject constructor(
R.string.multiplayer_notification_request_declined
)
val body = context.resources.getString(
- com.anytypeio.anytype.core_ui.R.string.multiplayer_notification_member_join_request_declined,
+ R.string.multiplayer_notification_member_join_request_declined,
payload.spaceName.ifEmpty { placeholder }
)
showBasicNotification(
diff --git a/app/src/main/java/com/anytypeio/anytype/device/DeviceCoverCollectionProvider.kt b/app/src/main/java/com/anytypeio/anytype/device/DeviceCoverCollectionProvider.kt
deleted file mode 100644
index e8798f32df..0000000000
--- a/app/src/main/java/com/anytypeio/anytype/device/DeviceCoverCollectionProvider.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.anytypeio.anytype.device
-
-import android.content.Context
-import com.anytypeio.anytype.core_utils.ext.getJsonDataFromAsset
-import com.anytypeio.anytype.domain.cover.CoverCollectionProvider
-import com.anytypeio.anytype.domain.cover.CoverImage
-import com.google.gson.Gson
-
-class DeviceCoverCollectionProvider(
- private val context: Context,
- private val gson: Gson
-) : CoverCollectionProvider {
-
- override fun provide(): List {
- val json = context.getJsonDataFromAsset(COVER_FILE)
- return if (json != null) {
- gson.fromJson(json, Array::class.java).toList()
- } else {
- emptyList()
- }
- }
-
- companion object {
- const val COVER_FILE = "covers.json"
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/anytypeio/anytype/device/PhotoPickerExt.kt b/app/src/main/java/com/anytypeio/anytype/device/PhotoPickerExt.kt
new file mode 100644
index 0000000000..ad314aa369
--- /dev/null
+++ b/app/src/main/java/com/anytypeio/anytype/device/PhotoPickerExt.kt
@@ -0,0 +1,56 @@
+package com.anytypeio.anytype.device
+
+import androidx.activity.result.ActivityResultLauncher
+import androidx.activity.result.PickVisualMediaRequest
+import androidx.activity.result.contract.ActivityResultContracts.PickVisualMedia
+import androidx.activity.result.contract.ActivityResultContracts.PickVisualMedia.VisualMediaType
+import androidx.fragment.app.Fragment
+import com.anytypeio.anytype.core_utils.ext.Mimetype
+import com.anytypeio.anytype.other.MediaPermissionHelper
+import com.anytypeio.anytype.ui.editor.PickerDelegate
+import timber.log.Timber
+
+/**
+ * Launches a media picker (for images or videos) in a [Fragment].
+ *
+ * This function checks if the device supports the photo picker. If available,
+ * it launches the [pickMedia] launcher with a request for the specified [mediaType].
+ * If the picker is not available, it falls back to opening a file picker using [pickerDelegate]
+ * with the provided [fallbackMimeType].
+ *
+ * @param pickMedia The [ActivityResultLauncher] used to launch the media picker.
+ * @param pickerDelegate A delegate to open a fallback file picker when the media picker is unavailable.
+ * @param mediaType The type of media to pick (e.g. [PickVisualMedia.ImageOnly] or [PickVisualMedia.VideoOnly]).
+ * @param fallbackMimeType The MIME type to use with the fallback file picker (e.g. [Mimetype.MIME_IMAGE_ALL] or [Mimetype.MIME_VIDEO_ALL]).
+ */
+fun Fragment.launchMediaPicker(
+ pickMedia: ActivityResultLauncher,
+ pickerDelegate: PickerDelegate,
+ mediaType: VisualMediaType,
+ fallbackMimeType: Mimetype
+) {
+ context?.let { ctx ->
+ if (PickVisualMedia.isPhotoPickerAvailable(ctx)) {
+ pickMedia.launch(PickVisualMediaRequest(mediaType))
+ } else {
+ Timber.w("$mediaType picker is not available, using pickerDelegate")
+ pickerDelegate.openFilePicker(fallbackMimeType, null)
+ }
+ }
+}
+
+fun Fragment.launchMediaPicker(
+ pickMedia: ActivityResultLauncher,
+ permissionHelper: MediaPermissionHelper,
+ mediaType: VisualMediaType,
+ fallbackMimeType: Mimetype
+) {
+ context?.let { ctx ->
+ if (PickVisualMedia.isPhotoPickerAvailable(ctx)) {
+ pickMedia.launch(PickVisualMediaRequest(mediaType))
+ } else {
+ Timber.w("$mediaType picker is not available, using pickerDelegate")
+ permissionHelper.openFilePicker(fallbackMimeType, null)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/anytypeio/anytype/di/common/ComponentManager.kt b/app/src/main/java/com/anytypeio/anytype/di/common/ComponentManager.kt
index 73319f70e3..94095c1603 100644
--- a/app/src/main/java/com/anytypeio/anytype/di/common/ComponentManager.kt
+++ b/app/src/main/java/com/anytypeio/anytype/di/common/ComponentManager.kt
@@ -9,8 +9,10 @@ import com.anytypeio.anytype.di.feature.DaggerAllContentComponent
import com.anytypeio.anytype.di.feature.DaggerAppPreferencesComponent
import com.anytypeio.anytype.di.feature.DaggerBacklinkOrAddToObjectComponent
import com.anytypeio.anytype.di.feature.DaggerDateObjectComponent
+import com.anytypeio.anytype.di.feature.DaggerEditTypePropertiesComponent
import com.anytypeio.anytype.di.feature.DaggerLinkToObjectComponent
import com.anytypeio.anytype.di.feature.DaggerMoveToComponent
+import com.anytypeio.anytype.di.feature.DaggerObjectTypeComponent
import com.anytypeio.anytype.di.feature.DaggerSplashComponent
import com.anytypeio.anytype.di.feature.DebugSettingsModule
import com.anytypeio.anytype.di.feature.DefaultComponentParam
@@ -49,9 +51,9 @@ import com.anytypeio.anytype.di.feature.ViewerFilterModule
import com.anytypeio.anytype.di.feature.ViewerSortModule
import com.anytypeio.anytype.di.feature.auth.DaggerDeletedAccountComponent
import com.anytypeio.anytype.di.feature.chats.DaggerChatComponent
-import com.anytypeio.anytype.di.feature.cover.UnsplashModule
import com.anytypeio.anytype.di.feature.chats.DaggerChatReactionComponent
import com.anytypeio.anytype.di.feature.chats.DaggerSelectChatReactionComponent
+import com.anytypeio.anytype.di.feature.cover.UnsplashModule
import com.anytypeio.anytype.di.feature.gallery.DaggerGalleryInstallationComponent
import com.anytypeio.anytype.di.feature.home.DaggerHomeScreenComponent
import com.anytypeio.anytype.di.feature.membership.DaggerMembershipComponent
@@ -82,6 +84,7 @@ import com.anytypeio.anytype.di.feature.sets.PickConditionModule
import com.anytypeio.anytype.di.feature.sets.SelectFilterRelationModule
import com.anytypeio.anytype.di.feature.settings.DaggerAboutAppComponent
import com.anytypeio.anytype.di.feature.settings.DaggerAppearanceComponent
+import com.anytypeio.anytype.di.feature.settings.DaggerDebugComponent
import com.anytypeio.anytype.di.feature.settings.DaggerFilesStorageComponent
import com.anytypeio.anytype.di.feature.settings.DaggerSpacesStorageComponent
import com.anytypeio.anytype.di.feature.settings.LogoutWarningModule
@@ -96,17 +99,18 @@ import com.anytypeio.anytype.di.feature.templates.DaggerTemplateSelectComponent
import com.anytypeio.anytype.di.feature.types.DaggerCreateObjectTypeComponent
import com.anytypeio.anytype.di.feature.types.DaggerTypeEditComponent
import com.anytypeio.anytype.di.feature.types.DaggerTypeIconPickComponent
-import com.anytypeio.anytype.di.feature.update.DaggerMigrationErrorComponent
import com.anytypeio.anytype.di.feature.vault.DaggerVaultComponent
import com.anytypeio.anytype.di.feature.wallpaper.WallpaperSelectModule
import com.anytypeio.anytype.di.feature.widgets.DaggerSelectWidgetSourceComponent
import com.anytypeio.anytype.di.feature.widgets.DaggerSelectWidgetTypeComponent
import com.anytypeio.anytype.di.main.MainComponent
import com.anytypeio.anytype.feature_allcontent.presentation.AllContentViewModel
-import com.anytypeio.anytype.feature_date.viewmodel.DateObjectVmParams
import com.anytypeio.anytype.feature_chats.presentation.ChatReactionViewModel
import com.anytypeio.anytype.feature_chats.presentation.ChatViewModel
+import com.anytypeio.anytype.feature_object_type.ui.ObjectTypeVmParams
import com.anytypeio.anytype.feature_chats.presentation.SelectChatReactionViewModel
+import com.anytypeio.anytype.feature_date.viewmodel.DateObjectVmParams
+import com.anytypeio.anytype.feature_properties.add.EditTypePropertiesVmParams
import com.anytypeio.anytype.gallery_experience.viewmodel.GalleryInstallationViewModel
import com.anytypeio.anytype.presentation.editor.EditorViewModel
import com.anytypeio.anytype.presentation.history.VersionHistoryViewModel
@@ -149,6 +153,12 @@ class ComponentManager(
.build()
}
+ val debugComponent = Component {
+ DaggerDebugComponent
+ .factory()
+ .create(findComponentDependencies())
+ }
+
val splashLoginComponent = Component {
DaggerSplashComponent
.factory()
@@ -834,12 +844,6 @@ class ComponentManager(
.create(findComponentDependencies())
}
- val migrationErrorComponent = Component {
- DaggerMigrationErrorComponent
- .factory()
- .create(findComponentDependencies())
- }
-
val onboardingComponent = Component {
DaggerOnboardingComponent
.factory()
@@ -1133,6 +1137,18 @@ class ComponentManager(
.create(findComponentDependencies())
}
+ val objectTypeComponent = ComponentWithParams { params: ObjectTypeVmParams ->
+ DaggerObjectTypeComponent
+ .factory()
+ .create(params, findComponentDependencies())
+ }
+
+ val editTypePropertiesComponent = ComponentWithParams { params: EditTypePropertiesVmParams ->
+ DaggerEditTypePropertiesComponent
+ .factory()
+ .create(params, findComponentDependencies())
+ }
+
class Component(private val builder: () -> T) {
private var instance: T? = null
diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/MainEntryDI.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/MainEntryDI.kt
index 6629a9b244..956ced5904 100644
--- a/app/src/main/java/com/anytypeio/anytype/di/feature/MainEntryDI.kt
+++ b/app/src/main/java/com/anytypeio/anytype/di/feature/MainEntryDI.kt
@@ -75,7 +75,9 @@ object MainEntryModule {
awaitAccountStartManager: AwaitAccountStartManager,
membershipProvider: MembershipProvider,
globalSubscriptionManager: GlobalSubscriptionManager,
- spaceInviteResolver: SpaceInviteResolver
+ spaceInviteResolver: SpaceInviteResolver,
+ spaceManager: SpaceManager,
+ spaceViewSubscriptionContainer: SpaceViewSubscriptionContainer
): MainViewModelFactory = MainViewModelFactory(
resumeAccount = resumeAccount,
analytics = analytics,
@@ -93,7 +95,9 @@ object MainEntryModule {
awaitAccountStartManager = awaitAccountStartManager,
membershipProvider = membershipProvider,
globalSubscriptionManager = globalSubscriptionManager,
- spaceInviteResolver = spaceInviteResolver
+ spaceInviteResolver = spaceInviteResolver,
+ spaceManager = spaceManager,
+ spaceViews = spaceViewSubscriptionContainer
)
@JvmStatic
diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/ObjectMenuDI.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/ObjectMenuDI.kt
index 100a3caece..72b11cb683 100644
--- a/app/src/main/java/com/anytypeio/anytype/di/feature/ObjectMenuDI.kt
+++ b/app/src/main/java/com/anytypeio/anytype/di/feature/ObjectMenuDI.kt
@@ -16,6 +16,7 @@ import com.anytypeio.anytype.domain.misc.DeepLinkResolver
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.multiplayer.GetSpaceInviteLink
import com.anytypeio.anytype.domain.multiplayer.SpaceViewSubscriptionContainer
+import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider
import com.anytypeio.anytype.domain.`object`.DuplicateObject
import com.anytypeio.anytype.domain.`object`.SetObjectDetails
import com.anytypeio.anytype.domain.objects.SetObjectListIsArchived
@@ -23,6 +24,8 @@ import com.anytypeio.anytype.domain.page.AddBackLinkToObject
import com.anytypeio.anytype.domain.page.CloseBlock
import com.anytypeio.anytype.domain.page.OpenPage
import com.anytypeio.anytype.domain.primitives.FieldParser
+import com.anytypeio.anytype.domain.relations.AddToFeaturedRelations
+import com.anytypeio.anytype.domain.relations.RemoveFromFeaturedRelations
import com.anytypeio.anytype.domain.templates.CreateTemplateFromObject
import com.anytypeio.anytype.domain.widgets.CreateWidget
import com.anytypeio.anytype.domain.workspace.SpaceManager
@@ -122,7 +125,10 @@ object ObjectMenuModule {
setObjectIsArchived: SetObjectListIsArchived,
fieldParser: FieldParser,
spaceViewSubscriptionContainer: SpaceViewSubscriptionContainer,
- getSpaceInviteLink: GetSpaceInviteLink
+ getSpaceInviteLink: GetSpaceInviteLink,
+ addToFeaturedRelations: AddToFeaturedRelations,
+ removeFromFeaturedRelations: RemoveFromFeaturedRelations,
+ userPermissionProvider: UserPermissionProvider
): ObjectMenuViewModel.Factory = ObjectMenuViewModel.Factory(
setObjectIsArchived = setObjectIsArchived,
duplicateObject = duplicateObject,
@@ -147,7 +153,10 @@ object ObjectMenuModule {
setObjectListIsFavorite = setObjectListIsFavorite,
fieldParser = fieldParser,
getSpaceInviteLink = getSpaceInviteLink,
- spaceViewSubscriptionContainer = spaceViewSubscriptionContainer
+ spaceViewSubscriptionContainer = spaceViewSubscriptionContainer,
+ addToFeaturedRelations = addToFeaturedRelations,
+ removeFromFeaturedRelations = removeFromFeaturedRelations,
+ userPermissionProvider = userPermissionProvider
)
@JvmStatic
@@ -214,6 +223,18 @@ object ObjectMenuModule {
repo: BlockRepository,
dispatchers: AppCoroutineDispatchers
): SetObjectListIsArchived = SetObjectListIsArchived(repo = repo, dispatchers = dispatchers)
+
+ @JvmStatic
+ @Provides
+ @PerDialog
+ fun addToFeaturedRelations(repo: BlockRepository): AddToFeaturedRelations =
+ AddToFeaturedRelations(repo)
+
+ @JvmStatic
+ @Provides
+ @PerDialog
+ fun removeFromFeaturedRelations(repo: BlockRepository): RemoveFromFeaturedRelations =
+ RemoveFromFeaturedRelations(repo)
}
@Module
@@ -242,7 +263,10 @@ object ObjectSetMenuModule {
setObjectIsArchived: SetObjectListIsArchived,
fieldParser: FieldParser,
getSpaceInviteLink: GetSpaceInviteLink,
- spaceViewSubscriptionContainer: SpaceViewSubscriptionContainer
+ spaceViewSubscriptionContainer: SpaceViewSubscriptionContainer,
+ addToFeaturedRelations: AddToFeaturedRelations,
+ removeFromFeaturedRelations: RemoveFromFeaturedRelations,
+ userPermissionProvider: UserPermissionProvider
): ObjectSetMenuViewModel.Factory = ObjectSetMenuViewModel.Factory(
setObjectListIsArchived = setObjectIsArchived,
addBackLinkToObject = addBackLinkToObject,
@@ -263,7 +287,10 @@ object ObjectSetMenuModule {
setObjectListIsFavorite = setObjectListIsFavorite,
fieldParser = fieldParser,
getSpaceInviteLink = getSpaceInviteLink,
- spaceViewSubscriptionContainer = spaceViewSubscriptionContainer
+ spaceViewSubscriptionContainer = spaceViewSubscriptionContainer,
+ addToFeaturedRelations = addToFeaturedRelations,
+ removeFromFeaturedRelations = removeFromFeaturedRelations,
+ userPermissionProvider = userPermissionProvider
)
@JvmStatic
@@ -333,4 +360,16 @@ object ObjectSetMenuModule {
)
}
}
+
+ @JvmStatic
+ @Provides
+ @PerDialog
+ fun addToFeaturedRelations(repo: BlockRepository): AddToFeaturedRelations =
+ AddToFeaturedRelations(repo)
+
+ @JvmStatic
+ @Provides
+ @PerDialog
+ fun removeFromFeaturedRelations(repo: BlockRepository): RemoveFromFeaturedRelations =
+ RemoveFromFeaturedRelations(repo)
}
\ No newline at end of file
diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/ObjectRelationListDI.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/ObjectRelationListDI.kt
index 444fc471df..83f28f6106 100644
--- a/app/src/main/java/com/anytypeio/anytype/di/feature/ObjectRelationListDI.kt
+++ b/app/src/main/java/com/anytypeio/anytype/di/feature/ObjectRelationListDI.kt
@@ -3,11 +3,16 @@ package com.anytypeio.anytype.di.feature
import com.anytypeio.anytype.analytics.base.Analytics
import com.anytypeio.anytype.core_models.Payload
import com.anytypeio.anytype.core_utils.di.scope.PerModal
+import com.anytypeio.anytype.core_utils.di.scope.PerScreen
+import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.block.repo.BlockRepository
import com.anytypeio.anytype.domain.misc.UrlBuilder
+import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider
import com.anytypeio.anytype.domain.`object`.UpdateDetail
+import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes
import com.anytypeio.anytype.domain.objects.StoreOfRelations
import com.anytypeio.anytype.domain.primitives.FieldParser
+import com.anytypeio.anytype.domain.primitives.SetObjectTypeRecommendedFields
import com.anytypeio.anytype.domain.relations.AddRelationToObject
import com.anytypeio.anytype.domain.relations.AddToFeaturedRelations
import com.anytypeio.anytype.domain.relations.DeleteRelationFromObject
@@ -18,6 +23,7 @@ import com.anytypeio.anytype.presentation.relations.ObjectRelationListViewModelF
import com.anytypeio.anytype.presentation.relations.RelationListViewModel
import com.anytypeio.anytype.presentation.relations.providers.ObjectRelationListProvider
import com.anytypeio.anytype.presentation.util.Dispatcher
+import com.anytypeio.anytype.ui.primitives.ObjectFieldsFragment
import com.anytypeio.anytype.ui.relations.ObjectRelationListFragment
import dagger.BindsInstance
import dagger.Module
@@ -37,6 +43,7 @@ interface ObjectRelationListComponent {
}
fun inject(fragment: ObjectRelationListFragment)
+ fun inject(fragment: ObjectFieldsFragment)
}
@Module
@@ -56,9 +63,12 @@ object ObjectRelationListModule {
deleteRelationFromObject: DeleteRelationFromObject,
analytics: Analytics,
storeOfRelations: StoreOfRelations,
+ storeOfObjectTypes: StoreOfObjectTypes,
addRelationToObject: AddRelationToObject,
analyticSpaceHelperDelegate: AnalyticSpaceHelperDelegate,
fieldParser: FieldParser,
+ userPermissionProvider: UserPermissionProvider,
+ setObjectTypeRecommendedFields: SetObjectTypeRecommendedFields
): ObjectRelationListViewModelFactory {
return ObjectRelationListViewModelFactory(
vmParams = vmParams,
@@ -72,9 +82,12 @@ object ObjectRelationListModule {
deleteRelationFromObject = deleteRelationFromObject,
analytics = analytics,
storeOfRelations = storeOfRelations,
+ storeOfObjectTypes = storeOfObjectTypes,
addRelationToObject = addRelationToObject,
analyticSpaceHelperDelegate = analyticSpaceHelperDelegate,
fieldParser = fieldParser,
+ userPermissionProvider = userPermissionProvider,
+ setObjectTypeRecommendedFields = setObjectTypeRecommendedFields
)
}
@@ -95,4 +108,12 @@ object ObjectRelationListModule {
@PerModal
fun deleteRelationFromObject(repo: BlockRepository): DeleteRelationFromObject =
DeleteRelationFromObject(repo)
+
+ @JvmStatic
+ @Provides
+ @PerModal
+ fun provideTypeSetRecommendedFields(
+ repo: BlockRepository,
+ dispatchers: AppCoroutineDispatchers
+ ): SetObjectTypeRecommendedFields = SetObjectTypeRecommendedFields(repo, dispatchers)
}
\ No newline at end of file
diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/PrimitivesObjectTypeDI.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/PrimitivesObjectTypeDI.kt
new file mode 100644
index 0000000000..0bcd0f3b0b
--- /dev/null
+++ b/app/src/main/java/com/anytypeio/anytype/di/feature/PrimitivesObjectTypeDI.kt
@@ -0,0 +1,166 @@
+package com.anytypeio.anytype.di.feature
+
+import androidx.lifecycle.ViewModelProvider
+import com.anytypeio.anytype.analytics.base.Analytics
+import com.anytypeio.anytype.core_utils.di.scope.PerScreen
+import com.anytypeio.anytype.di.common.ComponentDependencies
+import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
+import com.anytypeio.anytype.domain.block.repo.BlockRepository
+import com.anytypeio.anytype.domain.config.ConfigStorage
+import com.anytypeio.anytype.domain.config.UserSettingsRepository
+import com.anytypeio.anytype.domain.debugging.Logger
+import com.anytypeio.anytype.domain.event.interactor.EventChannel
+import com.anytypeio.anytype.domain.event.interactor.SpaceSyncAndP2PStatusProvider
+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.`object`.DuplicateObjects
+import com.anytypeio.anytype.domain.`object`.SetObjectDetails
+import com.anytypeio.anytype.domain.objects.DeleteObjects
+import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes
+import com.anytypeio.anytype.domain.objects.StoreOfRelations
+import com.anytypeio.anytype.domain.primitives.FieldParser
+import com.anytypeio.anytype.domain.primitives.GetObjectTypeConflictingFields
+import com.anytypeio.anytype.domain.primitives.SetObjectTypeHeaderRecommendedFields
+import com.anytypeio.anytype.domain.primitives.SetObjectTypeRecommendedFields
+import com.anytypeio.anytype.domain.resources.StringResourceProvider
+import com.anytypeio.anytype.domain.search.SubscriptionEventChannel
+import com.anytypeio.anytype.feature_object_type.ui.ObjectTypeVmParams
+import com.anytypeio.anytype.feature_object_type.viewmodel.ObjectTypeVMFactory
+import com.anytypeio.anytype.presentation.analytics.AnalyticSpaceHelperDelegate
+import com.anytypeio.anytype.presentation.editor.cover.CoverImageHashProvider
+import com.anytypeio.anytype.providers.DefaultCoverImageHashProvider
+import com.anytypeio.anytype.ui.primitives.ObjectTypeFieldsFragment
+import com.anytypeio.anytype.ui.primitives.ObjectTypeFragment
+import dagger.Binds
+import dagger.BindsInstance
+import dagger.Component
+import dagger.Module
+import dagger.Provides
+
+@Component(
+ dependencies = [ObjectTypeDependencies::class],
+ modules = [
+ ObjectTypeModule::class,
+ ObjectTypeModule.Declarations::class
+ ]
+)
+@PerScreen
+interface ObjectTypeComponent {
+ @Component.Factory
+ interface Factory {
+ fun create(
+ @BindsInstance vmParams: ObjectTypeVmParams,
+ dependencies: ObjectTypeDependencies
+ ): ObjectTypeComponent
+ }
+
+ fun inject(fragment: ObjectTypeFragment)
+ fun inject(fragment: ObjectTypeFieldsFragment)
+}
+
+@Module
+object ObjectTypeModule {
+
+ @JvmStatic
+ @Provides
+ @PerScreen
+ fun provideStoreLessSubscriptionContainer(
+ repo: BlockRepository,
+ channel: SubscriptionEventChannel,
+ dispatchers: AppCoroutineDispatchers,
+ logger: Logger
+ ): StorelessSubscriptionContainer = StorelessSubscriptionContainer.Impl(
+ repo = repo,
+ channel = channel,
+ dispatchers = dispatchers,
+ logger = logger
+ )
+
+ @JvmStatic
+ @Provides
+ @PerScreen
+ fun provideUpdateDetailUseCase(
+ repository: BlockRepository,
+ dispatchers: AppCoroutineDispatchers
+ ): SetObjectDetails = SetObjectDetails(repository, dispatchers)
+
+ @JvmStatic
+ @Provides
+ @PerScreen
+ fun coverHashProvider(): CoverImageHashProvider = DefaultCoverImageHashProvider()
+
+ @JvmStatic
+ @PerScreen
+ @Provides
+ fun getDeleteObjects(
+ repo: BlockRepository,
+ dispatchers: AppCoroutineDispatchers
+ ): DeleteObjects = DeleteObjects(repo, dispatchers)
+
+ @JvmStatic
+ @PerScreen
+ @Provides
+ fun getObjectTypeConflictingFields(
+ repo: BlockRepository,
+ dispatchers: AppCoroutineDispatchers
+ ): GetObjectTypeConflictingFields = GetObjectTypeConflictingFields(repo, dispatchers)
+
+ @JvmStatic
+ @Provides
+ @PerScreen
+ fun provideDuplicateObjectsListUseCase(
+ repo: BlockRepository,
+ dispatchers: AppCoroutineDispatchers
+ ): DuplicateObjects = DuplicateObjects(
+ repo = repo,
+ dispatchers = dispatchers
+ )
+
+ @JvmStatic
+ @Provides
+ @PerScreen
+ fun provideTypeSetRecommendedFields(
+ repo: BlockRepository,
+ dispatchers: AppCoroutineDispatchers
+ ): SetObjectTypeRecommendedFields = SetObjectTypeRecommendedFields(repo, dispatchers)
+
+ @JvmStatic
+ @Provides
+ @PerScreen
+ fun provideTypeSetHeaderRecommendedFields(
+ repo: BlockRepository,
+ dispatchers: AppCoroutineDispatchers
+ ): SetObjectTypeHeaderRecommendedFields =
+ SetObjectTypeHeaderRecommendedFields(repo, dispatchers)
+
+ @Module
+ interface Declarations {
+ @PerScreen
+ @Binds
+ fun bindViewModelFactory(
+ factory: ObjectTypeVMFactory
+ ): ViewModelProvider.Factory
+ }
+}
+
+interface ObjectTypeDependencies : ComponentDependencies {
+ fun blockRepository(): BlockRepository
+ fun analytics(): Analytics
+ fun urlBuilder(): UrlBuilder
+ fun dispatchers(): AppCoroutineDispatchers
+ fun storeOfObjectTypes(): StoreOfObjectTypes
+ fun analyticsHelper(): AnalyticSpaceHelperDelegate
+ fun subEventChannel(): SubscriptionEventChannel
+ fun logger(): Logger
+ fun localeProvider(): LocaleProvider
+ fun config(): ConfigStorage
+ fun userPermissionProvider(): UserPermissionProvider
+ fun provideStoreOfRelations(): StoreOfRelations
+ fun provideSpaceSyncAndP2PStatusProvider(): SpaceSyncAndP2PStatusProvider
+ fun provideUserSettingsRepository(): UserSettingsRepository
+ fun fieldParser(): FieldParser
+ fun provideEventChannel(): EventChannel
+ fun provideStringResourceProvider(): StringResourceProvider
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/PropertiesDI.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/PropertiesDI.kt
new file mode 100644
index 0000000000..c588f67aeb
--- /dev/null
+++ b/app/src/main/java/com/anytypeio/anytype/di/feature/PropertiesDI.kt
@@ -0,0 +1,88 @@
+package com.anytypeio.anytype.di.feature
+
+import androidx.lifecycle.ViewModelProvider
+import com.anytypeio.anytype.core_utils.di.scope.PerModal
+import com.anytypeio.anytype.di.common.ComponentDependencies
+import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
+import com.anytypeio.anytype.domain.block.repo.BlockRepository
+import com.anytypeio.anytype.domain.`object`.SetObjectDetails
+import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes
+import com.anytypeio.anytype.domain.objects.StoreOfRelations
+import com.anytypeio.anytype.domain.primitives.SetObjectTypeRecommendedFields
+import com.anytypeio.anytype.domain.relations.CreateRelation
+import com.anytypeio.anytype.domain.resources.StringResourceProvider
+import com.anytypeio.anytype.feature_properties.EditTypePropertiesViewModelFactory
+import com.anytypeio.anytype.feature_properties.add.EditTypePropertiesVmParams
+import com.anytypeio.anytype.ui.primitives.EditTypePropertiesFragment
+import dagger.Binds
+import dagger.BindsInstance
+import dagger.Component
+import dagger.Module
+import dagger.Provides
+
+//region EDIT OBJECT TYPE PROPERTIES SCREEN
+@PerModal
+@Component(
+ modules = [
+ EditTypePropertiesModule::class,
+ EditTypePropertiesModule.Declarations::class
+ ],
+ dependencies = [EditTypePropertiesDependencies::class]
+)
+interface EditTypePropertiesComponent {
+ @Component.Factory
+ interface Factory {
+ fun create(
+ @BindsInstance vmParams: EditTypePropertiesVmParams,
+ dependencies: EditTypePropertiesDependencies
+ ): EditTypePropertiesComponent
+ }
+
+ fun inject(fragment: EditTypePropertiesFragment)
+}
+
+@Module
+object EditTypePropertiesModule {
+
+ @JvmStatic
+ @Provides
+ @PerModal
+ fun provideTypeSetRecommendedFields(
+ repo: BlockRepository,
+ dispatchers: AppCoroutineDispatchers
+ ): SetObjectTypeRecommendedFields = SetObjectTypeRecommendedFields(repo, dispatchers)
+
+ @JvmStatic
+ @Provides
+ @PerModal
+ fun createRelation(
+ repo: BlockRepository,
+ storeOfRelations: StoreOfRelations,
+ ) = CreateRelation(repo, storeOfRelations)
+
+ @JvmStatic
+ @Provides
+ @PerModal
+ fun provideSetObjectDetails(
+ repo: BlockRepository,
+ dispatchers: AppCoroutineDispatchers
+ ): SetObjectDetails = SetObjectDetails(repo, dispatchers)
+
+ @Module
+ interface Declarations {
+ @PerModal
+ @Binds
+ fun bindViewModelFactory(
+ factory: EditTypePropertiesViewModelFactory
+ ): ViewModelProvider.Factory
+ }
+}
+
+interface EditTypePropertiesDependencies : ComponentDependencies {
+ fun provideStringResourceProvider(): StringResourceProvider
+ fun provideStoreOfRelations(): StoreOfRelations
+ fun provideStoreOfObjectTypes(): StoreOfObjectTypes
+ fun provideBlockRepository(): BlockRepository
+ fun provideAppCoroutineDispatchers(): AppCoroutineDispatchers
+}
+//endregion
\ No newline at end of file
diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/SplashDi.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/SplashDi.kt
index 62cdf8fffe..784dd274fc 100644
--- a/app/src/main/java/com/anytypeio/anytype/di/feature/SplashDi.kt
+++ b/app/src/main/java/com/anytypeio/anytype/di/feature/SplashDi.kt
@@ -33,6 +33,7 @@ import com.anytypeio.anytype.domain.subscriptions.GlobalSubscriptionManager
import com.anytypeio.anytype.domain.templates.GetTemplates
import com.anytypeio.anytype.domain.workspace.SpaceManager
import com.anytypeio.anytype.presentation.analytics.AnalyticSpaceHelperDelegate
+import com.anytypeio.anytype.presentation.auth.account.MigrationHelperDelegate
import com.anytypeio.anytype.presentation.splash.SplashViewModelFactory
import com.anytypeio.anytype.ui.splash.SplashFragment
import dagger.Binds
@@ -178,6 +179,12 @@ object SplashModule {
@PerScreen
@Binds
fun bindViewModelFactory(factory: SplashViewModelFactory): ViewModelProvider.Factory
+
+ @Binds
+ @PerScreen
+ fun bindMigrationHelperDelegate(
+ impl: MigrationHelperDelegate.Impl
+ ): MigrationHelperDelegate
}
}
diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/chats/ChatReactionDI.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/chats/ChatReactionDI.kt
index 5bb8654b8f..fee6b9ad75 100644
--- a/app/src/main/java/com/anytypeio/anytype/di/feature/chats/ChatReactionDI.kt
+++ b/app/src/main/java/com/anytypeio/anytype/di/feature/chats/ChatReactionDI.kt
@@ -3,6 +3,7 @@ package com.anytypeio.anytype.di.feature.chats
import androidx.lifecycle.ViewModelProvider
import com.anytypeio.anytype.core_utils.di.scope.PerScreen
import com.anytypeio.anytype.di.common.ComponentDependencies
+import com.anytypeio.anytype.domain.auth.repo.AuthRepository
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.block.repo.BlockRepository
import com.anytypeio.anytype.domain.misc.UrlBuilder
@@ -50,6 +51,7 @@ object ChatReactionModule {
interface ChatReactionDependencies : ComponentDependencies {
fun dispatchers(): AppCoroutineDispatchers
fun repo(): BlockRepository
+ fun auth(): AuthRepository
fun urlBuilder(): UrlBuilder
fun members(): ActiveSpaceMemberSubscriptionContainer
}
\ No newline at end of file
diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/onboarding/login/OnboardingMnemonicLoginDI.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/onboarding/login/OnboardingMnemonicLoginDI.kt
index 65b6d247a8..a2d8ee263c 100644
--- a/app/src/main/java/com/anytypeio/anytype/di/feature/onboarding/login/OnboardingMnemonicLoginDI.kt
+++ b/app/src/main/java/com/anytypeio/anytype/di/feature/onboarding/login/OnboardingMnemonicLoginDI.kt
@@ -22,6 +22,7 @@ import com.anytypeio.anytype.domain.platform.InitialParamsProvider
import com.anytypeio.anytype.domain.spaces.SpaceDeletedStatusWatcher
import com.anytypeio.anytype.domain.subscriptions.GlobalSubscriptionManager
import com.anytypeio.anytype.domain.workspace.SpaceManager
+import com.anytypeio.anytype.presentation.auth.account.MigrationHelperDelegate
import com.anytypeio.anytype.presentation.onboarding.login.OnboardingMnemonicLoginViewModel
import com.anytypeio.anytype.presentation.util.downloader.UriFileProvider
import com.anytypeio.anytype.providers.DefaultUriFileProvider
@@ -74,6 +75,12 @@ object OnboardingMnemonicLoginModule {
defaultProvider: DefaultUriFileProvider
): UriFileProvider
+ @Binds
+ @PerScreen
+ fun bindMigrationHelperDelegate(
+ impl: MigrationHelperDelegate.Impl
+ ): MigrationHelperDelegate
+
@Binds
@PerScreen
fun bindViewModelFactory(
diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/settings/DebugDI.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/settings/DebugDI.kt
new file mode 100644
index 0000000000..720f511042
--- /dev/null
+++ b/app/src/main/java/com/anytypeio/anytype/di/feature/settings/DebugDI.kt
@@ -0,0 +1,49 @@
+package com.anytypeio.anytype.di.feature.settings
+
+import androidx.lifecycle.ViewModelProvider
+import com.anytypeio.anytype.core_utils.di.scope.PerScreen
+import com.anytypeio.anytype.di.common.ComponentDependencies
+import com.anytypeio.anytype.domain.auth.repo.AuthRepository
+import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
+import com.anytypeio.anytype.domain.device.PathProvider
+import com.anytypeio.anytype.presentation.settings.DebugViewModel
+import com.anytypeio.anytype.ui.settings.DebugFragment
+import dagger.Binds
+import dagger.Component
+import dagger.Module
+
+@Component(
+ dependencies = [DebugDependencies::class],
+ modules = [
+ DebugModule::class,
+ DebugModule.Declarations::class
+ ]
+)
+@PerScreen
+interface DebugComponent {
+
+ @Component.Factory
+ interface Factory {
+ fun create(dependencies: DebugDependencies): DebugComponent
+ }
+
+ fun inject(fragment: DebugFragment)
+}
+
+@Module
+object DebugModule {
+ @Module
+ interface Declarations {
+ @PerScreen
+ @Binds
+ fun bindViewModelFactory(
+ factory: DebugViewModel.Factory
+ ): ViewModelProvider.Factory
+ }
+}
+
+interface DebugDependencies : ComponentDependencies {
+ fun path(): PathProvider
+ fun auth(): AuthRepository
+ fun dispatchers(): AppCoroutineDispatchers
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/update/MigrationErrorDI.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/update/MigrationErrorDI.kt
deleted file mode 100644
index 2757859829..0000000000
--- a/app/src/main/java/com/anytypeio/anytype/di/feature/update/MigrationErrorDI.kt
+++ /dev/null
@@ -1,48 +0,0 @@
-package com.anytypeio.anytype.di.feature.update
-
-import androidx.lifecycle.ViewModelProvider
-import com.anytypeio.anytype.analytics.base.Analytics
-import com.anytypeio.anytype.core_utils.di.scope.PerScreen
-import com.anytypeio.anytype.di.common.ComponentDependencies
-import com.anytypeio.anytype.presentation.update.MigrationErrorViewModel
-import com.anytypeio.anytype.ui.update.MigrationErrorFragment
-import dagger.Binds
-import dagger.Component
-import dagger.Module
-
-@Component(
- dependencies = [MigrationErrorDependencies::class],
- modules = [
- MigrationErrorModule::class,
- MigrationErrorModule.Declarations::class
- ]
-)
-@PerScreen
-interface MigrationErrorComponent {
-
- @Component.Factory
- interface Factory {
- fun create(dependencies: MigrationErrorDependencies): MigrationErrorComponent
- }
-
- fun inject(fragment: MigrationErrorFragment)
-}
-
-@Module
-object MigrationErrorModule {
-
- @Module
- interface Declarations {
-
- @PerScreen
- @Binds
- fun bindViewModelFactory(
- factory: MigrationErrorViewModel.Factory
- ): ViewModelProvider.Factory
-
- }
-}
-
-interface MigrationErrorDependencies : ComponentDependencies {
- fun analytics(): Analytics
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/anytypeio/anytype/di/main/MainComponent.kt b/app/src/main/java/com/anytypeio/anytype/di/main/MainComponent.kt
index d8e7fc314a..a49364bf25 100644
--- a/app/src/main/java/com/anytypeio/anytype/di/main/MainComponent.kt
+++ b/app/src/main/java/com/anytypeio/anytype/di/main/MainComponent.kt
@@ -3,6 +3,7 @@ package com.anytypeio.anytype.di.main
import com.anytypeio.anytype.app.AndroidApplication
import com.anytypeio.anytype.di.common.ComponentDependencies
import com.anytypeio.anytype.di.common.ComponentDependenciesKey
+import com.anytypeio.anytype.di.feature.EditTypePropertiesDependencies
import com.anytypeio.anytype.di.feature.AllContentDependencies
import com.anytypeio.anytype.di.feature.AppPreferencesDependencies
import com.anytypeio.anytype.di.feature.BacklinkOrAddToObjectDependencies
@@ -17,12 +18,13 @@ import com.anytypeio.anytype.di.feature.MainEntrySubComponent
import com.anytypeio.anytype.di.feature.MoveToDependencies
import com.anytypeio.anytype.di.feature.ObjectSetSubComponent
import com.anytypeio.anytype.di.feature.ObjectTypeChangeSubComponent
+import com.anytypeio.anytype.di.feature.ObjectTypeDependencies
import com.anytypeio.anytype.di.feature.PersonalizationSettingsSubComponent
import com.anytypeio.anytype.di.feature.SplashDependencies
import com.anytypeio.anytype.di.feature.auth.DeletedAccountDependencies
+import com.anytypeio.anytype.di.feature.chats.ChatComponentDependencies
import com.anytypeio.anytype.di.feature.chats.ChatReactionDependencies
import com.anytypeio.anytype.di.feature.chats.SelectChatReactionDependencies
-import com.anytypeio.anytype.di.feature.chats.ChatComponentDependencies
import com.anytypeio.anytype.di.feature.gallery.GalleryInstallationComponentDependencies
import com.anytypeio.anytype.di.feature.home.HomeScreenDependencies
import com.anytypeio.anytype.di.feature.membership.MembershipComponentDependencies
@@ -43,6 +45,7 @@ import com.anytypeio.anytype.di.feature.relations.RelationEditDependencies
import com.anytypeio.anytype.di.feature.search.GlobalSearchDependencies
import com.anytypeio.anytype.di.feature.settings.AboutAppDependencies
import com.anytypeio.anytype.di.feature.settings.AppearanceDependencies
+import com.anytypeio.anytype.di.feature.settings.DebugDependencies
import com.anytypeio.anytype.di.feature.settings.FilesStorageDependencies
import com.anytypeio.anytype.di.feature.settings.LogoutWarningSubComponent
import com.anytypeio.anytype.di.feature.settings.ProfileSubComponent
@@ -57,7 +60,6 @@ import com.anytypeio.anytype.di.feature.templates.TemplateSelectDependencies
import com.anytypeio.anytype.di.feature.types.CreateObjectTypeDependencies
import com.anytypeio.anytype.di.feature.types.TypeEditDependencies
import com.anytypeio.anytype.di.feature.types.TypeIconPickDependencies
-import com.anytypeio.anytype.di.feature.update.MigrationErrorDependencies
import com.anytypeio.anytype.di.feature.vault.VaultComponentDependencies
import com.anytypeio.anytype.di.feature.wallpaper.WallpaperSelectSubComponent
import com.anytypeio.anytype.di.feature.widgets.SelectWidgetSourceDependencies
@@ -104,7 +106,6 @@ interface MainComponent :
RelationEditDependencies,
SplashDependencies,
DeletedAccountDependencies,
- MigrationErrorDependencies,
BacklinkOrAddToObjectDependencies,
FilesStorageDependencies,
OnboardingDependencies,
@@ -139,9 +140,12 @@ interface MainComponent :
LinkToObjectDependencies,
MoveToDependencies,
DateObjectDependencies,
+ ObjectTypeDependencies,
SelectChatReactionDependencies,
ChatReactionDependencies,
- ParticipantComponentDependencies
+ ParticipantComponentDependencies,
+ EditTypePropertiesDependencies,
+ DebugDependencies
{
fun inject(app: AndroidApplication)
@@ -218,11 +222,6 @@ abstract class ComponentDependenciesModule {
@ComponentDependenciesKey(DeletedAccountDependencies::class)
abstract fun provideDeletedAccountDependencies(component: MainComponent): ComponentDependencies
- @Binds
- @IntoMap
- @ComponentDependenciesKey(MigrationErrorDependencies::class)
- abstract fun migrationErrorDependencies(component: MainComponent): ComponentDependencies
-
@Binds
@IntoMap
@ComponentDependenciesKey(BacklinkOrAddToObjectDependencies::class)
@@ -393,6 +392,11 @@ abstract class ComponentDependenciesModule {
@ComponentDependenciesKey(DateObjectDependencies::class)
abstract fun provideDateObjectDependencies(component: MainComponent): ComponentDependencies
+ @Binds
+ @IntoMap
+ @ComponentDependenciesKey(ObjectTypeDependencies::class)
+ abstract fun provideObjectTypeDependencies(component: MainComponent): ComponentDependencies
+
@Binds
@IntoMap
@ComponentDependenciesKey(SelectChatReactionDependencies::class)
@@ -407,4 +411,14 @@ abstract class ComponentDependenciesModule {
@IntoMap
@ComponentDependenciesKey(ParticipantComponentDependencies::class)
abstract fun provideParticipantComponentDependencies(component: MainComponent): ComponentDependencies
+
+ @Binds
+ @IntoMap
+ @ComponentDependenciesKey(DebugDependencies::class)
+ abstract fun provideDebugDependencies(component: MainComponent): ComponentDependencies
+
+ @Binds
+ @IntoMap
+ @ComponentDependenciesKey(EditTypePropertiesDependencies::class)
+ abstract fun provideEditTypePropertiesDependencies(component: MainComponent): ComponentDependencies
}
\ No newline at end of file
diff --git a/app/src/main/java/com/anytypeio/anytype/navigation/Navigator.kt b/app/src/main/java/com/anytypeio/anytype/navigation/Navigator.kt
index 055260ce89..3252c2d59b 100644
--- a/app/src/main/java/com/anytypeio/anytype/navigation/Navigator.kt
+++ b/app/src/main/java/com/anytypeio/anytype/navigation/Navigator.kt
@@ -16,7 +16,9 @@ import com.anytypeio.anytype.ui.date.DateObjectFragment
import com.anytypeio.anytype.ui.editor.EditorFragment
import com.anytypeio.anytype.ui.editor.EditorModalFragment
import com.anytypeio.anytype.ui.multiplayer.ShareSpaceFragment
+import com.anytypeio.anytype.ui.primitives.ObjectTypeFieldsFragment
import com.anytypeio.anytype.ui.profile.ParticipantFragment
+import com.anytypeio.anytype.ui.primitives.ObjectTypeFragment
import com.anytypeio.anytype.ui.relations.RelationCreateFromScratchForObjectFragment
import com.anytypeio.anytype.ui.relations.RelationEditFragment
import com.anytypeio.anytype.ui.search.GlobalSearchFragment
@@ -258,18 +260,6 @@ class Navigator : AppNavigation {
navController?.navigate(R.id.actionLogout)
}
- override fun migrationErrorScreen() {
- navController?.navigate(R.id.migrationNeededScreen)
- }
-
- override fun exitFromMigrationScreen() {
- navController?.navigate(R.id.onboarding_nav, null, navOptions {
- popUpTo(R.id.migrationNeededScreen) {
- inclusive = true
- }
- })
- }
-
override fun openRemoteFilesManageScreen(subscription: Id, space: Id) {
navController?.navigate(
resId = R.id.remoteStorageFragment,
@@ -369,4 +359,30 @@ class Navigator : AppNavigation {
)
)
}
+
+ override fun openObjectType(
+ objectId: Id,
+ space: Id
+ ) {
+ navController?.navigate(
+ resId = R.id.objectTypeScreen,
+ args = ObjectTypeFragment.args(
+ objectId = objectId,
+ space = space
+ )
+ )
+ }
+
+ override fun openCurrentObjectTypeFields(
+ objectId: Id,
+ space: Id
+ ) {
+ navController?.navigate(
+ resId = R.id.objectTypeFieldsScreen,
+ args = ObjectTypeFieldsFragment.args(
+ objectId = objectId,
+ space = space
+ )
+ )
+ }
}
diff --git a/app/src/main/java/com/anytypeio/anytype/other/Deeplinks.kt b/app/src/main/java/com/anytypeio/anytype/other/Deeplinks.kt
index cc10d296a9..977c80d1e6 100644
--- a/app/src/main/java/com/anytypeio/anytype/other/Deeplinks.kt
+++ b/app/src/main/java/com/anytypeio/anytype/other/Deeplinks.kt
@@ -6,29 +6,31 @@ import com.anytypeio.anytype.core_models.Url
import com.anytypeio.anytype.core_models.primitives.SpaceId
import com.anytypeio.anytype.domain.misc.DeepLinkResolver
import com.anytypeio.anytype.domain.multiplayer.SpaceInviteResolver
+import timber.log.Timber
const val DEEP_LINK_PATTERN = "anytype://"
const val DEEP_LINK_INVITE_DOMAIN = "invite.any.coop"
+const val DEEP_LINK_TO_OBJECT_BASE_URL = "https://object.any.coop"
+
/**
* Regex pattern for matching
*/
const val DEEP_LINK_INVITE_REG_EXP = "invite.any.coop/([a-zA-Z0-9]+)#([a-zA-Z0-9]+)"
+const val DEEP_LINK_TO_OBJECT_REG_EXP = """object\.any\.coop/([a-zA-Z0-9?=&._-]+)"""
const val DEE_LINK_INVITE_CUSTOM_REG_EXP = "anytype://invite/\\?cid=([a-zA-Z0-9]+)&key=([a-zA-Z0-9]+)"
const val MAIN_PATH = "main"
const val OBJECT_PATH = "object"
const val IMPORT_PATH = "import"
-const val INVITE_PATH = "invite"
const val MEMBERSHIP_PATH = "membership"
const val TYPE_PARAM = "type"
const val OBJECT_ID_PARAM = "objectId"
const val SPACE_ID_PARAM = "spaceId"
-const val CONTENT_ID_PARAM = "cid"
-const val ENCRYPTION_KEY_PARAM = "key"
+const val INVITE_ID_PARAM = "inviteID"
const val SOURCE_PARAM = "source"
const val TYPE_VALUE_EXPERIENCE = "experience"
const val TIER_ID_PARAM = "tier"
@@ -38,62 +40,82 @@ const val IMPORT_EXPERIENCE_DEEPLINK = "$DEEP_LINK_PATTERN$MAIN_PATH/$IMPORT_PAT
object DefaultDeepLinkResolver : DeepLinkResolver {
private val defaultInviteRegex = Regex(DEEP_LINK_INVITE_REG_EXP)
+ private val defaultLinkToObjectRegex = Regex(DEEP_LINK_TO_OBJECT_REG_EXP)
- override fun resolve(
- deeplink: String
- ): DeepLinkResolver.Action = when {
- deeplink.contains(IMPORT_EXPERIENCE_DEEPLINK) -> {
- try {
- val type = Uri.parse(deeplink).getQueryParameter(TYPE_PARAM)
- val source = Uri.parse(deeplink).getQueryParameter(SOURCE_PARAM)
- DeepLinkResolver.Action.Import.Experience(
- type = type.orEmpty(),
- source = source.orEmpty()
- )
- } catch (e: Exception) {
- DeepLinkResolver.Action.Unknown
- }
+ override fun resolve(deeplink: String): DeepLinkResolver.Action {
+ val uri = Uri.parse(deeplink)
+
+ return when {
+ deeplink.contains(IMPORT_EXPERIENCE_DEEPLINK) -> resolveImportExperience(uri)
+ defaultInviteRegex.containsMatchIn(deeplink) -> DeepLinkResolver.Action.Invite(deeplink)
+ defaultLinkToObjectRegex.containsMatchIn(deeplink) -> resolveDeepLinkToObject(uri)
+ deeplink.contains(OBJECT_PATH) -> resolveObjectPath(uri)
+ deeplink.contains(MEMBERSHIP_PATH) -> resolveMembershipPath(uri)
+ else -> DeepLinkResolver.Action.Unknown
+ }.also {
+ Timber.d("Resolving deep link: $deeplink")
}
- deeplink.contains(INVITE_PATH) -> {
- DeepLinkResolver.Action.Invite(deeplink)
+ }
+
+ private fun resolveImportExperience(uri: Uri): DeepLinkResolver.Action {
+ return try {
+ val type = uri.getQueryParameter(TYPE_PARAM).orEmpty()
+ val source = uri.getQueryParameter(SOURCE_PARAM).orEmpty()
+ DeepLinkResolver.Action.Import.Experience(type, source)
+ } catch (e: Exception) {
+ DeepLinkResolver.Action.Unknown
}
- defaultInviteRegex.containsMatchIn(deeplink) -> {
- DeepLinkResolver.Action.Invite(deeplink)
- }
- deeplink.contains(OBJECT_PATH) -> {
- val uri = Uri.parse(deeplink)
- val obj = uri.getQueryParameter(OBJECT_ID_PARAM)
- val space = uri.getQueryParameter(SPACE_ID_PARAM)
- if (!obj.isNullOrEmpty() && !space.isNullOrEmpty()) {
- val cid = uri.getQueryParameter(CONTENT_ID_PARAM)
- val key = uri.getQueryParameter(ENCRYPTION_KEY_PARAM)
- DeepLinkResolver.Action.DeepLinkToObject(
- obj = obj,
- space = SpaceId(space),
- invite = if (!cid.isNullOrEmpty() && !key.isNullOrEmpty()) {
- DeepLinkResolver.Action.DeepLinkToObject.Invite(
- cid = cid,
- key = key
- )
- } else {
- null
- }
- )
- } else {
- DeepLinkResolver.Action.Unknown
- }
- }
- deeplink.contains(MEMBERSHIP_PATH) -> {
- val uri = Uri.parse(deeplink)
- DeepLinkResolver.Action.DeepLinkToMembership(
- tierId = uri.getQueryParameter(TIER_ID_PARAM)
+ }
+
+ private fun resolveDeepLinkToObject(uri: Uri): DeepLinkResolver.Action {
+ val obj = uri.pathSegments.getOrNull(0) ?: return DeepLinkResolver.Action.Unknown
+ val space = uri.getQueryParameter(SPACE_ID_PARAM)?.takeIf { it.isNotEmpty() }
+ ?: return DeepLinkResolver.Action.Unknown // Ensure spaceId is required
+
+ return DeepLinkResolver.Action.DeepLinkToObject(
+ obj = obj,
+ space = SpaceId(space),
+ invite = parseInvite(uri)
+ )
+ }
+
+ private fun resolveObjectPath(uri: Uri): DeepLinkResolver.Action {
+ val obj = uri.getQueryParameter(OBJECT_ID_PARAM)?.takeIf { it.isNotEmpty() }
+ val space = uri.getQueryParameter(SPACE_ID_PARAM)?.takeIf { it.isNotEmpty() }
+ ?: return DeepLinkResolver.Action.Unknown // Ensure spaceId is required
+
+ return if (obj != null) {
+ DeepLinkResolver.Action.DeepLinkToObject(
+ obj = obj,
+ space = SpaceId(space),
+ invite = parseInvite(uri)
)
+ } else {
+ DeepLinkResolver.Action.Unknown
+ }
+ }
+
+ private fun resolveMembershipPath(uri: Uri): DeepLinkResolver.Action {
+ return DeepLinkResolver.Action.DeepLinkToMembership(
+ tierId = uri.getQueryParameter(TIER_ID_PARAM)
+ )
+ }
+
+ private fun parseInvite(uri: Uri): DeepLinkResolver.Action.DeepLinkToObject.Invite? {
+ val inviteId = uri.getQueryParameter(INVITE_ID_PARAM)?.takeIf { it.isNotEmpty() }
+ val encryption = uri.fragment?.takeIf { it.isNotEmpty() }
+ return if (inviteId != null && encryption != null) {
+ DeepLinkResolver.Action.DeepLinkToObject.Invite(
+ key = encryption,
+ cid = inviteId
+ )
+ } else {
+ null
}
- else -> DeepLinkResolver.Action.Unknown
}
override fun createObjectDeepLink(obj: Id, space: SpaceId): Url {
- return "${DEEP_LINK_PATTERN}${OBJECT_PATH}?${OBJECT_ID_PARAM}=$obj&${SPACE_ID_PARAM}=${space.id}"
+ return "$DEEP_LINK_TO_OBJECT_BASE_URL/$obj?$SPACE_ID_PARAM=${space.id}"
}
override fun createObjectDeepLinkWithInvite(
@@ -102,7 +124,7 @@ object DefaultDeepLinkResolver : DeepLinkResolver {
invite: Id,
encryptionKey: String
): Url {
- return "${DEEP_LINK_PATTERN}${OBJECT_PATH}?${OBJECT_ID_PARAM}=$obj&${SPACE_ID_PARAM}=${space.id}&${DefaultSpaceInviteResolver.CONTENT_ID_KEY}=$invite&${DefaultSpaceInviteResolver.FILE_KEY_KEY}=$encryptionKey"
+ return "${DEEP_LINK_TO_OBJECT_BASE_URL}/$obj?${SPACE_ID_PARAM}=${space.id}&${INVITE_ID_PARAM}=$invite#$encryptionKey"
}
override fun isDeepLink(link: String): Boolean {
@@ -139,6 +161,7 @@ object DefaultSpaceInviteResolver : SpaceInviteResolver {
return "https://$DEEP_LINK_INVITE_DOMAIN/$contentId#$encryptionKey"
}
+
private const val CONTENT_INDEX = 1
private const val KEY_INDEX = 2
const val CONTENT_ID_KEY = "cid"
diff --git a/app/src/main/java/com/anytypeio/anytype/other/MediaPermissionHelper.kt b/app/src/main/java/com/anytypeio/anytype/other/MediaPermissionHelper.kt
index 8119086069..761cabd4e6 100644
--- a/app/src/main/java/com/anytypeio/anytype/other/MediaPermissionHelper.kt
+++ b/app/src/main/java/com/anytypeio/anytype/other/MediaPermissionHelper.kt
@@ -44,6 +44,7 @@ class MediaPermissionHelper(
}
fun openFilePicker(mimeType: Mimetype, requestCode: Int?) {
+ Timber.d("openFilePicker, mimeType:$mimeType, requestCode:$requestCode")
if (isRequestInProgress) {
Timber.w("Permission request already in progress")
return
@@ -62,10 +63,12 @@ class MediaPermissionHelper(
val hasPermission = mimeType.hasPermission(context)
if (hasPermission) {
+ Timber.d("Permission already granted")
onPermissionSuccess(mimeType, requestCode)
isRequestInProgress = false
} else {
val permissions = mimeType.getPermissionToRequestByMime()
+ Timber.d("Requesting permissions: $permissions")
if (permissions.isNotEmpty()) {
permissionReadStorage.launch(permissions)
} else {
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/allcontent/AllContentFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/allcontent/AllContentFragment.kt
index 16f1f9879b..2add470436 100644
--- a/app/src/main/java/com/anytypeio/anytype/ui/allcontent/AllContentFragment.kt
+++ b/app/src/main/java/com/anytypeio/anytype/ui/allcontent/AllContentFragment.kt
@@ -207,11 +207,9 @@ class AllContentFragment : BaseComposeFragment(), ObjectTypeSelectionListener {
is AllContentViewModel.Command.OpenTypeEditing -> {
runCatching {
- navigation().openTypeEditingScreen(
- id = command.item.id,
- name = command.item.name,
- icon = (command.item.icon as? ObjectIcon.Basic.Emoji)?.unicode ?: "",
- readOnly = command.item.readOnly
+ navigation().openObjectType(
+ objectId = command.item.id,
+ space = space
)
}.onFailure {
toast("Failed to open type editing screen")
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/base/NavigationRouter.kt b/app/src/main/java/com/anytypeio/anytype/ui/base/NavigationRouter.kt
index 9a1146ec54..3f359498c8 100644
--- a/app/src/main/java/com/anytypeio/anytype/ui/base/NavigationRouter.kt
+++ b/app/src/main/java/com/anytypeio/anytype/ui/base/NavigationRouter.kt
@@ -11,7 +11,6 @@ class NavigationRouter(
Timber.d("Navigate to $command")
try {
when (command) {
- is AppNavigation.Command.ExitFromMigrationScreen -> navigation.exitFromMigrationScreen()
is AppNavigation.Command.OpenSettings -> navigation.openSpaceSettings()
is AppNavigation.Command.OpenObject -> navigation.openDocument(
target = command.target,
@@ -58,7 +57,6 @@ class NavigationRouter(
is AppNavigation.Command.OpenTemplates -> navigation.openTemplatesModal(
typeId = command.typeId
)
- is AppNavigation.Command.MigrationErrorScreen -> navigation.migrationErrorScreen()
is AppNavigation.Command.OpenDateObject -> navigation.openDateObject(
objectId = command.objectId,
space = command.space
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/chats/ChatFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/chats/ChatFragment.kt
index da01f3b6b1..7ca853a84b 100644
--- a/app/src/main/java/com/anytypeio/anytype/ui/chats/ChatFragment.kt
+++ b/app/src/main/java/com/anytypeio/anytype/ui/chats/ChatFragment.kt
@@ -251,6 +251,17 @@ class ChatFragment : BaseComposeFragment() {
Timber.e(it, "Error while opening space member card")
}
}
+ is ChatViewModel.ViewModelCommand.Browse -> {
+ runCatching {
+ proceedWithAction(
+ SystemAction.OpenUrl(
+ command.url
+ )
+ )
+ }.onFailure {
+ Timber.e(it, "Error while opening bookmark from chat")
+ }
+ }
}
}
}
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/editor/EditorFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/editor/EditorFragment.kt
index 998ce32882..7094206448 100644
--- a/app/src/main/java/com/anytypeio/anytype/ui/editor/EditorFragment.kt
+++ b/app/src/main/java/com/anytypeio/anytype/ui/editor/EditorFragment.kt
@@ -121,6 +121,7 @@ import com.anytypeio.anytype.core_utils.ext.toast
import com.anytypeio.anytype.core_utils.ext.visible
import com.anytypeio.anytype.core_utils.ui.showActionableSnackBar
import com.anytypeio.anytype.databinding.FragmentEditorBinding
+import com.anytypeio.anytype.device.launchMediaPicker
import com.anytypeio.anytype.di.common.componentManager
import com.anytypeio.anytype.di.feature.DefaultComponentParam
import com.anytypeio.anytype.ext.extractMarks
@@ -166,7 +167,7 @@ import com.anytypeio.anytype.ui.objects.creation.ObjectTypeSelectionFragment
import com.anytypeio.anytype.ui.objects.creation.ObjectTypeUpdateFragment
import com.anytypeio.anytype.ui.objects.types.pickers.ObjectTypeSelectionListener
import com.anytypeio.anytype.ui.objects.types.pickers.ObjectTypeUpdateListener
-import com.anytypeio.anytype.ui.relations.ObjectRelationListFragment
+import com.anytypeio.anytype.ui.primitives.ObjectFieldsFragment
import com.anytypeio.anytype.ui.relations.RelationAddToObjectBlockFragment
import com.anytypeio.anytype.ui.relations.RelationDateValueFragment
import com.anytypeio.anytype.ui.relations.RelationTextValueFragment
@@ -956,22 +957,20 @@ open class EditorFragment : NavigationFragment(R.layout.f
).showChildFragment()
}
is Command.OpenPhotoPicker -> {
- try {
- pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.ImageOnly))
- } catch (e: Exception) {
- Timber.w(e, "Error while opening photo picker")
- toast("Error while opening photo picker")
- pickerDelegate.openFilePicker(Mimetype.MIME_IMAGE_ALL, null)
- }
+ launchMediaPicker(
+ pickMedia = pickMedia,
+ pickerDelegate = pickerDelegate,
+ mediaType = PickVisualMedia.ImageOnly,
+ fallbackMimeType = Mimetype.MIME_IMAGE_ALL
+ )
}
is Command.OpenVideoPicker -> {
- try {
- pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.VideoOnly))
- } catch (e: Exception) {
- Timber.e(e, "Error while opening video picker")
- toast("Error while opening video picker")
- pickerDelegate.openFilePicker(Mimetype.MIME_VIDEO_ALL, null)
- }
+ launchMediaPicker(
+ pickMedia = pickMedia,
+ pickerDelegate = pickerDelegate,
+ mediaType = PickVisualMedia.VideoOnly,
+ fallbackMimeType = Mimetype.MIME_VIDEO_ALL
+ )
}
is Command.OpenFilePicker -> {
pickerDelegate.openFilePicker(Mimetype.MIME_FILE_ALL, null)
@@ -1075,10 +1074,10 @@ open class EditorFragment : NavigationFragment(R.layout.f
R.id.pageScreen,
R.id.objectRelationListScreen,
bundleOf(
- ObjectRelationListFragment.ARG_CTX to command.ctx,
- ObjectRelationListFragment.ARG_SPACE to space,
- ObjectRelationListFragment.ARG_TARGET to command.target,
- ObjectRelationListFragment.ARG_LOCKED to command.isLocked,
+ ObjectFieldsFragment.ARG_CTX to command.ctx,
+ ObjectFieldsFragment.ARG_SPACE to space,
+ ObjectFieldsFragment.ARG_TARGET to command.target,
+ ObjectFieldsFragment.ARG_LOCKED to command.isLocked,
)
)
}
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/editor/cover/SelectCoverGalleryFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/editor/cover/SelectCoverGalleryFragment.kt
index 4e12c7cd32..4ae6ed4c5c 100644
--- a/app/src/main/java/com/anytypeio/anytype/ui/editor/cover/SelectCoverGalleryFragment.kt
+++ b/app/src/main/java/com/anytypeio/anytype/ui/editor/cover/SelectCoverGalleryFragment.kt
@@ -28,6 +28,7 @@ import com.anytypeio.anytype.core_utils.ext.subscribe
import com.anytypeio.anytype.core_utils.ext.toast
import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetFragment
import com.anytypeio.anytype.databinding.FragmentDocCoverGalleryBinding
+import com.anytypeio.anytype.device.launchMediaPicker
import com.anytypeio.anytype.di.common.componentManager
import com.anytypeio.anytype.di.feature.DefaultComponentParam
import com.anytypeio.anytype.other.MediaPermissionHelper
@@ -104,13 +105,12 @@ abstract class SelectCoverGalleryFragment :
binding.btnUpload.clicks()
.onEach {
- try {
- pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.ImageOnly))
- } catch (e: Exception) {
- Timber.w(e, "Error while opening photo picker")
- toast("Error while opening photo picker")
- permissionHelper.openFilePicker(Mimetype.MIME_IMAGE_ALL, null)
- }
+ launchMediaPicker(
+ pickMedia = pickMedia,
+ permissionHelper = permissionHelper,
+ mediaType = PickVisualMedia.ImageOnly,
+ fallbackMimeType = Mimetype.MIME_IMAGE_ALL
+ )
}
.launchIn(lifecycleScope)
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/editor/layout/ObjectLayoutFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/editor/layout/ObjectLayoutFragment.kt
index 64a0a81fe6..f53ac8396b 100644
--- a/app/src/main/java/com/anytypeio/anytype/ui/editor/layout/ObjectLayoutFragment.kt
+++ b/app/src/main/java/com/anytypeio/anytype/ui/editor/layout/ObjectLayoutFragment.kt
@@ -25,6 +25,7 @@ import com.anytypeio.anytype.presentation.editor.layout.ObjectLayoutViewModel
import com.anytypeio.anytype.presentation.objects.ObjectLayoutView
import javax.inject.Inject
+@Deprecated("epic Primitives")
class ObjectLayoutFragment : BaseBottomSheetFragment() {
private val ctx: String get() = argString(CONTEXT_ID_KEY)
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/editor/modals/IconPickerFragmentBase.kt b/app/src/main/java/com/anytypeio/anytype/ui/editor/modals/IconPickerFragmentBase.kt
index b9b99025b1..44cd15ee19 100644
--- a/app/src/main/java/com/anytypeio/anytype/ui/editor/modals/IconPickerFragmentBase.kt
+++ b/app/src/main/java/com/anytypeio/anytype/ui/editor/modals/IconPickerFragmentBase.kt
@@ -23,6 +23,7 @@ import com.anytypeio.anytype.core_utils.ext.toast
import com.anytypeio.anytype.core_utils.ext.visible
import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetTextInputFragment
import com.anytypeio.anytype.databinding.FragmentPageIconPickerBinding
+import com.anytypeio.anytype.device.launchMediaPicker
import com.anytypeio.anytype.library_page_icon_picker_widget.ui.DocumentEmojiIconPickerAdapter
import com.anytypeio.anytype.other.MediaPermissionHelper
import com.anytypeio.anytype.presentation.editor.picker.EmojiPickerView.Companion.HOLDER_EMOJI_CATEGORY_HEADER
@@ -85,13 +86,12 @@ abstract class IconPickerFragmentBase :
btnRemoveIcon.setOnClickListener { vm.onRemoveClicked(target) }
tvTabRandom.setOnClickListener { vm.onRandomEmoji(target) }
tvTabUpload.setOnClickListener {
- try {
- pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.ImageOnly))
- } catch (e: Exception) {
- Timber.w(e, "Error while opening photo picker")
- toast("Error while opening photo picker")
- permissionHelper.openFilePicker(Mimetype.MIME_IMAGE_ALL, 0)
- }
+ launchMediaPicker(
+ pickMedia = pickMedia,
+ permissionHelper = permissionHelper,
+ mediaType = PickVisualMedia.ImageOnly,
+ fallbackMimeType = Mimetype.MIME_IMAGE_ALL
+ )
}
}
skipCollapsed()
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/editor/sheets/ObjectMenuBaseFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/editor/sheets/ObjectMenuBaseFragment.kt
index c9a2caf324..1ec22c6450 100644
--- a/app/src/main/java/com/anytypeio/anytype/ui/editor/sheets/ObjectMenuBaseFragment.kt
+++ b/app/src/main/java/com/anytypeio/anytype/ui/editor/sheets/ObjectMenuBaseFragment.kt
@@ -31,13 +31,12 @@ import com.anytypeio.anytype.presentation.objects.menu.ObjectMenuViewModelBase
import com.anytypeio.anytype.ui.base.navigation
import com.anytypeio.anytype.ui.editor.cover.SelectCoverObjectFragment
import com.anytypeio.anytype.ui.editor.cover.SelectCoverObjectSetFragment
-import com.anytypeio.anytype.ui.editor.layout.ObjectLayoutFragment
import com.anytypeio.anytype.ui.editor.modals.IconPickerFragmentBase
import com.anytypeio.anytype.ui.history.VersionHistoryFragment
import com.anytypeio.anytype.ui.linking.BacklinkAction
import com.anytypeio.anytype.ui.linking.BacklinkOrAddToObjectFragment
import com.anytypeio.anytype.ui.moving.OnMoveToAction
-import com.anytypeio.anytype.ui.relations.ObjectRelationListFragment
+import com.anytypeio.anytype.ui.primitives.ObjectFieldsFragment
import com.google.android.material.snackbar.Snackbar
import timber.log.Timber
@@ -84,7 +83,7 @@ abstract class ObjectMenuBaseFragment :
override fun onStart() {
click(binding.objectDiagnostics) { vm.onDiagnosticsClicked(ctx = ctx) }
click(binding.optionHistory) { vm.onHistoryClicked(ctx = ctx, space = space) }
- click(binding.optionLayout) { vm.onLayoutClicked(ctx = ctx, space = space) }
+ click(binding.optionDescription) { vm.onDescriptionClicked(ctx = ctx, space = space) }
click(binding.optionIcon) { vm.onIconClicked(ctx = ctx, space = space) }
click(binding.optionRelations) { vm.onRelationsClicked() }
click(binding.optionCover) { vm.onCoverClicked(ctx = ctx, space = space) }
@@ -116,19 +115,22 @@ abstract class ObjectMenuBaseFragment :
private fun renderOptions(options: ObjectMenuOptionsProvider.Options) {
val iconVisibility = options.hasIcon.toVisibility()
val coverVisibility = options.hasCover.toVisibility()
- val layoutVisibility = options.hasLayout.toVisibility()
val relationsVisibility = options.hasRelations.toVisibility()
val historyVisibility = options.hasHistory.toVisibility()
val objectDiagnosticsVisibility = options.hasDiagnosticsVisibility.toVisibility()
+ if (options.hasDescriptionShow) {
+ binding.optionDescription.setAction(setAsHide = false)
+ } else {
+ binding.optionDescription.setAction(setAsHide = true)
+ }
+
binding.optionIcon.visibility = iconVisibility
binding.optionCover.visibility = coverVisibility
- binding.optionLayout.visibility = layoutVisibility
binding.optionRelations.visibility = relationsVisibility
binding.optionHistory.visibility = historyVisibility
binding.iconDivider.visibility = iconVisibility
binding.coverDivider.visibility = coverVisibility
- binding.layoutDivider.visibility = layoutVisibility
binding.relationsDivider.visibility = relationsVisibility
binding.historyDivider.visibility = historyVisibility
binding.objectDiagnostics.visibility = objectDiagnosticsVisibility
@@ -139,7 +141,6 @@ abstract class ObjectMenuBaseFragment :
when (command) {
ObjectMenuViewModelBase.Command.OpenObjectCover -> openObjectCover()
ObjectMenuViewModelBase.Command.OpenObjectIcons -> openObjectIcons()
- ObjectMenuViewModelBase.Command.OpenObjectLayout -> openObjectLayout()
ObjectMenuViewModelBase.Command.OpenObjectRelations -> openObjectRelations()
ObjectMenuViewModelBase.Command.OpenSetCover -> openSetCover()
ObjectMenuViewModelBase.Command.OpenSetIcons -> openSetIcons()
@@ -218,20 +219,15 @@ abstract class ObjectMenuBaseFragment :
)
}
- private fun openObjectLayout() {
- val fr = ObjectLayoutFragment.new(ctx = ctx, space = space)
- fr.showChildFragment()
- }
-
private fun openObjectRelations() {
findNavController().navigate(
R.id.objectRelationListScreen,
bundleOf(
- ObjectRelationListFragment.ARG_CTX to ctx,
- ObjectRelationListFragment.ARG_SPACE to space,
- ObjectRelationListFragment.ARG_TARGET to null,
- ObjectRelationListFragment.ARG_LOCKED to isLocked,
- ObjectRelationListFragment.ARG_SET_FLOW to false
+ ObjectFieldsFragment.ARG_CTX to ctx,
+ ObjectFieldsFragment.ARG_SPACE to space,
+ ObjectFieldsFragment.ARG_TARGET to null,
+ ObjectFieldsFragment.ARG_LOCKED to isLocked,
+ ObjectFieldsFragment.ARG_SET_FLOW to false
)
)
}
@@ -240,11 +236,11 @@ abstract class ObjectMenuBaseFragment :
findNavController().navigate(
R.id.objectRelationListScreen,
bundleOf(
- ObjectRelationListFragment.ARG_CTX to ctx,
- ObjectRelationListFragment.ARG_SPACE to space,
- ObjectRelationListFragment.ARG_TARGET to null,
- ObjectRelationListFragment.ARG_LOCKED to isLocked,
- ObjectRelationListFragment.ARG_SET_FLOW to true
+ ObjectFieldsFragment.ARG_CTX to ctx,
+ ObjectFieldsFragment.ARG_SPACE to space,
+ ObjectFieldsFragment.ARG_TARGET to null,
+ ObjectFieldsFragment.ARG_LOCKED to isLocked,
+ ObjectFieldsFragment.ARG_SET_FLOW to true
)
)
}
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreen.kt b/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreen.kt
index 178b3e66f5..d1e684c1e0 100644
--- a/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreen.kt
+++ b/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreen.kt
@@ -91,11 +91,11 @@ fun HomeScreen(
onHomeButtonClicked: () -> Unit,
onCreateNewObjectClicked: () -> Unit,
onCreateNewObjectLongClicked: () -> Unit,
- onShareButtonClicked: () -> Unit,
+ onNavBarShareButtonClicked: () -> Unit,
onObjectCheckboxClicked: (Id, Boolean) -> Unit,
onSpaceWidgetClicked: () -> Unit,
onMove: (List, FromIndex, ToIndex) -> Unit,
- onSpaceShareIconClicked: (ObjectWrapper.SpaceView) -> Unit,
+ onSpaceWidgetShareIconClicked: (ObjectWrapper.SpaceView) -> Unit,
onSeeAllObjectsClicked: (WidgetView.Gallery) -> Unit,
onCreateObjectInsideWidget: (Id) -> Unit,
onCreateDataViewObject: (WidgetId, ViewId?) -> Unit
@@ -116,7 +116,7 @@ fun HomeScreen(
onSpaceWidgetClicked = onSpaceWidgetClicked,
onMove = onMove,
onObjectCheckboxClicked = onObjectCheckboxClicked,
- onSpaceShareIconClicked = onSpaceShareIconClicked,
+ onSpaceWidgetShareIconClicked = onSpaceWidgetShareIconClicked,
onSeeAllObjectsClicked = onSeeAllObjectsClicked,
onCreateWidget = onCreateWidget,
onCreateObjectInsideWidget = onCreateObjectInsideWidget,
@@ -162,7 +162,7 @@ fun HomeScreen(
searchClick = onSearchClicked,
addDocClick = onCreateNewObjectClicked,
addDocLongClick = onCreateNewObjectLongClicked,
- onShareButtonClicked = onShareButtonClicked,
+ onShareButtonClicked = onNavBarShareButtonClicked,
onHomeButtonClicked = onHomeButtonClicked
)
}
@@ -187,7 +187,7 @@ private fun WidgetList(
onMove: (List, FromIndex, ToIndex) -> Unit,
onObjectCheckboxClicked: (Id, Boolean) -> Unit,
onSpaceWidgetClicked: () -> Unit,
- onSpaceShareIconClicked: (ObjectWrapper.SpaceView) -> Unit,
+ onSpaceWidgetShareIconClicked: (ObjectWrapper.SpaceView) -> Unit,
onSeeAllObjectsClicked: (WidgetView.Gallery) -> Unit,
onCreateWidget: () -> Unit,
onCreateObjectInsideWidget: (Id) -> Unit,
@@ -229,7 +229,7 @@ private fun WidgetList(
name = item.space.name.orEmpty(),
icon = item.icon,
spaceType = item.type,
- onSpaceShareIconClicked = { onSpaceShareIconClicked(item.space) },
+ onSpaceShareIconClicked = { onSpaceWidgetShareIconClicked(item.space) },
isShared = item.isShared,
membersCount = item.membersCount
)
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreenFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreenFragment.kt
index 1a60584c8a..52740891da 100644
--- a/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreenFragment.kt
+++ b/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreenFragment.kt
@@ -112,7 +112,7 @@ class HomeScreenFragment : BaseComposeFragment(),
) {
HomeScreenToolbar(
spaceIconView = view?.icon ?: SpaceIconView.Loading,
- onSpaceIconClicked = vm::onSpaceSettingsClicked,
+ onSpaceIconClicked = vm::onSpaceWidgetClicked,
membersCount = view?.membersCount ?: 0,
name = view?.space?.name.orEmpty(),
onBackButtonClicked = {
@@ -140,7 +140,6 @@ class HomeScreenFragment : BaseComposeFragment(),
)
}
}
-
BackHandler {
vm.onBackClicked(
isSpaceRoot = isSpaceRootScreen()
@@ -177,16 +176,16 @@ class HomeScreenFragment : BaseComposeFragment(),
onClick = { vm.onCreateNewObjectLongClicked() }
),
onSpaceWidgetClicked = throttledClick(
- onClick = vm::onSpaceSettingsClicked
+ onClick = vm::onSpaceWidgetClicked
),
onBundledWidgetClicked = vm::onBundledWidgetClicked,
onMove = vm::onMove,
onObjectCheckboxClicked = vm::onObjectCheckboxClicked,
- onSpaceShareIconClicked = vm::onSpaceShareIconClicked,
+ onSpaceWidgetShareIconClicked = vm::onSpaceWidgetShareIconClicked,
onSeeAllObjectsClicked = vm::onSeeAllObjectsClicked,
onCreateObjectInsideWidget = vm::onCreateObjectInsideWidget,
onCreateDataViewObject = vm::onCreateDataViewObject,
- onShareButtonClicked = vm::onSpaceShareIconClicked,
+ onNavBarShareButtonClicked = vm::onNavBarShareIconClicked,
navPanelState = vm.navPanelState.collectAsStateWithLifecycle().value,
onHomeButtonClicked = vm::onHomeButtonClicked,
)
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreenToolbar.kt b/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreenToolbar.kt
index 6b471213ca..c7aa3c6bcd 100644
--- a/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreenToolbar.kt
+++ b/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreenToolbar.kt
@@ -95,7 +95,7 @@ fun HomeScreenToolbar(
} else
stringResource(id = R.string.three_dots_text_placeholder),
style = Relations2,
- color = colorResource(R.color.text_secondary),
+ color = colorResource(R.color.transparent_active),
modifier = Modifier
.align(Alignment.BottomStart)
.padding(
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/main/MainActivity.kt b/app/src/main/java/com/anytypeio/anytype/ui/main/MainActivity.kt
index 6cce4ba1b6..0e5677f353 100644
--- a/app/src/main/java/com/anytypeio/anytype/ui/main/MainActivity.kt
+++ b/app/src/main/java/com/anytypeio/anytype/ui/main/MainActivity.kt
@@ -52,6 +52,7 @@ import com.anytypeio.anytype.presentation.notifications.NotificationAction
import com.anytypeio.anytype.presentation.notifications.NotificationCommand
import com.anytypeio.anytype.presentation.wallpaper.WallpaperColor
import com.anytypeio.anytype.presentation.wallpaper.WallpaperView
+import com.anytypeio.anytype.ui.chats.ChatFragment
import com.anytypeio.anytype.ui.date.DateObjectFragment
import com.anytypeio.anytype.ui.editor.CreateObjectFragment
import com.anytypeio.anytype.ui.editor.EditorFragment
@@ -196,82 +197,38 @@ class MainActivity : AppCompatActivity(R.layout.activity_main), AppNavigation.Pr
}
}
is Command.Navigate -> {
- when(val dest = command.destination) {
- is OpenObjectNavigation.OpenDataView -> {
- runCatching {
- findNavController(R.id.fragment).navigate(
- R.id.dataViewNavigation,
- args = ObjectSetFragment.args(
- ctx = dest.target,
- space = dest.space
- ),
- navOptions = NavOptions.Builder()
- .setPopUpTo(R.id.homeScreen, true)
- .build()
- )
- }.onFailure {
- Timber.e(it, "Error while data view navigation")
- }
- }
- is OpenObjectNavigation.OpenParticipant -> {
- runCatching {
- findNavController(R.id.fragment).navigate(
- R.id.participantScreen,
- ParticipantFragment.args(
- objectId = dest.target,
- space = dest.space
- )
- )
- }.onFailure {
- Timber.w("Error while opening participant screen")
- }
- }
- is OpenObjectNavigation.OpenEditor -> {
- runCatching {
- findNavController(R.id.fragment).navigate(
- R.id.objectNavigation,
- args = EditorFragment.args(
- ctx = dest.target,
- space = dest.space
- ),
- navOptions = NavOptions.Builder()
- .setPopUpTo(R.id.homeScreen, true)
- .build()
- )
- }.onFailure {
- Timber.e(it, "Error while editor navigation")
- }
- }
- is OpenObjectNavigation.OpenChat -> {
- toast("Cannot open chat from here")
- }
- is OpenObjectNavigation.UnexpectedLayoutError -> {
- toast(getString(R.string.error_unexpected_layout))
- }
- OpenObjectNavigation.NonValidObject -> {
- toast(getString(R.string.error_non_valid_object))
- }
- is OpenObjectNavigation.OpenDateObject -> {
- runCatching {
- findNavController(R.id.fragment).navigate(
- R.id.dateObjectScreen,
- args = DateObjectFragment.args(
- objectId = dest.target,
- space = dest.space
- ),
- navOptions = Builder()
- .setPopUpTo(R.id.homeScreen, true)
- .build()
- )
- }.onFailure {
- Timber.e(it, "Error while date object navigation")
- }
- }
- }
+ proceedWithOpenObjectNavigation(command.destination)
}
is Command.Deeplink.DeepLinkToObjectNotWorking -> {
toast(getString(R.string.multiplayer_deeplink_to_your_object_error))
}
+ is Command.Deeplink.DeepLinkToObject -> {
+ when(val effect = command.sideEffect) {
+ is Command.Deeplink.DeepLinkToObject.SideEffect.SwitchSpace -> {
+ runCatching {
+ val controller = findNavController(R.id.fragment)
+ controller.popBackStack(R.id.vaultScreen, false)
+ if (effect.chat != null) {
+ controller.navigate(
+ R.id.actionOpenChatFromVault,
+ ChatFragment.args(
+ space = command.space,
+ ctx = effect.chat.orEmpty()
+ )
+ )
+ } else {
+ controller.navigate(R.id.actionOpenSpaceFromVault)
+ }
+ proceedWithOpenObjectNavigation(command.navigation)
+ }.onFailure {
+ Timber.e(it, "Error while switching space when handling deep link to object")
+ }
+ }
+ null -> {
+ proceedWithOpenObjectNavigation(command.navigation)
+ }
+ }
+ }
is Command.Deeplink.GalleryInstallation -> {
runCatching {
findNavController(R.id.fragment).navigate(
@@ -322,6 +279,84 @@ class MainActivity : AppCompatActivity(R.layout.activity_main), AppNavigation.Pr
}
}
+ private fun proceedWithOpenObjectNavigation(dest: OpenObjectNavigation) {
+ when (dest) {
+ is OpenObjectNavigation.OpenDataView -> {
+ runCatching {
+ findNavController(R.id.fragment).navigate(
+ R.id.dataViewNavigation,
+ args = ObjectSetFragment.args(
+ ctx = dest.target,
+ space = dest.space
+ ),
+ navOptions = Builder()
+ .setPopUpTo(R.id.homeScreen, true)
+ .build()
+ )
+ }.onFailure {
+ Timber.e(it, "Error while data view navigation")
+ }
+ }
+
+ is OpenObjectNavigation.OpenParticipant -> {
+ runCatching {
+ findNavController(R.id.fragment).navigate(
+ R.id.participantScreen,
+ ParticipantFragment.args(
+ objectId = dest.target,
+ space = dest.space
+ )
+ )
+ }.onFailure {
+ Timber.w("Error while opening participant screen")
+ }
+ }
+
+ is OpenObjectNavigation.OpenEditor -> {
+ runCatching {
+ findNavController(R.id.fragment).navigate(
+ R.id.objectNavigation,
+ args = EditorFragment.args(
+ ctx = dest.target,
+ space = dest.space
+ )
+ )
+ }.onFailure {
+ Timber.e(it, "Error while editor navigation")
+ }
+ }
+
+ is OpenObjectNavigation.OpenChat -> {
+ toast("Cannot open chat from here")
+ }
+
+ is OpenObjectNavigation.UnexpectedLayoutError -> {
+ toast(getString(R.string.error_unexpected_layout))
+ }
+
+ OpenObjectNavigation.NonValidObject -> {
+ toast(getString(R.string.error_non_valid_object))
+ }
+
+ is OpenObjectNavigation.OpenDateObject -> {
+ runCatching {
+ findNavController(R.id.fragment).navigate(
+ R.id.dateObjectScreen,
+ args = DateObjectFragment.args(
+ objectId = dest.target,
+ space = dest.space
+ ),
+ navOptions = Builder()
+ .setPopUpTo(R.id.homeScreen, true)
+ .build()
+ )
+ }.onFailure {
+ Timber.e(it, "Error while date object navigation")
+ }
+ }
+ }
+ }
+
private fun startAppUpdater() {
if (featureToggles.isAutoUpdateEnabled) {
AppUpdater(this)
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/onboarding/OnboardingFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/onboarding/OnboardingFragment.kt
index eaf08c12be..e492b42cb3 100644
--- a/app/src/main/java/com/anytypeio/anytype/ui/onboarding/OnboardingFragment.kt
+++ b/app/src/main/java/com/anytypeio/anytype/ui/onboarding/OnboardingFragment.kt
@@ -427,21 +427,6 @@ class OnboardingFragment : Fragment() {
Timber.e(it, "Error while trying to open vault screen from onboarding")
}
}
- OnboardingMnemonicLoginViewModel.Command.NavigateToMigrationErrorScreen -> {
- runCatching {
- findNavController().navigate(
- R.id.migrationNeededScreen,
- null,
- navOptions {
- popUpTo(R.id.onboarding_nav) {
- inclusive = false
- }
- }
- )
- }.onFailure {
- Timber.e(it, "Error while trying to open migration screen from onboarding")
- }
- }
is OnboardingMnemonicLoginViewModel.Command.ShareDebugGoroutines -> {
try {
this@OnboardingFragment.shareFirstFileFromPath(command.path, command.uriFileProvider)
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/onboarding/screens/signin/OnboardingRecoveryPhraseLoginScreen.kt b/app/src/main/java/com/anytypeio/anytype/ui/onboarding/screens/signin/OnboardingRecoveryPhraseLoginScreen.kt
index 41709c39b3..b98afbd6f4 100644
--- a/app/src/main/java/com/anytypeio/anytype/ui/onboarding/screens/signin/OnboardingRecoveryPhraseLoginScreen.kt
+++ b/app/src/main/java/com/anytypeio/anytype/ui/onboarding/screens/signin/OnboardingRecoveryPhraseLoginScreen.kt
@@ -41,6 +41,7 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.anytypeio.anytype.BuildConfig
import com.anytypeio.anytype.R
+import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_ui.ColorButtonRegular
import com.anytypeio.anytype.core_ui.MnemonicPhrasePaletteColors
import com.anytypeio.anytype.core_ui.OnBoardingTextPrimaryColor
@@ -54,6 +55,8 @@ 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 com.anytypeio.anytype.ui.update.MigrationFailedScreen
+import com.anytypeio.anytype.ui.update.MigrationInProgressScreen
import kotlin.Unit
@Composable
@@ -67,11 +70,12 @@ fun RecoveryScreenWrapper(
onNextClicked = vm::onLoginClicked,
onActionDoneClicked = vm::onActionDone,
onScanQrClicked = onScanQrClick,
- isLoading = vm.state.collectAsState().value is SetupState.InProgress,
+ state = vm.state.collectAsState().value,
onEnterMyVaultClicked = vm::onEnterMyVaultClicked,
onDebugAccountTraceClicked = {
vm.onAccountThraceButtonClicked()
- }
+ },
+ onRetryMigrationClicked = vm::onRetryMigrationClicked
)
}
@@ -81,9 +85,10 @@ fun RecoveryScreen(
onNextClicked: (Mnemonic) -> Unit,
onActionDoneClicked: (Mnemonic) -> Unit,
onScanQrClicked: () -> Unit,
- isLoading: Boolean,
+ state: SetupState,
onEnterMyVaultClicked: () -> Unit,
- onDebugAccountTraceClicked: () -> Unit
+ onDebugAccountTraceClicked: () -> Unit,
+ onRetryMigrationClicked: (Id) -> Unit
) {
val focus = LocalFocusManager.current
val context = LocalContext.current
@@ -186,7 +191,7 @@ fun RecoveryScreen(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 18.dp),
- isLoading = isLoading
+ isLoading = state is SetupState.InProgress
)
}
item {
@@ -207,7 +212,7 @@ fun RecoveryScreen(
onClick = {
onScanQrClicked.invoke()
},
- enabled = !isLoading,
+ enabled = state !is SetupState.InProgress,
disabledBackgroundColor = Color.Transparent,
size = ButtonSize.Large,
modifier = Modifier
@@ -218,6 +223,16 @@ fun RecoveryScreen(
}
}
)
+ if (state is SetupState.Migration.InProgress) {
+ MigrationInProgressScreen()
+ } else if(state is SetupState.Migration.Failed) {
+ MigrationFailedScreen(
+ state = state.state,
+ onRetryClicked = {
+ onRetryMigrationClicked(state.account)
+ }
+ )
+ }
}
}
@@ -267,9 +282,10 @@ fun RecoveryScreenPreview() {
onNextClicked = {},
onActionDoneClicked = {},
onScanQrClicked = {},
- isLoading = false,
+ state = SetupState.Idle,
onEnterMyVaultClicked = {},
- onDebugAccountTraceClicked = {}
+ onDebugAccountTraceClicked = {},
+ onRetryMigrationClicked = {}
)
}
@@ -282,8 +298,9 @@ fun RecoveryScreenLoadingPreview() {
onNextClicked = {},
onActionDoneClicked = {},
onScanQrClicked = {},
- isLoading = true,
+ state = SetupState.InProgress,
onEnterMyVaultClicked = {},
- onDebugAccountTraceClicked = {}
+ onDebugAccountTraceClicked = {},
+ onRetryMigrationClicked = {}
)
}
\ No newline at end of file
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/primitives/EditTypePropertiesFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/primitives/EditTypePropertiesFragment.kt
new file mode 100644
index 0000000000..f72a23b72d
--- /dev/null
+++ b/app/src/main/java/com/anytypeio/anytype/ui/primitives/EditTypePropertiesFragment.kt
@@ -0,0 +1,146 @@
+package com.anytypeio.anytype.ui.primitives
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.res.stringResource
+import androidx.core.os.bundleOf
+import androidx.fragment.app.viewModels
+import androidx.fragment.compose.content
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import androidx.lifecycle.lifecycleScope
+import androidx.navigation.fragment.findNavController
+import com.anytypeio.anytype.R
+import com.anytypeio.anytype.core_models.Id
+import com.anytypeio.anytype.core_models.primitives.SpaceId
+import com.anytypeio.anytype.core_ui.views.BaseAlertDialog
+import com.anytypeio.anytype.core_utils.ext.argString
+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.feature_properties.EditTypePropertiesViewModelFactory
+import com.anytypeio.anytype.feature_properties.EditTypePropertiesViewModel
+import com.anytypeio.anytype.feature_properties.EditTypePropertiesViewModel.EditTypePropertiesCommand
+import com.anytypeio.anytype.feature_properties.add.EditTypePropertiesVmParams
+import com.anytypeio.anytype.feature_properties.add.UiEditTypePropertiesErrorState
+import com.anytypeio.anytype.feature_properties.add.ui.AddFieldScreen
+import javax.inject.Inject
+
+class EditTypePropertiesFragment : BaseBottomSheetComposeFragment() {
+
+ @Inject
+ lateinit var viewModelFactory: EditTypePropertiesViewModelFactory
+ private val vm by viewModels { viewModelFactory }
+ private val space get() = argString(ARG_SPACE)
+ private val typeId get() = argString(ARG_OBJECT_ID)
+
+ @OptIn(ExperimentalMaterial3Api::class)
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ) = content {
+ MaterialTheme {
+ AddFieldScreen(
+ state = vm.uiState.collectAsStateWithLifecycle().value,
+ uiStateEditProperty = vm.uiPropertyEditState.collectAsStateWithLifecycle().value,
+ event = vm::onEvent
+ )
+ ErrorScreen()
+ }
+ }
+
+ @OptIn(ExperimentalMaterial3Api::class)
+ @Composable
+ private fun ErrorScreen() {
+ val errorStateScreen = vm.errorState.collectAsStateWithLifecycle().value
+ if (errorStateScreen is UiEditTypePropertiesErrorState.Show) {
+ when (val r = errorStateScreen.reason) {
+ is UiEditTypePropertiesErrorState.Reason.ErrorAddingProperty -> {
+ BaseAlertDialog(
+ dialogText = stringResource(id = R.string.add_property_error_add),
+ buttonText = stringResource(id = R.string.membership_error_button_text_dismiss),
+ onButtonClick = vm::hideError,
+ onDismissRequest = vm::hideError
+ )
+ }
+
+ is UiEditTypePropertiesErrorState.Reason.ErrorCreatingProperty -> {
+ BaseAlertDialog(
+ dialogText = stringResource(id = R.string.add_property_error_create_new),
+ buttonText = stringResource(id = R.string.membership_error_button_text_dismiss),
+ onButtonClick = vm::hideError,
+ onDismissRequest = vm::hideError
+ )
+ }
+
+ is UiEditTypePropertiesErrorState.Reason.ErrorUpdatingProperty -> {
+ BaseAlertDialog(
+ dialogText = stringResource(id = R.string.add_property_error_update),
+ buttonText = stringResource(id = R.string.membership_error_button_text_dismiss),
+ onButtonClick = vm::hideError,
+ onDismissRequest = vm::hideError
+ )
+ }
+
+ is UiEditTypePropertiesErrorState.Reason.Other -> {
+ BaseAlertDialog(
+ dialogText = r.msg,
+ buttonText = stringResource(id = R.string.membership_error_button_text_dismiss),
+ onButtonClick = vm::hideError,
+ onDismissRequest = vm::hideError
+ )
+ }
+ }
+ }
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ setupBottomSheetBehavior(DEFAULT_PADDING_TOP)
+ }
+
+ override fun onStart() {
+ super.onStart()
+ jobs += lifecycleScope.subscribe(vm.commands) { command -> execute(command) }
+ }
+
+ private fun execute(command: EditTypePropertiesCommand) {
+ when (command) {
+ is EditTypePropertiesCommand.Exit -> {
+ findNavController().popBackStack()
+ }
+ }
+ }
+
+ override fun injectDependencies() {
+ val params = EditTypePropertiesVmParams(
+ objectTypeId = typeId,
+ spaceId = SpaceId(space)
+
+ )
+ componentManager().editTypePropertiesComponent.get(params).inject(this)
+ }
+
+ override fun releaseDependencies() {
+ componentManager().editTypePropertiesComponent.release()
+ }
+
+ companion object {
+
+ fun args(objectId: Id, space: Id) = bundleOf(
+ ARG_OBJECT_ID to objectId,
+ ARG_SPACE to space
+ )
+
+ const val ARG_OBJECT_ID = "arg.primitives.edit.type.property.object.id"
+ const val ARG_SPACE = "arg.primitives.edit.type.property.space"
+
+ const val DEFAULT_PADDING_TOP = 10
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/primitives/ObjectFieldsFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/primitives/ObjectFieldsFragment.kt
new file mode 100644
index 0000000000..bb93600585
--- /dev/null
+++ b/app/src/main/java/com/anytypeio/anytype/ui/primitives/ObjectFieldsFragment.kt
@@ -0,0 +1,313 @@
+package com.anytypeio.anytype.ui.primitives
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.rememberModalBottomSheetState
+import androidx.compose.ui.Modifier
+import androidx.core.os.bundleOf
+import androidx.fragment.app.viewModels
+import androidx.fragment.compose.content
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import androidx.lifecycle.lifecycleScope
+import androidx.navigation.fragment.findNavController
+import com.anytypeio.anytype.R
+import com.anytypeio.anytype.core_models.Id
+import com.anytypeio.anytype.core_models.Key
+import com.anytypeio.anytype.core_models.TimeInMillis
+import com.anytypeio.anytype.core_models.primitives.SpaceId
+import com.anytypeio.anytype.core_ui.features.fields.FieldListScreen
+import com.anytypeio.anytype.core_utils.ext.arg
+import com.anytypeio.anytype.core_utils.ext.argString
+import com.anytypeio.anytype.core_utils.ext.argStringOrNull
+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.ext.toast
+import com.anytypeio.anytype.core_utils.ext.withParent
+import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetComposeFragment
+import com.anytypeio.anytype.di.common.componentManager
+import com.anytypeio.anytype.di.feature.DefaultComponentParam
+import com.anytypeio.anytype.feature_object_type.fields.ui.LocalInfoScreen
+import com.anytypeio.anytype.presentation.relations.ObjectRelationListViewModelFactory
+import com.anytypeio.anytype.presentation.relations.RelationListViewModel
+import com.anytypeio.anytype.presentation.relations.RelationListViewModel.Command
+import com.anytypeio.anytype.presentation.relations.value.tagstatus.RelationContext
+import com.anytypeio.anytype.ui.base.navigation
+import com.anytypeio.anytype.ui.editor.OnFragmentInteractionListener
+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 javax.inject.Inject
+import kotlin.getValue
+import timber.log.Timber
+
+class ObjectFieldsFragment : BaseBottomSheetComposeFragment(),
+ RelationTextValueFragment.TextValueEditReceiver,
+ RelationDateValueFragment.DateValueEditReceiver {
+
+ private val vm by viewModels { factory }
+
+ private val ctx: String get() = argString(ARG_CTX)
+ private val space: String get() = argString(ARG_SPACE)
+ private val target: String? get() = argStringOrNull(ARG_TARGET)
+ private val isSetFlow: Boolean get() = arg(ARG_SET_FLOW)
+
+ @Inject
+ lateinit var factory: ObjectRelationListViewModelFactory
+
+ @OptIn(ExperimentalMaterial3Api::class)
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ) =
+ content {
+ MaterialTheme {
+ FieldListScreen(
+ state = vm.views.collectAsStateWithLifecycle().value,
+ onRelationClicked = {
+ vm.onRelationClicked(
+ ctx = ctx,
+ target = target,
+ view = it.view
+ )
+ },
+ onLocalInfoIconClicked = {
+ vm.onShowLocalInfo()
+ },
+ onTypeIconClicked = {
+ vm.onTypeIconClicked()
+ },
+ onRemoveFromObjectClicked = vm::onRemoveFromObjectClicked,
+ onAddToTypeClicked = vm::onAddToTypeClicked
+ )
+ val showLocalFieldExplanationScreen = vm.showLocalInfo.collectAsStateWithLifecycle().value
+ if (showLocalFieldExplanationScreen) {
+ val bottomSheetState = rememberModalBottomSheetState(
+ skipPartiallyExpanded = true
+ )
+ LocalInfoScreen(
+ modifier = Modifier.fillMaxWidth(),
+ bottomSheetState = bottomSheetState,
+ onDismiss = { vm.onDismissLocalInfo() }
+ )
+ }
+ }
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ setupBottomSheetBehavior(DEFAULT_PADDING_TOP)
+ }
+
+ private fun execute(command: Command) {
+ when (command) {
+ is Command.EditTextRelationValue -> {
+ runCatching {
+ val fr = RelationTextValueFragment.new(
+ ctx = ctx,
+ relationKey = command.relationKey,
+ objectId = command.target,
+ isLocked = command.isLocked,
+ flow = if (isSetFlow)
+ RelationTextValueFragment.FLOW_DATAVIEW
+ else
+ RelationTextValueFragment.FLOW_DEFAULT,
+ space = space
+ )
+ fr.showChildFragment()
+ }.onFailure {
+ Timber.e(it, "Error while opening relation text value from relation list")
+ }
+ }
+
+ is Command.EditDateRelationValue -> {
+ val fr = RelationDateValueFragment.new(
+ ctx = ctx,
+ space = space,
+ relationKey = command.relationKey,
+ objectId = command.target,
+ flow = if (isSetFlow) {
+ RelationDateValueFragment.FLOW_SET_OR_COLLECTION
+ } else {
+ RelationDateValueFragment.FLOW_DEFAULT
+ },
+ isLocked = command.isLocked
+ )
+ fr.showChildFragment()
+ }
+
+ is Command.EditFileObjectRelationValue -> {
+ val relationContext =
+ if (isSetFlow) RelationContext.OBJECT_SET else RelationContext.OBJECT
+ findNavController().safeNavigate(
+ R.id.objectRelationListScreen,
+ R.id.objectValueScreen,
+ ObjectValueFragment.args(
+ ctx = command.ctx,
+ space = space,
+ obj = command.target,
+ relation = command.relationKey,
+ isLocked = command.isLocked,
+ relationContext = relationContext
+ )
+ )
+ }
+
+ is Command.SetRelationKey -> {
+ withParent {
+ onSetRelationKeyClicked(
+ blockId = command.blockId,
+ key = command.key
+ )
+ }
+ dismiss()
+ }
+
+ is Command.EditTagOrStatusRelationValue -> {
+ val relationContext =
+ if (isSetFlow) RelationContext.OBJECT_SET else RelationContext.OBJECT
+ val bundle = TagOrStatusValueFragment.args(
+ ctx = command.ctx,
+ space = space,
+ obj = command.target,
+ relation = command.relationKey,
+ isLocked = command.isLocked,
+ context = relationContext
+ )
+ findNavController().safeNavigate(
+ R.id.objectRelationListScreen,
+ R.id.nav_relations,
+ bundle
+ )
+ }
+
+ is Command.NavigateToDateObject -> {
+ runCatching {
+ navigation().openDateObject(
+ objectId = command.objectId,
+ space = space
+ )
+ }.onFailure {
+ Timber.e(it, "Error while opening date object from relation list")
+ }
+ }
+
+ is Command.NavigateToObjectType -> {
+ runCatching {
+ navigation().openCurrentObjectTypeFields(
+ objectId = command.objectTypeId,
+ space = space
+ )
+ }.onFailure {
+ Timber.e(it, "Error while opening object type fields from object fields list")
+ }
+ }
+ }
+ }
+
+ override fun onStart() {
+ jobs += lifecycleScope.subscribe(vm.commands) { command -> execute(command) }
+ jobs += lifecycleScope.subscribe(vm.toasts) { toast(it) }
+ super.onStart()
+ vm.onStartListMode(ctx)
+ }
+
+ override fun onStop() {
+ super.onStop()
+ vm.onStop()
+ }
+
+ override fun onTextValueChanged(ctx: Id, text: String, objectId: Id, relationKey: Key) {
+ vm.onRelationTextValueChanged(
+ ctx = ctx,
+ relationKey = relationKey,
+ value = text,
+ isValueEmpty = text.isEmpty()
+ )
+ }
+
+ override fun onNumberValueChanged(ctx: Id, number: Double?, objectId: Id, relationKey: Key) {
+ vm.onRelationTextValueChanged(
+ ctx = ctx,
+ relationKey = relationKey,
+ value = number,
+ isValueEmpty = number == null
+ )
+ }
+
+ override fun onDateValueChanged(
+ ctx: Id,
+ timeInSeconds: Number?,
+ objectId: Id,
+ relationKey: Key
+ ) {
+ vm.onRelationTextValueChanged(
+ ctx = ctx,
+ relationKey = relationKey,
+ value = timeInSeconds,
+ isValueEmpty = timeInSeconds == null
+ )
+ }
+
+ override fun onOpenDateObject(timeInMillis: TimeInMillis) {
+ vm.onOpenDateObjectByTimeInMillis(timeInMillis)
+ }
+
+ override fun injectDependencies() {
+ val param = DefaultComponentParam(
+ ctx = ctx,
+ space = SpaceId(space)
+ )
+ if (isSetFlow) {
+ componentManager().objectSetRelationListComponent.get(param).inject(this)
+ } else {
+ componentManager().objectRelationListComponent.get(param).inject(this)
+ }
+ }
+
+ override fun releaseDependencies() {
+ if (isSetFlow) {
+ componentManager().objectSetRelationListComponent.release()
+ } else {
+ componentManager().objectRelationListComponent.release()
+ }
+ }
+
+ /**
+ * This screen should be started from Objects with Editor Layouts
+ * or from objects with Set or Collection Layouts
+ * @param isSetFlow - true if started from Set or Collection
+ */
+ companion object {
+ fun new(
+ ctx: Id,
+ space: Id,
+ target: String?,
+ locked: Boolean = false,
+ isSetFlow: Boolean = false,
+ ) = ObjectFieldsFragment().apply {
+ arguments = bundleOf(
+ ARG_CTX to ctx,
+ ARG_SPACE to space,
+ ARG_TARGET to target,
+ ARG_LOCKED to locked,
+ ARG_SET_FLOW to isSetFlow
+ )
+ }
+
+ const val ARG_CTX = "arg.primitives.properties.ctx"
+ const val ARG_SPACE = "arg.primitives.properties.space"
+ const val ARG_TARGET = "arg.primitives.properties.target"
+ const val ARG_LOCKED = "arg.primitives.properties.locked"
+ const val ARG_SET_FLOW = "arg.primitives.properties.set_flow"
+
+ const val DEFAULT_PADDING_TOP = 10
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/primitives/ObjectTypeFieldsFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/primitives/ObjectTypeFieldsFragment.kt
new file mode 100644
index 0000000000..79ab82face
--- /dev/null
+++ b/app/src/main/java/com/anytypeio/anytype/ui/primitives/ObjectTypeFieldsFragment.kt
@@ -0,0 +1,91 @@
+package com.anytypeio.anytype.ui.primitives
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.core.os.bundleOf
+import androidx.fragment.app.viewModels
+import androidx.fragment.compose.content
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.anytypeio.anytype.core_models.Id
+import com.anytypeio.anytype.core_models.primitives.SpaceId
+import com.anytypeio.anytype.core_utils.ext.argString
+import com.anytypeio.anytype.core_utils.ext.setupBottomSheetBehavior
+import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetComposeFragment
+import com.anytypeio.anytype.di.common.componentManager
+import com.anytypeio.anytype.feature_object_type.fields.ui.FieldsMainScreen
+import com.anytypeio.anytype.feature_object_type.ui.ObjectTypeVmParams
+import com.anytypeio.anytype.feature_object_type.viewmodel.ObjectTypeVMFactory
+import com.anytypeio.anytype.feature_object_type.viewmodel.ObjectTypeViewModel
+import javax.inject.Inject
+import kotlin.getValue
+
+class ObjectTypeFieldsFragment : BaseBottomSheetComposeFragment() {
+
+ @Inject
+ lateinit var factory: ObjectTypeVMFactory
+
+ private val vm by viewModels { factory }
+
+ private val space get() = argString(ARG_SPACE)
+ private val typeId get() = argString(ARG_OBJECT_ID)
+
+ @OptIn(ExperimentalMaterial3Api::class)
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ) = content {
+ MaterialTheme {
+ FieldsMainScreen(
+ uiFieldsListState = vm.uiFieldsListState.collectAsStateWithLifecycle().value,
+ uiTitleState = vm.uiTitleState.collectAsStateWithLifecycle().value,
+ uiIconState = vm.uiIconState.collectAsStateWithLifecycle().value,
+ uiEditPropertyState = vm.uiEditPropertyScreen.collectAsStateWithLifecycle().value,
+ uiFieldLocalInfoState = vm.uiFieldLocalInfoState.collectAsStateWithLifecycle().value,
+ fieldEvent = vm::onFieldEvent
+ )
+ }
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ setupBottomSheetBehavior(DEFAULT_PADDING_TOP)
+ }
+
+ override fun onStart() {
+ super.onStart()
+ vm.onStart()
+ }
+
+ override fun onStop() {
+ super.onStop()
+ vm.onStop()
+ }
+
+ override fun injectDependencies() {
+ val params = ObjectTypeVmParams(
+ spaceId = SpaceId(space),
+ objectId = typeId,
+ showHiddenFields = true
+ )
+ componentManager().objectTypeComponent.get(params).inject(this)
+ }
+
+ override fun releaseDependencies() {
+ componentManager().objectTypeComponent.release()
+ }
+
+ companion object {
+ const val ARG_SPACE = "arg.object.type.space"
+ const val ARG_OBJECT_ID = "arg.object.type.object_id"
+
+ fun args(space: Id, objectId: Id) = bundleOf(
+ ARG_SPACE to space,
+ ARG_OBJECT_ID to objectId
+ )
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/primitives/ObjectTypeFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/primitives/ObjectTypeFragment.kt
new file mode 100644
index 0000000000..8217d3322e
--- /dev/null
+++ b/app/src/main/java/com/anytypeio/anytype/ui/primitives/ObjectTypeFragment.kt
@@ -0,0 +1,235 @@
+package com.anytypeio.anytype.ui.primitives
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.res.stringResource
+import androidx.core.os.bundleOf
+import androidx.fragment.app.setFragmentResultListener
+import androidx.fragment.app.viewModels
+import androidx.fragment.compose.content
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import androidx.navigation.NavHostController
+import androidx.navigation.compose.NavHost
+import androidx.navigation.compose.composable
+import androidx.navigation.compose.rememberNavController
+import androidx.navigation.fragment.findNavController
+import com.anytypeio.anytype.R
+import com.anytypeio.anytype.core_models.Id
+import com.anytypeio.anytype.core_models.primitives.SpaceId
+import com.anytypeio.anytype.core_ui.views.BaseAlertDialog
+import com.anytypeio.anytype.core_utils.ext.argString
+import com.anytypeio.anytype.core_utils.ext.subscribe
+import com.anytypeio.anytype.core_utils.ui.BaseComposeFragment
+import com.anytypeio.anytype.di.common.componentManager
+import com.anytypeio.anytype.feature_object_type.fields.ui.FieldsMainScreen
+import com.anytypeio.anytype.feature_object_type.ui.ObjectTypeCommand
+import com.anytypeio.anytype.feature_object_type.ui.ObjectTypeVmParams
+import com.anytypeio.anytype.feature_object_type.ui.UiErrorState
+import com.anytypeio.anytype.feature_object_type.viewmodel.ObjectTypeVMFactory
+import com.anytypeio.anytype.feature_object_type.viewmodel.ObjectTypeViewModel
+import com.anytypeio.anytype.ui.editor.EditorModalFragment
+import com.anytypeio.anytype.ui.templates.EditorTemplateFragment.Companion.TYPE_TEMPLATE_EDIT
+import com.anytypeio.anytype.ui.types.picker.REQUEST_KEY_PICK_EMOJI
+import com.anytypeio.anytype.ui.types.picker.REQUEST_KEY_REMOVE_EMOJI
+import com.anytypeio.anytype.ui.types.picker.RESULT_EMOJI_UNICODE
+import com.google.accompanist.navigation.material.ExperimentalMaterialNavigationApi
+import com.google.accompanist.navigation.material.rememberBottomSheetNavigator
+import javax.inject.Inject
+import kotlin.getValue
+import timber.log.Timber
+
+class ObjectTypeFragment : BaseComposeFragment() {
+ @Inject
+ lateinit var factory: ObjectTypeVMFactory
+ private val vm by viewModels { factory }
+ private lateinit var navComposeController: NavHostController
+
+ private val space get() = argString(ARG_SPACE)
+ private val objectId get() = argString(ARG_OBJECT_ID)
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setFragmentResultListener(REQUEST_KEY_PICK_EMOJI) { _, bundle ->
+ val res = requireNotNull(bundle.getString(RESULT_EMOJI_UNICODE))
+ vm.updateIcon(res)
+ }
+ setFragmentResultListener(REQUEST_KEY_REMOVE_EMOJI) { _, _ ->
+ vm.removeIcon()
+ }
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ) = content {
+ MaterialTheme {
+ ObjectTypeScreen()
+ ErrorScreen()
+ }
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ subscribe(vm.commands) { command ->
+ Timber.d("Received command: $command")
+ when (command) {
+ ObjectTypeCommand.Back -> {
+ runCatching {
+ findNavController().popBackStack()
+ }.onFailure { e ->
+ Timber.e(e, "Error while exiting back from object type screen")
+ }
+ }
+ ObjectTypeCommand.OpenEmojiPicker -> {
+ runCatching {
+ findNavController().navigate(R.id.openEmojiPicker)
+ }.onFailure {
+ Timber.w("Error while opening emoji picker")
+ }
+ }
+
+ is ObjectTypeCommand.OpenTemplate -> {
+ findNavController().navigate(
+ R.id.nav_editor_modal,
+ bundleOf(
+ EditorModalFragment.ARG_TEMPLATE_ID to command.templateId,
+ EditorModalFragment.ARG_TEMPLATE_TYPE_ID to command.typeId,
+ EditorModalFragment.ARG_TEMPLATE_TYPE_KEY to command.typeKey,
+ EditorModalFragment.ARG_SCREEN_TYPE to TYPE_TEMPLATE_EDIT,
+ EditorModalFragment.ARG_SPACE_ID to command.spaceId
+ )
+ )
+ }
+
+ ObjectTypeCommand.OpenFieldsScreen -> {
+ navComposeController.navigate(OBJ_TYPE_FIELDS)
+ }
+
+ is ObjectTypeCommand.OpenEditTypePropertiesScreen -> {
+ runCatching {
+ findNavController().navigate(
+ R.id.editTypePropertiesScreen,
+ EditTypePropertiesFragment.args(
+ objectId = command.typeId,
+ space = command.space
+ )
+ )
+ }.onFailure {
+ Timber.e(it, "Error while opening edit object type properties screen")
+ }
+ }
+ }
+ }
+ }
+
+ override fun onStart() {
+ super.onStart()
+ vm.onStart()
+ }
+
+ override fun onStop() {
+ super.onStop()
+ vm.onStop()
+ }
+
+ @OptIn(ExperimentalMaterialNavigationApi::class)
+ @Composable
+ fun ObjectTypeScreen() {
+ val bottomSheetNavigator = rememberBottomSheetNavigator()
+ navComposeController = rememberNavController(bottomSheetNavigator)
+ NavHost(
+ navController = navComposeController,
+ startDestination = OBJ_TYPE_MAIN
+ ) {
+ composable(route = OBJ_TYPE_MAIN) {
+ WithSetScreen(
+ uiEditButtonState = vm.uiEditButtonState.collectAsStateWithLifecycle().value,
+ uiSyncStatusBadgeState = vm.uiSyncStatusBadgeState.collectAsStateWithLifecycle().value,
+ uiIconState = vm.uiIconState.collectAsStateWithLifecycle().value,
+ uiTitleState = vm.uiTitleState.collectAsStateWithLifecycle().value,
+ uiFieldsButtonState = vm.uiFieldsButtonState.collectAsStateWithLifecycle().value,
+ uiLayoutButtonState = vm.uiLayoutButtonState.collectAsStateWithLifecycle().value,
+ uiTemplatesButtonState = vm.uiTemplatesButtonState.collectAsStateWithLifecycle().value,
+ uiTemplatesModalListState = vm.uiTemplatesModalListState.collectAsStateWithLifecycle().value,
+ uiLayoutTypeState = vm.uiTypeLayoutsState.collectAsStateWithLifecycle().value,
+ uiSyncStatusState = vm.uiSyncStatusWidgetState.collectAsStateWithLifecycle().value,
+ uiDeleteAlertState = vm.uiAlertState.collectAsStateWithLifecycle().value,
+ objectId = objectId,
+ space = space,
+ onTypeEvent = vm::onTypeEvent
+ )
+ }
+ composable(route = OBJ_TYPE_FIELDS) {
+ FieldsMainScreen(
+ uiFieldsListState = vm.uiFieldsListState.collectAsStateWithLifecycle().value,
+ uiTitleState = vm.uiTitleState.collectAsStateWithLifecycle().value,
+ uiIconState = vm.uiIconState.collectAsStateWithLifecycle().value,
+ uiEditPropertyState = vm.uiEditPropertyScreen.collectAsStateWithLifecycle().value,
+ uiFieldLocalInfoState = vm.uiFieldLocalInfoState.collectAsStateWithLifecycle().value,
+ fieldEvent = vm::onFieldEvent
+ )
+ }
+ }
+ }
+
+ @OptIn(ExperimentalMaterial3Api::class)
+ @Composable
+ private fun ErrorScreen() {
+ val errorStateScreen = vm.errorState.collectAsStateWithLifecycle().value
+ if (errorStateScreen is UiErrorState.Show) {
+ when (val r = errorStateScreen.reason) {
+ is UiErrorState.Reason.ErrorGettingObjects -> {
+ BaseAlertDialog(
+ dialogText = "${stringResource(R.string.object_type_open_type_error)}:\n${r.msg}",
+ buttonText = stringResource(id = R.string.membership_error_button_text_dismiss),
+ onButtonClick = vm::closeObject,
+ onDismissRequest = vm::closeObject
+ )
+ }
+ is UiErrorState.Reason.Other -> {
+ BaseAlertDialog(
+ dialogText = r.msg,
+ buttonText = stringResource(id = R.string.membership_error_button_text_dismiss),
+ onButtonClick = vm::hideError,
+ onDismissRequest = vm::hideError
+ )
+ }
+ }
+ }
+ }
+
+ override fun injectDependencies() {
+ val params = ObjectTypeVmParams(
+ spaceId = SpaceId(space),
+ objectId = objectId,
+ showHiddenFields = true
+ )
+ componentManager().objectTypeComponent.get(params).inject(this)
+ }
+
+ override fun releaseDependencies() {
+ componentManager().objectTypeComponent.release()
+ }
+
+ override fun onApplyWindowRootInsets(view: View) {
+ // Skipping this, since window insets will be applied by compose code.
+ }
+
+ companion object {
+ private const val OBJ_TYPE_MAIN = "obj_type_main"
+ private const val OBJ_TYPE_FIELDS = "obj_fields"
+ const val ARG_SPACE = "arg.object.type.space"
+ const val ARG_OBJECT_ID = "arg.object.type.object_id"
+
+ fun args(space: Id, objectId: Id) = bundleOf(
+ ARG_SPACE to space,
+ ARG_OBJECT_ID to objectId
+ )
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/primitives/WithSetScreen.kt b/app/src/main/java/com/anytypeio/anytype/ui/primitives/WithSetScreen.kt
new file mode 100644
index 0000000000..557cfec3ee
--- /dev/null
+++ b/app/src/main/java/com/anytypeio/anytype/ui/primitives/WithSetScreen.kt
@@ -0,0 +1,194 @@
+package com.anytypeio.anytype.ui.primitives
+
+import android.os.Build
+import android.view.View
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.navigationBars
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.windowInsetsPadding
+import androidx.compose.foundation.layout.wrapContentHeight
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.TopAppBarDefaults
+import androidx.compose.material3.rememberTopAppBarState
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.input.nestedscroll.nestedScroll
+import androidx.compose.ui.res.colorResource
+import androidx.compose.ui.unit.dp
+import androidx.fragment.compose.AndroidFragment
+import com.anytypeio.anytype.core_utils.insets.EDGE_TO_EDGE_MIN_SDK
+import com.anytypeio.anytype.feature_object_type.R
+import com.anytypeio.anytype.feature_object_type.ui.BottomSyncStatus
+import com.anytypeio.anytype.feature_object_type.ui.TopBarContent
+import com.anytypeio.anytype.feature_object_type.ui.TypeEvent
+import com.anytypeio.anytype.feature_object_type.ui.UiDeleteAlertState
+import com.anytypeio.anytype.feature_object_type.ui.UiEditButton
+import com.anytypeio.anytype.feature_object_type.ui.UiFieldsButtonState
+import com.anytypeio.anytype.feature_object_type.ui.UiIconState
+import com.anytypeio.anytype.feature_object_type.ui.UiLayoutButtonState
+import com.anytypeio.anytype.feature_object_type.ui.UiLayoutTypeState
+import com.anytypeio.anytype.feature_object_type.ui.UiSyncStatusBadgeState
+import com.anytypeio.anytype.feature_object_type.ui.UiTemplatesButtonState
+import com.anytypeio.anytype.feature_object_type.ui.UiTemplatesModalListState
+import com.anytypeio.anytype.feature_object_type.ui.UiTitleState
+import com.anytypeio.anytype.feature_object_type.ui.alerts.DeleteAlertScreen
+import com.anytypeio.anytype.feature_object_type.ui.header.HorizontalButtons
+import com.anytypeio.anytype.feature_object_type.ui.header.IconAndTitleWidget
+import com.anytypeio.anytype.feature_object_type.ui.layouts.TypeLayoutsScreen
+import com.anytypeio.anytype.feature_object_type.ui.templates.TemplatesModalList
+import com.anytypeio.anytype.presentation.sync.SyncStatusWidgetState
+import com.anytypeio.anytype.ui.sets.ObjectSetFragment
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun WithSetScreen(
+ //top bar
+ uiEditButtonState: UiEditButton,
+ uiSyncStatusBadgeState: UiSyncStatusBadgeState,
+ uiSyncStatusState: SyncStatusWidgetState,
+ //header
+ uiIconState: UiIconState,
+ uiTitleState: UiTitleState,
+ //layout and fields buttons
+ uiFieldsButtonState: UiFieldsButtonState,
+ uiLayoutButtonState: UiLayoutButtonState,
+ uiLayoutTypeState: UiLayoutTypeState,
+ uiTemplatesButtonState: UiTemplatesButtonState,
+ //templates modal list
+ uiTemplatesModalListState: UiTemplatesModalListState,
+ //delete alert
+ uiDeleteAlertState: UiDeleteAlertState,
+ //events
+ onTypeEvent: (TypeEvent) -> Unit,
+ objectId: String,
+ space: String,
+) {
+ val topAppBarScrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(
+ state = rememberTopAppBarState()
+ )
+
+ Scaffold(
+ modifier = Modifier
+ .fillMaxSize()
+ .nestedScroll(topAppBarScrollBehavior.nestedScrollConnection),
+ containerColor = colorResource(id = R.color.background_primary),
+ contentColor = colorResource(id = R.color.background_primary),
+ topBar = {
+ TopBarContent(
+ uiSyncStatusBadgeState = uiSyncStatusBadgeState,
+ uiEditButtonState = uiEditButtonState,
+ uiTitleState = uiTitleState,
+ topBarScrollBehavior = topAppBarScrollBehavior,
+ onTypeEvent = onTypeEvent
+ )
+ },
+ content = { paddingValues ->
+ MainContentSet(
+ paddingValues = paddingValues,
+ uiIconState = uiIconState,
+ uiTitleState = uiTitleState,
+ uiFieldsButtonState = uiFieldsButtonState,
+ uiLayoutButtonState = uiLayoutButtonState,
+ uiTemplatesButtonState = uiTemplatesButtonState,
+ objectId = objectId,
+ space = space,
+ onTypeEvent = onTypeEvent
+ )
+ }
+ )
+
+ BottomSyncStatus(
+ uiSyncStatusState = uiSyncStatusState,
+ onDismiss = { onTypeEvent(TypeEvent.OnSyncStatusDismiss) }
+ )
+
+ if (uiDeleteAlertState is UiDeleteAlertState.Show) {
+ DeleteAlertScreen(
+ onTypeEvent = onTypeEvent
+ )
+ }
+
+ if (uiLayoutTypeState is UiLayoutTypeState.Visible) {
+ TypeLayoutsScreen(
+ modifier = Modifier.fillMaxWidth(),
+ uiState = uiLayoutTypeState,
+ onTypeEvent = onTypeEvent
+ )
+ }
+
+ if (uiTemplatesModalListState is UiTemplatesModalListState.Visible) {
+ TemplatesModalList(
+ modifier = Modifier.fillMaxWidth(),
+ uiState = uiTemplatesModalListState,
+ onTypeEvent = onTypeEvent
+ )
+ }
+}
+
+
+@Composable
+private fun MainContentSet(
+ paddingValues: PaddingValues,
+ uiIconState: UiIconState,
+ uiTitleState: UiTitleState,
+ uiFieldsButtonState: UiFieldsButtonState,
+ uiLayoutButtonState: UiLayoutButtonState,
+ uiTemplatesButtonState: UiTemplatesButtonState,
+ objectId: String,
+ space: String,
+ onTypeEvent: (TypeEvent) -> Unit
+) {
+ val contentModifier = if (Build.VERSION.SDK_INT >= EDGE_TO_EDGE_MIN_SDK) {
+ Modifier
+ .windowInsetsPadding(WindowInsets.navigationBars)
+ .fillMaxSize()
+ .padding(top = paddingValues.calculateTopPadding())
+ } else {
+ Modifier
+ .fillMaxSize()
+ .padding(paddingValues)
+ }
+
+ Column(modifier = contentModifier) {
+ IconAndTitleWidget(
+ modifier = Modifier
+ .fillMaxWidth()
+ .wrapContentHeight()
+ .padding(top = 35.dp)
+ .padding(horizontal = 20.dp),
+ uiIconState = uiIconState,
+ uiTitleState = uiTitleState,
+ onTypeEvent = onTypeEvent
+ )
+ Spacer(modifier = Modifier.height(20.dp))
+ HorizontalButtons(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(36.dp)
+ .padding(horizontal = 20.dp),
+ uiFieldsButtonState = uiFieldsButtonState,
+ uiLayoutButtonState = uiLayoutButtonState,
+ uiTemplatesButtonState = uiTemplatesButtonState,
+ onTypeEvent = onTypeEvent
+ )
+ Spacer(modifier = Modifier.height(24.dp))
+ AndroidFragment(
+ modifier = Modifier
+ .fillMaxSize(),
+ arguments = ObjectSetFragment.args(
+ ctx = objectId,
+ space = space
+ )
+ ) { fragment ->
+ fragment.view?.findViewById(R.id.objectHeader)?.visibility =
+ View.GONE
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/relations/ObjectRelationListFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/relations/ObjectRelationListFragment.kt
index 58e47b4c06..962320c399 100644
--- a/app/src/main/java/com/anytypeio/anytype/ui/relations/ObjectRelationListFragment.kt
+++ b/app/src/main/java/com/anytypeio/anytype/ui/relations/ObjectRelationListFragment.kt
@@ -41,6 +41,7 @@ import com.anytypeio.anytype.ui.relations.value.TagOrStatusValueFragment
import javax.inject.Inject
import timber.log.Timber
+@Deprecated("Legacy, epic Primitives, use ObjectFieldsFragment instead")
open class ObjectRelationListFragment : BaseBottomSheetFragment(),
RelationTextValueFragment.TextValueEditReceiver,
RelationDateValueFragment.DateValueEditReceiver {
@@ -194,6 +195,10 @@ open class ObjectRelationListFragment : BaseBottomSheetFragment {
+ //do nothing
+ }
}
}
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/sets/ObjectSetFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/sets/ObjectSetFragment.kt
index 433da47e82..32c4263c67 100644
--- a/app/src/main/java/com/anytypeio/anytype/ui/sets/ObjectSetFragment.kt
+++ b/app/src/main/java/com/anytypeio/anytype/ui/sets/ObjectSetFragment.kt
@@ -705,6 +705,57 @@ open class ObjectSetFragment :
dataViewInfo.hide()
setViewer(viewer = null)
}
+ is DataViewViewState.TypeSet.Default -> {
+ topToolbarThreeDotsButton.gone()
+ topToolbarStatusContainer.gone()
+ topBackButton.gone()
+ initView.gone()
+ header.gone()
+ dataViewHeader.visible()
+ viewerTitle.isEnabled = true
+ setupNewButtonsForTypeSet(state.isCreateObjectAllowed)
+ if (state.isEditingViewAllowed) {
+ customizeViewButton.visible()
+ } else {
+ customizeViewButton.invisible()
+ }
+ customizeViewButton.isEnabled = true
+ setCurrentViewerName(state.viewer?.title)
+ setViewer(viewer = state.viewer)
+ dataViewInfo.hide()
+ }
+ is DataViewViewState.TypeSet.NoItems -> {
+ topToolbarThreeDotsButton.gone()
+ topToolbarStatusContainer.gone()
+ topBackButton.gone()
+ initView.gone()
+ header.gone()
+ dataViewHeader.visible()
+ viewerTitle.isEnabled = true
+ setupNewButtonsForTypeSet(state.isCreateObjectAllowed)
+ if (state.isEditingViewAllowed) {
+ customizeViewButton.visible()
+ } else {
+ customizeViewButton.invisible()
+ }
+ customizeViewButton.isEnabled = true
+ setCurrentViewerName(state.title)
+ dataViewInfo.show(
+ type = DataViewInfo.TYPE.SET_NO_ITEMS,
+ isReadOnlyAccess = !state.isCreateObjectAllowed
+ )
+ setViewer(viewer = null)
+ }
+
+ is DataViewViewState.TypeSet.Error -> {
+ topToolbarThreeDotsButton.gone()
+ topToolbarStatusContainer.gone()
+ topBackButton.gone()
+ initView.gone()
+ header.gone()
+ dataViewHeader.visible()
+ setViewer(viewer = null)
+ }
}
}
@@ -726,6 +777,16 @@ open class ObjectSetFragment :
}
}
+ private fun setupNewButtonsForTypeSet(isCreateObjectAllowed: Boolean) {
+ if (isCreateObjectAllowed) {
+ addNewButton.visible()
+ addNewIconButton.gone()
+ } else {
+ addNewButton.gone()
+ addNewIconButton.gone()
+ }
+ }
+
private fun setViewer(viewer: Viewer?) {
when (viewer) {
is Viewer.GridView -> {
@@ -824,29 +885,28 @@ open class ObjectSetFragment :
.launchIn(lifecycleScope)
}
- binding.objectHeader.root.findViewById(R.id.imageIcon).apply {
- if (header.title.image != null) visible() else gone()
+ binding.objectHeader.root.findViewById(R.id.imageIcon).apply {
jobs += this.clicks()
.throttleFirst()
.onEach { vm.onObjectIconClicked() }
.launchIn(lifecycleScope)
+
+ if (header.title.image != null) {
+ this.visible()
+ Glide
+ .with(this)
+ .load(header.title.image)
+ .centerCrop()
+ .into(this)
+ } else {
+ this.gone()
+ this.setImageDrawable(null)
+ }
}
binding.objectHeader.root.findViewById(R.id.emojiIcon)
.setEmojiOrNull(header.title.emoji)
- if (header.title.image != null) {
- binding.objectHeader.root.findViewById(R.id.imageIcon).apply {
- Glide
- .with(this)
- .load(header.title.image)
- .centerCrop()
- .into(this)
- }
- } else {
- binding.objectHeader.root.findViewById(R.id.imageIcon).setImageDrawable(null)
- }
-
setCover(
coverColor = header.title.coverColor,
coverGradient = header.title.coverGradient,
@@ -1439,34 +1499,44 @@ open class ObjectSetFragment :
}
private fun observeSelectingTemplate() {
- val navController = findNavController()
- val navBackStackEntry = navController.getBackStackEntry(R.id.objectSetScreen)
- val observer = LifecycleEventObserver { _, event ->
- if (event == Lifecycle.Event.ON_RESUME
- && navBackStackEntry.savedStateHandle.contains(ARG_TEMPLATE_ID)) {
- val resultTemplateId = navBackStackEntry.savedStateHandle.get(ARG_TEMPLATE_ID)
- val resultTypeId = navBackStackEntry.savedStateHandle.get(ARG_TARGET_TYPE_ID)
- val resultTypeKey = navBackStackEntry.savedStateHandle.get(ARG_TARGET_TYPE_KEY)
- if (!resultTemplateId.isNullOrBlank() && !resultTypeId.isNullOrBlank() && !resultTypeKey.isNullOrBlank()) {
- navBackStackEntry.savedStateHandle.remove(ARG_TEMPLATE_ID)
- navBackStackEntry.savedStateHandle.remove(ARG_TARGET_TYPE_ID)
- navBackStackEntry.savedStateHandle.remove(ARG_TARGET_TYPE_KEY)
- vm.proceedWithSelectedTemplate(
- template = resultTemplateId,
- typeId = resultTypeId,
- typeKey = resultTypeKey
- )
+ try {
+ val navController = findNavController()
+ val navBackStackEntry = navController.getBackStackEntry(R.id.objectSetScreen)
+ val observer = LifecycleEventObserver { _, event ->
+ if (event == Lifecycle.Event.ON_RESUME
+ && navBackStackEntry.savedStateHandle.contains(ARG_TEMPLATE_ID)
+ ) {
+ val resultTemplateId =
+ navBackStackEntry.savedStateHandle.get(ARG_TEMPLATE_ID)
+ val resultTypeId =
+ navBackStackEntry.savedStateHandle.get(ARG_TARGET_TYPE_ID)
+ val resultTypeKey =
+ navBackStackEntry.savedStateHandle.get(ARG_TARGET_TYPE_KEY)
+ if (!resultTemplateId.isNullOrBlank() && !resultTypeId.isNullOrBlank() && !resultTypeKey.isNullOrBlank()) {
+ navBackStackEntry.savedStateHandle.remove(ARG_TEMPLATE_ID)
+ navBackStackEntry.savedStateHandle.remove(ARG_TARGET_TYPE_ID)
+ navBackStackEntry.savedStateHandle.remove(ARG_TARGET_TYPE_KEY)
+ vm.proceedWithSelectedTemplate(
+ template = resultTemplateId,
+ typeId = resultTypeId,
+ typeKey = resultTypeKey
+ )
+ }
}
}
+
+ navBackStackEntry.lifecycle.addObserver(observer)
+
+ viewLifecycleOwner.lifecycle.addObserver(LifecycleEventObserver { _, event ->
+ if (event == Lifecycle.Event.ON_DESTROY) {
+ navBackStackEntry.lifecycle.removeObserver(observer)
+ }
+ })
+ } catch (
+ e: Exception
+ ) {
+ Timber.w(e)
}
-
- navBackStackEntry.lifecycle.addObserver(observer)
-
- viewLifecycleOwner.lifecycle.addObserver(LifecycleEventObserver { _, event ->
- if (event == Lifecycle.Event.ON_DESTROY) {
- navBackStackEntry.lifecycle.removeObserver(observer)
- }
- })
}
override fun injectDependencies() {
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/settings/DebugFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/settings/DebugFragment.kt
new file mode 100644
index 0000000000..3c0ef402b5
--- /dev/null
+++ b/app/src/main/java/com/anytypeio/anytype/ui/settings/DebugFragment.kt
@@ -0,0 +1,93 @@
+package com.anytypeio.anytype.ui.settings
+
+import android.net.Uri
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.compose.runtime.LaunchedEffect
+import androidx.fragment.app.viewModels
+import androidx.fragment.compose.content
+import com.anytypeio.anytype.core_utils.tools.ZIP_MIME_TYPE
+import com.anytypeio.anytype.core_utils.tools.zipDirectory
+import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetComposeFragment
+import com.anytypeio.anytype.di.common.componentManager
+import com.anytypeio.anytype.presentation.settings.DebugViewModel
+import java.io.File
+import java.io.FileInputStream
+import java.io.IOException
+import javax.inject.Inject
+import kotlin.getValue
+
+class DebugFragment : BaseBottomSheetComposeFragment() {
+
+ private val createFileLauncher = registerForActivityResult(ActivityResultContracts.CreateDocument(ZIP_MIME_TYPE)) { uri ->
+ uri?.let { saveZipToUri(it) }
+ }
+
+ @Inject
+ lateinit var factory: DebugViewModel.Factory
+
+ private val vm by viewModels { factory }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View = content {
+ DebugScreen(
+ onExportAllClicked = vm::onExportWorkingDirectory
+ )
+ LaunchedEffect(Unit) {
+ vm.commands.collect { cmd ->
+ when(cmd) {
+ is DebugViewModel.Command.ExportWorkingDirectory -> {
+ proceedWithZippingAndSharingWorkDirectory(
+ folderName = cmd.folderName,
+ exportFileName = cmd.exportFileName
+ )
+ }
+ }
+ }
+ }
+ }
+
+ private fun proceedWithZippingAndSharingWorkDirectory(
+ folderName: String,
+ exportFileName: String
+ ) {
+ val folder = File(
+ requireContext().filesDir,
+ folderName
+ )
+ val zipped = File(
+ requireContext().cacheDir,
+ DebugViewModel.EXPORT_WORK_DIRECTORY_TEMP_FOLDER
+ )
+ zipDirectory(
+ sourceDir = folder,
+ zipFile = zipped
+ )
+ createFileLauncher.launch(exportFileName)
+ }
+
+ private fun saveZipToUri(uri: Uri) {
+ try {
+ requireContext().contentResolver.openOutputStream(uri)?.use { outputStream ->
+ val zipFile = File(requireContext().cacheDir, DebugViewModel.EXPORT_WORK_DIRECTORY_TEMP_FOLDER)
+ FileInputStream(zipFile).use { it.copyTo(outputStream) }
+ }
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ }
+
+ override fun injectDependencies() {
+ componentManager().debugComponent.get().inject(this)
+ }
+
+ override fun releaseDependencies() {
+ componentManager().debugComponent.release()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/settings/DebugScreen.kt b/app/src/main/java/com/anytypeio/anytype/ui/settings/DebugScreen.kt
new file mode 100644
index 0000000000..4379ad8963
--- /dev/null
+++ b/app/src/main/java/com/anytypeio/anytype/ui/settings/DebugScreen.kt
@@ -0,0 +1,78 @@
+package com.anytypeio.anytype.ui.settings
+
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.colorResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.dp
+import com.anytypeio.anytype.core_ui.common.DefaultPreviews
+import com.anytypeio.anytype.core_ui.foundation.Dragger
+import com.anytypeio.anytype.core_ui.foundation.Header
+
+import com.anytypeio.anytype.R
+import com.anytypeio.anytype.core_ui.foundation.Divider
+import com.anytypeio.anytype.core_ui.views.BodyRegular
+
+@Composable
+fun DebugScreen(
+ onExportAllClicked: () -> Unit
+) {
+ Column(
+ modifier = Modifier.fillMaxSize()
+ ) {
+ Dragger(
+ modifier = Modifier
+ .align(Alignment.CenterHorizontally)
+ .padding(vertical = 6.dp)
+ )
+ Header(
+ text = stringResource(R.string.debug)
+ )
+
+ Spacer(modifier = Modifier.height(10.dp))
+
+ ActionItem(
+ title = "Export work directory",
+ onClick = onExportAllClicked
+ )
+
+ Divider()
+
+ }
+}
+
+@Composable
+private fun ActionItem(
+ title: String,
+ onClick: () -> Unit
+) {
+ Text(
+ text = title,
+ style = BodyRegular,
+ color = colorResource(R.color.text_primary),
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(20.dp)
+ .clickable {
+ onClick()
+ }
+ )
+}
+
+@DefaultPreviews
+@Composable
+fun DebugScreenPreview() {
+ DebugScreen(
+ onExportAllClicked = {}
+ )
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/settings/ProfileSettingsFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/settings/ProfileSettingsFragment.kt
index c8cd219d89..c6aff8ba4b 100644
--- a/app/src/main/java/com/anytypeio/anytype/ui/settings/ProfileSettingsFragment.kt
+++ b/app/src/main/java/com/anytypeio/anytype/ui/settings/ProfileSettingsFragment.kt
@@ -5,7 +5,6 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
-import androidx.activity.result.PickVisualMediaRequest
import androidx.activity.result.contract.ActivityResultContracts.PickVisualMedia
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.collectAsState
@@ -28,6 +27,7 @@ import com.anytypeio.anytype.core_utils.ext.subscribe
import com.anytypeio.anytype.core_utils.ext.toast
import com.anytypeio.anytype.core_utils.tools.FeatureToggles
import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetComposeFragment
+import com.anytypeio.anytype.device.launchMediaPicker
import com.anytypeio.anytype.di.common.componentManager
import com.anytypeio.anytype.other.MediaPermissionHelper
import com.anytypeio.anytype.ui.profile.KeychainPhraseDialog
@@ -120,7 +120,14 @@ class ProfileSettingsFragment : BaseBottomSheetComposeFragment() {
}
}
),
- clearProfileImage = { vm.onClearProfileImage() }
+ clearProfileImage = { vm.onClearProfileImage() },
+ onDebugClicked = {
+ runCatching {
+ findNavController().navigate(R.id.debugScreen)
+ }
+ },
+ isDebugEnabled = vm.isDebugEnabled.collectAsStateWithLifecycle().value,
+ onHeaderTitleClicked = vm::onHeaderTitleClicked
)
}
}
@@ -140,13 +147,12 @@ class ProfileSettingsFragment : BaseBottomSheetComposeFragment() {
}
private fun proceedWithIconClick() {
- try {
- pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.ImageOnly))
- } catch (e: Exception) {
- Timber.w(e, "Error while opening photo picker")
- toast("Error while opening photo picker")
- permissionHelper.openFilePicker(Mimetype.MIME_IMAGE_ALL, null)
- }
+ launchMediaPicker(
+ pickMedia = pickMedia,
+ permissionHelper = permissionHelper,
+ mediaType = PickVisualMedia.ImageOnly,
+ fallbackMimeType = Mimetype.MIME_IMAGE_ALL
+ )
}
private fun openGallery() {
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/spaces/CreateSpaceFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/spaces/CreateSpaceFragment.kt
index f8f4712ea6..39fae64634 100644
--- a/app/src/main/java/com/anytypeio/anytype/ui/spaces/CreateSpaceFragment.kt
+++ b/app/src/main/java/com/anytypeio/anytype/ui/spaces/CreateSpaceFragment.kt
@@ -63,9 +63,6 @@ class CreateSpaceFragment : BaseBottomSheetComposeFragment() {
deeplink = null
)
)
-// if (command.showMultiplayerTooltip) {
-// findNavController().navigate(R.id.multiplayerFeatureDialog)
-// }
}.onFailure {
Timber.e(it, "Error while exiting to vault or opening created space")
}
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/splash/SplashFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/splash/SplashFragment.kt
index a5161d767b..5490c29e48 100644
--- a/app/src/main/java/com/anytypeio/anytype/ui/splash/SplashFragment.kt
+++ b/app/src/main/java/com/anytypeio/anytype/ui/splash/SplashFragment.kt
@@ -18,7 +18,6 @@ import com.anytypeio.anytype.core_utils.ext.orNull
import com.anytypeio.anytype.core_utils.ext.toast
import com.anytypeio.anytype.core_utils.ext.visible
import com.anytypeio.anytype.core_utils.ui.BaseFragment
-import com.anytypeio.anytype.core_utils.ui.ViewState
import com.anytypeio.anytype.databinding.FragmentSplashBinding
import com.anytypeio.anytype.di.common.componentManager
import com.anytypeio.anytype.other.DefaultDeepLinkResolver
@@ -31,6 +30,8 @@ import com.anytypeio.anytype.ui.editor.EditorFragment
import com.anytypeio.anytype.ui.home.HomeScreenFragment
import com.anytypeio.anytype.ui.onboarding.OnboardingFragment
import com.anytypeio.anytype.ui.sets.ObjectSetFragment
+import com.anytypeio.anytype.ui.update.MigrationFailedScreen
+import com.anytypeio.anytype.ui.update.MigrationInProgressScreen
import com.anytypeio.anytype.ui.vault.VaultFragment
import javax.inject.Inject
import kotlinx.coroutines.launch
@@ -64,31 +65,37 @@ class SplashFragment : BaseFragment(R.layout.fragment_spl
launch {
vm.state.collect { state ->
when(state) {
- is ViewState.Error -> {
- binding.error.text = state.error
+ is SplashViewModel.State.Init -> {
+ binding.error.gone()
+ binding.compose.visibility = View.GONE
+ }
+ is SplashViewModel.State.Error -> {
+ binding.error.text = state.msg
binding.error.visible()
}
- else -> {
- binding.error.gone()
- binding.error.text = ""
- }
- }
- }
- }
-
- launch {
- vm.loadingState.collect { isLoading ->
- when (isLoading) {
- true -> {
- binding.loadingContainer.setContent {
+ is SplashViewModel.State.Loading -> {
+ binding.compose.setContent {
PulsatingCircleScreen()
}
- binding.logo.visibility = View.GONE
- binding.loadingContainer.visibility = View.VISIBLE
+ binding.compose.visible()
}
- false -> {
- binding.logo.visibility = View.GONE
- binding.loadingContainer.visibility = View.GONE
+ is SplashViewModel.State.Migration -> {
+ binding.compose.setContent {
+ if (state is SplashViewModel.State.Migration.InProgress) {
+ MigrationInProgressScreen()
+ } else if (state is SplashViewModel.State.Migration.Failed) {
+ MigrationFailedScreen(
+ state = state.state,
+ onRetryClicked = vm::onRetryMigrationClicked
+ )
+ }
+ }
+ binding.compose.visible()
+ }
+ is SplashViewModel.State.Success -> {
+ binding.compose.gone()
+ binding.error.gone()
+ binding.error.text = ""
}
}
}
@@ -271,11 +278,6 @@ class SplashFragment : BaseFragment(R.layout.fragment_spl
args = OnboardingFragment.args(deepLink)
)
}
- is SplashViewModel.Command.NavigateToMigration -> {
- findNavController().navigate(
- R.id.migrationNeededScreen
- )
- }
is SplashViewModel.Command.CheckAppStartIntent -> {
val intent = activity?.intent
if (intent != null && (intent.action == Intent.ACTION_VIEW || intent.action == Intent.ACTION_SEND)) {
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/update/MigrationErrorFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/update/MigrationErrorFragment.kt
deleted file mode 100644
index d9b06acb8b..0000000000
--- a/app/src/main/java/com/anytypeio/anytype/ui/update/MigrationErrorFragment.kt
+++ /dev/null
@@ -1,82 +0,0 @@
-package com.anytypeio.anytype.ui.update
-
-import android.content.Intent
-import android.net.Uri
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import androidx.compose.material.MaterialTheme
-import androidx.compose.ui.platform.ComposeView
-import androidx.compose.ui.platform.ViewCompositionStrategy
-import androidx.fragment.app.viewModels
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.lifecycleScope
-import androidx.lifecycle.repeatOnLifecycle
-import com.anytypeio.anytype.core_utils.ui.BaseComposeFragment
-import com.anytypeio.anytype.di.common.componentManager
-import com.anytypeio.anytype.presentation.update.MigrationErrorViewModel
-import com.anytypeio.anytype.ui.base.navigation
-import com.anytypeio.anytype.ui.settings.typography
-import javax.inject.Inject
-import kotlinx.coroutines.launch
-import timber.log.Timber
-
-class MigrationErrorFragment : BaseComposeFragment() {
-
- @Inject
- lateinit var factory: MigrationErrorViewModel.Factory
-
- private val vm by viewModels { factory }
-
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ) = ComposeView(
- context = requireContext()
- ).apply {
- setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
- setContent {
- MaterialTheme(typography = typography) {
- MigrationErrorScreen(vm::onAction)
- }
- }
- }
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
- viewLifecycleOwner.lifecycleScope.launch {
- viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
- vm.commands.collect { command ->
- when(command) {
- is MigrationErrorViewModel.Command.Browse -> {
- browseUrl(command)
- }
- is MigrationErrorViewModel.Command.Exit -> {
- navigation().exitFromMigrationScreen()
- }
- }
- }
- }
- }
- }
-
- private fun browseUrl(command: MigrationErrorViewModel.Command.Browse) {
- try {
- Intent(Intent.ACTION_VIEW).apply {
- data = Uri.parse(command.url)
- }.let(::startActivity)
- } catch (e: Exception) {
- Timber.e(e, "Error while browsing url")
- }
- }
-
- override fun injectDependencies() {
- componentManager().migrationErrorComponent.get().inject(this)
- }
-
- override fun releaseDependencies() {
- componentManager().migrationErrorComponent.release()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/update/MigrationErrorScreen.kt b/app/src/main/java/com/anytypeio/anytype/ui/update/MigrationErrorScreen.kt
index 049aa7ef2f..aa3d6d4407 100644
--- a/app/src/main/java/com/anytypeio/anytype/ui/update/MigrationErrorScreen.kt
+++ b/app/src/main/java/com/anytypeio/anytype/ui/update/MigrationErrorScreen.kt
@@ -1,219 +1,159 @@
package com.anytypeio.anytype.ui.update
-import androidx.activity.compose.BackHandler
-import androidx.compose.animation.AnimatedVisibility
-import androidx.compose.animation.AnimatedVisibilityScope
-import androidx.compose.animation.core.Animatable
-import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.foundation.text.ClickableText
-import androidx.compose.material.Card
+import androidx.compose.foundation.layout.size
+import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.rotate
+import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.colorResource
-import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.text.SpanStyle
-import androidx.compose.ui.text.buildAnnotatedString
-import androidx.compose.ui.text.font.FontWeight
-import androidx.compose.ui.text.withStyle
+import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import com.anytypeio.anytype.R
-import com.anytypeio.anytype.core_ui.foundation.noRippleClickable
-import com.anytypeio.anytype.core_ui.views.BodyCallout
-import com.anytypeio.anytype.core_ui.views.BodyRegular
+import com.anytypeio.anytype.core_ui.common.DefaultPreviews
+import com.anytypeio.anytype.core_ui.foundation.AlertConfig
+import com.anytypeio.anytype.core_ui.foundation.AlertIcon
+import com.anytypeio.anytype.core_ui.foundation.GRADIENT_TYPE_RED
+import com.anytypeio.anytype.core_ui.views.BodyCalloutRegular
import com.anytypeio.anytype.core_ui.views.ButtonPrimary
import com.anytypeio.anytype.core_ui.views.ButtonSize
import com.anytypeio.anytype.core_ui.views.HeadlineHeading
-import com.anytypeio.anytype.core_ui.views.HeadlineSubheading
-import com.anytypeio.anytype.presentation.update.MigrationErrorViewModel.ViewAction
-import kotlinx.coroutines.launch
-
+import com.anytypeio.anytype.presentation.auth.account.MigrationHelperDelegate
@Composable
-fun MigrationErrorScreen(onViewAction: (ViewAction) -> Unit) {
+fun MigrationInProgressScreen() {
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ .background(color = colorResource(id = R.color.background_primary)),
+ contentAlignment = Alignment.Center
+ ) {
+ Column(
+ modifier = Modifier.fillMaxWidth()
+ ) {
+ CircularProgressIndicator(
+ modifier = Modifier
+ .size(96.dp)
+ .align(Alignment.CenterHorizontally)
+ ,
+ backgroundColor = colorResource(R.color.shape_secondary),
+ color = Color(0xFFFFB522),
+ strokeWidth = 8.dp
+ )
+ Spacer(modifier = Modifier.height(16.dp))
+ Text(
+ text = stringResource(R.string.migration_migration_is_in_progress),
+ style = HeadlineHeading,
+ color = colorResource(R.color.text_primary),
+ textAlign = TextAlign.Center,
+ modifier = Modifier
+ .padding(horizontal = 44.dp)
+ .fillMaxWidth()
+ )
+ Spacer(modifier = Modifier.height(8.dp))
+ Text(
+ text = stringResource(R.string.migration_this_shouldn_t_take_long),
+ style = BodyCalloutRegular,
+ color = colorResource(R.color.text_secondary),
+ textAlign = TextAlign.Center,
+ modifier = Modifier
+ .padding(horizontal = 44.dp)
+ .fillMaxWidth()
+ )
+ }
+ }
+}
+
+@Composable
+fun MigrationFailedScreen(
+ state: MigrationHelperDelegate.State.Failed,
+ onRetryClicked: () -> Unit
+) {
+ val description = when(state) {
+ MigrationHelperDelegate.State.Failed.NotEnoughSpace -> {
+ stringResource(R.string.migration_error_please_free_up_space_and_run_the_process_again)
+ }
+ is MigrationHelperDelegate.State.Failed.UnknownError -> {
+ state.error.message ?: stringResource(R.string.unknown_error)
+ }
+ }
Box(
modifier = Modifier
.fillMaxSize()
.background(color = colorResource(id = R.color.background_primary))
) {
- Cards(onViewAction)
- CloseButton(closeClicks = { onViewAction(ViewAction.CloseScreen) })
- BackHandler(enabled = true) { onViewAction(ViewAction.CloseScreen) }
- }
-}
-
-@Composable
-fun Cards(onViewAction: (ViewAction) -> Unit) {
- Column(modifier = Modifier.padding(horizontal = 20.dp)) {
- Text(
- text = stringResource(id = R.string.almost_there),
- style = HeadlineHeading,
- color = colorResource(id = R.color.text_primary),
- modifier = Modifier.padding(top = 56.dp)
- )
- Text(
- text = stringResource(id = R.string.almost_there_subtitle),
- style = BodyRegular,
- color = colorResource(id = R.color.text_primary),
- modifier = Modifier.padding(top = 12.dp)
- )
- InfoCard(
- modifier = Modifier.padding(top = 32.dp),
- title = stringResource(id = R.string.i_did_not_not_complete_migration),
- toggleClick = { onViewAction(ViewAction.ToggleMigrationNotReady) },
- expanded = true,
- content = {
- val hereText = stringResource(id = R.string.here)
- val text = buildAnnotatedString {
- append(stringResource(id = R.string.update_steps_first))
- append(" ")
- pushStringAnnotation(
- tag = ANNOTATION_TAG,
- annotation = hereText
- )
- withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) {
- append(hereText)
- }
- pop()
- append(stringResource(R.string.update_steps_last))
- }
- ClickableText(
- modifier = Modifier.padding(top = 12.dp),
- text = text,
- style = BodyCallout.copy(
- color = colorResource(id = R.color.text_primary)
- ),
- onClick = { offset ->
- text.getStringAnnotations(
- tag = ANNOTATION_TAG,
- start = offset,
- end = offset
- ).firstOrNull().let {
- if (it?.item == hereText) {
- onViewAction(ViewAction.DownloadDesktop)
- }
- }
- },
+ Column(
+ modifier = Modifier.align(Alignment.Center)
+ ) {
+ AlertIcon(
+ icon = AlertConfig.Icon(
+ gradient = GRADIENT_TYPE_RED,
+ icon = R.drawable.ic_alert_error
)
- },
- )
- InfoCard(
- modifier = Modifier.padding(top = 20.dp),
- title = stringResource(id = R.string.i_completed_migration),
- expanded = false,
- toggleClick = { onViewAction(ViewAction.ToggleMigrationReady) },
- content = {
- Column {
- Text(
- modifier = Modifier.padding(top = 12.dp),
- text = stringResource(id = R.string.migration_error_msg),
- style = BodyCallout,
- color = colorResource(id = R.color.text_primary)
- )
- ButtonPrimary(
- text = stringResource(id = R.string.visit_forum),
- modifier = Modifier
- .fillMaxWidth()
- .padding(top = 16.dp),
- onClick = { onViewAction(ViewAction.VisitForum) },
- size = ButtonSize.Large
- )
- }
- }
- )
- }
-}
-
-@Composable
-fun InfoCard(
- modifier: Modifier = Modifier,
- title: String,
- expanded: Boolean,
- toggleClick: () -> Unit,
- content: @Composable AnimatedVisibilityScope.() -> Unit
-) {
-
- val cardOpened = remember { mutableStateOf(expanded) }
-
- val rotationDegree = remember {
- Animatable(
- if (expanded) ROTATION_CLOSED else ROTATION_OPENED
- )
- }
- val coroutineScope = rememberCoroutineScope()
-
- Card(
- modifier = modifier,
- backgroundColor = colorResource(id = R.color.shape_transparent),
- elevation = 0.dp,
- shape = RoundedCornerShape(16.dp)
- ) {
- Box {
- Image(
- painter = painterResource(id = R.drawable.icon_migration_card_arrow),
- contentDescription = "",
- modifier = Modifier
- .align(Alignment.TopEnd)
- .padding(top = 22.dp, end = 12.dp)
- .rotate(rotationDegree.value)
- .noRippleClickable {
- cardOpened.value = !cardOpened.value
- coroutineScope.launch {
- if (cardOpened.value) {
- toggleClick()
- rotationDegree.animateTo(ROTATION_CLOSED)
- } else {
- rotationDegree.animateTo(ROTATION_OPENED)
- }
- }
- }
)
-
- Column(
- Modifier
- .fillMaxWidth()
- .padding(20.dp)
- ) {
+ Spacer(modifier = Modifier.height(16.dp))
+ Text(
+ text = stringResource(R.string.migration_migration_failed),
+ style = HeadlineHeading,
+ color = colorResource(R.color.text_primary),
+ modifier = Modifier.fillMaxWidth(),
+ textAlign = TextAlign.Center
+ )
+ if (description.isNotEmpty()) {
+ Spacer(modifier = Modifier.height(8.dp))
Text(
- text = title,
- style = HeadlineSubheading,
- color = colorResource(id = R.color.text_primary)
+ text = description,
+ color = colorResource(R.color.text_secondary),
+ style = BodyCalloutRegular,
+ modifier = Modifier.padding(horizontal = 20.dp).fillMaxWidth(),
+ textAlign = TextAlign.Center
)
- AnimatedVisibility(visible = cardOpened.value) {
- content()
- }
}
}
+ ButtonPrimary(
+ modifier = Modifier
+ .padding(20.dp)
+ .align(Alignment.BottomCenter)
+ .fillMaxWidth(),
+ text = stringResource(R.string.migration_error_try_again),
+ size = ButtonSize.Large,
+ onClick = onRetryClicked
+ )
}
}
-
-private const val ANNOTATION_TAG = "here_text_tag"
-private const val ROTATION_OPENED = 0F
-private const val ROTATION_CLOSED = 180F
-
+@DefaultPreviews
@Composable
-private fun CloseButton(closeClicks: () -> Unit) {
- Box(modifier = Modifier.fillMaxSize()) {
- Image(painter = painterResource(id = R.drawable.ic_navigation_close),
- contentDescription = "close image",
- modifier = Modifier
- .align(Alignment.TopEnd)
- .padding(top = 12.dp, end = 12.dp)
- .noRippleClickable { closeClicks.invoke() }
- )
- }
+fun MigrationInProgressScreenPreview() {
+ MigrationInProgressScreen()
+}
+
+@DefaultPreviews
+@Composable
+fun MigrationFailedScreenPreview() {
+ MigrationFailedScreen(
+ state = MigrationHelperDelegate.State.Failed.NotEnoughSpace,
+ onRetryClicked = {}
+ )
+}
+
+@DefaultPreviews
+@Composable
+fun MigrationFailedGenericScreenPreview() {
+ MigrationFailedScreen(
+ state = MigrationHelperDelegate.State.Failed.UnknownError(
+ Exception(stringResource(R.string.default_text_placeholder))
+ ),
+ onRetryClicked = {}
+ )
}
\ No newline at end of file
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/vault/IntroduceVaultFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/vault/IntroduceVaultFragment.kt
index 9b254f617e..bb62fcb265 100644
--- a/app/src/main/java/com/anytypeio/anytype/ui/vault/IntroduceVaultFragment.kt
+++ b/app/src/main/java/com/anytypeio/anytype/ui/vault/IntroduceVaultFragment.kt
@@ -10,6 +10,7 @@ import androidx.compose.ui.platform.ViewCompositionStrategy
import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetComposeFragment
import com.anytypeio.anytype.ui.settings.typography
+@Deprecated("Outdated. To be deleted soon.")
class IntroduceVaultFragment : BaseBottomSheetComposeFragment() {
override fun onCreateView(
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/vault/IntroduceVaultScreen.kt b/app/src/main/java/com/anytypeio/anytype/ui/vault/IntroduceVaultScreen.kt
index 90b3876c5b..aa404a0205 100644
--- a/app/src/main/java/com/anytypeio/anytype/ui/vault/IntroduceVaultScreen.kt
+++ b/app/src/main/java/com/anytypeio/anytype/ui/vault/IntroduceVaultScreen.kt
@@ -34,6 +34,7 @@ import com.anytypeio.anytype.core_ui.views.ButtonSize
import com.anytypeio.anytype.core_ui.views.HeadlineHeading
import kotlinx.coroutines.launch
+@Deprecated("To be deleted")
@Composable
fun IntroduceVaultScreen(
onDoneClicked: () -> Unit
diff --git a/app/src/main/java/com/anytypeio/anytype/ui/vault/VaultFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/vault/VaultFragment.kt
index 6d00e0617f..bb524ab30a 100644
--- a/app/src/main/java/com/anytypeio/anytype/ui/vault/VaultFragment.kt
+++ b/app/src/main/java/com/anytypeio/anytype/ui/vault/VaultFragment.kt
@@ -117,13 +117,6 @@ class VaultFragment : BaseComposeFragment() {
Timber.e(it, "Error while opening profile settings from vault")
}
}
- is Command.ShowIntroduceVault -> {
- runCatching {
- findNavController().navigate(R.id.actionShowIntroduceVaultScreen)
- }.onFailure {
- Timber.e(it, "Error while opening introduce-vault-screen from vault")
- }
- }
is Command.Deeplink.Invite -> {
findNavController().navigate(
R.id.requestJoinSpaceScreen,
diff --git a/app/src/main/res/layout/fragment_object_menu.xml b/app/src/main/res/layout/fragment_object_menu.xml
index d7bd9d1c9a..7bf4498f39 100644
--- a/app/src/main/res/layout/fragment_object_menu.xml
+++ b/app/src/main/res/layout/fragment_object_menu.xml
@@ -1,209 +1,184 @@
-
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+ android:background="@drawable/dragger" />
+
+
+
+
-
+
+
+
+
-
-
-
-
+ app:title="@string/description" />
-
+
-
+
-
+
-
+
-
+
-
+
-
-
+
+
+
+
+
+ android:layout_marginTop="12dp"
+ android:layout_weight="0">
+ android:layout_height="match_parent"
+ android:layout_gravity="center_vertical" />
@@ -211,7 +186,7 @@
android:id="@+id/anchor"
android:layout_width="match_parent"
android:layout_height="1dp"
- app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
- />
-
\ No newline at end of file
+ app:layout_constraintEnd_toEndOf="parent" />
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_splash.xml b/app/src/main/res/layout/fragment_splash.xml
index 1d95f2888f..fabfb3e84e 100644
--- a/app/src/main/res/layout/fragment_splash.xml
+++ b/app/src/main/res/layout/fragment_splash.xml
@@ -5,13 +5,6 @@
android:layout_height="match_parent"
android:background="@color/background_primary">
-
-
+ android:visibility="gone" />
\ No newline at end of file
diff --git a/app/src/main/res/layout/layout_object_set_header.xml b/app/src/main/res/layout/layout_object_set_header.xml
index bd5f6d006f..df57ab26ac 100644
--- a/app/src/main/res/layout/layout_object_set_header.xml
+++ b/app/src/main/res/layout/layout_object_set_header.xml
@@ -84,7 +84,6 @@
android:ellipsize="end"
android:hint="@string/description"
android:inputType="textMultiLine"
- android:maxLines="3"
android:textColorHint="@color/text_tertiary"
tools:text="Description" />
diff --git a/app/src/main/res/navigation/graph.xml b/app/src/main/res/navigation/graph.xml
index e5089aa9ec..4d4c1b23dc 100644
--- a/app/src/main/res/navigation/graph.xml
+++ b/app/src/main/res/navigation/graph.xml
@@ -34,7 +34,7 @@
android:label="Object-Menu-Screen" />
+
+
+
@@ -109,9 +114,10 @@
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
+