Split the "no connectivity" snack bar into two by introducing an enum abut the different states of connectivity..

MAILAND-1235

#comment Affected: App behaviour when offline and when domain blocked..
This commit is contained in:
Zorica Stojchevska 2021-02-23 18:14:51 +01:00
parent b672873004
commit a1917cbdd4
17 changed files with 151 additions and 98 deletions

View File

@ -149,6 +149,7 @@ import ch.protonmail.android.events.user.MailSettingsEvent;
import ch.protonmail.android.events.verification.PostHumanVerificationEvent;
import ch.protonmail.android.jobs.contacts.GetSendPreferenceJob;
import ch.protonmail.android.tasks.EmbeddedImagesThread;
import ch.protonmail.android.usecase.VerifyConnection;
import ch.protonmail.android.usecase.model.FetchPublicKeysRequest;
import ch.protonmail.android.usecase.model.FetchPublicKeysResult;
import ch.protonmail.android.utils.AppUtil;
@ -815,16 +816,17 @@ public class ComposeMessageActivity
};
}
private void onConnectivityEvent(boolean hasConnectivity) {
Timber.v("onConnectivityEvent hasConnectivity:%s DoHOngoing:%s", hasConnectivity, isDohOngoing);
private void onConnectivityEvent(VerifyConnection.ConnectionState connectivity) {
Timber.v("onConnectivityEvent hasConnectivity:%s DoHOngoing:%s", connectivity.name(), isDohOngoing);
if (!isDohOngoing) {
if (!hasConnectivity) {
if (connectivity != VerifyConnection.ConnectionState.CONNECTED) {
networkSnackBarUtil.getNoConnectionSnackBar(
mSnackLayout,
mUserManager.getUser(),
this,
onConnectivityCheckRetry(),
null
null,
null,
connectivity == VerifyConnection.ConnectionState.NO_INTERNET
).show();
} else {
networkSnackBarUtil.hideAllSnackBars();

View File

@ -262,7 +262,7 @@ public class BillingFragment extends CreateAccountBaseFragment {
// Set up no connectivity SnackBar
noConnectivitySnackBar =
Snackbar.make(snackBarLayout, R.string.no_connectivity_detected_troubleshoot, Snackbar.LENGTH_INDEFINITE);
Snackbar.make(snackBarLayout, R.string.no_connectivity_detected, Snackbar.LENGTH_INDEFINITE);
View snackBarView = noConnectivitySnackBar.getView();
snackBarView.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.red));
TextView snackBarTextView =

View File

@ -76,6 +76,7 @@ import ch.protonmail.android.jobs.GetDirectEnabledJob;
import ch.protonmail.android.jobs.SendVerificationCodeJob;
import ch.protonmail.android.jobs.general.GetAvailableDomainsJob;
import ch.protonmail.android.jobs.payments.VerifyPaymentJob;
import ch.protonmail.android.usecase.VerifyConnection;
import ch.protonmail.android.usecase.fetch.LaunchInitialDataFetch;
import ch.protonmail.android.utils.AppUtil;
import ch.protonmail.android.utils.UiUtil;
@ -564,15 +565,16 @@ public class CreateAccountActivity extends BaseConnectivityActivity implements
}
}
private void onConnectivityEvent(boolean hasConnectivity) {
Timber.v("onConnectivityEvent hasConnectivity:%s", hasConnectivity);
if (!hasConnectivity) {
private void onConnectivityEvent(VerifyConnection.ConnectionState connectivity) {
Timber.v("onConnectivityEvent hasConnectivity:%s", connectivity.name());
if (connectivity.equals(VerifyConnection.ConnectionState.NO_INTERNET)) {
networkSnackBarUtil.getNoConnectionSnackBar(
mSnackLayout,
mUserManager.getUser(),
this,
onConnectivityCheckRetry(),
null
null,
connectivity == VerifyConnection.ConnectionState.NO_INTERNET
).show();
} else {
if (captchaFragment != null && captchaFragment.isAdded()) {
@ -632,7 +634,7 @@ public class CreateAccountActivity extends BaseConnectivityActivity implements
break;
case NO_NETWORK:
checkDirectEnabled();
onConnectivityEvent(false);
onConnectivityEvent(VerifyConnection.ConnectionState.NO_INTERNET);
break;
}
}

View File

@ -58,6 +58,7 @@ import ch.protonmail.android.events.Login2FAEvent;
import ch.protonmail.android.events.LoginEvent;
import ch.protonmail.android.events.LoginInfoEvent;
import ch.protonmail.android.events.MailboxLoginEvent;
import ch.protonmail.android.usecase.VerifyConnection;
import ch.protonmail.android.utils.AppUtil;
import ch.protonmail.android.utils.UiUtil;
import ch.protonmail.android.utils.extensions.TextExtensions;
@ -217,15 +218,16 @@ public class LoginActivity extends BaseLoginActivity {
};
}
private void onConnectivityEvent(boolean hasConnectivity) {
Timber.v("onConnectivityEvent hasConnectivity:%s", hasConnectivity);
if (!hasConnectivity) {
private void onConnectivityEvent(VerifyConnection.ConnectionState connectivity) {
Timber.v("onConnectivityEvent hasConnectivity:%s", connectivity.name());
if (connectivity != VerifyConnection.ConnectionState.CONNECTED) {
networkSnackBarUtil.getNoConnectionSnackBar(
mSnackLayout,
mUserManager.getUser(),
this,
onConnectivityCheckRetry(),
null
null,
null,
connectivity == VerifyConnection.ConnectionState.NO_INTERNET
).show();
} else {
networkSnackBarUtil.hideAllSnackBars();

View File

@ -42,6 +42,7 @@ import ch.protonmail.android.events.LogoutEvent;
import ch.protonmail.android.events.MailboxLoginEvent;
import ch.protonmail.android.events.Status;
import ch.protonmail.android.events.user.MailSettingsEvent;
import ch.protonmail.android.usecase.VerifyConnection;
import ch.protonmail.android.utils.AppUtil;
import ch.protonmail.android.utils.UiUtil;
import ch.protonmail.android.utils.extensions.TextExtensions;
@ -197,15 +198,16 @@ public class MailboxLoginActivity extends BaseLoginActivity {
};
}
private void onConnectivityEvent(boolean hasConnectivity) {
Timber.v("onConnectivityEvent hasConnectivity:%s", hasConnectivity);
if (!hasConnectivity) {
private void onConnectivityEvent(VerifyConnection.ConnectionState connectivity) {
Timber.v("onConnectivityEvent hasConnectivity:%s", connectivity.name());
if (connectivity != VerifyConnection.ConnectionState.CONNECTED) {
networkSnackBarUtil.getNoConnectionSnackBar(
mSnackLayout,
mUserManager.getUser(),
this,
onConnectivityCheckRetry(),
null
null,
null,
connectivity == VerifyConnection.ConnectionState.NO_INTERNET
).show();
} else {
networkSnackBarUtil.hideAllSnackBars();

View File

@ -159,6 +159,7 @@ import ch.protonmail.android.prefs.SecureSharedPreferences
import ch.protonmail.android.servers.notification.EXTRA_MAILBOX_LOCATION
import ch.protonmail.android.servers.notification.EXTRA_USERNAME
import ch.protonmail.android.settings.pin.EXTRA_TOTAL_COUNT_EVENT
import ch.protonmail.android.usecase.VerifyConnection
import ch.protonmail.android.utils.AppUtil
import ch.protonmail.android.utils.Event
import ch.protonmail.android.utils.MessageUtils
@ -892,12 +893,12 @@ class MailboxActivity :
val mailboxLocation = mailboxLocationMain.value
menu.findItem(R.id.empty).isVisible =
mailboxLocation in listOf(
MessageLocationType.DRAFT,
MessageLocationType.SPAM,
MessageLocationType.TRASH,
MessageLocationType.LABEL,
MessageLocationType.LABEL_FOLDER
)
MessageLocationType.DRAFT,
MessageLocationType.SPAM,
MessageLocationType.TRASH,
MessageLocationType.LABEL,
MessageLocationType.LABEL_FOLDER
)
return super.onPrepareOptionsMenu(menu)
}
@ -1033,14 +1034,15 @@ class MailboxActivity :
supportActionBar!!.setTitle(titleRes)
}
private fun showNoConnSnackAndScheduleRetry() {
private fun showNoConnSnackAndScheduleRetry(connectivity: VerifyConnection.ConnectionState) {
Timber.v("show NoConnection Snackbar ${mConnectivitySnackLayout != null}")
mConnectivitySnackLayout?.let {
networkSnackBarUtil.getNoConnectionSnackBar(
parentView = it,
user = mUserManager.user,
netConfiguratorCallback = this,
onRetryClick = { onConnectivityCheckRetry() }
onRetryClick = { onConnectivityCheckRetry() },
isOffline = connectivity == VerifyConnection.ConnectionState.NO_INTERNET
).show()
}
}
@ -1146,13 +1148,13 @@ class MailboxActivity :
setRefreshing(false)
}
private fun onConnectivityEvent(hasConnection: Boolean) {
Timber.v("onConnectivityEvent hasConnection: $hasConnection")
private fun onConnectivityEvent(connectivity: VerifyConnection.ConnectionState) {
Timber.v("onConnectivityEvent hasConnection: ${connectivity.name}")
if (!isDohOngoing) {
Timber.d("DoH NOT ongoing showing UI")
if (!hasConnection) {
if (connectivity != VerifyConnection.ConnectionState.CONNECTED) {
setRefreshing(false)
showNoConnSnackAndScheduleRetry()
showNoConnSnackAndScheduleRetry(connectivity)
} else {
hideNoConnSnack()
}
@ -1183,7 +1185,7 @@ class MailboxActivity :
when (status) {
Status.FAILED,
Status.NO_NETWORK -> {
showNoConnSnackAndScheduleRetry()
showNoConnSnackAndScheduleRetry(VerifyConnection.ConnectionState.NO_INTERNET)
}
Status.SUCCESS -> {
hideNoConnSnack()

View File

@ -83,6 +83,7 @@ import ch.protonmail.android.jobs.PostSpamJob
import ch.protonmail.android.jobs.PostTrashJobV2
import ch.protonmail.android.jobs.PostUnreadJob
import ch.protonmail.android.jobs.ReportPhishingJob
import ch.protonmail.android.usecase.VerifyConnection
import ch.protonmail.android.utils.AppUtil
import ch.protonmail.android.utils.CustomLocale
import ch.protonmail.android.utils.Event
@ -425,7 +426,7 @@ internal class MessageDetailsActivity :
buttonsVisibilityHandler.removeCallbacks(buttonsVisibilityRunnable)
}
private fun showNoConnSnackExtended() {
private fun showNoConnSnackExtended(connectivity: VerifyConnection.ConnectionState) {
Timber.v("Show no connection")
networkSnackBarUtil.hideAllSnackBars()
networkSnackBarUtil.getNoConnectionSnackBar(
@ -433,7 +434,8 @@ internal class MessageDetailsActivity :
mUserManager.user,
this,
{ onConnectivityCheckRetry() },
anchorViewId = R.id.action_buttons
anchorViewId = R.id.action_buttons,
isOffline = connectivity == VerifyConnection.ConnectionState.NO_INTERNET
).show()
invalidateOptionsMenu()
}
@ -457,12 +459,12 @@ internal class MessageDetailsActivity :
viewModel.hasConnectivity.observe(
this,
{ isConnectionActive ->
Timber.v("isConnectionActive:$isConnectionActive")
if (isConnectionActive) {
Timber.v("isConnectionActive:${isConnectionActive.name}")
if (isConnectionActive == VerifyConnection.ConnectionState.CONNECTED) {
hideNoConnSnackExtended()
viewModel.fetchMessageDetails(false)
} else {
showNoConnSnackExtended()
showNoConnSnackExtended(isConnectionActive)
}
}
)

View File

@ -76,6 +76,7 @@ import ch.protonmail.android.jobs.FetchByLocationJob
import ch.protonmail.android.servers.notification.CHANNEL_ID_EMAIL
import ch.protonmail.android.settings.pin.PinSettingsActivity
import ch.protonmail.android.uiModel.SettingsItemUiModel
import ch.protonmail.android.usecase.VerifyConnection
import ch.protonmail.android.usecase.fetch.LaunchInitialDataFetch
import ch.protonmail.android.utils.AppUtil
import ch.protonmail.android.utils.CustomLocale
@ -474,14 +475,15 @@ abstract class BaseSettingsActivity : BaseConnectivityActivity() {
}
}
private fun onConnectivityEvent(hasConnection: Boolean) {
Timber.v("onConnectivityEvent hasConnection:$hasConnection")
if (!hasConnection) {
private fun onConnectivityEvent(connectivity: VerifyConnection.ConnectionState) {
Timber.v("onConnectivityEvent hasConnection:${connectivity.name}")
if (connectivity != VerifyConnection.ConnectionState.CONNECTED) {
networkSnackBarUtil.getNoConnectionSnackBar(
mSnackLayout,
mUserManager.user,
this,
{ onConnectivityCheckRetry() }
{ onConnectivityCheckRetry() },
isOffline = connectivity == VerifyConnection.ConnectionState.NO_INTERNET
).show()
} else {
networkSnackBarUtil.hideAllSnackBars()

View File

@ -48,6 +48,7 @@ import ch.protonmail.android.core.Constants
import ch.protonmail.android.events.LogoutEvent
import ch.protonmail.android.events.user.MailSettingsEvent
import ch.protonmail.android.permissions.PermissionHelper
import ch.protonmail.android.usecase.VerifyConnection
import ch.protonmail.android.utils.AppUtil
import ch.protonmail.android.utils.extensions.showToast
import ch.protonmail.android.utils.moveToLogin
@ -183,15 +184,16 @@ class ContactsActivity :
contactsViewModel.checkConnectivityDelayed()
}
private fun onConnectivityEvent(hasConnection: Boolean) {
Timber.v("onConnectivityEvent hasConnection:$hasConnection")
private fun onConnectivityEvent(connectivity: VerifyConnection.ConnectionState) {
Timber.v("onConnectivityEvent hasConnection:${connectivity.name}")
networkSnackBarUtil.hideAllSnackBars()
if (!hasConnection) {
if (connectivity != VerifyConnection.ConnectionState.CONNECTED) {
networkSnackBarUtil.getNoConnectionSnackBar(
mSnackLayout,
mUserManager.user,
this,
{ onConnectivityCheckRetry() }
{ onConnectivityCheckRetry() },
isOffline = connectivity == VerifyConnection.ConnectionState.NO_INTERNET
).show()
}
}

View File

@ -80,6 +80,7 @@ import ch.protonmail.android.core.ProtonMailApplication;
import ch.protonmail.android.events.ContactEvent;
import ch.protonmail.android.events.LogoutEvent;
import ch.protonmail.android.events.user.MailSettingsEvent;
import ch.protonmail.android.usecase.VerifyConnection;
import ch.protonmail.android.utils.AppUtil;
import ch.protonmail.android.utils.DateUtil;
import ch.protonmail.android.utils.Event;
@ -779,15 +780,16 @@ public class EditContactDetailsActivity extends BaseConnectivityActivity {
return new ContactAddressView(this, titleText, optionTitleText, standardOptionUIValues, standardOptionValues, rootView);
}
private void onConnectivityEvent(boolean hasConnectivity) {
Timber.v("onConnectivityEvent hasConnectivity:%s", hasConnectivity);
if (!hasConnectivity) {
private void onConnectivityEvent(VerifyConnection.ConnectionState connectivity) {
Timber.v("onConnectivityEvent hasConnectivity:%s", connectivity.name());
if (connectivity != VerifyConnection.ConnectionState.CONNECTED) {
networkSnackBarUtil.getNoConnectionSnackBar(
mSnackLayout,
mUserManager.getUser(),
this,
onConnectivityCheckRetry(),
null
null,
null,
connectivity == VerifyConnection.ConnectionState.NO_INTERNET
).show();
} else {
networkSnackBarUtil.hideAllSnackBars();

View File

@ -112,7 +112,7 @@ class EditContactDetailsViewModel @ViewModelInject constructor(
get() = _setupConvertContactFlow
val freeUserEvent: LiveData<Unit>
get() = _freeUserEvent
val hasConnectivity: LiveData<Boolean> =
val hasConnectivity: LiveData<VerifyConnection.ConnectionState> =
_verifyConnectionTrigger.switchMap { verifyConnection().asLiveData() }
val createContactResult: MutableLiveData<Int> = MutableLiveData()
// endregion

View File

@ -26,6 +26,7 @@ import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
import android.net.NetworkRequest
import android.os.Build
import androidx.annotation.RequiresApi
import ch.protonmail.android.usecase.VerifyConnection
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
@ -61,7 +62,7 @@ class NetworkConnectivityManager @Inject constructor(
/**
* Flow of boolean connection events. True when internet connection is established, false when it is lost.
*/
fun isConnectionAvailableFlow(): Flow<Boolean> = callbackFlow {
fun isConnectionAvailableFlow(): Flow<VerifyConnection.ConnectionState> = callbackFlow {
val callback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
Timber.v("Network $network available")
@ -69,10 +70,10 @@ class NetworkConnectivityManager @Inject constructor(
override fun onLost(network: Network) {
launch {
delay(2.seconds)
delay(3.seconds)
Timber.d("Network $network lost isInternetPossible: ${isInternetConnectionPossible()}")
if (!isInternetConnectionPossible()) {
offer(false)
offer(VerifyConnection.ConnectionState.NO_INTERNET)
}
}
}
@ -84,7 +85,7 @@ class NetworkConnectivityManager @Inject constructor(
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
if (networkCapabilities.hasCapability(NET_CAPABILITY_INTERNET)) {
Timber.v("Network $network has internet capability")
offer(true)
offer(VerifyConnection.ConnectionState.CONNECTED)
}
}
}

View File

@ -24,6 +24,7 @@ import android.content.Intent
import android.content.IntentFilter
import android.net.ConnectivityManager
import ch.protonmail.android.api.NetworkConfigurator
import ch.protonmail.android.usecase.VerifyConnection
import com.birbit.android.jobqueue.network.NetworkEventProvider
import com.birbit.android.jobqueue.network.NetworkUtil
import kotlinx.coroutines.flow.MutableStateFlow
@ -45,17 +46,17 @@ class QueueNetworkUtil @Inject constructor(
) : NetworkUtil, NetworkEventProvider {
private var listener: NetworkEventProvider.Listener? = null
private var isInternetAccessible: Boolean = false
private var isServerAccessible: Boolean = true
private var lastEmissionTime = 0L
/**
* Flow that emits false when backend replies with an error, or true when
* a correct reply is received.
*/
val isBackendRespondingWithoutErrorFlow: StateFlow<Boolean>
val isBackendRespondingWithoutErrorFlow: StateFlow<VerifyConnection.ConnectionState>
get() = backendExceptionFlow
private val backendExceptionFlow = MutableStateFlow(true)
private val backendExceptionFlow = MutableStateFlow(VerifyConnection.ConnectionState.CONNECTED)
init {
updateRealConnectivity(true) // initially we assume there is connectivity
@ -79,21 +80,21 @@ class QueueNetworkUtil @Inject constructor(
}
@Synchronized
private fun updateRealConnectivity(internetAccessible: Boolean) {
isInternetAccessible = internetAccessible
private fun updateRealConnectivity(serverAccessible: Boolean) {
isServerAccessible = serverAccessible
if (internetAccessible) {
backendExceptionFlow.value = internetAccessible
if (serverAccessible) {
backendExceptionFlow.value = VerifyConnection.ConnectionState.CONNECTED
} else {
// to prevent consecutive series of disconnection emissions we introduce a disconnection
// emission buffer below
val currentTime = System.currentTimeMillis()
val emissionTimeDelta = currentTime - lastEmissionTime
Timber.v("updateRealConnectivity isInternetAccessible: $isInternetAccessible timeDelta: $emissionTimeDelta")
Timber.v("updateRealConnectivity isServerAccessible: $serverAccessible timeDelta: $emissionTimeDelta")
val mayEmit = emissionTimeDelta > DISCONNECTION_EMISSION_WINDOW_MS
if (mayEmit) {
lastEmissionTime = currentTime
backendExceptionFlow.value = internetAccessible
backendExceptionFlow.value = VerifyConnection.ConnectionState.CANT_REACH_SERVER
}
}
}
@ -108,7 +109,6 @@ class QueueNetworkUtil @Inject constructor(
// should be followed by no connection snackbar and DoH setup
when (throwable) {
is SocketTimeoutException,
is UnknownHostException,
is GeneralSecurityException, // e.g. CertificateException
is SSLException -> updateRealConnectivity(false)
else -> Timber.d("connectivityHasFailed ignoring exception: $throwable")
@ -120,13 +120,13 @@ class QueueNetworkUtil @Inject constructor(
}
private fun hasConn(checkReal: Boolean): Boolean {
synchronized(isInternetAccessible) {
synchronized(isServerAccessible) {
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val netInfo = cm.activeNetworkInfo
var hasConnection = netInfo != null && netInfo.isConnectedOrConnecting
val currentStatus = isInternetAccessible
val currentStatus = isServerAccessible
if (checkReal) {
hasConnection = hasConnection && isInternetAccessible
hasConnection = hasConnection && isServerAccessible
}
if (checkReal && currentStatus != hasConnection) {
Timber.d("Network statuses differs hasConnection $hasConnection currentStatus $currentStatus")

View File

@ -56,16 +56,16 @@ class VerifyConnection @Inject constructor(
private val queueNetworkUtil: QueueNetworkUtil
) {
operator fun invoke(): Flow<Boolean> {
operator fun invoke(): Flow<ConnectionState> {
val connectivityManagerFlow = flowOf(
connectivityManager.isConnectionAvailableFlow(),
queueNetworkUtil.isBackendRespondingWithoutErrorFlow
)
.flattenMerge()
.filter { !it } // observe only disconnections
.filter { it != ConnectionState.CONNECTED } // observe only disconnections
.onEach {
Timber.v("connectivityManagerFlow value: $it")
Timber.v("connectivityManagerFlow value: ${it.name}")
pingWorkerEnqueuer.enqueue() // re-schedule ping
}
@ -76,17 +76,24 @@ class VerifyConnection @Inject constructor(
.flattenMerge()
.onStart {
pingWorkerEnqueuer.enqueue()
emit(connectivityManager.isInternetConnectionPossible()) // start with current net state
emit(
if (connectivityManager.isInternetConnectionPossible())
ConnectionState.CONNECTED else ConnectionState.NO_INTERNET
) // start with current net state
}
}
private fun getPingStateList(workInfoLiveData: LiveData<List<WorkInfo>?>): Flow<Boolean> {
private fun getPingStateList(workInfoLiveData: LiveData<List<WorkInfo>?>): Flow<ConnectionState> {
return workInfoLiveData
.map { workInfoList ->
val hasSucceededEvents = mutableListOf<Boolean>()
val hasSucceededEvents = mutableListOf<ConnectionState>()
workInfoList?.forEach { info ->
if (info.state.isFinished) {
hasSucceededEvents.add(info.state == WorkInfo.State.SUCCEEDED)
if (info.state == WorkInfo.State.FAILED) {
hasSucceededEvents.add(ConnectionState.CANT_REACH_SERVER)
} else {
hasSucceededEvents.add(ConnectionState.CONNECTED)
}
}
}
Timber.v(
@ -98,4 +105,8 @@ class VerifyConnection @Inject constructor(
.filter { it.isNotEmpty() }
.map { it[0] }
}
enum class ConnectionState {
CONNECTED, NO_INTERNET, CANT_REACH_SERVER
}
}

View File

@ -44,6 +44,8 @@ import javax.inject.Inject
class NetworkSnackBarUtil @Inject constructor() {
private var noConnectionSnackBar: Snackbar? = null
// private var serverNotReachableSnackBar: Snackbar? = null
private var checkingConnectionSnackBar: Snackbar? = null
/**
@ -60,28 +62,48 @@ class NetworkSnackBarUtil @Inject constructor() {
user: User,
netConfiguratorCallback: INetworkConfiguratorCallback,
onRetryClick: (() -> Unit)?,
@IdRes anchorViewId: Int? = null
@IdRes anchorViewId: Int? = null,
isOffline: Boolean
): Snackbar {
val snackBar = noConnectionSnackBar
?: Snackbar.make(
parentView,
R.string.no_connectivity_detected_troubleshoot,
Snackbar.LENGTH_INDEFINITE
).apply {
anchorViewId?.let { setAnchorView(it) }
setAction(context.getString(R.string.retry)) { onRetryClick?.invoke() }
setActionTextColor(ContextCompat.getColor(context, R.color.white))
view.apply {
setBackgroundColor(ContextCompat.getColor(context, R.color.red))
isClickable = true
isFocusable = true
setOnClickListener { showNoConnectionTroubleshootDialog(context, user, netConfiguratorCallback) }
findViewById<TextView>(com.google.android.material.R.id.snackbar_text).apply {
setTextColor(Color.WHITE)
val snackBar = if (isOffline) {
noConnectionSnackBar
?: Snackbar.make(
parentView,
R.string.you_are_offline,
Snackbar.LENGTH_INDEFINITE
).apply {
anchorViewId?.let { setAnchorView(it) }
setActionTextColor(ContextCompat.getColor(context, R.color.white))
view.apply {
setBackgroundColor(ContextCompat.getColor(context, R.color.orange))
findViewById<TextView>(com.google.android.material.R.id.snackbar_text).apply {
setTextColor(Color.WHITE)
}
}
}
}
} else {
noConnectionSnackBar
?: Snackbar.make(
parentView,
R.string.no_connectivity_detected_troubleshoot,
Snackbar.LENGTH_INDEFINITE
).apply {
anchorViewId?.let { setAnchorView(it) }
setAction(context.getString(R.string.retry)) { onRetryClick?.invoke() }
setActionTextColor(ContextCompat.getColor(context, R.color.white))
view.apply {
setBackgroundColor(ContextCompat.getColor(context, R.color.red))
isClickable = true
isFocusable = true
setOnClickListener {
showNoConnectionTroubleshootDialog(context, user, netConfiguratorCallback)
}
findViewById<TextView>(com.google.android.material.R.id.snackbar_text).apply {
setTextColor(Color.WHITE)
}
}
}
}
noConnectionSnackBar = snackBar
Timber.d("getNoConnectionSnackBar $snackBar $parentView")
return snackBar

View File

@ -46,12 +46,12 @@ open class ConnectivityBaseViewModel @ViewModelInject constructor(
private val verifyConnectionTrigger: MutableLiveData<Unit> = MutableLiveData()
val hasConnectivity: LiveData<Boolean> =
val hasConnectivity: LiveData<VerifyConnection.ConnectionState> =
verifyConnectionTrigger.switchMap {
verifyConnection()
.distinctUntilChanged()
.onEach { isConnected ->
if (!isConnected) {
if (isConnected != VerifyConnection.ConnectionState.CONNECTED) {
retryWithDoh()
}
}

View File

@ -80,6 +80,7 @@ along with ProtonMail. If not, see https://www.gnu.org/licenses/.
<color name="red">#BF0000</color>
<color name="red_orange">#EA644C</color>
<color name="orange">#D9804B</color>
<color name="green">#A2C276</color>
<color name="blue">#7569D1</color>
<color name="yellow">#EDCF54</color>