mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
DROID-2731 Merge branch 'refs/heads/main' into droid-2731-epic-release-7-new-vault-5
This commit is contained in:
commit
53f23b002c
33 changed files with 241 additions and 85 deletions
|
@ -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 {
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
11
core-ui/src/main/res/drawable/ic_arrow_top_end.xml
Normal file
11
core-ui/src/main/res/drawable/ic_arrow_top_end.xml
Normal 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>
|
|
@ -4,11 +4,7 @@
|
|||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M16.9047,7.8655L11.6709,17.2312L6.9697,12.53L8.0303,11.4693L11.3291,14.7681L15.5953,7.1338L16.9047,7.8655Z"
|
||||
android:fillColor="@color/glyph_active"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M12,20.5C16.6944,20.5 20.5,16.6944 20.5,12C20.5,7.3056 16.6944,3.5 12,3.5C7.3056,3.5 3.5,7.3056 3.5,12C3.5,16.6944 7.3056,20.5 12,20.5ZM12,22C17.5228,22 22,17.5228 22,12C22,6.4771 17.5228,2 12,2C6.4771,2 2,6.4771 2,12C2,17.5228 6.4771,22 12,22Z"
|
||||
android:pathData="M7.5,4.5H16.5C18.157,4.5 19.5,5.843 19.5,7.5V16.5C19.5,18.157 18.157,19.5 16.5,19.5H7.5C5.843,19.5 4.5,18.157 4.5,16.5V7.5C4.5,5.843 5.843,4.5 7.5,4.5ZM3,7.5C3,5.015 5.015,3 7.5,3H16.5C18.985,3 21,5.015 21,7.5V16.5C21,18.985 18.985,21 16.5,21H7.5C5.015,21 3,18.985 3,16.5V7.5ZM11.671,17.232L16.905,7.866L15.595,7.134L11.329,14.768L8.03,11.47L6.97,12.53L11.671,17.232Z"
|
||||
android:fillColor="@color/glyph_active"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
|
|
|
@ -4,11 +4,11 @@
|
|||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12,20.5C16.694,20.5 20.5,16.694 20.5,12C20.5,7.306 16.694,3.5 12,3.5C7.306,3.5 3.5,7.306 3.5,12C3.5,16.694 7.306,20.5 12,20.5ZM12,22C17.523,22 22,17.523 22,12C22,6.477 17.523,2 12,2C6.477,2 2,6.477 2,12C2,17.523 6.477,22 12,22Z"
|
||||
android:pathData="M5.47,14.47C5.763,14.177 6.237,14.177 6.53,14.47L12,19.939L17.47,14.47C17.763,14.177 18.237,14.177 18.53,14.47C18.823,14.763 18.823,15.237 18.53,15.53L12,22.061L5.47,15.53C5.177,15.237 5.177,14.763 5.47,14.47Z"
|
||||
android:fillColor="@color/glyph_active"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M7.47,10.47C7.763,10.177 8.237,10.177 8.53,10.47L12,13.939L15.47,10.47C15.763,10.177 16.237,10.177 16.53,10.47C16.823,10.763 16.823,11.237 16.53,11.53L12,16.061L7.47,11.53C7.177,11.237 7.177,10.763 7.47,10.47Z"
|
||||
android:pathData="M5.47,9.53C5.763,9.823 6.237,9.823 6.53,9.53L12,4.061L17.47,9.53C17.763,9.823 18.237,9.823 18.53,9.53C18.823,9.237 18.823,8.763 18.53,8.47L12,1.939L5.47,8.47C5.177,8.763 5.177,9.237 5.47,9.53Z"
|
||||
android:fillColor="@color/glyph_active"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
|
|
|
@ -15,9 +15,6 @@
|
|||
<path
|
||||
android:pathData="M19.5,6m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"
|
||||
android:fillColor="#B6B6B6"/>
|
||||
<path
|
||||
android:pathData="M19.5,12m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"
|
||||
android:fillColor="#B6B6B6"/>
|
||||
<path
|
||||
android:pathData="M19.5,18m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"
|
||||
android:fillColor="#B6B6B6"/>
|
||||
|
|
21
core-ui/src/main/res/drawable/ic_sync_limitations.xml
Normal file
21
core-ui/src/main/res/drawable/ic_sync_limitations.xml
Normal 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>
|
9
core-ui/src/main/res/drawable/ic_sync_slow_10.xml
Normal file
9
core-ui/src/main/res/drawable/ic_sync_slow_10.xml
Normal 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>
|
|
@ -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))
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -2,15 +2,26 @@ package com.anytypeio.anytype.domain.account
|
|||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.filterIsInstance
|
||||
|
||||
interface AwaitAccountStartManager {
|
||||
fun isStarted(): Flow<Boolean>
|
||||
fun setIsStarted(isStarted: Boolean)
|
||||
|
||||
fun state(): Flow<State>
|
||||
fun setState(state: State)
|
||||
fun awaitStart(): Flow<State.Started>
|
||||
fun awaitStopped(): Flow<State.Stopped>
|
||||
|
||||
object Default: AwaitAccountStartManager {
|
||||
private val isStarted = MutableStateFlow(false)
|
||||
override fun isStarted(): Flow<Boolean> = isStarted
|
||||
override fun setIsStarted(isStarted: Boolean) {
|
||||
this.isStarted.value = isStarted
|
||||
}
|
||||
private val state = MutableStateFlow<State>(State.Init)
|
||||
override fun state(): Flow<State> = state
|
||||
override fun setState(state: State) { this.state.value = state }
|
||||
override fun awaitStart(): Flow<State.Started> = state.filterIsInstance()
|
||||
override fun awaitStopped(): Flow<State.Stopped> = state.filterIsInstance()
|
||||
}
|
||||
|
||||
sealed class State {
|
||||
data object Init : State()
|
||||
data object Started : State()
|
||||
data object Stopped : State()
|
||||
}
|
||||
}
|
|
@ -47,7 +47,7 @@ open class CreateAccount @Inject constructor(
|
|||
}
|
||||
configStorage.set(setup.config)
|
||||
spaceManager.set(setup.config.space)
|
||||
awaitAccountStartManager.setIsStarted(true)
|
||||
awaitAccountStartManager.setState(AwaitAccountStartManager.State.Started)
|
||||
return setup.account
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ import com.anytypeio.anytype.core_models.Id
|
|||
import com.anytypeio.anytype.domain.account.AwaitAccountStartManager
|
||||
import com.anytypeio.anytype.domain.auth.repo.AuthRepository
|
||||
import com.anytypeio.anytype.domain.base.BaseUseCase
|
||||
import com.anytypeio.anytype.domain.base.Either
|
||||
import com.anytypeio.anytype.domain.config.ConfigStorage
|
||||
import com.anytypeio.anytype.domain.config.UserSettingsRepository
|
||||
import com.anytypeio.anytype.domain.device.PathProvider
|
||||
|
@ -57,7 +56,7 @@ class LaunchAccount @Inject constructor(
|
|||
} else {
|
||||
spaceManager.set(setup.config.space)
|
||||
}
|
||||
awaitAccountStartManager.setIsStarted(true)
|
||||
awaitAccountStartManager.setState(AwaitAccountStartManager.State.Started)
|
||||
setup.config.analytics
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ class Logout @Inject constructor(
|
|||
user.clear()
|
||||
config.clear()
|
||||
spaceManager.clear()
|
||||
awaitAccountStartManager.setIsStarted(false)
|
||||
awaitAccountStartManager.setState(AwaitAccountStartManager.State.Stopped)
|
||||
}
|
||||
|
||||
class Params(
|
||||
|
|
|
@ -61,7 +61,7 @@ class ResumeAccount @Inject constructor(
|
|||
}
|
||||
setup.account.id
|
||||
}
|
||||
awaitAccountStartManager.setIsStarted(true)
|
||||
awaitAccountStartManager.setState(AwaitAccountStartManager.State.Started)
|
||||
result
|
||||
}
|
||||
}
|
|
@ -9,7 +9,6 @@ import com.anytypeio.anytype.domain.base.BaseUseCase
|
|||
import com.anytypeio.anytype.domain.config.ConfigStorage
|
||||
import com.anytypeio.anytype.domain.platform.MetricsProvider
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
/**
|
||||
* Use case for selecting user account.
|
||||
|
@ -42,7 +41,7 @@ class SelectAccount @Inject constructor(
|
|||
setCurrentAccount(setup.account.id)
|
||||
}
|
||||
configStorage.set(config = setup.config)
|
||||
awaitAccountStartManager.setIsStarted(true)
|
||||
awaitAccountStartManager.setState(AwaitAccountStartManager.State.Started)
|
||||
StartAccountResult(setup.config.analytics, setup.status)
|
||||
}
|
||||
|
||||
|
|
|
@ -43,11 +43,18 @@ interface ActiveSpaceMemberSubscriptionContainer {
|
|||
|
||||
init {
|
||||
scope.launch {
|
||||
awaitAccountStart.isStarted().collect { isStarted ->
|
||||
if (isStarted)
|
||||
start()
|
||||
else
|
||||
stop()
|
||||
awaitAccountStart.state().collect { state ->
|
||||
when(state) {
|
||||
AwaitAccountStartManager.State.Init -> {
|
||||
// Do nothing
|
||||
}
|
||||
AwaitAccountStartManager.State.Started -> {
|
||||
start()
|
||||
}
|
||||
AwaitAccountStartManager.State.Stopped -> {
|
||||
stop()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,11 +51,18 @@ interface SpaceViewSubscriptionContainer {
|
|||
|
||||
init {
|
||||
scope.launch {
|
||||
awaitAccountStart.isStarted().collect { isStarted ->
|
||||
if (isStarted)
|
||||
start()
|
||||
else
|
||||
stop()
|
||||
awaitAccountStart.state().collect { state ->
|
||||
when(state) {
|
||||
AwaitAccountStartManager.State.Init -> {
|
||||
// Do nothing
|
||||
}
|
||||
AwaitAccountStartManager.State.Started -> {
|
||||
start()
|
||||
}
|
||||
AwaitAccountStartManager.State.Stopped -> {
|
||||
stop()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -127,7 +127,7 @@ class CreateAccountTest {
|
|||
verifyNoMoreInteractions(repo)
|
||||
verify(configStorage, times(1)).set(setup.config)
|
||||
verify(spaceManager, times(1)).set(setup.config.space)
|
||||
verify(awaitAccountStartManager, times(1)).setIsStarted(true)
|
||||
verify(awaitAccountStartManager, times(1)).setState(AwaitAccountStartManager.State.Started)
|
||||
}
|
||||
|
||||
private fun stubMetricsProvider(version: String, platform: String) {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -112,7 +112,7 @@ class MembershipProviderTest {
|
|||
}
|
||||
whenever(localeProvider.language()).thenReturn("en")
|
||||
|
||||
awaitAccountStartManager.setIsStarted(true)
|
||||
awaitAccountStartManager.setState(AwaitAccountStartManager.State.Started)
|
||||
val membershipProviderFlow = provider.status().testIn(backgroundScope)
|
||||
val membershipProviderFlow1 = provider.status().testIn(backgroundScope)
|
||||
val membershipProviderFlow2 = provider.activeTier().testIn(backgroundScope)
|
||||
|
|
|
@ -7413,6 +7413,10 @@ class EditorViewModel(
|
|||
fun onSyncWidgetDismiss() {
|
||||
syncStatusWidget.value = SyncStatusWidgetState.Hidden
|
||||
}
|
||||
|
||||
fun onUpdateAppClick() {
|
||||
dispatch(command = Command.OpenAppStore)
|
||||
}
|
||||
//endregion
|
||||
|
||||
data class Params(
|
||||
|
|
|
@ -57,6 +57,8 @@ sealed class Command {
|
|||
val url: Url
|
||||
) : Command()
|
||||
|
||||
data object OpenAppStore: Command()
|
||||
|
||||
data class OpenDocumentMenu(
|
||||
val ctx: Id,
|
||||
val space: Id,
|
||||
|
|
|
@ -12,7 +12,6 @@ import com.anytypeio.anytype.core_models.NotificationPayload
|
|||
import com.anytypeio.anytype.core_models.NotificationStatus
|
||||
import com.anytypeio.anytype.core_models.Wallpaper
|
||||
import com.anytypeio.anytype.core_models.exceptions.NeedToUpdateApplicationException
|
||||
import com.anytypeio.anytype.core_models.membership.TierId
|
||||
import com.anytypeio.anytype.core_utils.ext.cancel
|
||||
import com.anytypeio.anytype.domain.account.AwaitAccountStartManager
|
||||
import com.anytypeio.anytype.domain.account.InterceptAccountStatus
|
||||
|
@ -41,7 +40,6 @@ import kotlinx.coroutines.Job
|
|||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.take
|
||||
import kotlinx.coroutines.launch
|
||||
|
@ -306,16 +304,11 @@ class MainViewModel(
|
|||
deepLinkJobs.cancel()
|
||||
deepLinkJobs += viewModelScope.launch {
|
||||
awaitAccountStartManager
|
||||
.isStarted()
|
||||
.filter { isStarted -> isStarted }
|
||||
.awaitStart()
|
||||
.onEach { delay(NEW_DEEP_LINK_DELAY) }
|
||||
.take(1)
|
||||
.collect { isStarted ->
|
||||
if (isStarted) {
|
||||
proceedWithNewDeepLink(deeplink)
|
||||
} else {
|
||||
Timber.w("Account not started")
|
||||
}
|
||||
.collect {
|
||||
proceedWithNewDeepLink(deeplink)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,15 +2,15 @@ package com.anytypeio.anytype.presentation.membership.provider
|
|||
|
||||
import com.anytypeio.anytype.core_models.Command
|
||||
import com.anytypeio.anytype.core_models.membership.Membership
|
||||
import com.anytypeio.anytype.core_models.membership.MembershipStatus
|
||||
import com.anytypeio.anytype.core_models.membership.MembershipTierData
|
||||
import com.anytypeio.anytype.core_models.membership.TierId
|
||||
import com.anytypeio.anytype.domain.account.AwaitAccountStartManager
|
||||
import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers
|
||||
import com.anytypeio.anytype.domain.block.repo.BlockRepository
|
||||
import com.anytypeio.anytype.domain.misc.DateProvider
|
||||
import com.anytypeio.anytype.domain.misc.LocaleProvider
|
||||
import com.anytypeio.anytype.domain.workspace.MembershipChannel
|
||||
import com.anytypeio.anytype.core_models.membership.MembershipStatus
|
||||
import com.anytypeio.anytype.core_models.membership.TierId
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
|
@ -38,13 +38,13 @@ interface MembershipProvider {
|
|||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
override fun status(): Flow<MembershipStatus> {
|
||||
return awaitAccountStartManager.isStarted().flatMapLatest { isStarted ->
|
||||
if (isStarted) {
|
||||
buildStatusFlow(
|
||||
return awaitAccountStartManager.state().flatMapLatest { state ->
|
||||
when(state) {
|
||||
AwaitAccountStartManager.State.Started -> buildStatusFlow(
|
||||
initial = proceedWithGettingMembership()
|
||||
)
|
||||
} else {
|
||||
emptyFlow()
|
||||
AwaitAccountStartManager.State.Init -> emptyFlow()
|
||||
AwaitAccountStartManager.State.Stopped -> emptyFlow()
|
||||
}
|
||||
}.catch { e -> Timber.e(e) }
|
||||
.flowOn(dispatchers.io)
|
||||
|
@ -52,13 +52,13 @@ interface MembershipProvider {
|
|||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
override fun activeTier(): Flow<TierId> {
|
||||
return awaitAccountStartManager.isStarted().flatMapLatest { isStarted ->
|
||||
if (isStarted) {
|
||||
buildActiveTierFlow(
|
||||
return awaitAccountStartManager.state().flatMapLatest { state ->
|
||||
when(state) {
|
||||
AwaitAccountStartManager.State.Started -> buildActiveTierFlow(
|
||||
initial = proceedWithGettingMembership()
|
||||
)
|
||||
} else {
|
||||
emptyFlow()
|
||||
AwaitAccountStartManager.State.Init -> emptyFlow()
|
||||
AwaitAccountStartManager.State.Stopped -> emptyFlow()
|
||||
}
|
||||
}.catch { e -> Timber.e(e) }
|
||||
.flowOn(dispatchers.io)
|
||||
|
|
|
@ -42,8 +42,11 @@ interface NotificationsProvider {
|
|||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
private fun observe(): Flow<List<Notification.Event>> {
|
||||
return awaitAccountStartManager.isStarted().flatMapLatest { isStarted ->
|
||||
if (isStarted) notificationsChannel.observe() else emptyFlow()
|
||||
return awaitAccountStartManager.state().flatMapLatest { state ->
|
||||
if (state is AwaitAccountStartManager.State.Started)
|
||||
notificationsChannel.observe()
|
||||
else
|
||||
emptyFlow()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -2865,6 +2865,10 @@ class ObjectSetViewModel(
|
|||
fun onSyncWidgetDismiss() {
|
||||
syncStatusWidget.value = SyncStatusWidgetState.Hidden
|
||||
}
|
||||
|
||||
fun onUpdateAppClick() {
|
||||
dispatch(command = ObjectSetCommand.Intent.OpenAppStore)
|
||||
}
|
||||
//endregion
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -51,7 +51,6 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
|||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.onSubscription
|
||||
import kotlinx.coroutines.flow.shareIn
|
||||
|
@ -105,8 +104,7 @@ class AddToAnytypeViewModel(
|
|||
}
|
||||
viewModelScope.launch {
|
||||
awaitAccountStartManager
|
||||
.isStarted()
|
||||
.filter { isStarted -> isStarted }
|
||||
.awaitStart()
|
||||
.flatMapLatest {
|
||||
combine(
|
||||
spaces,
|
||||
|
|
|
@ -139,6 +139,7 @@ class CollectionCreateAndAddObjectTest: ObjectSetViewModelTestSetup() {
|
|||
|
||||
@Test
|
||||
fun `create pre-populated record in Collection`() = runTest {
|
||||
|
||||
// SETUP
|
||||
|
||||
val filters = mockObjectCollection.filters
|
||||
|
@ -169,13 +170,19 @@ class CollectionCreateAndAddObjectTest: ObjectSetViewModelTestSetup() {
|
|||
)
|
||||
|
||||
// TESTING
|
||||
|
||||
proceedWithStartingViewModel()
|
||||
|
||||
|
||||
// ASSERT DATA VIEW STATE
|
||||
|
||||
viewModel.currentViewer.test {
|
||||
val first = awaitItem()
|
||||
|
||||
assertIs<DataViewViewState.Init>(first)
|
||||
|
||||
advanceUntilIdle()
|
||||
|
||||
cancelAndIgnoreRemainingEvents()
|
||||
|
||||
advanceUntilIdle()
|
||||
|
@ -191,7 +198,10 @@ class CollectionCreateAndAddObjectTest: ObjectSetViewModelTestSetup() {
|
|||
|
||||
val spaceId = SpaceId(mockObjectCollection.spaceId)
|
||||
val command = Command.CreateObject(
|
||||
prefilled = mapOf(filters[0].relation to filters[0].value, filters[1].relation to filters[1].value),
|
||||
prefilled = mapOf(
|
||||
filters[0].relation to filters[0].value,
|
||||
filters[1].relation to filters[1].value
|
||||
),
|
||||
internalFlags = listOf(InternalFlags.ShouldSelectTemplate),
|
||||
space = spaceId,
|
||||
typeKey = TypeKey(newObjectTypeKey),
|
||||
|
|
|
@ -64,7 +64,7 @@ class NotificationsProviderTest {
|
|||
// Arrange
|
||||
val eventList = listOf(testEvent)
|
||||
whenever(notificationsChannel.observe()).thenReturn(flowOf(eventList))
|
||||
awaitAccountStartManager.setIsStarted(true)
|
||||
awaitAccountStartManager.setState(AwaitAccountStartManager.State.Started)
|
||||
|
||||
// Act
|
||||
notificationsProvider.events.test {
|
||||
|
@ -78,8 +78,8 @@ class NotificationsProviderTest {
|
|||
// Arrange
|
||||
val eventList = listOf(testEvent)
|
||||
whenever(notificationsChannel.observe()).thenReturn(flowOf(eventList))
|
||||
awaitAccountStartManager.setIsStarted(true) // Start and then stop
|
||||
awaitAccountStartManager.setIsStarted(false)
|
||||
awaitAccountStartManager.setState(AwaitAccountStartManager.State.Started) // Start and then stop
|
||||
awaitAccountStartManager.setState(AwaitAccountStartManager.State.Stopped)
|
||||
|
||||
// Act & Assert
|
||||
notificationsProvider.events.test(timeout = Duration.parse("2s")) {
|
||||
|
@ -94,7 +94,7 @@ class NotificationsProviderTest {
|
|||
// Arrange
|
||||
val eventFlow = flowOf(listOf(testEvent))
|
||||
whenever(notificationsChannel.observe()).thenReturn(eventFlow)
|
||||
awaitAccountStartManager.setIsStarted(true)
|
||||
awaitAccountStartManager.setState(AwaitAccountStartManager.State.Started)
|
||||
|
||||
// Act & Assert
|
||||
notificationsProvider.events.test(timeout = Duration.parse("2s")) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue