diff --git a/app/src/main/java/com/example/objectionapp/Providers.kt b/app/src/main/java/com/example/objectionapp/Providers.kt index 4057994..6744465 100644 --- a/app/src/main/java/com/example/objectionapp/Providers.kt +++ b/app/src/main/java/com/example/objectionapp/Providers.kt @@ -117,9 +117,14 @@ fun TestProvider(controller: Controller) { } } +@Composable +fun useController(): Controller { + return LocalController.current!! +} + @Composable fun useObject(id: String?): Object? { - val controller = LocalController.current!! + val controller = useController() var obj by remember { mutableStateOf(id?.let { controller.objectStore.getCurrentObject(id) }) } DisposableEffect(id) { diff --git a/app/src/main/java/com/example/objectionapp/Schema.kt b/app/src/main/java/com/example/objectionapp/Schema.kt index 09397cc..d5cf4f6 100644 --- a/app/src/main/java/com/example/objectionapp/Schema.kt +++ b/app/src/main/java/com/example/objectionapp/Schema.kt @@ -41,214 +41,211 @@ annotation class IsColor annotation class ContentKey(val key: String) fun getSchema(klass: KClass<*>): Schema { - return Schema(getItemSchema(serialDescriptor(klass.createType()))) + return Schema(getItemSchema(serialDescriptor(klass.createType()))) } @OptIn(ExperimentalSerializationApi::class) private fun getItemSchema( - descriptor: SerialDescriptor, annotations: List = listOf() + descriptor: SerialDescriptor, annotations: List = listOf() ): ItemSchema { - return when (descriptor.kind) { - StructureKind.CLASS -> getClassSchema(descriptor) - PrimitiveKind.STRING -> getStringSchema(annotations) - PrimitiveKind.DOUBLE -> ItemSchema.NumberSchema - PrimitiveKind.FLOAT -> ItemSchema.NumberSchema - PrimitiveKind.INT -> ItemSchema.NumberSchema - PrimitiveKind.BOOLEAN -> ItemSchema.BooleanSchema - StructureKind.LIST -> getListSchema(descriptor) - PolymorphicKind.SEALED -> getSealedSchema(descriptor) - SerialKind.ENUM -> throw Exception("Use a sealed class with objects instead of an enum. Failed at: $descriptor") - else -> throw Exception("unknown item at $descriptor") - } + return when (descriptor.kind) { + StructureKind.CLASS -> getClassSchema(descriptor) + PrimitiveKind.STRING -> getStringSchema(annotations) + PrimitiveKind.DOUBLE -> ItemSchema.NumberSchema + PrimitiveKind.FLOAT -> ItemSchema.NumberSchema + PrimitiveKind.INT -> ItemSchema.NumberSchema + PrimitiveKind.BOOLEAN -> ItemSchema.BooleanSchema + StructureKind.LIST -> getListSchema(descriptor) + PolymorphicKind.SEALED -> getSealedSchema(descriptor) + SerialKind.ENUM -> throw Exception("Use a sealed class with objects instead of an enum. Failed at: $descriptor") + else -> throw Exception("unknown item at $descriptor") + } } @OptIn(ExperimentalSerializationApi::class) private fun getStringSchema(annotations: List): ItemSchema { - for (annotation in annotations) { - when (annotation) { - is ObjectReference -> return ItemSchema.ReferenceSchema( - expectedTopLevelVariant = serialDescriptor( - annotation.expectedTopLevelVariant.createType() - ).serialName - ) - - is AnyObjectReference -> return ItemSchema.ReferenceSchema(expectedTopLevelVariant = null) - } - } - - return ItemSchema.StringSchema + for (annotation in annotations) { + when (annotation) { + is ObjectReference -> return ItemSchema.ReferenceSchema( + expectedTopLevelVariant = serialDescriptor( + annotation.expectedTopLevelVariant.createType() + ).serialName + ) + + is AnyObjectReference -> return ItemSchema.ReferenceSchema(expectedTopLevelVariant = null) + } + } + + return ItemSchema.StringSchema } @OptIn(ExperimentalSerializationApi::class) private fun getSealedSchema(descriptor: SerialDescriptor): ItemSchema.EnumSchema { - val variants = mutableListOf() - val child = descriptor.getElementDescriptor(1) - var discriminatorKey: String? = null - var contentKey: String? = null - - for (variant in child.elementDescriptors) { - variants.add( - EnumVariantSchema( - name = variant.serialName, description = getDescription(listOf()), // FIXME - type = getItemSchema(variant) - ) - ) - } - - for (annotation in descriptor.annotations) { - if (annotation is JsonClassDiscriminator) { - discriminatorKey = annotation.discriminator - } - if (annotation is ContentKey) { - contentKey = annotation.key - } - } - - if (discriminatorKey == null) { - throw Exception("All sealed classes must have a JsonDiscriminatorKey annotation. Failed at: $descriptor") - } - - return ItemSchema.EnumSchema(discriminatorKey, contentKey, variants) + val variants = mutableListOf() + val child = descriptor.getElementDescriptor(1) + var discriminatorKey: String? = null + var contentKey: String? = null + + for (variant in child.elementDescriptors) { + variants.add( + EnumVariantSchema( + name = variant.serialName, description = getDescription(listOf()), // FIXME + type = getItemSchema(variant) + ) + ) + } + + for (annotation in descriptor.annotations) { + if (annotation is JsonClassDiscriminator) { + discriminatorKey = annotation.discriminator + } + if (annotation is ContentKey) { + contentKey = annotation.key + } + } + + if (discriminatorKey == null) { + throw Exception("All sealed classes must have a JsonDiscriminatorKey annotation. Failed at: $descriptor") + } + + return ItemSchema.EnumSchema(discriminatorKey, contentKey, variants) } @OptIn(ExperimentalSerializationApi::class) private fun getListSchema(descriptor: SerialDescriptor): ItemSchema { - if (descriptor.elementsCount != 1) { - throw Exception("A list must have exactly on child element") - } + if (descriptor.elementsCount != 1) { + throw Exception("A list must have exactly on child element") + } - return ItemSchema.ListSchema(option = getItemSchema(descriptor.getElementDescriptor(0))) + return ItemSchema.ListSchema(option = getItemSchema(descriptor.getElementDescriptor(0))) } @OptIn(ExperimentalSerializationApi::class) private fun getClassSchema(descriptor: SerialDescriptor): ItemSchema { - val items = mutableListOf() - - for (annotation in descriptor.annotations) { - if (annotation is IsColor) return ItemSchema.ColorSchema - } - - for (childIndex in 0..() + + for (annotation in descriptor.annotations) { + if (annotation is IsColor) return ItemSchema.ColorSchema + } + + for (childIndex in 0..): String? { - for (annotation in annotations) { - if (annotation is Description) { - return annotation.content - } - } + for (annotation in annotations) { + if (annotation is Description) { + return annotation.content + } + } - return null + return null } @OptIn(ExperimentalSerializationApi::class) private fun getTopLevelVariant(klass: KClass<*>): String? { - val descriptor = serialDescriptor(klass.createType()) + val descriptor = serialDescriptor(klass.createType()) - for (annotation in descriptor.annotations) { - if (annotation is ObjectReference) { - return serialDescriptor( - annotation.expectedTopLevelVariant.createType() - ).serialName - } - } + for (annotation in descriptor.annotations) { + if (annotation is ObjectReference) { + return serialDescriptor( + annotation.expectedTopLevelVariant.createType() + ).serialName + } + } - return null + return null } @Serializable data class Schema(@SerialName("object") val obj: ItemSchema) { - val version = "0.1" - - @SerialName("initial_objects") - val initialObjects = listOf( - InitialObject( - id = "theme_default", - description = "The theme that will be applied by default to all UI elements", - expectedTopLevelVariant = getTopLevelVariant(Theme::class) - ), - InitialObject( - id = "layout_default", - description = "The layout that will wrap everything", - expectedTopLevelVariant = getTopLevelVariant(Theme::class) - ), - ) + val version = "0.1" + + @SerialName("initial_objects") + val initialObjects = listOf( + InitialObject( + id = "theme_default", + description = "The theme that will be applied by default to all UI elements", + expectedTopLevelVariant = getTopLevelVariant(Theme::class) + ), + InitialObject( + id = "layout_default", + description = "The layout that will wrap everything", + expectedTopLevelVariant = getTopLevelVariant(Theme::class) + ), + ) } @Serializable data class InitialObject( - val id: String, - val description: String, - @SerialName("expected_top_level_variant") val expectedTopLevelVariant: String?, + val id: String, + val description: String, + @SerialName("expected_top_level_variant") val expectedTopLevelVariant: String?, ) @OptIn(ExperimentalSerializationApi::class) @JsonClassDiscriminator("$") @Serializable sealed class ItemSchema { - @Serializable - @SerialName("struct") - data class StructSchema( - val properties: List - ) : ItemSchema() - - @Serializable - @SerialName("enum") - data class EnumSchema( - @SerialName("discriminator_key") val discriminatorKey: String, - @SerialName("content_key") val contentKey: String?, - val variants: List - ) : ItemSchema() - - @Serializable - @SerialName("string") - data object StringSchema : ItemSchema() - - @Serializable - @SerialName("number") - data object NumberSchema : ItemSchema() - - @Serializable - @SerialName("boolean") - data object BooleanSchema : ItemSchema() - - @Serializable - @SerialName("color") - data object ColorSchema : ItemSchema() - - @Serializable - @SerialName("list") - data class ListSchema( - val option: ItemSchema - ) : ItemSchema() - - @Serializable - @SerialName("reference") - data class ReferenceSchema( - val expectedTopLevelVariant: String? - ) : ItemSchema() + @Serializable + @SerialName("struct") + data class StructSchema( + val properties: List + ) : ItemSchema() + + @Serializable + @SerialName("enum") + data class EnumSchema( + @SerialName("discriminator_key") val discriminatorKey: String, + @SerialName("content_key") val contentKey: String?, + val variants: List + ) : ItemSchema() + + @Serializable + @SerialName("string") + data object StringSchema : ItemSchema() + + @Serializable + @SerialName("number") + data object NumberSchema : ItemSchema() + + @Serializable + @SerialName("boolean") + data object BooleanSchema : ItemSchema() + + @Serializable + @SerialName("color") + data object ColorSchema : ItemSchema() + + @Serializable + @SerialName("list") + data class ListSchema( + val option: ItemSchema + ) : ItemSchema() + + @Serializable + @SerialName("reference") + data class ReferenceSchema( + @SerialName("expected_top_level_variant") val expectedTopLevelVariant: String? + ) : ItemSchema() } @Serializable data class StructPropertySchema( - val name: String, - val description: String?, - val type: ItemSchema, - val optional: Boolean + val name: String, val description: String?, val type: ItemSchema, val optional: Boolean ) @Serializable diff --git a/app/src/main/java/com/example/objectionapp/StandardIcon.kt b/app/src/main/java/com/example/objectionapp/StandardIcon.kt index a672f15..a48248b 100644 --- a/app/src/main/java/com/example/objectionapp/StandardIcon.kt +++ b/app/src/main/java/com/example/objectionapp/StandardIcon.kt @@ -14,23 +14,23 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector import java.lang.System.console - @Composable fun StandardIcon( name: String, modifier: Modifier = Modifier, tint: Color = LocalContentColor.current, ) { + val logger = useController().logger.scope("StandardIcon") val theme = useDefaultTheme() val icon: ImageVector? = remember(name) { try { val cl = Class.forName("androidx.compose.material.icons.${theme.iconPack.getJavaName()}.${name}Kt") - println(cl) + val method = cl.declaredMethods.first() method.invoke(null, theme.iconPack.getIcons()) as ImageVector } catch (err: Throwable) { - println("Error with icon loading: $err") + logger.error("failed to load icon: $err") null } }