Skip to content

Commit

Permalink
Merge remote-tracking branch 'refs/remotes/origin/develop' into fix/n…
Browse files Browse the repository at this point in the history
…on-paginated-conversations-not-loading
  • Loading branch information
saleniuk committed Dec 16, 2024
2 parents e67aff9 + 7a53935 commit 1a14d1a
Show file tree
Hide file tree
Showing 9 changed files with 106 additions and 72 deletions.
18 changes: 8 additions & 10 deletions app/src/main/kotlin/com/wire/android/ui/WireActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -517,16 +517,14 @@ class WireActivity : AppCompatActivity() {
)
CustomBackendDialog(
viewModel.globalAppState,
viewModel::dismissCustomBackendDialog
) {
viewModel.customBackendDialogProceedButtonClicked {
navigate(
NavigationCommand(
WelcomeScreenDestination
)
)
}
}
viewModel::dismissCustomBackendDialog,
onConfirm = {
viewModel.customBackendDialogProceedButtonClicked {
navigate(NavigationCommand(WelcomeScreenDestination))
}
},
onTryAgain = viewModel::onCustomServerConfig
)
MaxAccountDialog(
shouldShow = viewModel.globalAppState.maxAccountDialog,
onConfirm = {
Expand Down
13 changes: 8 additions & 5 deletions app/src/main/kotlin/com/wire/android/ui/WireActivityDialogs.kt
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ import com.wire.android.ui.common.button.WireButtonState
import com.wire.android.ui.common.button.WireSecondaryButton
import com.wire.android.ui.common.dialogs.CustomServerDetailsDialog
import com.wire.android.ui.common.dialogs.CustomServerDetailsDialogState
import com.wire.android.ui.common.dialogs.CustomServerInvalidJsonDialog
import com.wire.android.ui.common.dialogs.CustomServerInvalidJsonDialogState
import com.wire.android.ui.common.dialogs.CustomServerNoNetworkDialog
import com.wire.android.ui.common.dialogs.CustomServerNoNetworkDialogState
import com.wire.android.ui.common.dialogs.MaxAccountAllowedDialogContent
import com.wire.android.ui.common.dimensions
import com.wire.android.ui.common.wireDialogPropertiesBuilder
Expand Down Expand Up @@ -244,7 +244,8 @@ fun JoinConversationDialog(
fun CustomBackendDialog(
globalAppState: GlobalAppState,
onDismiss: () -> Unit,
onConfirm: () -> Unit
onConfirm: () -> Unit,
onTryAgain: (String) -> Unit
) {
when (globalAppState.customBackendDialog) {
is CustomServerDetailsDialogState -> {
Expand All @@ -255,8 +256,9 @@ fun CustomBackendDialog(
)
}

is CustomServerInvalidJsonDialogState -> {
CustomServerInvalidJsonDialog(
is CustomServerNoNetworkDialogState -> {
CustomServerNoNetworkDialog(
onTryAgain = { onTryAgain(globalAppState.customBackendDialog.customServerUrl) },
onDismiss = onDismiss
)
}
Expand Down Expand Up @@ -581,6 +583,7 @@ fun PreviewCustomBackendDialog() {
)
),
{},
{},
{}
)
}
Expand Down
21 changes: 12 additions & 9 deletions app/src/main/kotlin/com/wire/android/ui/WireActivityViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import com.wire.android.services.ServicesManager
import com.wire.android.ui.authentication.devices.model.displayName
import com.wire.android.ui.common.dialogs.CustomServerDetailsDialogState
import com.wire.android.ui.common.dialogs.CustomServerDialogState
import com.wire.android.ui.common.dialogs.CustomServerInvalidJsonDialogState
import com.wire.android.ui.common.dialogs.CustomServerNoNetworkDialogState
import com.wire.android.ui.joinConversation.JoinConversationViaCodeState
import com.wire.android.ui.theme.ThemeOption
import com.wire.android.util.CurrentScreen
Expand Down Expand Up @@ -320,7 +320,7 @@ class WireActivityViewModel @Inject constructor(
when (val result = deepLinkProcessor.get().invoke(intent?.data, isSharingIntent)) {
DeepLinkResult.AuthorizationNeeded -> onAuthorizationNeeded()
is DeepLinkResult.SSOLogin -> onSSOLogin(result)
is DeepLinkResult.CustomServerConfig -> onCustomServerConfig(result)
is DeepLinkResult.CustomServerConfig -> onCustomServerConfig(result.url)
is DeepLinkResult.Failure.OngoingCall -> onCannotLoginDuringACall()
is DeepLinkResult.Failure.Unknown -> appLogger.e("unknown deeplink failure")
is DeepLinkResult.JoinConversation -> onConversationInviteDeepLink(
Expand Down Expand Up @@ -429,13 +429,16 @@ class WireActivityViewModel @Inject constructor(
}
}

private suspend fun onCustomServerConfig(result: DeepLinkResult.CustomServerConfig) {
val customBackendDialogData = loadServerConfig(result.url)?.let { serverLinks ->
CustomServerDetailsDialogState(serverLinks = serverLinks)
} ?: CustomServerInvalidJsonDialogState
globalAppState = globalAppState.copy(
customBackendDialog = customBackendDialogData
)
fun onCustomServerConfig(customServerUrl: String) {
viewModelScope.launch(dispatchers.io()) {
val customBackendDialogData = loadServerConfig(customServerUrl)
?.let { serverLinks -> CustomServerDetailsDialogState(serverLinks = serverLinks) }
?: CustomServerNoNetworkDialogState(customServerUrl)

globalAppState = globalAppState.copy(
customBackendDialog = customBackendDialogData
)
}
}

private suspend fun onConversationInviteDeepLink(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,29 +28,40 @@ import com.wire.android.ui.theme.WireTheme
import com.wire.android.util.ui.PreviewMultipleThemes

@Composable
internal fun CustomServerInvalidJsonDialog(
internal fun CustomServerNoNetworkDialog(
onTryAgain: () -> Unit,
onDismiss: () -> Unit
) {
WireDialog(
title = stringResource(R.string.custom_backend_invalid_deeplink_data_title),
text = stringResource(R.string.custom_backend_invalid_deeplink_data_body),
title = stringResource(R.string.custom_backend_error_title),
text = stringResource(R.string.custom_backend_error_no_internet_connection_body),
onDismiss = onDismiss,
buttonsHorizontalAlignment = false,
optionButton1Properties = WireDialogButtonProperties(
onClick = onDismiss,
text = stringResource(id = R.string.label_ok),
onClick = {
onTryAgain()
onDismiss()
},
text = stringResource(id = R.string.custom_backend_error_no_internet_connection_try_again),
type = WireDialogButtonType.Primary,
state =
WireButtonState.Default
state = WireButtonState.Default
),
optionButton2Properties = WireDialogButtonProperties(
onClick = onDismiss,
text = stringResource(id = R.string.label_cancel),
type = WireDialogButtonType.Secondary,
state = WireButtonState.Default
)
)
}

data object CustomServerInvalidJsonDialogState : CustomServerDialogState()
data class CustomServerNoNetworkDialogState(val customServerUrl: String) : CustomServerDialogState()

@PreviewMultipleThemes
@Composable
fun PreviewCustomServerInvalidJsonDialog() = WireTheme {
CustomServerInvalidJsonDialog(
onDismiss = { }
fun PreviewCustomServerNoNetworkDialog() = WireTheme {
CustomServerNoNetworkDialog(
onTryAgain = {},
onDismiss = {}
)
}
3 changes: 1 addition & 2 deletions app/src/main/res/values-hu/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1133,8 +1133,7 @@ Ez a beállítás az összes beszélgetésre érvényes ezen az eszközön.</str
<string name="custom_backend_dialog_body_backend_accounts">Fiókok URL:</string>
<string name="custom_backend_dialog_body_backend_website">Honlap URL:</string>
<string name="custom_backend_dialog_body_backend_websocket">Kiszolgáló WSURL:</string>
<string name="custom_backend_invalid_deeplink_data_title">Hiba történt</string>
<string name="custom_backend_invalid_deeplink_data_body">A saját kiszolgálóra történő átirányítás nem volt lehetséges, mivel a JSON fájl érvénytelen beállítást tartalmazott.\n\nLépjen kapcsolatba a rendszergazdával, vagy ellenőrizze a mélylinket, ami ide vezette.</string>
<string name="custom_backend_error_title">Hiba történt</string>
<string name="label_fetching_your_messages">Új üzenetek lekérdezése</string>
<string name="label_text_copied">Szöveg a vágólapra másolva</string>
<string name="label_logs_option_title">Naplók</string>
Expand Down
3 changes: 1 addition & 2 deletions app/src/main/res/values-ru/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1171,8 +1171,7 @@
<string name="custom_backend_dialog_body_backend_accounts">URL аккаунта:</string>
<string name="custom_backend_dialog_body_backend_website">URL веб-сайта:</string>
<string name="custom_backend_dialog_body_backend_websocket">WSURL бэкэнда:</string>
<string name="custom_backend_invalid_deeplink_data_title">Произошла ошибка</string>
<string name="custom_backend_invalid_deeplink_data_body">Перенаправление на локальный бэкэнд было неудачным, поскольку в JSON-файле была неверная конфигурация.\n\nСвяжитесь с администратором или проверьте ссылку, которая привела вас сюда.</string>
<string name="custom_backend_error_title">Произошла ошибка</string>
<string name="label_fetching_your_messages">Получение новых сообщений</string>
<string name="label_text_copied">Текст скопирован в буфер обмена</string>
<string name="label_logs_option_title">Журналы</string>
Expand Down
5 changes: 3 additions & 2 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1183,8 +1183,9 @@ In group conversations, the group admin can overwrite this setting.</string>
<string name="custom_backend_dialog_body_backend_accounts">Accounts URL:</string>
<string name="custom_backend_dialog_body_backend_website">Website URL:</string>
<string name="custom_backend_dialog_body_backend_websocket">Backend WSURL:</string>
<string name="custom_backend_invalid_deeplink_data_title">An error occurred</string>
<string name="custom_backend_invalid_deeplink_data_body">Redirecting to an on-premises backend was not possible, as there was an invalid configuration in the JSON file.\n\nContact your admin or check the deeplink that brought you here.</string>
<string name="custom_backend_error_title">An error occurred</string>
<string name="custom_backend_error_no_internet_connection_body">Redirecting to an on-premises backend was not possible, you don’t seem to be connected to the internet.\n\nEstablish an internet connection and try again.</string>
<string name="custom_backend_error_no_internet_connection_try_again">Try again</string>
<string name="label_fetching_your_messages">Receiving new messages</string>
<string name="label_text_copied">Text copied to clipboard</string>
<string name="label_logs_option_title">Logs</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import com.wire.android.framework.TestUser
import com.wire.android.migration.MigrationManager
import com.wire.android.services.ServicesManager
import com.wire.android.ui.common.dialogs.CustomServerDetailsDialogState
import com.wire.android.ui.common.dialogs.CustomServerInvalidJsonDialogState
import com.wire.android.ui.common.dialogs.CustomServerNoNetworkDialogState
import com.wire.android.ui.common.topappbar.CommonTopAppBarViewModelTest
import com.wire.android.ui.joinConversation.JoinConversationViaCodeState
import com.wire.android.ui.theme.ThemeOption
Expand Down Expand Up @@ -141,39 +141,39 @@ class WireActivityViewModelTest {
}

@Test
fun `given Intent with malformed ServerConfig json, when currentSessions is present, then initialAppState is LOGGED_IN and customBackEndInvalidJson dialog is shown`() =
fun `given intent with correct ServerConfig json, when no network is present, then initialAppState is LOGGED_IN and no network dialog is shown`() =
runTest {
val result = DeepLinkResult.CustomServerConfig("url")
val (arrangement, viewModel) = Arrangement()
.withSomeCurrentSession()
.withDeepLinkResult(result)
.withMalformedServerJson()
.withNoNetworkConnectionWhenGettingServerConfig()
.withNoOngoingCall()
.arrange()

viewModel.handleDeepLink(mockedIntent(), {}, {}, arrangement.onDeepLinkResult, {}, {}, {}, {})

assertEquals(InitialAppState.LOGGED_IN, viewModel.initialAppState())
verify(exactly = 0) { arrangement.onDeepLinkResult(any()) }
assertInstanceOf(CustomServerInvalidJsonDialogState::class.java, viewModel.globalAppState.customBackendDialog)
assertInstanceOf(CustomServerNoNetworkDialogState::class.java, viewModel.globalAppState.customBackendDialog)
}

@Test
fun `given Intent with malformed ServerConfig json, when currentSessions is present, then initialAppState is NOT_LOGGED_IN and customBackEndInvalidJson dialog is shown`() =
fun `given Intent with malformed ServerConfig json, when currentSessions is absent, then initialAppState is NOT_LOGGED_IN and no network dialog is shown`() =
runTest {
val result = DeepLinkResult.CustomServerConfig("url")
val (arrangement, viewModel) = Arrangement()
.withNoCurrentSession()
.withDeepLinkResult(result)
.withMalformedServerJson()
.withNoNetworkConnectionWhenGettingServerConfig()
.withNoOngoingCall()
.arrange()

viewModel.handleDeepLink(mockedIntent(), {}, {}, arrangement.onDeepLinkResult, {}, {}, {}, {})

assertEquals(InitialAppState.NOT_LOGGED_IN, viewModel.initialAppState())
verify(exactly = 0) { arrangement.onDeepLinkResult(any()) }
assertInstanceOf(CustomServerInvalidJsonDialogState::class.java, viewModel.globalAppState.customBackendDialog)
assertInstanceOf(CustomServerNoNetworkDialogState::class.java, viewModel.globalAppState.customBackendDialog)
}

@Test
Expand Down Expand Up @@ -919,7 +919,7 @@ class WireActivityViewModelTest {
coEvery { coreLogic.getSessionScope(TEST_ACCOUNT_INFO.userId).observeIfE2EIRequiredDuringLogin() } returns flowOf(false)
}

fun withMalformedServerJson() = apply {
fun withNoNetworkConnectionWhenGettingServerConfig() = apply {
coEvery { getServerConfigUseCase(any()) } returns
GetServerConfigResult.Failure.Generic(NetworkFailure.NoNetworkConnection(null))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package com.wire.android.feature.analytics
import android.app.Activity
import android.app.Application
import android.content.Context
import android.util.Log
import com.wire.android.feature.analytics.model.AnalyticsEvent
import com.wire.android.feature.analytics.model.AnalyticsEventConstants
import com.wire.android.feature.analytics.model.AnalyticsSettings
Expand All @@ -34,8 +35,8 @@ class AnonymousAnalyticsRecorderImpl : AnonymousAnalyticsRecorder {
override fun configure(
context: Context,
analyticsSettings: AnalyticsSettings
) {
if (isConfigured) return
) = wrapCountlyRequest {
if (isConfigured) return@wrapCountlyRequest

val countlyConfig = CountlyConfig(
context,
Expand All @@ -54,36 +55,36 @@ class AnonymousAnalyticsRecorderImpl : AnonymousAnalyticsRecorder {
}
}

Countly.sharedInstance().init(countlyConfig)
Countly.sharedInstance().consent().giveConsent(arrayOf("apm"))
Countly.sharedInstance()?.init(countlyConfig)
Countly.sharedInstance()?.consent()?.giveConsent(arrayOf("apm"))

val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)
val globalSegmentations = mapOf<String, Any>(
AnalyticsEventConstants.APP_NAME to AnalyticsEventConstants.APP_NAME_ANDROID,
AnalyticsEventConstants.APP_VERSION to packageInfo.versionName
)
Countly.sharedInstance().views().setGlobalViewSegmentation(globalSegmentations)
Countly.sharedInstance()?.views()?.setGlobalViewSegmentation(globalSegmentations)
isConfigured = true
}

override fun onStart(activity: Activity) {
Countly.sharedInstance().onStart(activity)
override fun onStart(activity: Activity) = wrapCountlyRequest {
Countly.sharedInstance()?.onStart(activity)
}

override fun onStop() {
Countly.sharedInstance().onStop()
override fun onStop() = wrapCountlyRequest {
Countly.sharedInstance()?.onStop()
}

/**
* We need to change our segmentation map to [MutableMap] because
* Countly is doing additional operations on it.
* See [UtilsInternalLimits.removeUnsupportedDataTypes]
*/
override fun sendEvent(event: AnalyticsEvent) {
Countly.sharedInstance().events().recordEvent(event.key, event.toSegmentation().toMutableMap())
override fun sendEvent(event: AnalyticsEvent) = wrapCountlyRequest {
Countly.sharedInstance()?.events()?.recordEvent(event.key, event.toSegmentation().toMutableMap())
}

override fun halt() {
override fun halt() = wrapCountlyRequest {
isConfigured = false
Countly.sharedInstance().consent().removeConsentAll()
}
Expand All @@ -93,7 +94,9 @@ class AnonymousAnalyticsRecorderImpl : AnonymousAnalyticsRecorder {
isTeamMember: Boolean,
migrationComplete: suspend () -> Unit
) {
Countly.sharedInstance().deviceId().changeWithMerge(identifier).also {
wrapCountlyRequest {
Countly.sharedInstance()?.deviceId()?.changeWithMerge(identifier)
}.also {
migrationComplete()
}

Expand All @@ -106,7 +109,9 @@ class AnonymousAnalyticsRecorderImpl : AnonymousAnalyticsRecorder {
isTeamMember: Boolean,
propagateIdentifier: suspend () -> Unit
) {
Countly.sharedInstance().deviceId().changeWithoutMerge(identifier)
wrapCountlyRequest {
Countly.sharedInstance()?.deviceId()?.changeWithoutMerge(identifier)
}

setUserProfileProperties(isTeamMember = isTeamMember)

Expand All @@ -115,27 +120,42 @@ class AnonymousAnalyticsRecorderImpl : AnonymousAnalyticsRecorder {
}
}

private fun setUserProfileProperties(isTeamMember: Boolean) {
Countly.sharedInstance().userProfile().setProperty(
private fun setUserProfileProperties(isTeamMember: Boolean) = wrapCountlyRequest {
Countly.sharedInstance()?.userProfile()?.setProperty(
AnalyticsEventConstants.TEAM_IS_TEAM,
isTeamMember
)
Countly.sharedInstance().userProfile().save()
Countly.sharedInstance()?.userProfile()?.save()
}

override fun isAnalyticsInitialized(): Boolean = Countly.sharedInstance().isInitialized

override fun applicationOnCreate() {
if (isConfigured) return
override fun applicationOnCreate() = wrapCountlyRequest {
if (isConfigured) return@wrapCountlyRequest

Countly.applicationOnCreate()
}

override fun recordView(screen: String) {
Countly.sharedInstance().views().startAutoStoppedView(screen)
override fun recordView(screen: String) = wrapCountlyRequest {
Countly.sharedInstance()?.views()?.startAutoStoppedView(screen)
}

override fun stopView(screen: String) = wrapCountlyRequest {
Countly.sharedInstance()?.views()?.stopViewWithName(screen)
}

@Suppress("TooGenericExceptionCaught")
private fun wrapCountlyRequest(block: () -> Unit) {
try {
block()
} catch (e: Exception) {
// Countly SDK throws exceptions on some cases, just log it
// We don't want to crash the app because of that.
Log.wtf(TAG, "Countly SDK request failed", e)
}
}

override fun stopView(screen: String) {
Countly.sharedInstance().views().stopViewWithName(screen)
companion object {
private const val TAG = "AnonymousAnalyticsRecorderImpl"
}
}

0 comments on commit 1a14d1a

Please sign in to comment.