improvement: Show category in passkeys directory and correctly select items with the same name
This commit is contained in:
parent
b402e038bc
commit
e0949a7042
|
@ -1,6 +1,7 @@
|
||||||
import json
|
import json
|
||||||
import requests
|
import requests
|
||||||
import argparse
|
import argparse
|
||||||
|
import hashlib
|
||||||
|
|
||||||
parser = argparse.ArgumentParser("update_passkeys")
|
parser = argparse.ArgumentParser("update_passkeys")
|
||||||
parser.add_argument("api_key", help="An API Key to access the https://passkeys.directory/ backend.", type=str)
|
parser.add_argument("api_key", help="An API Key to access the https://passkeys.directory/ backend.", type=str)
|
||||||
|
@ -23,8 +24,14 @@ response = requests.get(
|
||||||
aggr = []
|
aggr = []
|
||||||
|
|
||||||
for site in response.json():
|
for site in response.json():
|
||||||
|
# generate a unique id
|
||||||
|
id_str = site['name'] + '|' + site['domain'] + '|' + (site.get('created_at') or '')
|
||||||
|
id = hashlib\
|
||||||
|
.md5(id_str.encode('utf-8'))\
|
||||||
|
.hexdigest()
|
||||||
features = []
|
features = []
|
||||||
entry = {
|
entry = {
|
||||||
|
'id': id,
|
||||||
'name': site['name'],
|
'name': site['name'],
|
||||||
'domain': site['domain'],
|
'domain': site['domain'],
|
||||||
'features': features,
|
'features': features,
|
||||||
|
@ -36,6 +43,8 @@ for site in response.json():
|
||||||
|
|
||||||
append_if_not_empty('documentation_link', 'documentation')
|
append_if_not_empty('documentation_link', 'documentation')
|
||||||
append_if_not_empty('setup_link', 'setup')
|
append_if_not_empty('setup_link', 'setup')
|
||||||
|
append_if_not_empty('category', 'category')
|
||||||
|
append_if_not_empty('created_at', 'created_at')
|
||||||
append_if_not_empty('notes', 'notes')
|
append_if_not_empty('notes', 'notes')
|
||||||
|
|
||||||
# convert features to a list
|
# convert features to a list
|
||||||
|
|
|
@ -1,11 +1,16 @@
|
||||||
package com.artemchep.keyguard.common.service.passkey
|
package com.artemchep.keyguard.common.service.passkey
|
||||||
|
|
||||||
|
import kotlinx.datetime.Instant
|
||||||
|
|
||||||
data class PassKeyServiceInfo(
|
data class PassKeyServiceInfo(
|
||||||
|
val id: String,
|
||||||
val name: String,
|
val name: String,
|
||||||
val domain: String,
|
val domain: String,
|
||||||
val domains: Set<String> = emptySet(),
|
val domains: Set<String> = emptySet(),
|
||||||
val setup: String? = null,
|
val setup: String? = null,
|
||||||
val documentation: String? = null,
|
val documentation: String? = null,
|
||||||
val notes: String? = null,
|
val notes: String? = null,
|
||||||
|
val category: String? = null,
|
||||||
|
val addedAt: Instant? = null,
|
||||||
val features: Set<String> = emptySet(),
|
val features: Set<String> = emptySet(),
|
||||||
)
|
)
|
||||||
|
|
|
@ -8,6 +8,7 @@ import com.artemchep.keyguard.common.service.passkey.PassKeyServiceInfo
|
||||||
import com.artemchep.keyguard.common.service.text.TextService
|
import com.artemchep.keyguard.common.service.text.TextService
|
||||||
import com.artemchep.keyguard.common.service.text.readFromResourcesAsText
|
import com.artemchep.keyguard.common.service.text.readFromResourcesAsText
|
||||||
import com.artemchep.keyguard.res.Res
|
import com.artemchep.keyguard.res.Res
|
||||||
|
import kotlinx.datetime.Instant
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
@ -16,6 +17,7 @@ import org.kodein.di.instance
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class PassKeyEntity(
|
data class PassKeyEntity(
|
||||||
|
val id: String,
|
||||||
val name: String,
|
val name: String,
|
||||||
val domain: String,
|
val domain: String,
|
||||||
@SerialName("additional-domains")
|
@SerialName("additional-domains")
|
||||||
|
@ -23,17 +25,23 @@ data class PassKeyEntity(
|
||||||
val setup: String? = null,
|
val setup: String? = null,
|
||||||
val documentation: String? = null,
|
val documentation: String? = null,
|
||||||
val notes: String? = null,
|
val notes: String? = null,
|
||||||
|
val category: String? = null,
|
||||||
|
@SerialName("created_at")
|
||||||
|
val createdAt: Instant? = null,
|
||||||
val features: Set<String> = emptySet(),
|
val features: Set<String> = emptySet(),
|
||||||
)
|
)
|
||||||
|
|
||||||
fun PassKeyEntity.toDomain() = kotlin.run {
|
fun PassKeyEntity.toDomain() = kotlin.run {
|
||||||
PassKeyServiceInfo(
|
PassKeyServiceInfo(
|
||||||
|
id = id,
|
||||||
name = name,
|
name = name,
|
||||||
domain = domain,
|
domain = domain,
|
||||||
domains = domains + domain,
|
domains = domains + domain,
|
||||||
setup = setup,
|
setup = setup,
|
||||||
documentation = documentation,
|
documentation = documentation,
|
||||||
notes = notes,
|
notes = notes,
|
||||||
|
category = category,
|
||||||
|
addedAt = createdAt,
|
||||||
features = features,
|
features = features,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -258,7 +258,7 @@ private fun AppItem(
|
||||||
val nextEntry = navigationNextEntryOrNull()
|
val nextEntry = navigationNextEntryOrNull()
|
||||||
val nextRoute = nextEntry?.route as? PasskeysServiceViewFullRoute
|
val nextRoute = nextEntry?.route as? PasskeysServiceViewFullRoute
|
||||||
|
|
||||||
val selected = nextRoute?.args?.model?.name == item.name.text
|
val selected = nextRoute?.args?.model?.id == item.data.id
|
||||||
if (selected) {
|
if (selected) {
|
||||||
return@run MaterialTheme.colorScheme.selectedContainer
|
return@run MaterialTheme.colorScheme.selectedContainer
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,10 +82,10 @@ fun producePasskeysListState(
|
||||||
.map { serviceInfo ->
|
.map { serviceInfo ->
|
||||||
val key = kotlin.run {
|
val key = kotlin.run {
|
||||||
val newNameCollisionCounter = nameCollisions
|
val newNameCollisionCounter = nameCollisions
|
||||||
.getOrDefault(serviceInfo.name, 0) + 1
|
.getOrDefault(serviceInfo.id, 0) + 1
|
||||||
nameCollisions[serviceInfo.name] =
|
nameCollisions[serviceInfo.id] =
|
||||||
newNameCollisionCounter
|
newNameCollisionCounter
|
||||||
serviceInfo.name + ":" + newNameCollisionCounter
|
serviceInfo.id + ":" + newNameCollisionCounter
|
||||||
}
|
}
|
||||||
val faviconUrl = serviceInfo.documentation?.let { url ->
|
val faviconUrl = serviceInfo.documentation?.let { url ->
|
||||||
FaviconUrl(
|
FaviconUrl(
|
||||||
|
|
|
@ -29,6 +29,7 @@ import androidx.compose.ui.unit.dp
|
||||||
import com.artemchep.keyguard.common.model.Loadable
|
import com.artemchep.keyguard.common.model.Loadable
|
||||||
import com.artemchep.keyguard.common.model.getOrNull
|
import com.artemchep.keyguard.common.model.getOrNull
|
||||||
import com.artemchep.keyguard.feature.dialog.Dialog
|
import com.artemchep.keyguard.feature.dialog.Dialog
|
||||||
|
import com.artemchep.keyguard.feature.home.vault.component.Section
|
||||||
import com.artemchep.keyguard.feature.navigation.NavigationIcon
|
import com.artemchep.keyguard.feature.navigation.NavigationIcon
|
||||||
import com.artemchep.keyguard.feature.tfa.directory.FlatLaunchBrowserItem
|
import com.artemchep.keyguard.feature.tfa.directory.FlatLaunchBrowserItem
|
||||||
import com.artemchep.keyguard.res.Res
|
import com.artemchep.keyguard.res.Res
|
||||||
|
@ -194,14 +195,26 @@ fun ColumnScope.Content(
|
||||||
.padding(horizontal = Dimens.horizontalPadding),
|
.padding(horizontal = Dimens.horizontalPadding),
|
||||||
markdown = notes,
|
markdown = notes,
|
||||||
)
|
)
|
||||||
Spacer(
|
}
|
||||||
|
|
||||||
|
val category = state?.model?.category
|
||||||
|
if (category != null) {
|
||||||
|
Section(
|
||||||
|
text = stringResource(Res.strings.category),
|
||||||
|
)
|
||||||
|
Text(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.height(16.dp),
|
.padding(horizontal = Dimens.horizontalPadding),
|
||||||
|
text = category,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val documentationUrl = state?.model?.documentation
|
val documentationUrl = state?.model?.documentation
|
||||||
if (documentationUrl != null) {
|
if (documentationUrl != null) {
|
||||||
|
Spacer(
|
||||||
|
modifier = Modifier
|
||||||
|
.height(16.dp),
|
||||||
|
)
|
||||||
FlatLaunchBrowserItem(
|
FlatLaunchBrowserItem(
|
||||||
title = stringResource(Res.strings.uri_action_launch_docs_title),
|
title = stringResource(Res.strings.uri_action_launch_docs_title),
|
||||||
url = documentationUrl,
|
url = documentationUrl,
|
||||||
|
|
|
@ -89,6 +89,7 @@
|
||||||
<string name="organizations">Organizations</string>
|
<string name="organizations">Organizations</string>
|
||||||
<string name="organizations_empty_label">No organizations</string>
|
<string name="organizations_empty_label">No organizations</string>
|
||||||
<string name="misc">Miscellaneous</string>
|
<string name="misc">Miscellaneous</string>
|
||||||
|
<string name="category">Category</string>
|
||||||
<string name="command">Command</string>
|
<string name="command">Command</string>
|
||||||
<string name="execute_command">Execute</string>
|
<string name="execute_command">Execute</string>
|
||||||
<!-- Add (something) -->
|
<!-- Add (something) -->
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue