diff --git a/MobileSdk/build.gradle.kts b/MobileSdk/build.gradle.kts
index 62fb571..0507d87 100644
--- a/MobileSdk/build.gradle.kts
+++ b/MobileSdk/build.gradle.kts
@@ -118,7 +118,7 @@ android {
}
dependencies {
- api("com.spruceid.mobile.sdk.rs:mobilesdkrs:0.0.30")
+ api("com.spruceid.mobile.sdk.rs:mobilesdkrs:0.0.31")
//noinspection GradleCompatible
implementation("com.android.support:appcompat-v7:28.0.0")
/* Begin UI dependencies */
diff --git a/MobileSdk/src/main/java/com/spruceid/mobile/sdk/MDoc.kt b/MobileSdk/src/main/java/com/spruceid/mobile/sdk/MDoc.kt
index c7e1c53..7e2529e 100644
--- a/MobileSdk/src/main/java/com/spruceid/mobile/sdk/MDoc.kt
+++ b/MobileSdk/src/main/java/com/spruceid/mobile/sdk/MDoc.kt
@@ -1,14 +1,14 @@
package com.spruceid.mobile.sdk
import android.util.Log
-import com.spruceid.mobile.sdk.rs.MDoc as InnerMDoc
+import com.spruceid.mobile.sdk.rs.Mdoc as InnerMDoc
class MDoc(id: String, issuerAuth: ByteArray, val keyAlias: String) : BaseCredential(id) {
val inner: InnerMDoc
init {
try {
- inner = InnerMDoc.fromCbor(issuerAuth)
+ inner = InnerMDoc.fromCborEncodedDocument(issuerAuth, keyAlias)
} catch (e: Throwable) {
Log.e("MDoc.init", e.toString())
throw e
diff --git a/example/src/main/AndroidManifest.xml b/example/src/main/AndroidManifest.xml
index 4ace2ee..497c108 100644
--- a/example/src/main/AndroidManifest.xml
+++ b/example/src/main/AndroidManifest.xml
@@ -20,6 +20,7 @@
+
+
+
+
+
+
+
+
+
diff --git a/example/src/main/ic_launcher-playstore.png b/example/src/main/ic_launcher-playstore.png
new file mode 100644
index 0000000..f1304ef
Binary files /dev/null and b/example/src/main/ic_launcher-playstore.png differ
diff --git a/example/src/main/java/com/spruceid/mobilesdkexample/HomeView.kt b/example/src/main/java/com/spruceid/mobilesdkexample/HomeView.kt
index 7bcaf91..ae6bad2 100644
--- a/example/src/main/java/com/spruceid/mobilesdkexample/HomeView.kt
+++ b/example/src/main/java/com/spruceid/mobilesdkexample/HomeView.kt
@@ -30,6 +30,8 @@ import com.spruceid.mobilesdkexample.ui.theme.Bg
import com.spruceid.mobilesdkexample.ui.theme.Inter
import com.spruceid.mobilesdkexample.ui.theme.MobileSdkTheme
import com.spruceid.mobilesdkexample.verifier.VerifierHomeView
+import com.spruceid.mobilesdkexample.viewmodels.IRawCredentialsViewModel
+import com.spruceid.mobilesdkexample.viewmodels.RawCredentialsViewModelPreview
import com.spruceid.mobilesdkexample.wallet.WalletHomeView
enum class HomeTabs {
@@ -39,7 +41,8 @@ enum class HomeTabs {
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@Composable
fun HomeView(
- navController: NavController
+ navController: NavController,
+ rawCredentialsViewModel: IRawCredentialsViewModel
) {
var tab by remember {
mutableStateOf(HomeTabs.WALLET)
@@ -88,7 +91,10 @@ fun HomeView(
) {
Box(modifier = Modifier.padding(bottom = 30.dp)) {
if (tab == HomeTabs.WALLET) {
- WalletHomeView()
+ WalletHomeView(
+ navController,
+ rawCredentialsViewModel
+ )
} else {
VerifierHomeView(navController = navController)
}
@@ -101,6 +107,6 @@ fun HomeView(
fun HomeViewPreview() {
var navController: NavHostController = rememberNavController()
MobileSdkTheme {
- HomeView(navController)
+ HomeView(navController, RawCredentialsViewModelPreview())
}
}
\ No newline at end of file
diff --git a/example/src/main/java/com/spruceid/mobilesdkexample/MainActivity.kt b/example/src/main/java/com/spruceid/mobilesdkexample/MainActivity.kt
index a964878..92afdbd 100644
--- a/example/src/main/java/com/spruceid/mobilesdkexample/MainActivity.kt
+++ b/example/src/main/java/com/spruceid/mobilesdkexample/MainActivity.kt
@@ -6,16 +6,19 @@ import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
+import androidx.activity.viewModels
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Surface
import androidx.compose.ui.Modifier
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import com.spruceid.mobilesdkexample.db.AppDatabase
-import com.spruceid.mobilesdkexample.db.VerificationActivityLogsRepository
+import com.spruceid.mobilesdkexample.db.RawCredentialsRepository
import com.spruceid.mobilesdkexample.navigation.SetupNavGraph
import com.spruceid.mobilesdkexample.ui.theme.Bg
import com.spruceid.mobilesdkexample.ui.theme.MobileSdkTheme
+import com.spruceid.mobilesdkexample.viewmodels.IRawCredentialsViewModel
+import com.spruceid.mobilesdkexample.viewmodels.RawCredentialsViewModelFactory
class MainActivity : ComponentActivity() {
private lateinit var navController: NavHostController
@@ -38,9 +41,17 @@ class MainActivity : ComponentActivity() {
) {
navController = rememberNavController()
- SetupNavGraph(navController = navController)
+ val credentialsViewModel: IRawCredentialsViewModel by viewModels {
+ RawCredentialsViewModelFactory((application as MainApplication).rawCredentialsRepository)
+ }
+ SetupNavGraph(navController, credentialsViewModel)
}
}
}
}
+}
+
+class MainApplication : Application() {
+ val db by lazy { AppDatabase.getDatabase(applicationContext) }
+ val rawCredentialsRepository by lazy { RawCredentialsRepository(db.rawCredentialsDao()) }
}
\ No newline at end of file
diff --git a/example/src/main/java/com/spruceid/mobilesdkexample/db/AppDatabase.kt b/example/src/main/java/com/spruceid/mobilesdkexample/db/AppDatabase.kt
index 45f0214..f235e32 100644
--- a/example/src/main/java/com/spruceid/mobilesdkexample/db/AppDatabase.kt
+++ b/example/src/main/java/com/spruceid/mobilesdkexample/db/AppDatabase.kt
@@ -6,10 +6,17 @@ import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
-@Database(entities = [VerificationActivityLogs::class], version = 1)
+@Database(
+ entities = [
+ VerificationActivityLogs::class,
+ RawCredentials::class,
+ ],
+ version = 2
+)
@TypeConverters(*[DateConverter::class])
abstract class AppDatabase : RoomDatabase() {
abstract fun verificationActivityLogsDao(): VerificationActivityLogsDao
+ abstract fun rawCredentialsDao(): RawCredentialsDao
companion object {
@Volatile
@@ -21,7 +28,7 @@ abstract class AppDatabase : RoomDatabase() {
Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
- "verification_activity_logs",
+ "referenceAppDb",
)
.allowMainThreadQueries()
.build()
diff --git a/example/src/main/java/com/spruceid/mobilesdkexample/db/Daos.kt b/example/src/main/java/com/spruceid/mobilesdkexample/db/Daos.kt
index 7d4b976..1f11174 100644
--- a/example/src/main/java/com/spruceid/mobilesdkexample/db/Daos.kt
+++ b/example/src/main/java/com/spruceid/mobilesdkexample/db/Daos.kt
@@ -12,3 +12,15 @@ interface VerificationActivityLogsDao {
@Query("SELECT * FROM verification_activity_logs")
fun getAllVerificationActivityLogs(): List
}
+
+@Dao
+interface RawCredentialsDao {
+ @Insert
+ suspend fun insertRawCredential(rawCredential: RawCredentials)
+
+ @Query("SELECT * FROM raw_credentials")
+ fun getAllRawCredentials(): List
+
+ @Query("DELETE FROM raw_credentials")
+ fun deleteAllRawCredentials(): Int
+}
diff --git a/example/src/main/java/com/spruceid/mobilesdkexample/db/Entities.kt b/example/src/main/java/com/spruceid/mobilesdkexample/db/Entities.kt
index 238dcd9..be9707a 100644
--- a/example/src/main/java/com/spruceid/mobilesdkexample/db/Entities.kt
+++ b/example/src/main/java/com/spruceid/mobilesdkexample/db/Entities.kt
@@ -13,3 +13,9 @@ data class VerificationActivityLogs(
val expirationDate: Date,
val status: String,
)
+
+@Entity(tableName = "raw_credentials")
+data class RawCredentials(
+ @PrimaryKey(autoGenerate = true) val id: Long = 0,
+ val rawCredential: String,
+)
\ No newline at end of file
diff --git a/example/src/main/java/com/spruceid/mobilesdkexample/db/Repositories.kt b/example/src/main/java/com/spruceid/mobilesdkexample/db/Repositories.kt
index cec2bdd..67048f6 100644
--- a/example/src/main/java/com/spruceid/mobilesdkexample/db/Repositories.kt
+++ b/example/src/main/java/com/spruceid/mobilesdkexample/db/Repositories.kt
@@ -15,3 +15,22 @@ class VerificationActivityLogsRepository(private val verificationActivityLogsDao
return verificationActivityLogsDao.getAllVerificationActivityLogs()
}
}
+
+class RawCredentialsRepository(private val rawCredentialsDao: RawCredentialsDao) {
+ val rawCredentials: List = rawCredentialsDao.getAllRawCredentials()
+
+ @WorkerThread
+ suspend fun insertRawCredential(credential: RawCredentials) {
+ rawCredentialsDao.insertRawCredential(credential)
+ }
+
+ @WorkerThread
+ suspend fun getRawCredentials(): List {
+ return rawCredentialsDao.getAllRawCredentials()
+ }
+
+ @WorkerThread
+ suspend fun deleteAllRawCredentials(): Int {
+ return rawCredentialsDao.deleteAllRawCredentials()
+ }
+}
\ No newline at end of file
diff --git a/example/src/main/java/com/spruceid/mobilesdkexample/navigation/Screen.kt b/example/src/main/java/com/spruceid/mobilesdkexample/navigation/Screen.kt
index 0c2f11f..790446b 100644
--- a/example/src/main/java/com/spruceid/mobilesdkexample/navigation/Screen.kt
+++ b/example/src/main/java/com/spruceid/mobilesdkexample/navigation/Screen.kt
@@ -5,6 +5,9 @@ const val VERIFY_DL_PATH = "verify_dl"
const val VERIFY_EA_PATH = "verify_ea"
const val VERIFY_VC_PATH = "verify_vc"
const val VERIFIER_SETTINGS_HOME_PATH = "verifier_settings_home"
+const val WALLET_SETTINGS_HOME_PATH = "wallet_settings_home"
+const val ADD_TO_WALLET_PATH = "add_to_wallet/{rawCredential}"
+const val OID4VP_PATH = "oid4vp/{params}"
sealed class Screen(val route: String) {
@@ -13,4 +16,7 @@ sealed class Screen(val route: String) {
object VerifyEAScreen : Screen(VERIFY_EA_PATH)
object VerifyVCScreen : Screen(VERIFY_VC_PATH)
object VerifierSettingsHomeScreen : Screen(VERIFIER_SETTINGS_HOME_PATH)
+ object WalletSettingsHomeScreen : Screen(WALLET_SETTINGS_HOME_PATH)
+ object AddToWalletScreen : Screen(ADD_TO_WALLET_PATH)
+ object OID4VPScreen : Screen(OID4VP_PATH)
}
\ No newline at end of file
diff --git a/example/src/main/java/com/spruceid/mobilesdkexample/navigation/SetupNavGraph.kt b/example/src/main/java/com/spruceid/mobilesdkexample/navigation/SetupNavGraph.kt
index 3a23e8b..2bc14a2 100644
--- a/example/src/main/java/com/spruceid/mobilesdkexample/navigation/SetupNavGraph.kt
+++ b/example/src/main/java/com/spruceid/mobilesdkexample/navigation/SetupNavGraph.kt
@@ -1,18 +1,24 @@
package com.spruceid.mobilesdkexample.navigation
+import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
+import androidx.navigation.navDeepLink
import com.spruceid.mobilesdkexample.HomeView
import com.spruceid.mobilesdkexample.verifier.VerifyDLView
import com.spruceid.mobilesdkexample.verifier.VerifyEAView
import com.spruceid.mobilesdkexample.verifier.VerifyVCView
import com.spruceid.mobilesdkexample.verifiersettings.VerifierSettingsHomeView
+import com.spruceid.mobilesdkexample.viewmodels.IRawCredentialsViewModel
+import com.spruceid.mobilesdkexample.wallet.AddToWalletView
+import com.spruceid.mobilesdkexample.walletsettings.WalletSettingsHomeView
@Composable
fun SetupNavGraph(
- navController: NavHostController
+ navController: NavHostController,
+ rawCredentialsViewModel: IRawCredentialsViewModel
) {
NavHost(
navController = navController,
@@ -21,7 +27,7 @@ fun SetupNavGraph(
composable(
route = Screen.HomeScreen.route,
) {
- HomeView(navController)
+ HomeView(navController, rawCredentialsViewModel)
}
composable(
route = Screen.VerifyDLScreen.route,
@@ -43,6 +49,32 @@ fun SetupNavGraph(
) {
VerifierSettingsHomeView(navController)
}
-
+ composable(
+ route = Screen.WalletSettingsHomeScreen.route,
+ ) {
+ WalletSettingsHomeView(navController, rawCredentialsViewModel)
+ }
+ composable(
+ route = Screen.AddToWalletScreen.route,
+ deepLinks = listOf(
+ navDeepLink {
+ uriPattern = "spruceid://?sd-jwt={rawCredential}"
+ }
+ )
+ ) { backStackEntry ->
+ val rawCredential = backStackEntry.arguments?.getString("rawCredential")!!
+ AddToWalletView(navController, rawCredential, rawCredentialsViewModel)
+ }
+ composable(
+ route = Screen.OID4VPScreen.route,
+ deepLinks = listOf(
+ navDeepLink {
+ uriPattern = "oid4vp://{params}"
+ }
+ )
+ ) {
+ // val params = backStackEntry.arguments?.getString("params")!!
+ Text(text = "@TODO: OID4VP flow")
+ }
}
}
diff --git a/example/src/main/java/com/spruceid/mobilesdkexample/ui/theme/Color.kt b/example/src/main/java/com/spruceid/mobilesdkexample/ui/theme/Color.kt
index a0d932c..d293b82 100644
--- a/example/src/main/java/com/spruceid/mobilesdkexample/ui/theme/Color.kt
+++ b/example/src/main/java/com/spruceid/mobilesdkexample/ui/theme/Color.kt
@@ -7,7 +7,9 @@ val Primary = Color(0xFFF7F7F5)
val Bg = Color(0xFFFDFDFC)
val CredentialBorder = Color(0xFFE6E1D6)
val CodeBorder = Color(0xff949494)
+val CTAButtonGreen = Color(0xFF087455)
val GreenValid = Color(0xFF059669)
+val SecondaryButtonRed = Color(0xFFE11D48)
val TextBody = Color(0xFF57534E)
val TextHeader = Color(0xFF0C0A09)
val TextOnPrimary = Color(0xFFA8A29E)
diff --git a/example/src/main/java/com/spruceid/mobilesdkexample/verifiersettings/VerifierSettingsHomeView.kt b/example/src/main/java/com/spruceid/mobilesdkexample/verifiersettings/VerifierSettingsHomeView.kt
index f140efc..051bd90 100644
--- a/example/src/main/java/com/spruceid/mobilesdkexample/verifiersettings/VerifierSettingsHomeView.kt
+++ b/example/src/main/java/com/spruceid/mobilesdkexample/verifiersettings/VerifierSettingsHomeView.kt
@@ -1,9 +1,6 @@
package com.spruceid.mobilesdkexample.verifiersettings
-import android.graphics.Bitmap
import androidx.compose.foundation.Image
-import androidx.compose.foundation.background
-import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
@@ -11,26 +8,17 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.layout.width
-import androidx.compose.foundation.rememberScrollState
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.List
-import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.State
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.draw.clip
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.draw.scale
import androidx.compose.ui.res.painterResource
@@ -40,18 +28,9 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
import com.spruceid.mobilesdkexample.R
-import com.spruceid.mobilesdkexample.navigation.Screen
import com.spruceid.mobilesdkexample.ui.theme.Inter
-import com.spruceid.mobilesdkexample.ui.theme.Primary
import com.spruceid.mobilesdkexample.ui.theme.TextBody
import com.spruceid.mobilesdkexample.ui.theme.TextHeader
-import com.spruceid.mobilesdkexample.ui.theme.TextOnPrimary
-import com.spruceid.mobilesdkexample.ui.theme.VerifierRequestBadgeBinaryBorder
-import com.spruceid.mobilesdkexample.ui.theme.VerifierRequestBadgeBinaryFill
-import com.spruceid.mobilesdkexample.ui.theme.VerifierRequestBadgeBinaryText
-import com.spruceid.mobilesdkexample.ui.theme.VerifierRequestBadgeFieldBorder
-import com.spruceid.mobilesdkexample.ui.theme.VerifierRequestBadgeFieldFill
-import com.spruceid.mobilesdkexample.ui.theme.VerifierRequestBadgeFieldText
enum class VerifierSubSettings {
VERIFICATION_ACTIVITY_LOG,
@@ -182,89 +161,3 @@ fun VerifierSettingsHomeBody(
VerificationActivityLogsScreen()
}
}
-
-@Composable
-fun VerifierListItem(
- title: String,
- description: String,
- binary: Boolean,
- fields: Int,
- modifier: Modifier = Modifier
-) {
- Column(
- modifier = modifier.padding(vertical = 12.dp)
- ) {
- Row(
- modifier = Modifier.fillMaxWidth(),
- verticalAlignment = Alignment.CenterVertically
- ) {
- Text(
- text = title,
- fontFamily = Inter,
- fontWeight = FontWeight.SemiBold,
- fontSize = 18.sp,
- color = TextHeader,
- modifier = Modifier.weight(2f)
- )
- VerifierListItemTag(binary = binary, fields = fields)
- Spacer(modifier = Modifier.weight(1f))
- Image(
- painter = painterResource(id = R.drawable.arrow_right),
- contentDescription = stringResource(id = R.string.arrow_right),
- modifier = Modifier.width(24.dp)
- )
- }
- Text(
- text = description,
- fontFamily = Inter,
- fontWeight = FontWeight.Normal,
- fontSize = 14.sp,
- color = TextBody,
- )
- HorizontalDivider()
- }
-}
-
-@Composable
-fun VerifierListItemTag(
- binary: Boolean,
- fields: Int
-) {
- if (binary) {
- Text(
- text = "Binary",
- fontFamily = Inter,
- fontWeight = FontWeight.Normal,
- fontSize = 12.sp,
- color = VerifierRequestBadgeBinaryText,
- modifier = Modifier
- .border(
- width = 1.dp,
- color = VerifierRequestBadgeBinaryBorder,
- shape = RoundedCornerShape(8.dp)
- )
- .clip(shape = RoundedCornerShape(8.dp, 8.dp, 8.dp, 8.dp))
- .background(VerifierRequestBadgeBinaryFill)
- .padding(vertical = 2.dp)
- .padding(horizontal = 8.dp),
- )
- } else {
- Text(
- text = "$fields Fields",
- fontFamily = Inter,
- fontWeight = FontWeight.Normal,
- fontSize = 12.sp,
- color = VerifierRequestBadgeFieldText,
- modifier = Modifier
- .border(
- width = 1.dp,
- color = VerifierRequestBadgeFieldBorder,
- shape = RoundedCornerShape(8.dp)
- )
- .clip(shape = RoundedCornerShape(8.dp, 8.dp, 8.dp, 8.dp))
- .background(VerifierRequestBadgeFieldFill)
- .padding(vertical = 2.dp)
- .padding(horizontal = 8.dp),
- )
- }
-}
\ No newline at end of file
diff --git a/example/src/main/java/com/spruceid/mobilesdkexample/viewmodels/RawCredentialsViewModel.kt b/example/src/main/java/com/spruceid/mobilesdkexample/viewmodels/RawCredentialsViewModel.kt
new file mode 100644
index 0000000..e759a44
--- /dev/null
+++ b/example/src/main/java/com/spruceid/mobilesdkexample/viewmodels/RawCredentialsViewModel.kt
@@ -0,0 +1,64 @@
+package com.spruceid.mobilesdkexample.viewmodels
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.viewModelScope
+import com.spruceid.mobilesdkexample.db.RawCredentials
+import com.spruceid.mobilesdkexample.db.RawCredentialsRepository
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.launch
+
+abstract class IRawCredentialsViewModel : ViewModel(){
+ abstract val rawCredentials: StateFlow>
+ abstract suspend fun saveRawCredential(rawCredential: RawCredentials)
+ abstract suspend fun deleteAllRawCredentials()
+ abstract fun generateRawCredentialsCSV(): String
+}
+
+class RawCredentialsViewModel(private val rawCredentialsRepository: RawCredentialsRepository) : IRawCredentialsViewModel() {
+ private val _rawCredentials = MutableStateFlow(listOf())
+ override val rawCredentials = _rawCredentials.asStateFlow()
+
+ init {
+ viewModelScope.launch {
+ _rawCredentials.value = rawCredentialsRepository.rawCredentials
+ }
+ }
+
+ override suspend fun saveRawCredential(rawCredential: RawCredentials) {
+ rawCredentialsRepository.insertRawCredential(rawCredential)
+ _rawCredentials.value = rawCredentialsRepository.getRawCredentials()
+ }
+
+ override suspend fun deleteAllRawCredentials() {
+ rawCredentialsRepository.deleteAllRawCredentials()
+ _rawCredentials.value = rawCredentialsRepository.getRawCredentials()
+ }
+
+ override fun generateRawCredentialsCSV(): String {
+ val heading = "ID, Raw Credential\n"
+ return heading +
+ rawCredentials.value.joinToString("\n") {
+ "${it.id}, ${it.rawCredential}"
+ }
+ }
+}
+
+class RawCredentialsViewModelFactory(private val repository: RawCredentialsRepository) : ViewModelProvider.NewInstanceFactory() {
+ @Suppress("UNCHECKED_CAST")
+ override fun create(modelClass: Class): T = RawCredentialsViewModel(repository) as T
+}
+
+class RawCredentialsViewModelPreview(override val rawCredentials: StateFlow> = MutableStateFlow(
+ emptyList()
+)) : IRawCredentialsViewModel() {
+ override suspend fun saveRawCredential(credential: RawCredentials) {}
+
+ override suspend fun deleteAllRawCredentials() {}
+
+ override fun generateRawCredentialsCSV(): String {
+ return ""
+ }
+}
\ No newline at end of file
diff --git a/example/src/main/java/com/spruceid/mobilesdkexample/wallet/AchievementCredentialItem.kt b/example/src/main/java/com/spruceid/mobilesdkexample/wallet/AchievementCredentialItem.kt
new file mode 100644
index 0000000..41dd83f
--- /dev/null
+++ b/example/src/main/java/com/spruceid/mobilesdkexample/wallet/AchievementCredentialItem.kt
@@ -0,0 +1,233 @@
+package com.spruceid.mobilesdkexample.wallet
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.border
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.IntrinsicSize
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.ModalBottomSheet
+import androidx.compose.material3.Text
+import androidx.compose.material3.rememberModalBottomSheetState
+import androidx.compose.runtime.Composable
+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.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import com.spruceid.mobile.sdk.rs.decodeRevealSdJwt
+import com.spruceid.mobilesdkexample.R
+import com.spruceid.mobilesdkexample.ui.theme.Bg
+import com.spruceid.mobilesdkexample.ui.theme.CredentialBorder
+import com.spruceid.mobilesdkexample.ui.theme.GreenValid
+import com.spruceid.mobilesdkexample.ui.theme.Inter
+import com.spruceid.mobilesdkexample.ui.theme.TextBody
+import com.spruceid.mobilesdkexample.ui.theme.TextHeader
+import org.json.JSONArray
+import org.json.JSONObject
+import java.time.OffsetDateTime
+import java.time.format.DateTimeFormatter
+
+class AchievementCredentialItem {
+ private var credential: JSONObject
+
+ constructor(credential: JSONObject) {
+ this.credential = credential
+ }
+
+ constructor(rawCredential: String) {
+ val decodedSdJwt = decodeRevealSdJwt(rawCredential)
+ this.credential = JSONObject(decodedSdJwt)
+ }
+
+ @Composable
+ fun listComponent() {
+ val achievementName = keyPathFinder(credential, mutableListOf("achievement", "name")).toString()
+ val issuerName = keyPathFinder(credential, mutableListOf("issuer", "name")).toString()
+
+ Row(
+ Modifier.height(intrinsicSize = IntrinsicSize.Max)
+ ) {
+ // Leading icon
+ Column {
+ // Title
+ Text(
+ text = achievementName,
+ fontFamily = Inter,
+ fontWeight = FontWeight.Medium,
+ fontSize = 22.sp,
+ color = TextHeader,
+ modifier = Modifier.padding(bottom = 8.dp)
+ )
+
+ // Description
+ Column {
+ Text(
+ text = issuerName,
+ fontFamily = Inter,
+ fontWeight = FontWeight.Normal,
+ fontSize = 14.sp,
+ color = TextBody
+ )
+ Spacer(modifier = Modifier.height(16.dp))
+ Row(verticalAlignment = Alignment.CenterVertically) {
+ Image(
+ painter = painterResource(id = R.drawable.valid),
+ contentDescription = stringResource(id = R.string.valid),
+ modifier = Modifier.width(15.dp)
+ )
+ Text(
+ text = "Valid",
+ fontFamily = Inter,
+ fontWeight = FontWeight.Medium,
+ fontSize = 10.sp,
+ color = GreenValid
+ )
+ }
+ }
+ }
+ Spacer(modifier = Modifier.weight(1.0f))
+ // Trailing action button
+ }
+ }
+
+ @Composable
+ fun detailsComponent() {
+ val awardedDate = keyPathFinder(credential, mutableListOf("awardedDate")).toString()
+ val ISO8601DateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss[.SSS]Z")
+ val parsedDate = OffsetDateTime.parse(awardedDate, ISO8601DateFormat)
+ val dateTimeFormatter = DateTimeFormatter.ofPattern("MMM dd, yyyy 'at' h:mm a")
+
+ val identity = keyPathFinder(credential, mutableListOf("credentialSubject", "identity")) as JSONArray
+ val details = MutableList(identity.length()) { i ->
+ val obj = identity.get(i) as JSONObject
+ Pair(obj["identityType"].toString(), obj["identityHash"].toString())
+ }
+
+ details.add(0, Pair("awardedDate", parsedDate.format(dateTimeFormatter)))
+
+ Row(
+ Modifier.padding(horizontal = 12.dp)
+ ) {
+ Column {
+ details.map { detail ->
+ Text(
+ text = splitCamelCase(detail.first),
+ fontFamily = Inter,
+ fontWeight = FontWeight.Normal,
+ fontSize = 14.sp,
+ color = TextBody,
+ modifier = Modifier.padding(top = 10.dp)
+ )
+ Text(
+ text = detail.second,
+ fontFamily = Inter,
+ fontSize = 14.sp
+ )
+ }
+ }
+ Spacer(modifier = Modifier.weight(1.0f))
+ }
+ }
+
+ @Composable
+ fun borderedListComponent() {
+ Box(
+ Modifier
+ .fillMaxWidth()
+ .border(
+ width = 1.dp,
+ color = CredentialBorder,
+ shape = RoundedCornerShape(8.dp)
+ )
+ .padding(12.dp)
+ ) {
+ listComponent()
+ }
+ }
+
+ @OptIn(ExperimentalMaterial3Api::class)
+ @Composable
+ fun component() {
+ var sheetOpen by remember {
+ mutableStateOf(false)
+ }
+
+ Column(
+ Modifier
+ .padding(vertical = 10.dp)
+ .border(
+ width = 1.dp,
+ color = CredentialBorder,
+ shape = RoundedCornerShape(8.dp)
+ )
+ ) {
+ Box(
+ Modifier
+ .padding(all = 12.dp)
+ .clickable {
+ sheetOpen = true
+ }
+ ) {
+// GenericCredentialListItem(credentialPack = credentialPack)
+ listComponent()
+ }
+ }
+ if (sheetOpen) {
+ ModalBottomSheet(
+ onDismissRequest = {
+ sheetOpen = false
+ },
+ modifier = Modifier
+ .fillMaxHeight(0.8f),
+ sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true),
+ dragHandle = null,
+ containerColor = Bg,
+ shape = RoundedCornerShape(8.dp)
+ ) {
+ Column(
+ Modifier
+ .padding(12.dp)
+ ) {
+ Text(
+ text = "Review Info",
+ textAlign = TextAlign.Center,
+ fontFamily = Inter,
+ fontWeight = FontWeight.Bold,
+ fontSize = 24.sp,
+ color = TextHeader,
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(vertical = 20.dp),
+ )
+ borderedListComponent()
+ Column(
+ Modifier
+ .verticalScroll(rememberScrollState())
+ .weight(1f, false)
+ ) {
+ detailsComponent()
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/example/src/main/java/com/spruceid/mobilesdkexample/wallet/AddToWalletView.kt b/example/src/main/java/com/spruceid/mobilesdkexample/wallet/AddToWalletView.kt
new file mode 100644
index 0000000..63f3dc8
--- /dev/null
+++ b/example/src/main/java/com/spruceid/mobilesdkexample/wallet/AddToWalletView.kt
@@ -0,0 +1,131 @@
+package com.spruceid.mobilesdkexample.wallet
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.navigation.NavHostController
+import androidx.navigation.compose.rememberNavController
+import com.spruceid.mobilesdkexample.db.RawCredentials
+import com.spruceid.mobilesdkexample.ui.theme.CTAButtonGreen
+import com.spruceid.mobilesdkexample.ui.theme.Inter
+import com.spruceid.mobilesdkexample.ui.theme.MobileSdkTheme
+import com.spruceid.mobilesdkexample.ui.theme.SecondaryButtonRed
+import com.spruceid.mobilesdkexample.ui.theme.TextHeader
+import com.spruceid.mobilesdkexample.viewmodels.IRawCredentialsViewModel
+import com.spruceid.mobilesdkexample.viewmodels.RawCredentialsViewModelPreview
+import kotlinx.coroutines.launch
+
+@Composable
+fun AddToWalletView(
+ navController: NavHostController,
+ rawCredential: String,
+ rawCredentialsViewModel: IRawCredentialsViewModel
+) {
+ val credential = AchievementCredentialItem(rawCredential)
+ val scope = rememberCoroutineScope()
+
+ Column(
+ Modifier
+ .padding(all = 20.dp)
+ .padding(top = 20.dp)
+ ) {
+ Text(
+ text = "Review Info",
+ textAlign = TextAlign.Center,
+ fontFamily = Inter,
+ fontWeight = FontWeight.Bold,
+ fontSize = 24.sp,
+ color = TextHeader,
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(vertical = 20.dp),
+ )
+
+ credential.borderedListComponent()
+
+ Column(
+ Modifier
+ .verticalScroll(rememberScrollState())
+ .weight(1f, false)
+ ) {
+ credential.detailsComponent()
+ }
+
+ Spacer(Modifier.weight(1f))
+
+ Button(
+ onClick = {
+ scope.launch {
+ rawCredentialsViewModel.saveRawCredential(RawCredentials(
+ rawCredential = rawCredential
+ ))
+ navController.popBackStack()
+ }
+ },
+ shape = RoundedCornerShape(5.dp),
+ colors = ButtonDefaults.buttonColors(
+ containerColor = CTAButtonGreen,
+ contentColor = Color.White,
+ ),
+ modifier = Modifier
+ .fillMaxWidth()
+ ) {
+ Text(
+ text = "Add to Wallet",
+ fontFamily = Inter,
+ fontWeight = FontWeight.SemiBold,
+ color = Color.White,
+ )
+ }
+
+ Button(
+ onClick = {
+ navController.popBackStack()
+ },
+ shape = RoundedCornerShape(5.dp),
+ colors = ButtonDefaults.buttonColors(
+ containerColor = Color.Transparent,
+ contentColor = SecondaryButtonRed,
+ ),
+ modifier = Modifier
+ .fillMaxWidth()
+ ) {
+ Text(
+ text = "Close",
+ fontFamily = Inter,
+ fontWeight = FontWeight.SemiBold,
+ color = SecondaryButtonRed,
+ )
+ }
+ }
+}
+
+@Preview(showBackground = true)
+@Composable
+fun AddToWalletPreview() {
+ var navController: NavHostController = rememberNavController()
+
+ MobileSdkTheme {
+ AddToWalletView(
+ navController = navController,
+ rawCredential = "{}",
+ rawCredentialsViewModel = RawCredentialsViewModelPreview()
+ )
+ }
+}
\ No newline at end of file
diff --git a/example/src/main/java/com/spruceid/mobilesdkexample/wallet/WalletHomeView.kt b/example/src/main/java/com/spruceid/mobilesdkexample/wallet/WalletHomeView.kt
index 471f824..6e3f685 100644
--- a/example/src/main/java/com/spruceid/mobilesdkexample/wallet/WalletHomeView.kt
+++ b/example/src/main/java/com/spruceid/mobilesdkexample/wallet/WalletHomeView.kt
@@ -1,40 +1,58 @@
package com.spruceid.mobilesdkexample.wallet
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.rememberScrollState
-import androidx.compose.foundation.verticalScroll
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.items
+import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
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 androidx.navigation.NavController
+import com.spruceid.mobilesdkexample.R
+import com.spruceid.mobilesdkexample.navigation.Screen
import com.spruceid.mobilesdkexample.ui.theme.Inter
import com.spruceid.mobilesdkexample.ui.theme.TextHeader
-import com.spruceid.mobilesdkexample.ui.theme.MobileSdkTheme
+import com.spruceid.mobilesdkexample.ui.theme.Primary
import com.spruceid.mobilesdkexample.utils.vcs
import com.spruceid.mobilesdkexample.utils.mdocBase64
+import com.spruceid.mobilesdkexample.viewmodels.IRawCredentialsViewModel
@Composable
-fun WalletHomeView() {
+fun WalletHomeView(
+ navController: NavController,
+ rawCredentialsViewModel: IRawCredentialsViewModel
+) {
Column(
Modifier
.padding(all = 20.dp)
.padding(top = 20.dp)
) {
- WalletHomeHeader()
- WalletHomeBody()
+ WalletHomeHeader(navController = navController)
+ WalletHomeBody(rawCredentialsViewModel = rawCredentialsViewModel)
}
}
@Composable
-fun WalletHomeHeader() {
+fun WalletHomeHeader(navController: NavController) {
Row(verticalAlignment = Alignment.CenterVertically) {
Text(
text = "Spruce Wallet",
@@ -44,28 +62,46 @@ fun WalletHomeHeader() {
color = TextHeader
)
Spacer(Modifier.weight(1f))
+ Box(
+ contentAlignment = Alignment.Center,
+ modifier = Modifier
+ .width(36.dp)
+ .height(36.dp)
+ .padding(start = 4.dp)
+ .clip(shape = RoundedCornerShape(8.dp))
+ .background(Primary)
+ .clickable {
+ navController.navigate(Screen.WalletSettingsHomeScreen.route)
+ }
+ ) {
+ Image(
+ painter = painterResource(id = R.drawable.user),
+ contentDescription = stringResource(id = R.string.user),
+ modifier = Modifier
+ .width(20.dp)
+ .height(20.dp)
+ )
+ }
}
}
@Composable
-fun WalletHomeBody() {
- Column(
+fun WalletHomeBody(rawCredentialsViewModel: IRawCredentialsViewModel) {
+ val rawCredentials by rawCredentialsViewModel.rawCredentials.collectAsState()
+
+ LazyColumn(
Modifier
.fillMaxWidth()
- .verticalScroll(rememberScrollState())
.padding(top = 20.dp)
) {
- vcs.map { vc ->
- GenericCredentialListItems(vc = vc)
+ items(rawCredentials) { rawCredential ->
+ AchievementCredentialItem(rawCredential.rawCredential).component()
+ }
+ item {
+ vcs.map { vc ->
+ GenericCredentialListItems(vc = vc)
+ }
+ ShareableCredentialListItems(mdocBase64 = mdocBase64)
}
- ShareableCredentialListItems(mdocBase64 = mdocBase64)
}
}
-
-@Preview(showBackground = true)
-@Composable
-fun WalletHomeViewPreview() {
- MobileSdkTheme {
- WalletHomeView()
- }
-}
\ No newline at end of file
diff --git a/example/src/main/java/com/spruceid/mobilesdkexample/wallet/WalletUtils.kt b/example/src/main/java/com/spruceid/mobilesdkexample/wallet/WalletUtils.kt
index e68ed0b..e3ce68a 100644
--- a/example/src/main/java/com/spruceid/mobilesdkexample/wallet/WalletUtils.kt
+++ b/example/src/main/java/com/spruceid/mobilesdkexample/wallet/WalletUtils.kt
@@ -10,6 +10,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.asImageBitmap
import androidx.core.content.ContextCompat
+import org.json.JSONObject
@Composable
fun BitmapImage(
@@ -48,4 +49,29 @@ fun checkAndRequestBluetoothPermissions(
// Request permissions
launcher.launch(permissions)
}
+}
+
+fun keyPathFinder(json: Any, path: MutableList): Any {
+ try {
+ val firstKey = path.first()
+ val element = (json as JSONObject)[firstKey]
+ path.removeAt(0)
+ if (path.isNotEmpty()) {
+ return keyPathFinder(element, path)
+ }
+ return element
+ } catch (e: Exception) {
+ return ""
+ }
+}
+
+fun splitCamelCase(s: String): String {
+ return s.replace(
+ String.format(
+ "%s|%s|%s",
+ "(?<=[A-Z])(?=[A-Z][a-z])",
+ "(?<=[^A-Z])(?=[A-Z])",
+ "(?<=[A-Za-z])(?=[^A-Za-z])"
+ ).toRegex(), " "
+ ).replaceFirstChar(Char::titlecase)
}
\ No newline at end of file
diff --git a/example/src/main/java/com/spruceid/mobilesdkexample/walletsettings/WalletSettingsHomeView.kt b/example/src/main/java/com/spruceid/mobilesdkexample/walletsettings/WalletSettingsHomeView.kt
new file mode 100644
index 0000000..bf35efe
--- /dev/null
+++ b/example/src/main/java/com/spruceid/mobilesdkexample/walletsettings/WalletSettingsHomeView.kt
@@ -0,0 +1,114 @@
+package com.spruceid.mobilesdkexample.walletsettings
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.rotate
+import androidx.compose.ui.draw.scale
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.navigation.NavController
+import com.spruceid.mobilesdkexample.R
+import com.spruceid.mobilesdkexample.ui.theme.Inter
+import com.spruceid.mobilesdkexample.ui.theme.TextHeader
+import com.spruceid.mobilesdkexample.ui.theme.VerifiedRedInvalid
+import com.spruceid.mobilesdkexample.viewmodels.IRawCredentialsViewModel
+import kotlinx.coroutines.launch
+
+@Composable
+fun WalletSettingsHomeView(
+ navController: NavController,
+ rawCredentialsViewModel: IRawCredentialsViewModel
+) {
+ Column(
+ Modifier
+ .padding(all = 20.dp)
+ .padding(top = 20.dp)
+ ) {
+ WalletSettingsHomeHeader(
+ onBack = {
+ navController.popBackStack()
+ }
+ )
+ WalletSettingsHomeBody(rawCredentialsViewModel)
+ }
+}
+
+@Composable
+fun WalletSettingsHomeHeader(
+ onBack: () -> Unit
+) {
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ modifier = Modifier.clickable {
+ onBack()
+ }
+ ) {
+ Image(
+ painter = painterResource(id = R.drawable.chevron),
+ contentDescription = stringResource(id = R.string.chevron),
+ modifier = Modifier
+ .rotate(180f)
+ .scale(0.7f)
+ )
+ Text(
+ text = "Wallet Settings",
+ fontFamily = Inter,
+ fontWeight = FontWeight.SemiBold,
+ fontSize = 24.sp,
+ color = TextHeader,
+ modifier = Modifier.padding(start = 10.dp)
+ )
+ Spacer(Modifier.weight(1f))
+ }
+
+}
+
+@Composable
+fun WalletSettingsHomeBody(rawCredentialsViewModel: IRawCredentialsViewModel) {
+ val scope = rememberCoroutineScope()
+
+ Column(
+ Modifier
+ .padding(horizontal = 20.dp)
+ .padding(top = 10.dp),
+ ) {
+ Button(
+ onClick = {
+ scope.launch {
+ rawCredentialsViewModel.deleteAllRawCredentials()
+ }
+ },
+ shape = RoundedCornerShape(5.dp),
+ colors = ButtonDefaults.buttonColors(
+ containerColor = VerifiedRedInvalid,
+ contentColor = Color.White,
+ ),
+ modifier = Modifier
+ .fillMaxWidth()
+ ) {
+ Text(
+ text = "Delete all added credentials",
+ fontFamily = Inter,
+ fontWeight = FontWeight.SemiBold,
+ color = Color.White,
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/example/src/main/res/drawable/ic_launcher_background.xml b/example/src/main/res/drawable/ic_launcher_background.xml
index 07d5da9..ca3826a 100644
--- a/example/src/main/res/drawable/ic_launcher_background.xml
+++ b/example/src/main/res/drawable/ic_launcher_background.xml
@@ -1,170 +1,74 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ xmlns:android="http://schemas.android.com/apk/res/android">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/example/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/example/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..036d09b
--- /dev/null
+++ b/example/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/example/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/example/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..036d09b
--- /dev/null
+++ b/example/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/example/src/main/res/mipmap-anydpi/ic_launcher.xml b/example/src/main/res/mipmap-anydpi/ic_launcher.xml
deleted file mode 100644
index 6f3b755..0000000
--- a/example/src/main/res/mipmap-anydpi/ic_launcher.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/example/src/main/res/mipmap-anydpi/ic_launcher_round.xml b/example/src/main/res/mipmap-anydpi/ic_launcher_round.xml
deleted file mode 100644
index 6f3b755..0000000
--- a/example/src/main/res/mipmap-anydpi/ic_launcher_round.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/example/src/main/res/mipmap-hdpi/ic_launcher.webp b/example/src/main/res/mipmap-hdpi/ic_launcher.webp
index c209e78..0347617 100644
Binary files a/example/src/main/res/mipmap-hdpi/ic_launcher.webp and b/example/src/main/res/mipmap-hdpi/ic_launcher.webp differ
diff --git a/example/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp b/example/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp
new file mode 100644
index 0000000..c6b84ed
Binary files /dev/null and b/example/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp differ
diff --git a/example/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/example/src/main/res/mipmap-hdpi/ic_launcher_round.webp
index b2dfe3d..bd4a5c9 100644
Binary files a/example/src/main/res/mipmap-hdpi/ic_launcher_round.webp and b/example/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ
diff --git a/example/src/main/res/mipmap-mdpi/ic_launcher.webp b/example/src/main/res/mipmap-mdpi/ic_launcher.webp
index 4f0f1d6..42c4043 100644
Binary files a/example/src/main/res/mipmap-mdpi/ic_launcher.webp and b/example/src/main/res/mipmap-mdpi/ic_launcher.webp differ
diff --git a/example/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp b/example/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp
new file mode 100644
index 0000000..fcec82a
Binary files /dev/null and b/example/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp differ
diff --git a/example/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/example/src/main/res/mipmap-mdpi/ic_launcher_round.webp
index 62b611d..d83010e 100644
Binary files a/example/src/main/res/mipmap-mdpi/ic_launcher_round.webp and b/example/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ
diff --git a/example/src/main/res/mipmap-xhdpi/ic_launcher.webp b/example/src/main/res/mipmap-xhdpi/ic_launcher.webp
index 948a307..1eb3ba1 100644
Binary files a/example/src/main/res/mipmap-xhdpi/ic_launcher.webp and b/example/src/main/res/mipmap-xhdpi/ic_launcher.webp differ
diff --git a/example/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp b/example/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp
new file mode 100644
index 0000000..de6cbc9
Binary files /dev/null and b/example/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp differ
diff --git a/example/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/example/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
index 1b9a695..699d061 100644
Binary files a/example/src/main/res/mipmap-xhdpi/ic_launcher_round.webp and b/example/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ
diff --git a/example/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/example/src/main/res/mipmap-xxhdpi/ic_launcher.webp
index 28d4b77..96086c9 100644
Binary files a/example/src/main/res/mipmap-xxhdpi/ic_launcher.webp and b/example/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ
diff --git a/example/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp b/example/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp
new file mode 100644
index 0000000..e509b0b
Binary files /dev/null and b/example/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp differ
diff --git a/example/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/example/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
index 9287f50..1d1d167 100644
Binary files a/example/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp and b/example/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ
diff --git a/example/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/example/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
index aa7d642..c952590 100644
Binary files a/example/src/main/res/mipmap-xxxhdpi/ic_launcher.webp and b/example/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ
diff --git a/example/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp b/example/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp
new file mode 100644
index 0000000..98dccc2
Binary files /dev/null and b/example/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp differ
diff --git a/example/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/example/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
index 9126ae3..f319c59 100644
Binary files a/example/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp and b/example/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ
diff --git a/example/src/main/res/values/colors.xml b/example/src/main/res/values/colors.xml
index dfaaf12..5e9ab92 100644
--- a/example/src/main/res/values/colors.xml
+++ b/example/src/main/res/values/colors.xml
@@ -18,4 +18,6 @@
#FFBE123C
#FF44403C
#FF2F6AE1
+ #FFE11D48
+ #FF087455
\ No newline at end of file
diff --git a/example/src/main/res/values/ic_launcher_background.xml b/example/src/main/res/values/ic_launcher_background.xml
new file mode 100644
index 0000000..f8282e3
--- /dev/null
+++ b/example/src/main/res/values/ic_launcher_background.xml
@@ -0,0 +1,4 @@
+
+
+ #EEECE8
+
\ No newline at end of file
diff --git a/example/src/main/res/values/strings.xml b/example/src/main/res/values/strings.xml
index f7e09e8..290b1a7 100644
--- a/example/src/main/res/values/strings.xml
+++ b/example/src/main/res/values/strings.xml
@@ -1,5 +1,5 @@
- MobileSdk Example
+ SpruceKit Reference App
User profile
Scan QR Code
Valid