Merge pull request #2730 from Philoul/wear/new_custom_watchface
Wear CWF : Reduce complexity and add new customized capabilities
This commit is contained in:
commit
c50bdd0f78
|
@ -2,10 +2,10 @@ package info.nightscout.rx.weardata
|
||||||
|
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
|
import android.graphics.Typeface
|
||||||
import android.graphics.drawable.BitmapDrawable
|
import android.graphics.drawable.BitmapDrawable
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.graphics.drawable.PictureDrawable
|
import android.graphics.drawable.PictureDrawable
|
||||||
import androidx.annotation.DrawableRes
|
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import com.caverock.androidsvg.SVG
|
import com.caverock.androidsvg.SVG
|
||||||
import info.nightscout.shared.R
|
import info.nightscout.shared.R
|
||||||
|
@ -22,53 +22,73 @@ import java.util.zip.ZipOutputStream
|
||||||
|
|
||||||
val CUSTOM_VERSION = "1.0"
|
val CUSTOM_VERSION = "1.0"
|
||||||
|
|
||||||
enum class CwfDrawableFileMap(val key: String, @DrawableRes val icon: Int?, val fileName: String) {
|
enum class ResFileMap(val fileName: String) {
|
||||||
UNKNOWN("unknown", null, "Unknown"),
|
UNKNOWN("Unknown"),
|
||||||
CUSTOM_WATCHFACE("customWatchface", R.drawable.watchface_custom, "CustomWatchface"),
|
CUSTOM_WATCHFACE("CustomWatchface"),
|
||||||
BACKGROUND(ViewKeys.BACKGROUND.key, R.drawable.background, "Background"),
|
BACKGROUND("Background"),
|
||||||
BACKGROUND_HIGH(ViewKeys.BACKGROUND.key, R.drawable.background, "BackgroundHigh"),
|
BACKGROUND_HIGH("BackgroundHigh"),
|
||||||
BACKGROUND_LOW(ViewKeys.BACKGROUND.key, R.drawable.background, "BackgroundLow"),
|
BACKGROUND_LOW("BackgroundLow"),
|
||||||
COVER_CHART(ViewKeys.COVER_CHART.key, null, "CoverChart"),
|
COVER_CHART("CoverChart"),
|
||||||
COVER_PLATE(ViewKeys.COVER_PLATE.key, R.drawable.simplified_dial, "CoverPlate"),
|
COVER_CHART_HIGH("CoverChartHigh"),
|
||||||
HOUR_HAND(ViewKeys.HOUR_HAND.key, R.drawable.hour_hand, "HourHand"),
|
COVER_CHART_LOW("CoverChartLow"),
|
||||||
MINUTE_HAND(ViewKeys.MINUTE_HAND.key, R.drawable.minute_hand, "MinuteHand"),
|
COVER_PLATE("CoverPlate"),
|
||||||
SECOND_HAND(ViewKeys.SECOND_HAND.key, R.drawable.second_hand, "SecondHand");
|
COVER_PLATE_HIGH("CoverPlateHigh"),
|
||||||
|
COVER_PLATE_LOW("CoverPlateLow"),
|
||||||
|
HOUR_HAND("HourHand"),
|
||||||
|
HOUR_HAND_HIGH("HourHandHigh"),
|
||||||
|
HOUR_HAND_LOW("HourHandLow"),
|
||||||
|
MINUTE_HAND("MinuteHand"),
|
||||||
|
MINUTE_HAND_HIGH("MinuteHandHigh"),
|
||||||
|
MINUTE_HAND_LOW("MinuteHandLow"),
|
||||||
|
SECOND_HAND("SecondHand"),
|
||||||
|
SECOND_HAND_HIGH("SecondHandHigh"),
|
||||||
|
SECOND_HAND_LOW("SecondHandLow"),
|
||||||
|
ARROW_NONE("ArrowNone"),
|
||||||
|
ARROW_DOUBLE_UP("ArrowDoubleUp"),
|
||||||
|
ARROW_SINGLE_UP("ArrowSingleUp"),
|
||||||
|
ARROW_FORTY_FIVE_UP("Arrow45Up"),
|
||||||
|
ARROW_FLAT("ArrowFlat"),
|
||||||
|
ARROW_FORTY_FIVE_DOWN("Arrow45Down"),
|
||||||
|
ARROW_SINGLE_DOWN("ArrowSingleDown"),
|
||||||
|
ARROW_DOUBLE_DOWN("ArrowDoubleDown"),
|
||||||
|
FONT1("Font1"),
|
||||||
|
FONT2("Font2"),
|
||||||
|
FONT3("Font3"),
|
||||||
|
FONT4("Font4");
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
fun fromKey(key: String): CwfDrawableFileMap =
|
fun fromFileName(file: String): ResFileMap = values().firstOrNull { it.fileName == file.substringBeforeLast(".") } ?: UNKNOWN
|
||||||
values().firstOrNull { it.key == key } ?: UNKNOWN
|
|
||||||
|
|
||||||
fun fromFileName(file: String): CwfDrawableFileMap = values().firstOrNull { it.fileName == file.substringBeforeLast(".") } ?: UNKNOWN
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class DrawableFormat(val extension: String) {
|
enum class ResFormat(val extension: String) {
|
||||||
UNKNOWN(""),
|
UNKNOWN(""),
|
||||||
SVG("svg"),
|
SVG("svg"),
|
||||||
JPG("jpg"),
|
JPG("jpg"),
|
||||||
PNG("png");
|
PNG("png"),
|
||||||
|
TTF("ttf");
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
fun fromFileName(fileName: String): DrawableFormat =
|
fun fromFileName(fileName: String): ResFormat =
|
||||||
values().firstOrNull { it.extension == fileName.substringAfterLast(".") } ?: UNKNOWN
|
values().firstOrNull { it.extension == fileName.substringAfterLast(".").lowercase() } ?: UNKNOWN
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class DrawableData(val value: ByteArray, val format: DrawableFormat) {
|
data class ResData(val value: ByteArray, val format: ResFormat) {
|
||||||
|
|
||||||
fun toDrawable(resources: Resources): Drawable? {
|
fun toDrawable(resources: Resources): Drawable? {
|
||||||
try {
|
try {
|
||||||
return when (format) {
|
return when (format) {
|
||||||
DrawableFormat.PNG, DrawableFormat.JPG -> {
|
ResFormat.PNG, ResFormat.JPG -> {
|
||||||
val bitmap = BitmapFactory.decodeByteArray(value, 0, value.size)
|
val bitmap = BitmapFactory.decodeByteArray(value, 0, value.size)
|
||||||
BitmapDrawable(resources, bitmap)
|
BitmapDrawable(resources, bitmap)
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawableFormat.SVG -> {
|
ResFormat.SVG -> {
|
||||||
val svg = SVG.getFromInputStream(ByteArrayInputStream(value))
|
val svg = SVG.getFromInputStream(ByteArrayInputStream(value))
|
||||||
val picture = svg.renderToPicture()
|
val picture = svg.renderToPicture()
|
||||||
PictureDrawable(picture).apply {
|
PictureDrawable(picture).apply {
|
||||||
|
@ -76,7 +96,37 @@ data class DrawableData(val value: ByteArray, val format: DrawableFormat) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> null
|
else -> null
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toTypeface(): Typeface? {
|
||||||
|
try {
|
||||||
|
return when (format) {
|
||||||
|
ResFormat.TTF -> {
|
||||||
|
// Workaround with temporary File, Typeface.createFromFileDescriptor(null, value, 0, value.size) more simple not available
|
||||||
|
File.createTempFile("temp", ".ttf").let { tempFile ->
|
||||||
|
FileOutputStream(tempFile).let { fileOutputStream ->
|
||||||
|
fileOutputStream.write(value)
|
||||||
|
fileOutputStream.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
Typeface.createFromFile(tempFile).let {
|
||||||
|
if (!tempFile.delete()) {
|
||||||
|
// delete tempfile after usage
|
||||||
|
}
|
||||||
|
it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
null
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
return null
|
return null
|
||||||
|
@ -84,11 +134,11 @@ data class DrawableData(val value: ByteArray, val format: DrawableFormat) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typealias CwfDrawableDataMap = MutableMap<CwfDrawableFileMap, DrawableData>
|
typealias CwfResDataMap = MutableMap<ResFileMap, ResData>
|
||||||
typealias CwfMetadataMap = MutableMap<CwfMetadataKey, String>
|
typealias CwfMetadataMap = MutableMap<CwfMetadataKey, String>
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class CwfData(val json: String, var metadata: CwfMetadataMap, val drawableDatas: CwfDrawableDataMap)
|
data class CwfData(val json: String, var metadata: CwfMetadataMap, val resDatas: CwfResDataMap)
|
||||||
|
|
||||||
enum class CwfMetadataKey(val key: String, @StringRes val label: Int, val isPref: Boolean) {
|
enum class CwfMetadataKey(val key: String, @StringRes val label: Int, val isPref: Boolean) {
|
||||||
|
|
||||||
|
@ -98,7 +148,7 @@ enum class CwfMetadataKey(val key: String, @StringRes val label: Int, val isPref
|
||||||
CWF_CREATED_AT("created_at", R.string.metadata_label_watchface_created_at, false),
|
CWF_CREATED_AT("created_at", R.string.metadata_label_watchface_created_at, false),
|
||||||
CWF_VERSION("cwf_version", R.string.metadata_label_plugin_version, false),
|
CWF_VERSION("cwf_version", R.string.metadata_label_plugin_version, false),
|
||||||
CWF_AUTHOR_VERSION("author_version", R.string.metadata_label_watchface_name_version, false),
|
CWF_AUTHOR_VERSION("author_version", R.string.metadata_label_watchface_name_version, false),
|
||||||
CWF_COMMENT("comment", R.string.metadata_label_watchface_comment, false), // label not planed to be used for CWF_COMMENT
|
CWF_COMMENT("comment", R.string.metadata_label_watchface_infos, false), // label not planed to be used for CWF_COMMENT
|
||||||
CWF_AUTHORIZATION("cwf_authorization", R.string.metadata_label_watchface_authorization, false),
|
CWF_AUTHORIZATION("cwf_authorization", R.string.metadata_label_watchface_authorization, false),
|
||||||
CWF_PREF_WATCH_SHOW_DETAILED_IOB("key_show_detailed_iob", R.string.pref_show_detailed_iob, true),
|
CWF_PREF_WATCH_SHOW_DETAILED_IOB("key_show_detailed_iob", R.string.pref_show_detailed_iob, true),
|
||||||
CWF_PREF_WATCH_SHOW_DETAILED_DELTA("key_show_detailed_delta", R.string.pref_show_detailed_delta, true),
|
CWF_PREF_WATCH_SHOW_DETAILED_DELTA("key_show_detailed_delta", R.string.pref_show_detailed_delta, true),
|
||||||
|
@ -210,7 +260,10 @@ enum class JsonKeyValues(val key: String, val jsonKey: JsonKeys) {
|
||||||
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),
|
||||||
BGCOLOR1("bgColor", JsonKeys.FONTCOLOR)
|
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?) {
|
||||||
|
@ -229,7 +282,7 @@ class ZipWatchfaceFormat {
|
||||||
fun loadCustomWatchface(cwfFile: File, authorization: Boolean): CwfData? {
|
fun loadCustomWatchface(cwfFile: File, authorization: Boolean): CwfData? {
|
||||||
var json = JSONObject()
|
var json = JSONObject()
|
||||||
var metadata: CwfMetadataMap = mutableMapOf()
|
var metadata: CwfMetadataMap = mutableMapOf()
|
||||||
val drawableDatas: CwfDrawableDataMap = mutableMapOf()
|
val resDatas: CwfResDataMap = mutableMapOf()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val zipInputStream = ZipInputStream(cwfFile.inputStream())
|
val zipInputStream = ZipInputStream(cwfFile.inputStream())
|
||||||
|
@ -253,18 +306,18 @@ class ZipWatchfaceFormat {
|
||||||
metadata[CwfMetadataKey.CWF_FILENAME] = cwfFile.name
|
metadata[CwfMetadataKey.CWF_FILENAME] = cwfFile.name
|
||||||
metadata[CwfMetadataKey.CWF_AUTHORIZATION] = authorization.toString()
|
metadata[CwfMetadataKey.CWF_AUTHORIZATION] = authorization.toString()
|
||||||
} else {
|
} else {
|
||||||
val cwfDrawableFileMap = CwfDrawableFileMap.fromFileName(entryName)
|
val cwfResFileMap = ResFileMap.fromFileName(entryName)
|
||||||
val drawableFormat = DrawableFormat.fromFileName(entryName)
|
val drawableFormat = ResFormat.fromFileName(entryName)
|
||||||
if (cwfDrawableFileMap != CwfDrawableFileMap.UNKNOWN && drawableFormat != DrawableFormat.UNKNOWN) {
|
if (cwfResFileMap != ResFileMap.UNKNOWN && drawableFormat != ResFormat.UNKNOWN) {
|
||||||
drawableDatas[cwfDrawableFileMap] = DrawableData(byteArrayOutputStream.toByteArray(), drawableFormat)
|
resDatas[cwfResFileMap] = 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) && drawableDatas.containsKey(CwfDrawableFileMap.CUSTOM_WATCHFACE))
|
return if (metadata.containsKey(CwfMetadataKey.CWF_NAME) && resDatas.containsKey(ResFileMap.CUSTOM_WATCHFACE))
|
||||||
CwfData(json.toString(4), metadata, drawableDatas)
|
CwfData(json.toString(4), metadata, resDatas)
|
||||||
else
|
else
|
||||||
null
|
null
|
||||||
|
|
||||||
|
@ -286,10 +339,10 @@ class ZipWatchfaceFormat {
|
||||||
zipOutputStream.closeEntry()
|
zipOutputStream.closeEntry()
|
||||||
|
|
||||||
// Ajouter les fichiers divers au ZIP
|
// Ajouter les fichiers divers au ZIP
|
||||||
for (drawableData in customWatchface.drawableDatas) {
|
for (resData in customWatchface.resDatas) {
|
||||||
val fileEntry = ZipEntry("${drawableData.key.fileName}.${drawableData.value.format.extension}")
|
val fileEntry = ZipEntry("${resData.key.fileName}.${resData.value.format.extension}")
|
||||||
zipOutputStream.putNextEntry(fileEntry)
|
zipOutputStream.putNextEntry(fileEntry)
|
||||||
zipOutputStream.write(drawableData.value.value)
|
zipOutputStream.write(resData.value.value)
|
||||||
zipOutputStream.closeEntry()
|
zipOutputStream.closeEntry()
|
||||||
}
|
}
|
||||||
zipOutputStream.close()
|
zipOutputStream.close()
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
<string name="metadata_wear_import_filename">Failo pavadinimas: %1$s</string>
|
<string name="metadata_wear_import_filename">Failo pavadinimas: %1$s</string>
|
||||||
<string name="metadata_label_plugin_version">Įskiepio versija: %1$s</string>
|
<string name="metadata_label_plugin_version">Įskiepio versija: %1$s</string>
|
||||||
<string name="metadata_label_watchface_name_version">Pavadinimas: %1$s (%2$s)</string>
|
<string name="metadata_label_watchface_name_version">Pavadinimas: %1$s (%2$s)</string>
|
||||||
<string name="metadata_label_watchface_comment">Komentaras: %1$s</string>
|
<string name="metadata_label_watchface_info">Komentaras: %1$s</string>
|
||||||
<string name="pref_show_iob">Rodyti AIO</string>
|
<string name="pref_show_iob">Rodyti AIO</string>
|
||||||
<string name="pref_show_detailed_iob">Rodyti detalų AIO</string>
|
<string name="pref_show_detailed_iob">Rodyti detalų AIO</string>
|
||||||
<string name="pref_show_cob">Rodyti AAO</string>
|
<string name="pref_show_cob">Rodyti AAO</string>
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
<string name="metadata_wear_import_filename">File name: %1$s</string>
|
<string name="metadata_wear_import_filename">File name: %1$s</string>
|
||||||
<string name="metadata_label_plugin_version">Plugin version: %1$s</string>
|
<string name="metadata_label_plugin_version">Plugin version: %1$s</string>
|
||||||
<string name="metadata_label_watchface_name_version">Name: %1$s (%2$s)</string>
|
<string name="metadata_label_watchface_name_version">Name: %1$s (%2$s)</string>
|
||||||
<string name="metadata_label_watchface_comment">Comment: %1$s</string>
|
<string name="metadata_label_watchface_infos">Info: %1$s</string>
|
||||||
<string name="metadata_label_watchface_authorization" translatable="false">%1$s</string>
|
<string name="metadata_label_watchface_authorization" translatable="false">%1$s</string>
|
||||||
<string name="pref_show_iob">Show IOB</string>
|
<string name="pref_show_iob">Show IOB</string>
|
||||||
<string name="pref_show_detailed_iob">Show detailed IOB</string>
|
<string name="pref_show_detailed_iob">Show detailed IOB</string>
|
||||||
|
|
|
@ -18,7 +18,7 @@ import info.nightscout.rx.events.EventMobileDataToWear
|
||||||
import info.nightscout.rx.logging.AAPSLogger
|
import info.nightscout.rx.logging.AAPSLogger
|
||||||
import info.nightscout.rx.weardata.CUSTOM_VERSION
|
import info.nightscout.rx.weardata.CUSTOM_VERSION
|
||||||
import info.nightscout.rx.weardata.CwfData
|
import info.nightscout.rx.weardata.CwfData
|
||||||
import info.nightscout.rx.weardata.CwfDrawableFileMap
|
import info.nightscout.rx.weardata.ResFileMap
|
||||||
import info.nightscout.rx.weardata.CwfMetadataKey.CWF_AUTHOR
|
import info.nightscout.rx.weardata.CwfMetadataKey.CWF_AUTHOR
|
||||||
import info.nightscout.rx.weardata.CwfMetadataKey.CWF_AUTHOR_VERSION
|
import info.nightscout.rx.weardata.CwfMetadataKey.CWF_AUTHOR_VERSION
|
||||||
import info.nightscout.rx.weardata.CwfMetadataKey.CWF_CREATED_AT
|
import info.nightscout.rx.weardata.CwfMetadataKey.CWF_CREATED_AT
|
||||||
|
@ -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.drawableDatas[CwfDrawableFileMap
|
val drawable = customWatchfaceFile.resDatas[ResFileMap
|
||||||
.CUSTOM_WATCHFACE]?.toDrawable(resources)
|
.CUSTOM_WATCHFACE]?.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])
|
||||||
|
|
|
@ -18,7 +18,7 @@ import info.nightscout.rx.events.EventMobileToWear
|
||||||
import info.nightscout.rx.events.EventWearUpdateGui
|
import info.nightscout.rx.events.EventWearUpdateGui
|
||||||
import info.nightscout.rx.logging.AAPSLogger
|
import info.nightscout.rx.logging.AAPSLogger
|
||||||
import info.nightscout.rx.weardata.CwfData
|
import info.nightscout.rx.weardata.CwfData
|
||||||
import info.nightscout.rx.weardata.CwfDrawableFileMap
|
import info.nightscout.rx.weardata.ResFileMap
|
||||||
import info.nightscout.rx.weardata.CwfMetadataKey
|
import info.nightscout.rx.weardata.CwfMetadataKey
|
||||||
import info.nightscout.rx.weardata.EventData
|
import info.nightscout.rx.weardata.EventData
|
||||||
import info.nightscout.shared.extensions.toVisibility
|
import info.nightscout.shared.extensions.toVisibility
|
||||||
|
@ -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.drawableDatas[CwfDrawableFileMap.CUSTOM_WATCHFACE]?.toDrawable(resources))
|
binding.coverChart.setImageDrawable(it.resDatas[ResFileMap.CUSTOM_WATCHFACE]?.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, "")
|
||||||
|
|
|
@ -20,7 +20,7 @@ import info.nightscout.rx.events.EventWearUpdateGui
|
||||||
import info.nightscout.rx.logging.AAPSLogger
|
import info.nightscout.rx.logging.AAPSLogger
|
||||||
import info.nightscout.rx.logging.LTag
|
import info.nightscout.rx.logging.LTag
|
||||||
import info.nightscout.rx.weardata.CUSTOM_VERSION
|
import info.nightscout.rx.weardata.CUSTOM_VERSION
|
||||||
import info.nightscout.rx.weardata.CwfDrawableFileMap
|
import info.nightscout.rx.weardata.ResFileMap
|
||||||
import info.nightscout.rx.weardata.CwfMetadataKey
|
import info.nightscout.rx.weardata.CwfMetadataKey
|
||||||
import info.nightscout.rx.weardata.CwfMetadataMap
|
import info.nightscout.rx.weardata.CwfMetadataMap
|
||||||
import info.nightscout.rx.weardata.JsonKeyValues
|
import info.nightscout.rx.weardata.JsonKeyValues
|
||||||
|
@ -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.drawableDatas[CwfDrawableFileMap.CUSTOM_WATCHFACE]?.toDrawable(resources)
|
val drawable = it.resDatas[ResFileMap.CUSTOM_WATCHFACE]?.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 ->
|
||||||
|
|
|
@ -4,12 +4,14 @@ package info.nightscout.androidaps.watchfaces
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.res.Resources
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.graphics.ColorFilter
|
import android.graphics.ColorFilter
|
||||||
import android.graphics.ColorMatrix
|
import android.graphics.ColorMatrix
|
||||||
import android.graphics.ColorMatrixColorFilter
|
import android.graphics.ColorMatrixColorFilter
|
||||||
import android.graphics.Point
|
import android.graphics.Point
|
||||||
import android.graphics.Typeface
|
import android.graphics.Typeface
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
import android.support.wearable.watchface.WatchFaceStyle
|
import android.support.wearable.watchface.WatchFaceStyle
|
||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
import android.view.Gravity
|
import android.view.Gravity
|
||||||
|
@ -33,12 +35,12 @@ import info.nightscout.androidaps.watchfaces.utils.BaseWatchFace
|
||||||
import info.nightscout.rx.logging.LTag
|
import info.nightscout.rx.logging.LTag
|
||||||
import info.nightscout.rx.weardata.CUSTOM_VERSION
|
import info.nightscout.rx.weardata.CUSTOM_VERSION
|
||||||
import info.nightscout.rx.weardata.CwfData
|
import info.nightscout.rx.weardata.CwfData
|
||||||
import info.nightscout.rx.weardata.CwfDrawableFileMap
|
import info.nightscout.rx.weardata.ResFileMap
|
||||||
import info.nightscout.rx.weardata.CwfDrawableDataMap
|
import info.nightscout.rx.weardata.CwfResDataMap
|
||||||
import info.nightscout.rx.weardata.CwfMetadataKey
|
import info.nightscout.rx.weardata.CwfMetadataKey
|
||||||
import info.nightscout.rx.weardata.CwfMetadataMap
|
import info.nightscout.rx.weardata.CwfMetadataMap
|
||||||
import info.nightscout.rx.weardata.DrawableData
|
import info.nightscout.rx.weardata.ResData
|
||||||
import info.nightscout.rx.weardata.DrawableFormat
|
import info.nightscout.rx.weardata.ResFormat
|
||||||
import info.nightscout.rx.weardata.EventData
|
import info.nightscout.rx.weardata.EventData
|
||||||
import info.nightscout.rx.weardata.JsonKeyValues
|
import info.nightscout.rx.weardata.JsonKeyValues
|
||||||
import info.nightscout.rx.weardata.JsonKeys.*
|
import info.nightscout.rx.weardata.JsonKeys.*
|
||||||
|
@ -61,10 +63,11 @@ class CustomWatchface : BaseWatchFace() {
|
||||||
private val TEMPLATE_RESOLUTION = 400
|
private val TEMPLATE_RESOLUTION = 400
|
||||||
private var lowBatColor = Color.RED
|
private var lowBatColor = Color.RED
|
||||||
private var bgColor = Color.WHITE
|
private var bgColor = Color.WHITE
|
||||||
|
private var resDataMap: CwfResDataMap = mutableMapOf()
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
FontMap.init(context)
|
FontMap.init(context, resDataMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
|
@ -88,7 +91,7 @@ class CustomWatchface : BaseWatchFace() {
|
||||||
@SuppressLint("UseCompatLoadingForDrawables")
|
@SuppressLint("UseCompatLoadingForDrawables")
|
||||||
override fun setDataFields() {
|
override fun setDataFields() {
|
||||||
super.setDataFields()
|
super.setDataFields()
|
||||||
binding.direction2.setImageDrawable(this.resources.getDrawable(TrendArrowMap.icon(singleBg.slopeArrow)))
|
binding.direction2.setImageDrawable(TrendArrowMap.drawable(singleBg.slopeArrow, resources, resDataMap))
|
||||||
// rotate the second hand.
|
// rotate the second hand.
|
||||||
binding.secondHand.rotation = TimeOfDay().secondOfMinute * 6f
|
binding.secondHand.rotation = TimeOfDay().secondOfMinute * 6f
|
||||||
// rotate the minute hand.
|
// rotate the minute hand.
|
||||||
|
@ -100,7 +103,7 @@ class CustomWatchface : BaseWatchFace() {
|
||||||
override fun setColorDark() {
|
override fun setColorDark() {
|
||||||
setWatchfaceStyle()
|
setWatchfaceStyle()
|
||||||
binding.sgv.setTextColor(bgColor)
|
binding.sgv.setTextColor(bgColor)
|
||||||
binding.direction2.colorFilter = changeDrawableColor(bgColor)
|
binding.direction2.setColorFilter(changeDrawableColor(bgColor))
|
||||||
|
|
||||||
if (ageLevel != 1)
|
if (ageLevel != 1)
|
||||||
binding.timestamp.setTextColor(ContextCompat.getColor(this, R.color.dark_TimestampOld))
|
binding.timestamp.setTextColor(ContextCompat.getColor(this, R.color.dark_TimestampOld))
|
||||||
|
@ -128,7 +131,6 @@ class CustomWatchface : BaseWatchFace() {
|
||||||
getString(R.string.hour_minute_second, dateUtil.hourString(), dateUtil.minuteString(), dateUtil.secondString())
|
getString(R.string.hour_minute_second, dateUtil.hourString(), dateUtil.minuteString(), dateUtil.secondString())
|
||||||
else
|
else
|
||||||
getString(R.string.hour_minute, dateUtil.hourString(), dateUtil.minuteString())
|
getString(R.string.hour_minute, dateUtil.hourString(), dateUtil.minuteString())
|
||||||
//binding.time.text = "${dateUtil.hourString()}:${dateUtil.minuteString()}" + if (showSecond) ":${dateUtil.secondString()}" else ""
|
|
||||||
binding.second.text = dateUtil.secondString()
|
binding.second.text = dateUtil.secondString()
|
||||||
// rotate the second hand.
|
// rotate the second hand.
|
||||||
binding.secondHand.rotation = TimeOfDay().secondOfMinute * 6f
|
binding.secondHand.rotation = TimeOfDay().secondOfMinute * 6f
|
||||||
|
@ -146,7 +148,8 @@ class CustomWatchface : BaseWatchFace() {
|
||||||
updatePref(it.customWatchfaceData.metadata)
|
updatePref(it.customWatchfaceData.metadata)
|
||||||
try {
|
try {
|
||||||
val json = JSONObject(it.customWatchfaceData.json)
|
val json = JSONObject(it.customWatchfaceData.json)
|
||||||
val drawableDataMap = it.customWatchfaceData.drawableDatas
|
resDataMap = it.customWatchfaceData.resDatas
|
||||||
|
FontMap.init(context, resDataMap)
|
||||||
enableSecond = json.optBoolean(ENABLESECOND.key) && sp.getBoolean(R.string.key_show_seconds, true)
|
enableSecond = json.optBoolean(ENABLESECOND.key) && sp.getBoolean(R.string.key_show_seconds, true)
|
||||||
highColor = getColor(json.optString(HIGHCOLOR.key), ContextCompat.getColor(this, R.color.dark_highColor))
|
highColor = getColor(json.optString(HIGHCOLOR.key), ContextCompat.getColor(this, R.color.dark_highColor))
|
||||||
midColor = getColor(json.optString(MIDCOLOR.key), ContextCompat.getColor(this, R.color.inrange))
|
midColor = getColor(json.optString(MIDCOLOR.key), ContextCompat.getColor(this, R.color.inrange))
|
||||||
|
@ -167,17 +170,10 @@ class CustomWatchface : BaseWatchFace() {
|
||||||
-1L -> lowColor
|
-1L -> lowColor
|
||||||
else -> midColor
|
else -> midColor
|
||||||
}
|
}
|
||||||
val backGroundDrawable = when (singleBg.sgvLevel) {
|
|
||||||
1L -> drawableDataMap[CwfDrawableFileMap.BACKGROUND_HIGH]?.toDrawable(resources) ?: drawableDataMap[CwfDrawableFileMap.BACKGROUND]?.toDrawable(resources)
|
|
||||||
0L -> drawableDataMap[CwfDrawableFileMap.BACKGROUND]?.toDrawable(resources)
|
|
||||||
-1L -> drawableDataMap[CwfDrawableFileMap.BACKGROUND_LOW]?.toDrawable(resources) ?: drawableDataMap[CwfDrawableFileMap.BACKGROUND]?.toDrawable(resources)
|
|
||||||
else -> drawableDataMap[CwfDrawableFileMap.BACKGROUND]?.toDrawable(resources)
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.mainLayout.forEach { view ->
|
binding.mainLayout.forEach { view ->
|
||||||
ViewMap.fromId(view.id)?.let { id ->
|
ViewMap.fromId(view.id)?.let { id ->
|
||||||
if (json.has(id.key)) {
|
json.optJSONObject(id.key)?.also { viewJson ->
|
||||||
val viewJson = json.getJSONObject(id.key)
|
|
||||||
val width = (viewJson.optInt(WIDTH.key) * zoomFactor).toInt()
|
val width = (viewJson.optInt(WIDTH.key) * zoomFactor).toInt()
|
||||||
val height = (viewJson.optInt(HEIGHT.key) * zoomFactor).toInt()
|
val height = (viewJson.optInt(HEIGHT.key) * zoomFactor).toInt()
|
||||||
val params = FrameLayout.LayoutParams(width, height)
|
val params = FrameLayout.LayoutParams(width, height)
|
||||||
|
@ -202,18 +198,14 @@ class CustomWatchface : BaseWatchFace() {
|
||||||
|
|
||||||
is ImageView -> {
|
is ImageView -> {
|
||||||
view.clearColorFilter()
|
view.clearColorFilter()
|
||||||
val drawable = if (id.key == CwfDrawableFileMap.BACKGROUND.key)
|
id.drawable(resources, resDataMap, singleBg.sgvLevel)?.let {
|
||||||
backGroundDrawable
|
if (viewJson.has(COLOR.key)) // Note only works on bitmap (png or jpg) or xml included into res, not for svg files
|
||||||
else
|
|
||||||
drawableDataMap[CwfDrawableFileMap.fromKey(id.key)]?.toDrawable(resources)
|
|
||||||
drawable?.let {
|
|
||||||
if (viewJson.has(COLOR.key))
|
|
||||||
it.colorFilter = changeDrawableColor(getColor(viewJson.optString(COLOR.key)))
|
it.colorFilter = changeDrawableColor(getColor(viewJson.optString(COLOR.key)))
|
||||||
else
|
else
|
||||||
it.clearColorFilter()
|
it.clearColorFilter()
|
||||||
view.setImageDrawable(it)
|
view.setImageDrawable(it)
|
||||||
} ?: apply {
|
} ?: apply {
|
||||||
view.setImageDrawable(CwfDrawableFileMap.fromKey(id.key).icon?.let { context.getDrawable(it) })
|
view.setImageDrawable(id.defaultDrawable?.let {resources.getDrawable(it)})
|
||||||
if (viewJson.has(COLOR.key))
|
if (viewJson.has(COLOR.key))
|
||||||
view.setColorFilter(getColor(viewJson.optString(COLOR.key)))
|
view.setColorFilter(getColor(viewJson.optString(COLOR.key)))
|
||||||
else
|
else
|
||||||
|
@ -222,7 +214,7 @@ class CustomWatchface : BaseWatchFace() {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
} ?:apply {
|
||||||
view.visibility = View.GONE
|
view.visibility = View.GONE
|
||||||
if (view is TextView) {
|
if (view is TextView) {
|
||||||
view.text = ""
|
view.text = ""
|
||||||
|
@ -305,9 +297,9 @@ class CustomWatchface : BaseWatchFace() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val metadataMap = ZipWatchfaceFormat.loadMetadata(json)
|
val metadataMap = ZipWatchfaceFormat.loadMetadata(json)
|
||||||
val drawableDataMap: CwfDrawableDataMap = mutableMapOf()
|
val drawableDataMap: CwfResDataMap = mutableMapOf()
|
||||||
getResourceByteArray(info.nightscout.shared.R.drawable.watchface_custom)?.let {
|
getResourceByteArray(info.nightscout.shared.R.drawable.watchface_custom)?.let {
|
||||||
drawableDataMap[CwfDrawableFileMap.CUSTOM_WATCHFACE] = DrawableData(it, DrawableFormat.PNG)
|
drawableDataMap[ResFileMap.CUSTOM_WATCHFACE] = ResData(it, ResFormat.PNG)
|
||||||
}
|
}
|
||||||
return EventData.ActionSetCustomWatchface(CwfData(json.toString(4), metadataMap, drawableDataMap))
|
return EventData.ActionSetCustomWatchface(CwfData(json.toString(4), metadataMap, drawableDataMap))
|
||||||
}
|
}
|
||||||
|
@ -327,7 +319,7 @@ class CustomWatchface : BaseWatchFace() {
|
||||||
JsonKeyValues.VISIBLE.key -> pref.toVisibility()
|
JsonKeyValues.VISIBLE.key -> pref.toVisibility()
|
||||||
JsonKeyValues.INVISIBLE.key -> pref.toVisibilityKeepSpace()
|
JsonKeyValues.INVISIBLE.key -> pref.toVisibilityKeepSpace()
|
||||||
JsonKeyValues.GONE.key -> View.GONE
|
JsonKeyValues.GONE.key -> View.GONE
|
||||||
else -> View.GONE
|
else -> View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getVisibility(visibility: Int): String = when (visibility) {
|
private fun getVisibility(visibility: Int): String = when (visibility) {
|
||||||
|
@ -373,7 +365,11 @@ class CustomWatchface : BaseWatchFace() {
|
||||||
if (color == JsonKeyValues.BGCOLOR.key)
|
if (color == JsonKeyValues.BGCOLOR.key)
|
||||||
bgColor
|
bgColor
|
||||||
else
|
else
|
||||||
try { Color.parseColor(color) } catch (e: Exception) { defaultColor }
|
try {
|
||||||
|
Color.parseColor(color)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
defaultColor
|
||||||
|
}
|
||||||
|
|
||||||
private fun manageSpecificViews() {
|
private fun manageSpecificViews() {
|
||||||
//Background should fill all the watchface and must be visible
|
//Background should fill all the watchface and must be visible
|
||||||
|
@ -388,41 +384,98 @@ class CustomWatchface : BaseWatchFace() {
|
||||||
// Update timePeriod visibility
|
// Update timePeriod visibility
|
||||||
binding.timePeriod.visibility = (binding.timePeriod.visibility == View.VISIBLE && android.text.format.DateFormat.is24HourFormat(this).not()).toVisibility()
|
binding.timePeriod.visibility = (binding.timePeriod.visibility == View.VISIBLE && android.text.format.DateFormat.is24HourFormat(this).not()).toVisibility()
|
||||||
}
|
}
|
||||||
private enum class ViewMap(val key: String, @IdRes val id: Int, @StringRes val pref: Int?) {
|
|
||||||
|
|
||||||
BACKGROUND(ViewKeys.BACKGROUND.key, R.id.background, null),
|
private enum class ViewMap(
|
||||||
CHART(ViewKeys.CHART.key, R.id.chart, null),
|
val key: String,
|
||||||
COVER_CHART(ViewKeys.COVER_CHART.key, R.id.cover_chart, null),
|
@IdRes val id: Int,
|
||||||
FREETEXT1(ViewKeys.FREETEXT1.key, R.id.freetext1, null),
|
@StringRes val pref: Int?,
|
||||||
FREETEXT2(ViewKeys.FREETEXT2.key, R.id.freetext2, null),
|
@IdRes val defaultDrawable: Int?,
|
||||||
FREETEXT3(ViewKeys.FREETEXT3.key, R.id.freetext3, null),
|
val customDrawable: ResFileMap?,
|
||||||
FREETEXT4(ViewKeys.FREETEXT4.key, R.id.freetext4, null),
|
val customHigh:ResFileMap?,
|
||||||
IOB1(ViewKeys.IOB1.key, R.id.iob1, R.string.key_show_iob),
|
val customLow: ResFileMap?
|
||||||
IOB2(ViewKeys.IOB2.key, R.id.iob2, R.string.key_show_iob),
|
) {
|
||||||
COB1(ViewKeys.COB1.key, R.id.cob1, R.string.key_show_cob),
|
|
||||||
COB2(ViewKeys.COB2.key, R.id.cob2, R.string.key_show_cob),
|
BACKGROUND(
|
||||||
DELTA(ViewKeys.DELTA.key, R.id.delta, R.string.key_show_delta),
|
ViewKeys.BACKGROUND.key,
|
||||||
AVG_DELTA(ViewKeys.AVG_DELTA.key, R.id.avg_delta, R.string.key_show_avg_delta),
|
R.id.background,
|
||||||
UPLOADER_BATTERY(ViewKeys.UPLOADER_BATTERY.key, R.id.uploader_battery, R.string.key_show_uploader_battery),
|
null,
|
||||||
RIG_BATTERY(ViewKeys.RIG_BATTERY.key, R.id.rig_battery, R.string.key_show_rig_battery),
|
info.nightscout.shared.R.drawable.background,
|
||||||
BASALRATE(ViewKeys.BASALRATE.key, R.id.basalRate, R.string.key_show_temp_basal),
|
ResFileMap.BACKGROUND,
|
||||||
BGI(ViewKeys.BGI.key, R.id.bgi, R.string.key_show_bgi),
|
ResFileMap.BACKGROUND_HIGH,
|
||||||
TIME(ViewKeys.TIME.key, R.id.time, null),
|
ResFileMap.BACKGROUND_LOW
|
||||||
HOUR(ViewKeys.HOUR.key, R.id.hour, null),
|
),
|
||||||
MINUTE(ViewKeys.MINUTE.key, R.id.minute, null),
|
CHART(ViewKeys.CHART.key, R.id.chart, null, null, null, null, null),
|
||||||
SECOND(ViewKeys.SECOND.key, R.id.second, R.string.key_show_seconds),
|
COVER_CHART(
|
||||||
TIMEPERIOD(ViewKeys.TIMEPERIOD.key, R.id.timePeriod, null),
|
ViewKeys.COVER_CHART.key,
|
||||||
DAY_NAME(ViewKeys.DAY_NAME.key, R.id.day_name, null),
|
R.id.cover_chart,
|
||||||
DAY(ViewKeys.DAY.key, R.id.day, null),
|
null,
|
||||||
MONTH(ViewKeys.MONTH.key, R.id.month, null),
|
null,
|
||||||
LOOP(ViewKeys.LOOP.key, R.id.loop, R.string.key_show_external_status),
|
ResFileMap.COVER_CHART,
|
||||||
DIRECTION(ViewKeys.DIRECTION.key, R.id.direction2, R.string.key_show_direction),
|
ResFileMap.COVER_CHART_HIGH,
|
||||||
TIMESTAMP(ViewKeys.TIMESTAMP.key, R.id.timestamp, R.string.key_show_ago),
|
ResFileMap.COVER_CHART_LOW
|
||||||
SGV(ViewKeys.SGV.key, R.id.sgv, R.string.key_show_bg),
|
),
|
||||||
COVER_PLATE(ViewKeys.COVER_PLATE.key, R.id.cover_plate, null),
|
FREETEXT1(ViewKeys.FREETEXT1.key, R.id.freetext1, null, null, null, null, null),
|
||||||
HOUR_HAND(ViewKeys.HOUR_HAND.key, R.id.hour_hand, null),
|
FREETEXT2(ViewKeys.FREETEXT2.key, R.id.freetext2, null, null, null, null, null),
|
||||||
MINUTE_HAND(ViewKeys.MINUTE_HAND.key, R.id.minute_hand, null),
|
FREETEXT3(ViewKeys.FREETEXT3.key, R.id.freetext3, null, null, null, null, null),
|
||||||
SECOND_HAND(ViewKeys.SECOND_HAND.key, R.id.second_hand, R.string.key_show_seconds);
|
FREETEXT4(ViewKeys.FREETEXT4.key, R.id.freetext4, null, null, null, null, null),
|
||||||
|
IOB1(ViewKeys.IOB1.key, R.id.iob1, R.string.key_show_iob, null, null, null, null),
|
||||||
|
IOB2(ViewKeys.IOB2.key, R.id.iob2, R.string.key_show_iob, null, null, null, null),
|
||||||
|
COB1(ViewKeys.COB1.key, R.id.cob1, R.string.key_show_cob, null, null, null, null),
|
||||||
|
COB2(ViewKeys.COB2.key, R.id.cob2, R.string.key_show_cob, null, null, null, null),
|
||||||
|
DELTA(ViewKeys.DELTA.key, R.id.delta, R.string.key_show_delta, null, null, null, null),
|
||||||
|
AVG_DELTA(ViewKeys.AVG_DELTA.key, R.id.avg_delta, R.string.key_show_avg_delta, null, null, null, null),
|
||||||
|
UPLOADER_BATTERY(ViewKeys.UPLOADER_BATTERY.key, R.id.uploader_battery, R.string.key_show_uploader_battery, null, null, null, null),
|
||||||
|
RIG_BATTERY(ViewKeys.RIG_BATTERY.key, R.id.rig_battery, R.string.key_show_rig_battery, null, null, null, null),
|
||||||
|
BASALRATE(ViewKeys.BASALRATE.key, R.id.basalRate, R.string.key_show_temp_basal, null, null, null, null),
|
||||||
|
BGI(ViewKeys.BGI.key, R.id.bgi, R.string.key_show_bgi, null, null, null, null),
|
||||||
|
TIME(ViewKeys.TIME.key, R.id.time, null, null, null, null, null),
|
||||||
|
HOUR(ViewKeys.HOUR.key, R.id.hour, null, null, null, null, null),
|
||||||
|
MINUTE(ViewKeys.MINUTE.key, R.id.minute, null, null, null, null, null),
|
||||||
|
SECOND(ViewKeys.SECOND.key, R.id.second, R.string.key_show_seconds, null, null, null, null),
|
||||||
|
TIMEPERIOD(ViewKeys.TIMEPERIOD.key, R.id.timePeriod, null, null, null, null, null),
|
||||||
|
DAY_NAME(ViewKeys.DAY_NAME.key, R.id.day_name, null, null, null, null, null),
|
||||||
|
DAY(ViewKeys.DAY.key, R.id.day, null, null, null, null, null),
|
||||||
|
MONTH(ViewKeys.MONTH.key, R.id.month, null, null, null, null, null),
|
||||||
|
LOOP(ViewKeys.LOOP.key, R.id.loop, R.string.key_show_external_status, null, null, null, null),
|
||||||
|
DIRECTION(ViewKeys.DIRECTION.key, R.id.direction2, R.string.key_show_direction, null, null, null, null),
|
||||||
|
TIMESTAMP(ViewKeys.TIMESTAMP.key, R.id.timestamp, R.string.key_show_ago, null, null, null, null),
|
||||||
|
SGV(ViewKeys.SGV.key, R.id.sgv, R.string.key_show_bg, null, null, null, null),
|
||||||
|
COVER_PLATE(
|
||||||
|
ViewKeys.COVER_PLATE.key,
|
||||||
|
R.id.cover_plate,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
ResFileMap.COVER_PLATE,
|
||||||
|
ResFileMap.COVER_PLATE_HIGH,
|
||||||
|
ResFileMap.COVER_PLATE_LOW
|
||||||
|
),
|
||||||
|
HOUR_HAND(
|
||||||
|
ViewKeys.HOUR_HAND.key,
|
||||||
|
R.id.hour_hand,
|
||||||
|
null,
|
||||||
|
info.nightscout.shared.R.drawable.hour_hand,
|
||||||
|
ResFileMap.HOUR_HAND,
|
||||||
|
ResFileMap.HOUR_HAND_HIGH,
|
||||||
|
ResFileMap.HOUR_HAND_LOW
|
||||||
|
),
|
||||||
|
MINUTE_HAND(
|
||||||
|
ViewKeys.MINUTE_HAND.key,
|
||||||
|
R.id.minute_hand,
|
||||||
|
null,
|
||||||
|
info.nightscout.shared.R.drawable.minute_hand,
|
||||||
|
ResFileMap.MINUTE_HAND,
|
||||||
|
ResFileMap.MINUTE_HAND_HIGH,
|
||||||
|
ResFileMap.MINUTE_HAND_LOW
|
||||||
|
),
|
||||||
|
SECOND_HAND(
|
||||||
|
ViewKeys.SECOND_HAND.key,
|
||||||
|
R.id.second_hand,
|
||||||
|
R.string.key_show_seconds,
|
||||||
|
info.nightscout.shared.R.drawable.second_hand,
|
||||||
|
ResFileMap.SECOND_HAND,
|
||||||
|
ResFileMap.SECOND_HAND_HIGH,
|
||||||
|
ResFileMap.SECOND_HAND_LOW
|
||||||
|
);
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
|
@ -431,85 +484,116 @@ class CustomWatchface : BaseWatchFace() {
|
||||||
|
|
||||||
fun visibility(sp: SP): Boolean = this.pref?.let { sp.getBoolean(it, true) }
|
fun visibility(sp: SP): Boolean = this.pref?.let { sp.getBoolean(it, true) }
|
||||||
?: true
|
?: true
|
||||||
}
|
|
||||||
|
|
||||||
private enum class TrendArrowMap(val symbol: String, @DrawableRes val icon: Int) {
|
fun drawable(resources: Resources, drawableDataMap: CwfResDataMap, sgvLevel: Long): Drawable? = customDrawable?.let { cd ->
|
||||||
NONE("??", R.drawable.ic_invalid),
|
when (sgvLevel) {
|
||||||
TRIPLE_UP("X", R.drawable.ic_doubleup),
|
1L -> { drawableDataMap[customHigh]?.toDrawable(resources) ?: drawableDataMap[cd]?.toDrawable(resources) }
|
||||||
DOUBLE_UP("\u21c8", R.drawable.ic_doubleup),
|
0L -> { drawableDataMap[cd]?.toDrawable(resources) }
|
||||||
SINGLE_UP("\u2191", R.drawable.ic_singleup),
|
-1L -> { drawableDataMap[customLow]?.toDrawable(resources) ?: drawableDataMap[cd]?.toDrawable(resources) }
|
||||||
FORTY_FIVE_UP("\u2197", R.drawable.ic_fortyfiveup),
|
else -> drawableDataMap[cd]?.toDrawable(resources)
|
||||||
FLAT("\u2192", R.drawable.ic_flat),
|
}
|
||||||
FORTY_FIVE_DOWN("\u2198", R.drawable.ic_fortyfivedown),
|
|
||||||
SINGLE_DOWN("\u2193", R.drawable.ic_singledown),
|
|
||||||
DOUBLE_DOWN("\u21ca", R.drawable.ic_doubledown),
|
|
||||||
TRIPLE_DOWN("X", R.drawable.ic_doubledown);
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
fun icon(direction: String?) = values().firstOrNull { it.symbol == direction }?.icon ?: NONE.icon
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum class GravityMap(val key: String, val gravity: Int) {
|
|
||||||
CENTER(JsonKeyValues.CENTER.key, Gravity.CENTER),
|
|
||||||
LEFT(JsonKeyValues.LEFT.key, Gravity.LEFT),
|
|
||||||
RIGHT(JsonKeyValues.RIGHT.key, Gravity.RIGHT);
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
fun gravity(key: String?) = values().firstOrNull { it.key == key }?.gravity ?: CENTER.gravity
|
|
||||||
fun key(gravity: Int) = values().firstOrNull { it.gravity == gravity }?.key ?: CENTER.key
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum class FontMap(val key: String, var font: Typeface, @FontRes val fontRessources: Int?) {
|
|
||||||
SANS_SERIF(JsonKeyValues.SANS_SERIF.key, Typeface.SANS_SERIF, null),
|
|
||||||
DEFAULT(JsonKeyValues.DEFAULT.key, Typeface.DEFAULT, null),
|
|
||||||
DEFAULT_BOLD(JsonKeyValues.DEFAULT_BOLD.key, Typeface.DEFAULT_BOLD, null),
|
|
||||||
MONOSPACE(JsonKeyValues.MONOSPACE.key, Typeface.MONOSPACE, null),
|
|
||||||
SERIF(JsonKeyValues.SERIF.key, Typeface.SERIF, 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),
|
|
||||||
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);
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun init(context: Context) = values().forEach { it.font = it.fontRessources?.let { font -> ResourcesCompat.getFont(context, font) } ?: it.font }
|
|
||||||
fun font(key: String) = values().firstOrNull { it.key == key }?.font ?: DEFAULT.font
|
|
||||||
fun key() = DEFAULT.key
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum class StyleMap(val key: String, val style: Int) {
|
|
||||||
NORMAL(JsonKeyValues.NORMAL.key, Typeface.NORMAL),
|
|
||||||
BOLD(JsonKeyValues.BOLD.key, Typeface.BOLD),
|
|
||||||
BOLD_ITALIC(JsonKeyValues.BOLD_ITALIC.key, Typeface.BOLD_ITALIC),
|
|
||||||
ITALIC(JsonKeyValues.ITALIC.key, Typeface.ITALIC);
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
fun style(key: String?) = values().firstOrNull { it.key == key }?.style ?: NORMAL.style
|
|
||||||
fun key(style: Int) = values().firstOrNull { it.style == style }?.key ?: NORMAL.key
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This class containt mapping between keys used within json of Custom Watchface and preferences
|
|
||||||
private enum class PrefMap(val key: String, @StringRes val prefKey: Int) {
|
|
||||||
SHOW_IOB(CwfMetadataKey.CWF_PREF_WATCH_SHOW_IOB.key, R.string.key_show_iob),
|
|
||||||
SHOW_DETAILED_IOB(CwfMetadataKey.CWF_PREF_WATCH_SHOW_DETAILED_IOB.key, R.string.key_show_detailed_iob),
|
|
||||||
SHOW_COB(CwfMetadataKey.CWF_PREF_WATCH_SHOW_COB.key, R.string.key_show_cob),
|
|
||||||
SHOW_DELTA(CwfMetadataKey.CWF_PREF_WATCH_SHOW_DELTA.key, R.string.key_show_delta),
|
|
||||||
SHOW_AVG_DELTA(CwfMetadataKey.CWF_PREF_WATCH_SHOW_AVG_DELTA.key, R.string.key_show_avg_delta),
|
|
||||||
SHOW_DETAILED_DELTA(CwfMetadataKey.CWF_PREF_WATCH_SHOW_DETAILED_DELTA.key, R.string.key_show_detailed_delta),
|
|
||||||
SHOW_UPLOADER_BATTERY(CwfMetadataKey.CWF_PREF_WATCH_SHOW_UPLOADER_BATTERY.key, R.string.key_show_uploader_battery),
|
|
||||||
SHOW_RIG_BATTERY(CwfMetadataKey.CWF_PREF_WATCH_SHOW_RIG_BATTERY.key, R.string.key_show_rig_battery),
|
|
||||||
SHOW_TEMP_BASAL(CwfMetadataKey.CWF_PREF_WATCH_SHOW_TEMP_BASAL.key, R.string.key_show_temp_basal),
|
|
||||||
SHOW_DIRECTION(CwfMetadataKey.CWF_PREF_WATCH_SHOW_DIRECTION.key, R.string.key_show_direction),
|
|
||||||
SHOW_AGO(CwfMetadataKey.CWF_PREF_WATCH_SHOW_AGO.key, R.string.key_show_ago),
|
|
||||||
SHOW_BG(CwfMetadataKey.CWF_PREF_WATCH_SHOW_BG.key, R.string.key_show_bg),
|
|
||||||
SHOW_BGI(CwfMetadataKey.CWF_PREF_WATCH_SHOW_BGI.key, R.string.key_show_bgi),
|
|
||||||
SHOW_LOOP_STATUS(CwfMetadataKey.CWF_PREF_WATCH_SHOW_LOOP_STATUS.key, R.string.key_show_external_status)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum class TrendArrowMap(val symbol: String, @DrawableRes val icon: Int,val customDrawable: ResFileMap?) {
|
||||||
|
NONE("??", R.drawable.ic_invalid, ResFileMap.ARROW_NONE),
|
||||||
|
TRIPLE_UP("X", R.drawable.ic_doubleup, ResFileMap.ARROW_DOUBLE_UP),
|
||||||
|
DOUBLE_UP("\u21c8", R.drawable.ic_doubleup, ResFileMap.ARROW_DOUBLE_UP),
|
||||||
|
SINGLE_UP("\u2191", R.drawable.ic_singleup, ResFileMap.ARROW_SINGLE_UP),
|
||||||
|
FORTY_FIVE_UP("\u2197", R.drawable.ic_fortyfiveup, ResFileMap.ARROW_FORTY_FIVE_UP),
|
||||||
|
FLAT("\u2192", R.drawable.ic_flat, ResFileMap.ARROW_FLAT),
|
||||||
|
FORTY_FIVE_DOWN("\u2198", R.drawable.ic_fortyfivedown, ResFileMap.ARROW_FORTY_FIVE_DOWN),
|
||||||
|
SINGLE_DOWN("\u2193", R.drawable.ic_singledown, ResFileMap.ARROW_SINGLE_DOWN),
|
||||||
|
DOUBLE_DOWN("\u21ca", R.drawable.ic_doubledown, ResFileMap.ARROW_DOUBLE_DOWN),
|
||||||
|
TRIPLE_DOWN("X", R.drawable.ic_doubledown, ResFileMap.ARROW_DOUBLE_DOWN);
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun drawable(direction: String?, resources: Resources, drawableDataMap: CwfResDataMap): Drawable {
|
||||||
|
val arrow = values().firstOrNull { it.symbol == direction } ?:NONE
|
||||||
|
return drawableDataMap[arrow.customDrawable]?.toDrawable(resources) ?:resources.getDrawable(arrow.icon)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum class GravityMap(val key: String, val gravity: Int) {
|
||||||
|
CENTER(JsonKeyValues.CENTER.key, Gravity.CENTER),
|
||||||
|
LEFT(JsonKeyValues.LEFT.key, Gravity.LEFT),
|
||||||
|
RIGHT(JsonKeyValues.RIGHT.key, Gravity.RIGHT);
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun gravity(key: String?) = values().firstOrNull { it.key == key }?.gravity ?: CENTER.gravity
|
||||||
|
fun key(gravity: Int) = values().firstOrNull { it.gravity == gravity }?.key ?: CENTER.key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum class FontMap(val key: String, var font: Typeface, @FontRes val fontRessources: Int?, val customFont: ResFileMap?) {
|
||||||
|
SANS_SERIF(JsonKeyValues.SANS_SERIF.key, Typeface.SANS_SERIF, null, null),
|
||||||
|
DEFAULT(JsonKeyValues.DEFAULT.key, Typeface.DEFAULT, null, null),
|
||||||
|
DEFAULT_BOLD(JsonKeyValues.DEFAULT_BOLD.key, Typeface.DEFAULT_BOLD, null, null),
|
||||||
|
MONOSPACE(JsonKeyValues.MONOSPACE.key, Typeface.MONOSPACE, null, null),
|
||||||
|
SERIF(JsonKeyValues.SERIF.key, Typeface.SERIF, null, null),
|
||||||
|
ROBOTO_CONDENSED_BOLD(JsonKeyValues.ROBOTO_CONDENSED_BOLD.key, Typeface.DEFAULT, R.font.roboto_condensed_bold, null),
|
||||||
|
ROBOTO_CONDENSED_LIGHT(JsonKeyValues.ROBOTO_CONDENSED_LIGHT.key, Typeface.DEFAULT, R.font.roboto_condensed_light, null),
|
||||||
|
ROBOTO_CONDENSED_REGULAR(JsonKeyValues.ROBOTO_CONDENSED_REGULAR.key, Typeface.DEFAULT, R.font.roboto_condensed_regular, null),
|
||||||
|
ROBOTO_SLAB_LIGHT(JsonKeyValues.ROBOTO_SLAB_LIGHT.key, Typeface.DEFAULT, R.font.roboto_slab_light, null),
|
||||||
|
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 {
|
||||||
|
|
||||||
|
fun init(context: Context, resDataMap: CwfResDataMap) = values().forEach { fontMap ->
|
||||||
|
fontMap.customFont?.let { customFont ->
|
||||||
|
fontMap.font = Typeface.DEFAULT
|
||||||
|
resDataMap[customFont]?.toTypeface()?.let { resData ->
|
||||||
|
fontMap.font = resData
|
||||||
|
}
|
||||||
|
} ?: run {
|
||||||
|
fontMap.font = fontMap.fontRessources?.let { fontResource ->
|
||||||
|
ResourcesCompat.getFont(context, fontResource)
|
||||||
|
} ?: fontMap.font
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fun font(key: String) = values().firstOrNull { it.key == key }?.font ?: DEFAULT.font
|
||||||
|
fun key() = DEFAULT.key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum class StyleMap(val key: String, val style: Int) {
|
||||||
|
NORMAL(JsonKeyValues.NORMAL.key, Typeface.NORMAL),
|
||||||
|
BOLD(JsonKeyValues.BOLD.key, Typeface.BOLD),
|
||||||
|
BOLD_ITALIC(JsonKeyValues.BOLD_ITALIC.key, Typeface.BOLD_ITALIC),
|
||||||
|
ITALIC(JsonKeyValues.ITALIC.key, Typeface.ITALIC);
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun style(key: String?) = values().firstOrNull { it.key == key }?.style ?: NORMAL.style
|
||||||
|
fun key(style: Int) = values().firstOrNull { it.style == style }?.key ?: NORMAL.key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This class containt mapping between keys used within json of Custom Watchface and preferences
|
||||||
|
private enum class PrefMap(val key: String, @StringRes val prefKey: Int) {
|
||||||
|
|
||||||
|
SHOW_IOB(CwfMetadataKey.CWF_PREF_WATCH_SHOW_IOB.key, R.string.key_show_iob),
|
||||||
|
SHOW_DETAILED_IOB(CwfMetadataKey.CWF_PREF_WATCH_SHOW_DETAILED_IOB.key, R.string.key_show_detailed_iob),
|
||||||
|
SHOW_COB(CwfMetadataKey.CWF_PREF_WATCH_SHOW_COB.key, R.string.key_show_cob),
|
||||||
|
SHOW_DELTA(CwfMetadataKey.CWF_PREF_WATCH_SHOW_DELTA.key, R.string.key_show_delta),
|
||||||
|
SHOW_AVG_DELTA(CwfMetadataKey.CWF_PREF_WATCH_SHOW_AVG_DELTA.key, R.string.key_show_avg_delta),
|
||||||
|
SHOW_DETAILED_DELTA(CwfMetadataKey.CWF_PREF_WATCH_SHOW_DETAILED_DELTA.key, R.string.key_show_detailed_delta),
|
||||||
|
SHOW_UPLOADER_BATTERY(CwfMetadataKey.CWF_PREF_WATCH_SHOW_UPLOADER_BATTERY.key, R.string.key_show_uploader_battery),
|
||||||
|
SHOW_RIG_BATTERY(CwfMetadataKey.CWF_PREF_WATCH_SHOW_RIG_BATTERY.key, R.string.key_show_rig_battery),
|
||||||
|
SHOW_TEMP_BASAL(CwfMetadataKey.CWF_PREF_WATCH_SHOW_TEMP_BASAL.key, R.string.key_show_temp_basal),
|
||||||
|
SHOW_DIRECTION(CwfMetadataKey.CWF_PREF_WATCH_SHOW_DIRECTION.key, R.string.key_show_direction),
|
||||||
|
SHOW_AGO(CwfMetadataKey.CWF_PREF_WATCH_SHOW_AGO.key, R.string.key_show_ago),
|
||||||
|
SHOW_BG(CwfMetadataKey.CWF_PREF_WATCH_SHOW_BG.key, R.string.key_show_bg),
|
||||||
|
SHOW_BGI(CwfMetadataKey.CWF_PREF_WATCH_SHOW_BGI.key, R.string.key_show_bgi),
|
||||||
|
SHOW_LOOP_STATUS(CwfMetadataKey.CWF_PREF_WATCH_SHOW_LOOP_STATUS.key, R.string.key_show_external_status)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue