mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
DROID-99 Editor | Navigation | Fix double clicks / crashes (#2757)
This commit is contained in:
parent
a71e8ec55c
commit
b11fabeb11
15 changed files with 184 additions and 126 deletions
|
@ -6,6 +6,7 @@ import androidx.viewbinding.ViewBinding
|
|||
import com.anytypeio.anytype.BuildConfig
|
||||
import com.anytypeio.anytype.core_utils.common.EventWrapper
|
||||
import com.anytypeio.anytype.core_utils.ui.BaseFragment
|
||||
import com.anytypeio.anytype.core_utils.ui.getNavigationId
|
||||
import com.anytypeio.anytype.presentation.navigation.AppNavigation
|
||||
import com.anytypeio.anytype.presentation.navigation.AppNavigation.Command
|
||||
import timber.log.Timber
|
||||
|
@ -14,10 +15,14 @@ abstract class NavigationFragment<BINDING : ViewBinding>(
|
|||
@LayoutRes private val layout: Int
|
||||
) : BaseFragment<BINDING>(layout) {
|
||||
|
||||
private val currentNavigationId by lazy { getNavigationId() }
|
||||
|
||||
val navObserver = Observer<EventWrapper<Command>> { event ->
|
||||
event.getContentIfNotHandled()?.let {
|
||||
try {
|
||||
navigate(it)
|
||||
if (currentNavigationId == getNavigationId()) {
|
||||
throttle { navigate(it) }
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "Navigation: $it")
|
||||
if (BuildConfig.DEBUG) {
|
||||
|
@ -51,7 +56,10 @@ abstract class NavigationFragment<BINDING : ViewBinding>(
|
|||
is Command.OpenSettings -> navigation.openSettings()
|
||||
is Command.OpenObject -> navigation.openDocument(command.id, command.editorSettings)
|
||||
is Command.OpenArchive -> navigation.openArchive(command.target)
|
||||
is Command.OpenObjectSet -> navigation.openObjectSet(command.target, command.isPopUpToDashboard)
|
||||
is Command.OpenObjectSet -> navigation.openObjectSet(
|
||||
command.target,
|
||||
command.isPopUpToDashboard
|
||||
)
|
||||
is Command.LaunchObjectSet -> navigation.launchObjectSet(command.target)
|
||||
is Command.LaunchDocument -> navigation.launchDocument(command.id)
|
||||
is Command.LaunchObjectFromSplash -> navigation.launchObjectFromSplash(command.target)
|
||||
|
@ -79,4 +87,4 @@ abstract class NavigationFragment<BINDING : ViewBinding>(
|
|||
else -> Timber.d("Nav command ignored: $command")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,12 +17,11 @@ import androidx.transition.TransitionSet
|
|||
import androidx.viewpager2.widget.ViewPager2
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_models.ObjectWrapper
|
||||
import com.anytypeio.anytype.core_ui.reactive.clicks
|
||||
import com.anytypeio.anytype.core_ui.reactive.click
|
||||
import com.anytypeio.anytype.core_utils.ext.argOrNull
|
||||
import com.anytypeio.anytype.core_utils.ext.cancel
|
||||
import com.anytypeio.anytype.core_utils.ext.gone
|
||||
import com.anytypeio.anytype.core_utils.ext.invisible
|
||||
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.ViewState
|
||||
|
@ -38,8 +37,6 @@ import com.anytypeio.anytype.ui.base.ViewStateFragment
|
|||
import com.anytypeio.anytype.ui.editor.EditorFragment
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
@ -442,51 +439,15 @@ class DashboardFragment :
|
|||
})
|
||||
}
|
||||
|
||||
binding.btnAddDoc
|
||||
.clicks()
|
||||
.onEach { vm.onAddNewDocumentClicked() }
|
||||
.launchIn(lifecycleScope)
|
||||
|
||||
binding.btnSearch
|
||||
.clicks()
|
||||
.onEach { vm.onPageSearchClicked() }
|
||||
.launchIn(lifecycleScope)
|
||||
|
||||
binding.btnMarketplace
|
||||
.clicks()
|
||||
.onEach { toast(getString(R.string.coming_soon)) }
|
||||
.launchIn(lifecycleScope)
|
||||
|
||||
binding.ivSettings
|
||||
.clicks()
|
||||
.throttleFirst()
|
||||
.onEach { vm.onSettingsClicked() }
|
||||
.launchIn(lifecycleScope)
|
||||
|
||||
binding.avatarContainer
|
||||
.clicks()
|
||||
.onEach { vm.onAvatarClicked() }
|
||||
.launchIn(lifecycleScope)
|
||||
|
||||
binding.tvCancel
|
||||
.clicks()
|
||||
.onEach { vm.onCancelSelectionClicked() }
|
||||
.launchIn(lifecycleScope)
|
||||
|
||||
binding.tvSelectAll
|
||||
.clicks()
|
||||
.onEach { vm.onSelectAllClicked() }
|
||||
.launchIn(lifecycleScope)
|
||||
|
||||
binding.tvRestore
|
||||
.clicks()
|
||||
.onEach { vm.onPutBackClicked() }
|
||||
.launchIn(lifecycleScope)
|
||||
|
||||
binding.tvDelete
|
||||
.clicks()
|
||||
.onEach { vm.onDeleteObjectsClicked() }
|
||||
.launchIn(lifecycleScope)
|
||||
click(binding.btnAddDoc) { vm.onAddNewDocumentClicked() }
|
||||
click(binding.btnSearch) { vm.onPageSearchClicked() }
|
||||
click(binding.btnMarketplace) { toast(getString(R.string.coming_soon)) }
|
||||
click(binding.ivSettings) { vm.onSettingsClicked() }
|
||||
click(binding.avatarContainer) { vm.onAvatarClicked() }
|
||||
click(binding.tvCancel) { vm.onCancelSelectionClicked() }
|
||||
click(binding.tvSelectAll) { vm.onSelectAllClicked() }
|
||||
click(binding.tvRestore) { vm.onPutBackClicked() }
|
||||
click(binding.tvDelete) { vm.onDeleteObjectsClicked() }
|
||||
}
|
||||
|
||||
override fun inflateBinding(
|
||||
|
|
|
@ -132,10 +132,10 @@ import com.anytypeio.anytype.ui.linking.LinkToObjectOrWebPagesFragment
|
|||
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.types.pickers.DraftObjectSelectTypeFragment
|
||||
import com.anytypeio.anytype.ui.objects.types.pickers.ObjectSelectTypeFragment
|
||||
import com.anytypeio.anytype.ui.objects.types.pickers.OnObjectSelectTypeAction
|
||||
import com.anytypeio.anytype.ui.objects.appearance.ObjectAppearanceSettingFragment
|
||||
import com.anytypeio.anytype.ui.relations.RelationAddBaseFragment.Companion.CTX_KEY
|
||||
import com.anytypeio.anytype.ui.relations.RelationAddResult
|
||||
import com.anytypeio.anytype.ui.relations.RelationAddToObjectBlockFragment
|
||||
|
@ -886,7 +886,7 @@ open class EditorFragment : NavigationFragment<FragmentEditorBinding>(R.layout.f
|
|||
is Command.OpenTextBlockIconPicker -> {
|
||||
TextBlockIconPickerFragment.new(
|
||||
context = ctx, blockId = command.block
|
||||
).show(childFragmentManager, null)
|
||||
).showChildFragment()
|
||||
}
|
||||
Command.OpenDocumentEmojiIconPicker -> {
|
||||
hideSoftInput()
|
||||
|
@ -901,7 +901,7 @@ open class EditorFragment : NavigationFragment<FragmentEditorBinding>(R.layout.f
|
|||
is Command.OpenBookmarkSetter -> {
|
||||
CreateBookmarkFragment.newInstance(
|
||||
target = command.target
|
||||
).show(childFragmentManager, null)
|
||||
).showChildFragment()
|
||||
}
|
||||
is Command.OpenGallery -> {
|
||||
pickerDelegate.openFilePicker(command.mimeType, null)
|
||||
|
@ -936,7 +936,7 @@ open class EditorFragment : NavigationFragment<FragmentEditorBinding>(R.layout.f
|
|||
isProfile = false,
|
||||
fromName = getFrom()
|
||||
)
|
||||
fr.show(childFragmentManager, null)
|
||||
fr.showChildFragment()
|
||||
}
|
||||
is Command.OpenProfileMenu -> {
|
||||
hideKeyboard()
|
||||
|
@ -963,7 +963,7 @@ open class EditorFragment : NavigationFragment<FragmentEditorBinding>(R.layout.f
|
|||
val fr = ObjectLayoutFragment.new(command.ctx).apply {
|
||||
onDismissListener = { vm.onLayoutDialogDismissed() }
|
||||
}
|
||||
fr.show(childFragmentManager, null)
|
||||
fr.showChildFragment()
|
||||
}
|
||||
is Command.OpenFullScreenImage -> {
|
||||
val screen = FullScreenPictureFragment.new(command.target, command.url).apply {
|
||||
|
@ -978,7 +978,7 @@ open class EditorFragment : NavigationFragment<FragmentEditorBinding>(R.layout.f
|
|||
}
|
||||
is Command.AlertDialog -> {
|
||||
if (childFragmentManager.findFragmentByTag(TAG_ALERT) == null) {
|
||||
AlertUpdateAppFragment().show(childFragmentManager, TAG_ALERT)
|
||||
AlertUpdateAppFragment().showChildFragment(TAG_ALERT)
|
||||
} else {
|
||||
// Do nothing
|
||||
}
|
||||
|
@ -988,7 +988,7 @@ open class EditorFragment : NavigationFragment<FragmentEditorBinding>(R.layout.f
|
|||
}
|
||||
is Command.Dialog.SelectLanguage -> {
|
||||
SelectProgrammingLanguageFragment.new(command.target)
|
||||
.show(childFragmentManager, null)
|
||||
.showChildFragment()
|
||||
}
|
||||
is Command.OpenObjectRelationScreen.RelationAdd -> {
|
||||
hideKeyboard()
|
||||
|
@ -998,7 +998,7 @@ open class EditorFragment : NavigationFragment<FragmentEditorBinding>(R.layout.f
|
|||
target = command.target,
|
||||
mode = RelationListFragment.MODE_ADD
|
||||
)
|
||||
.show(childFragmentManager, null)
|
||||
.showChildFragment()
|
||||
}
|
||||
is Command.OpenObjectRelationScreen.RelationList -> {
|
||||
hideKeyboard()
|
||||
|
@ -1023,7 +1023,7 @@ open class EditorFragment : NavigationFragment<FragmentEditorBinding>(R.layout.f
|
|||
targetObjectTypes = command.targetObjectTypes,
|
||||
isLocked = command.isLocked
|
||||
)
|
||||
fr.show(childFragmentManager, null)
|
||||
fr.showChildFragment()
|
||||
}
|
||||
is Command.OpenObjectRelationScreen.Value.Text -> {
|
||||
hideKeyboard()
|
||||
|
@ -1034,7 +1034,7 @@ open class EditorFragment : NavigationFragment<FragmentEditorBinding>(R.layout.f
|
|||
objectId = command.target,
|
||||
isLocked = command.isLocked
|
||||
)
|
||||
fr.show(childFragmentManager, null)
|
||||
fr.showChildFragment()
|
||||
}
|
||||
is Command.OpenObjectRelationScreen.Value.Date -> {
|
||||
hideKeyboard()
|
||||
|
@ -1044,7 +1044,7 @@ open class EditorFragment : NavigationFragment<FragmentEditorBinding>(R.layout.f
|
|||
relationId = command.relationId,
|
||||
relationKey = command.relationKey
|
||||
)
|
||||
fr.show(childFragmentManager, null)
|
||||
fr.showChildFragment()
|
||||
}
|
||||
Command.AddSlashWidgetTriggerToFocusedBlock -> {
|
||||
binding.recycler.addTextFromSelectedStart(text = "/")
|
||||
|
@ -1054,14 +1054,14 @@ open class EditorFragment : NavigationFragment<FragmentEditorBinding>(R.layout.f
|
|||
val fr = DraftObjectSelectTypeFragment.newInstance(
|
||||
excludeTypes = command.excludedTypes
|
||||
)
|
||||
fr.show(childFragmentManager, null)
|
||||
fr.showChildFragment()
|
||||
}
|
||||
is Command.OpenObjectSelectTypeScreen -> {
|
||||
hideKeyboard()
|
||||
val fr = ObjectSelectTypeFragment.newInstance(
|
||||
excludeTypes = command.excludedTypes
|
||||
)
|
||||
fr.show(childFragmentManager, null)
|
||||
fr.showChildFragment()
|
||||
}
|
||||
is Command.OpenMoveToScreen -> {
|
||||
jobs += lifecycleScope.launch {
|
||||
|
@ -1073,7 +1073,7 @@ open class EditorFragment : NavigationFragment<FragmentEditorBinding>(R.layout.f
|
|||
restorePosition = command.restorePosition,
|
||||
restoreBlock = command.restoreBlock
|
||||
)
|
||||
fr.show(childFragmentManager, null)
|
||||
fr.showChildFragment()
|
||||
}
|
||||
}
|
||||
is Command.OpenObjectSnackbar -> {
|
||||
|
@ -1099,7 +1099,7 @@ open class EditorFragment : NavigationFragment<FragmentEditorBinding>(R.layout.f
|
|||
position = command.position,
|
||||
ignore = vm.context
|
||||
)
|
||||
fr.show(childFragmentManager, null)
|
||||
fr.showChildFragment()
|
||||
}
|
||||
}
|
||||
is Command.AddMentionWidgetTriggerToFocusedBlock -> {
|
||||
|
@ -1125,7 +1125,7 @@ open class EditorFragment : NavigationFragment<FragmentEditorBinding>(R.layout.f
|
|||
rangeEnd = command.range.last,
|
||||
isWholeBlockMarkup = command.isWholeBlockMarkup
|
||||
)
|
||||
fr.show(childFragmentManager, null)
|
||||
fr.showChildFragment()
|
||||
}
|
||||
is Command.ShowKeyboard -> {
|
||||
binding.recycler.findFocus()?.focusAndShowKeyboard()
|
||||
|
@ -1144,7 +1144,7 @@ open class EditorFragment : NavigationFragment<FragmentEditorBinding>(R.layout.f
|
|||
ctx = command.ctx,
|
||||
block = command.block
|
||||
)
|
||||
fr.show(childFragmentManager, null)
|
||||
fr.showChildFragment()
|
||||
}
|
||||
is Command.ScrollToPosition -> {
|
||||
val lm = binding.recycler.layoutManager as LinearLayoutManager
|
||||
|
@ -1162,7 +1162,7 @@ open class EditorFragment : NavigationFragment<FragmentEditorBinding>(R.layout.f
|
|||
hideKeyboard()
|
||||
}
|
||||
}
|
||||
fr.show(childFragmentManager, null)
|
||||
fr.showChildFragment()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,11 +12,12 @@ import com.anytypeio.anytype.core_models.Id
|
|||
import com.anytypeio.anytype.core_ui.features.objects.ObjectActionAdapter
|
||||
import com.anytypeio.anytype.core_ui.layout.SpacingItemDecoration
|
||||
import com.anytypeio.anytype.core_ui.reactive.click
|
||||
import com.anytypeio.anytype.core_ui.reactive.proceed
|
||||
import com.anytypeio.anytype.core_utils.ext.arg
|
||||
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.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.objects.ObjectIcon
|
||||
|
@ -75,7 +76,7 @@ abstract class ObjectMenuBaseFragment :
|
|||
proceed(vm.actions) { actionAdapter.submitList(it) }
|
||||
proceed(vm.toasts) { toast(it) }
|
||||
proceed(vm.isDismissed) { isDismissed -> if (isDismissed) dismiss() }
|
||||
proceed(vm.commands) { command -> execute(command) }
|
||||
proceed(vm.commands.throttleFirst()) { command -> execute(command) }
|
||||
proceed(vm.options) { options -> renderOptions(options) }
|
||||
|
||||
super.onStart()
|
||||
|
@ -121,7 +122,7 @@ abstract class ObjectMenuBaseFragment :
|
|||
ObjectMenuViewModelBase.Command.OpenSetIcons -> openSetIcons()
|
||||
ObjectMenuViewModelBase.Command.OpenSetLayout -> toast(COMING_SOON_MSG)
|
||||
ObjectMenuViewModelBase.Command.OpenSetRelations -> toast(COMING_SOON_MSG)
|
||||
ObjectMenuViewModelBase.Command.OpenLinkToChooser -> openLinkChooser(command)
|
||||
ObjectMenuViewModelBase.Command.OpenLinkToChooser -> openLinkChooser()
|
||||
is ObjectMenuViewModelBase.Command.OpenSnackbar -> openSnackbar(command)
|
||||
is ObjectMenuViewModelBase.Command.ShareDebugTree -> shareFile(command.uri)
|
||||
}
|
||||
|
@ -178,7 +179,7 @@ abstract class ObjectMenuBaseFragment :
|
|||
}
|
||||
|
||||
|
||||
private fun openLinkChooser(command: ObjectMenuViewModelBase.Command) {
|
||||
private fun openLinkChooser() {
|
||||
val fr = MoveToFragment.new(
|
||||
ctx = ctx,
|
||||
blocks = emptyList(),
|
||||
|
|
|
@ -594,7 +594,7 @@ open class ObjectSetFragment :
|
|||
flow = RelationTextValueFragment.FLOW_DATAVIEW,
|
||||
relationKey = command.relationKey
|
||||
)
|
||||
fr.show(childFragmentManager, EMPTY_TAG)
|
||||
fr.showChildFragment(EMPTY_TAG)
|
||||
}
|
||||
is ObjectSetCommand.Modal.EditGridDateCell -> {
|
||||
//todo Relation as object, fix relationKey
|
||||
|
@ -605,7 +605,7 @@ open class ObjectSetFragment :
|
|||
flow = RelationDateValueFragment.FLOW_DATAVIEW,
|
||||
relationKey = ""
|
||||
)
|
||||
fr.show(childFragmentManager, EMPTY_TAG)
|
||||
fr.showChildFragment(EMPTY_TAG)
|
||||
}
|
||||
is ObjectSetCommand.Modal.EditRelationCell -> {
|
||||
findNavController().safeNavigate(
|
||||
|
@ -628,25 +628,25 @@ open class ObjectSetFragment :
|
|||
ctx = command.ctx,
|
||||
viewer = command.viewer
|
||||
)
|
||||
fr.show(childFragmentManager, EMPTY_TAG)
|
||||
fr.showChildFragment(EMPTY_TAG)
|
||||
}
|
||||
is ObjectSetCommand.Modal.CreateViewer -> {
|
||||
val fr = CreateDataViewViewerFragment.new(
|
||||
ctx = command.ctx,
|
||||
target = command.target
|
||||
)
|
||||
fr.show(childFragmentManager, EMPTY_TAG)
|
||||
fr.showChildFragment(EMPTY_TAG)
|
||||
}
|
||||
is ObjectSetCommand.Modal.EditDataViewViewer -> {
|
||||
val fr = EditDataViewViewerFragment.new(
|
||||
ctx = command.ctx,
|
||||
viewer = command.viewer
|
||||
)
|
||||
fr.show(childFragmentManager, EMPTY_TAG)
|
||||
fr.showChildFragment(EMPTY_TAG)
|
||||
}
|
||||
is ObjectSetCommand.Modal.ManageViewer -> {
|
||||
val fr = ManageViewerFragment.new(ctx = command.ctx, dataview = command.dataview)
|
||||
fr.show(childFragmentManager, EMPTY_TAG)
|
||||
fr.showChildFragment(EMPTY_TAG)
|
||||
}
|
||||
is ObjectSetCommand.Modal.OpenSettings -> {
|
||||
val fr = ObjectSetSettingsFragment.new(
|
||||
|
@ -654,7 +654,7 @@ open class ObjectSetFragment :
|
|||
dv = command.dv,
|
||||
viewer = command.viewer
|
||||
)
|
||||
fr.show(childFragmentManager, EMPTY_TAG)
|
||||
fr.showChildFragment(EMPTY_TAG)
|
||||
}
|
||||
is ObjectSetCommand.Modal.SetNameForCreatedObject -> {
|
||||
findNavController().safeNavigate(
|
||||
|
@ -712,11 +712,11 @@ open class ObjectSetFragment :
|
|||
val fr = ViewerFilterFragment.new(
|
||||
ctx = command.ctx
|
||||
)
|
||||
fr.show(childFragmentManager, EMPTY_TAG)
|
||||
fr.showChildFragment(EMPTY_TAG)
|
||||
}
|
||||
is ObjectSetCommand.Modal.ModifyViewerSorts -> {
|
||||
val fr = ViewerSortFragment.new(ctx)
|
||||
fr.show(childFragmentManager, EMPTY_TAG)
|
||||
fr.showChildFragment(EMPTY_TAG)
|
||||
}
|
||||
is ObjectSetCommand.Modal.OpenCoverActionMenu -> {
|
||||
findNavController().safeNavigate(
|
||||
|
@ -735,11 +735,11 @@ open class ObjectSetFragment :
|
|||
val fr = DataViewSelectSourceFragment.newInstance(
|
||||
selectedTypes = command.selectedTypes
|
||||
)
|
||||
fr.show(childFragmentManager, null)
|
||||
fr.showChildFragment()
|
||||
}
|
||||
is ObjectSetCommand.Modal.OpenEmptyDataViewSelectSourceScreen -> {
|
||||
val fr = EmptyDataViewSelectSourceFragment()
|
||||
fr.show(childFragmentManager, null)
|
||||
fr.showChildFragment()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ import androidx.compose.ui.platform.ViewCompositionStrategy
|
|||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.analytics.base.EventsDictionary
|
||||
import com.anytypeio.anytype.core_utils.ext.shareFile
|
||||
|
@ -39,11 +38,11 @@ class AccountAndDataFragment : BaseBottomSheetComposeFragment() {
|
|||
private val onKeychainPhraseClicked = {
|
||||
val bundle =
|
||||
bundleOf(KeychainPhraseDialog.ARG_SCREEN_TYPE to EventsDictionary.Type.screenSettings)
|
||||
findNavController().navigate(R.id.keychainDialog, bundle)
|
||||
safeNavigate(R.id.keychainDialog, bundle)
|
||||
}
|
||||
|
||||
private val onLogoutClicked = {
|
||||
findNavController().navigate(R.id.logoutWarningScreen)
|
||||
safeNavigate(R.id.logoutWarningScreen)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
|
@ -62,10 +61,10 @@ class AccountAndDataFragment : BaseBottomSheetComposeFragment() {
|
|||
MaterialTheme(typography = typography) {
|
||||
AccountAndDataScreen(
|
||||
onKeychainPhraseClicked = onKeychainPhraseClicked,
|
||||
onClearFileCachedClicked = { proceedWithClearFileCacheWarning() },
|
||||
onDeleteAccountClicked = { proceedWithAccountDeletion() },
|
||||
onClearFileCachedClicked = { throttle { proceedWithClearFileCacheWarning() } },
|
||||
onDeleteAccountClicked = { throttle { proceedWithAccountDeletion() } },
|
||||
onLogoutClicked = onLogoutClicked,
|
||||
onDebugSyncReportClicked = { vm.onDebugSyncReportClicked() },
|
||||
onDebugSyncReportClicked = { throttle { vm.onDebugSyncReportClicked() } },
|
||||
isLogoutInProgress = vm.isLoggingOut.collectAsState().value,
|
||||
isClearCacheInProgress = vm.isClearFileCacheInProgress.collectAsState().value,
|
||||
isDebugSyncReportInProgress = vm.isDebugSyncReportInProgress.collectAsState().value,
|
||||
|
|
|
@ -9,7 +9,6 @@ import androidx.compose.runtime.collectAsState
|
|||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.compose.ui.platform.ViewCompositionStrategy
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetComposeFragment
|
||||
import com.anytypeio.anytype.di.common.componentManager
|
||||
|
@ -25,7 +24,7 @@ class AppearanceFragment : BaseBottomSheetComposeFragment() {
|
|||
private val vm by viewModels<AppearanceViewModel> { factory }
|
||||
|
||||
private val onWallpaperClicked = {
|
||||
findNavController().navigate(R.id.wallpaperSetScreen)
|
||||
safeNavigate(R.id.wallpaperSetScreen)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
|
@ -39,9 +38,9 @@ class AppearanceFragment : BaseBottomSheetComposeFragment() {
|
|||
MaterialTheme(typography = typography) {
|
||||
AppearanceScreen(
|
||||
onWallpaperClicked = onWallpaperClicked,
|
||||
light = { vm.onLight() },
|
||||
dark = { vm.onDark() },
|
||||
system = { vm.onSystem() },
|
||||
light = { throttle { vm.onLight() } },
|
||||
dark = { throttle { vm.onDark() } },
|
||||
system = { throttle { vm.onSystem() } },
|
||||
selectedMode = vm.selectedTheme.collectAsState().value
|
||||
)
|
||||
}
|
||||
|
|
|
@ -12,17 +12,15 @@ import androidx.fragment.app.viewModels
|
|||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_utils.tools.FeatureToggles
|
||||
import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetComposeFragment
|
||||
import com.anytypeio.anytype.di.common.componentManager
|
||||
import com.anytypeio.anytype.presentation.settings.MainSettingsViewModel
|
||||
import com.anytypeio.anytype.presentation.settings.MainSettingsViewModel.Event
|
||||
import com.anytypeio.anytype.presentation.settings.MainSettingsViewModel.Command
|
||||
import com.anytypeio.anytype.presentation.settings.MainSettingsViewModel.Event
|
||||
import com.anytypeio.anytype.ui.settings.system.SettingsActivity
|
||||
import com.anytypeio.anytype.ui_settings.main.MainSettingScreen
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -90,16 +88,16 @@ class MainSettingFragment : BaseBottomSheetComposeFragment() {
|
|||
private fun processCommands(command: Command) {
|
||||
when (command) {
|
||||
Command.OpenAboutScreen -> {
|
||||
findNavController().navigate(R.id.actionOpenAboutAppScreen)
|
||||
safeNavigate(R.id.actionOpenAboutAppScreen)
|
||||
}
|
||||
Command.OpenAccountAndDataScreen -> {
|
||||
findNavController().navigate(R.id.actionOpenAccountAndDataScreen)
|
||||
safeNavigate(R.id.actionOpenAccountAndDataScreen)
|
||||
}
|
||||
Command.OpenAppearanceScreen -> {
|
||||
findNavController().navigate(R.id.actionOpenAppearanceScreen)
|
||||
safeNavigate(R.id.actionOpenAppearanceScreen)
|
||||
}
|
||||
Command.OpenPersonalizationScreen -> {
|
||||
findNavController().navigate(R.id.actionOpenPersonalizationScreen)
|
||||
safeNavigate(R.id.actionOpenPersonalizationScreen)
|
||||
}
|
||||
Command.OpenDebugScreen -> {
|
||||
startActivity(Intent(requireActivity(), SettingsActivity::class.java))
|
||||
|
|
|
@ -5,11 +5,10 @@ import android.view.LayoutInflater
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.anytypeio.anytype.core_models.Id
|
||||
import com.anytypeio.anytype.core_utils.ext.subscribe
|
||||
import com.anytypeio.anytype.core_utils.ext.toast
|
||||
import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetFragment
|
||||
import com.anytypeio.anytype.core_utils.ui.proceed
|
||||
import com.anytypeio.anytype.databinding.FragmentUserSettingsBinding
|
||||
import com.anytypeio.anytype.di.common.componentManager
|
||||
import com.anytypeio.anytype.presentation.settings.OtherSettingsViewModel
|
||||
|
@ -38,26 +37,23 @@ class OtherSettingsFragment : BaseBottomSheetFragment<FragmentUserSettingsBindin
|
|||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
with(lifecycleScope) {
|
||||
jobs += subscribe(vm.commands) { observe(it) }
|
||||
jobs += subscribe(vm.defaultObjectTypeName) { binding.objectType.text = it }
|
||||
}
|
||||
proceed(vm.commands) { observe(it) }
|
||||
proceed(vm.defaultObjectTypeName) { binding.objectType.text = it }
|
||||
}
|
||||
|
||||
private fun observe(command: OtherSettingsViewModel.Command) {
|
||||
when (command) {
|
||||
is OtherSettingsViewModel.Command.Exit -> dismiss()
|
||||
is OtherSettingsViewModel.Command.Exit -> throttle { dismiss() }
|
||||
is OtherSettingsViewModel.Command.NavigateToObjectTypesScreen -> {
|
||||
val fr = AppDefaultObjectTypeFragment.newInstance(
|
||||
AppDefaultObjectTypeFragment.newInstance(
|
||||
excludeTypes = command.excludeTypes
|
||||
)
|
||||
fr.show(childFragmentManager, null)
|
||||
).showChildFragment()
|
||||
}
|
||||
is OtherSettingsViewModel.Command.Toast -> toast(command.msg)
|
||||
is OtherSettingsViewModel.Command.ShowClearCacheAlert -> {
|
||||
val dialog = ClearCacheAlertFragment.new()
|
||||
dialog.onClearAccepted = { vm.proceedWithClearCache() }
|
||||
dialog.show(childFragmentManager, null)
|
||||
dialog.showChildFragment()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -127,12 +127,4 @@ fun BaseBottomSheetFragment<*>.click(
|
|||
.throttleFirst()
|
||||
.onEach { action() }
|
||||
.launchIn(lifecycleScope)
|
||||
}
|
||||
|
||||
fun <T> BaseFragment<*>.proceed(flow: Flow<T>, body: suspend (T) -> Unit) {
|
||||
jobs += flow.onEach { body(it) }.launchIn(lifecycleScope)
|
||||
}
|
||||
|
||||
fun <T> BaseBottomSheetFragment<*>.proceed(flow: Flow<T>, body: suspend (T) -> Unit) {
|
||||
jobs += flow.onEach { body(it) }.launchIn(lifecycleScope)
|
||||
}
|
|
@ -104,4 +104,5 @@ fun MutableList<Job>.cancel() {
|
|||
clear()
|
||||
}
|
||||
|
||||
const val DEFAULT_THROTTLE_DURATION = 1000L
|
||||
const val DEFAULT_THROTTLE_DURATION = 1000L
|
||||
const val LONG_THROTTLE_DURATION = 2000L
|
|
@ -2,13 +2,49 @@ package com.anytypeio.anytype.core_utils.ui
|
|||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.annotation.IdRes
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import com.anytypeio.anytype.core_utils.R
|
||||
import com.anytypeio.anytype.core_utils.ext.LONG_THROTTLE_DURATION
|
||||
import com.anytypeio.anytype.core_utils.ext.throttleFirst
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
abstract class BaseBottomSheetComposeFragment : BottomSheetDialogFragment() {
|
||||
|
||||
protected val jobs = mutableListOf<Job>()
|
||||
val jobs = mutableListOf<Job>()
|
||||
|
||||
private val currentNavigationId by lazy { getNavigationId() }
|
||||
private val throttleFlow = MutableSharedFlow<() -> Unit>(0)
|
||||
|
||||
protected fun safeNavigate(
|
||||
@IdRes id: Int,
|
||||
args: Bundle? = null
|
||||
) {
|
||||
jobs += this.lifecycleScope.launch {
|
||||
throttleFlow.emit {
|
||||
if (currentNavigationId == getNavigationId()) {
|
||||
findNavController().navigate(id, args)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected fun throttle(task: () -> Unit) {
|
||||
jobs += this.lifecycleScope.launch { throttleFlow.emit { task() } }
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
proceed(throttleFlow.throttleFirst(LONG_THROTTLE_DURATION)) { it() }
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
|
@ -35,4 +71,10 @@ abstract class BaseBottomSheetComposeFragment : BottomSheetDialogFragment() {
|
|||
|
||||
abstract fun injectDependencies()
|
||||
abstract fun releaseDependencies()
|
||||
}
|
||||
|
||||
fun Fragment.getNavigationId() = findNavController().currentDestination?.id
|
||||
|
||||
fun <T> BaseBottomSheetComposeFragment.proceed(flow: Flow<T>, body: suspend (T) -> Unit) {
|
||||
jobs += flow.onEach { body(it) }.launchIn(lifecycleScope)
|
||||
}
|
|
@ -5,11 +5,20 @@ import android.view.LayoutInflater
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.anytypeio.anytype.core_utils.R
|
||||
import com.anytypeio.anytype.core_utils.ext.LONG_THROTTLE_DURATION
|
||||
import com.anytypeio.anytype.core_utils.ext.throttleFirst
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import com.google.android.material.R.id.design_bottom_sheet as BOTTOM_SHEET_ID
|
||||
|
||||
abstract class BaseBottomSheetFragment<T : ViewBinding>(
|
||||
|
@ -21,6 +30,12 @@ abstract class BaseBottomSheetFragment<T : ViewBinding>(
|
|||
|
||||
val sheet: FrameLayout? get() = dialog?.findViewById(BOTTOM_SHEET_ID)
|
||||
|
||||
private val throttleFlow = MutableSharedFlow<() -> Unit>(0)
|
||||
|
||||
protected fun throttle(task: () -> Unit) {
|
||||
jobs += this.lifecycleScope.launch { throttleFlow.emit { task() } }
|
||||
}
|
||||
|
||||
val jobs = mutableListOf<Job>()
|
||||
|
||||
override fun onCreateView(
|
||||
|
@ -42,6 +57,11 @@ abstract class BaseBottomSheetFragment<T : ViewBinding>(
|
|||
injectDependencies()
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
proceed(throttleFlow.throttleFirst(LONG_THROTTLE_DURATION)) { it() }
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
jobs.apply {
|
||||
|
@ -50,6 +70,12 @@ abstract class BaseBottomSheetFragment<T : ViewBinding>(
|
|||
}
|
||||
}
|
||||
|
||||
protected fun DialogFragment.showChildFragment(tag: String? = null) {
|
||||
jobs += this@BaseBottomSheetFragment.lifecycleScope.launch {
|
||||
throttleFlow.emit { show(this@BaseBottomSheetFragment.childFragmentManager, tag) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
if (fragmentScope) releaseDependencies()
|
||||
|
@ -80,4 +106,8 @@ abstract class BaseBottomSheetFragment<T : ViewBinding>(
|
|||
}
|
||||
|
||||
protected abstract fun inflateBinding(inflater: LayoutInflater, container: ViewGroup?): T
|
||||
}
|
||||
|
||||
fun <T> BaseBottomSheetFragment<*>.proceed(flow: Flow<T>, body: suspend (T) -> Unit) {
|
||||
jobs += flow.onEach { body(it) }.launchIn(lifecycleScope)
|
||||
}
|
|
@ -8,11 +8,20 @@ import android.view.ViewGroup
|
|||
import androidx.annotation.LayoutRes
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.anytypeio.anytype.core_utils.BuildConfig
|
||||
import com.anytypeio.anytype.core_utils.ext.LONG_THROTTLE_DURATION
|
||||
import com.anytypeio.anytype.core_utils.ext.throttleFirst
|
||||
import com.anytypeio.anytype.core_utils.insets.RootViewDeferringInsetsCallback
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
abstract class BaseFragment<T : ViewBinding>(
|
||||
@LayoutRes private val layout: Int,
|
||||
|
@ -26,6 +35,7 @@ abstract class BaseFragment<T : ViewBinding>(
|
|||
val hasBinding get() = _binding != null
|
||||
|
||||
val jobs = mutableListOf<Job>()
|
||||
private val throttleFlow = MutableSharedFlow<() -> Unit>(0)
|
||||
|
||||
abstract fun injectDependencies()
|
||||
abstract fun releaseDependencies()
|
||||
|
@ -35,6 +45,15 @@ abstract class BaseFragment<T : ViewBinding>(
|
|||
injectDependencies()
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
proceed(throttleFlow.throttleFirst(LONG_THROTTLE_DURATION)) { it() }
|
||||
}
|
||||
|
||||
protected fun throttle(task: () -> Unit) {
|
||||
jobs += this.lifecycleScope.launch { throttleFlow.emit { task() } }
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
jobs.apply {
|
||||
|
@ -59,7 +78,9 @@ abstract class BaseFragment<T : ViewBinding>(
|
|||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
if (applyWindowRootInsets) { onApplyWindowRootInsets() }
|
||||
if (applyWindowRootInsets) {
|
||||
onApplyWindowRootInsets()
|
||||
}
|
||||
}
|
||||
|
||||
open fun onApplyWindowRootInsets() {
|
||||
|
@ -73,10 +94,20 @@ abstract class BaseFragment<T : ViewBinding>(
|
|||
}
|
||||
}
|
||||
|
||||
protected fun DialogFragment.showChildFragment(tag: String? = null) {
|
||||
jobs += this@BaseFragment.lifecycleScope.launch {
|
||||
throttleFlow.emit { show(this@BaseFragment.childFragmentManager, tag) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
}
|
||||
|
||||
protected abstract fun inflateBinding(inflater: LayoutInflater, container: ViewGroup?): T
|
||||
}
|
||||
|
||||
fun <T> BaseFragment<*>.proceed(flow: Flow<T>, body: suspend (T) -> Unit) {
|
||||
jobs += flow.onEach { body(it) }.launchIn(lifecycleScope)
|
||||
}
|
|
@ -910,7 +910,7 @@ class ObjectSetViewModel(
|
|||
}
|
||||
|
||||
fun onViewerSettingsClicked() {
|
||||
Timber.d("onViewerRelationsClicked, ")
|
||||
Timber.d("onViewerSettingsClicked, ")
|
||||
if (isRestrictionPresent(DataViewRestriction.RELATION)) {
|
||||
toast(NOT_ALLOWED)
|
||||
} else {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue