Refactor Custom Watchface code (simplified)
This commit is contained in:
parent
b259425361
commit
26dff28e1c
22 changed files with 204 additions and 296 deletions
|
@ -1,3 +1,5 @@
|
||||||
package info.nightscout.rx.events
|
package info.nightscout.rx.events
|
||||||
|
|
||||||
class EventWearUpdateGui : Event()
|
import info.nightscout.rx.weardata.CustomWatchfaceData
|
||||||
|
|
||||||
|
class EventWearUpdateGui(val customWatchfaceData: CustomWatchfaceData? = null, val exportFile: Boolean = false) : Event()
|
|
@ -1,27 +1,30 @@
|
||||||
package info.nightscout.rx.weardata
|
package info.nightscout.rx.weardata
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
import android.graphics.drawable.BitmapDrawable
|
import android.graphics.drawable.BitmapDrawable
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.os.Parcelable
|
|
||||||
import android.util.Xml
|
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import info.nightscout.shared.R
|
import info.nightscout.shared.R
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
import java.io.BufferedOutputStream
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.io.FileOutputStream
|
||||||
|
import java.util.zip.ZipEntry
|
||||||
|
import java.util.zip.ZipInputStream
|
||||||
|
import java.util.zip.ZipOutputStream
|
||||||
|
|
||||||
enum class CustomWatchfaceDrawableDataKey(val key: String, @DrawableRes val icon: Int?, val fileName: String) {
|
enum class CustomWatchfaceDrawableDataKey(val key: String, @DrawableRes val icon: Int?, val fileName: String) {
|
||||||
UNKNOWN("unknown", null,"Unknown"),
|
UNKNOWN("unknown", null, "Unknown"),
|
||||||
CUSTOM_WATCHFACE("customWatchface", R.drawable.watchface_custom, "CustomWatchface"),
|
CUSTOM_WATCHFACE("customWatchface", R.drawable.watchface_custom, "CustomWatchface"),
|
||||||
BACKGROUND("background", R.drawable.background, "Background"),
|
BACKGROUND("background", R.drawable.background, "Background"),
|
||||||
COVERCHART("cover_chart", null,"CoverChart"),
|
COVERCHART("cover_chart", null, "CoverChart"),
|
||||||
COVERPLATE("cover_plate", R.drawable.simplified_dial, "CoverPlate"),
|
COVERPLATE("cover_plate", R.drawable.simplified_dial, "CoverPlate"),
|
||||||
HOURHAND("hour_hand", R.drawable.hour_hand,"HourHand"),
|
HOURHAND("hour_hand", R.drawable.hour_hand, "HourHand"),
|
||||||
MINUTEHAND("minute_hand", R.drawable.minute_hand,"MinuteHand"),
|
MINUTEHAND("minute_hand", R.drawable.minute_hand, "MinuteHand"),
|
||||||
SECONDHAND("second_hand", R.drawable.second_hand, "SecondHand");
|
SECONDHAND("second_hand", R.drawable.second_hand, "SecondHand");
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -36,14 +39,14 @@ enum class CustomWatchfaceDrawableDataKey(val key: String, @DrawableRes val icon
|
||||||
|
|
||||||
fun fromKey(key: String): CustomWatchfaceDrawableDataKey =
|
fun fromKey(key: String): CustomWatchfaceDrawableDataKey =
|
||||||
if (keyToEnumMap.containsKey(key)) {
|
if (keyToEnumMap.containsKey(key)) {
|
||||||
keyToEnumMap[key] ?:UNKNOWN
|
keyToEnumMap[key] ?: UNKNOWN
|
||||||
} else {
|
} else {
|
||||||
UNKNOWN
|
UNKNOWN
|
||||||
}
|
}
|
||||||
|
|
||||||
fun fromFileName(file: String): CustomWatchfaceDrawableDataKey =
|
fun fromFileName(file: String): CustomWatchfaceDrawableDataKey =
|
||||||
if (fileNameToEnumMap.containsKey(file.substringBeforeLast("."))) {
|
if (fileNameToEnumMap.containsKey(file.substringBeforeLast("."))) {
|
||||||
fileNameToEnumMap[file.substringBeforeLast(".")] ?:UNKNOWN
|
fileNameToEnumMap[file.substringBeforeLast(".")] ?: UNKNOWN
|
||||||
} else {
|
} else {
|
||||||
UNKNOWN
|
UNKNOWN
|
||||||
}
|
}
|
||||||
|
@ -53,8 +56,9 @@ enum class CustomWatchfaceDrawableDataKey(val key: String, @DrawableRes val icon
|
||||||
|
|
||||||
enum class DrawableFormat(val extension: String) {
|
enum class DrawableFormat(val extension: String) {
|
||||||
UNKNOWN(""),
|
UNKNOWN(""),
|
||||||
|
|
||||||
//XML("xml"),
|
//XML("xml"),
|
||||||
//svg("svg"),
|
//SVG("svg"),
|
||||||
JPG("jpg"),
|
JPG("jpg"),
|
||||||
PNG("png");
|
PNG("png");
|
||||||
|
|
||||||
|
@ -68,7 +72,7 @@ enum class DrawableFormat(val extension: String) {
|
||||||
|
|
||||||
fun fromFileName(fileName: String): DrawableFormat =
|
fun fromFileName(fileName: String): DrawableFormat =
|
||||||
if (extensionToEnumMap.containsKey(fileName.substringAfterLast("."))) {
|
if (extensionToEnumMap.containsKey(fileName.substringAfterLast("."))) {
|
||||||
extensionToEnumMap[fileName.substringAfterLast(".")] ?:UNKNOWN
|
extensionToEnumMap[fileName.substringAfterLast(".")] ?: UNKNOWN
|
||||||
} else {
|
} else {
|
||||||
UNKNOWN
|
UNKNOWN
|
||||||
}
|
}
|
||||||
|
@ -85,15 +89,20 @@ data class DrawableData(val value: ByteArray, val format: DrawableFormat) {
|
||||||
val bitmap = BitmapFactory.decodeByteArray(value, 0, value.size)
|
val bitmap = BitmapFactory.decodeByteArray(value, 0, value.size)
|
||||||
BitmapDrawable(resources, bitmap)
|
BitmapDrawable(resources, bitmap)
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
DrawableFormat.XML -> {
|
DrawableFormat.SVG -> {
|
||||||
val xmlInputStream = ByteArrayInputStream(value)
|
//TODO: include svg to Drawable convertor here
|
||||||
val xmlPullParser = Xml.newPullParser()
|
null
|
||||||
xmlPullParser.setInput(xmlInputStream, null)
|
}
|
||||||
Drawable.createFromXml(resources, xmlPullParser)
|
DrawableFormat.XML -> {
|
||||||
}
|
// Always return a null Drawable, even if xml file is a valid xml vector file
|
||||||
*/
|
val xmlInputStream = ByteArrayInputStream(value)
|
||||||
else -> null
|
val xmlPullParser = Xml.newPullParser()
|
||||||
|
xmlPullParser.setInput(xmlInputStream, null)
|
||||||
|
Drawable.createFromXml(resources, xmlPullParser)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
else -> null
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
return null
|
return null
|
||||||
|
@ -104,18 +113,13 @@ data class DrawableData(val value: ByteArray, val format: DrawableFormat) {
|
||||||
typealias CustomWatchfaceDrawableDataMap = MutableMap<CustomWatchfaceDrawableDataKey, DrawableData>
|
typealias CustomWatchfaceDrawableDataMap = MutableMap<CustomWatchfaceDrawableDataKey, DrawableData>
|
||||||
typealias CustomWatchfaceMetadataMap = MutableMap<CustomWatchfaceMetadataKey, String>
|
typealias CustomWatchfaceMetadataMap = MutableMap<CustomWatchfaceMetadataKey, String>
|
||||||
|
|
||||||
data class CustomWatchface(val json: String, var metadata: CustomWatchfaceMetadataMap, val drawableDatas: CustomWatchfaceDrawableDataMap)
|
@Serializable
|
||||||
|
data class CustomWatchfaceData(val json: String, var metadata: CustomWatchfaceMetadataMap, val drawableDatas: CustomWatchfaceDrawableDataMap)
|
||||||
interface CustomWatchfaceFormat {
|
|
||||||
|
|
||||||
fun saveCustomWatchface(file: File, customWatchface: EventData.ActionSetCustomWatchface)
|
|
||||||
fun loadCustomWatchface(cwfFile: File): CustomWatchface?
|
|
||||||
fun loadMetadata(contents: JSONObject): CustomWatchfaceMetadataMap
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class CustomWatchfaceMetadataKey(val key: String, @StringRes val label: Int) {
|
enum class CustomWatchfaceMetadataKey(val key: String, @StringRes val label: Int) {
|
||||||
|
|
||||||
CWF_NAME("name", R.string.metadata_label_watchface_name),
|
CWF_NAME("name", R.string.metadata_label_watchface_name),
|
||||||
|
CWF_FILENAME("filename", R.string.metadata_wear_import_filename),
|
||||||
CWF_AUTHOR("author", R.string.metadata_label_watchface_author),
|
CWF_AUTHOR("author", R.string.metadata_label_watchface_author),
|
||||||
CWF_CREATED_AT("created_at", R.string.metadata_label_watchface_created_at),
|
CWF_CREATED_AT("created_at", R.string.metadata_label_watchface_created_at),
|
||||||
CWF_VERSION("cwf_version", R.string.metadata_label_watchface_version);
|
CWF_VERSION("cwf_version", R.string.metadata_label_watchface_version);
|
||||||
|
@ -137,4 +141,100 @@ enum class CustomWatchfaceMetadataKey(val key: String, @StringRes val label: Int
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class ZipWatchfaceFormat {
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
const val CUSTOM_WF_EXTENTION = ".zip"
|
||||||
|
const val CUSTOM_JSON_FILE = "CustomWatchface.json"
|
||||||
|
|
||||||
|
fun loadCustomWatchface(cwfFile: File): CustomWatchfaceData? {
|
||||||
|
var json = JSONObject()
|
||||||
|
var metadata: CustomWatchfaceMetadataMap = mutableMapOf()
|
||||||
|
val drawableDatas: CustomWatchfaceDrawableDataMap = mutableMapOf()
|
||||||
|
|
||||||
|
try {
|
||||||
|
val zipInputStream = ZipInputStream(cwfFile.inputStream())
|
||||||
|
var zipEntry: ZipEntry? = zipInputStream.nextEntry
|
||||||
|
while (zipEntry != null) {
|
||||||
|
val entryName = zipEntry.name
|
||||||
|
|
||||||
|
val buffer = ByteArray(2048)
|
||||||
|
val byteArrayOutputStream = ByteArrayOutputStream()
|
||||||
|
var count = zipInputStream.read(buffer)
|
||||||
|
while (count != -1) {
|
||||||
|
byteArrayOutputStream.write(buffer, 0, count)
|
||||||
|
count = zipInputStream.read(buffer)
|
||||||
|
}
|
||||||
|
zipInputStream.closeEntry()
|
||||||
|
|
||||||
|
if (entryName == CUSTOM_JSON_FILE) {
|
||||||
|
val jsonString = byteArrayOutputStream.toByteArray().toString(Charsets.UTF_8)
|
||||||
|
json = JSONObject(jsonString)
|
||||||
|
metadata = loadMetadata(json)
|
||||||
|
metadata[CustomWatchfaceMetadataKey.CWF_FILENAME] = cwfFile.name
|
||||||
|
} else {
|
||||||
|
val customWatchfaceDrawableDataKey = CustomWatchfaceDrawableDataKey.fromFileName(entryName)
|
||||||
|
val drawableFormat = DrawableFormat.fromFileName(entryName)
|
||||||
|
if (customWatchfaceDrawableDataKey != CustomWatchfaceDrawableDataKey.UNKNOWN && drawableFormat != DrawableFormat.UNKNOWN) {
|
||||||
|
drawableDatas[customWatchfaceDrawableDataKey] = DrawableData(byteArrayOutputStream.toByteArray(), drawableFormat)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
zipEntry = zipInputStream.nextEntry
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid CWF file must contains a valid json file with a name within metadata and a custom watchface image
|
||||||
|
if (metadata.containsKey(CustomWatchfaceMetadataKey.CWF_NAME) && drawableDatas.containsKey(CustomWatchfaceDrawableDataKey.CUSTOM_WATCHFACE))
|
||||||
|
return CustomWatchfaceData(json.toString(4), metadata, drawableDatas)
|
||||||
|
else
|
||||||
|
return null
|
||||||
|
|
||||||
|
} catch (e: Exception) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveCustomWatchface(file: File, customWatchface: CustomWatchfaceData) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
val outputStream = FileOutputStream(file)
|
||||||
|
val zipOutputStream = ZipOutputStream(BufferedOutputStream(outputStream))
|
||||||
|
|
||||||
|
// Ajouter le fichier JSON au ZIP
|
||||||
|
val jsonEntry = ZipEntry(CUSTOM_JSON_FILE)
|
||||||
|
zipOutputStream.putNextEntry(jsonEntry)
|
||||||
|
zipOutputStream.write(customWatchface.json.toByteArray())
|
||||||
|
zipOutputStream.closeEntry()
|
||||||
|
|
||||||
|
// Ajouter les fichiers divers au ZIP
|
||||||
|
for (drawableData in customWatchface.drawableDatas) {
|
||||||
|
val fileEntry = ZipEntry("${drawableData.key.fileName}.${drawableData.value.format.extension}")
|
||||||
|
zipOutputStream.putNextEntry(fileEntry)
|
||||||
|
zipOutputStream.write(drawableData.value.value)
|
||||||
|
zipOutputStream.closeEntry()
|
||||||
|
}
|
||||||
|
zipOutputStream.close()
|
||||||
|
outputStream.close()
|
||||||
|
} catch (_: Exception) {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadMetadata(contents: JSONObject): CustomWatchfaceMetadataMap {
|
||||||
|
val metadata: CustomWatchfaceMetadataMap = mutableMapOf()
|
||||||
|
|
||||||
|
if (contents.has("metadata")) {
|
||||||
|
val meta = contents.getJSONObject("metadata")
|
||||||
|
for (key in meta.keys()) {
|
||||||
|
val metaKey = CustomWatchfaceMetadataKey.fromKey(key)
|
||||||
|
if (metaKey != null) {
|
||||||
|
metadata[metaKey] = meta.getString(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return metadata
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -14,15 +14,15 @@ sealed class EventData : Event() {
|
||||||
|
|
||||||
fun serialize() = Json.encodeToString(serializer(), this)
|
fun serialize() = Json.encodeToString(serializer(), this)
|
||||||
|
|
||||||
|
@ExperimentalSerializationApi
|
||||||
fun serializeByte() = ProtoBuf.encodeToByteArray(serializer(), this)
|
fun serializeByte() = ProtoBuf.encodeToByteArray(serializer(), this)
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
fun deserialize(json: String) = try {
|
fun deserialize(json: String) = try {
|
||||||
Json.decodeFromString(serializer(), json)
|
Json.decodeFromString(serializer(), json)
|
||||||
} catch (ignored: Exception) {
|
} catch (ignored: Exception) {
|
||||||
Error(System.currentTimeMillis())
|
Error(System.currentTimeMillis())
|
||||||
}
|
}
|
||||||
|
@ExperimentalSerializationApi
|
||||||
fun deserializeByte(byteArray: ByteArray) = try {
|
fun deserializeByte(byteArray: ByteArray) = try {
|
||||||
ProtoBuf.decodeFromByteArray(serializer(), byteArray)
|
ProtoBuf.decodeFromByteArray(serializer(), byteArray)
|
||||||
} catch (ignored: Exception) {
|
} catch (ignored: Exception) {
|
||||||
|
@ -153,7 +153,7 @@ sealed class EventData : Event() {
|
||||||
@Serializable
|
@Serializable
|
||||||
data class ActionGetCustomWatchface(
|
data class ActionGetCustomWatchface(
|
||||||
val customWatchface: ActionSetCustomWatchface,
|
val customWatchface: ActionSetCustomWatchface,
|
||||||
val exportFile: Boolean
|
val exportFile: Boolean = false
|
||||||
) : EventData()
|
) : EventData()
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
|
@ -283,9 +283,7 @@ sealed class EventData : Event() {
|
||||||
}
|
}
|
||||||
@Serializable
|
@Serializable
|
||||||
data class ActionSetCustomWatchface(
|
data class ActionSetCustomWatchface(
|
||||||
val name: String,
|
val customWatchfaceData: CustomWatchfaceData
|
||||||
val json: String,
|
|
||||||
val drawableDataMap: CustomWatchfaceDrawableDataMap
|
|
||||||
) : EventData()
|
) : EventData()
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
|
|
|
@ -40,10 +40,10 @@
|
||||||
<string name="waiting_for_disconnection">Waiting for disconnection</string>
|
<string name="waiting_for_disconnection">Waiting for disconnection</string>
|
||||||
|
|
||||||
<!-- Custom Watchface -->
|
<!-- Custom Watchface -->
|
||||||
<string name="key_custom_watchface" translatable="false">key_custom_watchface</string>
|
|
||||||
<string name="metadata_label_watchface_created_at">Created at: %1$s</string>
|
<string name="metadata_label_watchface_created_at">Created at: %1$s</string>
|
||||||
<string name="metadata_label_watchface_author">Author: %1$s</string>
|
<string name="metadata_label_watchface_author">Author: %1$s</string>
|
||||||
<string name="metadata_label_watchface_name">Name: %1$s</string>
|
<string name="metadata_label_watchface_name">Name: %1$s</string>
|
||||||
|
<string name="metadata_wear_import_filename">File name: %1$s</string>
|
||||||
<string name="metadata_label_watchface_version">Watchface version: %1$s</string>
|
<string name="metadata_label_watchface_version">Watchface version: %1$s</string>
|
||||||
<string name="wear_default_watchface">Default Watchface</string>
|
<string name="wear_default_watchface">Default Watchface</string>
|
||||||
|
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
package info.nightscout.interfaces.maintenance
|
|
||||||
|
|
||||||
import android.os.Parcelable
|
|
||||||
import info.nightscout.rx.weardata.CustomWatchfaceDrawableDataKey
|
|
||||||
import info.nightscout.rx.weardata.CustomWatchfaceDrawableDataMap
|
|
||||||
import info.nightscout.rx.weardata.CustomWatchfaceMetadataMap
|
|
||||||
import info.nightscout.rx.weardata.DrawableData
|
|
||||||
import kotlinx.parcelize.Parcelize
|
|
||||||
import kotlinx.parcelize.RawValue
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
data class CustomWatchfaceFile(
|
|
||||||
val name: String,
|
|
||||||
val file: File,
|
|
||||||
val baseDir: File,
|
|
||||||
val json: String,
|
|
||||||
|
|
||||||
val metadata: @RawValue CustomWatchfaceMetadataMap,
|
|
||||||
val drawableFiles: @RawValue CustomWatchfaceDrawableDataMap
|
|
||||||
|
|
||||||
)
|
|
|
@ -2,7 +2,7 @@ package info.nightscout.interfaces.maintenance
|
||||||
|
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import info.nightscout.rx.weardata.EventData
|
import info.nightscout.rx.weardata.CustomWatchfaceData
|
||||||
|
|
||||||
interface ImportExportPrefs {
|
interface ImportExportPrefs {
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ interface ImportExportPrefs {
|
||||||
fun importSharedPreferences(fragment: Fragment)
|
fun importSharedPreferences(fragment: Fragment)
|
||||||
fun importCustomWatchface(activity: FragmentActivity)
|
fun importCustomWatchface(activity: FragmentActivity)
|
||||||
fun importCustomWatchface(fragment: Fragment)
|
fun importCustomWatchface(fragment: Fragment)
|
||||||
fun exportCustomWatchface(customWatchface: EventData.ActionSetCustomWatchface)
|
fun exportCustomWatchface(customWatchface: CustomWatchfaceData)
|
||||||
fun prefsFileExists(): Boolean
|
fun prefsFileExists(): Boolean
|
||||||
fun verifyStoragePermissions(fragment: Fragment, onGranted: Runnable)
|
fun verifyStoragePermissions(fragment: Fragment, onGranted: Runnable)
|
||||||
fun exportSharedPreferences(f: Fragment)
|
fun exportSharedPreferences(f: Fragment)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package info.nightscout.interfaces.maintenance
|
package info.nightscout.interfaces.maintenance
|
||||||
|
|
||||||
|
import info.nightscout.rx.weardata.CustomWatchfaceData
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
interface PrefFileListProvider {
|
interface PrefFileListProvider {
|
||||||
|
@ -12,7 +13,7 @@ interface PrefFileListProvider {
|
||||||
fun newExportCsvFile(): File
|
fun newExportCsvFile(): File
|
||||||
fun newCwfFile(filename: String): File
|
fun newCwfFile(filename: String): File
|
||||||
fun listPreferenceFiles(loadMetadata: Boolean = false): MutableList<PrefsFile>
|
fun listPreferenceFiles(loadMetadata: Boolean = false): MutableList<PrefsFile>
|
||||||
fun listCustomWatchfaceFiles(): MutableList<CustomWatchfaceFile>
|
fun listCustomWatchfaceFiles(): MutableList<CustomWatchfaceData>
|
||||||
fun checkMetadata(metadata: Map<PrefsMetadataKey, PrefMetadata>): Map<PrefsMetadataKey, PrefMetadata>
|
fun checkMetadata(metadata: Map<PrefsMetadataKey, PrefMetadata>): Map<PrefsMetadataKey, PrefMetadata>
|
||||||
fun formatExportedAgo(utcTime: String): String
|
fun formatExportedAgo(utcTime: String): String
|
||||||
}
|
}
|
|
@ -14,7 +14,6 @@ import info.nightscout.configuration.maintenance.PrefFileListProviderImpl
|
||||||
import info.nightscout.configuration.maintenance.activities.CustomWatchfaceImportListActivity
|
import info.nightscout.configuration.maintenance.activities.CustomWatchfaceImportListActivity
|
||||||
import info.nightscout.configuration.maintenance.activities.LogSettingActivity
|
import info.nightscout.configuration.maintenance.activities.LogSettingActivity
|
||||||
import info.nightscout.configuration.maintenance.activities.PrefImportListActivity
|
import info.nightscout.configuration.maintenance.activities.PrefImportListActivity
|
||||||
import info.nightscout.configuration.maintenance.formats.ZipCustomWatchfaceFormat
|
|
||||||
import info.nightscout.configuration.maintenance.formats.EncryptedPrefsFormat
|
import info.nightscout.configuration.maintenance.formats.EncryptedPrefsFormat
|
||||||
import info.nightscout.interfaces.AndroidPermission
|
import info.nightscout.interfaces.AndroidPermission
|
||||||
import info.nightscout.interfaces.ConfigBuilder
|
import info.nightscout.interfaces.ConfigBuilder
|
||||||
|
@ -37,7 +36,6 @@ abstract class ConfigurationModule {
|
||||||
@ContributesAndroidInjector abstract fun contributesCsvExportWorker(): ImportExportPrefsImpl.CsvExportWorker
|
@ContributesAndroidInjector abstract fun contributesCsvExportWorker(): ImportExportPrefsImpl.CsvExportWorker
|
||||||
@ContributesAndroidInjector abstract fun contributesPrefImportListActivity(): PrefImportListActivity
|
@ContributesAndroidInjector abstract fun contributesPrefImportListActivity(): PrefImportListActivity
|
||||||
@ContributesAndroidInjector abstract fun contributesCustomWatchfaceImportListActivity(): CustomWatchfaceImportListActivity
|
@ContributesAndroidInjector abstract fun contributesCustomWatchfaceImportListActivity(): CustomWatchfaceImportListActivity
|
||||||
@ContributesAndroidInjector abstract fun contributesZipCustomWatchfaceFormat(): ZipCustomWatchfaceFormat
|
|
||||||
@ContributesAndroidInjector abstract fun encryptedPrefsFormatInjector(): EncryptedPrefsFormat
|
@ContributesAndroidInjector abstract fun encryptedPrefsFormatInjector(): EncryptedPrefsFormat
|
||||||
@ContributesAndroidInjector abstract fun prefImportListProviderInjector(): PrefFileListProvider
|
@ContributesAndroidInjector abstract fun prefImportListProviderInjector(): PrefFileListProvider
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,6 @@ import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.configuration.R
|
import info.nightscout.configuration.R
|
||||||
import info.nightscout.configuration.activities.DaggerAppCompatActivityWithResult
|
import info.nightscout.configuration.activities.DaggerAppCompatActivityWithResult
|
||||||
import info.nightscout.configuration.maintenance.dialogs.PrefImportSummaryDialog
|
import info.nightscout.configuration.maintenance.dialogs.PrefImportSummaryDialog
|
||||||
import info.nightscout.configuration.maintenance.formats.ZipCustomWatchfaceFormat
|
|
||||||
import info.nightscout.configuration.maintenance.formats.EncryptedPrefsFormat
|
import info.nightscout.configuration.maintenance.formats.EncryptedPrefsFormat
|
||||||
import info.nightscout.core.ui.dialogs.OKDialog
|
import info.nightscout.core.ui.dialogs.OKDialog
|
||||||
import info.nightscout.core.ui.dialogs.TwoMessagesAlertDialog
|
import info.nightscout.core.ui.dialogs.TwoMessagesAlertDialog
|
||||||
|
@ -56,7 +55,9 @@ import info.nightscout.rx.events.EventAppExit
|
||||||
import info.nightscout.rx.events.EventDiaconnG8PumpLogReset
|
import info.nightscout.rx.events.EventDiaconnG8PumpLogReset
|
||||||
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.EventData
|
import info.nightscout.rx.weardata.CustomWatchfaceData
|
||||||
|
import info.nightscout.rx.weardata.CustomWatchfaceMetadataKey
|
||||||
|
import info.nightscout.rx.weardata.ZipWatchfaceFormat
|
||||||
import info.nightscout.shared.interfaces.ResourceHelper
|
import info.nightscout.shared.interfaces.ResourceHelper
|
||||||
import info.nightscout.shared.sharedPreferences.SP
|
import info.nightscout.shared.sharedPreferences.SP
|
||||||
import info.nightscout.shared.utils.DateUtil
|
import info.nightscout.shared.utils.DateUtil
|
||||||
|
@ -86,8 +87,7 @@ class ImportExportPrefsImpl @Inject constructor(
|
||||||
private val prefFileList: PrefFileListProvider,
|
private val prefFileList: PrefFileListProvider,
|
||||||
private val uel: UserEntryLogger,
|
private val uel: UserEntryLogger,
|
||||||
private val dateUtil: DateUtil,
|
private val dateUtil: DateUtil,
|
||||||
private val uiInteraction: UiInteraction,
|
private val uiInteraction: UiInteraction
|
||||||
private val customWatchfaceCWFFormat: ZipCustomWatchfaceFormat
|
|
||||||
) : ImportExportPrefs {
|
) : ImportExportPrefs {
|
||||||
|
|
||||||
override fun prefsFileExists(): Boolean {
|
override fun prefsFileExists(): Boolean {
|
||||||
|
@ -315,10 +315,10 @@ class ImportExportPrefsImpl @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun exportCustomWatchface(customWatchface: EventData.ActionSetCustomWatchface) {
|
override fun exportCustomWatchface(customWatchface: CustomWatchfaceData) {
|
||||||
prefFileList.ensureExportDirExists()
|
prefFileList.ensureExportDirExists()
|
||||||
val newFile = prefFileList.newCwfFile(customWatchface.name)
|
val newFile = prefFileList.newCwfFile(customWatchface.metadata[CustomWatchfaceMetadataKey.CWF_FILENAME] ?:"")
|
||||||
customWatchfaceCWFFormat.saveCustomWatchface(newFile,customWatchface)
|
ZipWatchfaceFormat.saveCustomWatchface(newFile, customWatchface)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun importSharedPreferences(activity: FragmentActivity, importFile: PrefsFile) {
|
override fun importSharedPreferences(activity: FragmentActivity, importFile: PrefsFile) {
|
||||||
|
|
|
@ -6,10 +6,8 @@ import dagger.Lazy
|
||||||
import dagger.Reusable
|
import dagger.Reusable
|
||||||
import info.nightscout.androidaps.annotations.OpenForTesting
|
import info.nightscout.androidaps.annotations.OpenForTesting
|
||||||
import info.nightscout.configuration.R
|
import info.nightscout.configuration.R
|
||||||
import info.nightscout.configuration.maintenance.formats.ZipCustomWatchfaceFormat
|
|
||||||
import info.nightscout.configuration.maintenance.formats.EncryptedPrefsFormat
|
import info.nightscout.configuration.maintenance.formats.EncryptedPrefsFormat
|
||||||
import info.nightscout.interfaces.Config
|
import info.nightscout.interfaces.Config
|
||||||
import info.nightscout.interfaces.maintenance.CustomWatchfaceFile
|
|
||||||
import info.nightscout.interfaces.maintenance.PrefFileListProvider
|
import info.nightscout.interfaces.maintenance.PrefFileListProvider
|
||||||
import info.nightscout.interfaces.maintenance.PrefMetadata
|
import info.nightscout.interfaces.maintenance.PrefMetadata
|
||||||
import info.nightscout.interfaces.maintenance.PrefMetadataMap
|
import info.nightscout.interfaces.maintenance.PrefMetadataMap
|
||||||
|
@ -19,6 +17,8 @@ import info.nightscout.interfaces.maintenance.PrefsMetadataKey
|
||||||
import info.nightscout.interfaces.maintenance.PrefsStatus
|
import info.nightscout.interfaces.maintenance.PrefsStatus
|
||||||
import info.nightscout.interfaces.storage.Storage
|
import info.nightscout.interfaces.storage.Storage
|
||||||
import info.nightscout.interfaces.versionChecker.VersionCheckerUtils
|
import info.nightscout.interfaces.versionChecker.VersionCheckerUtils
|
||||||
|
import info.nightscout.rx.weardata.CustomWatchfaceData
|
||||||
|
import info.nightscout.rx.weardata.ZipWatchfaceFormat
|
||||||
import info.nightscout.shared.interfaces.ResourceHelper
|
import info.nightscout.shared.interfaces.ResourceHelper
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
import org.joda.time.Days
|
import org.joda.time.Days
|
||||||
|
@ -36,7 +36,6 @@ class PrefFileListProviderImpl @Inject constructor(
|
||||||
private val rh: ResourceHelper,
|
private val rh: ResourceHelper,
|
||||||
private val config: Lazy<Config>,
|
private val config: Lazy<Config>,
|
||||||
private val encryptedPrefsFormat: EncryptedPrefsFormat,
|
private val encryptedPrefsFormat: EncryptedPrefsFormat,
|
||||||
private val customWatchfaceCWFFormat: ZipCustomWatchfaceFormat,
|
|
||||||
private val storage: Storage,
|
private val storage: Storage,
|
||||||
private val versionCheckerUtils: VersionCheckerUtils,
|
private val versionCheckerUtils: VersionCheckerUtils,
|
||||||
context: Context
|
context: Context
|
||||||
|
@ -91,14 +90,14 @@ class PrefFileListProviderImpl @Inject constructor(
|
||||||
return prefFiles
|
return prefFiles
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun listCustomWatchfaceFiles(): MutableList<CustomWatchfaceFile> {
|
override fun listCustomWatchfaceFiles(): MutableList<CustomWatchfaceData> {
|
||||||
val customWatchfaceFiles = mutableListOf<CustomWatchfaceFile>()
|
val customWatchfaceFiles = mutableListOf<CustomWatchfaceData>()
|
||||||
|
|
||||||
// searching dedicated dir, only for new CWF format
|
// searching dedicated dir, only for new CWF format
|
||||||
exportsPath.walk().filter { it.isFile && it.name.endsWith(ZipCustomWatchfaceFormat.CUSTOM_WF_EXTENTION) }.forEach { file ->
|
exportsPath.walk().filter { it.isFile && it.name.endsWith(ZipWatchfaceFormat.CUSTOM_WF_EXTENTION) }.forEach { file ->
|
||||||
// Here loadCustomWatchface will unzip, check and load CustomWatchface
|
// Here loadCustomWatchface will unzip, check and load CustomWatchface
|
||||||
customWatchfaceCWFFormat.loadCustomWatchface(file)?.also { customWatchface ->
|
ZipWatchfaceFormat.loadCustomWatchface(file)?.also { customWatchface ->
|
||||||
customWatchfaceFiles.add(CustomWatchfaceFile(file.name, file, exportsPath, customWatchface.json, customWatchface.metadata, customWatchface.drawableDatas))
|
customWatchfaceFiles.add(customWatchface)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,7 +146,7 @@ class PrefFileListProviderImpl @Inject constructor(
|
||||||
}
|
}
|
||||||
override fun newCwfFile(filename: String): File {
|
override fun newCwfFile(filename: String): File {
|
||||||
val timeLocal = LocalDateTime.now().toString(DateTimeFormat.forPattern("yyyy-MM-dd'_'HHmmss"))
|
val timeLocal = LocalDateTime.now().toString(DateTimeFormat.forPattern("yyyy-MM-dd'_'HHmmss"))
|
||||||
return File(exportsPath, "${filename}_$timeLocal${ZipCustomWatchfaceFormat.CUSTOM_WF_EXTENTION}")
|
return File(exportsPath, "${filename}_$timeLocal${ZipWatchfaceFormat.CUSTOM_WF_EXTENTION}")
|
||||||
}
|
}
|
||||||
|
|
||||||
// check metadata for known issues, change their status and add info with explanations
|
// check metadata for known issues, change their status and add info with explanations
|
||||||
|
|
|
@ -10,7 +10,6 @@ import androidx.fragment.app.FragmentActivity
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import info.nightscout.core.ui.activities.TranslatedDaggerAppCompatActivity
|
import info.nightscout.core.ui.activities.TranslatedDaggerAppCompatActivity
|
||||||
import info.nightscout.interfaces.maintenance.CustomWatchfaceFile
|
|
||||||
import info.nightscout.interfaces.maintenance.PrefFileListProvider
|
import info.nightscout.interfaces.maintenance.PrefFileListProvider
|
||||||
import info.nightscout.configuration.databinding.CustomWatchfaceImportListActivityBinding
|
import info.nightscout.configuration.databinding.CustomWatchfaceImportListActivityBinding
|
||||||
import info.nightscout.configuration.R
|
import info.nightscout.configuration.R
|
||||||
|
@ -18,6 +17,7 @@ import info.nightscout.configuration.databinding.CustomWatchfaceImportListItemBi
|
||||||
import info.nightscout.rx.bus.RxBus
|
import info.nightscout.rx.bus.RxBus
|
||||||
import info.nightscout.rx.events.EventMobileDataToWear
|
import info.nightscout.rx.events.EventMobileDataToWear
|
||||||
import info.nightscout.rx.logging.AAPSLogger
|
import info.nightscout.rx.logging.AAPSLogger
|
||||||
|
import info.nightscout.rx.weardata.CustomWatchfaceData
|
||||||
import info.nightscout.rx.weardata.CustomWatchfaceDrawableDataKey
|
import info.nightscout.rx.weardata.CustomWatchfaceDrawableDataKey
|
||||||
import info.nightscout.rx.weardata.CustomWatchfaceMetadataKey.*
|
import info.nightscout.rx.weardata.CustomWatchfaceMetadataKey.*
|
||||||
import info.nightscout.rx.weardata.EventData
|
import info.nightscout.rx.weardata.EventData
|
||||||
|
@ -51,7 +51,7 @@ class CustomWatchfaceImportListActivity: TranslatedDaggerAppCompatActivity() {
|
||||||
binding.recyclerview.adapter = RecyclerViewAdapter(prefFileListProvider.listCustomWatchfaceFiles())
|
binding.recyclerview.adapter = RecyclerViewAdapter(prefFileListProvider.listCustomWatchfaceFiles())
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class RecyclerViewAdapter internal constructor(private var customWatchfaceFileList: List<CustomWatchfaceFile>) : RecyclerView.Adapter<RecyclerViewAdapter.PrefFileViewHolder>() {
|
inner class RecyclerViewAdapter internal constructor(private var customWatchfaceFileList: List<CustomWatchfaceData>) : RecyclerView.Adapter<RecyclerViewAdapter.PrefFileViewHolder>() {
|
||||||
|
|
||||||
inner class PrefFileViewHolder(val customWatchfaceImportListItemBinding: CustomWatchfaceImportListItemBinding) : RecyclerView.ViewHolder(customWatchfaceImportListItemBinding.root) {
|
inner class PrefFileViewHolder(val customWatchfaceImportListItemBinding: CustomWatchfaceImportListItemBinding) : RecyclerView.ViewHolder(customWatchfaceImportListItemBinding.root) {
|
||||||
|
|
||||||
|
@ -59,14 +59,12 @@ class CustomWatchfaceImportListActivity: TranslatedDaggerAppCompatActivity() {
|
||||||
with(customWatchfaceImportListItemBinding) {
|
with(customWatchfaceImportListItemBinding) {
|
||||||
root.isClickable = true
|
root.isClickable = true
|
||||||
customWatchfaceImportListItemBinding.root.setOnClickListener {
|
customWatchfaceImportListItemBinding.root.setOnClickListener {
|
||||||
val customWatchfaceFile = filelistName.tag as CustomWatchfaceFile
|
val customWatchfaceFile = filelistName.tag as CustomWatchfaceData
|
||||||
val customWF = EventData.ActionSetCustomWatchface(customWatchfaceFile.metadata[CWF_NAME] ?:"", customWatchfaceFile.json, customWatchfaceFile.drawableFiles)
|
val customWF = EventData.ActionSetCustomWatchface(customWatchfaceFile)
|
||||||
sp.putString(info.nightscout.shared.R.string.key_custom_watchface, customWF.serialize())
|
|
||||||
val i = Intent()
|
val i = Intent()
|
||||||
setResult(FragmentActivity.RESULT_OK, i)
|
setResult(FragmentActivity.RESULT_OK, i)
|
||||||
|
//rxBus.send(EventWearUpdateGui(customWatchfaceFile))
|
||||||
rxBus.send(EventMobileDataToWear(customWF))
|
rxBus.send(EventMobileDataToWear(customWF))
|
||||||
aapsLogger.debug("XXXXX EventMobileDataToWear sent")
|
|
||||||
|
|
||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,13 +83,12 @@ class CustomWatchfaceImportListActivity: TranslatedDaggerAppCompatActivity() {
|
||||||
override fun onBindViewHolder(holder: PrefFileViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: PrefFileViewHolder, position: Int) {
|
||||||
val customWatchfaceFile = customWatchfaceFileList[position]
|
val customWatchfaceFile = customWatchfaceFileList[position]
|
||||||
val metadata = customWatchfaceFile.metadata
|
val metadata = customWatchfaceFile.metadata
|
||||||
val drawable = customWatchfaceFile.drawableFiles[CustomWatchfaceDrawableDataKey
|
val drawable = customWatchfaceFile.drawableDatas[CustomWatchfaceDrawableDataKey
|
||||||
.CUSTOM_WATCHFACE]?.toDrawable(resources)
|
.CUSTOM_WATCHFACE]?.toDrawable(resources)
|
||||||
with(holder.customWatchfaceImportListItemBinding) {
|
with(holder.customWatchfaceImportListItemBinding) {
|
||||||
filelistName.text = rh.gs(R.string.wear_import_filename, customWatchfaceFile.file.name)
|
filelistName.text = rh.gs(info.nightscout.shared.R.string.metadata_wear_import_filename, metadata[CWF_FILENAME])
|
||||||
filelistName.tag = customWatchfaceFile
|
filelistName.tag = customWatchfaceFile
|
||||||
customWatchface.setImageDrawable(drawable)
|
customWatchface.setImageDrawable(drawable)
|
||||||
filelistDir.text = rh.gs(R.string.wear_import_directory, customWatchfaceFile.file.parentFile?.absolutePath)
|
|
||||||
customName.text = rh.gs(CWF_NAME.label, metadata[CWF_NAME])
|
customName.text = rh.gs(CWF_NAME.label, metadata[CWF_NAME])
|
||||||
author.text = rh.gs(CWF_AUTHOR.label, metadata[CWF_AUTHOR] ?:"")
|
author.text = rh.gs(CWF_AUTHOR.label, metadata[CWF_AUTHOR] ?:"")
|
||||||
createdAt.text = rh.gs(CWF_CREATED_AT.label, metadata[CWF_CREATED_AT] ?:"")
|
createdAt.text = rh.gs(CWF_CREATED_AT.label, metadata[CWF_CREATED_AT] ?:"")
|
||||||
|
|
|
@ -1,128 +0,0 @@
|
||||||
package info.nightscout.configuration.maintenance.formats
|
|
||||||
|
|
||||||
import info.nightscout.core.utils.CryptoUtil
|
|
||||||
import info.nightscout.interfaces.storage.Storage
|
|
||||||
import info.nightscout.rx.weardata.CustomWatchface
|
|
||||||
import info.nightscout.rx.weardata.CustomWatchfaceDrawableDataKey
|
|
||||||
import info.nightscout.rx.weardata.CustomWatchfaceDrawableDataMap
|
|
||||||
import info.nightscout.rx.weardata.CustomWatchfaceFormat
|
|
||||||
import info.nightscout.rx.weardata.CustomWatchfaceMetadataKey
|
|
||||||
import info.nightscout.rx.weardata.CustomWatchfaceMetadataMap
|
|
||||||
import info.nightscout.rx.weardata.DrawableData
|
|
||||||
import info.nightscout.rx.weardata.DrawableFormat
|
|
||||||
import info.nightscout.rx.weardata.EventData
|
|
||||||
import info.nightscout.shared.interfaces.ResourceHelper
|
|
||||||
import org.json.JSONObject
|
|
||||||
import java.io.BufferedOutputStream
|
|
||||||
import java.io.ByteArrayOutputStream
|
|
||||||
import java.io.File
|
|
||||||
import java.io.FileOutputStream
|
|
||||||
import java.util.zip.ZipEntry
|
|
||||||
import java.util.zip.ZipInputStream
|
|
||||||
import java.util.zip.ZipOutputStream
|
|
||||||
import javax.inject.Inject
|
|
||||||
import javax.inject.Singleton
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
class ZipCustomWatchfaceFormat @Inject constructor(
|
|
||||||
private var rh: ResourceHelper,
|
|
||||||
private var cryptoUtil: CryptoUtil,
|
|
||||||
private var storage: Storage
|
|
||||||
) : CustomWatchfaceFormat {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
const val CUSTOM_WF_EXTENTION = ".zip"
|
|
||||||
const val CUSTOM_JSON_FILE = "CustomWatchface.json"
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun loadCustomWatchface(cwfFile: File): CustomWatchface? {
|
|
||||||
var json = JSONObject()
|
|
||||||
var metadata: CustomWatchfaceMetadataMap = mutableMapOf()
|
|
||||||
val drawableDatas: CustomWatchfaceDrawableDataMap = mutableMapOf()
|
|
||||||
|
|
||||||
try {
|
|
||||||
val zipInputStream = ZipInputStream(cwfFile.inputStream())
|
|
||||||
var zipEntry: ZipEntry? = zipInputStream.nextEntry
|
|
||||||
while (zipEntry != null) {
|
|
||||||
val entryName = zipEntry.name
|
|
||||||
|
|
||||||
val buffer = ByteArray(2048)
|
|
||||||
val byteArrayOutputStream = ByteArrayOutputStream()
|
|
||||||
var count = zipInputStream.read(buffer)
|
|
||||||
while (count != -1) {
|
|
||||||
byteArrayOutputStream.write(buffer, 0, count)
|
|
||||||
count = zipInputStream.read(buffer)
|
|
||||||
}
|
|
||||||
zipInputStream.closeEntry()
|
|
||||||
|
|
||||||
if (entryName == CUSTOM_JSON_FILE) {
|
|
||||||
val jsonString = byteArrayOutputStream.toByteArray().toString(Charsets.UTF_8)
|
|
||||||
json = JSONObject(jsonString)
|
|
||||||
metadata = loadMetadata(json)
|
|
||||||
} else {
|
|
||||||
val customWatchfaceDrawableDataKey = CustomWatchfaceDrawableDataKey.fromFileName(entryName)
|
|
||||||
val drawableFormat = DrawableFormat.fromFileName(entryName)
|
|
||||||
if (customWatchfaceDrawableDataKey != CustomWatchfaceDrawableDataKey.UNKNOWN && drawableFormat != DrawableFormat.UNKNOWN) {
|
|
||||||
drawableDatas[customWatchfaceDrawableDataKey] = DrawableData(byteArrayOutputStream.toByteArray(),drawableFormat)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
zipEntry = zipInputStream.nextEntry
|
|
||||||
}
|
|
||||||
|
|
||||||
// Valid CWF file must contains a valid json file with a name within metadata and a custom watchface image
|
|
||||||
if (metadata.containsKey(CustomWatchfaceMetadataKey.CWF_NAME) && drawableDatas.containsKey(CustomWatchfaceDrawableDataKey.CUSTOM_WATCHFACE))
|
|
||||||
return CustomWatchface(json.toString(4), metadata, drawableDatas)
|
|
||||||
else
|
|
||||||
return null
|
|
||||||
|
|
||||||
} catch (e: Exception) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override fun saveCustomWatchface(file: File, customWatchface: EventData.ActionSetCustomWatchface) {
|
|
||||||
|
|
||||||
try {
|
|
||||||
val outputStream = FileOutputStream(file)
|
|
||||||
val zipOutputStream = ZipOutputStream(BufferedOutputStream(outputStream))
|
|
||||||
|
|
||||||
// Ajouter le fichier JSON au ZIP
|
|
||||||
val jsonEntry = ZipEntry(CUSTOM_JSON_FILE)
|
|
||||||
zipOutputStream.putNextEntry(jsonEntry)
|
|
||||||
zipOutputStream.write(customWatchface.json.toByteArray())
|
|
||||||
zipOutputStream.closeEntry()
|
|
||||||
|
|
||||||
// Ajouter les fichiers divers au ZIP
|
|
||||||
for (drawableData in customWatchface.drawableDataMap) {
|
|
||||||
val fileEntry = ZipEntry("${drawableData.key.fileName}.${drawableData.value.format.extension}")
|
|
||||||
zipOutputStream.putNextEntry(fileEntry)
|
|
||||||
zipOutputStream.write(drawableData.value.value)
|
|
||||||
zipOutputStream.closeEntry()
|
|
||||||
}
|
|
||||||
zipOutputStream.close()
|
|
||||||
outputStream.close()
|
|
||||||
} catch (e: Exception) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override fun loadMetadata(contents: JSONObject): CustomWatchfaceMetadataMap {
|
|
||||||
val metadata: CustomWatchfaceMetadataMap = mutableMapOf()
|
|
||||||
|
|
||||||
if (contents.has("metadata")) {
|
|
||||||
val meta = contents.getJSONObject("metadata")
|
|
||||||
for (key in meta.keys()) {
|
|
||||||
val metaKey = CustomWatchfaceMetadataKey.fromKey(key)
|
|
||||||
if (metaKey != null) {
|
|
||||||
metadata[metaKey] = meta.getString(key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return metadata
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -59,23 +59,6 @@
|
||||||
android:textColor="?attr/importListFileNameColor"
|
android:textColor="?attr/importListFileNameColor"
|
||||||
tools:ignore="HardcodedText" />
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/filelist_dir"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="5dp"
|
|
||||||
android:layout_marginTop="0dp"
|
|
||||||
android:ellipsize="none"
|
|
||||||
android:maxLines="2"
|
|
||||||
android:paddingStart="0dp"
|
|
||||||
android:paddingEnd="10dp"
|
|
||||||
android:scrollHorizontally="false"
|
|
||||||
android:text="File dir here"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
|
||||||
android:textColor="?attr/importListFileNameColor"
|
|
||||||
android:textSize="11sp"
|
|
||||||
tools:ignore="HardcodedText" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/filelist_name"
|
android:id="@+id/filelist_name"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|
|
@ -166,8 +166,6 @@
|
||||||
|
|
||||||
<!-- Custom Watchface -->
|
<!-- Custom Watchface -->
|
||||||
<string name="wear_import_custom_watchface_title">Select Custom Watchface</string>
|
<string name="wear_import_custom_watchface_title">Select Custom Watchface</string>
|
||||||
<string name="wear_import_directory" comment="placeholder is for imported watchface path">Directory: %1$s</string>
|
|
||||||
<string name="wear_import_filename">File name: %1$s</string>
|
|
||||||
|
|
||||||
<!-- Permissions -->
|
<!-- Permissions -->
|
||||||
<string name="alert_dialog_storage_permission_text">Please reboot your phone or restart AAPS from the System Settings \notherwise Android APS will not have logging (important to track and verify that the algorithms are working correctly)!</string>
|
<string name="alert_dialog_storage_permission_text">Please reboot your phone or restart AAPS from the System Settings \notherwise Android APS will not have logging (important to track and verify that the algorithms are working correctly)!</string>
|
||||||
|
|
|
@ -17,6 +17,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.CustomWatchfaceDrawableDataKey
|
import info.nightscout.rx.weardata.CustomWatchfaceDrawableDataKey
|
||||||
|
import info.nightscout.rx.weardata.CustomWatchfaceMetadataKey
|
||||||
import info.nightscout.rx.weardata.EventData
|
import info.nightscout.rx.weardata.EventData
|
||||||
import info.nightscout.shared.interfaces.ResourceHelper
|
import info.nightscout.shared.interfaces.ResourceHelper
|
||||||
import info.nightscout.shared.sharedPreferences.SP
|
import info.nightscout.shared.sharedPreferences.SP
|
||||||
|
@ -61,13 +62,11 @@ class WearFragment : DaggerFragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
binding.defaultCustom.setOnClickListener {
|
binding.defaultCustom.setOnClickListener {
|
||||||
sp.remove(info.nightscout.shared.R.string.key_custom_watchface)
|
|
||||||
wearPlugin.savedCustomWatchface = null
|
|
||||||
rxBus.send(EventMobileToWear(EventData.ActionrequestSetDefaultWatchface(dateUtil.now())))
|
rxBus.send(EventMobileToWear(EventData.ActionrequestSetDefaultWatchface(dateUtil.now())))
|
||||||
updateGui()
|
updateGui()
|
||||||
}
|
}
|
||||||
binding.sendCustom.setOnClickListener {
|
binding.sendCustom.setOnClickListener {
|
||||||
wearPlugin.savedCustomWatchface?.let { cwf -> rxBus.send(EventMobileDataToWear(cwf)) }
|
wearPlugin.savedCustomWatchface?.let { cwf -> rxBus.send(EventMobileDataToWear(EventData.ActionSetCustomWatchface(cwf))) }
|
||||||
}
|
}
|
||||||
binding.exportCustom.setOnClickListener {
|
binding.exportCustom.setOnClickListener {
|
||||||
wearPlugin.savedCustomWatchface?.let { importExportPrefs.exportCustomWatchface(it) }
|
wearPlugin.savedCustomWatchface?.let { importExportPrefs.exportCustomWatchface(it) }
|
||||||
|
@ -80,16 +79,11 @@ class WearFragment : DaggerFragment() {
|
||||||
disposable += rxBus
|
disposable += rxBus
|
||||||
.toObservable(EventWearUpdateGui::class.java)
|
.toObservable(EventWearUpdateGui::class.java)
|
||||||
.observeOn(aapsSchedulers.main)
|
.observeOn(aapsSchedulers.main)
|
||||||
.subscribe({ updateGui() }, fabricPrivacy::logException)
|
|
||||||
disposable += rxBus
|
|
||||||
.toObservable(EventMobileDataToWear::class.java)
|
|
||||||
.observeOn(aapsSchedulers.main)
|
|
||||||
.subscribe({
|
.subscribe({
|
||||||
loadCustom(it.payload)
|
it.customWatchfaceData?.let { wearPlugin.savedCustomWatchface = it }
|
||||||
wearPlugin.customWatchfaceSerialized = ""
|
if (it.exportFile)
|
||||||
wearPlugin.savedCustomWatchface = null
|
ToastUtils.okToast(context,rh.gs(R.string.wear_new_custom_watchface_received))
|
||||||
updateGui()
|
updateGui()
|
||||||
ToastUtils.okToast(context,rh.gs(R.string.wear_new_custom_watchface_received))
|
|
||||||
}, fabricPrivacy::logException)
|
}, fabricPrivacy::logException)
|
||||||
if (wearPlugin.savedCustomWatchface == null)
|
if (wearPlugin.savedCustomWatchface == null)
|
||||||
rxBus.send(EventMobileToWear(EventData.ActionrequestCustomWatchface(false)))
|
rxBus.send(EventMobileToWear(EventData.ActionrequestCustomWatchface(false)))
|
||||||
|
@ -110,24 +104,10 @@ class WearFragment : DaggerFragment() {
|
||||||
|
|
||||||
private fun updateGui() {
|
private fun updateGui() {
|
||||||
_binding ?: return
|
_binding ?: return
|
||||||
sp.getString(info.nightscout.shared.R.string.key_custom_watchface, "").let {
|
|
||||||
if (it != wearPlugin.customWatchfaceSerialized && it != "") {
|
|
||||||
aapsLogger.debug("XXXXX Serialisation: ${it.length}")
|
|
||||||
try {
|
|
||||||
wearPlugin.savedCustomWatchface = (EventData.deserialize(it) as EventData.ActionSetCustomWatchface)
|
|
||||||
wearPlugin.customWatchfaceSerialized = it
|
|
||||||
}
|
|
||||||
catch(e: Exception) {
|
|
||||||
wearPlugin.customWatchfaceSerialized = ""
|
|
||||||
wearPlugin.savedCustomWatchface = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sp.remove(info.nightscout.shared.R.string.key_custom_watchface)
|
|
||||||
}
|
|
||||||
wearPlugin.savedCustomWatchface?.let {
|
wearPlugin.savedCustomWatchface?.let {
|
||||||
binding.customName.text = rh.gs(R.string.wear_custom_watchface, it.name)
|
binding.customName.text = rh.gs(R.string.wear_custom_watchface, it.metadata[CustomWatchfaceMetadataKey.CWF_NAME])
|
||||||
binding.sendCustom.visibility = View.VISIBLE
|
binding.sendCustom.visibility = View.VISIBLE
|
||||||
binding.coverChart.setImageDrawable(it.drawableDataMap[CustomWatchfaceDrawableDataKey.CUSTOM_WATCHFACE]?.toDrawable(resources))
|
binding.coverChart.setImageDrawable(it.drawableDatas[CustomWatchfaceDrawableDataKey.CUSTOM_WATCHFACE]?.toDrawable(resources))
|
||||||
} ?:apply {
|
} ?:apply {
|
||||||
binding.customName.text = rh.gs(R.string.wear_custom_watchface, rh.gs(info.nightscout.shared.R.string.wear_default_watchface))
|
binding.customName.text = rh.gs(R.string.wear_custom_watchface, rh.gs(info.nightscout.shared.R.string.wear_default_watchface))
|
||||||
binding.sendCustom.visibility = View.INVISIBLE
|
binding.sendCustom.visibility = View.INVISIBLE
|
||||||
|
@ -137,7 +117,6 @@ class WearFragment : DaggerFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadCustom(cwf: EventData.ActionSetCustomWatchface) {
|
private fun loadCustom(cwf: EventData.ActionSetCustomWatchface) {
|
||||||
aapsLogger.debug("XXXXX EventWearCwfExported received")
|
wearPlugin.savedCustomWatchface = cwf.customWatchfaceData
|
||||||
wearPlugin.savedCustomWatchface = cwf
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -18,6 +18,7 @@ import info.nightscout.rx.events.EventMobileToWear
|
||||||
import info.nightscout.rx.events.EventOverviewBolusProgress
|
import info.nightscout.rx.events.EventOverviewBolusProgress
|
||||||
import info.nightscout.rx.events.EventPreferenceChange
|
import info.nightscout.rx.events.EventPreferenceChange
|
||||||
import info.nightscout.rx.logging.AAPSLogger
|
import info.nightscout.rx.logging.AAPSLogger
|
||||||
|
import info.nightscout.rx.weardata.CustomWatchfaceData
|
||||||
import info.nightscout.rx.weardata.EventData
|
import info.nightscout.rx.weardata.EventData
|
||||||
import info.nightscout.shared.interfaces.ResourceHelper
|
import info.nightscout.shared.interfaces.ResourceHelper
|
||||||
import info.nightscout.shared.sharedPreferences.SP
|
import info.nightscout.shared.sharedPreferences.SP
|
||||||
|
@ -55,7 +56,7 @@ class WearPlugin @Inject constructor(
|
||||||
|
|
||||||
var connectedDevice = "---"
|
var connectedDevice = "---"
|
||||||
var customWatchfaceSerialized = ""
|
var customWatchfaceSerialized = ""
|
||||||
var savedCustomWatchface: EventData.ActionSetCustomWatchface? = null
|
var savedCustomWatchface: CustomWatchfaceData? = null
|
||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
|
|
|
@ -60,7 +60,6 @@ import info.nightscout.plugins.R
|
||||||
import info.nightscout.rx.AapsSchedulers
|
import info.nightscout.rx.AapsSchedulers
|
||||||
import info.nightscout.rx.bus.RxBus
|
import info.nightscout.rx.bus.RxBus
|
||||||
import info.nightscout.rx.events.EventMobileToWear
|
import info.nightscout.rx.events.EventMobileToWear
|
||||||
import info.nightscout.rx.events.EventWearCwfExported
|
|
||||||
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.logging.LTag
|
import info.nightscout.rx.logging.LTag
|
||||||
|
@ -1262,14 +1261,10 @@ class DataHandlerMobile @Inject constructor(
|
||||||
|
|
||||||
private fun handleGetCustomWatchface(command: EventData.ActionGetCustomWatchface) {
|
private fun handleGetCustomWatchface(command: EventData.ActionGetCustomWatchface) {
|
||||||
val customWatchface = command.customWatchface
|
val customWatchface = command.customWatchface
|
||||||
aapsLogger.debug(LTag.WEAR, "Custom Watchface received from ${command.sourceNodeId}: ${customWatchface.json}")
|
aapsLogger.debug(LTag.WEAR, "Custom Watchface received from ${command.sourceNodeId}: ${customWatchface.customWatchfaceData.json}")
|
||||||
//Update Wear Fragment
|
rxBus.send(EventWearUpdateGui(customWatchface.customWatchfaceData, command.exportFile))
|
||||||
sp.putString(info.nightscout.shared.R.string.key_custom_watchface, customWatchface.serialize())
|
|
||||||
//rxBus.send(EventWearCwfExported(customWatchface))
|
|
||||||
rxBus.send(EventWearUpdateGui())
|
|
||||||
if (command.exportFile)
|
if (command.exportFile)
|
||||||
importExportPrefs.exportCustomWatchface(customWatchface)
|
importExportPrefs.exportCustomWatchface(customWatchface.customWatchfaceData)
|
||||||
//Implement here a record within SP and a save within exports subfolder as zipFile
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,7 @@ import kotlinx.coroutines.SupervisorJob
|
||||||
import kotlinx.coroutines.cancel
|
import kotlinx.coroutines.cancel
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.tasks.await
|
import kotlinx.coroutines.tasks.await
|
||||||
|
import kotlinx.serialization.ExperimentalSerializationApi
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class DataLayerListenerServiceMobile : WearableListenerService() {
|
class DataLayerListenerServiceMobile : WearableListenerService() {
|
||||||
|
@ -82,7 +83,7 @@ class DataLayerListenerServiceMobile : WearableListenerService() {
|
||||||
|
|
||||||
private val rxPath get() = getString(info.nightscout.shared.R.string.path_rx_bridge)
|
private val rxPath get() = getString(info.nightscout.shared.R.string.path_rx_bridge)
|
||||||
private val rxDataPath get() = getString(info.nightscout.shared.R.string.path_rx_data_bridge)
|
private val rxDataPath get() = getString(info.nightscout.shared.R.string.path_rx_data_bridge)
|
||||||
|
@ExperimentalSerializationApi
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
AndroidInjection.inject(this)
|
AndroidInjection.inject(this)
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
|
@ -131,7 +132,7 @@ class DataLayerListenerServiceMobile : WearableListenerService() {
|
||||||
}
|
}
|
||||||
super.onDataChanged(dataEvents)
|
super.onDataChanged(dataEvents)
|
||||||
}
|
}
|
||||||
|
@ExperimentalSerializationApi
|
||||||
override fun onMessageReceived(messageEvent: MessageEvent) {
|
override fun onMessageReceived(messageEvent: MessageEvent) {
|
||||||
super.onMessageReceived(messageEvent)
|
super.onMessageReceived(messageEvent)
|
||||||
|
|
||||||
|
|
|
@ -186,6 +186,9 @@ class DataHandlerWear @Inject constructor(
|
||||||
.subscribe {
|
.subscribe {
|
||||||
aapsLogger.debug(LTag.WEAR, "Custom Watchface received from ${it.sourceNodeId}")
|
aapsLogger.debug(LTag.WEAR, "Custom Watchface received from ${it.sourceNodeId}")
|
||||||
persistence.store(it)
|
persistence.store(it)
|
||||||
|
persistence.readCustomWatchface()?.let {
|
||||||
|
rxBus.send(EventWearDataToMobile(EventData.ActionGetCustomWatchface(it, false)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
disposable += rxBus
|
disposable += rxBus
|
||||||
.toObservable(EventData.ActionrequestSetDefaultWatchface::class.java)
|
.toObservable(EventData.ActionrequestSetDefaultWatchface::class.java)
|
||||||
|
@ -193,6 +196,9 @@ class DataHandlerWear @Inject constructor(
|
||||||
.subscribe {
|
.subscribe {
|
||||||
aapsLogger.debug(LTag.WEAR, "Set Default Watchface received from ${it.sourceNodeId}")
|
aapsLogger.debug(LTag.WEAR, "Set Default Watchface received from ${it.sourceNodeId}")
|
||||||
persistence.setDefaultWatchface()
|
persistence.setDefaultWatchface()
|
||||||
|
persistence.readCustomWatchface()?.let {
|
||||||
|
rxBus.send(EventWearDataToMobile(EventData.ActionGetCustomWatchface(it, false)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
disposable += rxBus
|
disposable += rxBus
|
||||||
.toObservable(EventData.ActionrequestCustomWatchface::class.java)
|
.toObservable(EventData.ActionrequestCustomWatchface::class.java)
|
||||||
|
|
|
@ -22,6 +22,7 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.tasks.await
|
import kotlinx.coroutines.tasks.await
|
||||||
|
import kotlinx.serialization.ExperimentalSerializationApi
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class DataLayerListenerServiceWear : WearableListenerService() {
|
class DataLayerListenerServiceWear : WearableListenerService() {
|
||||||
|
@ -45,7 +46,7 @@ class DataLayerListenerServiceWear : WearableListenerService() {
|
||||||
|
|
||||||
private val rxPath get() = getString(info.nightscout.shared.R.string.path_rx_bridge)
|
private val rxPath get() = getString(info.nightscout.shared.R.string.path_rx_bridge)
|
||||||
private val rxDataPath get() = getString(info.nightscout.shared.R.string.path_rx_data_bridge)
|
private val rxDataPath get() = getString(info.nightscout.shared.R.string.path_rx_data_bridge)
|
||||||
|
@ExperimentalSerializationApi
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
AndroidInjection.inject(this)
|
AndroidInjection.inject(this)
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
|
@ -95,7 +96,7 @@ class DataLayerListenerServiceWear : WearableListenerService() {
|
||||||
}
|
}
|
||||||
super.onDataChanged(dataEvents)
|
super.onDataChanged(dataEvents)
|
||||||
}
|
}
|
||||||
|
@ExperimentalSerializationApi
|
||||||
override fun onMessageReceived(messageEvent: MessageEvent) {
|
override fun onMessageReceived(messageEvent: MessageEvent) {
|
||||||
super.onMessageReceived(messageEvent)
|
super.onMessageReceived(messageEvent)
|
||||||
|
|
||||||
|
|
|
@ -172,7 +172,7 @@ open class Persistence @Inject constructor(
|
||||||
|
|
||||||
fun store(customWatchface: EventData.ActionSetCustomWatchface, isdefault: Boolean = false) {
|
fun store(customWatchface: EventData.ActionSetCustomWatchface, isdefault: Boolean = false) {
|
||||||
putString(if (isdefault) CUSTOM_DEFAULT_WATCHFACE else CUSTOM_WATCHFACE, customWatchface.serialize())
|
putString(if (isdefault) CUSTOM_DEFAULT_WATCHFACE else CUSTOM_WATCHFACE, customWatchface.serialize())
|
||||||
aapsLogger.debug(LTag.WEAR, "Stored Custom Watchface ${customWatchface.name} ${isdefault}: $customWatchface")
|
aapsLogger.debug(LTag.WEAR, "Stored Custom Watchface ${customWatchface.customWatchfaceData} ${isdefault}: $customWatchface")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setDefaultWatchface() {
|
fun setDefaultWatchface() {
|
||||||
|
|
|
@ -26,12 +26,14 @@ import androidx.viewbinding.ViewBinding
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.databinding.ActivityCustomBinding
|
import info.nightscout.androidaps.databinding.ActivityCustomBinding
|
||||||
import info.nightscout.androidaps.watchfaces.utils.BaseWatchFace
|
import info.nightscout.androidaps.watchfaces.utils.BaseWatchFace
|
||||||
|
import info.nightscout.rx.weardata.CustomWatchfaceData
|
||||||
import info.nightscout.rx.weardata.CustomWatchfaceDrawableDataKey
|
import info.nightscout.rx.weardata.CustomWatchfaceDrawableDataKey
|
||||||
import info.nightscout.rx.weardata.CustomWatchfaceDrawableDataMap
|
import info.nightscout.rx.weardata.CustomWatchfaceDrawableDataMap
|
||||||
import info.nightscout.rx.weardata.CustomWatchfaceMetadataKey
|
import info.nightscout.rx.weardata.CustomWatchfaceMetadataKey
|
||||||
import info.nightscout.rx.weardata.DrawableData
|
import info.nightscout.rx.weardata.DrawableData
|
||||||
import info.nightscout.rx.weardata.DrawableFormat
|
import info.nightscout.rx.weardata.DrawableFormat
|
||||||
import info.nightscout.rx.weardata.EventData
|
import info.nightscout.rx.weardata.EventData
|
||||||
|
import info.nightscout.rx.weardata.ZipWatchfaceFormat
|
||||||
import info.nightscout.shared.extensions.toVisibility
|
import info.nightscout.shared.extensions.toVisibility
|
||||||
import org.joda.time.TimeOfDay
|
import org.joda.time.TimeOfDay
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
@ -111,23 +113,14 @@ class CustomWatchface : BaseWatchFace() {
|
||||||
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
|
||||||
//aapsLogger.debug("XXXXXX Setsecond calles:")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setWatchfaceStyle() {
|
private fun setWatchfaceStyle() {
|
||||||
bgColor = when (singleBg.sgvLevel) {
|
|
||||||
1L -> highColor
|
|
||||||
0L -> midColor
|
|
||||||
-1L -> lowColor
|
|
||||||
else -> midColor
|
|
||||||
}
|
|
||||||
val customWatchface = persistence.readCustomWatchface() ?: persistence.readCustomWatchface(true)
|
val customWatchface = persistence.readCustomWatchface() ?: persistence.readCustomWatchface(true)
|
||||||
//aapsLogger.debug("XXXXX + setWatchfaceStyle Json ${customWatchface?.json}")
|
|
||||||
customWatchface?.let { customWatchface ->
|
customWatchface?.let { customWatchface ->
|
||||||
val json = JSONObject(customWatchface.json)
|
val json = JSONObject(customWatchface.customWatchfaceData.json)
|
||||||
val drawableDataMap = customWatchface.drawableDataMap
|
val drawableDataMap = customWatchface.customWatchfaceData.drawableDatas
|
||||||
enableSecond = (if (json.has("enableSecond")) json.getBoolean("enableSecond") else false) && sp.getBoolean(R.string.key_show_seconds, true)
|
enableSecond = (if (json.has("enableSecond")) json.getBoolean("enableSecond") else false) && sp.getBoolean(R.string.key_show_seconds, true)
|
||||||
//aapsLogger.debug("XXXXXX json File (beginning):" + customWatchface.json)
|
|
||||||
|
|
||||||
highColor = if (json.has("highColor")) Color.parseColor(json.getString("highColor")) else ContextCompat.getColor(this, R.color.dark_highColor)
|
highColor = if (json.has("highColor")) Color.parseColor(json.getString("highColor")) else ContextCompat.getColor(this, R.color.dark_highColor)
|
||||||
midColor = if (json.has("midColor")) Color.parseColor(json.getString("midColor")) else ContextCompat.getColor(this, R.color.inrange)
|
midColor = if (json.has("midColor")) Color.parseColor(json.getString("midColor")) else ContextCompat.getColor(this, R.color.inrange)
|
||||||
|
@ -136,13 +129,16 @@ class CustomWatchface : BaseWatchFace() {
|
||||||
carbColor = if (json.has("carbColor")) Color.parseColor(json.getString("carbColor")) else ContextCompat.getColor(this, R.color.carbs)
|
carbColor = if (json.has("carbColor")) Color.parseColor(json.getString("carbColor")) else ContextCompat.getColor(this, R.color.carbs)
|
||||||
gridColor = if (json.has("gridColor")) Color.parseColor(json.getString("gridColor")) else ContextCompat.getColor(this, R.color.carbs)
|
gridColor = if (json.has("gridColor")) Color.parseColor(json.getString("gridColor")) else ContextCompat.getColor(this, R.color.carbs)
|
||||||
pointSize = if (json.has("pointSize")) json.getInt("pointSize") else 2
|
pointSize = if (json.has("pointSize")) json.getInt("pointSize") else 2
|
||||||
aapsLogger.debug("XXXXXX enableSecond $enableSecond ${sp.getBoolean(R.string.key_show_seconds, false)} pointSize $pointSize")
|
bgColor = when (singleBg.sgvLevel) {
|
||||||
|
1L -> highColor
|
||||||
|
0L -> midColor
|
||||||
|
-1L -> lowColor
|
||||||
|
else -> midColor
|
||||||
|
}
|
||||||
binding.mainLayout.forEach { view ->
|
binding.mainLayout.forEach { view ->
|
||||||
//aapsLogger.debug("XXXXXX view:" + view.tag.toString())
|
|
||||||
view.tag?.let { tag ->
|
view.tag?.let { tag ->
|
||||||
if (json.has(tag.toString())) {
|
if (json.has(tag.toString())) {
|
||||||
var viewjson = json.getJSONObject(tag.toString())
|
var viewjson = json.getJSONObject(tag.toString())
|
||||||
//aapsLogger.debug("XXXXXX \"" + tag.toString() + "\": " + viewjson.toString(4))
|
|
||||||
var wrapContent = LayoutParams.WRAP_CONTENT
|
var wrapContent = LayoutParams.WRAP_CONTENT
|
||||||
val width = if (viewjson.has("width")) (viewjson.getInt("width") * zoomFactor).toInt() else wrapContent
|
val width = if (viewjson.has("width")) (viewjson.getInt("width") * zoomFactor).toInt() else wrapContent
|
||||||
val height = if (viewjson.has("height")) (viewjson.getInt("height") * zoomFactor).toInt() else wrapContent
|
val height = if (viewjson.has("height")) (viewjson.getInt("height") * zoomFactor).toInt() else wrapContent
|
||||||
|
@ -191,6 +187,7 @@ class CustomWatchface : BaseWatchFace() {
|
||||||
private fun defaultWatchface(): EventData.ActionSetCustomWatchface {
|
private fun defaultWatchface(): EventData.ActionSetCustomWatchface {
|
||||||
val metadata = JSONObject()
|
val metadata = JSONObject()
|
||||||
.put(CustomWatchfaceMetadataKey.CWF_NAME.key, getString(info.nightscout.shared.R.string.wear_default_watchface))
|
.put(CustomWatchfaceMetadataKey.CWF_NAME.key, getString(info.nightscout.shared.R.string.wear_default_watchface))
|
||||||
|
.put(CustomWatchfaceMetadataKey.CWF_FILENAME.key, getString(R.string.wear_default_watchface))
|
||||||
.put(CustomWatchfaceMetadataKey.CWF_AUTHOR.key, "Philoul")
|
.put(CustomWatchfaceMetadataKey.CWF_AUTHOR.key, "Philoul")
|
||||||
.put(CustomWatchfaceMetadataKey.CWF_CREATED_AT.key, dateUtil.dateString(dateUtil.now()))
|
.put(CustomWatchfaceMetadataKey.CWF_CREATED_AT.key, dateUtil.dateString(dateUtil.now()))
|
||||||
.put(CustomWatchfaceMetadataKey.CWF_VERSION.key, CUSTOM_VERSION)
|
.put(CustomWatchfaceMetadataKey.CWF_VERSION.key, CUSTOM_VERSION)
|
||||||
|
@ -248,12 +245,13 @@ class CustomWatchface : BaseWatchFace() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val drawableDatas: CustomWatchfaceDrawableDataMap = mutableMapOf()
|
val metadataMap = ZipWatchfaceFormat.loadMetadata(json)
|
||||||
|
val drawableDataMap: CustomWatchfaceDrawableDataMap = mutableMapOf()
|
||||||
getResourceByteArray(info.nightscout.shared.R.drawable.watchface_custom)?.let {
|
getResourceByteArray(info.nightscout.shared.R.drawable.watchface_custom)?.let {
|
||||||
val drawableDataMap = DrawableData(it,DrawableFormat.PNG)
|
val drawableData = DrawableData(it,DrawableFormat.PNG)
|
||||||
drawableDatas[CustomWatchfaceDrawableDataKey.CUSTOM_WATCHFACE] = drawableDataMap
|
drawableDataMap[CustomWatchfaceDrawableDataKey.CUSTOM_WATCHFACE] = drawableData
|
||||||
}
|
}
|
||||||
return EventData.ActionSetCustomWatchface(getString(info.nightscout.shared.R.string.wear_default_watchface),json.toString(4),drawableDatas)
|
return EventData.ActionSetCustomWatchface(CustomWatchfaceData(json.toString(4), metadataMap, drawableDataMap))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setDefaultColors() {
|
private fun setDefaultColors() {
|
||||||
|
|
Loading…
Reference in a new issue