Skip to content

Commit

Permalink
feat: show sync retry state for internal build #WPB-11198 (#3505)
Browse files Browse the repository at this point in the history
  • Loading branch information
damian-kaczmarek authored Oct 22, 2024
1 parent 90262c3 commit 562a406
Show file tree
Hide file tree
Showing 7 changed files with 177 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,19 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.IntSize
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import com.wire.android.BuildConfig
import com.wire.android.R
import com.wire.android.ui.theme.ThemeOption
import com.wire.android.ui.theme.WireTheme
Expand All @@ -52,6 +58,7 @@ import com.wire.android.ui.theme.wireDimensions
import com.wire.android.ui.theme.wireTypography
import com.wire.android.util.ui.PreviewMultipleThemes
import com.wire.kalium.logic.data.id.ConversationId
import com.wire.kalium.network.NetworkState

@Composable
fun CommonTopAppBar(
Expand All @@ -65,6 +72,7 @@ fun CommonTopAppBar(
Column(modifier = modifier) {
ConnectivityStatusBar(
themeOption = themeOption,
networkState = commonTopAppBarState.networkState,
connectivityInfo = commonTopAppBarState.connectivityState,
onReturnToCallClick = onReturnToCallClick,
onReturnToIncomingCallClick = onReturnToIncomingCallClick,
Expand All @@ -79,7 +87,10 @@ fun getBackgroundColor(connectivityInfo: ConnectivityUIState): Color {
is ConnectivityUIState.EstablishedCall,
is ConnectivityUIState.IncomingCall,
is ConnectivityUIState.OutgoingCall -> MaterialTheme.wireColorScheme.positive
ConnectivityUIState.Connecting, ConnectivityUIState.WaitingConnection -> MaterialTheme.wireColorScheme.primary

is ConnectivityUIState.WaitingConnection,
ConnectivityUIState.Connecting -> MaterialTheme.wireColorScheme.primary

ConnectivityUIState.None -> MaterialTheme.wireColorScheme.background
}
}
Expand All @@ -88,6 +99,7 @@ fun getBackgroundColor(connectivityInfo: ConnectivityUIState): Color {
private fun ConnectivityStatusBar(
themeOption: ThemeOption,
connectivityInfo: ConnectivityUIState,
networkState: NetworkState,
onReturnToCallClick: (ConnectivityUIState.EstablishedCall) -> Unit,
onReturnToIncomingCallClick: (ConnectivityUIState.IncomingCall) -> Unit,
onReturnToOutgoingCallClick: (ConnectivityUIState.OutgoingCall) -> Unit
Expand Down Expand Up @@ -119,14 +131,23 @@ private fun ConnectivityStatusBar(
.background(backgroundColor)
.run {
when (connectivityInfo) {
is ConnectivityUIState.EstablishedCall ->
clickable(onClick = { onReturnToCallClick(connectivityInfo) })
is ConnectivityUIState.EstablishedCall -> clickable(onClick = {
onReturnToCallClick(
connectivityInfo
)
})

is ConnectivityUIState.IncomingCall ->
clickable(onClick = { onReturnToIncomingCallClick(connectivityInfo) })
is ConnectivityUIState.IncomingCall -> clickable(onClick = {
onReturnToIncomingCallClick(
connectivityInfo
)
})

is ConnectivityUIState.OutgoingCall ->
clickable(onClick = { onReturnToOutgoingCallClick(connectivityInfo) })
is ConnectivityUIState.OutgoingCall -> clickable(onClick = {
onReturnToOutgoingCallClick(
connectivityInfo
)
})

else -> this
}
Expand Down Expand Up @@ -158,18 +179,63 @@ private fun ConnectivityStatusBar(
MaterialTheme.wireColorScheme.onPrimary
)

ConnectivityUIState.WaitingConnection ->
StatusLabel(
R.string.connectivity_status_bar_waiting_for_network,
MaterialTheme.wireColorScheme.onPrimary
)
is ConnectivityUIState.WaitingConnection -> {
val color = MaterialTheme.wireColorScheme.onPrimary
val waitingStatus: @Composable () -> Unit = {
StatusLabel(
stringResource = R.string.connectivity_status_bar_waiting_for_network,
color
)
}

if (!BuildConfig.PRIVATE_BUILD) {
waitingStatus()
return@Column
}

WaitingStatusLabelInternal(connectivityInfo, networkState, waitingStatus)
}

ConnectivityUIState.None -> {}
}
}
}
}

@Composable
private fun WaitingStatusLabelInternal(
connectivityInfo: ConnectivityUIState.WaitingConnection,
networkState: NetworkState,
waitingStatus: @Composable () -> Unit,
) {
assert(BuildConfig.PRIVATE_BUILD) { "This composable should only be used in the internal versions" }

val cause = connectivityInfo.cause?.javaClass?.simpleName ?: "null"
val delay = connectivityInfo.retryDelay ?: "null"
var fontSize by remember { mutableStateOf(1f) }

Column(
horizontalAlignment = Alignment.CenterHorizontally
) {
waitingStatus()
Text(
text = "Cause: $cause Delay: $delay, Net: $networkState",
style = MaterialTheme.wireTypography.title03.copy(
fontSize = MaterialTheme.wireTypography.title03.fontSize * fontSize,
color = MaterialTheme.wireColorScheme.onPrimary,
),
onTextLayout = {
// This is used to make sure the text fits in the available space
// so no needed information is cut off. It introduces a small delay in the text
// rendering but it is not important as this code is only used in the debug version
if (it.hasVisualOverflow) {
fontSize *= 0.9f
}
},
)
}
}

@Composable
private fun OngoingCallContent(isMuted: Boolean) {
Row {
Expand Down Expand Up @@ -208,11 +274,23 @@ private fun OutgoingCallContent(conversationName: String?) {
private fun StatusLabel(
stringResource: Int,
color: Color = MaterialTheme.wireColorScheme.onPrimary
) {
StatusLabel(
string = stringResource(id = stringResource),
color = color,
)
}

@Composable
private fun StatusLabel(
string: String,
color: Color = MaterialTheme.wireColorScheme.onPrimary
) {
Text(
text = stringResource(id = stringResource).uppercase(),
text = string.uppercase(),
color = color,
style = MaterialTheme.wireTypography.title03,
textAlign = TextAlign.Center,
)
}

Expand Down Expand Up @@ -294,7 +372,32 @@ fun PreviewCommonTopAppBar_ConnectivityCallNotMuted() =
fun PreviewCommonTopAppBar_ConnectivityConnecting() =
PreviewCommonTopAppBar(ConnectivityUIState.Connecting)

@PreviewMultipleThemes
@Composable
fun PreviewCommonTopAppBar_ConnectivityWaitingConnection() =
PreviewCommonTopAppBar(ConnectivityUIState.WaitingConnection(null, null))

@PreviewMultipleThemes
@Composable
fun PreviewCommonTopAppBar_ConnectivityNone() =
PreviewCommonTopAppBar(ConnectivityUIState.None)

@PreviewMultipleThemes
@Composable
fun PreviewCommonTopAppBar_ConnectivityIncomingCall() =
PreviewCommonTopAppBar(
ConnectivityUIState.IncomingCall(
ConversationId("what", "ever"),
"callerName"
)
)

@PreviewMultipleThemes
@Composable
fun PreviewCommonTopAppBar_ConnectivityOutgoingCall() =
PreviewCommonTopAppBar(
ConnectivityUIState.OutgoingCall(
ConversationId("what", "ever"),
"conversationName"
)
)
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
*/
package com.wire.android.ui.common.topappbar

import com.wire.kalium.network.NetworkState

data class CommonTopAppBarState(
val connectivityState: ConnectivityUIState = ConnectivityUIState.None,
val networkState: NetworkState = NetworkState.NotConnected,
)
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,10 @@ class CommonTopAppBarViewModel @Inject constructor(
coreLogic.sessionScope(userId) {
observeSyncState().map {
when (it) {
is SyncState.Failed, SyncState.Waiting -> Connectivity.WAITING_CONNECTION
SyncState.GatheringPendingEvents, SyncState.SlowSync -> Connectivity.CONNECTING
SyncState.Live -> Connectivity.CONNECTED
SyncState.Waiting -> Connectivity.WaitingConnection(null, null)
is SyncState.Failed -> Connectivity.WaitingConnection(it.cause, it.retryDelay)
SyncState.GatheringPendingEvents, SyncState.SlowSync -> Connectivity.Connecting
SyncState.Live -> Connectivity.Connected
}
}
}
Expand Down Expand Up @@ -117,6 +118,9 @@ class CommonTopAppBarViewModel @Inject constructor(
state = state.copy(connectivityState = connectivityUIState)
}
}
coreLogic.networkStateObserver.observeNetworkState().collectLatest {
state = state.copy(networkState = it)
}
}
}

Expand All @@ -129,20 +133,38 @@ class CommonTopAppBarViewModel @Inject constructor(
val canDisplayConnectivityIssues = currentScreen !is CurrentScreen.AuthRelated

if (activeCall != null) {
return if (activeCall.status == CallStatus.INCOMING) {
ConnectivityUIState.IncomingCall(activeCall.conversationId, activeCall.callerName)
} else if (activeCall.status == CallStatus.STARTED) {
ConnectivityUIState.OutgoingCall(activeCall.conversationId, activeCall.conversationName)
} else {
ConnectivityUIState.EstablishedCall(activeCall.conversationId, activeCall.isMuted)
return when (activeCall.status) {
CallStatus.INCOMING -> {
ConnectivityUIState.IncomingCall(
activeCall.conversationId,
activeCall.callerName
)
}

CallStatus.STARTED -> {
ConnectivityUIState.OutgoingCall(
activeCall.conversationId,
activeCall.conversationName
)
}

else -> {
ConnectivityUIState.EstablishedCall(
activeCall.conversationId,
activeCall.isMuted
)
}
}
}

return if (canDisplayConnectivityIssues) {
when (connectivity) {
Connectivity.WAITING_CONNECTION -> ConnectivityUIState.WaitingConnection
Connectivity.CONNECTING -> ConnectivityUIState.Connecting
Connectivity.CONNECTED -> ConnectivityUIState.None
Connectivity.Connecting -> ConnectivityUIState.Connecting
Connectivity.Connected -> ConnectivityUIState.None
is Connectivity.WaitingConnection -> ConnectivityUIState.WaitingConnection(
connectivity.cause,
connectivity.retryDelay,
)
}
} else {
ConnectivityUIState.None
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@

package com.wire.android.ui.common.topappbar

enum class Connectivity {
WAITING_CONNECTION, CONNECTING, CONNECTED
import com.wire.kalium.logic.CoreFailure
import kotlin.time.Duration

sealed interface Connectivity {
data class WaitingConnection(val cause: CoreFailure?, val retryDelay: Duration?) : Connectivity
data object Connecting : Connectivity
data object Connected : Connectivity
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@
package com.wire.android.ui.common.topappbar

import androidx.compose.runtime.Stable
import com.wire.kalium.logic.CoreFailure
import com.wire.kalium.logic.data.id.ConversationId
import kotlin.time.Duration

@Stable
sealed interface ConnectivityUIState {
data object Connecting : ConnectivityUIState

data object WaitingConnection : ConnectivityUIState
data class WaitingConnection(val cause: CoreFailure?, val retryDelay: Duration?) : ConnectivityUIState

data object None : ConnectivityUIState

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ import com.wire.kalium.logic.feature.call.usecase.ObserveEstablishedCallsUseCase
import com.wire.kalium.logic.feature.call.usecase.ObserveOutgoingCallUseCase
import com.wire.kalium.logic.feature.session.CurrentSessionResult
import com.wire.kalium.logic.sync.ObserveSyncStateUseCase
import com.wire.kalium.network.NetworkState
import com.wire.kalium.network.NetworkStateObserver
import io.mockk.MockKAnnotations
import io.mockk.coEvery
import io.mockk.every
Expand Down Expand Up @@ -264,6 +266,9 @@ class CommonTopAppBarViewModelTest {
@MockK
private lateinit var globalKaliumScope: GlobalKaliumScope

@MockK
private lateinit var networkStateObserver: NetworkStateObserver

init {
MockKAnnotations.init(this)
every {
Expand Down Expand Up @@ -294,6 +299,14 @@ class CommonTopAppBarViewModelTest {
coreLogic.getGlobalScope()
} returns globalKaliumScope

every {
coreLogic.networkStateObserver
} returns networkStateObserver

every {
networkStateObserver.observeNetworkState()
} returns MutableStateFlow(NetworkState.ConnectedWithInternet)

every {
globalKaliumScope.session.currentSessionFlow()
} returns emptyFlow()
Expand Down

0 comments on commit 562a406

Please sign in to comment.