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

DROID-2780 Sync status | Need update status (#1530)

This commit is contained in:
Konstantin Ivanov 2024-09-04 10:31:04 +02:00 committed by GitHub
parent c6fb926fe2
commit e064007837
Signed by: github
GPG key ID: B5690EEEBB952194
14 changed files with 153 additions and 17 deletions

View file

@ -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<FragmentEditorBinding>(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<FragmentEditorBinding>(R.layout.f
toast("Couldn't parse url: ${command.url}")
}
}
is Command.OpenAppStore -> {
startMarketPageOrWeb()
}
is Command.OpenDocumentMenu -> {
hideKeyboard()
runCatching {

View file

@ -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()
}
}
}

View file

@ -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)
}

View file

@ -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)
}
}
}

View file

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="12dp"
android:height="12dp"
android:viewportWidth="12"
android:viewportHeight="12">
<path
android:pathData="M3.5,1H11M11,1V8.5M11,1L1,11"
android:strokeWidth="1.25"
android:fillColor="#00000000"
android:strokeColor="@color/glyph_active"/>
</vector>

View file

@ -0,0 +1,21 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="48dp"
android:viewportWidth="48"
android:viewportHeight="48">
<path
android:pathData="M24,0L24,0A24,24 0,0 1,48 24L48,24A24,24 0,0 1,24 48L24,48A24,24 0,0 1,0 24L0,24A24,24 0,0 1,24 0z"
android:fillColor="@color/palette_light_yellow"/>
<path
android:pathData="M20.5,16L20.5,16A0.5,0.5 0,0 1,21 16.5L21,19.5A0.5,0.5 0,0 1,20.5 20L20.5,20A0.5,0.5 0,0 1,20 19.5L20,16.5A0.5,0.5 0,0 1,20.5 16z"
android:fillColor="@color/palette_dark_yellow"/>
<path
android:pathData="M27.5,16L27.5,16A0.5,0.5 0,0 1,28 16.5L28,19.5A0.5,0.5 0,0 1,27.5 20L27.5,20A0.5,0.5 0,0 1,27 19.5L27,16.5A0.5,0.5 0,0 1,27.5 16z"
android:fillColor="@color/palette_dark_yellow"/>
<path
android:strokeWidth="1"
android:pathData="M16,29H32"
android:fillColor="#00000000"
android:strokeColor="@color/palette_dark_yellow"
android:strokeLineCap="round"/>
</vector>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="10dp"
android:height="10dp"
android:viewportWidth="10"
android:viewportHeight="10">
<path
android:pathData="M5,5m-5,0a5,5 0,1 1,10 0a5,5 0,1 1,-10 0"
android:fillColor="@color/palette_system_yellow"/>
</vector>

View file

@ -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 <T> CoroutineScope.subscribe(flow: Flow<T>, body: suspend (T) -> Unit): Job
flow.cancellable().onEach { body(it) }.launchIn(this)
fun <T> Fragment.subscribe(flow: Flow<T>, body: (T) -> Unit): Job =
flow.cancellable().onEach { body(it) }.launchIn(viewLifecycleOwner.lifecycleScope)
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))
)
)
}
}

View file

@ -1,3 +1,5 @@
<resources>
<string name="app_name">CoreUtils</string>
<string name="download_anytype_url" translatable="false">https://download.anytype.io</string>
<string name="play_market_url" translatable="false">market://details?id=</string>
</resources>

View file

@ -916,7 +916,6 @@
<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">It\'s time to update</string>
<string name="download_anytype_url" translatable="false">https://download.anytype.io</string>
<string name="space_type_default">Entry</string>
<string name="space_type_default_space">Entry space</string>
@ -1734,6 +1733,7 @@ Please provide specific details of your needs here.</string>
</plurals>
<string name="sync_status_anytype_network_connecting">Network Connecting...</string>
<string name="sync_status_anytype_network_no_connecting">No connection</string>
<string name="sync_status_anytype_sync_slow">Sync might be slow. Update the app.</string>
<string name="sync_status_storage_limit_exceed">Storage limit reached</string>
<string name="sync_status_incompatible_version">Incompatible version</string>

View file

@ -7413,6 +7413,10 @@ class EditorViewModel(
fun onSyncWidgetDismiss() {
syncStatusWidget.value = SyncStatusWidgetState.Hidden
}
fun onUpdateAppClick() {
dispatch(command = Command.OpenAppStore)
}
//endregion
data class Params(

View file

@ -57,6 +57,8 @@ sealed class Command {
val url: Url
) : Command()
data object OpenAppStore: Command()
data class OpenDocumentMenu(
val ctx: Id,
val space: Id,

View file

@ -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()

View file

@ -2865,6 +2865,10 @@ class ObjectSetViewModel(
fun onSyncWidgetDismiss() {
syncStatusWidget.value = SyncStatusWidgetState.Hidden
}
fun onUpdateAppClick() {
dispatch(command = ObjectSetCommand.Intent.OpenAppStore)
}
//endregion
companion object {