simplify :core:interfaces
This commit is contained in:
parent
91d19b51dc
commit
46c2abdc5b
25 changed files with 154 additions and 121 deletions
|
@ -0,0 +1,7 @@
|
|||
package info.nightscout.interfaces.maintenance
|
||||
|
||||
import android.os.Parcelable
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
data class PrefMetadata(var value: String, var status: PrefsStatus, var info: String? = null) : Parcelable
|
|
@ -0,0 +1,11 @@
|
|||
package info.nightscout.interfaces.maintenance
|
||||
|
||||
import android.content.Context
|
||||
|
||||
interface PrefsMetadataKey {
|
||||
|
||||
val key: String
|
||||
val icon: Int
|
||||
val label: Int
|
||||
fun formatForDisplay(context: Context, value: String): String
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package info.nightscout.interfaces.maintenance
|
||||
|
||||
import android.os.Parcelable
|
||||
|
||||
interface PrefsStatus : Parcelable {
|
||||
|
||||
val icon: Int
|
||||
}
|
|
@ -1,17 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Maintenance -->
|
||||
<string name="metadata_label_format">File format</string>
|
||||
<string name="metadata_label_created_at">Created at</string>
|
||||
<string name="metadata_label_aaps_version">AAPS Version</string>
|
||||
<string name="metadata_label_aaps_flavour">Build Variant</string>
|
||||
<string name="metadata_label_device_name">Exporting device patient name</string>
|
||||
<string name="metadata_label_device_model">Exporting device model</string>
|
||||
<string name="metadata_label_encryption">File encryption</string>
|
||||
<string name="metadata_format_new">New encrypted format</string>
|
||||
<string name="metadata_format_debug">New debug format (unencrypted)</string>
|
||||
<string name="metadata_format_other">Unknown export format</string>
|
||||
|
||||
<!-- PumpPluginBase -->
|
||||
<string name="pump_driver_changed" comment="26 characters max for translation">Pump driver changed.</string>
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package info.nightscout.implementation.utils
|
||||
|
||||
import info.nightscout.interfaces.R
|
||||
import info.nightscout.interfaces.utils.DecimalFormatter
|
||||
import info.nightscout.shared.interfaces.ResourceHelper
|
||||
import java.text.DecimalFormat
|
||||
|
|
|
@ -3,6 +3,7 @@ plugins {
|
|||
id 'kotlin-android'
|
||||
id 'kotlin-kapt'
|
||||
id 'kotlin-allopen'
|
||||
id 'kotlin-parcelize'
|
||||
}
|
||||
|
||||
apply from: "${project.rootDir}/core/main/android_dependencies.gradle"
|
||||
|
|
|
@ -44,7 +44,7 @@ import info.nightscout.interfaces.maintenance.Prefs
|
|||
import info.nightscout.interfaces.maintenance.PrefsFile
|
||||
import info.nightscout.interfaces.maintenance.PrefsFormat
|
||||
import info.nightscout.interfaces.maintenance.PrefsMetadataKey
|
||||
import info.nightscout.interfaces.maintenance.PrefsStatus
|
||||
import info.nightscout.interfaces.maintenance.PrefsStatusImpl
|
||||
import info.nightscout.interfaces.protection.PasswordCheck
|
||||
import info.nightscout.interfaces.storage.Storage
|
||||
import info.nightscout.interfaces.ui.UiInteraction
|
||||
|
@ -114,12 +114,12 @@ class ImportExportPrefsImpl @Inject constructor(
|
|||
|
||||
val metadata: MutableMap<PrefsMetadataKey, PrefMetadata> = mutableMapOf()
|
||||
|
||||
metadata[PrefsMetadataKey.DEVICE_NAME] = PrefMetadata(detectUserName(context), PrefsStatus.OK)
|
||||
metadata[PrefsMetadataKey.CREATED_AT] = PrefMetadata(dateUtil.toISOString(dateUtil.now()), PrefsStatus.OK)
|
||||
metadata[PrefsMetadataKey.AAPS_VERSION] = PrefMetadata(config.VERSION_NAME, PrefsStatus.OK)
|
||||
metadata[PrefsMetadataKey.AAPS_FLAVOUR] = PrefMetadata(config.FLAVOR, PrefsStatus.OK)
|
||||
metadata[PrefsMetadataKey.DEVICE_MODEL] = PrefMetadata(config.currentDeviceModelString, PrefsStatus.OK)
|
||||
metadata[PrefsMetadataKey.ENCRYPTION] = PrefMetadata("Enabled", PrefsStatus.OK)
|
||||
metadata[PrefsMetadataKeyImpl.DEVICE_NAME] = PrefMetadata(detectUserName(context), PrefsStatusImpl.OK)
|
||||
metadata[PrefsMetadataKeyImpl.CREATED_AT] = PrefMetadata(dateUtil.toISOString(dateUtil.now()), PrefsStatusImpl.OK)
|
||||
metadata[PrefsMetadataKeyImpl.AAPS_VERSION] = PrefMetadata(config.VERSION_NAME, PrefsStatusImpl.OK)
|
||||
metadata[PrefsMetadataKeyImpl.AAPS_FLAVOUR] = PrefMetadata(config.FLAVOR, PrefsStatusImpl.OK)
|
||||
metadata[PrefsMetadataKeyImpl.DEVICE_MODEL] = PrefMetadata(config.currentDeviceModelString, PrefsStatusImpl.OK)
|
||||
metadata[PrefsMetadataKeyImpl.ENCRYPTION] = PrefMetadata("Enabled", PrefsStatusImpl.OK)
|
||||
|
||||
return metadata
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ class ImportExportPrefsImpl @Inject constructor(
|
|||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S || ActivityCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH_CONNECT) == PackageManager.PERMISSION_GRANTED) {
|
||||
(context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager?)?.adapter?.name
|
||||
} else null
|
||||
} catch (e: Exception){
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
val n4 = Settings.System.getString(context.contentResolver, "device_name")
|
||||
|
@ -219,7 +219,7 @@ class ImportExportPrefsImpl @Inject constructor(
|
|||
) {
|
||||
|
||||
// current master password was not the one used for decryption, so we prompt for old password...
|
||||
if (!importOk && (prefs.metadata[PrefsMetadataKey.ENCRYPTION]?.status == PrefsStatus.ERROR)) {
|
||||
if (!importOk && (prefs.metadata[PrefsMetadataKeyImpl.ENCRYPTION]?.status == PrefsStatusImpl.ERROR)) {
|
||||
askForEncryptionPass(
|
||||
activity, R.string.preferences_import_canceled, R.string.old_master_password,
|
||||
R.string.different_password_used, R.string.master_password_will_be_replaced
|
||||
|
@ -303,6 +303,7 @@ class ImportExportPrefsImpl @Inject constructor(
|
|||
override fun importCustomWatchface(fragment: Fragment) {
|
||||
fragment.activity?.let { importCustomWatchface(it) }
|
||||
}
|
||||
|
||||
override fun importCustomWatchface(activity: FragmentActivity) {
|
||||
try {
|
||||
if (activity is DaggerAppCompatActivityWithResult)
|
||||
|
@ -317,7 +318,7 @@ class ImportExportPrefsImpl @Inject constructor(
|
|||
|
||||
override fun exportCustomWatchface(customWatchface: CwfData, withDate: Boolean) {
|
||||
prefFileList.ensureExportDirExists()
|
||||
val newFile = prefFileList.newCwfFile(customWatchface.metadata[CwfMetadataKey.CWF_FILENAME] ?:"", withDate)
|
||||
val newFile = prefFileList.newCwfFile(customWatchface.metadata[CwfMetadataKey.CWF_FILENAME] ?: "", withDate)
|
||||
ZipWatchfaceFormat.saveCustomWatchface(newFile, customWatchface)
|
||||
}
|
||||
|
||||
|
@ -374,7 +375,7 @@ class ImportExportPrefsImpl @Inject constructor(
|
|||
var importOk = true
|
||||
|
||||
for ((_, value) in prefs.metadata) {
|
||||
if (value.status == PrefsStatus.ERROR)
|
||||
if (value.status == PrefsStatusImpl.ERROR)
|
||||
importOk = false
|
||||
}
|
||||
return importOk
|
||||
|
|
|
@ -14,7 +14,7 @@ import info.nightscout.interfaces.maintenance.PrefMetadataMap
|
|||
import info.nightscout.interfaces.maintenance.PrefsFile
|
||||
import info.nightscout.interfaces.maintenance.PrefsImportDir
|
||||
import info.nightscout.interfaces.maintenance.PrefsMetadataKey
|
||||
import info.nightscout.interfaces.maintenance.PrefsStatus
|
||||
import info.nightscout.interfaces.maintenance.PrefsStatusImpl
|
||||
import info.nightscout.interfaces.storage.Storage
|
||||
import info.nightscout.interfaces.versionChecker.VersionCheckerUtils
|
||||
import info.nightscout.rx.bus.RxBus
|
||||
|
@ -89,8 +89,8 @@ class PrefFileListProviderImpl @Inject constructor(
|
|||
// we sort only if we have metadata to be used for that
|
||||
if (loadMetadata) {
|
||||
prefFiles.sortWith(
|
||||
compareByDescending<PrefsFile> { it.metadata[PrefsMetadataKey.AAPS_FLAVOUR]?.status }
|
||||
.thenByDescending { it.metadata[PrefsMetadataKey.CREATED_AT]?.value }
|
||||
compareByDescending<PrefsFile> { it.metadata[PrefsMetadataKeyImpl.AAPS_FLAVOUR]?.status as PrefsStatusImpl }
|
||||
.thenByDescending { it.metadata[PrefsMetadataKeyImpl.CREATED_AT]?.value }
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -169,29 +169,29 @@ class PrefFileListProviderImpl @Inject constructor(
|
|||
|
||||
override fun newCwfFile(filename: String, withDate: Boolean): File {
|
||||
val timeLocal = LocalDateTime.now().toString(DateTimeFormat.forPattern("yyyy-MM-dd'_'HHmmss"))
|
||||
return if (withDate) File(exportsPath, "${filename}_$timeLocal${ZipWatchfaceFormat.CWF_EXTENTION}") else File(exportsPath,"${filename}${ZipWatchfaceFormat.CWF_EXTENTION}")
|
||||
return if (withDate) File(exportsPath, "${filename}_$timeLocal${ZipWatchfaceFormat.CWF_EXTENTION}") else File(exportsPath, "${filename}${ZipWatchfaceFormat.CWF_EXTENTION}")
|
||||
}
|
||||
|
||||
// check metadata for known issues, change their status and add info with explanations
|
||||
override fun checkMetadata(metadata: Map<PrefsMetadataKey, PrefMetadata>): Map<PrefsMetadataKey, PrefMetadata> {
|
||||
val meta = metadata.toMutableMap()
|
||||
|
||||
meta[PrefsMetadataKey.AAPS_FLAVOUR]?.let { flavour ->
|
||||
meta[PrefsMetadataKeyImpl.AAPS_FLAVOUR]?.let { flavour ->
|
||||
val flavourOfPrefs = flavour.value
|
||||
if (flavour.value != config.get().FLAVOR) {
|
||||
flavour.status = PrefsStatus.WARN
|
||||
flavour.status = PrefsStatusImpl.WARN
|
||||
flavour.info = rh.gs(R.string.metadata_warning_different_flavour, flavourOfPrefs, config.get().FLAVOR)
|
||||
}
|
||||
}
|
||||
|
||||
meta[PrefsMetadataKey.DEVICE_MODEL]?.let { model ->
|
||||
meta[PrefsMetadataKeyImpl.DEVICE_MODEL]?.let { model ->
|
||||
if (model.value != config.get().currentDeviceModelString) {
|
||||
model.status = PrefsStatus.WARN
|
||||
model.status = PrefsStatusImpl.WARN
|
||||
model.info = rh.gs(R.string.metadata_warning_different_device)
|
||||
}
|
||||
}
|
||||
|
||||
meta[PrefsMetadataKey.CREATED_AT]?.let { createdAt ->
|
||||
meta[PrefsMetadataKeyImpl.CREATED_AT]?.let { createdAt ->
|
||||
try {
|
||||
val date1 = DateTime.parse(createdAt.value)
|
||||
val date2 = DateTime.now()
|
||||
|
@ -199,26 +199,26 @@ class PrefFileListProviderImpl @Inject constructor(
|
|||
val daysOld = Days.daysBetween(date1.toLocalDate(), date2.toLocalDate()).days
|
||||
|
||||
if (daysOld > IMPORT_AGE_NOT_YET_OLD_DAYS) {
|
||||
createdAt.status = PrefsStatus.WARN
|
||||
createdAt.status = PrefsStatusImpl.WARN
|
||||
createdAt.info = rh.gs(R.string.metadata_warning_old_export, daysOld.toString())
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
createdAt.status = PrefsStatus.WARN
|
||||
createdAt.status = PrefsStatusImpl.WARN
|
||||
createdAt.info = rh.gs(R.string.metadata_warning_date_format)
|
||||
}
|
||||
}
|
||||
|
||||
meta[PrefsMetadataKey.AAPS_VERSION]?.let { version ->
|
||||
meta[PrefsMetadataKeyImpl.AAPS_VERSION]?.let { version ->
|
||||
val currentAppVer = versionCheckerUtils.versionDigits(config.get().VERSION_NAME)
|
||||
val metadataVer = versionCheckerUtils.versionDigits(version.value)
|
||||
|
||||
if ((currentAppVer.size >= 2) && (metadataVer.size >= 2) && (abs(currentAppVer[1] - metadataVer[1]) > 1)) {
|
||||
version.status = PrefsStatus.WARN
|
||||
version.status = PrefsStatusImpl.WARN
|
||||
version.info = rh.gs(R.string.metadata_warning_different_version)
|
||||
}
|
||||
|
||||
if ((currentAppVer.isNotEmpty()) && (metadataVer.isNotEmpty()) && (currentAppVer[0] != metadataVer[0])) {
|
||||
version.status = PrefsStatus.WARN
|
||||
version.status = PrefsStatusImpl.WARN
|
||||
version.info = rh.gs(R.string.metadata_urgent_different_version)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
package info.nightscout.interfaces.maintenance
|
||||
package info.nightscout.configuration.maintenance
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Parcelable
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import info.nightscout.interfaces.R
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import java.io.File
|
||||
import info.nightscout.configuration.R
|
||||
import info.nightscout.interfaces.maintenance.PrefsFormat
|
||||
import info.nightscout.interfaces.maintenance.PrefsMetadataKey
|
||||
|
||||
enum class PrefsMetadataKey(val key: String, @DrawableRes val icon: Int, @StringRes val label: Int) {
|
||||
enum class PrefsMetadataKeyImpl(override val key: String, @DrawableRes override val icon: Int, @StringRes override val label: Int) : PrefsMetadataKey {
|
||||
|
||||
FILE_FORMAT("format", R.drawable.ic_meta_format, R.string.metadata_label_format),
|
||||
CREATED_AT("created_at", R.drawable.ic_meta_date, R.string.metadata_label_created_at),
|
||||
|
@ -35,48 +34,16 @@ enum class PrefsMetadataKey(val key: String, @DrawableRes val icon: Int, @String
|
|||
|
||||
}
|
||||
|
||||
fun formatForDisplay(context: Context, value: String): String {
|
||||
override fun formatForDisplay(context: Context, value: String): String {
|
||||
return when (this) {
|
||||
FILE_FORMAT -> when (value) {
|
||||
PrefsFormat.FORMAT_KEY_ENC -> context.getString(R.string.metadata_format_new)
|
||||
PrefsFormat.FORMAT_KEY_NOENC -> context.getString(R.string.metadata_format_debug)
|
||||
else -> context.getString(R.string.metadata_format_other)
|
||||
}
|
||||
|
||||
CREATED_AT -> value.replace("T", " ").replace("Z", " (UTC)")
|
||||
else -> value
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Parcelize
|
||||
data class PrefMetadata(var value: String, var status: PrefsStatus, var info: String? = null) : Parcelable
|
||||
|
||||
typealias PrefMetadataMap = Map<PrefsMetadataKey, PrefMetadata>
|
||||
|
||||
data class Prefs(val values: Map<String, String>, var metadata: PrefMetadataMap)
|
||||
|
||||
interface PrefsFormat {
|
||||
companion object {
|
||||
|
||||
const val FORMAT_KEY_ENC = "aaps_encrypted"
|
||||
const val FORMAT_KEY_NOENC = "aaps_structured"
|
||||
}
|
||||
|
||||
fun savePreferences(file: File, prefs: Prefs, masterPassword: String? = null)
|
||||
fun loadPreferences(file: File, masterPassword: String? = null): Prefs
|
||||
fun loadMetadata(contents: String? = null): PrefMetadataMap
|
||||
fun isPreferencesFile(file: File, preloadedContents: String? = null): Boolean
|
||||
}
|
||||
|
||||
enum class PrefsStatus(@DrawableRes val icon: Int) {
|
||||
OK(R.drawable.ic_meta_ok),
|
||||
WARN(R.drawable.ic_meta_warning),
|
||||
ERROR(R.drawable.ic_meta_error),
|
||||
UNKNOWN(R.drawable.ic_meta_error),
|
||||
DISABLED(R.drawable.ic_meta_error)
|
||||
}
|
||||
|
||||
class PrefFileNotFoundError(message: String) : Exception(message)
|
||||
class PrefIOError(message: String) : Exception(message)
|
||||
class PrefFormatError(message: String) : Exception(message)
|
|
@ -12,11 +12,11 @@ import info.nightscout.configuration.R
|
|||
import info.nightscout.configuration.databinding.MaintenanceImportListActivityBinding
|
||||
import info.nightscout.configuration.databinding.MaintenanceImportListItemBinding
|
||||
import info.nightscout.configuration.maintenance.PrefsFileContract
|
||||
import info.nightscout.configuration.maintenance.PrefsMetadataKeyImpl
|
||||
import info.nightscout.core.ui.activities.TranslatedDaggerAppCompatActivity
|
||||
import info.nightscout.interfaces.maintenance.PrefFileListProvider
|
||||
import info.nightscout.interfaces.maintenance.PrefsFile
|
||||
import info.nightscout.interfaces.maintenance.PrefsMetadataKey
|
||||
import info.nightscout.interfaces.maintenance.PrefsStatus
|
||||
import info.nightscout.interfaces.maintenance.PrefsStatusImpl
|
||||
import info.nightscout.shared.interfaces.ResourceHelper
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -82,23 +82,23 @@ class PrefImportListActivity : TranslatedDaggerAppCompatActivity() {
|
|||
metaDateTimeIcon.visibility = View.VISIBLE
|
||||
metaAppVersion.visibility = View.VISIBLE
|
||||
|
||||
prefFile.metadata[PrefsMetadataKey.AAPS_FLAVOUR]?.let {
|
||||
prefFile.metadata[PrefsMetadataKeyImpl.AAPS_FLAVOUR]?.let {
|
||||
metaVariantFormat.text = it.value
|
||||
val colorAttr = if (it.status == PrefsStatus.OK) info.nightscout.core.ui.R.attr.metadataTextOkColor else info.nightscout.core.ui.R.attr.metadataTextWarningColor
|
||||
val colorAttr = if (it.status == PrefsStatusImpl.OK) info.nightscout.core.ui.R.attr.metadataTextOkColor else info.nightscout.core.ui.R.attr.metadataTextWarningColor
|
||||
metaVariantFormat.setTextColor(rh.gac(metaVariantFormat.context, colorAttr))
|
||||
}
|
||||
|
||||
prefFile.metadata[PrefsMetadataKey.CREATED_AT]?.let {
|
||||
prefFile.metadata[PrefsMetadataKeyImpl.CREATED_AT]?.let {
|
||||
metaDateTime.text = prefFileListProvider.formatExportedAgo(it.value)
|
||||
}
|
||||
|
||||
prefFile.metadata[PrefsMetadataKey.AAPS_VERSION]?.let {
|
||||
prefFile.metadata[PrefsMetadataKeyImpl.AAPS_VERSION]?.let {
|
||||
metaAppVersion.text = it.value
|
||||
val colorAttr = if (it.status == PrefsStatus.OK) info.nightscout.core.ui.R.attr.metadataTextOkColor else info.nightscout.core.ui.R.attr.metadataTextWarningColor
|
||||
val colorAttr = if (it.status == PrefsStatusImpl.OK) info.nightscout.core.ui.R.attr.metadataTextOkColor else info.nightscout.core.ui.R.attr.metadataTextWarningColor
|
||||
metaAppVersion.setTextColor(rh.gac(metaVariantFormat.context, colorAttr))
|
||||
}
|
||||
|
||||
prefFile.metadata[PrefsMetadataKey.DEVICE_NAME]?.let {
|
||||
prefFile.metadata[PrefsMetadataKeyImpl.DEVICE_NAME]?.let {
|
||||
metaDeviceName.text = it.value
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|||
import info.nightscout.configuration.R
|
||||
import info.nightscout.core.ui.toast.ToastUtils
|
||||
import info.nightscout.interfaces.maintenance.Prefs
|
||||
import info.nightscout.interfaces.maintenance.PrefsStatus
|
||||
import info.nightscout.interfaces.maintenance.PrefsStatusImpl
|
||||
import info.nightscout.shared.extensions.runOnUiThread
|
||||
import java.util.LinkedList
|
||||
|
||||
|
@ -57,8 +57,8 @@ object PrefImportSummaryDialog {
|
|||
(rowLayout.findViewById<View>(R.id.summary_icon) as ImageView).setImageResource(metaKey.icon)
|
||||
(rowLayout.findViewById<View>(R.id.status_icon) as ImageView).setImageResource(metaEntry.status.icon)
|
||||
|
||||
if (metaEntry.status == PrefsStatus.WARN) label.setTextColor(themedCtx.getColor(info.nightscout.interfaces.R.color.metadataTextWarning))
|
||||
else if (metaEntry.status == PrefsStatus.ERROR) label.setTextColor(themedCtx.getColor(info.nightscout.interfaces.R.color.metadataTextError))
|
||||
if (metaEntry.status == PrefsStatusImpl.WARN) label.setTextColor(themedCtx.getColor(info.nightscout.interfaces.R.color.metadataTextWarning))
|
||||
else if (metaEntry.status == PrefsStatusImpl.ERROR) label.setTextColor(themedCtx.getColor(info.nightscout.interfaces.R.color.metadataTextError))
|
||||
|
||||
if (metaEntry.info != null) {
|
||||
details.add("<b>${context.getString(metaKey.label)}</b>: ${metaEntry.value}<br/><i style=\"color:silver\">${metaEntry.info}</i>")
|
||||
|
@ -66,9 +66,9 @@ object PrefImportSummaryDialog {
|
|||
rowLayout.setOnClickListener {
|
||||
val msg = "[${context.getString(metaKey.label)}] ${metaEntry.info}"
|
||||
when (metaEntry.status) {
|
||||
PrefsStatus.WARN -> ToastUtils.Long.warnToast(context, msg)
|
||||
PrefsStatus.ERROR -> ToastUtils.Long.errorToast(context, msg)
|
||||
else -> ToastUtils.Long.infoToast(context, msg)
|
||||
PrefsStatusImpl.WARN -> ToastUtils.Long.warnToast(context, msg)
|
||||
PrefsStatusImpl.ERROR -> ToastUtils.Long.errorToast(context, msg)
|
||||
else -> ToastUtils.Long.infoToast(context, msg)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package info.nightscout.configuration.maintenance.formats
|
||||
|
||||
import info.nightscout.configuration.R
|
||||
import info.nightscout.configuration.maintenance.PrefsMetadataKeyImpl
|
||||
import info.nightscout.core.utils.CryptoUtil
|
||||
import info.nightscout.core.utils.hexStringToByteArray
|
||||
import info.nightscout.core.utils.toHex
|
||||
|
@ -13,6 +14,7 @@ import info.nightscout.interfaces.maintenance.Prefs
|
|||
import info.nightscout.interfaces.maintenance.PrefsFormat
|
||||
import info.nightscout.interfaces.maintenance.PrefsMetadataKey
|
||||
import info.nightscout.interfaces.maintenance.PrefsStatus
|
||||
import info.nightscout.interfaces.maintenance.PrefsStatusImpl
|
||||
import info.nightscout.interfaces.storage.Storage
|
||||
import info.nightscout.shared.interfaces.ResourceHelper
|
||||
import org.json.JSONException
|
||||
|
@ -59,8 +61,8 @@ class EncryptedPrefsFormat @Inject constructor(
|
|||
val content = JSONObject()
|
||||
val meta = JSONObject()
|
||||
|
||||
val encStatus = prefs.metadata[PrefsMetadataKey.ENCRYPTION]?.status ?: PrefsStatus.OK
|
||||
var encrypted = encStatus == PrefsStatus.OK && masterPassword != null
|
||||
val encStatus = prefs.metadata[PrefsMetadataKeyImpl.ENCRYPTION]?.status ?: PrefsStatusImpl.OK
|
||||
var encrypted = encStatus == PrefsStatusImpl.OK && masterPassword != null
|
||||
|
||||
try {
|
||||
for ((key, value) in prefs.values.toSortedMap()) {
|
||||
|
@ -68,14 +70,14 @@ class EncryptedPrefsFormat @Inject constructor(
|
|||
}
|
||||
|
||||
for ((metaKey, metaEntry) in prefs.metadata) {
|
||||
if (metaKey == PrefsMetadataKey.FILE_FORMAT)
|
||||
if (metaKey == PrefsMetadataKeyImpl.FILE_FORMAT)
|
||||
continue
|
||||
if (metaKey == PrefsMetadataKey.ENCRYPTION)
|
||||
if (metaKey == PrefsMetadataKeyImpl.ENCRYPTION)
|
||||
continue
|
||||
meta.put(metaKey.key, metaEntry.value)
|
||||
}
|
||||
|
||||
container.put(PrefsMetadataKey.FILE_FORMAT.key, if (encrypted) PrefsFormat.FORMAT_KEY_ENC else PrefsFormat.FORMAT_KEY_NOENC)
|
||||
container.put(PrefsMetadataKeyImpl.FILE_FORMAT.key, if (encrypted) PrefsFormat.FORMAT_KEY_ENC else PrefsFormat.FORMAT_KEY_NOENC)
|
||||
container.put("metadata", meta)
|
||||
|
||||
val security = JSONObject()
|
||||
|
@ -130,22 +132,22 @@ class EncryptedPrefsFormat @Inject constructor(
|
|||
val container = JSONObject(jsonBody)
|
||||
val metadata: MutableMap<PrefsMetadataKey, PrefMetadata> = loadMetadata(container)
|
||||
|
||||
if (container.has(PrefsMetadataKey.FILE_FORMAT.key) && container.has("security") && container.has("content")) {
|
||||
val fileFormat = container.getString(PrefsMetadataKey.FILE_FORMAT.key)
|
||||
if (container.has(PrefsMetadataKeyImpl.FILE_FORMAT.key) && container.has("security") && container.has("content")) {
|
||||
val fileFormat = container.getString(PrefsMetadataKeyImpl.FILE_FORMAT.key)
|
||||
val security = container.getJSONObject("security")
|
||||
val encrypted = fileFormat == PrefsFormat.FORMAT_KEY_ENC
|
||||
var secure: PrefsStatus = PrefsStatus.OK
|
||||
var secure: PrefsStatus = PrefsStatusImpl.OK
|
||||
var decryptedOk = false
|
||||
var contentJsonObj: JSONObject? = null
|
||||
var insecurityReason = rh.gs(R.string.prefdecrypt_settings_tampered)
|
||||
|
||||
if (security.has("file_hash")) {
|
||||
if (calculatedFileHash != security.getString("file_hash")) {
|
||||
secure = PrefsStatus.ERROR
|
||||
secure = PrefsStatusImpl.ERROR
|
||||
issues.add(rh.gs(R.string.prefdecrypt_issue_modified))
|
||||
}
|
||||
} else {
|
||||
secure = PrefsStatus.ERROR
|
||||
secure = PrefsStatusImpl.ERROR
|
||||
issues.add(rh.gs(R.string.prefdecrypt_issue_missing_file_hash))
|
||||
}
|
||||
|
||||
|
@ -164,38 +166,38 @@ class EncryptedPrefsFormat @Inject constructor(
|
|||
contentJsonObj = JSONObject(decrypted)
|
||||
decryptedOk = true
|
||||
} else {
|
||||
secure = PrefsStatus.ERROR
|
||||
secure = PrefsStatusImpl.ERROR
|
||||
issues.add(rh.gs(R.string.prefdecrypt_issue_modified))
|
||||
}
|
||||
|
||||
} catch (e: JSONException) {
|
||||
secure = PrefsStatus.ERROR
|
||||
secure = PrefsStatusImpl.ERROR
|
||||
issues.add(rh.gs(R.string.prefdecrypt_issue_parsing))
|
||||
}
|
||||
|
||||
} else {
|
||||
secure = PrefsStatus.ERROR
|
||||
secure = PrefsStatusImpl.ERROR
|
||||
issues.add(rh.gs(R.string.prefdecrypt_issue_wrong_pass))
|
||||
insecurityReason = rh.gs(R.string.prefdecrypt_wrong_password)
|
||||
}
|
||||
|
||||
} else {
|
||||
secure = PrefsStatus.ERROR
|
||||
secure = PrefsStatusImpl.ERROR
|
||||
issues.add(rh.gs(R.string.prefdecrypt_issue_wrong_format))
|
||||
}
|
||||
} else {
|
||||
secure = PrefsStatus.ERROR
|
||||
secure = PrefsStatusImpl.ERROR
|
||||
issues.add(rh.gs(R.string.prefdecrypt_issue_wrong_algorithm))
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (secure == PrefsStatus.OK) {
|
||||
secure = PrefsStatus.WARN
|
||||
if (secure == PrefsStatusImpl.OK) {
|
||||
secure = PrefsStatusImpl.WARN
|
||||
}
|
||||
|
||||
if (!(security.has("algorithm") && security.get("algorithm") == "none")) {
|
||||
secure = PrefsStatus.ERROR
|
||||
secure = PrefsStatusImpl.ERROR
|
||||
issues.add(rh.gs(R.string.prefdecrypt_issue_wrong_algorithm))
|
||||
}
|
||||
|
||||
|
@ -211,12 +213,12 @@ class EncryptedPrefsFormat @Inject constructor(
|
|||
|
||||
val issuesStr: String? = if (issues.size > 0) issues.joinToString("\n") else null
|
||||
val encryptionDescStr = if (encrypted) {
|
||||
if (secure == PrefsStatus.OK) rh.gs(R.string.prefdecrypt_settings_secure) else insecurityReason
|
||||
if (secure == PrefsStatusImpl.OK) rh.gs(R.string.prefdecrypt_settings_secure) else insecurityReason
|
||||
} else {
|
||||
if (secure != PrefsStatus.ERROR) rh.gs(R.string.prefdecrypt_settings_unencrypted) else rh.gs(R.string.prefdecrypt_settings_tampered)
|
||||
if (secure != PrefsStatusImpl.ERROR) rh.gs(R.string.prefdecrypt_settings_unencrypted) else rh.gs(R.string.prefdecrypt_settings_tampered)
|
||||
}
|
||||
|
||||
metadata[PrefsMetadataKey.ENCRYPTION] = PrefMetadata(encryptionDescStr, secure, issuesStr)
|
||||
metadata[PrefsMetadataKeyImpl.ENCRYPTION] = PrefMetadata(encryptionDescStr, secure, issuesStr)
|
||||
}
|
||||
|
||||
return Prefs(entries, metadata)
|
||||
|
@ -243,22 +245,22 @@ class EncryptedPrefsFormat @Inject constructor(
|
|||
|
||||
private fun loadMetadata(container: JSONObject): MutableMap<PrefsMetadataKey, PrefMetadata> {
|
||||
val metadata: MutableMap<PrefsMetadataKey, PrefMetadata> = mutableMapOf()
|
||||
if (container.has(PrefsMetadataKey.FILE_FORMAT.key) && container.has("security") && container.has("content") && container.has("metadata")) {
|
||||
val fileFormat = container.getString(PrefsMetadataKey.FILE_FORMAT.key)
|
||||
if (container.has(PrefsMetadataKeyImpl.FILE_FORMAT.key) && container.has("security") && container.has("content") && container.has("metadata")) {
|
||||
val fileFormat = container.getString(PrefsMetadataKeyImpl.FILE_FORMAT.key)
|
||||
if ((fileFormat != PrefsFormat.FORMAT_KEY_ENC) && (fileFormat != PrefsFormat.FORMAT_KEY_NOENC)) {
|
||||
metadata[PrefsMetadataKey.FILE_FORMAT] = PrefMetadata(rh.gs(info.nightscout.interfaces.R.string.metadata_format_other), PrefsStatus.ERROR)
|
||||
metadata[PrefsMetadataKeyImpl.FILE_FORMAT] = PrefMetadata(rh.gs(R.string.metadata_format_other), PrefsStatusImpl.ERROR)
|
||||
} else {
|
||||
val meta = container.getJSONObject("metadata")
|
||||
metadata[PrefsMetadataKey.FILE_FORMAT] = PrefMetadata(fileFormat, PrefsStatus.OK)
|
||||
metadata[PrefsMetadataKeyImpl.FILE_FORMAT] = PrefMetadata(fileFormat, PrefsStatusImpl.OK)
|
||||
for (key in meta.keys()) {
|
||||
val metaKey = PrefsMetadataKey.fromKey(key)
|
||||
val metaKey = PrefsMetadataKeyImpl.fromKey(key)
|
||||
if (metaKey != null) {
|
||||
metadata[metaKey] = PrefMetadata(meta.getString(key), PrefsStatus.OK)
|
||||
metadata[metaKey] = PrefMetadata(meta.getString(key), PrefsStatusImpl.OK)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
metadata[PrefsMetadataKey.FILE_FORMAT] = PrefMetadata(rh.gs(R.string.prefdecrypt_wrong_json), PrefsStatus.ERROR)
|
||||
metadata[PrefsMetadataKeyImpl.FILE_FORMAT] = PrefMetadata(rh.gs(R.string.prefdecrypt_wrong_json), PrefsStatusImpl.ERROR)
|
||||
}
|
||||
|
||||
return metadata
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
package info.nightscout.interfaces.maintenance
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import info.nightscout.configuration.R
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import java.io.File
|
||||
|
||||
typealias PrefMetadataMap = Map<PrefsMetadataKey, PrefMetadata>
|
||||
|
||||
data class Prefs(val values: Map<String, String>, var metadata: PrefMetadataMap)
|
||||
|
||||
interface PrefsFormat {
|
||||
companion object {
|
||||
|
||||
const val FORMAT_KEY_ENC = "aaps_encrypted"
|
||||
const val FORMAT_KEY_NOENC = "aaps_structured"
|
||||
}
|
||||
|
||||
fun savePreferences(file: File, prefs: Prefs, masterPassword: String? = null)
|
||||
fun loadPreferences(file: File, masterPassword: String? = null): Prefs
|
||||
fun loadMetadata(contents: String? = null): PrefMetadataMap
|
||||
fun isPreferencesFile(file: File, preloadedContents: String? = null): Boolean
|
||||
}
|
||||
|
||||
@Parcelize
|
||||
enum class PrefsStatusImpl(@DrawableRes override val icon: Int) : PrefsStatus {
|
||||
|
||||
OK(R.drawable.ic_meta_ok),
|
||||
WARN(R.drawable.ic_meta_warning),
|
||||
ERROR(R.drawable.ic_meta_error),
|
||||
UNKNOWN(R.drawable.ic_meta_error),
|
||||
DISABLED(R.drawable.ic_meta_error)
|
||||
}
|
||||
|
||||
class PrefFileNotFoundError(message: String) : Exception(message)
|
||||
class PrefIOError(message: String) : Exception(message)
|
||||
class PrefFormatError(message: String) : Exception(message)
|
|
@ -170,4 +170,16 @@
|
|||
<!-- 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>
|
||||
|
||||
<!-- Maintenance -->
|
||||
<string name="metadata_label_format">File format</string>
|
||||
<string name="metadata_label_created_at">Created at</string>
|
||||
<string name="metadata_label_aaps_version">AAPS Version</string>
|
||||
<string name="metadata_label_aaps_flavour">Build Variant</string>
|
||||
<string name="metadata_label_device_name">Exporting device patient name</string>
|
||||
<string name="metadata_label_device_model">Exporting device model</string>
|
||||
<string name="metadata_label_encryption">File encryption</string>
|
||||
<string name="metadata_format_new">New encrypted format</string>
|
||||
<string name="metadata_format_debug">New debug format (unencrypted)</string>
|
||||
<string name="metadata_format_other">Unknown export format</string>
|
||||
|
||||
</resources>
|
|
@ -120,7 +120,7 @@ class TreatmentsUserEntryFragment : DaggerFragment(), MenuProvider {
|
|||
_binding = null
|
||||
}
|
||||
|
||||
inner class UserEntryAdapter internal constructor(var entries: List<UserEntry>) : RecyclerView.Adapter<UserEntryAdapter.UserEntryViewHolder>() {
|
||||
inner class UserEntryAdapter internal constructor(private var entries: List<UserEntry>) : RecyclerView.Adapter<UserEntryAdapter.UserEntryViewHolder>() {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserEntryViewHolder {
|
||||
val view: View = LayoutInflater.from(parent.context).inflate(R.layout.treatments_user_entry_item, parent, false)
|
||||
|
|
Loading…
Reference in a new issue