Skip to content

Commit

Permalink
Integrate BitStringStatusList lookup into showcase (#57)
Browse files Browse the repository at this point in the history
Integrates the status list lookup into the showcase apps. The status appears when listing the credentials and when opening to view details. It also adds a pull-down to refresh that updates the status list.

Signed-off-by: Ryan Tate <[email protected]>
Co-authored-by: Ryan Tate <[email protected]>
  • Loading branch information
Juliano1612 and Ryanmtate authored Dec 13, 2024
1 parent f114d3e commit 60269fa
Show file tree
Hide file tree
Showing 32 changed files with 980 additions and 338 deletions.
11 changes: 10 additions & 1 deletion MobileSdk/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,17 @@ publishing {
password = System.getenv("GITHUB_TOKEN")
}
}
mavenLocal()
}
publications {
create<MavenPublication>("debug") {
groupId = "com.spruceid.mobile.sdk"
artifactId = "mobilesdk"
version = System.getenv("VERSION")

afterEvaluate { from(components["release"]) }
}

// Creates a Maven publication called "release".
create<MavenPublication>("release") {
groupId = "com.spruceid.mobile.sdk"
Expand Down Expand Up @@ -116,7 +125,7 @@ android {
}

dependencies {
api("com.spruceid.mobile.sdk.rs:mobilesdkrs:0.3.0")
api("com.spruceid.mobile.sdk.rs:mobilesdkrs:0.4.0")
//noinspection GradleCompatible
implementation("com.android.support:appcompat-v7:28.0.0")
/* Begin UI dependencies */
Expand Down
98 changes: 86 additions & 12 deletions MobileSdk/src/main/java/com/spruceid/mobile/sdk/CredentialPack.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@ import com.spruceid.mobile.sdk.rs.JsonVc
import com.spruceid.mobile.sdk.rs.JwtVc
import com.spruceid.mobile.sdk.rs.Mdoc
import com.spruceid.mobile.sdk.rs.ParsedCredential
import com.spruceid.mobile.sdk.rs.Vcdm2SdJwt
import com.spruceid.mobile.sdk.rs.StorageManagerInterface
import com.spruceid.mobile.sdk.rs.Uuid
import com.spruceid.mobile.sdk.rs.Vcdm2SdJwt
import com.spruceid.mobile.sdk.rs.VdcCollection
import com.spruceid.mobile.sdk.rs.VdcCollectionException
import org.json.JSONException
import org.json.JSONObject
import java.lang.IllegalArgumentException
import java.util.UUID

/**
Expand All @@ -40,6 +39,10 @@ class CredentialPack {
this.credentials = credentialsArray
}

fun id(): UUID {
return this.id
}

/**
* Try to add a credential and throws a ParsingException if not possible
*/
Expand Down Expand Up @@ -103,6 +106,34 @@ class CredentialPack {
return credentials
}

/**
* Get all status from all credentials async
*/
suspend fun getStatusListsAsync(hasConnection: Boolean): Map<Uuid, CredentialStatusList> {
var res = mutableMapOf<Uuid, CredentialStatusList>()
credentials.forEach { credential ->
val credentialId = credential.id()
credential.asJsonVc()?.let {
if (hasConnection) {
try {
val status = it.status()
if (status.isRevoked()) {
res[credentialId] = CredentialStatusList.REVOKED
} else if (status.isSuspended()) {
res[credentialId] = CredentialStatusList.SUSPENDED
} else {
res[credentialId] = CredentialStatusList.VALID
}
} catch (_: Exception) {
}
} else {
res[credentialId] = CredentialStatusList.UNKNOWN
}
}
}
return res
}

/**
* Find claims from all credentials in this CredentialPack.
*/
Expand Down Expand Up @@ -187,12 +218,16 @@ class CredentialPack {
try {
list().forEach {
if (vdcCollection.get(it.id()) == null) {
Log.d("sprucekit", "Saving credential '${it.id()}' " +
"to the VdcCollection")
Log.d(
"sprucekit", "Saving credential '${it.id()}' " +
"to the VdcCollection"
)
vdcCollection.add(it.intoGenericForm())
} else {
Log.d("sprucekit", "Skipped saving credential '${it.id()}' " +
"to the VdcCollection as it already exists")
Log.d(
"sprucekit", "Skipped saving credential '${it.id()}' " +
"to the VdcCollection as it already exists"
)
}
}
} catch (e: VdcCollectionException) {
Expand Down Expand Up @@ -269,6 +304,7 @@ class CredentialPackContents {
private const val ID_KEY = "id"
private const val CREDENTIALS_KEY = "credentials"
}

val id: UUID
val credentials: List<Uuid>

Expand Down Expand Up @@ -310,23 +346,29 @@ class CredentialPackContents {
try {
val credential = vdcCollection.get(it)
if (credential == null) {
Log.w("sprucekit", "credential '$it' in pack '${id}'" +
" could not be found")
Log.w(
"sprucekit", "credential '$it' in pack '${id}'" +
" could not be found"
)
Log.d("sprucekit", "VdcCollection: ${vdcCollection.allEntries()}")
}
credential
} catch (e: Exception) {
Log.w("sprucekit" ,"credential '$it' could not be loaded from" +
" storage")
Log.w(
"sprucekit", "credential '$it' could not be loaded from" +
" storage"
)
return@mapNotNull null
}
}
.mapNotNull {
try {
return@mapNotNull ParsedCredential.parseFromCredential(it)
} catch (e: CredentialDecodingException) {
Log.w("sprucekit", "failed to parse credential '${it.id}'" +
" as a known variant")
Log.w(
"sprucekit", "failed to parse credential '${it.id}'" +
" as a known variant"
)
return@mapNotNull null
}
}
Expand Down Expand Up @@ -375,3 +417,35 @@ class ParsingException(message: String, cause: Throwable?) : Exception(message,
class LoadingException(message: String, cause: Throwable) : Exception(message, cause)
class SavingException(message: String, cause: Throwable) : Exception(message, cause)
class ClearingException(message: String, cause: Throwable) : Exception(message, cause)

enum class CredentialStatusList {
/**
* Valid credential
*/
VALID,

/**
* Credential revoked
*/
REVOKED,

/**
* Credential suspended
*/
SUSPENDED,

/**
* No connection
*/
UNKNOWN,

/**
* Invalid credential
*/
INVALID,

/**
* Credential doesn't have status list
*/
UNDEFINED
}
5 changes: 3 additions & 2 deletions example/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ android {
applicationId = "com.spruceid.mobilesdkexample"
minSdk = 26
targetSdk = 34
versionCode = 15
versionName = "1.1.1"
versionCode = 16
versionName = "1.2.0"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
Expand Down Expand Up @@ -65,6 +65,7 @@ dependencies {
implementation("androidx.activity:activity-compose:1.8.2")
implementation(platform("androidx.compose:compose-bom:2023.03.00"))
implementation("com.google.accompanist:accompanist-permissions:0.35.1-alpha")
implementation("com.google.accompanist:accompanist-swiperefresh:0.36.0")
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-graphics")
implementation("androidx.compose.ui:ui-tooling-preview")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import com.spruceid.mobilesdkexample.ui.theme.ColorBlue900
import com.spruceid.mobilesdkexample.ui.theme.Switzer
import com.spruceid.mobilesdkexample.verifier.VerifierHomeView
import com.spruceid.mobilesdkexample.viewmodels.CredentialPacksViewModel
import com.spruceid.mobilesdkexample.viewmodels.StatusListViewModel
import com.spruceid.mobilesdkexample.viewmodels.HelpersViewModel
import com.spruceid.mobilesdkexample.viewmodels.VerificationMethodsViewModel
import com.spruceid.mobilesdkexample.wallet.WalletHomeView
Expand All @@ -55,6 +56,7 @@ fun HomeView(
initialTab: String,
verificationMethodsViewModel: VerificationMethodsViewModel,
credentialPacksViewModel: CredentialPacksViewModel,
statusListViewModel: StatusListViewModel,
helpersViewModel: HelpersViewModel
) {
var tab by remember {
Expand All @@ -79,6 +81,7 @@ fun HomeView(
WalletHomeView(
navController,
credentialPacksViewModel = credentialPacksViewModel,
statusListViewModel = statusListViewModel,
helpersViewModel = helpersViewModel
)
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import androidx.compose.material3.Surface
import androidx.compose.ui.Modifier
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import com.spruceid.mobile.sdk.ConnectionLiveData
import com.spruceid.mobilesdkexample.db.AppDatabase
import com.spruceid.mobilesdkexample.db.VerificationActivityLogsRepository
import com.spruceid.mobilesdkexample.db.VerificationMethodsRepository
Expand All @@ -22,13 +23,15 @@ import com.spruceid.mobilesdkexample.ui.theme.MobileSdkTheme
import com.spruceid.mobilesdkexample.viewmodels.CredentialPacksViewModel
import com.spruceid.mobilesdkexample.viewmodels.CredentialPacksViewModelFactory
import com.spruceid.mobilesdkexample.viewmodels.HelpersViewModel
import com.spruceid.mobilesdkexample.viewmodels.StatusListViewModel
import com.spruceid.mobilesdkexample.viewmodels.VerificationActivityLogsViewModel
import com.spruceid.mobilesdkexample.viewmodels.VerificationActivityLogsViewModelFactory
import com.spruceid.mobilesdkexample.viewmodels.VerificationMethodsViewModel
import com.spruceid.mobilesdkexample.viewmodels.VerificationMethodsViewModelFactory

class MainActivity : ComponentActivity() {
private lateinit var navController: NavHostController
private lateinit var connectionLiveData: ConnectionLiveData

override fun onNewIntent(intent: Intent?) {
if (intent != null && intent.action == "android.intent.action.VIEW" && intent.data != null) {
Expand Down Expand Up @@ -83,13 +86,22 @@ class MainActivity : ComponentActivity() {
CredentialPacksViewModelFactory(application as MainApplication)
}

val statusListViewModel: StatusListViewModel by viewModels<StatusListViewModel>()
connectionLiveData = ConnectionLiveData(this)
connectionLiveData.observe(this) { isNetworkAvailable ->
isNetworkAvailable?.let {
statusListViewModel.setHasConnection(it)
}
}

val helpersViewModel: HelpersViewModel by viewModels<HelpersViewModel>()

SetupNavGraph(
navController,
verificationMethodsViewModel = verificationMethodsViewModel,
verificationActivityLogsViewModel = verificationActivityLogsViewModel,
credentialPacksViewModel = credentialPacksViewModel,
statusListViewModel = statusListViewModel,
helpersViewModel = helpersViewModel
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import com.spruceid.mobilesdkexample.ui.theme.ColorStone950
import com.spruceid.mobilesdkexample.ui.theme.Inter
import com.spruceid.mobilesdkexample.utils.credentialDisplaySelector
import com.spruceid.mobilesdkexample.viewmodels.CredentialPacksViewModel
import com.spruceid.mobilesdkexample.viewmodels.StatusListViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
Expand All @@ -41,7 +42,8 @@ import kotlinx.coroutines.launch
fun AddToWalletView(
navController: NavHostController,
rawCredential: String,
credentialPacksViewModel: CredentialPacksViewModel
credentialPacksViewModel: CredentialPacksViewModel,
statusListViewModel: StatusListViewModel
) {
var credentialItem by remember { mutableStateOf<ICredentialView?>(null) }
var err by remember { mutableStateOf<String?>(null) }
Expand All @@ -50,7 +52,7 @@ fun AddToWalletView(
val scope = rememberCoroutineScope()

LaunchedEffect(Unit) {
credentialItem = credentialDisplaySelector(rawCredential, null, null)
credentialItem = credentialDisplaySelector(rawCredential, statusListViewModel, null, null)
}

fun back() {
Expand Down
Loading

0 comments on commit 60269fa

Please sign in to comment.