diff --git a/.gitignore b/.gitignore
index a2c219b..79adf2f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
# Project exclude paths
.gradle/
.idea/
+.DS_Store
/build
/local.properties
/satodime-android
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 2a04edc..50b4482 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -99,4 +99,11 @@ dependencies {
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_ui_version"
debugImplementation "androidx.compose.ui:ui-tooling:$compose_ui_version"
debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_ui_version"
+
+ //Material 3 compose
+ implementation 'androidx.compose.material3:material3:1.2.1'
+
+ //Compose coil image
+ implementation "io.coil-kt:coil-gif:2.0.0-rc02"
+ implementation 'io.coil-kt:coil-compose:2.0.0-rc02'
}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 127b842..a84c01c 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -4,6 +4,7 @@
+
(null)
+ }
+
+ Box(
+ modifier = Modifier.fillMaxSize()
+ ) {
+ Navigation()
+ if (prevStatus == ConnectionChecker.InternetStatus.Lost && status == ConnectionChecker.InternetStatus.Available) {
+ SatoToast(
+ title = R.string.networkConnected,
+ text = R.string.networkConnectedMessage,
+ icon = R.drawable.contactless_24px,
+ iconColor = SatoGreen
+ )
+ }
+ if (status == ConnectionChecker.InternetStatus.Lost ||
+ status == ConnectionChecker.InternetStatus.Unavailable
+ ) {
+ SatoToast(
+ title = R.string.networkError,
+ text = R.string.networkErrorMessage,
+ icon = R.drawable.error_cross
+ )
+ prevStatus = status
+ }
+ }
}
}
}
diff --git a/app/src/main/java/org/satochip/satodimeapp/ui/VaultsView.kt b/app/src/main/java/org/satochip/satodimeapp/ui/VaultsView.kt
index 527092f..45b219f 100644
--- a/app/src/main/java/org/satochip/satodimeapp/ui/VaultsView.kt
+++ b/app/src/main/java/org/satochip/satodimeapp/ui/VaultsView.kt
@@ -49,6 +49,7 @@ import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Loop
import androidx.compose.material.icons.filled.MoreVert
+import androidx.compose.material.icons.outlined.ContentCopy
import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
@@ -92,10 +93,14 @@ import org.satochip.satodimeapp.ui.components.NfcDialog
import org.satochip.satodimeapp.ui.components.NftDialog
import org.satochip.satodimeapp.ui.components.RedGradientBackground
import org.satochip.satodimeapp.ui.components.VaultCard
+import org.satochip.satodimeapp.ui.components.shared.SatoButton
+import org.satochip.satodimeapp.ui.components.vaults.VaultDrawerScreen
+import org.satochip.satodimeapp.ui.components.vaults.VaultsBottomDrawer
import org.satochip.satodimeapp.ui.theme.DarkRed
import org.satochip.satodimeapp.ui.theme.LightBlue
import org.satochip.satodimeapp.ui.theme.LightDarkBlue
import org.satochip.satodimeapp.ui.theme.LightGreen
+import org.satochip.satodimeapp.ui.theme.SatoGreen
import org.satochip.satodimeapp.ui.theme.SatodimeTheme
import org.satochip.satodimeapp.util.SatodimeScreen
import org.satochip.satodimeapp.util.formatBalance
@@ -112,6 +117,11 @@ fun VaultsView(navController: NavController, sharedViewModel: SharedViewModel) {
val showNfcDialog = remember{ mutableStateOf(false) } // for NfcDialog
val showNoCardScannedDialog = remember { mutableStateOf(false)}// for NoCardScannedDialog
+ // NfcDialog
+ if (showNfcDialog.value){
+ NfcDialog(openDialogCustom = showNfcDialog, resultCodeLive = sharedViewModel.resultCodeLive, isConnected = sharedViewModel.isCardConnected)
+ }
+
// val showOwnershipDialog = remember{ mutableStateOf(true) } // for OwnershipDialog
// val showAuthenticityDialog = remember{ mutableStateOf(true) } // for AuthenticityDialog
@@ -373,12 +383,6 @@ fun VaultsView(navController: NavController, sharedViewModel: SharedViewModel) {
uriHandler.openUri("https://satochip.io/satodime-ownership-explained/")
},)
}
-
- // NfcDialog
- if (showNfcDialog.value){
- NfcDialog(openDialogCustom = showNfcDialog, resultCodeLive = sharedViewModel.resultCodeLive, isConnected = sharedViewModel.isCardConnected)
- }
-
}
/// LIST VIEW
@@ -770,7 +774,7 @@ fun VaultsViewTokenRow(asset: Asset) {
contentDescription = "link to explorer",
modifier = Modifier
.width(30.dp)
- .clickable{
+ .clickable {
uriHandler.openUri(asset.explorerLink ?: "")
},
tint = MaterialTheme.colors.secondary, //Color.LightGray,
@@ -847,7 +851,7 @@ fun VaultsViewNftRow(asset: Asset) {
contentDescription = "link to NFT explorer",
modifier = Modifier
.width(30.dp)
- .clickable{
+ .clickable {
uriHandler.openUri(asset.nftExplorerLink ?: asset.explorerLink ?: "")
},
//.requiredWidth(30.dp)
diff --git a/app/src/main/java/org/satochip/satodimeapp/ui/components/NfcDialog.kt b/app/src/main/java/org/satochip/satodimeapp/ui/components/NfcDialog.kt
index a2b6949..582a050 100644
--- a/app/src/main/java/org/satochip/satodimeapp/ui/components/NfcDialog.kt
+++ b/app/src/main/java/org/satochip/satodimeapp/ui/components/NfcDialog.kt
@@ -30,6 +30,8 @@ import kotlinx.coroutines.delay
import org.satochip.satodimeapp.R
import org.satochip.satodimeapp.data.NfcResultCode
import org.satochip.satodimeapp.services.SatoLog
+import org.satochip.satodimeapp.ui.components.vaults.VaultDrawerScreen
+import org.satochip.satodimeapp.ui.components.vaults.VaultsBottomDrawer
import org.satochip.satodimeapp.ui.theme.LightBlue
import org.satochip.satodimeapp.ui.theme.Orange
import kotlin.time.Duration.Companion.seconds
@@ -39,24 +41,46 @@ private const val TAG = "NfcDialog"
@Composable
fun NfcDialog(openDialogCustom: MutableState, resultCodeLive: NfcResultCode, isConnected: Boolean) {
- Dialog(onDismissRequest = {
- openDialogCustom.value = false
- // todo: disable NFC scan?
- }) {
- NfcDialogUI(openDialogCustom = openDialogCustom, resultCodeLive = resultCodeLive, isConnected = isConnected)
+ VaultsBottomDrawer(
+ showSheet = openDialogCustom
+ ) {
- // auto-close alertDialog when action is done
LaunchedEffect(resultCodeLive) {
SatoLog.d(TAG, "LaunchedEffect START ${resultCodeLive}")
while (resultCodeLive == NfcResultCode.Busy || resultCodeLive == NfcResultCode.None) {
SatoLog.d(TAG, "LaunchedEffect in while delay 2s ${resultCodeLive}")
delay(2.seconds)
}
- SatoLog.d(TAG, "LaunchedEffect after while delay 3s ${resultCodeLive}")
- delay(3.seconds)
- openDialogCustom.value = false
+ SatoLog.d(TAG, "LaunchedEffect after while delay ${resultCodeLive}")
}
+ if (resultCodeLive == NfcResultCode.Busy){
+ VaultDrawerScreen(
+ closeSheet = {
+ openDialogCustom.value = !openDialogCustom.value
+ },
+ closeDrawerButton = true,
+ title = R.string.readyToScan,
+ image = R.drawable.phone_icon,
+ message = R.string.nfcHoldSatodime
+ )
+ } else {
+ if (resultCodeLive == NfcResultCode.Ok){
+ VaultDrawerScreen(
+ closeSheet = {
+ openDialogCustom.value = !openDialogCustom.value
+ },
+ closeDrawerButton = true,
+ title = R.string.readyToScan,
+ image = R.drawable.icon_check_gif,
+ message = R.string.nfcHoldSatodime
+ )
+ LaunchedEffect(Unit) {
+ delay(0.5.seconds)
+ openDialogCustom.value = false
+ }
+ }
+ }
}
}
diff --git a/app/src/main/java/org/satochip/satodimeapp/ui/components/shared/BottomSheet.kt b/app/src/main/java/org/satochip/satodimeapp/ui/components/shared/BottomSheet.kt
new file mode 100644
index 0000000..a148c91
--- /dev/null
+++ b/app/src/main/java/org/satochip/satodimeapp/ui/components/shared/BottomSheet.kt
@@ -0,0 +1,44 @@
+package org.satochip.satodimeapp.ui.components.shared
+
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.ModalBottomSheet
+import androidx.compose.material3.rememberModalBottomSheetState
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.MutableState
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.unit.dp
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun BottomSheet(
+ showSheet: MutableState,
+ modifier: Modifier,
+ content: @Composable () -> Unit,
+) {
+ val sheetState = rememberModalBottomSheetState(
+ skipPartiallyExpanded = false
+ )
+ if (!showSheet.value) {
+ return
+ } else {
+ BottomSheet(
+ modifier = modifier,
+ showSheet = showSheet,
+ ) {
+ content()
+ }
+ ModalBottomSheet(
+ modifier = modifier,
+ containerColor = Color.White,
+ sheetState = sheetState,
+ onDismissRequest = {
+ showSheet.value = !showSheet.value
+ },
+ shape = RoundedCornerShape(10.dp)
+ ) {
+ content()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/satochip/satodimeapp/ui/components/shared/GifImage.kt b/app/src/main/java/org/satochip/satodimeapp/ui/components/shared/GifImage.kt
new file mode 100644
index 0000000..d4cf02a
--- /dev/null
+++ b/app/src/main/java/org/satochip/satodimeapp/ui/components/shared/GifImage.kt
@@ -0,0 +1,46 @@
+package org.satochip.satodimeapp.ui.components.shared
+
+import android.os.Build
+import androidx.annotation.DrawableRes
+import androidx.compose.foundation.Image
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.ColorFilter
+import androidx.compose.ui.platform.LocalContext
+import coil.ImageLoader
+import coil.compose.rememberAsyncImagePainter
+import coil.decode.GifDecoder
+import coil.decode.ImageDecoderDecoder
+import coil.request.ImageRequest
+import coil.size.Size
+
+@Composable
+fun GifImage(
+ modifier: Modifier,
+ colorFilter: ColorFilter? = null,
+ @DrawableRes image: Int
+) {
+ val context = LocalContext.current
+ val imageLoader = ImageLoader.Builder(context)
+ .components {
+ if (Build.VERSION.SDK_INT >= 28) {
+ add(ImageDecoderDecoder.Factory())
+ } else {
+ add(GifDecoder.Factory())
+ }
+ }
+ .build()
+ val painter = rememberAsyncImagePainter(
+ ImageRequest.Builder(context).data(data = image)
+ .apply(block = {
+ size(Size.ORIGINAL)
+ }).build(), imageLoader = imageLoader
+ )
+ Image(
+ modifier = modifier,
+ painter = painter,
+ contentDescription = null,
+ colorFilter = colorFilter
+ )
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/satochip/satodimeapp/ui/components/shared/SatoButton.kt b/app/src/main/java/org/satochip/satodimeapp/ui/components/shared/SatoButton.kt
index 7145e66..b9d76a8 100644
--- a/app/src/main/java/org/satochip/satodimeapp/ui/components/shared/SatoButton.kt
+++ b/app/src/main/java/org/satochip/satodimeapp/ui/components/shared/SatoButton.kt
@@ -15,19 +15,21 @@ import androidx.compose.ui.unit.dp
@Composable
fun SatoButton(
+ modifier: Modifier = Modifier,
onClick: () -> Unit,
text: Int,
buttonColor: Color = MaterialTheme.colors.primary,
- textColor: Color = MaterialTheme.colors.secondary
+ textColor: Color = MaterialTheme.colors.secondary,
+ shape: RoundedCornerShape = RoundedCornerShape(50)
) {
Button(
onClick = {
onClick()
},
- modifier = Modifier
+ modifier = modifier
.padding(10.dp)
.height(40.dp),
- shape = RoundedCornerShape(50),
+ shape = shape,
colors = ButtonDefaults.buttonColors(
backgroundColor = buttonColor,
)
diff --git a/app/src/main/java/org/satochip/satodimeapp/ui/components/shared/SatoToast.kt b/app/src/main/java/org/satochip/satodimeapp/ui/components/shared/SatoToast.kt
new file mode 100644
index 0000000..317ed71
--- /dev/null
+++ b/app/src/main/java/org/satochip/satodimeapp/ui/components/shared/SatoToast.kt
@@ -0,0 +1,102 @@
+package org.satochip.satodimeapp.ui.components.shared
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.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.graphics.ColorFilter
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import kotlinx.coroutines.delay
+import org.satochip.satodimeapp.R
+import org.satochip.satodimeapp.ui.theme.SatoToastGrey
+import org.satochip.satodimeapp.ui.theme.SatoWarningOrange
+import kotlin.time.Duration.Companion.seconds
+
+@Composable
+fun SatoToast(
+ title: Int,
+ text: Int,
+ icon: Int,
+ iconColor: Color = SatoWarningOrange
+) {
+ var showToast by remember {
+ mutableStateOf(true)
+ }
+ if (showToast) {
+ Box(
+ modifier = Modifier
+ .padding(horizontal = 16.dp)
+ .fillMaxWidth()
+ .background(
+ color = SatoToastGrey,
+ shape = RoundedCornerShape(50)
+ ),
+ ) {
+ Row(
+ modifier = Modifier.padding(8.dp),
+ horizontalArrangement = Arrangement.Center,
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ GifImage(
+ modifier = Modifier
+ .padding(12.dp)
+ .size(36.dp),
+ colorFilter = ColorFilter.tint(iconColor),
+ image = icon
+ )
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ ) {
+ Text(
+ text = stringResource(id = title),
+ style = TextStyle(
+ fontSize = 20.sp,
+ fontWeight = FontWeight.Bold
+ )
+ )
+ Text(
+ text = stringResource(id = text),
+ style = TextStyle(
+ fontSize = 16.sp,
+ )
+ )
+ }
+ }
+ }
+ LaunchedEffect(showToast) {
+ delay(5.seconds)
+ showToast = !showToast
+ }
+ }
+}
+
+@Preview
+@Composable
+private fun SatoToastPreview() {
+ SatoToast(
+ title = R.string.networkError,
+ text = R.string.networkErrorMessage,
+ icon = R.drawable.error_cross
+ )
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/satochip/satodimeapp/ui/components/vaults/VaultDrawerScreen.kt b/app/src/main/java/org/satochip/satodimeapp/ui/components/vaults/VaultDrawerScreen.kt
new file mode 100644
index 0000000..4d934e6
--- /dev/null
+++ b/app/src/main/java/org/satochip/satodimeapp/ui/components/vaults/VaultDrawerScreen.kt
@@ -0,0 +1,80 @@
+package org.satochip.satodimeapp.ui.components.vaults
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.MutableState
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import org.satochip.satodimeapp.R
+import org.satochip.satodimeapp.ui.components.shared.GifImage
+import org.satochip.satodimeapp.ui.components.shared.SatoButton
+import org.satochip.satodimeapp.ui.theme.SatoLightGrey
+
+@Composable
+fun VaultDrawerScreen(
+ closeSheet: () -> Unit,
+ closeDrawerButton: Boolean = false,
+ title: Int? = null,
+ message: Int,
+ image: Int? = null
+) {
+ Column(
+ modifier = Modifier
+ .height(350.dp)
+ .fillMaxSize(),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.Center
+ ) {
+ title?.let {
+ Text(
+ text = stringResource(it),
+ style = TextStyle(
+ color = SatoLightGrey,
+ fontSize = 26.sp
+ )
+ )
+ }
+
+ Spacer(modifier = Modifier.height(16.dp))
+ image?.let {
+ GifImage(
+ modifier = Modifier.size(125.dp),
+ image = image
+ )
+
+ Spacer(modifier = Modifier.height(16.dp))
+ }
+
+ Text(
+ text = stringResource(message),
+ style = TextStyle(
+ color = Color.Black,
+ fontSize = 16.sp
+ )
+ )
+ Spacer(modifier = Modifier.height(16.dp))
+ if (closeDrawerButton) {
+ SatoButton(
+ modifier = Modifier.fillMaxWidth(),
+ onClick = closeSheet,
+ text = R.string.cancel,
+ buttonColor = SatoLightGrey,
+ textColor = Color.Black,
+ shape = RoundedCornerShape(20)
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/satochip/satodimeapp/ui/components/vaults/VaultsBottomDrawer.kt b/app/src/main/java/org/satochip/satodimeapp/ui/components/vaults/VaultsBottomDrawer.kt
new file mode 100644
index 0000000..864189a
--- /dev/null
+++ b/app/src/main/java/org/satochip/satodimeapp/ui/components/vaults/VaultsBottomDrawer.kt
@@ -0,0 +1,26 @@
+package org.satochip.satodimeapp.ui.components.vaults
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.MutableState
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import org.satochip.satodimeapp.ui.components.shared.BottomSheet
+
+@Composable
+fun VaultsBottomDrawer(
+ showSheet: MutableState,
+ content: @Composable () -> Unit,
+ ) {
+ BottomSheet(showSheet = showSheet, modifier = Modifier) {
+ Box(
+ modifier = Modifier.padding(16.dp),
+ contentAlignment = Alignment.Center
+ ) {
+ content()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/satochip/satodimeapp/ui/theme/Color.kt b/app/src/main/java/org/satochip/satodimeapp/ui/theme/Color.kt
index f9a407f..816f41a 100644
--- a/app/src/main/java/org/satochip/satodimeapp/ui/theme/Color.kt
+++ b/app/src/main/java/org/satochip/satodimeapp/ui/theme/Color.kt
@@ -17,4 +17,8 @@ val LightBlue = Color(0xFF65BBE0)
val InfoDialogBackgroundColor = Color(0xFF27273C)
val MoreInfoButtonColor = Color(0xFF525684)
-val SatoGreen = Color(0xFF25B59A)
\ No newline at end of file
+val SatoGreen = Color(0xFF25B59A)
+val SatoLightGrey = Color(0xFFC6C6C6)
+val SatoGrey = Color(0xFF8F8E94)
+val SatoToastGrey = Color(0xFFCCCCD4)
+val SatoWarningOrange = Color(0xFFFE8B00)
\ No newline at end of file
diff --git a/app/src/main/java/org/satochip/satodimeapp/util/internetconnection/ConnectionChecker.kt b/app/src/main/java/org/satochip/satodimeapp/util/internetconnection/ConnectionChecker.kt
new file mode 100644
index 0000000..a01c2c7
--- /dev/null
+++ b/app/src/main/java/org/satochip/satodimeapp/util/internetconnection/ConnectionChecker.kt
@@ -0,0 +1,60 @@
+package org.satochip.satodimeapp.util.internetconnection
+
+import android.content.Context
+import android.net.ConnectivityManager
+import android.net.Network
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.launch
+
+class ConnectionChecker(
+ context: Context
+) {
+
+ enum class InternetStatus {
+ Available, Unavailable, Losing, Lost
+ }
+
+ private val connectivityManager =
+ context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
+
+ fun observe(): Flow {
+ return callbackFlow {
+ val callback = object : ConnectivityManager.NetworkCallback() {
+ override fun onAvailable(network: Network) {
+ super.onAvailable(network)
+ launch {
+ send(InternetStatus.Available)
+ }
+ }
+
+ override fun onLosing(network: Network, maxMsToLive: Int) {
+ super.onLosing(network, maxMsToLive)
+ launch {
+ send(InternetStatus.Losing)
+ }
+ }
+
+ override fun onLost(network: Network) {
+ super.onLost(network)
+ launch {
+ send(InternetStatus.Lost)
+ }
+ }
+
+ override fun onUnavailable() {
+ super.onUnavailable()
+ launch {
+ send(InternetStatus.Unavailable)
+ }
+ }
+ }
+ connectivityManager.registerDefaultNetworkCallback(callback)
+ awaitClose {
+ connectivityManager.unregisterNetworkCallback(callback)
+ }
+ }.distinctUntilChanged()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/error_cross.xml b/app/src/main/res/drawable/error_cross.xml
new file mode 100644
index 0000000..f8ca0c6
--- /dev/null
+++ b/app/src/main/res/drawable/error_cross.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/icon_check.png b/app/src/main/res/drawable/icon_check.png
new file mode 100644
index 0000000..ce29757
Binary files /dev/null and b/app/src/main/res/drawable/icon_check.png differ
diff --git a/app/src/main/res/drawable/icon_check_gif.gif b/app/src/main/res/drawable/icon_check_gif.gif
new file mode 100644
index 0000000..b99d526
Binary files /dev/null and b/app/src/main/res/drawable/icon_check_gif.gif differ
diff --git a/app/src/main/res/drawable/phone_icon.gif b/app/src/main/res/drawable/phone_icon.gif
new file mode 100644
index 0000000..304febd
Binary files /dev/null and b/app/src/main/res/drawable/phone_icon.gif differ
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index 3a89e93..bc72c97 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -145,4 +145,8 @@
Certificat sub-CA
Certificat root CA
Copié dans le presse-papier
+ Erreur réseau
+ Échec de la récupération des données.\nVeuillez vérifier votre connexion réseau.
+ Connecté
+ Vous êtes de nouveau en ligne.
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 99825a0..9036e1b 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -152,4 +152,8 @@ To facilitate maintenance, keep same key name whenever possible
Sub-CA certificate
Root CA certificate
Explore
+ Network Error
+ Data recovery failed.\nPlease check your network connection.
+ Connected
+ You are back online.
\ No newline at end of file