diff --git a/app/src/main/java/com/anytypeio/anytype/ui/editor/EditorFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/editor/EditorFragment.kt index de1178aa0d..bb8e391717 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/editor/EditorFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/editor/EditorFragment.kt @@ -99,6 +99,7 @@ import com.anytypeio.anytype.core_utils.ext.lastDecorator import com.anytypeio.anytype.core_utils.ext.safeNavigate import com.anytypeio.anytype.core_utils.ext.screen import com.anytypeio.anytype.core_utils.ext.show +import com.anytypeio.anytype.core_utils.ext.startMarketPageOrWeb import com.anytypeio.anytype.core_utils.ext.subscribe import com.anytypeio.anytype.core_utils.ext.syncTranslationWithImeVisibility import com.anytypeio.anytype.core_utils.ext.throttleFirst @@ -745,7 +746,8 @@ open class EditorFragment : NavigationFragment(R.layout.f SpaceSyncStatusScreen( uiState = vm.syncStatusWidget.collectAsStateWithLifecycle().value, onDismiss = vm::onSyncWidgetDismiss, - scope = lifecycleScope + scope = lifecycleScope, + onUpdateAppClick = vm::onUpdateAppClick ) } } @@ -949,6 +951,9 @@ open class EditorFragment : NavigationFragment(R.layout.f toast("Couldn't parse url: ${command.url}") } } + is Command.OpenAppStore -> { + startMarketPageOrWeb() + } is Command.OpenDocumentMenu -> { hideKeyboard() runCatching { diff --git a/app/src/main/java/com/anytypeio/anytype/ui/sets/ObjectSetFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/sets/ObjectSetFragment.kt index 60eb0b3763..86bf0f6c85 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/sets/ObjectSetFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/sets/ObjectSetFragment.kt @@ -78,6 +78,7 @@ import com.anytypeio.anytype.core_utils.ext.hideKeyboard import com.anytypeio.anytype.core_utils.ext.hideSoftInput import com.anytypeio.anytype.core_utils.ext.invisible import com.anytypeio.anytype.core_utils.ext.safeNavigate +import com.anytypeio.anytype.core_utils.ext.startMarketPageOrWeb import com.anytypeio.anytype.core_utils.ext.subscribe import com.anytypeio.anytype.core_utils.ext.syncFocusWithImeVisibility import com.anytypeio.anytype.core_utils.ext.syncTranslationWithImeVisibility @@ -452,7 +453,8 @@ open class ObjectSetFragment : SpaceSyncStatusScreen( uiState = vm.syncStatusWidget.collectAsStateWithLifecycle().value, onDismiss = vm::onSyncWidgetDismiss, - scope = lifecycleScope + scope = lifecycleScope, + onUpdateAppClick = vm::onUpdateAppClick ) } } @@ -1228,6 +1230,9 @@ open class ObjectSetFragment : getString(R.string.multiplayer_read_only_access_error) ) } + ObjectSetCommand.Intent.OpenAppStore -> { + startMarketPageOrWeb() + } } } diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/syncstatus/SpaceSyncStatusScreen.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/syncstatus/SpaceSyncStatusScreen.kt index b61e8791d3..82947729be 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/syncstatus/SpaceSyncStatusScreen.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/syncstatus/SpaceSyncStatusScreen.kt @@ -4,7 +4,9 @@ import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.slideInVertically import androidx.compose.animation.slideOutVertically import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.Row @@ -46,6 +48,7 @@ import com.anytypeio.anytype.core_models.multiplayer.SpaceSyncStatus import com.anytypeio.anytype.core_models.multiplayer.SpaceSyncUpdate import com.anytypeio.anytype.core_ui.R import com.anytypeio.anytype.core_ui.foundation.Divider +import com.anytypeio.anytype.core_ui.foundation.noRippleClickable import com.anytypeio.anytype.core_ui.views.BodyRegular import com.anytypeio.anytype.core_ui.views.Relations3 import com.anytypeio.anytype.core_ui.views.Title2 @@ -60,7 +63,8 @@ import kotlinx.coroutines.launch fun SpaceSyncStatusScreen( uiState: SyncStatusWidgetState, onDismiss: () -> Unit, - scope: CoroutineScope + scope: CoroutineScope, + onUpdateAppClick: () -> Unit ) { val isVisible = uiState is SyncStatusWidgetState.Success || uiState is SyncStatusWidgetState.Error @@ -112,7 +116,8 @@ fun SpaceSyncStatusScreen( SyncStatusWidgetState.Hidden -> LoadingState() is SyncStatusWidgetState.Success -> SuccessState( spaceSyncUpdate = uiState.spaceSyncUpdate, - p2pStatus = uiState.p2PStatusUpdate + p2pStatus = uiState.p2PStatusUpdate, + onUpdateAppClick = onUpdateAppClick ) } } @@ -145,9 +150,13 @@ private fun ColumnScope.ErrorState() { } @Composable -private fun SuccessState(spaceSyncUpdate: SpaceSyncUpdate, p2pStatus: P2PStatusUpdate) { +private fun SuccessState( + spaceSyncUpdate: SpaceSyncUpdate, + p2pStatus: P2PStatusUpdate, + onUpdateAppClick: () -> Unit +) { if (spaceSyncUpdate is SpaceSyncUpdate.Update) { - SpaceSyncStatusItem(spaceSyncUpdate) + SpaceSyncStatusItem(spaceSyncUpdate, onUpdateAppClick) Divider() } if (p2pStatus is P2PStatusUpdate.Update) { @@ -197,7 +206,8 @@ private fun P2PStatusItem( @Composable private fun SpaceSyncStatusItem( - spaceSyncUpdate: SpaceSyncUpdate.Update + spaceSyncUpdate: SpaceSyncUpdate.Update, + onUpdateAppClick: () -> Unit = {} ) { val networkCardSettings = getNetworkCardSettings( syncStatus = spaceSyncUpdate.status, @@ -205,15 +215,21 @@ private fun SpaceSyncStatusItem( error = spaceSyncUpdate.error, syncingObjectsCounter = spaceSyncUpdate.syncingObjectsCounter ) - Row( + Box( modifier = Modifier .fillMaxWidth() .height(72.dp) - .padding(horizontal = 16.dp), - verticalAlignment = Alignment.CenterVertically + .noRippleClickable { + if (spaceSyncUpdate.status == SpaceSyncStatus.NETWORK_UPDATE_NEEDED) { + onUpdateAppClick() + } + } ) { Image( - modifier = Modifier.wrapContentSize(), + modifier = Modifier + .wrapContentSize() + .padding(start = 16.dp) + .align(Alignment.CenterStart), painter = networkCardSettings.icon, contentDescription = "dfas", alpha = networkCardSettings.alpha @@ -221,7 +237,8 @@ private fun SpaceSyncStatusItem( Column( modifier = Modifier .fillMaxWidth() - .padding(start = 12.dp) + .padding(start = 76.dp) + .align(Alignment.CenterStart) ) { Text( text = networkCardSettings.mainText, @@ -236,6 +253,16 @@ private fun SpaceSyncStatusItem( ) } } + if (spaceSyncUpdate.status == SpaceSyncStatus.NETWORK_UPDATE_NEEDED) { + Image( + modifier = Modifier + .padding(end = 20.dp) + .wrapContentSize() + .align(Alignment.CenterEnd), + painter = painterResource(id = R.drawable.ic_arrow_top_end), + contentDescription = "update app icon" + ) + } } } @@ -318,7 +345,11 @@ private fun getNetworkCardSettings( ) } SpaceSyncStatus.NETWORK_UPDATE_NEEDED -> { - TODO() + CardSettings( + icon = painterResource(R.drawable.ic_sync_limitations), + mainText = stringResource(id = R.string.sync_status_anytype_network), + secondaryText = stringResource(id = R.string.sync_status_anytype_sync_slow) + ) } } @@ -362,7 +393,13 @@ private fun getNetworkCardSettings( secondaryText = stringResource(id = R.string.sync_status_anytype_network_no_connecting) ) } - SpaceSyncStatus.NETWORK_UPDATE_NEEDED -> TODO() + SpaceSyncStatus.NETWORK_UPDATE_NEEDED -> { + CardSettings( + icon = painterResource(R.drawable.ic_sync_limitations), + mainText = stringResource(id = R.string.sync_status_self_host), + secondaryText = stringResource(id = R.string.sync_status_anytype_sync_slow) + ) + } } } SpaceSyncNetwork.LOCAL_ONLY -> { @@ -540,4 +577,17 @@ fun SpaceSyncStatusPreview12() { spaceId = "1" ) P2PStatusItem(p2pStatus = p2pStatus) +} + +@Preview(name = "AnytypeNetworkNeedUpdate", showBackground = true) +@Composable +fun SpaceSyncStatusPreview13() { + val spaceSyncUpdate = SpaceSyncUpdate.Update( + id = "1", + status = SpaceSyncStatus.NETWORK_UPDATE_NEEDED, + network = SpaceSyncNetwork.ANYTYPE, + error = SpaceSyncError.NULL, + syncingObjectsCounter = 0 + ) + SpaceSyncStatusItem(spaceSyncUpdate = spaceSyncUpdate) } \ No newline at end of file diff --git a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/StatusBadgeWidget.kt b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/StatusBadgeWidget.kt index c1f6c5f084..e56b1db2a6 100644 --- a/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/StatusBadgeWidget.kt +++ b/core-ui/src/main/java/com/anytypeio/anytype/core_ui/widgets/StatusBadgeWidget.kt @@ -52,7 +52,8 @@ class StatusBadgeWidget @JvmOverloads constructor( setImageResource(R.drawable.ic_sync_grey_10) } SpaceSyncStatus.NETWORK_UPDATE_NEEDED -> { - // TODO + visible() + setImageResource(R.drawable.ic_sync_slow_10) } } } diff --git a/core-ui/src/main/res/drawable/ic_arrow_top_end.xml b/core-ui/src/main/res/drawable/ic_arrow_top_end.xml new file mode 100644 index 0000000000..debef8774a --- /dev/null +++ b/core-ui/src/main/res/drawable/ic_arrow_top_end.xml @@ -0,0 +1,11 @@ + + + diff --git a/core-ui/src/main/res/drawable/ic_sync_limitations.xml b/core-ui/src/main/res/drawable/ic_sync_limitations.xml new file mode 100644 index 0000000000..93ca0cae0c --- /dev/null +++ b/core-ui/src/main/res/drawable/ic_sync_limitations.xml @@ -0,0 +1,21 @@ + + + + + + diff --git a/core-ui/src/main/res/drawable/ic_sync_slow_10.xml b/core-ui/src/main/res/drawable/ic_sync_slow_10.xml new file mode 100644 index 0000000000..9354df754d --- /dev/null +++ b/core-ui/src/main/res/drawable/ic_sync_slow_10.xml @@ -0,0 +1,9 @@ + + + diff --git a/core-utils/src/main/java/com/anytypeio/anytype/core_utils/ext/FragmentExtensions.kt b/core-utils/src/main/java/com/anytypeio/anytype/core_utils/ext/FragmentExtensions.kt index d13ae4f65e..ad2b7962a5 100644 --- a/core-utils/src/main/java/com/anytypeio/anytype/core_utils/ext/FragmentExtensions.kt +++ b/core-utils/src/main/java/com/anytypeio/anytype/core_utils/ext/FragmentExtensions.kt @@ -1,8 +1,11 @@ package com.anytypeio.anytype.core_utils.ext +import android.content.Intent +import android.net.Uri import android.os.Parcelable import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope +import com.anytypeio.anytype.core_utils.R import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.flow.Flow @@ -54,4 +57,22 @@ fun CoroutineScope.subscribe(flow: Flow, body: suspend (T) -> Unit): Job flow.cancellable().onEach { body(it) }.launchIn(this) fun Fragment.subscribe(flow: Flow, body: (T) -> Unit): Job = - flow.cancellable().onEach { body(it) }.launchIn(viewLifecycleOwner.lifecycleScope) \ No newline at end of file + flow.cancellable().onEach { body(it) }.launchIn(viewLifecycleOwner.lifecycleScope) + +fun Fragment.startMarketPageOrWeb() { + runCatching { + startActivity( + Intent( + Intent.ACTION_VIEW, + Uri.parse("${getString(R.string.play_market_url)}${context?.packageName}") + ) + ) + }.onFailure { + startActivity( + Intent( + Intent.ACTION_VIEW, + Uri.parse(getString(R.string.download_anytype_url)) + ) + ) + } +} \ No newline at end of file diff --git a/core-utils/src/main/res/values/strings.xml b/core-utils/src/main/res/values/strings.xml index e5e23fd62e..6ea8409a6d 100644 --- a/core-utils/src/main/res/values/strings.xml +++ b/core-utils/src/main/res/values/strings.xml @@ -1,3 +1,5 @@ CoreUtils + https://download.anytype.io + market://details?id= diff --git a/localization/src/main/res/values/strings.xml b/localization/src/main/res/values/strings.xml index 1c4c445f2d..4e87dfd3e2 100644 --- a/localization/src/main/res/values/strings.xml +++ b/localization/src/main/res/values/strings.xml @@ -916,7 +916,6 @@ 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. It\'s time to update - https://download.anytype.io Entry Entry space @@ -1734,6 +1733,7 @@ Please provide specific details of your needs here. Network Connecting... No connection + Sync might be slow. Update the app. Storage limit reached Incompatible version diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/EditorViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/EditorViewModel.kt index b179513b46..79bf82bff6 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/EditorViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/EditorViewModel.kt @@ -7413,6 +7413,10 @@ class EditorViewModel( fun onSyncWidgetDismiss() { syncStatusWidget.value = SyncStatusWidgetState.Hidden } + + fun onUpdateAppClick() { + dispatch(command = Command.OpenAppStore) + } //endregion data class Params( diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/Command.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/Command.kt index d17e99b7c3..a3dee935fc 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/Command.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/editor/editor/Command.kt @@ -57,6 +57,8 @@ sealed class Command { val url: Url ) : Command() + data object OpenAppStore: Command() + data class OpenDocumentMenu( val ctx: Id, val space: Id, diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetCommand.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetCommand.kt index 16e0c7afd7..a40d6875fa 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetCommand.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetCommand.kt @@ -115,6 +115,7 @@ sealed class ObjectSetCommand { data class GoTo(val url: String) : Intent() data class MailTo(val email: String) : Intent() data class Call(val phone: String) : Intent() + data object OpenAppStore : Intent() } data object ShowOnlyAccessError : ObjectSetCommand() diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetViewModel.kt index 0fe1b62975..e923c8ae4c 100644 --- a/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetViewModel.kt +++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/sets/ObjectSetViewModel.kt @@ -2865,6 +2865,10 @@ class ObjectSetViewModel( fun onSyncWidgetDismiss() { syncStatusWidget.value = SyncStatusWidgetState.Hidden } + + fun onUpdateAppClick() { + dispatch(command = ObjectSetCommand.Intent.OpenAppStore) + } //endregion companion object {