Wear CWF Refactor to allow more flexibility in additional resources

This commit is contained in:
Philoul 2023-09-09 19:11:49 +02:00
parent ffb73ef14b
commit aa85b4f173
5 changed files with 38 additions and 47 deletions

View file

@ -50,11 +50,7 @@ enum class ResFileMap(val fileName: String) {
ARROW_FLAT("ArrowFlat"), ARROW_FLAT("ArrowFlat"),
ARROW_FORTY_FIVE_DOWN("Arrow45Down"), ARROW_FORTY_FIVE_DOWN("Arrow45Down"),
ARROW_SINGLE_DOWN("ArrowSingleDown"), ARROW_SINGLE_DOWN("ArrowSingleDown"),
ARROW_DOUBLE_DOWN("ArrowDoubleDown"), ARROW_DOUBLE_DOWN("ArrowDoubleDown");
FONT1("Font1"),
FONT2("Font2"),
FONT3("Font3"),
FONT4("Font4");
companion object { companion object {
@ -134,7 +130,7 @@ data class ResData(val value: ByteArray, val format: ResFormat) {
} }
} }
typealias CwfResDataMap = MutableMap<ResFileMap, ResData> typealias CwfResDataMap = MutableMap<String, ResData>
typealias CwfMetadataMap = MutableMap<CwfMetadataKey, String> typealias CwfMetadataMap = MutableMap<CwfMetadataKey, String>
@Serializable @Serializable
@ -259,11 +255,7 @@ enum class JsonKeyValues(val key: String, val jsonKey: JsonKeys) {
BOLD("bold", JsonKeys.FONTSTYLE), BOLD("bold", JsonKeys.FONTSTYLE),
BOLD_ITALIC("bold_italic", JsonKeys.FONTSTYLE), BOLD_ITALIC("bold_italic", JsonKeys.FONTSTYLE),
ITALIC("italic", JsonKeys.FONTSTYLE), ITALIC("italic", JsonKeys.FONTSTYLE),
BGCOLOR("bgColor", JsonKeys.COLOR), BGCOLOR("bgColor", JsonKeys.COLOR)
FONT1("font1", JsonKeys.FONTCOLOR),
FONT2("font2", JsonKeys.FONTCOLOR),
FONT3("font3", JsonKeys.FONTCOLOR),
FONT4("font4", JsonKeys.FONTCOLOR)
} }
enum class ViewType(@StringRes val comment: Int?) { enum class ViewType(@StringRes val comment: Int?) {
@ -309,14 +301,15 @@ class ZipWatchfaceFormat {
val cwfResFileMap = ResFileMap.fromFileName(entryName) val cwfResFileMap = ResFileMap.fromFileName(entryName)
val drawableFormat = ResFormat.fromFileName(entryName) val drawableFormat = ResFormat.fromFileName(entryName)
if (cwfResFileMap != ResFileMap.UNKNOWN && drawableFormat != ResFormat.UNKNOWN) { if (cwfResFileMap != ResFileMap.UNKNOWN && drawableFormat != ResFormat.UNKNOWN) {
resDatas[cwfResFileMap] = ResData(byteArrayOutputStream.toByteArray(), drawableFormat) resDatas[cwfResFileMap.fileName] = ResData(byteArrayOutputStream.toByteArray(), drawableFormat)
} } else if (drawableFormat != ResFormat.UNKNOWN)
resDatas[entryName.substringBeforeLast(".")] = ResData(byteArrayOutputStream.toByteArray(), drawableFormat)
} }
zipEntry = zipInputStream.nextEntry zipEntry = zipInputStream.nextEntry
} }
// Valid CWF file must contains a valid json file with a name within metadata and a custom watchface image // Valid CWF file must contains a valid json file with a name within metadata and a custom watchface image
return if (metadata.containsKey(CwfMetadataKey.CWF_NAME) && resDatas.containsKey(ResFileMap.CUSTOM_WATCHFACE)) return if (metadata.containsKey(CwfMetadataKey.CWF_NAME) && resDatas.containsKey(ResFileMap.CUSTOM_WATCHFACE.fileName))
CwfData(json.toString(4), metadata, resDatas) CwfData(json.toString(4), metadata, resDatas)
else else
null null
@ -338,7 +331,7 @@ class ZipWatchfaceFormat {
zipOutputStream.closeEntry() zipOutputStream.closeEntry()
for (resData in customWatchface.resDatas) { for (resData in customWatchface.resDatas) {
val fileEntry = ZipEntry("${resData.key.fileName}.${resData.value.format.extension}") val fileEntry = ZipEntry("${resData.key}.${resData.value.format.extension}")
zipOutputStream.putNextEntry(fileEntry) zipOutputStream.putNextEntry(fileEntry)
zipOutputStream.write(resData.value.value) zipOutputStream.write(resData.value.value)
zipOutputStream.closeEntry() zipOutputStream.closeEntry()

View file

@ -89,7 +89,7 @@ class CustomWatchfaceImportListActivity: TranslatedDaggerAppCompatActivity() {
override fun onBindViewHolder(holder: CwfFileViewHolder, position: Int) { override fun onBindViewHolder(holder: CwfFileViewHolder, position: Int) {
val customWatchfaceFile = customWatchfaceFileList[position] val customWatchfaceFile = customWatchfaceFileList[position]
val metadata = customWatchfaceFile.metadata val metadata = customWatchfaceFile.metadata
val drawable = customWatchfaceFile.resDatas[ResFileMap.CUSTOM_WATCHFACE]?.toDrawable(resources) val drawable = customWatchfaceFile.resDatas[ResFileMap.CUSTOM_WATCHFACE.fileName]?.toDrawable(resources)
with(holder.customWatchfaceImportListItemBinding) { with(holder.customWatchfaceImportListItemBinding) {
filelistName.text = rh.gs(info.nightscout.shared.R.string.metadata_wear_import_filename, metadata[CWF_FILENAME]) filelistName.text = rh.gs(info.nightscout.shared.R.string.metadata_wear_import_filename, metadata[CWF_FILENAME])
filelistName.tag = customWatchfaceFile filelistName.tag = customWatchfaceFile

View file

@ -111,7 +111,7 @@ class WearFragment : DaggerFragment() {
wearPlugin.savedCustomWatchface?.let { wearPlugin.savedCustomWatchface?.let {
wearPlugin.checkCustomWatchfacePreferences() wearPlugin.checkCustomWatchfacePreferences()
binding.customName.text = rh.gs(R.string.wear_custom_watchface, it.metadata[CwfMetadataKey.CWF_NAME]) binding.customName.text = rh.gs(R.string.wear_custom_watchface, it.metadata[CwfMetadataKey.CWF_NAME])
binding.coverChart.setImageDrawable(it.resDatas[ResFileMap.CUSTOM_WATCHFACE]?.toDrawable(resources)) binding.coverChart.setImageDrawable(it.resDatas[ResFileMap.CUSTOM_WATCHFACE.fileName]?.toDrawable(resources))
binding.infosCustom.visibility = View.VISIBLE binding.infosCustom.visibility = View.VISIBLE
} ?:apply { } ?:apply {
binding.customName.text = rh.gs(R.string.wear_custom_watchface, "") binding.customName.text = rh.gs(R.string.wear_custom_watchface, "")

View file

@ -86,7 +86,7 @@ class CwfInfosActivity : TranslatedDaggerAppCompatActivity() {
wearPlugin.savedCustomWatchface?.let { wearPlugin.savedCustomWatchface?.let {
val cwfAuthorization = sp.getBoolean(info.nightscout.core.utils.R.string.key_wear_custom_watchface_autorization, false) val cwfAuthorization = sp.getBoolean(info.nightscout.core.utils.R.string.key_wear_custom_watchface_autorization, false)
val metadata = it.metadata val metadata = it.metadata
val drawable = it.resDatas[ResFileMap.CUSTOM_WATCHFACE]?.toDrawable(resources) val drawable = it.resDatas[ResFileMap.CUSTOM_WATCHFACE.fileName]?.toDrawable(resources)
binding.customWatchface.setImageDrawable(drawable) binding.customWatchface.setImageDrawable(drawable)
title = rh.gs(CwfMetadataKey.CWF_NAME.label, metadata[CwfMetadataKey.CWF_NAME]) title = rh.gs(CwfMetadataKey.CWF_NAME.label, metadata[CwfMetadataKey.CWF_NAME])
metadata[CwfMetadataKey.CWF_AUTHOR_VERSION]?.let { authorVersion -> metadata[CwfMetadataKey.CWF_AUTHOR_VERSION]?.let { authorVersion ->

View file

@ -301,7 +301,7 @@ class CustomWatchface : BaseWatchFace() {
val metadataMap = ZipWatchfaceFormat.loadMetadata(json) val metadataMap = ZipWatchfaceFormat.loadMetadata(json)
val drawableDataMap: CwfResDataMap = mutableMapOf() val drawableDataMap: CwfResDataMap = mutableMapOf()
getResourceByteArray(info.nightscout.shared.R.drawable.watchface_custom)?.let { getResourceByteArray(info.nightscout.shared.R.drawable.watchface_custom)?.let {
drawableDataMap[ResFileMap.CUSTOM_WATCHFACE] = ResData(it, ResFormat.PNG) drawableDataMap[ResFileMap.CUSTOM_WATCHFACE.fileName] = ResData(it, ResFormat.PNG)
} }
return EventData.ActionSetCustomWatchface(CwfData(json.toString(4), metadataMap, drawableDataMap)) return EventData.ActionSetCustomWatchface(CwfData(json.toString(4), metadataMap, drawableDataMap))
} }
@ -489,10 +489,10 @@ class CustomWatchface : BaseWatchFace() {
fun drawable(resources: Resources, drawableDataMap: CwfResDataMap, sgvLevel: Long): Drawable? = customDrawable?.let { cd -> fun drawable(resources: Resources, drawableDataMap: CwfResDataMap, sgvLevel: Long): Drawable? = customDrawable?.let { cd ->
when (sgvLevel) { when (sgvLevel) {
1L -> { drawableDataMap[customHigh]?.toDrawable(resources) ?: drawableDataMap[cd]?.toDrawable(resources) } 1L -> { customHigh?.let {drawableDataMap[customHigh.fileName]}?.toDrawable(resources) ?: drawableDataMap[cd.fileName]?.toDrawable(resources) }
0L -> { drawableDataMap[cd]?.toDrawable(resources) } 0L -> { drawableDataMap[cd.fileName]?.toDrawable(resources) }
-1L -> { drawableDataMap[customLow]?.toDrawable(resources) ?: drawableDataMap[cd]?.toDrawable(resources) } -1L -> { customLow?.let {drawableDataMap[customLow.fileName]}?.toDrawable(resources) ?: drawableDataMap[cd.fileName]?.toDrawable(resources) }
else -> drawableDataMap[cd]?.toDrawable(resources) else -> drawableDataMap[cd.fileName]?.toDrawable(resources)
} }
} }
} }
@ -514,7 +514,7 @@ private enum class TrendArrowMap(val symbol: String, @DrawableRes val icon: Int,
fun drawable(direction: String?, resources: Resources, drawableDataMap: CwfResDataMap): Drawable { fun drawable(direction: String?, resources: Resources, drawableDataMap: CwfResDataMap): Drawable {
val arrow = values().firstOrNull { it.symbol == direction } ?:NONE val arrow = values().firstOrNull { it.symbol == direction } ?:NONE
return drawableDataMap[arrow.customDrawable]?.toDrawable(resources) ?:resources.getDrawable(arrow.icon) return arrow.customDrawable?. let {drawableDataMap[arrow.customDrawable.fileName]}?.toDrawable(resources) ?:resources.getDrawable(arrow.icon)
} }
} }
@ -532,36 +532,34 @@ private enum class GravityMap(val key: String, val gravity: Int) {
} }
} }
private enum class FontMap(val key: String, var font: Typeface, @FontRes val fontRessources: Int?, val customFont: ResFileMap?) { private enum class FontMap(val key: String, var font: Typeface, @FontRes val fontRessources: Int?) {
SANS_SERIF(JsonKeyValues.SANS_SERIF.key, Typeface.SANS_SERIF, null, null), SANS_SERIF(JsonKeyValues.SANS_SERIF.key, Typeface.SANS_SERIF, null),
DEFAULT(JsonKeyValues.DEFAULT.key, Typeface.DEFAULT, null, null), DEFAULT(JsonKeyValues.DEFAULT.key, Typeface.DEFAULT, null),
DEFAULT_BOLD(JsonKeyValues.DEFAULT_BOLD.key, Typeface.DEFAULT_BOLD, null, null), DEFAULT_BOLD(JsonKeyValues.DEFAULT_BOLD.key, Typeface.DEFAULT_BOLD, null),
MONOSPACE(JsonKeyValues.MONOSPACE.key, Typeface.MONOSPACE, null, null), MONOSPACE(JsonKeyValues.MONOSPACE.key, Typeface.MONOSPACE, null),
SERIF(JsonKeyValues.SERIF.key, Typeface.SERIF, null, null), SERIF(JsonKeyValues.SERIF.key, Typeface.SERIF, null),
ROBOTO_CONDENSED_BOLD(JsonKeyValues.ROBOTO_CONDENSED_BOLD.key, Typeface.DEFAULT, R.font.roboto_condensed_bold, null), ROBOTO_CONDENSED_BOLD(JsonKeyValues.ROBOTO_CONDENSED_BOLD.key, Typeface.DEFAULT, R.font.roboto_condensed_bold),
ROBOTO_CONDENSED_LIGHT(JsonKeyValues.ROBOTO_CONDENSED_LIGHT.key, Typeface.DEFAULT, R.font.roboto_condensed_light, null), ROBOTO_CONDENSED_LIGHT(JsonKeyValues.ROBOTO_CONDENSED_LIGHT.key, Typeface.DEFAULT, R.font.roboto_condensed_light),
ROBOTO_CONDENSED_REGULAR(JsonKeyValues.ROBOTO_CONDENSED_REGULAR.key, Typeface.DEFAULT, R.font.roboto_condensed_regular, null), ROBOTO_CONDENSED_REGULAR(JsonKeyValues.ROBOTO_CONDENSED_REGULAR.key, Typeface.DEFAULT, R.font.roboto_condensed_regular),
ROBOTO_SLAB_LIGHT(JsonKeyValues.ROBOTO_SLAB_LIGHT.key, Typeface.DEFAULT, R.font.roboto_slab_light, null), ROBOTO_SLAB_LIGHT(JsonKeyValues.ROBOTO_SLAB_LIGHT.key, Typeface.DEFAULT, R.font.roboto_slab_light);
FONT1(JsonKeyValues.FONT1.key, Typeface.DEFAULT, null, ResFileMap.FONT1),
FONT2(JsonKeyValues.FONT2.key, Typeface.DEFAULT, null, ResFileMap.FONT2),
FONT3(JsonKeyValues.FONT3.key, Typeface.DEFAULT, null, ResFileMap.FONT3),
FONT4(JsonKeyValues.FONT4.key, Typeface.DEFAULT, null, ResFileMap.FONT4);
companion object { companion object {
fun init(context: Context, resDataMap: CwfResDataMap) = values().forEach { fontMap -> private val customFonts = mutableMapOf<String, Typeface>()
fontMap.customFont?.let { customFont -> fun init(context: Context, resDataMap: CwfResDataMap) {
fontMap.font = Typeface.DEFAULT values().forEach { fontMap ->
resDataMap[customFont]?.toTypeface()?.let { resData -> customFonts[fontMap.key.lowercase()] = fontMap.fontRessources?.let { fontResource ->
fontMap.font = resData
}
} ?: run {
fontMap.font = fontMap.fontRessources?.let { fontResource ->
ResourcesCompat.getFont(context, fontResource) ResourcesCompat.getFont(context, fontResource)
} ?: fontMap.font } ?: fontMap.font
} }
resDataMap.filter { (_, resData) ->
resData.format == ResFormat.TTF
}.forEach { (key, resData) ->
customFonts[key.lowercase()] = resData.toTypeface() ?:Typeface.DEFAULT
} }
fun font(key: String) = values().firstOrNull { it.key == key }?.font ?: DEFAULT.font }
fun font(key: String) = customFonts[key.lowercase()] ?: DEFAULT.font
fun key() = DEFAULT.key fun key() = DEFAULT.key
} }
} }