Compare commits

...

63 Commits

Author SHA1 Message Date
konstantiniiv
e8bbfec912 DROID-1949 fix 2023-11-16 17:48:57 +01:00
konstantiniiv
7ad158e7ed DROID-1949 close templates widget 2023-11-16 15:04:03 +01:00
uburoiubu
ef49cfe6bf
v0.26.11-beta 2023-11-16 11:42:15 +01:00
uburoiubu
dab2ac2e54
DROID-1965 Protocol | Enhancement | MW 0.29.12 2023-11-16 11:41:49 +01:00
uburoiubu
dcb80495de
v0.26.10-beta 2023-11-16 11:38:13 +01:00
Konstantin Ivanov
82a20883f3
DROID-1964 View | Fix | Relations done and name (#558) 2023-11-16 11:36:47 +01:00
Konstantin Ivanov
e0ce5dffbb
DROID-1949 Templates | Fix | Templates disappear in the collection after selecting a type (#557) 2023-11-16 10:32:01 +01:00
uburoiubu
3e09dc516a
v0.26.9-beta 2023-11-15 22:44:12 +01:00
Evgenii Kozlov
ae3dc2ef80
DROID-1955 Multispaces | Fix | Active space should be the first on the menu after app restart (#556) 2023-11-15 17:35:57 +01:00
Konstantin Ivanov
11e1bc7600
DROID-1939 View | Don't copy filter and sort when create new view (#554) 2023-11-15 17:12:44 +01:00
Konstantin Ivanov
9ec69ce50d
DROID-1945 Templates | Fix | Templates widget with only blank template (#555) 2023-11-15 17:11:38 +01:00
Konstantin Ivanov
1cd675563c
DROID-1886 Space | Menu with remote storage and limits per account (#548) 2023-11-15 17:09:36 +01:00
Evgenii Kozlov
bd20fb9a19
DROID-1957 Types | Fix | Fix marketplace type filtering (#551) 2023-11-15 15:32:31 +01:00
uburoiubu
7f38e77f53
v0.26.8-beta 2023-11-15 13:52:39 +01:00
Evgenii Kozlov
e656540b7e
DROID-1958 Relations | Fix | Fix broken limit-object-type-picker screen (#549) 2023-11-15 13:51:45 +01:00
Evgenii Kozlov
5ca83e11ce
DROID-1959 Protocol | Enhancement | MW 0.29.11 (#550) 2023-11-15 13:50:57 +01:00
uburoiubu
8667389f17
v0.26.7-beta 2023-11-14 19:07:00 +01:00
uburoiubu
fe847c6416
DROID-1814 Multispaces | Fix | Fix space type naming 2023-11-14 19:05:20 +01:00
Evgenii Kozlov
0ed7004469
DROID-1944 Multispaces | Fix | Re-set global subscriptions for type and relations when space is switched (#546) 2023-11-14 18:57:23 +01:00
Evgenii Kozlov
e958d1d0ca
DROID-1946 Multispaces | Fix | Avoid showing duplicated spaces on create-space screen (#545) 2023-11-14 18:57:05 +01:00
Evgenii Kozlov
1b59726142
DROID-1937 Widgets | Fix | Filter out files, audio, and images from recently edited widget (#544) 2023-11-14 17:03:36 +01:00
uburoiubu
4c3d20c989
v0.26.6-beta 2023-11-14 16:32:12 +01:00
uburoiubu
c78e09d724
DROID-1884 Onboarding | Fix | Update title and button name on Login screen 2023-11-14 16:30:47 +01:00
uburoiubu
cc1868ad9e
DROID-1859 Multispaces | Fix | Fixed tests (#543) 2023-11-14 16:26:16 +01:00
Evgenii Kozlov
c95cc66b5e
DROID-1859 Multispaces | Fix | Switch space to personal when the current one has been deleted (#543) 2023-11-14 15:17:22 +01:00
Evgenii Kozlov
9561af3164
DROID-1938 Protocol | Enhancement | MW 0.29.10 (#542) 2023-11-14 12:55:02 +01:00
Evgenii Kozlov
5c2bcda941
DROID-1880 App | Fix | Fix update-app warning texts (#541) 2023-11-14 12:51:34 +01:00
uburoiubu
d6f7c7737b
DROID-1833 Widgets | Fix | Fix filters for widgets with recently edited objects (#539) 2023-11-13 20:15:51 +01:00
Evgenii Kozlov
55fc4a2da7
DROID-1833 Widgets | Fix | Fix filters for full-screen widgets with recently edited objects (#539) 2023-11-13 19:57:51 +01:00
uburoiubu
29c70708ca
v0.26.5-beta 2023-11-13 17:19:01 +01:00
Evgenii Kozlov
06048dfec5
DROID-1833 Widgets | Fix | Change recently edited widget filter (#538) 2023-11-13 17:17:13 +01:00
Evgenii Kozlov
e71014931c
DROID-1929 Protocol | Enhancement | MW 0.29.9 (#535) 2023-11-13 14:34:32 +01:00
Evgenii Kozlov
49f9fef100
DROID-1904 Multispaces | Fix | Incorrect button height with keyboard open when creating new space (#537) 2023-11-13 14:34:05 +01:00
Konstantin Ivanov
eaf5cf386a
DROID-1761 Relations | Fix | Relations are duplicated in DataView (#533) 2023-11-13 14:31:25 +01:00
Evgenii Kozlov
b2027538cb
DROID-1883 Multispaces | Fix | Fix corner radius for space icons (#531) 2023-11-09 19:06:57 +01:00
uburoiubu
2d4cde60c4
v0.26.4-beta 2023-11-09 16:59:22 +01:00
konstantiniiv
f87fad40ef DROID-1921 Tech | Integrate StackGoroutines, fix tests 2023-11-09 16:38:38 +01:00
Evgenii Kozlov
3ba407ab18
DROID-1823 Analytics | Create-space analytics (#529) 2023-11-09 16:25:19 +01:00
Evgenii Kozlov
4a11f304e7
DROID-1734 Analytics | Fix | Events for space and account settings (#530) 2023-11-09 16:25:00 +01:00
Evgenii Kozlov
68c5d67ed6
DROID-1835 Analytics | Added space-deletion events (#528) 2023-11-09 15:56:12 +01:00
Evgenii Kozlov
b33817d558
DROID-1869 Widgets | Fix | Profile icon should be circular (#527)
Co-authored-by: Konstantin Ivanov <54908981+konstantiniiv@users.noreply.github.com>
2023-11-09 15:28:36 +01:00
Konstantin Ivanov
2673b5bfc5 DROID-1921 Tech | Integrate StackGoroutines, added to the menu (#524) 2023-11-09 14:55:55 +01:00
Konstantin Ivanov
06e9e581bc DROID-1921 Tech | Integrate Debug Goroutines use case (#522) 2023-11-09 14:55:40 +01:00
Evgenii Kozlov
154545b7a7
DROID-1913 Onboarding | Fix | Misc. UX and design fixes (#526) 2023-11-09 14:17:16 +01:00
Konstantin Ivanov
201987e705
DROID-1897 Template | Fix | Make template from objects, text fix (#525) 2023-11-09 12:03:28 +01:00
uburoiubu
4128c82e14
v0.26.3-beta 2023-11-08 21:34:54 +01:00
Evgenii Kozlov
49fef69df0
DROID-1920 App | Tech | Unsubscribe when needed (#523) 2023-11-08 21:32:09 +01:00
uburoiubu
290767c598
DROID-1623 Onboarding | Fix | Design fixes 2023-11-08 18:27:15 +01:00
Evgenii Kozlov
21e4ab8523
DROID-1769 Objects | Introduce new object creation flow to editor, data view, library and full-screen widgets (#521) 2023-11-08 16:54:50 +01:00
Konstantin Ivanov
6bc114676d
DROID-1898 Templates | Fix | Blank state after tapping the New+ button (#519) 2023-11-08 15:58:50 +01:00
Konstantin Ivanov
242d6b41e6 DROID-1706 Analytics | SelectObjectType event (#515) 2023-11-07 16:05:48 +01:00
Evgenii Kozlov
95d4c055c3
DROID-1916 Protocol | Enhancement | MW 0.29.8 (#517) 2023-11-07 14:47:28 +01:00
Evgenii Kozlov
c75342bc34
DROID-1914 Widgets | Added haptic feedback for widgets actions (#514) 2023-11-07 11:51:13 +01:00
uburoiubu
799d0dd951
DROID-1769 Objects | Fix | Support nested scrolling on create-object-of-type screen 2023-11-07 00:54:48 +01:00
uburoiubu
1e6d2f2b97
v0.26.2-beta 2023-11-06 21:43:54 +01:00
uburoiubu
9fc67d4c8b
DROID-1769 Objects | Fix | Design fixes for new-object-creation UX panel 2023-11-06 21:43:26 +01:00
uburoiubu
fa564f7109
DROID-1769 Objects | Fix | Switch to FlowLayout for drawing screen content for new object-creation UX 2023-11-06 21:15:02 +01:00
uburoiubu
83d9ad8a4c
DROID-1769 Objects | Fix | Ensure unique keys for type views (#513) 2023-11-06 20:44:45 +01:00
uburoiubu
f7029501dd
v0.26.1-beta 2023-11-06 20:28:20 +01:00
Evgenii Kozlov
018a3bb62b
DROID-1769 Objects | Feature | New object-creation flow (#513) 2023-11-06 20:26:27 +01:00
Evgenii Kozlov
372bfa4375
DROID-1623 Onboarding | Fix | Misc. fixes, redesign, and renaming (#511) 2023-11-06 19:39:56 +01:00
Konstantin Ivanov
a9d75d8d57
DROID-1910 Type | Fix | Crash on object type change (#512) 2023-11-06 16:22:50 +01:00
uburoiubu
7672503414
DROID-1908 Onboarding | Fix | Capitalize button text 2023-11-06 11:19:30 +01:00
176 changed files with 4128 additions and 1435 deletions

View File

@ -20,6 +20,13 @@ object EventsDictionary {
// Settings events
const val screenSettingSpacesSpaceIndex = "ScreenSettingsSpaceIndex"
const val screenSettingsAccount = "ScreenSettingsAccount"
const val clickDeleteSpace = "ClickDeleteSpace"
const val clickDeleteSpaceWarning = "ClickDeleteSpaceWarning"
const val createSpace = "CreateSpace"
const val switchSpace = "SwitchSpace"
const val deleteSpace = "DeleteSpace"
const val screenSettingsSpaceCreate = "ScreenSettingsSpaceCreate"
const val wallpaperSet = "SettingsWallpaperSet"
@ -48,6 +55,7 @@ object EventsDictionary {
const val appearanceScreenShow = "ScreenSettingsAppearance"
const val screenSettingsStorage = "ScreenSettingsStorageIndex"
const val screenSettingsStorageManage = "ScreenSettingsStorageManager"
const val screenSettingsSpaceStorageManager = "ScreenSettingsSpaceStorageManager"
const val screenSettingsStorageOffload = "ScreenFileOffloadWarning"
const val settingsStorageOffload = "SettingsStorageOffload"
const val screenSettingsDelete = "ScreenSettingsDelete"
@ -57,6 +65,7 @@ object EventsDictionary {
const val searchResult = "SearchResult"
const val searchWords = "SearchWords"
const val objectTypeChanged = "ChangeObjectType"
const val selectObjectType = "SelectObjectType"
const val objectLayoutChange = "ChangeLayout"
const val objectSetIcon = "SetIcon"
const val objectRemoveIcon = "RemoveIcon"
@ -206,6 +215,7 @@ object EventsDictionary {
const val objPowerTool = "Powertool"
const val objTurnInto = "TurnInto"
const val screenSettings = "ScreenSettings"
const val settings = "Settings"
const val screenDeletion = "ScreenDeletion"
const val navigation = "Navigation"
}

View File

@ -1,4 +1,4 @@
version.versionMajor=0
version.versionMinor=26
version.versionPatch=0
version.versionPatch=11
version.useDatedVersionName=false

View File

@ -559,7 +559,7 @@ open class EditorTestSetup {
repo.stub {
onBlocking {
searchObjects(
filters = ObjectSearchConstants.filterObjectTypeLibrary(workspaceId),
filters = ObjectSearchConstants.filterTypes(workspaceId),
keys = ObjectSearchConstants.defaultKeysObjectType,
sorts = emptyList(),
limit = 0,

View File

@ -16,6 +16,7 @@ import com.anytypeio.anytype.domain.auth.repo.AuthRepository
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.base.Result
import com.anytypeio.anytype.domain.block.interactor.UpdateText
import com.anytypeio.anytype.domain.block.interactor.sets.GetObjectTypes
import com.anytypeio.anytype.domain.block.repo.BlockRepository
import com.anytypeio.anytype.domain.collections.AddObjectToCollection
import com.anytypeio.anytype.domain.config.ConfigStorage
@ -150,6 +151,9 @@ abstract class TestObjectSetSetup {
@Mock
lateinit var configStorage: ConfigStorage
@Mock
lateinit var getObjectTypes: GetObjectTypes
@Mock
lateinit var createTemplate: CreateTemplate
@ -265,14 +269,13 @@ abstract class TestObjectSetSetup {
objectStore = objectStore,
addObjectToCollection = addObjectToCollection,
storeOfObjectTypes = storeOfObjectTypes,
getDefaultObjectType = getDefaultObjectType,
updateDataViewViewer = updateDataViewViewer,
templatesContainer = templatesContainer,
setObjectListIsArchived = setObjectListIsArchived,
duplicateObjects = duplicateObjects,
viewerDelegate = viewerDelegate,
spaceManager = spaceManager,
createTemplate = createTemplate
createTemplate = createTemplate,
getObjectTypes = getObjectTypes
)
}

View File

@ -3,6 +3,8 @@ package com.anytypeio.anytype.di.common
import android.content.Context
import com.anytypeio.anytype.BuildConfig
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.di.feature.AddDataViewRelationObjectValueModule
import com.anytypeio.anytype.di.feature.AddDataViewRelationOptionValueModule
import com.anytypeio.anytype.di.feature.AddFileRelationModule
import com.anytypeio.anytype.di.feature.AddObjectRelationModule
import com.anytypeio.anytype.di.feature.AddObjectRelationValueModule
@ -64,6 +66,7 @@ import com.anytypeio.anytype.di.feature.auth.DaggerDeletedAccountComponent
import com.anytypeio.anytype.di.feature.cover.UnsplashModule
import com.anytypeio.anytype.di.feature.home.DaggerHomeScreenComponent
import com.anytypeio.anytype.di.feature.library.DaggerLibraryComponent
import com.anytypeio.anytype.di.feature.objects.DaggerCreateObjectOfTypeComponent
import com.anytypeio.anytype.di.feature.onboarding.DaggerOnboardingComponent
import com.anytypeio.anytype.di.feature.onboarding.DaggerOnboardingStartComponent
import com.anytypeio.anytype.di.feature.onboarding.login.DaggerOnboardingLoginSetupComponent
@ -71,7 +74,6 @@ import com.anytypeio.anytype.di.feature.onboarding.login.DaggerOnboardingMnemoni
import com.anytypeio.anytype.di.feature.onboarding.signup.DaggerOnboardingMnemonicComponent
import com.anytypeio.anytype.di.feature.onboarding.signup.DaggerOnboardingSoulCreationAnimComponent
import com.anytypeio.anytype.di.feature.onboarding.signup.DaggerOnboardingSoulCreationComponent
import com.anytypeio.anytype.di.feature.onboarding.signup.DaggerOnboardingVoidComponent
import com.anytypeio.anytype.di.feature.relations.DaggerRelationCreateFromLibraryComponent
import com.anytypeio.anytype.di.feature.relations.DaggerRelationEditComponent
import com.anytypeio.anytype.di.feature.relations.LimitObjectTypeModule
@ -89,6 +91,7 @@ import com.anytypeio.anytype.di.feature.sets.viewer.ViewerImagePreviewSelectModu
import com.anytypeio.anytype.di.feature.settings.DaggerAboutAppComponent
import com.anytypeio.anytype.di.feature.settings.DaggerAppearanceComponent
import com.anytypeio.anytype.di.feature.settings.DaggerFilesStorageComponent
import com.anytypeio.anytype.di.feature.settings.DaggerSpacesStorageComponent
import com.anytypeio.anytype.di.feature.settings.LogoutWarningModule
import com.anytypeio.anytype.di.feature.settings.MainSettingsModule
import com.anytypeio.anytype.di.feature.settings.ProfileModule
@ -374,7 +377,7 @@ class ComponentManager(
.build()
}
val dataViewRelationListComponent = DependentComponentMap { id ->
val objectSetRelationListComponent = DependentComponentMap { id ->
objectSetComponent
.get(id)
.objectRelationListComponent()
@ -494,6 +497,14 @@ class ComponentManager(
.build()
}
val addDataViewObjectRelationValueComponent = DependentComponentMap { ctx ->
dataViewRelationValueComponent
.get(ctx)
.addDataViewRelationOptionValueComponent()
.module(AddDataViewRelationOptionValueModule)
.build()
}
val objectObjectRelationValueComponent = DependentComponentMap { ctx ->
editorComponent
.get(ctx)
@ -518,6 +529,14 @@ class ComponentManager(
.build()
}
val addDataViewRelationObjectValueComponent = DependentComponentMap { ctx ->
dataViewRelationValueComponent
.get(ctx)
.addDataViewRelationObjectValueComponent()
.module(AddDataViewRelationObjectValueModule)
.build()
}
val addObjectRelationObjectValueComponent = DependentComponentMap { ctx ->
objectObjectRelationValueComponent
.get(ctx)
@ -848,6 +867,12 @@ class ComponentManager(
.build()
}
val spacesStorageComponent = Component {
DaggerSpacesStorageComponent.builder()
.withDependencies(findComponentDependencies())
.build()
}
val appearanceComponent = Component {
DaggerAppearanceComponent
.factory()
@ -928,12 +953,6 @@ class ComponentManager(
.create(findComponentDependencies())
}
val onboardingNewVoidComponent = Component {
DaggerOnboardingVoidComponent
.factory()
.create(findComponentDependencies())
}
val onboardingMnemonicComponent = Component {
DaggerOnboardingMnemonicComponent
.factory()
@ -982,6 +1001,13 @@ class ComponentManager(
.create(findComponentDependencies())
}
val createObjectOfTypeComponent = Component {
DaggerCreateObjectOfTypeComponent
.factory()
.create(findComponentDependencies())
}
class Component<T>(private val builder: () -> T) {
private var instance: T? = null

View File

@ -0,0 +1,52 @@
package com.anytypeio.anytype.di.feature
import com.anytypeio.anytype.core_utils.di.scope.PerDialog
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes
import com.anytypeio.anytype.domain.search.SearchObjects
import com.anytypeio.anytype.domain.workspace.SpaceManager
import com.anytypeio.anytype.presentation.relations.add.AddObjectRelationViewModel
import com.anytypeio.anytype.presentation.relations.providers.ObjectRelationProvider
import com.anytypeio.anytype.presentation.relations.providers.ObjectValueProvider
import com.anytypeio.anytype.ui.relations.add.AddObjectRelationFragment
import dagger.Module
import dagger.Provides
import dagger.Subcomponent
import javax.inject.Named
@Subcomponent(modules = [AddDataViewRelationObjectValueModule::class])
@PerDialog
interface AddDataViewRelationObjectValueSubComponent {
@Subcomponent.Builder
interface Builder {
fun module(module: AddDataViewRelationObjectValueModule): Builder
fun build(): AddDataViewRelationObjectValueSubComponent
}
fun inject(fragment: AddObjectRelationFragment)
}
@Module
object AddDataViewRelationObjectValueModule {
@JvmStatic
@Provides
@PerDialog
fun provideViewModelFactory(
@Named(ObjectRelationProvider.DATA_VIEW_PROVIDER_TYPE) relations: ObjectRelationProvider,
@Named(ObjectRelationProvider.DATA_VIEW_PROVIDER_TYPE) values: ObjectValueProvider,
storeOfObjectTypes: StoreOfObjectTypes,
searchObjects: SearchObjects,
urlBuilder: UrlBuilder,
spaceManager: SpaceManager
): AddObjectRelationViewModel.Factory = AddObjectRelationViewModel.Factory(
relations = relations,
values = values,
searchObjects = searchObjects,
urlBuilder = urlBuilder,
storeOfObjectTypes = storeOfObjectTypes,
spaceManager = spaceManager
)
}

View File

@ -13,6 +13,7 @@ import com.anytypeio.anytype.presentation.relations.add.AddOptionsRelationProvid
import com.anytypeio.anytype.presentation.relations.add.AddOptionsRelationViewModel
import com.anytypeio.anytype.presentation.relations.providers.ObjectDetailProvider
import com.anytypeio.anytype.presentation.relations.providers.ObjectRelationProvider
import com.anytypeio.anytype.presentation.relations.providers.ObjectRelationProvider.Companion.DATA_VIEW_PROVIDER_TYPE
import com.anytypeio.anytype.presentation.relations.providers.ObjectRelationProvider.Companion.INTRINSIC_PROVIDER_TYPE
import com.anytypeio.anytype.presentation.relations.providers.ObjectValueProvider
import com.anytypeio.anytype.presentation.util.Dispatcher
@ -36,6 +37,18 @@ interface AddObjectRelationValueSubComponent {
fun inject(fragment: AddOptionsRelationFragment)
}
@Subcomponent(modules = [AddDataViewRelationOptionValueModule::class])
@PerDialog
interface AddDataViewRelationOptionValueSubComponent {
@Subcomponent.Builder
interface Builder {
fun module(module: AddDataViewRelationOptionValueModule): Builder
fun build(): AddDataViewRelationOptionValueSubComponent
}
fun inject(fragment: AddOptionsRelationDVFragment)
}
@Module
object AddObjectRelationValueModule {
@ -91,6 +104,43 @@ object AddObjectRelationValueModule {
spaceManager = spaceManager
)
@JvmStatic
@Provides
@PerDialog
fun createRelationOption(
repo: BlockRepository
): CreateRelationOption = CreateRelationOption(repo = repo)
}
@Module
object AddDataViewRelationOptionValueModule {
@JvmStatic
@Provides
@PerDialog
fun provideViewModelFactoryForDataView(
@Named(DATA_VIEW_PROVIDER_TYPE) relations: ObjectRelationProvider,
@Named(DATA_VIEW_PROVIDER_TYPE) values: ObjectValueProvider,
dispatcher: Dispatcher<Payload>,
createRelationOption: CreateRelationOption,
analytics: Analytics,
setObjectDetail: UpdateDetail,
detailsProvider: ObjectDetailProvider,
getOptions: GetOptions,
spaceManager: SpaceManager
): AddOptionsRelationDVViewModel.Factory = AddOptionsRelationDVViewModel.Factory(
relations = relations,
values = values,
dispatcher = dispatcher,
createRelationOption = createRelationOption,
optionsProvider = AddOptionsRelationProvider(),
analytics = analytics,
setObjectDetail = setObjectDetail,
detailsProvider = detailsProvider,
getOptions = getOptions,
spaceManager = spaceManager
)
@JvmStatic
@Provides
@PerDialog

View File

@ -16,6 +16,7 @@ import com.anytypeio.anytype.domain.device.PathProvider
import com.anytypeio.anytype.domain.platform.MetricsProvider
import com.anytypeio.anytype.domain.search.ObjectTypesSubscriptionManager
import com.anytypeio.anytype.domain.search.RelationsSubscriptionManager
import com.anytypeio.anytype.domain.spaces.SpaceDeletedStatusWatcher
import com.anytypeio.anytype.domain.theme.GetTheme
import com.anytypeio.anytype.domain.wallpaper.ObserveWallpaper
import com.anytypeio.anytype.domain.wallpaper.RestoreWallpaper
@ -45,6 +46,7 @@ interface MainEntrySubComponent {
@Module
object MainEntryModule {
@JvmStatic
@PerScreen
@Provides
@ -58,7 +60,8 @@ object MainEntryModule {
relationsSubscriptionManager: RelationsSubscriptionManager,
objectTypesSubscriptionManager: ObjectTypesSubscriptionManager,
checkAuthorizationStatus: CheckAuthorizationStatus,
configStorage: ConfigStorage
configStorage: ConfigStorage,
spaceDeletedStatusWatcher: SpaceDeletedStatusWatcher
): MainViewModelFactory = MainViewModelFactory(
resumeAccount = resumeAccount,
analytics = analytics,
@ -69,7 +72,8 @@ object MainEntryModule {
relationsSubscriptionManager = relationsSubscriptionManager,
objectTypesSubscriptionManager = objectTypesSubscriptionManager,
checkAuthorizationStatus = checkAuthorizationStatus,
configStorage = configStorage
configStorage = configStorage,
spaceDeletedStatusWatcher = spaceDeletedStatusWatcher
)
@JvmStatic

View File

@ -1,9 +1,9 @@
package com.anytypeio.anytype.di.feature
import android.content.Context
import com.anytypeio.anytype.analytics.base.Analytics
import com.anytypeio.anytype.core_models.Payload
import com.anytypeio.anytype.core_utils.di.scope.PerDialog
import com.anytypeio.anytype.core_utils.di.scope.PerScreen
import com.anytypeio.anytype.core_utils.tools.FeatureToggles
import com.anytypeio.anytype.domain.`object`.DuplicateObject
import com.anytypeio.anytype.domain.auth.repo.AuthRepository
@ -30,7 +30,9 @@ import com.anytypeio.anytype.presentation.objects.menu.ObjectMenuViewModel
import com.anytypeio.anytype.presentation.objects.menu.ObjectSetMenuViewModel
import com.anytypeio.anytype.presentation.sets.state.ObjectState
import com.anytypeio.anytype.presentation.util.Dispatcher
import com.anytypeio.anytype.presentation.util.downloader.DebugGoroutinesShareDownloader
import com.anytypeio.anytype.presentation.util.downloader.DebugTreeShareDownloader
import com.anytypeio.anytype.presentation.util.downloader.UriFileProvider
import com.anytypeio.anytype.ui.editor.sheets.ObjectMenuFragment
import com.anytypeio.anytype.ui.sets.ObjectSetMenuFragment
import dagger.Module
@ -117,7 +119,8 @@ object ObjectMenuModule {
delegator: Delegator<Action>,
addObjectToCollection: AddObjectToCollection,
createTemplateFromObject: CreateTemplateFromObject,
setObjectDetails: SetObjectDetails
setObjectDetails: SetObjectDetails,
debugGoroutinesShareDownloader: DebugGoroutinesShareDownloader
): ObjectMenuViewModel.Factory = ObjectMenuViewModel.Factory(
setObjectIsArchived = setObjectIsArchived,
duplicateObject = duplicateObject,
@ -134,7 +137,8 @@ object ObjectMenuModule {
menuOptionsProvider = createMenuOptionsProvider(storage, featureToggles),
addObjectToCollection = addObjectToCollection,
createTemplateFromObject = createTemplateFromObject,
setObjectDetails = setObjectDetails
setObjectDetails = setObjectDetails,
debugGoroutinesShareDownloader = debugGoroutinesShareDownloader
)
@JvmStatic
@ -166,6 +170,21 @@ object ObjectMenuModule {
repo = repo,
dispatchers = dispatchers
)
@JvmStatic
@Provides
@PerDialog
fun debugGoRoutines(
repo: BlockRepository,
context: Context,
fileProvider: UriFileProvider,
dispatchers: AppCoroutineDispatchers
): DebugGoroutinesShareDownloader = DebugGoroutinesShareDownloader(
repo = repo,
context = context.applicationContext,
uriFileProvider = fileProvider,
dispatchers = dispatchers
)
}
@Module
@ -186,7 +205,8 @@ object ObjectSetMenuModule {
state: MutableStateFlow<ObjectState>,
featureToggles: FeatureToggles,
dispatcher: Dispatcher<Payload>,
addObjectToCollection: AddObjectToCollection
addObjectToCollection: AddObjectToCollection,
debugGoroutinesShareDownloader: DebugGoroutinesShareDownloader
): ObjectSetMenuViewModel.Factory = ObjectSetMenuViewModel.Factory(
setObjectIsArchived = setObjectIsArchived,
addToFavorite = addToFavorite,
@ -199,7 +219,8 @@ object ObjectSetMenuModule {
objectState = state,
dispatcher = dispatcher,
menuOptionsProvider = createMenuOptionsProvider(state, featureToggles),
addObjectToCollection = addObjectToCollection
addObjectToCollection = addObjectToCollection,
debugGoroutinesShareDownloader = debugGoroutinesShareDownloader
)
@JvmStatic
@ -222,6 +243,21 @@ object ObjectSetMenuModule {
dispatchers = dispatchers
)
@JvmStatic
@Provides
@PerDialog
fun debugGoRoutines(
repo: BlockRepository,
context: Context,
fileProvider: UriFileProvider,
dispatchers: AppCoroutineDispatchers
): DebugGoroutinesShareDownloader = DebugGoroutinesShareDownloader(
repo = repo,
context = context.applicationContext,
uriFileProvider = fileProvider,
dispatchers = dispatchers
)
@JvmStatic
private fun createMenuOptionsProvider(
state: StateFlow<ObjectState>,

View File

@ -38,6 +38,9 @@ interface DataViewObjectRelationValueSubComponent {
fun addObjectRelationValueComponent(): AddObjectRelationValueSubComponent.Builder
fun addObjectRelationObjectValueComponent(): AddObjectRelationSubComponent.Builder
fun addRelationFileValueAddComponent() : AddFileRelationSubComponent.Builder
fun addDataViewRelationOptionValueComponent(): AddDataViewRelationOptionValueSubComponent.Builder
fun addDataViewRelationObjectValueComponent(): AddDataViewRelationObjectValueSubComponent.Builder
}
@Subcomponent(modules = [SetOrCollectionRelationValueModule::class])

View File

@ -19,6 +19,7 @@ import com.anytypeio.anytype.di.feature.sets.viewer.ViewerImagePreviewSelectSubc
import com.anytypeio.anytype.domain.auth.repo.AuthRepository
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.block.interactor.UpdateText
import com.anytypeio.anytype.domain.block.interactor.sets.GetObjectTypes
import com.anytypeio.anytype.domain.block.repo.BlockRepository
import com.anytypeio.anytype.domain.collections.AddObjectToCollection
import com.anytypeio.anytype.domain.config.ConfigStorage
@ -93,7 +94,9 @@ import com.anytypeio.anytype.presentation.templates.ObjectTypeTemplatesContainer
import com.anytypeio.anytype.presentation.util.CopyFileToCacheDirectory
import com.anytypeio.anytype.presentation.util.DefaultCopyFileToCacheDirectory
import com.anytypeio.anytype.presentation.util.Dispatcher
import com.anytypeio.anytype.presentation.util.downloader.UriFileProvider
import com.anytypeio.anytype.providers.DefaultCoverImageHashProvider
import com.anytypeio.anytype.providers.DefaultUriFileProvider
import com.anytypeio.anytype.ui.sets.ObjectSetFragment
import dagger.Binds
import dagger.Module
@ -186,6 +189,14 @@ object ObjectSetModule {
dispatchers = dispatchers
)
@JvmStatic
@Provides
@PerScreen
fun provideGetObjectTypesUseCase(
repository: BlockRepository,
dispatchers: AppCoroutineDispatchers
): GetObjectTypes = GetObjectTypes(repository, dispatchers)
@JvmStatic
@Provides
@PerScreen
@ -218,8 +229,7 @@ object ObjectSetModule {
addObjectToCollection: AddObjectToCollection,
convertObjectToCollection: ConvertObjectToCollection,
storeOfObjectTypes: StoreOfObjectTypes,
getDefaultObjectType: GetDefaultObjectType,
updateDataViewViewer: UpdateDataViewViewer,
getObjectTypes: GetObjectTypes,
duplicateObjects: DuplicateObjects,
templatesContainer: ObjectTypeTemplatesContainer,
setObjectListIsArchived: SetObjectListIsArchived,
@ -255,8 +265,7 @@ object ObjectSetModule {
addObjectToCollection = addObjectToCollection,
objectToCollection = convertObjectToCollection,
storeOfObjectTypes = storeOfObjectTypes,
getDefaultObjectType = getDefaultObjectType,
updateDataViewViewer = updateDataViewViewer,
getObjectTypes = getObjectTypes,
duplicateObjects = duplicateObjects,
templatesContainer = templatesContainer,
setObjectListIsArchived = setObjectListIsArchived,
@ -639,6 +648,12 @@ object ObjectSetModule {
fun bindCoverImageHashProvider(
defaultProvider: DefaultCoverImageHashProvider
): CoverImageHashProvider
@PerScreen
@Binds
fun bindUriFileProvider(
defaultProvider: DefaultUriFileProvider
): UriFileProvider
}
@JvmStatic

View File

@ -24,9 +24,9 @@ import com.anytypeio.anytype.domain.page.CreateObject
import com.anytypeio.anytype.domain.platform.MetricsProvider
import com.anytypeio.anytype.domain.search.ObjectTypesSubscriptionManager
import com.anytypeio.anytype.domain.search.RelationsSubscriptionManager
import com.anytypeio.anytype.domain.spaces.SpaceDeletedStatusWatcher
import com.anytypeio.anytype.domain.templates.GetTemplates
import com.anytypeio.anytype.domain.workspace.SpaceManager
import com.anytypeio.anytype.domain.workspace.WorkspaceManager
import com.anytypeio.anytype.presentation.splash.SplashViewModelFactory
import com.anytypeio.anytype.ui.splash.SplashFragment
import dagger.Binds
@ -175,7 +175,6 @@ object SplashModule {
interface SplashDependencies : ComponentDependencies {
fun blockRepository(): BlockRepository
fun workspaceManager(): WorkspaceManager
fun urlBuilder(): UrlBuilder
fun analytics(): Analytics
fun relationsSubscriptionManager(): RelationsSubscriptionManager
@ -190,4 +189,5 @@ interface SplashDependencies : ComponentDependencies {
fun crashReporter(): CrashReporter
fun metricsProvider(): MetricsProvider
fun spaceManager(): SpaceManager
fun spaceStatusWatcher(): SpaceDeletedStatusWatcher
}

View File

@ -12,7 +12,9 @@ import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.config.ConfigStorage
import com.anytypeio.anytype.domain.config.UserSettingsRepository
import com.anytypeio.anytype.domain.misc.AppActionManager
import com.anytypeio.anytype.domain.search.ObjectTypesSubscriptionManager
import com.anytypeio.anytype.domain.search.RelationsSubscriptionManager
import com.anytypeio.anytype.domain.spaces.SpaceDeletedStatusWatcher
import com.anytypeio.anytype.domain.workspace.SpaceManager
import com.anytypeio.anytype.ext.DefaultDateHelper
import com.anytypeio.anytype.presentation.auth.account.DeletedAccountViewModel
@ -91,10 +93,13 @@ object DeletedAccountModule {
interface DeletedAccountDependencies : ComponentDependencies {
fun analytics(): Analytics
fun appActionManager(): AppActionManager
fun relationsSubscriptionManager(): RelationsSubscriptionManager
fun dispatchers(): AppCoroutineDispatchers
fun configStorage(): ConfigStorage
fun authRepository(): AuthRepository
fun userSettingsRepository(): UserSettingsRepository
fun spaceManager(): SpaceManager
fun relationsSubscriptionManager(): RelationsSubscriptionManager
fun objectTypesSubscriptionManager(): ObjectTypesSubscriptionManager
fun spaceDeletedStatusWatcher(): SpaceDeletedStatusWatcher
}

View File

@ -0,0 +1,48 @@
package com.anytypeio.anytype.di.feature.objects
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.workspace.SpaceManager
import com.anytypeio.anytype.presentation.objects.CreateObjectOfTypeViewModel
import com.anytypeio.anytype.ui.objects.creation.CreateObjectOfTypeFragment
import dagger.Binds
import dagger.Component
import dagger.Module
@Component(
dependencies = [CreateObjectOfTypeDependencies::class],
modules = [
CreateObjectOfTypeModule::class,
CreateObjectOfTypeModule.Declarations::class
]
)
@PerScreen
interface CreateObjectOfTypeComponent {
@Component.Factory
interface Builder {
fun create(dependencies: CreateObjectOfTypeDependencies): CreateObjectOfTypeComponent
}
fun inject(fragment: CreateObjectOfTypeFragment)
}
@Module
object CreateObjectOfTypeModule {
@Module
interface Declarations {
@Binds
@PerScreen
fun bindViewModelFactory(factory: CreateObjectOfTypeViewModel.Factory): ViewModelProvider.Factory
}
}
interface CreateObjectOfTypeDependencies : ComponentDependencies {
fun repo(): BlockRepository
fun analytics(): Analytics
fun dispatchers(): AppCoroutineDispatchers
fun spaceManager(): SpaceManager
}

View File

@ -12,7 +12,7 @@ import com.anytypeio.anytype.domain.device.PathProvider
import com.anytypeio.anytype.domain.platform.MetricsProvider
import com.anytypeio.anytype.domain.search.ObjectTypesSubscriptionManager
import com.anytypeio.anytype.domain.search.RelationsSubscriptionManager
import com.anytypeio.anytype.domain.workspace.WorkspaceManager
import com.anytypeio.anytype.domain.spaces.SpaceDeletedStatusWatcher
import com.anytypeio.anytype.presentation.onboarding.login.OnboardingLoginSetupViewModel
import dagger.Binds
import dagger.Component
@ -55,9 +55,9 @@ interface OnboardingLoginSetupDependencies : ComponentDependencies {
fun pathProvider(): PathProvider
fun crashReporter(): CrashReporter
fun configStorage(): ConfigStorage
fun workspaceManager(): WorkspaceManager
fun featureConfigProvider(): FeaturesConfigProvider
fun metricsProvider(): MetricsProvider
fun objectTypesSubscriptionManager(): ObjectTypesSubscriptionManager
fun relationsSubscriptionManager(): RelationsSubscriptionManager
fun spaceStatusWatcher(): SpaceDeletedStatusWatcher
}

View File

@ -16,6 +16,7 @@ import com.anytypeio.anytype.domain.`object`.SetupMobileUseCaseSkip
import com.anytypeio.anytype.domain.platform.MetricsProvider
import com.anytypeio.anytype.domain.search.ObjectTypesSubscriptionManager
import com.anytypeio.anytype.domain.search.RelationsSubscriptionManager
import com.anytypeio.anytype.domain.spaces.SpaceDeletedStatusWatcher
import com.anytypeio.anytype.domain.workspace.SpaceManager
import com.anytypeio.anytype.domain.workspace.WorkspaceManager
import com.anytypeio.anytype.presentation.onboarding.signup.OnboardingSetProfileNameViewModel
@ -107,6 +108,7 @@ interface OnboardingSoulCreationDependencies : ComponentDependencies {
fun metricsProvider(): MetricsProvider
fun crashReporter(): CrashReporter
fun spaceManager(): SpaceManager
fun spaceStatusWatcher(): SpaceDeletedStatusWatcher
}
@Scope

View File

@ -3,6 +3,7 @@ package com.anytypeio.anytype.di.feature.relations
import com.anytypeio.anytype.core_utils.di.scope.PerDialog
import com.anytypeio.anytype.domain.search.SearchObjects
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.workspace.SpaceManager
import com.anytypeio.anytype.presentation.relations.LimitObjectTypeViewModel
import com.anytypeio.anytype.presentation.relations.model.CreateFromScratchState
import com.anytypeio.anytype.presentation.relations.model.StateHolder
@ -32,10 +33,12 @@ object LimitObjectTypeModule {
fun provideViewModelFactory(
searchObjects: SearchObjects,
urlBuilder: UrlBuilder,
state: StateHolder<CreateFromScratchState>
state: StateHolder<CreateFromScratchState>,
spaceManager: SpaceManager
): LimitObjectTypeViewModel.Factory = LimitObjectTypeViewModel.Factory(
searchObjects = searchObjects,
urlBuilder = urlBuilder,
state = state
state = state,
spaceManager = spaceManager
)
}

View File

@ -6,7 +6,6 @@ import com.anytypeio.anytype.core_utils.di.scope.PerScreen
import com.anytypeio.anytype.device.BuildProvider
import com.anytypeio.anytype.di.common.ComponentDependencies
import com.anytypeio.anytype.domain.account.DeleteAccount
import com.anytypeio.anytype.domain.auth.interactor.GetAccount
import com.anytypeio.anytype.domain.auth.repo.AuthRepository
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.block.repo.BlockRepository
@ -17,7 +16,7 @@ import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.search.SubscriptionEventChannel
import com.anytypeio.anytype.domain.workspace.FileLimitsEventChannel
import com.anytypeio.anytype.domain.workspace.FileSpaceUsage
import com.anytypeio.anytype.domain.workspace.SpacesUsageInfo
import com.anytypeio.anytype.domain.workspace.InterceptFileLimitEvents
import com.anytypeio.anytype.domain.workspace.SpaceManager
import com.anytypeio.anytype.presentation.settings.FilesStorageViewModel
@ -81,9 +80,8 @@ object FilesStorageModule {
@PerScreen
fun provideSpaceUsage(
repo: BlockRepository,
dispatchers: AppCoroutineDispatchers,
spaceManager: SpaceManager
): FileSpaceUsage = FileSpaceUsage(repo, spaceManager, dispatchers)
dispatchers: AppCoroutineDispatchers
): SpacesUsageInfo = SpacesUsageInfo(repo, dispatchers)
@JvmStatic
@Provides
@ -93,14 +91,6 @@ object FilesStorageModule {
dispatchers: AppCoroutineDispatchers
) : InterceptFileLimitEvents = InterceptFileLimitEvents(channel, dispatchers)
@JvmStatic
@Provides
@PerScreen
fun provideGetAccountUseCase(
repo: AuthRepository,
dispatchers: AppCoroutineDispatchers
): GetAccount = GetAccount(repo = repo, dispatcher = dispatchers)
@JvmStatic
@Provides
@PerScreen

View File

@ -8,7 +8,9 @@ import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.config.ConfigStorage
import com.anytypeio.anytype.domain.config.UserSettingsRepository
import com.anytypeio.anytype.domain.misc.AppActionManager
import com.anytypeio.anytype.domain.search.ObjectTypesSubscriptionManager
import com.anytypeio.anytype.domain.search.RelationsSubscriptionManager
import com.anytypeio.anytype.domain.spaces.SpaceDeletedStatusWatcher
import com.anytypeio.anytype.domain.workspace.SpaceManager
import com.anytypeio.anytype.ui.settings.LogoutWarningFragment
import com.anytypeio.anytype.ui_settings.account.LogoutWarningViewModel
@ -39,12 +41,16 @@ object LogoutWarningModule {
logout: Logout,
analytics: Analytics,
relationsSubscriptionManager: RelationsSubscriptionManager,
appActionManager: AppActionManager
objectTypesSubscriptionManager: ObjectTypesSubscriptionManager,
spaceDeletedStatusWatcher: SpaceDeletedStatusWatcher,
appActionManager: AppActionManager,
): LogoutWarningViewModel.Factory = LogoutWarningViewModel.Factory(
logout = logout,
analytics = analytics,
relationsSubscriptionManager = relationsSubscriptionManager,
appActionManager = appActionManager
appActionManager = appActionManager,
spaceDeletedStatusWatcher = spaceDeletedStatusWatcher,
objectTypesSubscriptionManager = objectTypesSubscriptionManager
)
@JvmStatic

View File

@ -48,8 +48,7 @@ object ProfileModule {
setObjectDetails: SetObjectDetails,
configStorage: ConfigStorage,
urlBuilder: UrlBuilder,
setDocumentImageIcon: SetDocumentImageIcon,
spaceGradientProvider: SpaceGradientProvider
setDocumentImageIcon: SetDocumentImageIcon
): ProfileSettingsViewModel.Factory = ProfileSettingsViewModel.Factory(
deleteAccount = deleteAccount,
analytics = analytics,
@ -57,8 +56,7 @@ object ProfileModule {
setObjectDetails = setObjectDetails,
configStorage = configStorage,
urlBuilder = urlBuilder,
setDocumentImageIcon = setDocumentImageIcon,
spaceGradientProvider = spaceGradientProvider
setDocumentImageIcon = setDocumentImageIcon
)
@Provides

View File

@ -0,0 +1,107 @@
package com.anytypeio.anytype.di.feature.settings
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.auth.interactor.GetAccount
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.config.ConfigStorage
import com.anytypeio.anytype.domain.debugging.Logger
import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer
import com.anytypeio.anytype.domain.search.SubscriptionEventChannel
import com.anytypeio.anytype.domain.workspace.FileLimitsEventChannel
import com.anytypeio.anytype.domain.workspace.SpacesUsageInfo
import com.anytypeio.anytype.domain.workspace.InterceptFileLimitEvents
import com.anytypeio.anytype.domain.workspace.SpaceManager
import com.anytypeio.anytype.presentation.settings.SpacesStorageViewModelFactory
import com.anytypeio.anytype.ui.settings.SpacesStorageFragment
import dagger.Binds
import dagger.Component
import dagger.Module
import dagger.Provides
@PerScreen
@Component(
dependencies = [SpacesStorageDependencies::class],
modules = [
SpacesStorageModule::class,
SpacesStorageModule.Declarations::class
]
)
interface SpacesStorageComponent {
@Component.Builder
interface Builder {
fun withDependencies(dependency: SpacesStorageDependencies): Builder
fun build(): SpacesStorageComponent
}
fun inject(fragment: SpacesStorageFragment)
}
@Module
object SpacesStorageModule {
@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 provideSpaceUsage(
repo: BlockRepository,
dispatchers: AppCoroutineDispatchers
): SpacesUsageInfo = SpacesUsageInfo(repo, dispatchers)
@JvmStatic
@Provides
@PerScreen
fun provideFileLimitEvents(
channel: FileLimitsEventChannel,
dispatchers: AppCoroutineDispatchers
) : InterceptFileLimitEvents = InterceptFileLimitEvents(channel, dispatchers)
@JvmStatic
@Provides
@PerScreen
fun provideGetAccountUseCase(
repo: AuthRepository,
dispatchers: AppCoroutineDispatchers
): GetAccount = GetAccount(repo = repo, dispatcher = dispatchers)
@Module
interface Declarations {
@PerScreen
@Binds
fun bindViewModelFactory(factory: SpacesStorageViewModelFactory): ViewModelProvider.Factory
}
}
interface SpacesStorageDependencies : ComponentDependencies {
fun blockRepo(): BlockRepository
fun dispatchers(): AppCoroutineDispatchers
fun analytics(): Analytics
fun configStorage(): ConfigStorage
fun channel(): SubscriptionEventChannel
fun fileEventsChannel(): FileLimitsEventChannel
fun authRepo(): AuthRepository
fun logger(): Logger
fun spaceManager(): SpaceManager
}

View File

@ -8,8 +8,11 @@ import com.anytypeio.anytype.domain.debugging.Logger
import com.anytypeio.anytype.domain.workspace.SpaceManager
import dagger.Module
import dagger.Provides
import javax.inject.Named
import javax.inject.Singleton
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
@Module
object ConfigModule {
@ -38,4 +41,14 @@ object ConfigModule {
computation = Dispatchers.Default,
main = Dispatchers.Main
)
@JvmStatic
@Provides
@Singleton
@Named(DEFAULT_APP_COROUTINE_SCOPE)
fun applicationCoroutineScope() : CoroutineScope = CoroutineScope(
SupervisorJob() + Dispatchers.Default
)
const val DEFAULT_APP_COROUTINE_SCOPE = "Default application coroutine scope"
}

View File

@ -21,6 +21,7 @@ import com.anytypeio.anytype.di.feature.SplashDependencies
import com.anytypeio.anytype.di.feature.auth.DeletedAccountDependencies
import com.anytypeio.anytype.di.feature.home.HomeScreenDependencies
import com.anytypeio.anytype.di.feature.library.LibraryDependencies
import com.anytypeio.anytype.di.feature.objects.CreateObjectOfTypeDependencies
import com.anytypeio.anytype.di.feature.onboarding.OnboardingDependencies
import com.anytypeio.anytype.di.feature.onboarding.OnboardingStartDependencies
import com.anytypeio.anytype.di.feature.onboarding.login.OnboardingLoginSetupDependencies
@ -37,6 +38,7 @@ import com.anytypeio.anytype.di.feature.settings.FilesStorageDependencies
import com.anytypeio.anytype.di.feature.settings.LogoutWarningSubComponent
import com.anytypeio.anytype.di.feature.settings.MainSettingsSubComponent
import com.anytypeio.anytype.di.feature.settings.ProfileSubComponent
import com.anytypeio.anytype.di.feature.settings.SpacesStorageDependencies
import com.anytypeio.anytype.di.feature.spaces.CreateSpaceDependencies
import com.anytypeio.anytype.di.feature.spaces.SelectSpaceDependencies
import com.anytypeio.anytype.di.feature.spaces.SpaceSettingsDependencies
@ -103,7 +105,10 @@ interface MainComponent :
TemplateSelectDependencies,
SelectSpaceDependencies,
CreateSpaceDependencies,
SpaceSettingsDependencies {
SpaceSettingsDependencies,
CreateObjectOfTypeDependencies,
SpacesStorageDependencies
{
fun inject(app: AndroidApplication)
@ -278,4 +283,14 @@ private abstract class ComponentDependenciesModule private constructor() {
@IntoMap
@ComponentDependenciesKey(SpaceSettingsDependencies::class)
abstract fun provideSpaceSettingsDependencies(component: MainComponent): ComponentDependencies
@Binds
@IntoMap
@ComponentDependenciesKey(CreateObjectOfTypeDependencies::class)
abstract fun provideCreateObjectOfTypeDependencies(component: MainComponent): ComponentDependencies
@Binds
@IntoMap
@ComponentDependenciesKey(SpacesStorageDependencies::class)
abstract fun provideSpacesStorageDependencies(component: MainComponent): ComponentDependencies
}

View File

@ -1,7 +1,11 @@
package com.anytypeio.anytype.di.main
import com.anytypeio.anytype.di.main.ConfigModule.DEFAULT_APP_COROUTINE_SCOPE
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.debugging.Logger
import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer
import com.anytypeio.anytype.domain.objects.DefaultStoreOfObjectTypes
import com.anytypeio.anytype.domain.objects.DefaultStoreOfRelations
import com.anytypeio.anytype.domain.objects.StoreOfObjectTypes
@ -11,10 +15,13 @@ import com.anytypeio.anytype.domain.search.ObjectTypesSubscriptionManager
import com.anytypeio.anytype.domain.search.RelationsSubscriptionContainer
import com.anytypeio.anytype.domain.search.RelationsSubscriptionManager
import com.anytypeio.anytype.domain.search.SubscriptionEventChannel
import com.anytypeio.anytype.domain.spaces.SpaceDeletedStatusWatcher
import com.anytypeio.anytype.domain.workspace.SpaceManager
import dagger.Module
import dagger.Provides
import javax.inject.Named
import javax.inject.Singleton
import kotlinx.coroutines.CoroutineScope
@Module
object SubscriptionsModule {
@ -66,7 +73,7 @@ object SubscriptionsModule {
subscription: RelationsSubscriptionContainer,
spaceManager: SpaceManager
): RelationsSubscriptionManager = RelationsSubscriptionManager(
subscription = subscription,
container = subscription,
spaceManager = spaceManager
)
@ -77,7 +84,26 @@ object SubscriptionsModule {
subscription: ObjectTypesSubscriptionContainer,
spaceManager: SpaceManager
): ObjectTypesSubscriptionManager = ObjectTypesSubscriptionManager(
subscription = subscription,
container = subscription,
spaceManager = spaceManager
)
@JvmStatic
@Provides
@Singleton
fun spaceStatusWatcher(
spaceManager: SpaceManager,
dispatchers: AppCoroutineDispatchers,
@Named(DEFAULT_APP_COROUTINE_SCOPE) scope: CoroutineScope,
configStorage: ConfigStorage,
container: StorelessSubscriptionContainer,
logger: Logger
) : SpaceDeletedStatusWatcher = SpaceDeletedStatusWatcher(
spaceManager = spaceManager,
dispatchers = dispatchers,
configStorage = configStorage,
scope = scope,
container = container,
logger = logger
)
}

View File

@ -16,7 +16,7 @@ import com.anytypeio.anytype.ui.editor.EditorFragment
import com.anytypeio.anytype.ui.editor.EditorModalFragment
import com.anytypeio.anytype.ui.home.HomeScreenFragment
import com.anytypeio.anytype.ui.sets.ObjectSetFragment
import com.anytypeio.anytype.ui.settings.RemoteStorageFragment
import com.anytypeio.anytype.ui.settings.RemoteFilesManageFragment
import com.anytypeio.anytype.ui.templates.EditorTemplateFragment.Companion.TYPE_TEMPLATE_EDIT
import com.anytypeio.anytype.ui.templates.EditorTemplateFragment.Companion.TYPE_TEMPLATE_SELECT
import com.anytypeio.anytype.ui.templates.TemplateSelectFragment
@ -305,9 +305,9 @@ class Navigator : AppNavigation {
navController?.navigate(R.id.libraryFragment)
}
override fun openRemoteStorageScreen(subscription: Id) {
override fun openRemoteFilesManageScreen(subscription: Id) {
navController?.navigate(R.id.remoteStorageFragment,
bundleOf(RemoteStorageFragment.SUBSCRIPTION_KEY to subscription))
bundleOf(RemoteFilesManageFragment.SUBSCRIPTION_KEY to subscription))
}
override fun openTemplatesModal(typeId: Id) {

View File

@ -78,7 +78,7 @@ class NavigationRouter(
is AppNavigation.Command.OpenLibrary -> navigation.openLibrary()
is AppNavigation.Command.MigrationErrorScreen -> navigation.migrationErrorScreen()
is AppNavigation.Command.OpenRemoteStorageScreen -> navigation.openRemoteStorageScreen(
is AppNavigation.Command.OpenRemoteFilesManageScreen -> navigation.openRemoteFilesManageScreen(
command.subscription
)

View File

@ -61,6 +61,7 @@ import com.anytypeio.anytype.core_ui.features.editor.scrollandmove.ScrollAndMove
import com.anytypeio.anytype.core_ui.features.editor.scrollandmove.ScrollAndMoveTargetHighlighter
import com.anytypeio.anytype.core_ui.menu.ObjectTypePopupMenu
import com.anytypeio.anytype.core_ui.reactive.clicks
import com.anytypeio.anytype.core_ui.reactive.longClicks
import com.anytypeio.anytype.core_ui.tools.ClipboardInterceptor
import com.anytypeio.anytype.core_ui.tools.EditorHeaderOverlayDetector
import com.anytypeio.anytype.core_ui.tools.LastItemBottomOffsetDecorator
@ -139,6 +140,7 @@ import com.anytypeio.anytype.ui.linking.OnLinkToAction
import com.anytypeio.anytype.ui.moving.MoveToFragment
import com.anytypeio.anytype.ui.moving.OnMoveToAction
import com.anytypeio.anytype.ui.objects.appearance.ObjectAppearanceSettingFragment
import com.anytypeio.anytype.ui.objects.creation.CreateObjectOfTypeFragment
import com.anytypeio.anytype.ui.objects.types.pickers.DraftObjectSelectTypeFragment
import com.anytypeio.anytype.ui.objects.types.pickers.ObjectSelectTypeFragment
import com.anytypeio.anytype.ui.objects.types.pickers.OnObjectSelectTypeAction
@ -591,6 +593,26 @@ open class EditorFragment : NavigationFragment<FragmentEditorBinding>(R.layout.f
.onEach { vm.onAddNewDocumentClicked() }
.launchIn(lifecycleScope)
binding.bottomToolbar
.addDocClicks()
.onEach { vm.onAddNewDocumentClicked() }
.launchIn(lifecycleScope)
binding
.bottomToolbar
.binding
.btnAddDoc
.longClicks(withHaptic = true)
.onEach {
val dialog = CreateObjectOfTypeFragment().apply {
onTypeSelected = {
vm.onAddNewDocumentClicked(it)
}
}
dialog.show(childFragmentManager, "editor-create-object-of-type-dialog")
}
.launchIn(lifecycleScope)
binding.topToolbar.menu
.clicks()
.throttleFirst()

View File

@ -8,6 +8,7 @@ import androidx.core.os.bundleOf
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import com.anytypeio.anytype.R
import com.anytypeio.anytype.analytics.BuildConfig
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.core_ui.features.objects.ObjectActionAdapter
@ -18,16 +19,15 @@ import com.anytypeio.anytype.core_utils.ext.argOrNull
import com.anytypeio.anytype.core_utils.ext.shareFile
import com.anytypeio.anytype.core_utils.ext.throttleFirst
import com.anytypeio.anytype.core_utils.ext.toast
import com.anytypeio.anytype.core_utils.ext.visible
import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetFragment
import com.anytypeio.anytype.core_utils.ui.proceed
import com.anytypeio.anytype.core_utils.ui.showActionableSnackBar
import com.anytypeio.anytype.databinding.FragmentObjectMenuBinding
import com.anytypeio.anytype.presentation.navigation.AppNavigation
import com.anytypeio.anytype.presentation.objects.ObjectIcon
import com.anytypeio.anytype.presentation.objects.menu.ObjectMenuOptionsProvider
import com.anytypeio.anytype.presentation.objects.menu.ObjectMenuViewModelBase
import com.anytypeio.anytype.ui.base.navigation
import com.anytypeio.anytype.ui.editor.EditorModalFragment
import com.anytypeio.anytype.ui.editor.cover.SelectCoverObjectFragment
import com.anytypeio.anytype.ui.editor.cover.SelectCoverObjectSetFragment
import com.anytypeio.anytype.ui.editor.layout.ObjectLayoutFragment
@ -36,6 +36,7 @@ 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.google.android.material.snackbar.Snackbar
abstract class ObjectMenuBaseFragment :
BaseBottomSheetFragment<FragmentObjectMenuBinding>(),
@ -79,6 +80,7 @@ abstract class ObjectMenuBaseFragment :
click(binding.optionIcon) { vm.onIconClicked(ctx) }
click(binding.optionRelations) { vm.onRelationsClicked() }
click(binding.optionCover) { vm.onCoverClicked(ctx) }
click(binding.debugGoroutines) { vm.onDiagnosticsGoroutinesClicked(ctx) }
proceed(vm.actions) { actionAdapter.submitList(it) }
proceed(vm.toasts) { toast(it) }
@ -86,6 +88,11 @@ abstract class ObjectMenuBaseFragment :
proceed(vm.commands.throttleFirst()) { command -> execute(command) }
proceed(vm.options) { options -> renderOptions(options) }
if (BuildConfig.DEBUG) {
binding.debugGoroutines.visible()
binding.debugGoroutinesDivider.visible()
}
super.onStart()
vm.onStart(
ctx = ctx,
@ -134,11 +141,24 @@ abstract class ObjectMenuBaseFragment :
is ObjectMenuViewModelBase.Command.OpenSnackbar -> openSnackbar(command)
is ObjectMenuViewModelBase.Command.ShareDebugTree -> shareFile(command.uri)
is ObjectMenuViewModelBase.Command.OpenTemplate -> openTemplate(command)
is ObjectMenuViewModelBase.Command.ShareDebugGoroutines -> {
val snackbar = Snackbar.make(
dialog?.window?.decorView!!,
"Success, Path: ${command.path}",
Snackbar.LENGTH_INDEFINITE
)
snackbar.setAction("Done") {
snackbar.dismiss()
}
snackbar.anchorView = binding.anchor
snackbar.show()
}
}
}
private fun openTemplate(command: ObjectMenuViewModelBase.Command.OpenTemplate) {
toast(getString(R.string.snackbar_template_add) + command.typeName)
val msg = "${getString(R.string.snackbar_template_add)} ${command.typeName}"
toast(msg)
navigation().openModalTemplateEdit(
template = command.templateId,
templateTypeId = command.typeId,
@ -175,7 +195,7 @@ abstract class ObjectMenuBaseFragment :
ObjectRelationListFragment.ARG_TARGET to null,
ObjectRelationListFragment.ARG_LOCKED to isLocked,
ObjectRelationListFragment.ARG_MODE to ObjectRelationListFragment.MODE_LIST,
ObjectRelationListFragment.ARG_DATA_VIEW_FLOW to false
ObjectRelationListFragment.ARG_SET_FLOW to false
)
)
}
@ -188,7 +208,7 @@ abstract class ObjectMenuBaseFragment :
ObjectRelationListFragment.ARG_TARGET to null,
ObjectRelationListFragment.ARG_LOCKED to isLocked,
ObjectRelationListFragment.ARG_MODE to ObjectRelationListFragment.MODE_LIST,
ObjectRelationListFragment.ARG_DATA_VIEW_FLOW to true
ObjectRelationListFragment.ARG_SET_FLOW to true
)
)
}

View File

@ -37,7 +37,9 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
@ -50,6 +52,7 @@ import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_ui.extensions.throttledClick
import com.anytypeio.anytype.core_ui.foundation.noRippleClickable
import com.anytypeio.anytype.core_ui.foundation.noRippleCombinedClickable
import com.anytypeio.anytype.core_ui.views.UXBody
import com.anytypeio.anytype.emojifier.Emojifier
import com.anytypeio.anytype.presentation.home.InteractionMode
@ -95,6 +98,7 @@ fun HomeScreen(
onLibraryClicked: () -> Unit,
onOpenSpacesClicked: () -> Unit,
onCreateNewObjectClicked: () -> Unit,
onCreateNewObjectLongClicked: () -> Unit,
onProfileClicked: () -> Unit,
onObjectCheckboxClicked: (Id, Boolean) -> Unit,
onSpaceWidgetClicked: () -> Unit,
@ -158,6 +162,7 @@ fun HomeScreen(
onSearchClicked = throttledClick(onSearchClicked),
onCreateNewObjectClicked = throttledClick(onCreateNewObjectClicked),
onProfileClicked = throttledClick(onProfileClicked),
onCreateNewObjectLongClicked = onCreateNewObjectLongClicked,
modifier = Modifier
)
}
@ -515,14 +520,17 @@ fun HomeScreenButton(
}
}
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun HomeScreenBottomToolbar(
profileIcon: ProfileIconView,
modifier: Modifier,
onSearchClicked: () -> Unit,
onCreateNewObjectClicked: () -> Unit,
onCreateNewObjectLongClicked: () -> Unit,
onProfileClicked: () -> Unit
) {
val haptic = LocalHapticFeedback.current
Row(
modifier = modifier
.height(52.dp)
@ -548,7 +556,16 @@ fun HomeScreenBottomToolbar(
modifier = Modifier
.weight(1f)
.fillMaxSize()
.noRippleClickable { onCreateNewObjectClicked() }
.noRippleCombinedClickable(
onLongClicked = {
onCreateNewObjectLongClicked().also {
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
}
},
onClick = {
onCreateNewObjectClicked()
}
)
) {
Image(
painter = painterResource(id = R.drawable.ic_home_widget_plus),
@ -585,7 +602,7 @@ fun HomeScreenBottomToolbar(
contentDescription = "Custom image space icon",
modifier = Modifier
.size(24.dp)
.clip(RoundedCornerShape(3.dp))
.clip(CircleShape)
.align(Alignment.Center),
contentScale = ContentScale.Crop
)

View File

@ -28,6 +28,7 @@ import com.anytypeio.anytype.presentation.home.HomeScreenViewModel
import com.anytypeio.anytype.presentation.home.HomeScreenViewModel.Navigation
import com.anytypeio.anytype.presentation.widgets.DropDownMenuAction
import com.anytypeio.anytype.ui.base.navigation
import com.anytypeio.anytype.ui.objects.creation.CreateObjectOfTypeFragment
import com.anytypeio.anytype.ui.settings.typography
import com.anytypeio.anytype.ui.widgets.SelectWidgetSourceFragment
import com.anytypeio.anytype.ui.widgets.SelectWidgetTypeFragment
@ -84,6 +85,17 @@ class HomeScreenFragment : BaseComposeFragment() {
onCreateNewObjectClicked = throttledClick(
onClick = { vm.onCreateNewObjectClicked() }
),
onCreateNewObjectLongClicked = throttledClick(
onClick = {
val dialog = CreateObjectOfTypeFragment().apply {
onTypeSelected = {
vm.onCreateNewObjectClicked(it)
dismiss()
}
}
dialog.show(childFragmentManager, "TEST")
}
),
onProfileClicked = throttledClick(
onClick = {
runCatching {

View File

@ -24,6 +24,7 @@ import com.anytypeio.anytype.di.common.componentManager
import com.anytypeio.anytype.presentation.library.LibraryViewModel
import com.anytypeio.anytype.presentation.objects.ObjectIcon
import com.anytypeio.anytype.ui.editor.EditorFragment
import com.anytypeio.anytype.ui.objects.creation.CreateObjectOfTypeFragment
import com.anytypeio.anytype.ui.relations.REQUEST_KEY_MODIFY_RELATION
import com.anytypeio.anytype.ui.relations.REQUEST_KEY_UNINSTALL_RELATION
import com.anytypeio.anytype.ui.relations.REQUEST_UNINSTALL_RELATION_ARG_ID
@ -63,11 +64,20 @@ class LibraryFragment : BaseComposeFragment() {
setContent {
MaterialTheme(typography = typography) {
LibraryScreen(
LibraryConfiguration(),
vm
) {
findNavController().popBackStack()
}
configuration = LibraryConfiguration(),
viewModel = vm,
onBackPressed = {
findNavController().popBackStack()
},
onCreateObjectLongClicked = {
val dialog = CreateObjectOfTypeFragment().apply {
onTypeSelected = {
vm.onCreateObjectOfTypeClicked(it)
}
}
dialog.show(childFragmentManager, "library-create-object-of-type-dialog")
}
)
}
}
}

View File

@ -52,7 +52,8 @@ import kotlinx.coroutines.FlowPreview
fun LibraryScreen(
configuration: LibraryConfiguration,
viewModel: LibraryViewModel,
onBackPressed: () -> Unit
onBackPressed: () -> Unit,
onCreateObjectLongClicked: () -> Unit
) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
@ -67,7 +68,8 @@ fun LibraryScreen(
Menu(
viewModel,
modifier = modifier,
screenState = screenState
screenState = screenState,
onCreateObjectLongClicked = onCreateObjectLongClicked
)
}) {
println(it)
@ -105,7 +107,8 @@ fun LibraryScreen(
fun Menu(
viewModel: LibraryViewModel,
modifier: Modifier = Modifier,
screenState: MutableState<ScreenState>
screenState: MutableState<ScreenState>,
onCreateObjectLongClicked: () -> Unit = {}
) {
val isImeVisible = WindowInsets.ime.getBottom(LocalDensity.current) > 0
if (isImeVisible) return
@ -115,12 +118,13 @@ fun Menu(
if (screenState.value == ScreenState.SEARCH) {
screenState.value = ScreenState.CONTENT
} else {
viewModel.eventStream(LibraryEvent.BottomMenu.Back())
viewModel.eventStream(LibraryEvent.BottomMenu.Back)
}
},
homeClick = { viewModel.eventStream(LibraryEvent.BottomMenu.Back()) },
searchClick = { viewModel.eventStream(LibraryEvent.BottomMenu.Search()) },
addDocClick = { viewModel.eventStream(LibraryEvent.BottomMenu.AddDoc()) },
homeClick = { viewModel.eventStream(LibraryEvent.BottomMenu.Back) },
searchClick = { viewModel.eventStream(LibraryEvent.BottomMenu.Search) },
addDocClick = { viewModel.eventStream(LibraryEvent.BottomMenu.CreateObject) },
onCreateObjectLongClicked = onCreateObjectLongClicked
)
}

View File

@ -186,7 +186,6 @@ private fun SearchCancel(modifier: Modifier = Modifier, visible: Boolean = false
}
@OptIn(ExperimentalComposeUiApi::class)
@Composable
private fun LibraryList(
data: LibraryScreenState.Tabs.TabData,

View File

@ -0,0 +1,57 @@
package com.anytypeio.anytype.ui.objects.creation
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.compose.collectAsStateWithLifecycle
import com.anytypeio.anytype.core_models.Key
import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetComposeFragment
import com.anytypeio.anytype.di.common.componentManager
import com.anytypeio.anytype.presentation.objects.CreateObjectOfTypeViewModel
import com.anytypeio.anytype.ui.settings.typography
import javax.inject.Inject
class CreateObjectOfTypeFragment : BaseBottomSheetComposeFragment() {
@Inject
lateinit var factory: CreateObjectOfTypeViewModel.Factory
private val vm by viewModels<CreateObjectOfTypeViewModel> { factory }
lateinit var onTypeSelected: (Key) -> Unit
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View = ComposeView(requireContext()).apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
MaterialTheme(
typography = typography
) {
CreateObjectOfTypeScreen(
views = vm.views.collectAsStateWithLifecycle().value,
onTypeClicked = {
onTypeSelected.invoke(it)
},
onQueryChanged = vm::onQueryChanged,
onFocused = { expand() }
)
}
}
}
override fun injectDependencies() {
componentManager().createObjectOfTypeComponent.get().inject(this)
}
override fun releaseDependencies() {
componentManager().createObjectOfTypeComponent.release()
}
}

View File

@ -0,0 +1,383 @@
package com.anytypeio.anytype.ui.objects.creation
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
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.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.GridItemSpan
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.Text
import androidx.compose.material.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.rememberNestedScrollInteropConnection
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import coil.compose.rememberAsyncImagePainter
import com.anytypeio.anytype.R
import com.anytypeio.anytype.core_models.Key
import com.anytypeio.anytype.core_ui.extensions.throttledClick
import com.anytypeio.anytype.core_ui.foundation.Dragger
import com.anytypeio.anytype.core_ui.foundation.noRippleClickable
import com.anytypeio.anytype.core_ui.views.BodyRegular
import com.anytypeio.anytype.core_ui.views.Caption1Medium
import com.anytypeio.anytype.core_ui.views.Title2
import com.anytypeio.anytype.emojifier.Emojifier
import com.anytypeio.anytype.presentation.objects.SelectTypeView
@Preview
@Composable
fun PreviewScreen() {
CreateObjectOfTypeScreen(
onTypeClicked = {},
views = emptyList(),
onQueryChanged = {},
onFocused = {}
)
}
@Composable
fun CreateObjectOfTypeScreen(
onTypeClicked: (Key) -> Unit,
onQueryChanged: (String) -> Unit,
onFocused: () -> Unit,
views: List<SelectTypeView>
) {
Column(
modifier = Modifier.nestedScroll(rememberNestedScrollInteropConnection())
) {
Dragger(
Modifier
.align(Alignment.CenterHorizontally)
.padding(vertical = 6.dp)
)
SearchField(
onQueryChanged = onQueryChanged,
onFocused = onFocused
)
ScreenContent(views, onTypeClicked)
}
}
@Composable
private fun ScreenContent(
views: List<SelectTypeView>,
onTypeClicked: (Key) -> Unit
) {
FlowRowContent(views, onTypeClicked)
}
@Composable
@OptIn(ExperimentalLayoutApi::class)
private fun FlowRowContent(
views: List<SelectTypeView>,
onTypeClicked: (Key) -> Unit
) {
FlowRow(
modifier = Modifier
.fillMaxSize()
.padding(horizontal = 20.dp)
.verticalScroll(rememberScrollState())
,
verticalArrangement = Arrangement.spacedBy(8.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp),
) {
views.forEach { view ->
when (view) {
is SelectTypeView.Type -> {
ObjectTypeItem(
name = view.name,
emoji = view.icon,
onItemClicked = throttledClick(
onClick = {
onTypeClicked(view.typeKey)
}
),
modifier = Modifier
)
}
is SelectTypeView.Section.Groups -> {
Section(
title = stringResource(id = R.string.create_object_section_groups),
)
}
is SelectTypeView.Section.Objects -> {
Section(
title = stringResource(id = R.string.create_object_section_objects)
)
}
}
}
}
}
@Composable
@OptIn(ExperimentalFoundationApi::class)
private fun LazyColumnContent(
views: List<SelectTypeView>,
onTypeClicked: (Key) -> Unit
) {
LazyVerticalGrid(
modifier = Modifier.fillMaxSize(),
columns = GridCells.Fixed(3),
verticalArrangement = Arrangement.spacedBy(8.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp),
contentPadding = PaddingValues(
start = 20.dp,
end = 20.dp
)
) {
views.forEach { view ->
when (view) {
is SelectTypeView.Section.Groups -> {
item(
key = view.javaClass.name,
span = { GridItemSpan(maxLineSpan) }
) {
Section(
title = stringResource(id = R.string.create_object_section_groups),
)
}
}
is SelectTypeView.Section.Objects -> {
item(
key = view.javaClass.name,
span = { GridItemSpan(maxLineSpan) }
) {
Section(
title = stringResource(id = R.string.create_object_section_objects)
)
}
}
is SelectTypeView.Type -> {
item(
key = view.typeKey
) {
ObjectTypeItem(
name = view.name,
emoji = view.icon,
onItemClicked = throttledClick(
onClick = {
onTypeClicked(view.typeKey)
}
),
modifier = Modifier.animateItemPlacement()
)
}
}
}
}
}
}
@Composable
fun ObjectTypeItem(
modifier: Modifier,
name: String,
emoji: String,
onItemClicked: () -> Unit
) {
Row(
modifier = modifier
.height(48.dp)
.border(
width = 1.dp,
color = colorResource(id = R.color.shape_primary),
shape = RoundedCornerShape(12.dp)
)
.clip(RoundedCornerShape(12.dp))
.clickable { onItemClicked() }
,
verticalAlignment = Alignment.CenterVertically
) {
Spacer(
modifier = Modifier.width(14.dp)
)
val uri = Emojifier.safeUri(emoji)
if (uri.isNotEmpty()) {
Image(
painter = rememberAsyncImagePainter(
Emojifier.safeUri(emoji)
),
contentDescription = "Icon from URI",
modifier = Modifier.size(18.dp)
)
Spacer(modifier = Modifier.width(8.dp))
}
Text(
text = name,
style = Title2,
color = colorResource(id = R.color.text_primary),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.padding(end = 16.dp)
)
}
}
@OptIn(ExperimentalMaterialApi::class)
@Composable
private fun SearchField(
onQueryChanged: (String) -> Unit,
onFocused: () -> Unit
) {
Box(
modifier = Modifier
.height(48.dp)
.fillMaxWidth()
) {
val focusManager = LocalFocusManager.current
val focusRequester = FocusRequester()
val input = remember { mutableStateOf(String()) }
Box(
modifier = Modifier
.padding(horizontal = 16.dp)
.fillMaxWidth()
.height(36.dp)
.clip(RoundedCornerShape(10.dp))
.background(color = colorResource(id = R.color.shape_transparent))
.align(Alignment.Center)
) {
Image(
painter = painterResource(id = R.drawable.ic_search_18),
contentDescription = "Search icon",
modifier = Modifier
.align(Alignment.CenterStart)
.padding(start = 8.dp)
)
if (input.value.isNotEmpty()) {
Image(
painter = painterResource(id = R.drawable.ic_clear_18),
contentDescription = "Search icon",
modifier = Modifier
.align(Alignment.CenterEnd)
.padding(end = 8.dp)
.noRippleClickable {
input.value = ""
onQueryChanged("")
}
)
}
BasicTextField(
value = input.value,
onValueChange = {
input.value = it
onQueryChanged(it)
},
keyboardActions = KeyboardActions(
onDone = { focusManager.clearFocus() }
),
modifier = Modifier
.fillMaxWidth()
.padding(start = 32.dp, end = 32.dp)
.align(Alignment.CenterStart)
.focusRequester(focusRequester)
.onFocusChanged { state ->
if (state.isFocused)
onFocused()
}
,
maxLines = 1,
singleLine = true,
textStyle = BodyRegular.copy(
color = colorResource(id = R.color.text_primary)
),
cursorBrush = SolidColor(
colorResource(id = R.color.cursor_color)
),
decorationBox = @Composable { innerTextField ->
TextFieldDefaults.OutlinedTextFieldDecorationBox(
value = input.value,
innerTextField = innerTextField,
singleLine = true,
enabled = true,
placeholder = {
Text(
text = stringResource(R.string.search),
style = BodyRegular
)
},
colors = TextFieldDefaults.outlinedTextFieldColors(
textColor = colorResource(id = R.color.text_primary),
backgroundColor = Color.Transparent,
disabledBorderColor = Color.Transparent,
errorBorderColor = Color.Transparent,
focusedBorderColor = Color.Transparent,
unfocusedBorderColor = Color.Transparent,
placeholderColor = colorResource(id = R.color.text_tertiary)
),
interactionSource = remember { MutableInteractionSource() },
visualTransformation = VisualTransformation.None,
contentPadding = PaddingValues(
start = 0.dp,
top = 0.dp,
end = 0.dp,
bottom = 0.dp
),
border = {},
)
}
)
}
}
}
@Composable
private fun Section(title: String) {
Box(modifier = Modifier
.height(52.dp)
.fillMaxWidth()) {
Text(
modifier = Modifier
.padding(bottom = 8.dp)
.align(Alignment.BottomStart),
text = title,
color = colorResource(id = R.color.text_secondary),
style = Caption1Medium
)
}
}

View File

@ -75,14 +75,11 @@ import com.anytypeio.anytype.presentation.onboarding.OnboardingViewModel
import com.anytypeio.anytype.presentation.onboarding.login.OnboardingLoginSetupViewModel
import com.anytypeio.anytype.presentation.onboarding.login.OnboardingMnemonicLoginViewModel
import com.anytypeio.anytype.presentation.onboarding.signup.OnboardingSetProfileNameViewModel
import com.anytypeio.anytype.presentation.onboarding.signup.OnboardingVoidViewModel
import com.anytypeio.anytype.ui.onboarding.screens.AuthScreenWrapper
import com.anytypeio.anytype.ui.onboarding.screens.signin.EnteringTheVoidScreen
import com.anytypeio.anytype.ui.onboarding.screens.signin.RecoveryScreenWrapper
import com.anytypeio.anytype.ui.onboarding.screens.signup.CreateSoulAnimWrapper
import com.anytypeio.anytype.ui.onboarding.screens.signup.MnemonicPhraseScreenWrapper
import com.anytypeio.anytype.ui.onboarding.screens.signup.SetProfileNameWrapper
import com.anytypeio.anytype.ui.onboarding.screens.signup.VoidScreenWrapper
import com.google.android.exoplayer2.ExoPlayer
import com.google.android.exoplayer2.MediaItem
import com.google.android.exoplayer2.Player
@ -241,62 +238,6 @@ class OnboardingFragment : Fragment() {
currentPage.value = OnboardingPage.RECOVERY
Recovery(navController)
}
composable(
route = OnboardingNavigation.void,
enterTransition = {
when (initialState.destination.route) {
OnboardingNavigation.auth -> {
fadeIn(tween(ANIMATION_LENGTH_FADE))
}
else -> {
slideIntoContainer(Right, tween(ANIMATION_LENGTH_SLIDE))
}
}
},
exitTransition = {
when (targetState.destination.route) {
OnboardingNavigation.auth -> {
fadeOut(tween(ANIMATION_LENGTH_FADE))
}
else -> {
slideOutOfContainer(Left, tween(ANIMATION_LENGTH_SLIDE))
}
}
}
) {
currentPage.value = OnboardingPage.VOID
val component = componentManager().onboardingNewVoidComponent
val vm = daggerViewModel { component.get().getViewModel() }
VoidScreenWrapper(
contentPaddingTop = ContentPaddingTop(),
onNextClicked = vm::onNextClicked,
screenState = vm.state.collectAsState().value
)
backButtonCallback.value = vm::onBackButtonPressed
BackHandler { vm.onSystemBackPressed() }
LaunchedEffect(Unit) {
vm.navigation.collect { navigation ->
when (navigation) {
OnboardingVoidViewModel.Navigation.GoBack -> {
navController.popBackStack()
}
OnboardingVoidViewModel.Navigation.NavigateToMnemonic -> {
navController.navigate(OnboardingNavigation.mnemonic)
}
}
}
}
LaunchedEffect(Unit) {
vm.toasts.collect { toast(it) }
}
DisposableEffect(Unit) {
onDispose { component.release() }
}
}
composable(
route = OnboardingNavigation.mnemonic,
enterTransition = {
@ -325,7 +266,6 @@ class OnboardingFragment : Fragment() {
// Do nothing
}
Mnemonic(
contentPaddingTop = ContentPaddingTop(),
mnemonicColorPalette = mnemonicColorPalette
)
BackHandler {
@ -334,16 +274,11 @@ class OnboardingFragment : Fragment() {
}
composable(
route = OnboardingNavigation.setProfileName,
enterTransition = { slideIntoContainer(Left, tween(ANIMATION_LENGTH_SLIDE)) },
enterTransition = {
fadeIn(tween(ANIMATION_LENGTH_FADE))
},
exitTransition = {
when (targetState.destination.route) {
OnboardingNavigation.auth -> {
fadeOut(tween(ANIMATION_LENGTH_FADE))
}
else -> {
slideOutOfContainer(Left, tween(ANIMATION_LENGTH_SLIDE))
}
}
fadeOut(tween(ANIMATION_LENGTH_FADE))
}
) {
val focus = LocalFocusManager.current
@ -352,31 +287,12 @@ class OnboardingFragment : Fragment() {
focus.clearFocus(true)
navController.popBackStack()
}
SetProfileName(
navController = navController,
contentPaddingTop = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R)
LocalConfiguration.current.screenHeightDp / 6
else
ContentPaddingTop()
)
SetProfileName(navController = navController)
BackHandler {
focus.clearFocus(true)
navController.popBackStack()
}
}
composable(
route = OnboardingNavigation.createSoulAnim,
enterTransition = {
fadeIn(tween(ANIMATION_LENGTH_FADE))
}
) {
currentPage.value = OnboardingPage.SOUL_CREATION_ANIM
backButtonCallback.value = null
CreateSoulAnimation(ContentPaddingTop())
BackHandler {
// Intercepting back-press event but doing nothing.
}
}
composable(
route = OnboardingNavigation.enterTheVoid,
enterTransition = {
@ -470,7 +386,6 @@ class OnboardingFragment : Fragment() {
}
}
@Deprecated("To be deleted")
@Composable
private fun enterTheVoid(
navController: NavHostController
@ -511,25 +426,10 @@ class OnboardingFragment : Fragment() {
}
}
@Deprecated("To be deleted")
@Composable
private fun CreateSoulAnimation(contentPaddingTop: Int) {
val component = componentManager().onboardingSoulCreationAnimComponent
CreateSoulAnimWrapper(
contentPaddingTop = contentPaddingTop,
viewModel = daggerViewModel { component.get().getViewModel() },
onAnimationComplete = {
findNavController().navigate(R.id.action_openHome)
}
)
DisposableEffect(Unit) {
onDispose { component.release() }
}
}
@Composable
private fun SetProfileName(navController: NavHostController, contentPaddingTop: Int) {
private fun SetProfileName(
navController: NavHostController
) {
val component = componentManager().onboardingSoulCreationComponent
val vm = daggerViewModel { component.get().getViewModel() }
@ -537,7 +437,10 @@ class OnboardingFragment : Fragment() {
val keyboardInsets = WindowInsets.ime
val density = LocalDensity.current
SetProfileNameWrapper(vm, contentPaddingTop)
SetProfileNameWrapper(
viewModel = vm,
onBackClicked = { navController.popBackStack() }
)
LaunchedEffect(Unit) {
vm.navigation.collect { command ->
@ -552,7 +455,7 @@ class OnboardingFragment : Fragment() {
)
}
is OnboardingSetProfileNameViewModel.Navigation.GoBack -> {
TODO()
//
}
}
}
@ -569,13 +472,11 @@ class OnboardingFragment : Fragment() {
@Composable
private fun Mnemonic(
contentPaddingTop: Int,
mnemonicColorPalette: List<Color>
) {
val component = componentManager().onboardingMnemonicComponent
val vm = daggerViewModel { component.get().getViewModel() }
MnemonicPhraseScreenWrapper(
contentPaddingTop = contentPaddingTop,
viewModel = vm,
onCheckLaterClicked = {
findNavController().navigate(R.id.action_openHome)
@ -713,6 +614,13 @@ class OnboardingFragment : Fragment() {
}
fun releaseDependencies() {
with(componentManager()) {
onboardingComponent.release()
onboardingMnemonicComponent.release()
onboardingMnemonicLoginComponent.release()
onboardingLoginSetupComponent.release()
onboardingStartComponent.release()
}
componentManager().onboardingComponent.release()
}
}

View File

@ -6,6 +6,5 @@ object OnboardingNavigation {
const val void = "void"
const val mnemonic = "mnemonic"
const val setProfileName = "createSoul"
const val createSoulAnim = "createSoulAnim"
const val enterTheVoid = "enterTheVoid"
}

View File

@ -4,7 +4,7 @@ enum class OnboardingPage(val num: Int, val visible: Boolean) {
AUTH(0, false),
VOID(1, true),
MNEMONIC(2, false),
SET_PROFILE_NAME(1, true),
SET_PROFILE_NAME(1, false),
SOUL_CREATION_ANIM(4, false),
RECOVERY(5, false),
ENTER_THE_VOID(6, false)

View File

@ -1,5 +1,6 @@
package com.anytypeio.anytype.ui.onboarding.screens
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@ -14,19 +15,18 @@ import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
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.style.TextAlign
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.anytypeio.anytype.R
import com.anytypeio.anytype.core_ui.ColorButtonInversion
import com.anytypeio.anytype.core_ui.OnBoardingTextPrimaryColor
import com.anytypeio.anytype.core_ui.OnBoardingTextSecondaryColor
import com.anytypeio.anytype.core_ui.OnboardingSubtitleColor
import com.anytypeio.anytype.core_ui.views.ButtonSize
@ -35,7 +35,6 @@ import com.anytypeio.anytype.core_ui.views.HeadlineOnBoardingTitle
import com.anytypeio.anytype.core_ui.views.OnBoardingButtonPrimary
import com.anytypeio.anytype.core_ui.views.OnBoardingButtonSecondary
import com.anytypeio.anytype.core_ui.views.TextOnBoardingDescription
import com.anytypeio.anytype.core_ui.views.fontInterRegular
import com.anytypeio.anytype.presentation.onboarding.OnboardingStartViewModel
@Preview
@ -72,7 +71,7 @@ fun AuthScreen(
modifier = Modifier.fillMaxSize()
) {
Column(modifier = Modifier.fillMaxSize(), verticalArrangement = Arrangement.Center) {
Title(modifier = Modifier)
Title(modifier = Modifier.align(Alignment.CenterHorizontally))
Subtitle(modifier = Modifier)
Description()
Spacer(modifier = Modifier.height(72.dp))
@ -96,25 +95,11 @@ fun AuthScreen(
@Composable
fun Title(modifier: Modifier = Modifier) {
Box(
Image(
painter = painterResource(id = R.drawable.ic_the_everything_app) ,
contentDescription = "Everything app logo",
modifier = modifier
.fillMaxWidth()
.wrapContentHeight(),
contentAlignment = Alignment.Center
) {
Text(
text = stringResource(id = R.string.onboarding_auth_title),
textAlign = TextAlign.Center,
style = HeadlineOnBoardingTitle
.copy(
color = OnBoardingTextPrimaryColor,
fontFamily = fontInterRegular,
fontSize = 40.sp,
fontWeight = FontWeight.W300,
lineHeight = 37.5.sp
)
)
}
)
}
@Composable
@ -196,7 +181,11 @@ fun TermsAndPolicy(
)
pushStringAnnotation(tag = TermsOfUseTag, annotation = "")
withStyle(style = SpanStyle(textDecoration = TextDecoration.Underline)) {
withStyle(
style = SpanStyle(
color = Color(0xFF797976)
)
) {
append(stringResource(id = R.string.onboarding_terms_and_policy_terms))
}
pop()
@ -206,7 +195,11 @@ fun TermsAndPolicy(
)
pushStringAnnotation(tag = PrivacyPolicyTag, annotation = "")
withStyle(style = SpanStyle(textDecoration = TextDecoration.Underline)) {
withStyle(
style = SpanStyle(
color = Color(0xFF797976)
)
) {
append(stringResource(id = R.string.onboarding_terms_and_policy_privacy))
}
pop()
@ -216,7 +209,7 @@ fun TermsAndPolicy(
modifier = modifier.padding(vertical = 16.dp, horizontal = 58.dp),
text = annotatedString,
style = TextOnBoardingDescription
.copy(color = OnBoardingTextSecondaryColor, textAlign = TextAlign.Center),
.copy(color = Color(0xFF494843), textAlign = TextAlign.Center),
onClick = {
annotatedString.getStringAnnotations(TermsOfUseTag, it, it)
.firstOrNull()?.let {

View File

@ -115,7 +115,7 @@ fun RecoveryScreen(
}
item {
OnBoardingButtonPrimary(
text = stringResource(id = R.string.next),
text = stringResource(id = R.string.log_in),
onClick = {
onNextClicked.invoke(text.value).also {
focus.clearFocus()

View File

@ -54,7 +54,6 @@ fun MnemonicPhraseScreenWrapper(
viewModel: OnboardingMnemonicViewModel,
onCheckLaterClicked: () -> Unit,
copyMnemonicToClipboard: (String) -> Unit,
contentPaddingTop: Int,
vm: OnboardingMnemonicViewModel,
mnemonicColorPalette: List<Color>
) {
@ -68,7 +67,6 @@ fun MnemonicPhraseScreenWrapper(
}
},
copyMnemonicToClipboard = copyMnemonicToClipboard,
contentPaddingTop = contentPaddingTop,
mnemonicColorPalette = mnemonicColorPalette
)
}
@ -84,7 +82,6 @@ fun PreviewMnemonicPhraseScreen() {
reviewMnemonic = { /*TODO*/ },
onCheckLaterClicked = { /*TODO*/ },
copyMnemonicToClipboard = {},
contentPaddingTop = 0,
mnemonicColorPalette = emptyList()
)
}
@ -96,7 +93,6 @@ fun MnemonicPhraseScreen(
reviewMnemonic: () -> Unit,
onCheckLaterClicked: () -> Unit,
copyMnemonicToClipboard: (String) -> Unit,
contentPaddingTop: Int,
mnemonicColorPalette: List<Color>
) {
val showWhatIsRecoveryPhraseDialog = remember { mutableStateOf(false) }
@ -107,7 +103,7 @@ fun MnemonicPhraseScreen(
.padding(horizontal = 16.dp),
verticalArrangement = Arrangement.Top
) {
Spacer(modifier = Modifier.height(contentPaddingTop.dp))
Spacer(modifier = Modifier.height(148.dp))
MnemonicTitle()
MnemonicDescription()
ReadMoreButton(showWhatIsRecoveryPhraseDialog)
@ -153,7 +149,7 @@ private fun ReadMoreButton(showWhatIsRecoveryPhraseDialog: MutableState<Boolean>
Text(
text = stringResource(id = R.string.onboarding_mnemonic_read_more),
style = BodyRegular.copy(
color = Color.White
color = Color(0xFFDBDAD4)
),
modifier = Modifier.align(Alignment.Center)
)

View File

@ -1,17 +1,15 @@
package com.anytypeio.anytype.ui.onboarding.screens.signup
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
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.ime
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
@ -23,8 +21,8 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
@ -33,6 +31,7 @@ import com.anytypeio.anytype.R
import com.anytypeio.anytype.core_models.Name
import com.anytypeio.anytype.core_ui.OnBoardingTextPrimaryColor
import com.anytypeio.anytype.core_ui.OnBoardingTextSecondaryColor
import com.anytypeio.anytype.core_ui.foundation.noRippleClickable
import com.anytypeio.anytype.core_ui.views.ButtonSize
import com.anytypeio.anytype.core_ui.views.HeadlineHeading
import com.anytypeio.anytype.core_ui.views.HeadlineOnBoardingDescription
@ -42,74 +41,60 @@ import com.anytypeio.anytype.ui.onboarding.OnboardingInput
@Composable
fun SetProfileNameWrapper(viewModel: OnboardingSetProfileNameViewModel, contentPaddingTop: Int) {
fun SetProfileNameWrapper(
viewModel: OnboardingSetProfileNameViewModel,
onBackClicked: () -> Unit,
) {
SetProfileNameScreen(
contentPaddingTop = contentPaddingTop,
onNextClicked = viewModel::onNextClicked,
isLoading = viewModel.state
.collectAsStateWithLifecycle()
.value is OnboardingSetProfileNameViewModel.ScreenState.Loading
.value is OnboardingSetProfileNameViewModel.ScreenState.Loading,
onBackClicked = onBackClicked
)
}
@Composable
private fun SetProfileNameScreen(
contentPaddingTop: Int,
onNextClicked: (Name) -> Unit,
onBackClicked: () -> Unit,
isLoading: Boolean
) {
val text = remember { mutableStateOf("") }
val isKeyboardVisible = WindowInsets.ime.getBottom(LocalDensity.current) > 0
val animatedSpacerHeight = animateDpAsState(
targetValue = if (isKeyboardVisible)
contentPaddingTop.dp - 72.dp
else
contentPaddingTop.dp
)
val focus = LocalFocusManager.current
Box(
modifier = Modifier.fillMaxSize()
) {
LazyColumn(
modifier = Modifier
.fillMaxSize()
) {
item {
Spacer(
modifier = Modifier.height(animatedSpacerHeight.value)
)
}
item {
SetProfileNameTitle(modifier = Modifier.padding(bottom = 12.dp))
}
item {
SetProfileNameDescription()
}
item {
Spacer(modifier = Modifier.height(16.dp))
}
item {
SetProfileNameInput(
text = text,
onKeyboardActionDoneClicked = { onNextClicked(text.value) }
)
}
item {
Spacer(modifier = Modifier.height(16.dp))
}
Column {
Spacer(
modifier = Modifier.height(148.dp)
)
SetProfileNameTitle(modifier = Modifier.padding(bottom = 12.dp))
SetProfileNameDescription()
Spacer(modifier = Modifier.height(16.dp))
SetProfileNameInput(
text = text,
onKeyboardActionDoneClicked = { onNextClicked(text.value) }
)
Spacer(modifier = Modifier.height(16.dp))
}
Image(
modifier = Modifier
.align(Alignment.TopStart)
.padding(top = 16.dp, start = 9.dp)
.noRippleClickable {
focus.clearFocus()
onBackClicked()
},
painter = painterResource(id = R.drawable.ic_back_onboarding_32),
contentDescription = "Back button"
)
SetProfileNameNextButton(
modifier = Modifier
.align(Alignment.BottomCenter)
.fillMaxWidth()
.imePadding()
.padding(start = 20.dp, end = 20.dp)
.then(
if (isKeyboardVisible)
Modifier.padding(bottom = 0.dp)
else
Modifier.padding(bottom = 13.dp)
)
.padding(start = 20.dp, end = 20.dp, bottom = 12.dp)
,
onNextClicked = onNextClicked,
text = text,
@ -137,6 +122,7 @@ fun SetProfileNameTitle(modifier: Modifier) {
}
}
@OptIn(ExperimentalLayoutApi::class)
@Composable
fun SetProfileNameInput(
text: MutableState<String>,
@ -149,9 +135,7 @@ fun SetProfileNameInput(
contentAlignment = Alignment.Center
) {
val focus = LocalFocusManager.current
val isKeyboardVisible = WindowInsets.ime.getBottom(LocalDensity.current) > 0
val focusRequester = FocusRequester()
OnboardingInput(
modifier = Modifier
.fillMaxWidth()
@ -167,11 +151,6 @@ fun SetProfileNameInput(
}
)
)
if (!isKeyboardVisible) {
focus.clearFocus()
}
LaunchedEffect(Unit) {
focusRequester.requestFocus()
}

View File

@ -12,7 +12,9 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
@ -47,7 +49,9 @@ fun PreviewWhatIsRecoveryPhraseScreen() {
@Composable
fun WhatIsRecoveryPhraseScreen() {
Column(
modifier = Modifier.padding(horizontal = 24.dp)
modifier = Modifier
.padding(horizontal = 24.dp)
.verticalScroll(rememberScrollState())
) {
Dragger(
modifier = Modifier
@ -152,19 +156,33 @@ fun WhatIsRecoveryPhraseScreen() {
.fillMaxWidth()
)
Spacer(modifier = Modifier.height(15.dp))
Text(
text = stringResource(R.string.onboarding_how_to_save_my_phrase_2),
color = Color.White,
style = BodyCalloutRegular,
modifier = Modifier.padding(horizontal = 16.dp)
)
Row(Modifier.padding(horizontal = 16.dp)) {
Text(
text = "",
color = Color.White,
style = BodyRegular
)
Spacer(Modifier.width(4.dp))
Text(
text = stringResource(R.string.onboarding_how_to_save_my_phrase_2),
color = Color.White,
style = BodyCalloutRegular
)
}
Spacer(modifier = Modifier.height(8.dp))
Text(
text = stringResource(R.string.onboarding_how_to_save_my_phrase_3),
color = Color.White,
style = BodyCalloutRegular,
modifier = Modifier.padding(horizontal = 16.dp)
)
Row(Modifier.padding(horizontal = 16.dp)) {
Text(
text = "",
color = Color.White,
style = BodyRegular
)
Spacer(Modifier.width(4.dp))
Text(
text = stringResource(R.string.onboarding_how_to_save_my_phrase_3),
color = Color.White,
style = BodyCalloutRegular
)
}
Spacer(modifier = Modifier.height(24.dp))
}
}

View File

@ -11,6 +11,7 @@ import androidx.lifecycle.repeatOnLifecycle
import androidx.recyclerview.widget.LinearLayoutManager
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_ui.features.relations.ObjectTypeAddAdapter
import com.anytypeio.anytype.core_ui.reactive.textChanges
import com.anytypeio.anytype.core_utils.ext.arg
import com.anytypeio.anytype.core_utils.ext.visible
import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetFragment
@ -47,6 +48,14 @@ class LimitObjectTypeFragment : BaseBottomSheetFragment<FragmentObjectTypeChange
}
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
launch {
binding
.searchObjectTypeInput
.textChanges()
.collect {
vm.onSearchInputChanged(it.toString())
}
}
launch {
vm.views.collectLatest {
objectTypeAdapter.submitList(it)

View File

@ -51,7 +51,7 @@ open class ObjectRelationListFragment : BaseBottomSheetFragment<FragmentRelation
private val target: String? get() = argStringOrNull(ARG_TARGET)
private val mode: Int get() = argInt(ARG_MODE)
private val isLocked: Boolean get() = arg(ARG_LOCKED)
private val isDataViewFLow: Boolean get() = arg(ARG_DATA_VIEW_FLOW)
private val isSetFlow: Boolean get() = arg(ARG_SET_FLOW)
private val docRelationAdapter by lazy {
DocumentRelationAdapter(
@ -97,7 +97,7 @@ open class ObjectRelationListFragment : BaseBottomSheetFragment<FragmentRelation
if (!isLocked) {
RelationAddToObjectFragment.new(
ctx = ctx,
isSetOrCollection = isDataViewFLow
isSetOrCollection = isSetFlow
).showChildFragment()
} else {
toast(getString(R.string.unlock_your_object_to_add_new_relation))
@ -114,7 +114,7 @@ open class ObjectRelationListFragment : BaseBottomSheetFragment<FragmentRelation
relationKey = command.relationKey,
objectId = command.target,
isLocked = command.isLocked,
flow = if (isDataViewFLow)
flow = if (isSetFlow)
RelationTextValueFragment.FLOW_DATAVIEW
else
RelationTextValueFragment.FLOW_DEFAULT
@ -126,7 +126,7 @@ open class ObjectRelationListFragment : BaseBottomSheetFragment<FragmentRelation
ctx = ctx,
relationKey = command.relationKey,
objectId = command.target,
flow = if (isDataViewFLow) {
flow = if (isSetFlow) {
RelationDateValueFragment.FLOW_SET_OR_COLLECTION
} else {
RelationDateValueFragment.FLOW_DEFAULT
@ -134,8 +134,8 @@ open class ObjectRelationListFragment : BaseBottomSheetFragment<FragmentRelation
)
fr.showChildFragment()
}
is Command.EditRelationValue -> {
if (isDataViewFLow) {
is Command.EditTagFileObjectRelationValue -> {
if (isSetFlow) {
val fr = RelationValueDVFragment().apply {
arguments = RelationValueDVFragment.args(
ctx = command.ctx,
@ -167,7 +167,7 @@ open class ObjectRelationListFragment : BaseBottomSheetFragment<FragmentRelation
dismiss()
}
is Command.EditStatusRelationValue -> {
if (isDataViewFLow) {
if (isSetFlow) {
val fr = RelationValueDVFragment().apply {
arguments = RelationValueDVFragment.args(
ctx = command.ctx,
@ -272,16 +272,16 @@ open class ObjectRelationListFragment : BaseBottomSheetFragment<FragmentRelation
}
override fun injectDependencies() {
if (isDataViewFLow) {
componentManager().dataViewRelationListComponent.get(ctx).inject(this)
if (isSetFlow) {
componentManager().objectSetRelationListComponent.get(ctx).inject(this)
} else {
componentManager().objectRelationListComponent.get(ctx).inject(this)
}
}
override fun releaseDependencies() {
if (isDataViewFLow) {
componentManager().dataViewRelationListComponent.release(ctx)
if (isSetFlow) {
componentManager().objectSetRelationListComponent.release(ctx)
} else {
componentManager().objectRelationListComponent.release(ctx)
}
@ -294,20 +294,25 @@ open class ObjectRelationListFragment : BaseBottomSheetFragment<FragmentRelation
inflater, container, false
)
/**
* 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: String,
target: String?,
mode: Int,
locked: Boolean = false,
isDataViewFlow: Boolean = false,
isSetFlow: Boolean = false,
) = ObjectRelationListFragment().apply {
arguments = bundleOf(
ARG_CTX to ctx,
ARG_TARGET to target,
ARG_MODE to mode,
ARG_LOCKED to locked,
ARG_DATA_VIEW_FLOW to isDataViewFlow
ARG_SET_FLOW to isSetFlow
)
}
@ -317,6 +322,6 @@ open class ObjectRelationListFragment : BaseBottomSheetFragment<FragmentRelation
const val ARG_LOCKED = "arg.document-relation.locked"
const val MODE_ADD = 1
const val MODE_LIST = 2
const val ARG_DATA_VIEW_FLOW = "arg.document-relation.data-view-flow"
const val ARG_SET_FLOW = "arg.document-relation.set-flow"
}
}

View File

@ -119,12 +119,17 @@ open class RelationValueDVFragment : RelationValueBaseFragment<FragmentRelationV
}
private fun showAddObjectScreen() {
val flow = if (isIntrinsic) {
AddObjectRelationFragment.FLOW_OBJECT_SET
} else {
AddObjectRelationFragment.FLOW_DATAVIEW
}
val fr = AddObjectRelationFragment.new(
ctx = ctx,
relationKey = relationKey,
objectId = target,
types = types,
flow = AddObjectRelationFragment.FLOW_DATAVIEW
flow = flow
)
fr.showChildFragment()
}
@ -133,7 +138,8 @@ open class RelationValueDVFragment : RelationValueBaseFragment<FragmentRelationV
val fr = AddOptionsRelationDVFragment.new(
ctx = ctx,
target = target,
relationKey = relationKey
relationKey = relationKey,
isIntrinsic = isIntrinsic
)
fr.showChildFragment()
}

View File

@ -139,7 +139,8 @@ class RelationValueFragment : RelationValueBaseFragment<FragmentRelationValueBin
ctx = ctx,
relationKey = relationKey,
objectId = target,
types = types
types = types,
flow = AddObjectRelationFragment.FLOW_OBJECT
)
fr.showChildFragment()
}

View File

@ -164,18 +164,31 @@ class AddObjectRelationFragment : BaseDialogFragment<FragmentRelationObjectValue
}
override fun injectDependencies() {
if (flow == FLOW_DEFAULT) {
componentManager().addObjectRelationObjectValueComponent.get(ctx).inject(this)
} else {
componentManager().addObjectSetObjectRelationObjectValueComponent.get(ctx).inject(this)
when (flow) {
FLOW_OBJECT -> {
componentManager().addObjectRelationObjectValueComponent.get(ctx).inject(this)
}
FLOW_OBJECT_SET -> {
componentManager().addObjectSetObjectRelationObjectValueComponent.get(ctx)
.inject(this)
}
FLOW_DATAVIEW -> {
componentManager().addDataViewRelationObjectValueComponent.get(ctx).inject(this)
}
}
}
override fun releaseDependencies() {
if (flow == FLOW_DEFAULT) {
componentManager().addObjectRelationObjectValueComponent.release(ctx)
} else {
componentManager().addObjectSetObjectRelationObjectValueComponent.release(ctx)
when (flow) {
FLOW_OBJECT -> {
componentManager().addObjectRelationObjectValueComponent.release(ctx)
}
FLOW_OBJECT_SET -> {
componentManager().addObjectSetObjectRelationObjectValueComponent.release(ctx)
}
FLOW_DATAVIEW -> {
componentManager().addDataViewRelationObjectValueComponent.release(ctx)
}
}
}
@ -193,7 +206,7 @@ class AddObjectRelationFragment : BaseDialogFragment<FragmentRelationObjectValue
objectId: Id,
relationKey: Key,
types: List<Id>,
flow: Int = FLOW_DEFAULT
flow: Int
) = AddObjectRelationFragment().apply {
arguments = bundleOf(
CONTEXT_ID to ctx,
@ -209,8 +222,9 @@ class AddObjectRelationFragment : BaseDialogFragment<FragmentRelationObjectValue
const val OBJECT_ID = "arg.relation.add.object.object.id"
const val TARGET_TYPES = "arg.relation.add.object.target_types"
const val FLOW_KEY = "arg.relation.add.object.flow"
const val FLOW_DEFAULT = 0
const val FLOW_DATAVIEW = 1
const val FLOW_OBJECT = 1
const val FLOW_OBJECT_SET = 2
const val FLOW_DATAVIEW = 3
}
interface ObjectValueAddReceiver {

View File

@ -4,6 +4,7 @@ import androidx.core.os.bundleOf
import androidx.fragment.app.viewModels
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.Key
import com.anytypeio.anytype.core_utils.ext.argOrNull
import com.anytypeio.anytype.di.common.componentManager
import com.anytypeio.anytype.presentation.relations.RelationValueView
import com.anytypeio.anytype.presentation.relations.add.AddOptionsRelationDVViewModel
@ -15,6 +16,8 @@ open class AddOptionsRelationDVFragment : BaseAddOptionsRelationFragment() {
lateinit var factory: AddOptionsRelationDVViewModel.Factory
override val vm: AddOptionsRelationDVViewModel by viewModels { factory }
private val isIntrinsic: Boolean get() = argOrNull<Boolean>(IS_INTRINSIC_KEY) ?: false
override fun onStatusClicked(status: RelationValueView.Option.Status) {
vm.onAddObjectSetStatusClicked(
obj = target,
@ -41,24 +44,36 @@ open class AddOptionsRelationDVFragment : BaseAddOptionsRelationFragment() {
}
override fun injectDependencies() {
componentManager().addObjectSetObjectRelationValueComponent.get(ctx).inject(this)
if (isIntrinsic) {
componentManager().addObjectSetObjectRelationValueComponent.get(ctx).inject(this)
} else {
componentManager().addDataViewObjectRelationValueComponent.get(ctx).inject(this)
}
}
override fun releaseDependencies() {
componentManager().addObjectSetObjectRelationValueComponent.release(ctx)
if (isIntrinsic) {
componentManager().addObjectSetObjectRelationValueComponent.release(ctx)
} else {
componentManager().addDataViewObjectRelationValueComponent.release(ctx)
}
}
companion object {
fun new(
ctx: Id,
target: Id,
relationKey: Key
relationKey: Key,
isIntrinsic: Boolean
) = AddOptionsRelationDVFragment().apply {
arguments = bundleOf(
CTX_KEY to ctx,
TARGET_KEY to target,
RELATION_KEY to relationKey
RELATION_KEY to relationKey,
IS_INTRINSIC_KEY to isIntrinsic
)
}
private const val IS_INTRINSIC_KEY = "args.relations.edit-value.is-intrinsic"
}
}

View File

@ -48,6 +48,7 @@ import com.anytypeio.anytype.core_ui.features.dataview.ViewerGridAdapter
import com.anytypeio.anytype.core_ui.features.dataview.ViewerGridHeaderAdapter
import com.anytypeio.anytype.core_ui.reactive.clicks
import com.anytypeio.anytype.core_ui.reactive.editorActionEvents
import com.anytypeio.anytype.core_ui.reactive.longClicks
import com.anytypeio.anytype.core_ui.reactive.touches
import com.anytypeio.anytype.core_ui.tools.DefaultTextWatcher
import com.anytypeio.anytype.core_ui.views.ButtonPrimarySmallIcon
@ -94,6 +95,7 @@ import com.anytypeio.anytype.ui.editor.cover.SelectCoverObjectSetFragment
import com.anytypeio.anytype.ui.editor.modals.IconPickerFragmentBase
import com.anytypeio.anytype.ui.editor.sheets.ObjectMenuBaseFragment
import com.anytypeio.anytype.ui.objects.BaseObjectTypeChangeFragment
import com.anytypeio.anytype.ui.objects.creation.CreateObjectOfTypeFragment
import com.anytypeio.anytype.ui.objects.types.pickers.DataViewSelectSourceFragment
import com.anytypeio.anytype.ui.objects.types.pickers.EmptyDataViewSelectSourceFragment
import com.anytypeio.anytype.ui.objects.types.pickers.ObjectSelectTypeFragment
@ -290,6 +292,21 @@ open class ObjectSetFragment :
subscribe(
binding.bottomToolbar.addDocClicks().throttleFirst()
) { vm.onAddNewDocumentClicked() }
binding
.bottomToolbar
.binding
.btnAddDoc
.longClicks(withHaptic = true)
.onEach {
val dialog = CreateObjectOfTypeFragment().apply {
onTypeSelected = {
vm.onAddNewDocumentClicked(it)
}
}
dialog.show(childFragmentManager, "set-create-object-of-type-dialog")
}
.launchIn(lifecycleScope)
}
with(binding.paginatorToolbar) {

View File

@ -12,16 +12,9 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.fragment.findNavController
import com.anytypeio.anytype.R
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_ui.common.ComposeDialogView
import com.anytypeio.anytype.core_utils.ext.arg
import com.anytypeio.anytype.core_utils.ext.safeNavigate
import com.anytypeio.anytype.core_utils.ext.setupBottomSheetBehavior
import com.anytypeio.anytype.core_utils.ext.toast
import com.anytypeio.anytype.core_utils.intents.SystemAction
import com.anytypeio.anytype.core_utils.intents.proceedWithAction
import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetComposeFragment
import com.anytypeio.anytype.core_utils.ui.proceed
import com.anytypeio.anytype.di.common.componentManager
@ -30,14 +23,11 @@ import com.anytypeio.anytype.presentation.settings.FilesStorageViewModel.Event
import com.anytypeio.anytype.ui.auth.account.DeleteAccountWarning
import com.anytypeio.anytype.ui.dashboard.ClearCacheAlertFragment
import com.anytypeio.anytype.ui_settings.fstorage.LocalStorageScreen
import com.anytypeio.anytype.ui_settings.fstorage.RemoteStorageScreen
import javax.inject.Inject
import kotlinx.coroutines.launch
class FilesStorageFragment : BaseBottomSheetComposeFragment() {
private val isRemote get() = arg<Boolean>(ARG_STORAGE_TYPE)
@Inject
lateinit var factory: FilesStorageViewModel.Factory
@ -55,19 +45,11 @@ class FilesStorageFragment : BaseBottomSheetComposeFragment() {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
MaterialTheme(typography = typography) {
if (isRemote) {
RemoteStorageScreen(
data = vm.state.collectAsStateWithLifecycle().value,
onManageFilesClicked = { throttle { vm.event(Event.OnManageFilesClicked) } },
onGetMoreSpaceClicked = { throttle { vm.event(Event.OnGetMoreSpaceClicked) } },
)
} else {
LocalStorageScreen(
data = vm.state.collectAsStateWithLifecycle().value,
onOffloadFilesClicked = { throttle { vm.event(Event.OnOffloadFilesClicked) } },
onDeleteAccountClicked = { proceedWithAccountDeletion() }
)
}
LocalStorageScreen(
data = vm.state.collectAsStateWithLifecycle().value,
onOffloadFilesClicked = { throttle { vm.event(Event.OnOffloadFilesClicked) } },
onDeleteAccountClicked = { proceedWithAccountDeletion() }
)
}
}
}
@ -101,20 +83,6 @@ class FilesStorageFragment : BaseBottomSheetComposeFragment() {
private fun processCommands(command: FilesStorageViewModel.Command) {
when (command) {
FilesStorageViewModel.Command.OpenOffloadFilesScreen -> showClearCacheDialog()
is FilesStorageViewModel.Command.OpenRemoteStorageScreen -> openRemoteStorageScreen(
subscription = command.subscription
)
is FilesStorageViewModel.Command.SendGetMoreSpaceEmail -> {
proceedWithAction(
SystemAction.MailTo(
generateSupportMail(
account = command.account,
limit = command.limit,
name = command.name
)
)
)
}
}
}
@ -124,14 +92,6 @@ class FilesStorageFragment : BaseBottomSheetComposeFragment() {
dialog.show(childFragmentManager, null)
}
private fun openRemoteStorageScreen(subscription: String) {
findNavController().safeNavigate(
R.id.filesStorageScreen,
R.id.remoteStorageFragment,
bundleOf(RemoteStorageFragment.SUBSCRIPTION_KEY to subscription)
)
}
private fun proceedWithAccountDeletion() {
vm.proceedWithAccountDeletion()
val dialog = DeleteAccountWarning()
@ -142,18 +102,6 @@ class FilesStorageFragment : BaseBottomSheetComposeFragment() {
dialog.show(childFragmentManager, null)
}
private fun generateSupportMail(
account: Id,
name: String,
limit: String,
) : String {
val bodyString = resources.getString(R.string.mail_more_space_body, limit, account, name)
return "storage@anytype.io" +
"?subject=Get%20more%20storage,%20account%20$account" +
"&body=$bodyString"
}
override fun injectDependencies() {
componentManager().filesStorageComponent.get().inject(this)
}

View File

@ -97,11 +97,7 @@ class ProfileSettingsFragment : BaseBottomSheetComposeFragment() {
),
onDataManagementClicked = throttledClick(
onClick = {
findNavController()
.navigate(
R.id.filesStorageScreen,
FilesStorageFragment.args(isRemote = false)
)
findNavController().navigate(R.id.filesStorageScreen)
}
),
onAboutClicked = throttledClick(

View File

@ -21,10 +21,10 @@ import com.anytypeio.anytype.presentation.widgets.collection.Subscription
import com.anytypeio.anytype.presentation.widgets.collection.SubscriptionMapper
import com.anytypeio.anytype.ui.base.navigation
import com.anytypeio.anytype.ui.dashboard.DeleteAlertFragment
import com.anytypeio.anytype.ui.settings.remote.RemoteStorageScreen
import com.anytypeio.anytype.ui.settings.remote.RemoteFilesManageScreen
import javax.inject.Inject
class RemoteStorageFragment : BaseBottomSheetComposeFragment() {
class RemoteFilesManageFragment : BaseBottomSheetComposeFragment() {
@Inject
lateinit var factory: CollectionViewModel.Factory
@ -47,7 +47,7 @@ class RemoteStorageFragment : BaseBottomSheetComposeFragment() {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
MaterialTheme(typography = typography) {
RemoteStorageScreen(vm = vm)
RemoteFilesManageScreen(vm = vm)
}
}
}

View File

@ -0,0 +1,137 @@
package com.anytypeio.anytype.ui.settings
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.ViewCompositionStrategy
import androidx.core.os.bundleOf
import androidx.fragment.app.viewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.fragment.findNavController
import com.anytypeio.anytype.R
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_utils.ext.toast
import com.anytypeio.anytype.core_ui.common.ComposeDialogView
import com.anytypeio.anytype.core_utils.ext.safeNavigate
import com.anytypeio.anytype.core_utils.ext.setupBottomSheetBehavior
import com.anytypeio.anytype.core_utils.intents.SystemAction
import com.anytypeio.anytype.core_utils.intents.proceedWithAction
import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetComposeFragment
import com.anytypeio.anytype.core_utils.ui.proceed
import com.anytypeio.anytype.di.common.componentManager
import com.anytypeio.anytype.presentation.settings.SpacesStorageViewModelFactory
import com.anytypeio.anytype.presentation.settings.SpacesStorageViewModel
import com.anytypeio.anytype.ui_settings.space.SpaceStorageScreen
import javax.inject.Inject
import kotlinx.coroutines.launch
class SpacesStorageFragment : BaseBottomSheetComposeFragment() {
@Inject
lateinit var factory: SpacesStorageViewModelFactory
private val vm by viewModels<SpacesStorageViewModel> { factory }
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return ComposeDialogView(
context = requireContext(),
dialog = requireDialog()
).apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
MaterialTheme(typography = typography) {
SpaceStorageScreen(
data = vm.viewState.collectAsStateWithLifecycle().value,
onManageFilesClicked = { throttle { vm.event(SpacesStorageViewModel.Event.OnManageFilesClicked) } },
onGetMoreSpaceClicked = { throttle { vm.event(SpacesStorageViewModel.Event.OnGetMoreSpaceClicked) } },
)
}
}
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupBottomSheetBehavior(PADDING_TOP)
collectCommands()
}
override fun onStart() {
super.onStart()
proceed(vm.toasts) { toast(it) }
vm.onStart()
}
override fun onStop() {
vm.onStop()
super.onStop()
}
private fun collectCommands() {
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
vm.commands.collect { command -> processCommands(command) }
}
}
}
private fun processCommands(command: SpacesStorageViewModel.Command) {
when (command) {
is SpacesStorageViewModel.Command.OpenRemoteFilesManageScreen -> {
openRemoteStorageScreen(
subscription = command.subscription
)
}
is SpacesStorageViewModel.Command.SendGetMoreSpaceEmail -> {
proceedWithAction(
SystemAction.MailTo(
generateSupportMail(
account = command.account,
limit = command.limit,
name = command.name
)
)
)
}
}
}
private fun openRemoteStorageScreen(subscription: String) {
findNavController().safeNavigate(
R.id.spacesStorageScreen,
R.id.remoteStorageFragment,
bundleOf(RemoteFilesManageFragment.SUBSCRIPTION_KEY to subscription)
)
}
private fun generateSupportMail(
account: Id,
name: String,
limit: String,
): String {
val bodyString = resources.getString(R.string.mail_more_space_body, limit, account, name)
return "storage@anytype.io" +
"?subject=Get%20more%20storage,%20account%20$account" +
"&body=$bodyString"
}
override fun injectDependencies() {
componentManager().spacesStorageComponent.get().inject(this)
}
override fun releaseDependencies() {
componentManager().spacesStorageComponent.release()
}
}
private const val PADDING_TOP = 54

View File

@ -53,7 +53,7 @@ import kotlinx.coroutines.launch
@ExperimentalMaterialApi
@Composable
fun RemoteStorageScreen(vm: CollectionViewModel) {
fun RemoteFilesManageScreen(vm: CollectionViewModel) {
val uiState by vm.uiState.collectAsStateWithLifecycle()
val showFileAlert by vm.openFileDeleteAlert.collectAsStateWithLifecycle()

View File

@ -48,7 +48,6 @@ import com.anytypeio.anytype.di.common.componentManager
import com.anytypeio.anytype.presentation.spaces.SpaceSettingsViewModel
import com.anytypeio.anytype.presentation.spaces.SpaceSettingsViewModel.Command
import com.anytypeio.anytype.presentation.util.downloader.UriFileProvider
import com.anytypeio.anytype.ui.settings.FilesStorageFragment
import com.anytypeio.anytype.ui.settings.typography
import com.anytypeio.anytype.ui.spaces.DeleteSpaceWarning
import com.anytypeio.anytype.ui.spaces.Section
@ -82,21 +81,21 @@ class SpaceSettingsFragment : BaseBottomSheetComposeFragment() {
spaceData = vm.spaceViewState.collectAsStateWithLifecycle().value,
onDeleteSpaceClicked = throttledClick(
onClick = {
vm.onDeleteSpaceClicked()
val dialog = DeleteSpaceWarning.new()
dialog.onDeletionAccepted = {
dialog.dismiss()
vm.onDeleteSpaceClicked()
vm.onDeleteSpaceAcceptedClicked()
}
dialog.onDeletionCancelled = {
vm.onDeleteSpaceWarningCancelled()
}
dialog.show(childFragmentManager, null)
}
),
onFileStorageClick = throttledClick(
onClick = {
findNavController()
.navigate(
R.id.filesStorageScreen,
FilesStorageFragment.args(isRemote = true)
)
findNavController().navigate(R.id.spacesStorageScreen)
}
),
onPersonalizationClicked = throttledClick(

View File

@ -6,13 +6,15 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
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.layout.wrapContentSize
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.Text
import androidx.compose.material.TextFieldDefaults
@ -60,36 +62,44 @@ fun CreateSpaceScreen(
val input = remember {
mutableStateOf("")
}
Column(modifier = Modifier.fillMaxHeight()) {
Box(
modifier = Modifier.fillMaxSize()
) {
Dragger(
modifier = Modifier
.padding(vertical = 6.dp)
.align(Alignment.CenterHorizontally)
.align(Alignment.TopCenter)
)
Header()
Spacer(modifier = Modifier.height(16.dp))
SpaceIcon(
modifier = Modifier.align(Alignment.CenterHorizontally),
spaceIconView = spaceIconView,
onSpaceIconClicked = onSpaceIconClicked
)
Spacer(modifier = Modifier.height(10.dp))
SpaceNameInput(input = input)
Divider()
Section(title = stringResource(id = R.string.type))
TypeOfSpace(spaceType = PRIVATE_SPACE_TYPE)
Divider()
Section(title = stringResource(id = R.string.create_space_start_with))
UseCase()
Divider()
Box(modifier = Modifier.weight(1.0f)) {
CreateSpaceButton(
onCreate = onCreate,
input = input,
modifier = Modifier.align(Alignment.BottomCenter),
isLoading = isLoading
Column(
modifier = Modifier
.fillMaxSize()
.verticalScroll(rememberScrollState())
.padding(top = 16.dp)
) {
Header()
Spacer(modifier = Modifier.height(16.dp))
SpaceIcon(
modifier = Modifier.align(Alignment.CenterHorizontally),
spaceIconView = spaceIconView,
onSpaceIconClicked = onSpaceIconClicked
)
Spacer(modifier = Modifier.height(10.dp))
SpaceNameInput(input = input)
Divider()
Section(title = stringResource(id = R.string.type))
TypeOfSpace(spaceType = PRIVATE_SPACE_TYPE)
Divider()
Section(title = stringResource(id = R.string.create_space_start_with))
UseCase()
Divider()
Spacer(modifier = Modifier.height(78.dp))
}
CreateSpaceButton(
onCreate = onCreate,
input = input,
modifier = Modifier.align(Alignment.BottomCenter),
isLoading = isLoading
)
}
}

View File

@ -20,6 +20,7 @@ class DeleteSpaceWarning : BaseBottomSheetComposeFragment() {
private val name: String get() = arg(ARG_NAME)
var onDeletionAccepted: () -> Unit = {}
var onDeletionCancelled: () -> Unit = {}
override fun onCreateView(
inflater: LayoutInflater,
@ -35,7 +36,10 @@ class DeleteSpaceWarning : BaseBottomSheetComposeFragment() {
cancelButtonText = stringResource(R.string.back),
title = stringResource(R.string.delete_space_title),
subtitle = stringResource(R.string.delete_space_subtitle),
onNegativeClick = { dismiss() },
onNegativeClick = {
onDeletionCancelled()
dismiss()
},
onPositiveClick = { onDeletionAccepted() },
isInProgress = false
)

View File

@ -88,6 +88,16 @@ class SelectSpaceFragment : BaseBottomSheetComposeFragment() {
expand()
}
override fun onStart() {
vm.onStart()
super.onStart()
}
override fun onStop() {
vm.onStop()
super.onStop()
}
override fun injectDependencies() {
componentManager().selectSpaceComponent.get().inject(this)
}

View File

@ -28,6 +28,7 @@ import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import coil.compose.rememberAsyncImagePainter
@ -150,17 +151,22 @@ private fun SelectSpaceSpaceItem(
SpaceImageBlock(
icon = item.view.icon,
onSpaceIconClick = { onSpaceClicked(item.view) },
gradientBackground = colorResource(id = R.color.default_gradient_background)
gradientBackground = colorResource(id = R.color.default_gradient_background),
gradientCornerRadius = 4.dp
)
}
Spacer(modifier = Modifier.height(10.dp))
Text(
modifier = Modifier.fillMaxSize(),
modifier = Modifier
.fillMaxSize()
.padding(horizontal = 8.dp)
,
text = item.view.name.orEmpty().ifEmpty { stringResource(id = R.string.untitled) },
textAlign = TextAlign.Center,
style = Caption1Medium,
color = Color.White,
maxLines = 1
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
Spacer(modifier = Modifier.height(16.dp))
}

View File

@ -33,7 +33,7 @@ import com.anytypeio.anytype.domain.workspace.SpaceManager
import com.anytypeio.anytype.presentation.util.Dispatcher
import com.anytypeio.anytype.presentation.widgets.WidgetDispatchEvent
import com.anytypeio.anytype.presentation.widgets.collection.CollectionViewModel
import com.anytypeio.anytype.ui.settings.RemoteStorageFragment
import com.anytypeio.anytype.ui.settings.RemoteFilesManageFragment
import dagger.Binds
import dagger.Component
import dagger.Module
@ -53,7 +53,7 @@ interface CollectionComponent {
}
fun inject(fragment: CollectionFragment)
fun inject(fragment: RemoteStorageFragment)
fun inject(fragment: RemoteFilesManageFragment)
}

View File

@ -19,6 +19,7 @@ import com.anytypeio.anytype.presentation.widgets.collection.Subscription
import com.anytypeio.anytype.presentation.widgets.collection.SubscriptionMapper
import com.anytypeio.anytype.ui.base.navigation
import com.anytypeio.anytype.ui.dashboard.DeleteAlertFragment
import com.anytypeio.anytype.ui.objects.creation.CreateObjectOfTypeFragment
import javax.inject.Inject
class CollectionFragment : BaseComposeFragment() {
@ -48,7 +49,17 @@ class CollectionFragment : BaseComposeFragment() {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
DefaultTheme {
CollectionScreen(vm)
CollectionScreen(
vm = vm,
onCreateObjectLongClicked = {
val dialog = CreateObjectOfTypeFragment().apply {
onTypeSelected = {
vm.onAddClicked(it)
}
}
dialog.show(childFragmentManager, "fullscreen-widget-create-object-of-type-dialog")
}
)
}
}
}

View File

@ -109,7 +109,11 @@ import org.burnoutcrew.reorderable.reorderable
@SuppressLint("UnusedMaterialScaffoldPaddingParameter")
@Composable
fun ScreenContent(vm: CollectionViewModel, uiState: CollectionUiState) {
fun ScreenContent(
vm: CollectionViewModel,
uiState: CollectionUiState,
onCreateObjectLongClicked: () -> Unit
) {
Box(
Modifier.background(color = colorResource(R.color.background_primary))
)
@ -130,6 +134,7 @@ fun ScreenContent(vm: CollectionViewModel, uiState: CollectionUiState) {
homeClick = { vm.onHomeClicked() },
searchClick = { vm.onSearchClicked() },
addDocClick = { vm.onAddClicked() },
onCreateObjectLongClicked = onCreateObjectLongClicked
)
}
}
@ -532,7 +537,10 @@ fun CollectionItem(
@ExperimentalMaterialApi
@Composable
fun CollectionScreen(vm: CollectionViewModel) {
fun CollectionScreen(
vm: CollectionViewModel,
onCreateObjectLongClicked: () -> Unit
) {
val uiState by vm.uiState.collectAsStateWithLifecycle()
@ -550,7 +558,7 @@ fun CollectionScreen(vm: CollectionViewModel) {
sheetContent = { BlockWidget(localDensity, vm, state) },
sheetPeekHeight = 0.dp
) {
ScreenContent(vm, state)
ScreenContent(vm, state, onCreateObjectLongClicked)
LaunchedEffect(state) {

View File

@ -20,6 +20,8 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
@ -45,6 +47,7 @@ fun BinWidgetCard(
val isHeaderMenuExpanded = remember {
mutableStateOf(false)
}
val haptic = LocalHapticFeedback.current
Box(
modifier = Modifier
.fillMaxWidth()
@ -62,6 +65,7 @@ fun BinWidgetCard(
},
onLongClick = {
isCardMenuExpanded.value = !isCardMenuExpanded.value
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
},
indication = null,
interactionSource = remember { MutableInteractionSource() }

View File

@ -17,6 +17,8 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
@ -35,6 +37,7 @@ fun LibraryWidgetCard(
onClick: () -> Unit,
onDropDownMenuAction: (DropDownMenuAction) -> Unit,
) {
val haptic = LocalHapticFeedback.current
val isCardMenuExpanded = remember {
mutableStateOf(false)
}
@ -58,6 +61,7 @@ fun LibraryWidgetCard(
},
onLongClick = {
isCardMenuExpanded.value = !isCardMenuExpanded.value
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
},
indication = null,
interactionSource = remember { MutableInteractionSource() }

View File

@ -20,6 +20,8 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
@ -48,6 +50,7 @@ fun LinkWidgetCard(
val isHeaderMenuExpanded = remember {
mutableStateOf(false)
}
val haptic = LocalHapticFeedback.current
Box(
modifier = Modifier
.fillMaxWidth()
@ -67,6 +70,7 @@ fun LinkWidgetCard(
onClick = { onWidgetSourceClicked(item.source) },
onLongClick = {
isCardMenuExpanded.value = !isCardMenuExpanded.value
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
},
indication = null,
interactionSource = remember { MutableInteractionSource() }

View File

@ -51,7 +51,8 @@ fun SpaceWidgetCard(
onSpaceIconClick = {},
mainSize = 40.dp,
gradientSize = 24.dp,
emojiSize = 24.dp
emojiSize = 24.dp,
gradientCornerRadius = 2.dp
)
}
Text(

View File

@ -33,6 +33,8 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
@ -245,6 +247,7 @@ fun WidgetHeader(
isExpanded: Boolean = false,
isInEditMode: Boolean = true
) {
val haptic = LocalHapticFeedback.current
Box(
Modifier
.fillMaxWidth()
@ -272,6 +275,7 @@ fun WidgetHeader(
onClick = onWidgetHeaderClicked,
onLongClick = {
isCardMenuExpanded.value = !isCardMenuExpanded.value
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
},
indication = null,
interactionSource = remember { MutableInteractionSource() }

View File

@ -2,7 +2,8 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
xmlns:tools="http://schemas.android.com/tools">
<View
android:id="@+id/dragger"
@ -160,6 +161,32 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/objectDiagnostics" />
<com.anytypeio.anytype.core_ui.widgets.ObjectMenuItemWidget
android:id="@+id/debugGoroutines"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:background="@drawable/default_ripple"
android:visibility="gone"
app:icon="@drawable/ic_object_menu_debug_goroutines"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/objectDiagnosticsDivider"
app:subtitle="Command Debug.StackGoroutines"
app:title="Debug Goroutines"
tools:visibility="visible" />
<View
android:id="@+id/debugGoroutinesDivider"
android:layout_width="0dp"
android:layout_height="0.5dp"
android:layout_marginTop="21dp"
android:visibility="gone"
android:background="@color/shape_primary"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/debugGoroutines" />
<FrameLayout
android:id="@+id/rvContainer"
android:layout_width="match_parent"
@ -167,7 +194,7 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/objectDiagnosticsDivider">
app:layout_constraintTop_toBottomOf="@+id/debugGoroutinesDivider">
<androidx.recyclerview.widget.RecyclerView
android:layout_gravity="center_vertical"

View File

@ -165,7 +165,7 @@
<dialog
android:id="@+id/remoteStorageFragment"
android:name="com.anytypeio.anytype.ui.settings.RemoteStorageFragment"/>
android:name="com.anytypeio.anytype.ui.settings.RemoteFilesManageFragment"/>
<dialog
android:id="@+id/selectWidgetTypeScreen"
@ -237,6 +237,12 @@
android:label="Files-Storage-Screen">
</dialog>
<dialog
android:id="@+id/spacesStorageScreen"
android:name="com.anytypeio.anytype.ui.settings.SpacesStorageFragment"
android:label="Spaces-Storage-Screen">
</dialog>
<dialog
android:id="@+id/aboutAppScreen"
android:name="com.anytypeio.anytype.ui.settings.AboutAppFragment" />

View File

@ -363,17 +363,17 @@ Do the computation of an expensive paragraph of text on a background thread:
<string name="onboarding_terms_and_policy_terms">Terms\u00A0of\u00A0Use</string>
<string name="onboarding_terms_and_policy_infix">" and "</string>
<string name="onboarding_terms_and_policy_privacy">Privacy\u00A0Policy</string>
<string name="onboarding_join_button_text">Create new account</string>
<string name="onboarding_join_button_text">Create New Account</string>
<string name="onboarding_log_in_button_text">Login</string>
<string name="onboarding_invite_code_title">Enter your invite code</string>
<string name="onboarding_invite_code_description">If you don\'t have one just go to anytype.io\nand sign up to the waiting list.</string>
<string name="onboarding_void_title">This is your Void</string>
<string name="onboarding_void_description">It is an encrypted location for everything you create. Everything is stored on your device, and backed up to the distributed network.</string>
<string name="onboarding_mnemonic_title">Save your recovery phrase</string>
<string name="onboarding_mnemonic_title">Save your Recovery Phrase</string>
<string name="onboarding_mnemonic_description">Its a novel way of authentication that gives you full ownership over your account and data.</string>
<string name="onboarding_mnemonic_show_key">Show Recovery Phrase</string>
<string name="onboarding_mnemonic_key_saved">Go to the app</string>
<string name="onboarding_mnemonic_skip">Check later</string>
<string name="onboarding_mnemonic_skip">Skip</string>
<string name="onboarding_mnemonic_copy">Copy to clipboard</string>
<string name="onboarding_set_your_name_title">Choose your name</string>
<string name="onboarding_soul_creation_description">This is how you will appear in the app</string>
@ -413,20 +413,23 @@ Do the computation of an expensive paragraph of text on a background thread:
<string name="onboarding_mnemonic_read_more">Read more</string>
<string name="onboarding_mnemonic_additional_info">You can find Recovery Phrase later in\nAnytype settings</string>
<string name="onboqrding_what_is_recovery_phrase">What is Recovery Phrase?</string>
<string name="onboarding_recovery_phrase_description">Recovery Phrase is 12 random words from which your account is magically generated on this device.</string>
<string name="onboarding_recovery_phrase_description_2">"Who knows combination of these words owns the account. "</string>
<string name="onboarding_recovery_phrase_description_3">Now, you are the only person in the world who can access it.</string>
<string name="onboarding_recovery_phrase_description_4">That is why it is essential to keep Recovery Phrase secure! You own - you responsible!</string>
<string name="onboarding_how_to_save_my_phrase">How to save my phrase?</string>
<string name="onboarding_recovery_phrase_description">Recovery Phrase is a random combination of 12 words from which your account is magically generated on this device.</string>
<string name="onboarding_recovery_phrase_description_2">Whomever knows Recovery Phrase, owns the account. </string>
<string name="onboarding_recovery_phrase_description_3">At this moment, you are the only person in the world who knows it.</string>
<string name="onboarding_recovery_phrase_description_4">That\'s why it\'s essential to keep Recovery Phrase safe. As the sole owner, nobody can help you if it\'s lost.</string>
<string name="onboarding_how_to_save_my_phrase">How to save my Phrase?</string>
<string name="onboarding_how_to_save_my_phrase_2">The easiest way to store your Recovery Phrase is to save it in your password manager.</string>
<string name="onboarding_how_to_save_my_phrase_3">The most secure way is to write it down on paper and keep it offline, in a safe and secure place.</string>
<string name="anytype_update_alert_description">Some of your data was managed in a newer version of Anytype. Please update the app to work with all your docs and the latest features.</string>
<string name="anytype_update_alert_title">Its time to update</string>
<string name="anytype_update_alert_description">This object was modified in a newer version of Anytype. Please update the app to open it on this device.</string>
<string name="anytype_update_alert_title">Update Your App</string>
<string name="download_anytype_url">https://download.anytype.io</string>
<string name="space_type_personal">Personal</string>
<string name="space_type_private">Private</string>
<string name="space_type_personal">Personal Space</string>
<string name="space_type_private">Private Space</string>
<string name="space_type_unknown">Unknown</string>
<string name="create_space_start_with">Start with</string>
<string name="create_object_section_groups">Groups</string>
<string name="create_object_section_objects">Objects</string>
<string name="log_in">Log In</string>
</resources>

View File

@ -1,3 +1,4 @@
package com.anytypeio.anytype.core_models
const val NO_VALUE = ""
const val NO_VALUE = ""
const val EMPTY_QUERY = ""

View File

@ -1,7 +1,10 @@
package com.anytypeio.anytype.core_models
sealed class FileLimitsEvent {
data class SpaceUsage(val bytesUsage: Long) : FileLimitsEvent()
data class SpaceUsage(
val space: Id,
val bytesUsage: Long
) : FileLimitsEvent()
data class LocalUsage(val bytesUsage: Long) : FileLimitsEvent()
data class FileLimitReached(
val spaceId: String,

View File

@ -0,0 +1,33 @@
package com.anytypeio.anytype.core_models
data class NodeUsageInfo(
val nodeUsage: NodeUsage = NodeUsage.empty(),
val spaces: List<SpaceUsage> = emptyList()
)
data class NodeUsage(
var filesCount: Long?,
var cidsCount: Long?,
var bytesUsage: Long?,
var bytesLeft: Long?,
var bytesLimit: Long?,
var localBytesUsage: Long?
) {
companion object {
fun empty() = NodeUsage(
filesCount = null,
cidsCount = null,
bytesUsage = null,
bytesLeft = null,
bytesLimit = null,
localBytesUsage = null
)
}
}
data class SpaceUsage(
var space: Id,
var filesCount: Long,
var cidsCount: Long,
var bytesUsage: Long
)

View File

@ -3,6 +3,7 @@ package com.anytypeio.anytype.core_models
import com.anytypeio.anytype.core_models.Relations.RELATION_FORMAT_OBJECT_TYPES
import com.anytypeio.anytype.core_models.ext.typeOf
import com.anytypeio.anytype.core_models.restrictions.ObjectRestriction
import com.anytypeio.anytype.core_models.restrictions.SpaceStatus
/**
* Wrapper for easily parsing object's relations when object is represented as an untyped structure.
@ -134,6 +135,8 @@ sealed class ObjectWrapper {
val isValid get() = map.containsKey(Relations.ID)
val notDeletedNorArchived get() = (isDeleted != true && isArchived != true)
val targetSpaceId: String? by default
}
/**
@ -239,11 +242,19 @@ sealed class ObjectWrapper {
val color: String = relationOptionColor.orEmpty()
}
data class Workspace(override val map: Struct) : ObjectWrapper() {
data class SpaceView(override val map: Struct) : ObjectWrapper() {
private val default = map.withDefault { null }
val id: Id by default
val name: String? by default
val spaceId: String? by default
val targetSpaceId: String? by default
val spaceAccountStatus: SpaceStatus
get() {
val code = getValue<Double?>(Relations.SPACE_ACCOUNT_STATUS)
return SpaceStatus
.values()
.firstOrNull { it.code == code?.toInt() }
?: SpaceStatus.UNKNOWN
}
}
inline fun <reified T> getValue(relation: Key): T? {

View File

@ -1,6 +1,12 @@
package com.anytypeio.anytype.core_models.restrictions
enum class SpaceStatus(val code: Number) {
DELETED(7),
OK(2)
UNKNOWN(0),
LOADING(1),
OK(2),
MISSING(3),
ERROR(4),
REMOTE_WAITING_DELETION(5),
REMOTE_DELETED(6),
SPACE_DELETED(7),
}

View File

@ -1,7 +1,9 @@
package com.anytypeio.anytype.core_ui.foundation
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Indication
import androidx.compose.foundation.clickable
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
@ -23,7 +25,21 @@ fun Modifier.noRippleClickable(
enabled = enabled,
onClickLabel = onClickLabel,
role = role,
onClick = onClick
)
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun Modifier.noRippleCombinedClickable(
enabled: Boolean = true,
onLongClicked: () -> Unit,
onClick: () -> Unit,
) = combinedClickable(
interactionSource = remember { MutableInteractionSource() },
indication = null,
enabled = enabled,
onClick = onClick,
onLongClick = onLongClicked
)
@Composable

View File

@ -11,12 +11,15 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import com.anytypeio.anytype.core_ui.R
import com.anytypeio.anytype.core_ui.foundation.components.BottomNavigationDefaults.Height
import com.anytypeio.anytype.core_ui.foundation.noRippleClickable
import com.anytypeio.anytype.core_ui.foundation.noRippleCombinedClickable
@Composable
@ -26,6 +29,7 @@ fun BottomNavigationMenu(
homeClick: () -> Unit = {},
searchClick: () -> Unit = {},
addDocClick: () -> Unit = {},
onCreateObjectLongClicked: () -> Unit = {}
) {
Row(
modifier = modifier
@ -42,21 +46,33 @@ fun BottomNavigationMenu(
MenuItem(BottomNavigationItem.BACK.res, onClick = backClick)
MenuItem(BottomNavigationItem.HOME.res, onClick = homeClick)
MenuItem(BottomNavigationItem.SEARCH.res, onClick = searchClick)
MenuItem(BottomNavigationItem.ADD_DOC.res, onClick = addDocClick)
MenuItem(
BottomNavigationItem.ADD_DOC.res,
onClick = addDocClick,
onLongClick = onCreateObjectLongClicked
)
}
}
@Composable
private fun MenuItem(
@DrawableRes res: Int,
onClick: () -> Unit = {}
onClick: () -> Unit = {},
onLongClick: () -> Unit = {},
) {
val haptic = LocalHapticFeedback.current
Image(
painter = painterResource(id = res),
contentDescription = "",
modifier = Modifier.noRippleClickable {
onClick.invoke()
}
modifier = Modifier.noRippleCombinedClickable(
onClick = onClick,
onLongClicked = {
haptic.performHapticFeedback(
HapticFeedbackType.LongPress
)
onLongClick()
}
)
)
}

View File

@ -3,6 +3,7 @@ package com.anytypeio.anytype.core_ui.reactive
import android.os.Looper
import android.text.Editable
import android.text.TextWatcher
import android.view.HapticFeedbackConstants
import android.view.MotionEvent
import android.view.View
import android.widget.EditText
@ -27,6 +28,19 @@ fun View.clicks(): Flow<Unit> = callbackFlow {
awaitClose { setOnClickListener(null) }
}.conflate()
fun View.longClicks(withHaptic: Boolean = false): Flow<Unit> = callbackFlow {
checkMainThread()
val listener = View.OnLongClickListener {
trySend(Unit)
if (withHaptic) {
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
}
true
}
setOnLongClickListener(listener)
awaitClose { setOnClickListener(null) }
}.conflate()
fun EditText.textChanges(): Flow<CharSequence> = callbackFlow {
checkMainThread()
val listener = object : TextWatcher {

View File

@ -94,7 +94,6 @@ import com.anytypeio.anytype.core_ui.views.BodyCalloutRegular
import com.anytypeio.anytype.core_ui.views.BodyRegular
import com.anytypeio.anytype.core_ui.views.Caption1Medium
import com.anytypeio.anytype.core_ui.views.Caption2Semibold
import com.anytypeio.anytype.core_ui.views.ModalTitle
import com.anytypeio.anytype.core_ui.views.Title1
import com.anytypeio.anytype.core_ui.views.fontInterRegular
import com.anytypeio.anytype.emojifier.Emojifier
@ -917,7 +916,7 @@ fun ObjectTypesList(
is TemplateObjectTypeView.Item -> {
val borderWidth: Dp
val borderColor: Color
if (item.isDefault) {
if (item.isSelected) {
borderWidth = 2.dp
borderColor = colorResource(id = R.color.palette_system_amber_50)
} else {

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="19dp"
android:height="18dp"
android:viewportWidth="19"
android:viewportHeight="18">
<path
android:pathData="M17.115,9C17.115,13.418 13.533,17 9.115,17C4.696,17 1.115,13.418 1.115,9C1.115,4.582 4.696,1 9.115,1C13.533,1 17.115,4.582 17.115,9ZM5.69,5.576C5.925,5.341 6.305,5.341 6.539,5.576L9.115,8.151L11.691,5.576C11.925,5.341 12.305,5.341 12.539,5.576C12.773,5.81 12.773,6.19 12.539,6.424L9.963,9L12.539,11.576C12.773,11.81 12.773,12.19 12.539,12.424C12.305,12.659 11.925,12.659 11.691,12.424L9.115,9.849L6.539,12.424C6.305,12.659 5.925,12.659 5.69,12.424C5.456,12.19 5.456,11.81 5.69,11.576L8.266,9L5.69,6.424C5.456,6.19 5.456,5.81 5.69,5.576Z"
android:fillColor="@color/glyph_active"
android:fillType="evenOdd"/>
</vector>

View File

@ -0,0 +1,16 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="44dp"
android:height="44dp"
android:viewportWidth="44"
android:viewportHeight="44">
<path
android:pathData="M22,0L22,0A22,22 0,0 1,44 22L44,22A22,22 0,0 1,22 44L22,44A22,22 0,0 1,0 22L0,22A22,22 0,0 1,22 0z"
android:strokeAlpha="0.2"
android:fillColor="@color/palette_dark_red"
android:fillAlpha="0.2"/>
<path
android:pathData="M24.76,34C24.517,34 24.306,33.823 24.247,33.569L19.37,12.889L17.189,22.14C17.129,22.394 16.917,22.571 16.675,22.571L10.53,22.571C10.237,22.571 10,22.315 10,22C10,21.684 10.237,21.428 10.53,21.428H16.263L18.857,10.431C18.917,10.177 19.128,10 19.37,10C19.612,10 19.824,10.177 19.883,10.431L24.76,31.111L26.941,21.86C27.001,21.606 27.212,21.429 27.454,21.429H33.47C33.763,21.429 34,21.685 34,22C34,22.316 33.763,22.572 33.47,22.572L27.866,22.572L25.273,33.569C25.213,33.823 25.002,34 24.76,34H24.76Z"
android:strokeWidth="0.6"
android:fillColor="@color/palette_system_red"
android:strokeColor="@color/palette_system_red"/>
</vector>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="19dp"
android:height="18dp"
android:viewportWidth="19"
android:viewportHeight="18">
<path
android:pathData="M16.676,14.574L12.843,10.74C13.531,9.802 13.899,8.67 13.893,7.508C13.88,4.474 11.427,2.018 8.394,2C6.942,1.993 5.549,2.568 4.523,3.595C3.497,4.622 2.925,6.017 2.933,7.468C2.947,10.502 5.4,12.958 8.433,12.976C9.6,12.981 10.737,12.609 11.675,11.915L11.679,11.912L15.508,15.743C15.715,15.96 16.024,16.048 16.315,15.973C16.605,15.897 16.832,15.67 16.907,15.38C16.982,15.089 16.894,14.781 16.676,14.574ZM8.429,11.878C6.003,11.864 4.04,9.899 4.029,7.472C4.023,6.311 4.481,5.196 5.301,4.374C6.122,3.552 7.236,3.093 8.397,3.098C10.824,3.112 12.787,5.077 12.797,7.504C12.804,8.665 12.346,9.78 11.526,10.602C10.705,11.423 9.591,11.883 8.429,11.878Z"
android:fillColor="@color/glyph_active"
android:fillType="evenOdd"/>
</vector>

File diff suppressed because one or more lines are too long

View File

@ -147,8 +147,8 @@ inline fun <T, R> Iterable<T>.allUniqueBy(transform: (T) -> R): Boolean {
}
fun Long.readableFileSize(): String {
if (this <= 0) return "0"
val units = arrayOf("B", "kB", "MB", "GB", "TB")
if (this <= 0) return "Zero KB"
val units = arrayOf("B", "KB", "MB", "GB", "TB")
val digitGroups = (log10(this.toDouble()) / log10(1024.0)).toInt()
return DecimalFormat("#,##0.#").format(this / 1024.0.pow(digitGroups.toDouble())) + " " + units[digitGroups]
}

View File

@ -13,6 +13,7 @@ import com.anytypeio.anytype.core_models.FileLimits
import com.anytypeio.anytype.core_models.Hash
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.Key
import com.anytypeio.anytype.core_models.NodeUsageInfo
import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.core_models.ObjectView
import com.anytypeio.anytype.core_models.ObjectWrapper
@ -873,8 +874,8 @@ class BlockDataRepository(
return remote.setQueryToSet(command)
}
override suspend fun fileSpaceUsage(space: SpaceId): FileLimits {
return remote.fileSpaceUsage(space)
override suspend fun nodeUsage(): NodeUsageInfo {
return remote.nodeUsage()
}
override suspend fun setInternalFlags(command: Command.SetInternalFlags): Payload {
@ -888,4 +889,8 @@ class BlockDataRepository(
override suspend fun createTemplateFromObject(ctx: Id): Id {
return remote.createTemplateFromObject(ctx)
}
override suspend fun debugStackGoroutines(path: String) {
return remote.debugStackGoroutines(path)
}
}

View File

@ -12,6 +12,7 @@ import com.anytypeio.anytype.core_models.DVViewerType
import com.anytypeio.anytype.core_models.FileLimits
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.Key
import com.anytypeio.anytype.core_models.NodeUsageInfo
import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.core_models.ObjectView
import com.anytypeio.anytype.core_models.ObjectWrapper
@ -373,10 +374,11 @@ interface BlockRemote {
suspend fun sortDataViewViewRelation(command: Command.SortRelations): Payload
suspend fun addObjectToCollection(command: Command.AddObjectToCollection): Payload
suspend fun setQueryToSet(command: Command.SetQueryToSet): Payload
suspend fun fileSpaceUsage(space: SpaceId): FileLimits
suspend fun nodeUsage(): NodeUsageInfo
suspend fun setInternalFlags(command: Command.SetInternalFlags): Payload
suspend fun duplicateObjectsList(ids: List<Id>): List<Id>
suspend fun createTemplateFromObject(ctx: Id): Id
suspend fun debugStackGoroutines(path: String)
}

View File

@ -7,8 +7,9 @@ import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.base.ResultInteractor
import com.anytypeio.anytype.domain.block.repo.BlockRepository
import javax.inject.Inject
class GetObjectTypes(
class GetObjectTypes @Inject constructor(
private val repo: BlockRepository,
dispatchers: AppCoroutineDispatchers
) : ResultInteractor<GetObjectTypes.Params, List<ObjectWrapper.Type>>(dispatchers.io) {

View File

@ -13,6 +13,7 @@ import com.anytypeio.anytype.core_models.FileLimits
import com.anytypeio.anytype.core_models.Hash
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.Key
import com.anytypeio.anytype.core_models.NodeUsageInfo
import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.core_models.ObjectView
import com.anytypeio.anytype.core_models.ObjectWrapper
@ -186,11 +187,11 @@ interface BlockRepository {
): Payload
suspend fun searchObjects(
sorts: List<DVSort>,
filters: List<DVFilter>,
fulltext: String,
offset: Int,
limit: Int,
sorts: List<DVSort> = emptyList(),
filters: List<DVFilter> = emptyList(),
fulltext: String = "",
offset: Int = 0,
limit: Int = 0,
keys: List<Id> = emptyList()
): List<Struct>
@ -423,8 +424,9 @@ interface BlockRepository {
suspend fun sortDataViewViewRelation(command: Command.SortRelations): Payload
suspend fun addObjectToCollection(command: Command.AddObjectToCollection): Payload
suspend fun setQueryToSet(command: Command.SetQueryToSet): Payload
suspend fun fileSpaceUsage(space: SpaceId): FileLimits
suspend fun nodeUsage(): NodeUsageInfo
suspend fun setInternalFlags(command: Command.SetInternalFlags): Payload
suspend fun duplicateObjectsList(ids: List<Id>): List<Id>
suspend fun createTemplateFromObject(ctx: Id): Id
suspend fun debugStackGoroutines(path: String)
}

View File

@ -0,0 +1,18 @@
package com.anytypeio.anytype.domain.debugging
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.base.ResultInteractor
import com.anytypeio.anytype.domain.block.repo.BlockRepository
import javax.inject.Inject
class DebugGoroutines @Inject constructor(
private val repo: BlockRepository,
dispatchers: AppCoroutineDispatchers
) : ResultInteractor<DebugGoroutines.Params, Unit>(dispatchers.io) {
override suspend fun doWork(params: Params) {
repo.debugStackGoroutines(params.path)
}
data class Params(val path: String)
}

View File

@ -28,14 +28,7 @@ interface StorelessSubscriptionContainer {
fun subscribe(searchParams: StoreSearchParams): Flow<List<ObjectWrapper.Basic>>
fun subscribe(searchParams: StoreSearchByIdsParams) : Flow<List<ObjectWrapper.Basic>>
suspend fun unsubscribe(subscriptions: List<Id>)
companion object {
const val SUBSCRIPTION_SETTINGS = "settings-subscription"
const val SUBSCRIPTION_PROFILE = "profile-subscription"
const val SUBSCRIPTION_TEMPLATES = "templates-subscription"
}
class Impl @Inject constructor(
private val repo: BlockRepository,

View File

@ -1,5 +1,6 @@
package com.anytypeio.anytype.domain.library.processors
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_models.SubscriptionEvent
import com.anytypeio.anytype.domain.library.SubscriptionObject
@ -15,7 +16,7 @@ class EventSetProcessor : SubscriptionEventProcessor<SubscriptionEvent.Set> {
indexOfItem,
SubscriptionObject(
event.target,
com.anytypeio.anytype.core_models.ObjectWrapper.Basic(event.data)
ObjectWrapper.Basic(event.data)
)
)
} else {
@ -23,7 +24,7 @@ class EventSetProcessor : SubscriptionEventProcessor<SubscriptionEvent.Set> {
0,
SubscriptionObject(
event.target,
com.anytypeio.anytype.core_models.ObjectWrapper.Basic(event.data)
ObjectWrapper.Basic(event.data)
)
)
}

View File

@ -14,6 +14,7 @@ import kotlinx.coroutines.flow.emitAll
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.scan
import kotlinx.coroutines.withContext
class ObjectTypesSubscriptionContainer(
private val repo: BlockRepository,
@ -127,6 +128,14 @@ class ObjectTypesSubscriptionContainer(
*/
private fun subscribe(subscriptions: List<Id>) = channel.subscribe(subscriptions)
suspend fun unsubscribe() = withContext(dispatchers.io) {
runCatching {
repo.cancelObjectSearchSubscription(
listOf(SUBSCRIPTION_ID)
)
}
}
data class Params(
val subscription: Id,
val sorts: List<DVSort>,

View File

@ -1,5 +1,6 @@
package com.anytypeio.anytype.domain.search
import com.anytypeio.anytype.core_models.Config
import com.anytypeio.anytype.core_models.DVFilter
import com.anytypeio.anytype.core_models.DVFilterCondition
import com.anytypeio.anytype.core_models.ObjectType
@ -9,67 +10,76 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.launch
class ObjectTypesSubscriptionManager (
private val scope: CoroutineScope = GlobalScope,
private val subscription: ObjectTypesSubscriptionContainer,
private val container: ObjectTypesSubscriptionContainer,
private val spaceManager: SpaceManager
) {
private val pipeline = spaceManager.observe().flatMapLatest { config ->
val params = buildParams(config)
container.observe(params)
}
private var job: Job? = null
fun onStart() {
job?.cancel()
job = scope.launch {
val params = ObjectTypesSubscriptionContainer.Params(
subscription = ObjectTypesSubscriptionContainer.SUBSCRIPTION_ID,
filters = listOf(
DVFilter(
relation = Relations.LAYOUT,
condition = DVFilterCondition.EQUAL,
value = ObjectType.Layout.OBJECT_TYPE.code.toDouble()
),
DVFilter(
relation = Relations.SPACE_ID,
condition = DVFilterCondition.EQUAL,
value = spaceManager.get()
),
DVFilter(
relation = Relations.IS_DELETED,
condition = DVFilterCondition.NOT_EQUAL,
value = true
),
),
limit = 0,
offset = 0L,
sorts = emptyList(),
sources = emptyList(),
keys = listOf(
Relations.ID,
Relations.NAME,
Relations.IS_HIDDEN,
Relations.IS_DELETED,
Relations.IS_ARCHIVED,
Relations.SMARTBLOCKTYPES,
Relations.LAYOUT,
Relations.DESCRIPTION,
Relations.ICON_EMOJI,
Relations.SOURCE_OBJECT,
Relations.IS_READ_ONLY,
Relations.RECOMMENDED_LAYOUT,
Relations.DEFAULT_TEMPLATE_ID,
Relations.SPACE_ID,
Relations.UNIQUE_KEY
),
ignoreWorkspace = true
)
subscription.observe(params).collect()
}
job = scope.launch { pipeline.collect() }
}
private fun buildParams(config: Config) =
ObjectTypesSubscriptionContainer.Params(
subscription = ObjectTypesSubscriptionContainer.SUBSCRIPTION_ID,
filters = listOf(
DVFilter(
relation = Relations.LAYOUT,
condition = DVFilterCondition.EQUAL,
value = ObjectType.Layout.OBJECT_TYPE.code.toDouble()
),
DVFilter(
relation = Relations.SPACE_ID,
condition = DVFilterCondition.EQUAL,
value = config.space
),
DVFilter(
relation = Relations.IS_DELETED,
condition = DVFilterCondition.NOT_EQUAL,
value = true
),
),
limit = 0,
offset = 0L,
sorts = emptyList(),
sources = emptyList(),
keys = listOf(
Relations.ID,
Relations.NAME,
Relations.IS_HIDDEN,
Relations.IS_DELETED,
Relations.IS_ARCHIVED,
Relations.SMARTBLOCKTYPES,
Relations.LAYOUT,
Relations.DESCRIPTION,
Relations.ICON_EMOJI,
Relations.SOURCE_OBJECT,
Relations.IS_READ_ONLY,
Relations.RECOMMENDED_LAYOUT,
Relations.DEFAULT_TEMPLATE_ID,
Relations.SPACE_ID,
Relations.UNIQUE_KEY
),
ignoreWorkspace = true
)
fun onStop() {
job?.cancel()
job = null
scope.launch {
container.unsubscribe()
job?.cancel()
job = null
}
}
}

View File

@ -14,6 +14,7 @@ import kotlinx.coroutines.flow.emitAll
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.scan
import kotlinx.coroutines.withContext
class RelationsSubscriptionContainer(
private val repo: BlockRepository,
@ -122,11 +123,21 @@ class RelationsSubscriptionContainer(
}.flowOn(dispatchers.io)
}
/**
* Returns events for subscriptions and dependent subscriptions
*/
private fun subscribe(subscriptions: List<Id>) = channel.subscribe(subscriptions)
suspend fun unsubscribe() = withContext(dispatchers.io) {
runCatching {
repo.cancelObjectSearchSubscription(
listOf(SUBSCRIPTION_ID)
)
}
}
data class Params(
val subscription: Id,
val sorts: List<DVSort>,

View File

@ -2,6 +2,7 @@ package com.anytypeio.anytype.domain.search
import com.anytypeio.anytype.core_models.DVFilter
import com.anytypeio.anytype.core_models.DVFilterCondition
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.core_models.Relations
import com.anytypeio.anytype.domain.workspace.SpaceManager
@ -10,71 +11,78 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.launch
class RelationsSubscriptionManager @Inject constructor(
private val scope: CoroutineScope = GlobalScope,
private val subscription: RelationsSubscriptionContainer,
private val container: RelationsSubscriptionContainer,
private val spaceManager: SpaceManager
) {
private val pipeline = spaceManager.observe().flatMapLatest { config ->
val params = buildParams(config.space)
container.observe(params)
}
private var job: Job? = null
fun onStart() {
job?.cancel()
job = scope.launch {
val params = RelationsSubscriptionContainer.Params(
subscription = RelationsSubscriptionContainer.SUBSCRIPTION_ID,
filters = listOf(
DVFilter(
relation = Relations.LAYOUT,
condition = DVFilterCondition.EQUAL,
value = ObjectType.Layout.RELATION.code.toDouble()
),
DVFilter(
relation = Relations.IS_DELETED,
condition = DVFilterCondition.EQUAL,
value = false
),
DVFilter(
relation = Relations.SPACE_ID,
condition = DVFilterCondition.EQUAL,
value = spaceManager.get()
)
),
limit = 0,
offset = 0L,
sorts = emptyList(),
sources = emptyList(),
keys = listOf(
Relations.ID,
Relations.SPACE_ID,
Relations.TYPE,
Relations.LAYOUT,
Relations.NAME,
Relations.RELATION_FORMAT,
Relations.RELATION_KEY,
Relations.SCOPE,
Relations.IS_READ_ONLY,
Relations.IS_HIDDEN,
Relations.IS_DELETED,
Relations.IS_ARCHIVED,
Relations.IS_FAVORITE,
Relations.RESTRICTIONS,
Relations.MAX_COUNT,
Relations.RELATION_READ_ONLY_VALUE,
Relations.RELATION_DEFAULT_VALUE,
Relations.RELATION_FORMAT_OBJECT_TYPES
),
ignoreWorkspace = true
)
subscription.observe(params).collect()
}
job = scope.launch { pipeline.collect() }
}
private fun buildParams(space: Id) = RelationsSubscriptionContainer.Params(
subscription = RelationsSubscriptionContainer.SUBSCRIPTION_ID,
filters = listOf(
DVFilter(
relation = Relations.LAYOUT,
condition = DVFilterCondition.EQUAL,
value = ObjectType.Layout.RELATION.code.toDouble()
),
DVFilter(
relation = Relations.IS_DELETED,
condition = DVFilterCondition.EQUAL,
value = false
),
DVFilter(
relation = Relations.SPACE_ID,
condition = DVFilterCondition.EQUAL,
value = space
)
),
limit = 0,
offset = 0L,
sorts = emptyList(),
sources = emptyList(),
keys = listOf(
Relations.ID,
Relations.SPACE_ID,
Relations.TYPE,
Relations.LAYOUT,
Relations.NAME,
Relations.RELATION_FORMAT,
Relations.RELATION_KEY,
Relations.SCOPE,
Relations.IS_READ_ONLY,
Relations.IS_HIDDEN,
Relations.IS_DELETED,
Relations.IS_ARCHIVED,
Relations.IS_FAVORITE,
Relations.RESTRICTIONS,
Relations.MAX_COUNT,
Relations.RELATION_READ_ONLY_VALUE,
Relations.RELATION_DEFAULT_VALUE,
Relations.RELATION_FORMAT_OBJECT_TYPES
),
ignoreWorkspace = true
)
fun onStop() {
job?.cancel()
job = null
scope.launch {
container.unsubscribe()
job?.cancel()
job = null
}
}
}

View File

@ -0,0 +1,36 @@
package com.anytypeio.anytype.domain.spaces
import com.anytypeio.anytype.core_models.DVFilter
import com.anytypeio.anytype.core_models.DVFilterCondition
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_models.Relations
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.base.ResultInteractor
import com.anytypeio.anytype.domain.block.repo.BlockRepository
import javax.inject.Inject
class GetSpaceView @Inject constructor(
private val repo: BlockRepository,
dispatchers: AppCoroutineDispatchers
): ResultInteractor<Id, ObjectWrapper.Basic?>(dispatchers.io) {
override suspend fun doWork(params: Id): ObjectWrapper.Basic? {
val result = repo.searchObjects(
filters = buildList {
add(
DVFilter(
relation = Relations.ID,
value = params,
condition = DVFilterCondition.EQUAL
)
)
},
limit = 1
).firstOrNull()
return if (result != null) {
ObjectWrapper.Basic(result)
} else {
null
}
}
}

View File

@ -0,0 +1,83 @@
package com.anytypeio.anytype.domain.spaces
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_models.Relations
import com.anytypeio.anytype.core_models.restrictions.SpaceStatus
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.config.ConfigStorage
import com.anytypeio.anytype.domain.debugging.Logger
import com.anytypeio.anytype.domain.library.StoreSearchByIdsParams
import com.anytypeio.anytype.domain.library.StorelessSubscriptionContainer
import com.anytypeio.anytype.domain.workspace.SpaceManager
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
class SpaceDeletedStatusWatcher @Inject constructor(
private val scope: CoroutineScope,
private val container: StorelessSubscriptionContainer,
private val spaceManager: SpaceManager,
private val dispatchers: AppCoroutineDispatchers,
private val configStorage: ConfigStorage,
private val logger: Logger
) {
private val jobs = mutableListOf<Job>()
fun onStart() {
jobs += scope.launch(dispatchers.io) {
spaceManager
.observe()
.flatMapLatest { config ->
container.subscribe(
searchParams = StoreSearchByIdsParams(
subscription = GLOBAL_SPACE_VIEW_SUBSCRIPTION,
targets = listOf(config.spaceView),
keys = buildList {
add(Relations.ID)
add(Relations.TARGET_SPACE_ID)
add(Relations.SPACE_ACCOUNT_STATUS)
}
)
)
}
.mapNotNull { results -> results.firstOrNull() }
.onEach { result ->
val spaceView = result.let {
ObjectWrapper.SpaceView(it.map)
}
if (spaceView.spaceAccountStatus == SpaceStatus.SPACE_DELETED) {
logger.logWarning("Current space is deleted")
val accountConfig = configStorage.getOrNull()
if (accountConfig != null) {
logger.logWarning("Account config found. Switching to default space.")
spaceManager.set(accountConfig.space)
} else {
logger.logWarning("Account config not found. Resetting space.")
spaceManager.clear()
}
}
}
.collect()
}
}
fun onStop() {
scope.launch(dispatchers.io) {
container.unsubscribe(listOf(GLOBAL_SPACE_VIEW_SUBSCRIPTION))
with(jobs) {
forEach { it.cancel() }
clear()
}
}
}
companion object {
const val GLOBAL_SPACE_VIEW_SUBSCRIPTION = "subscription.global.space-view"
}
}

View File

@ -5,6 +5,7 @@ import com.anytypeio.anytype.core_models.DVFilter
import com.anytypeio.anytype.core_models.DVFilterCondition
import com.anytypeio.anytype.core_models.DVSort
import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.core_models.ObjectTypeIds
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_models.Relations
import com.anytypeio.anytype.core_models.primitives.TypeId
@ -52,6 +53,15 @@ class GetTemplates(
relation = Relations.SPACE_ID,
condition = DVFilterCondition.EQUAL,
value = spaceManager.get()
),
DVFilter(
relation = Relations.TYPE_UNIQUE_KEY,
condition = DVFilterCondition.EQUAL,
value = ObjectTypeIds.TEMPLATE
),
DVFilter(
relation = Relations.ID,
condition = DVFilterCondition.NOT_EMPTY
)
),
keys = listOf(

View File

@ -1,18 +0,0 @@
package com.anytypeio.anytype.domain.workspace
import com.anytypeio.anytype.core_models.FileLimits
import com.anytypeio.anytype.core_models.primitives.SpaceId
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
import com.anytypeio.anytype.domain.base.ResultInteractor
import com.anytypeio.anytype.domain.block.repo.BlockRepository
class FileSpaceUsage(
private val repo: BlockRepository,
private val spaceManager: SpaceManager,
dispatchers: AppCoroutineDispatchers
) : ResultInteractor<Unit, FileLimits>(dispatchers.io) {
override suspend fun doWork(params: Unit): FileLimits {
return repo.fileSpaceUsage(space = SpaceId(spaceManager.get()))
}
}

Some files were not shown because too many files have changed in this diff Show More