From 4fa61e7f52c2142b79f9588e137d3a27e48cfec8 Mon Sep 17 00:00:00 2001 From: Kelvin Date: Wed, 8 Nov 2023 16:02:52 +0100 Subject: [PATCH] Additional plugin settings capabilities --- .../media/platforms/js/SourcePluginConfig.kt | 5 +- .../views/fields/ButtonField.kt | 5 +- .../views/fields/DropdownField.kt | 31 ++++++- .../futo/platformplayer/views/fields/Field.kt | 6 +- .../platformplayer/views/fields/FieldForm.kt | 83 +++++++++++++++---- .../platformplayer/views/fields/GroupField.kt | 5 +- .../views/fields/ReadOnlyTextField.kt | 5 +- .../views/fields/ToggleField.kt | 28 +++++-- .../platformplayer/views/others/Toggle.kt | 5 +- app/src/main/res/drawable/ic_warning.xml | 9 ++ .../main/res/drawable/ic_warning_yellow.xml | 9 ++ app/src/unstable/assets/sources/youtube | 2 +- 12 files changed, 160 insertions(+), 33 deletions(-) create mode 100644 app/src/main/res/drawable/ic_warning.xml create mode 100644 app/src/main/res/drawable/ic_warning_yellow.xml diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/SourcePluginConfig.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/SourcePluginConfig.kt index 6320e983..2d39a2a5 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/SourcePluginConfig.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/SourcePluginConfig.kt @@ -144,7 +144,10 @@ class SourcePluginConfig( val description: String, val type: String, val default: String? = null, - val variable: String? = null + val variable: String? = null, + val dependency: String? = null, + val warningDialog: String? = null, + val options: List? = null ) { @kotlinx.serialization.Transient val variableOrName: String get() = variable ?: name; diff --git a/app/src/main/java/com/futo/platformplayer/views/fields/ButtonField.kt b/app/src/main/java/com/futo/platformplayer/views/fields/ButtonField.kt index 6e093fed..280bac4f 100644 --- a/app/src/main/java/com/futo/platformplayer/views/fields/ButtonField.kt +++ b/app/src/main/java/com/futo/platformplayer/views/fields/ButtonField.kt @@ -8,6 +8,7 @@ import androidx.core.view.updateLayoutParams import androidx.lifecycle.lifecycleScope import com.futo.platformplayer.R import com.futo.platformplayer.constructs.Event2 +import com.futo.platformplayer.constructs.Event3 import com.futo.platformplayer.dp import com.futo.platformplayer.views.buttons.BigButton import java.lang.reflect.Field @@ -37,7 +38,7 @@ class ButtonField : BigButton, IField { //private val _title : TextView; //private val _subtitle : TextView; - override val onChanged = Event2(); + override val onChanged = Event3(); constructor(context : Context, attrs : AttributeSet? = null) : super(context, attrs){ //inflate(context, R.layout.field_button, this); @@ -59,6 +60,8 @@ class ButtonField : BigButton, IField { } } + override fun setValue(value: Any) {} + fun fromMethod(obj : Any, method: Method) : ButtonField { this._method = method; this._obj = obj; diff --git a/app/src/main/java/com/futo/platformplayer/views/fields/DropdownField.kt b/app/src/main/java/com/futo/platformplayer/views/fields/DropdownField.kt index c1118f2f..96a97e22 100644 --- a/app/src/main/java/com/futo/platformplayer/views/fields/DropdownField.kt +++ b/app/src/main/java/com/futo/platformplayer/views/fields/DropdownField.kt @@ -6,6 +6,8 @@ import android.view.View import android.widget.* import com.futo.platformplayer.R import com.futo.platformplayer.constructs.Event2 +import com.futo.platformplayer.constructs.Event3 +import com.futo.platformplayer.logging.Logger import java.lang.reflect.Field class DropdownField : TableRow, IField { @@ -35,7 +37,7 @@ class DropdownField : TableRow, IField { override var reference: Any? = null; - override val onChanged = Event2(); + override val onChanged = Event3(); constructor(context: Context, attrs: AttributeSet? = null) : super(context, attrs){ inflate(context, R.layout.field_dropdown, this); @@ -50,13 +52,21 @@ class DropdownField : TableRow, IField { _isInitFire = false; return; } + Logger.i("DropdownField", "Changed: ${_selected} -> ${pos}"); + val old = _selected; _selected = pos; - onChanged.emit(this@DropdownField, pos); + onChanged.emit(this@DropdownField, pos, old); } override fun onNothingSelected(parent: AdapterView<*>?) = Unit }; } + override fun setValue(value: Any) { + if(value is Int) { + _spinner.setSelection(value); + } + } + fun asBoolean(name: String, description: String?, obj: Boolean) : DropdownField { _options = resources.getStringArray(R.array.enabled_disabled_array); _spinner.adapter = ArrayAdapter(context, R.layout.spinner_item_simple, _options).also { @@ -77,6 +87,23 @@ class DropdownField : TableRow, IField { return this; } + fun withValue(title: String, description: String?, options: List, value: Int): DropdownField { + _title.text = title; + _description.visibility = if(description.isNullOrEmpty()) View.GONE else View.VISIBLE; + _description.text = description ?: ""; + + _options = options.toTypedArray(); + _spinner.adapter = ArrayAdapter(context, R.layout.spinner_item_simple, _options).also { + it.setDropDownViewResource(R.layout.spinner_dropdownitem_simple); + }; + + _selected = value; + _spinner.isSelected = false; + _spinner.setSelection(_selected, true); + + return this; + } + override fun fromField(obj: Any, field: Field, formField: FormField?) : DropdownField { this._field = field; this._obj = obj; diff --git a/app/src/main/java/com/futo/platformplayer/views/fields/Field.kt b/app/src/main/java/com/futo/platformplayer/views/fields/Field.kt index 0376ccb1..eab6ce05 100644 --- a/app/src/main/java/com/futo/platformplayer/views/fields/Field.kt +++ b/app/src/main/java/com/futo/platformplayer/views/fields/Field.kt @@ -1,6 +1,7 @@ package com.futo.platformplayer.views.fields import com.futo.platformplayer.constructs.Event2 +import com.futo.platformplayer.constructs.Event3 import java.lang.reflect.Field @@ -13,11 +14,12 @@ interface IField { val obj : Any?; val field : Field?; - val onChanged : Event2; + val onChanged : Event3; var reference: Any?; - fun fromField(obj : Any, field : Field, formField: FormField? = null) : IField; fun setField(); + + fun setValue(value: Any); } \ No newline at end of file diff --git a/app/src/main/java/com/futo/platformplayer/views/fields/FieldForm.kt b/app/src/main/java/com/futo/platformplayer/views/fields/FieldForm.kt index 8b8e7d18..cbfbb8a6 100644 --- a/app/src/main/java/com/futo/platformplayer/views/fields/FieldForm.kt +++ b/app/src/main/java/com/futo/platformplayer/views/fields/FieldForm.kt @@ -5,6 +5,7 @@ import android.util.AttributeSet import android.view.View import android.widget.LinearLayout import com.futo.platformplayer.R +import com.futo.platformplayer.UIDialogs import com.futo.platformplayer.api.media.platforms.js.SourcePluginConfig import com.futo.platformplayer.constructs.Event2 import com.futo.platformplayer.logging.Logger @@ -49,7 +50,7 @@ class FieldForm : LinearLayout { throw java.lang.IllegalStateException("Only views can be IFields"); _root.addView(field as View); - field.onChanged.subscribe { a1, a2 -> + field.onChanged.subscribe { a1, a2, oldValue -> onChanged.emit(a1, a2); }; } @@ -67,7 +68,7 @@ class FieldForm : LinearLayout { throw java.lang.IllegalStateException("Only views can be IFields"); _root.addView(field as View); - field.onChanged.subscribe { a1, a2 -> + field.onChanged.subscribe { a1, a2, oldValue -> onChanged.emit(a1, a2); }; } @@ -82,25 +83,59 @@ class FieldForm : LinearLayout { if(groupTitle == null) { for(field in newFields) { - if(field !is View) + if(field.second !is View) throw java.lang.IllegalStateException("Only views can be IFields"); - field.onChanged.subscribe { field, value -> - onChanged.emit(field, value); - } + finalizePluginSettingField(field.first, field.second, newFields); _root.addView(field as View); } - _fields = newFields; + _fields = newFields.map { it.second }; } else { for(field in newFields) { - field.onChanged.subscribe { field, value -> - onChanged.emit(field, value); - } + finalizePluginSettingField(field.first, field.second, newFields); } val group = GroupField(context, groupTitle, groupDescription) - .withFields(newFields); + .withFields(newFields.map { it.second }); _root.addView(group as View); } } + private fun finalizePluginSettingField(setting: SourcePluginConfig.Setting, field: IField, others: List>) { + field.onChanged.subscribe { field, value, oldValue -> + onChanged.emit(field, value); + + setting.warningDialog?.let { + if(it.isNotBlank() && isValueTrue(value)) + UIDialogs.showDialog(context, R.drawable.ic_warning_yellow, setting.warningDialog, null, null, 0, + UIDialogs.Action("Cancel", { + field.setValue(oldValue); + }, UIDialogs.ActionStyle.NONE), + UIDialogs.Action("Ok", { + + }, UIDialogs.ActionStyle.PRIMARY)); + } + } + if(setting.dependency != null) { + val dependentField = others.firstOrNull { it.first.variableOrName == setting.dependency }; + if(dependentField == null || dependentField.second !is View) + (field as View).visibility = View.GONE; + else { + dependentField.second.onChanged.subscribe { dependentField, value, oldValue -> + val isValid = isValueTrue(value); + if(isValid) + (field as View).visibility = View.VISIBLE; + else + (field as View).visibility = View.GONE; + } + } + } + } + private fun isValueTrue(value: Any): Boolean { + return when(value) { + is Int -> value > 0; + is Boolean -> value; + is String -> value.toIntOrNull()?.let { it > 0 } ?: false || value.lowercase() == "true"; + else -> false + }; + } fun setObjectValues(){ val fields = _fields; @@ -133,26 +168,42 @@ class FieldForm : LinearLayout { private val _json = Json {}; - fun getFieldsFromPluginSettings(context: Context, settings: List, values: HashMap): List { - val fields = mutableListOf() + fun getFieldsFromPluginSettings(context: Context, settings: List, values: HashMap): List> { + val fields = mutableListOf>() for(setting in settings) { + val value = if(values.containsKey(setting.variableOrName)) values[setting.variableOrName] else setting.default; + val field = when(setting.type.lowercase()) { + "header" -> { + val groupField = GroupField(context, setting.name, setting.description); + groupField; + } "boolean" -> { - val value = if(values.containsKey(setting.variableOrName)) values[setting.variableOrName] else setting.default; val field = ToggleField(context).withValue(setting.name, setting.description, value == "true" || value == "1" || value == "True"); - field.onChanged.subscribe { field, value -> + field.onChanged.subscribe { field, value, oldValue -> values[setting.variableOrName] = _json.encodeToString (value == 1 || value == true); } field; } + "dropdown" -> { + if(setting.options != null && !setting.options.isEmpty()) { + var selected = value?.toIntOrNull()?.coerceAtLeast(0) ?: 0; + val field = DropdownField(context).withValue(setting.name, setting.description, setting.options, selected); + field.onChanged.subscribe { field, value, oldValue -> + values[setting.variableOrName] = value.toString(); + } + field; + } + else null; + } else -> null; } if(field != null) - fields.add(field); + fields.add(Pair(setting, field)); } return fields; } diff --git a/app/src/main/java/com/futo/platformplayer/views/fields/GroupField.kt b/app/src/main/java/com/futo/platformplayer/views/fields/GroupField.kt index a963da7d..f9c01320 100644 --- a/app/src/main/java/com/futo/platformplayer/views/fields/GroupField.kt +++ b/app/src/main/java/com/futo/platformplayer/views/fields/GroupField.kt @@ -7,6 +7,7 @@ import android.widget.LinearLayout import android.widget.TextView import com.futo.platformplayer.R import com.futo.platformplayer.constructs.Event2 +import com.futo.platformplayer.constructs.Event3 import java.lang.reflect.Field class GroupField : LinearLayout, IField { @@ -27,7 +28,7 @@ class GroupField : LinearLayout, IField { return _field; }; - override val onChanged = Event2(); + override val onChanged = Event3(); private val _title : TextView; private val _subtitle : TextView; @@ -138,4 +139,6 @@ class GroupField : LinearLayout, IField { field.setField(); } } + + override fun setValue(value: Any) {} } \ No newline at end of file diff --git a/app/src/main/java/com/futo/platformplayer/views/fields/ReadOnlyTextField.kt b/app/src/main/java/com/futo/platformplayer/views/fields/ReadOnlyTextField.kt index d5187a78..749ded72 100644 --- a/app/src/main/java/com/futo/platformplayer/views/fields/ReadOnlyTextField.kt +++ b/app/src/main/java/com/futo/platformplayer/views/fields/ReadOnlyTextField.kt @@ -5,6 +5,7 @@ import android.util.AttributeSet import android.widget.* import com.futo.platformplayer.R import com.futo.platformplayer.constructs.Event2 +import com.futo.platformplayer.constructs.Event3 import java.lang.reflect.Field import java.lang.reflect.Method @@ -27,7 +28,7 @@ class ReadOnlyTextField : TableRow, IField { private val _title : TextView; private val _value : TextView; - override val onChanged = Event2(); + override val onChanged = Event3(); override var reference: Any? = null; constructor(context : Context, attrs : AttributeSet? = null) : super(context, attrs){ @@ -36,6 +37,8 @@ class ReadOnlyTextField : TableRow, IField { _value = findViewById(R.id.field_value); } + override fun setValue(value: Any) {} + override fun fromField(obj : Any, field : Field, formField: FormField?) : ReadOnlyTextField { this._field = field; this._obj = obj; diff --git a/app/src/main/java/com/futo/platformplayer/views/fields/ToggleField.kt b/app/src/main/java/com/futo/platformplayer/views/fields/ToggleField.kt index 6f16bed1..78f219d0 100644 --- a/app/src/main/java/com/futo/platformplayer/views/fields/ToggleField.kt +++ b/app/src/main/java/com/futo/platformplayer/views/fields/ToggleField.kt @@ -6,6 +6,8 @@ import android.view.View import android.widget.* import com.futo.platformplayer.R import com.futo.platformplayer.constructs.Event2 +import com.futo.platformplayer.constructs.Event3 +import com.futo.platformplayer.logging.Logger import com.futo.platformplayer.views.others.Toggle import java.lang.reflect.Field @@ -28,10 +30,11 @@ class ToggleField : TableRow, IField { private val _title : TextView; private val _description : TextView; private val _toggle : Toggle; + private var _lastValue: Boolean = false; override var reference: Any? = null; - override val onChanged = Event2(); + override val onChanged = Event3(); constructor(context : Context, attrs : AttributeSet? = null) : super(context, attrs){ inflate(context, R.layout.field_toggle, this); @@ -40,10 +43,18 @@ class ToggleField : TableRow, IField { _description = findViewById(R.id.field_description); _toggle.onValueChanged.subscribe { - onChanged.emit(this, it); + val lastVal = _lastValue; + Logger.i("ToggleField", "Changed: ${lastVal} -> ${it}"); + _lastValue = it; + onChanged.emit(this, it, lastVal); }; } + override fun setValue(value: Any) { + if(value is Boolean) + _toggle.setValue(value, true, true); + } + fun withValue(title: String, description: String?, value: Boolean): ToggleField { _title.text = title; @@ -54,6 +65,7 @@ class ToggleField : TableRow, IField { _description.visibility = View.GONE; _toggle.setValue(value, true); + _lastValue = value; return this; } @@ -78,14 +90,16 @@ class ToggleField : TableRow, IField { } val value = field.get(obj); - if(value is Boolean) - _toggle.setValue(value, true); + val toggleValue = if(value is Boolean) + value; else if(value is Number) - _toggle.setValue((value as Number).toInt() > 0, true); + (value as Number).toInt() > 0; else if(value == null) - _toggle.setValue(false, true); + false; else - _toggle.setValue(false, true); + false; + _toggle.setValue(toggleValue, true); + _lastValue = toggleValue; return this; } diff --git a/app/src/main/java/com/futo/platformplayer/views/others/Toggle.kt b/app/src/main/java/com/futo/platformplayer/views/others/Toggle.kt index 844b58de..0bc0374c 100644 --- a/app/src/main/java/com/futo/platformplayer/views/others/Toggle.kt +++ b/app/src/main/java/com/futo/platformplayer/views/others/Toggle.kt @@ -29,7 +29,7 @@ class Toggle : AppCompatImageView { scaleType = ScaleType.FIT_CENTER; } - fun setValue(v: Boolean, animated: Boolean = true) { + fun setValue(v: Boolean, animated: Boolean = true, withEvent: Boolean = false) { if (value == v) { return; } @@ -44,5 +44,8 @@ class Toggle : AppCompatImageView { } else { setImageResource(if (v) R.drawable.toggle_enabled else R.drawable.toggle_disabled); } + + if(withEvent) + onValueChanged.emit(value); } } \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_warning.xml b/app/src/main/res/drawable/ic_warning.xml new file mode 100644 index 00000000..710d2177 --- /dev/null +++ b/app/src/main/res/drawable/ic_warning.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_warning_yellow.xml b/app/src/main/res/drawable/ic_warning_yellow.xml new file mode 100644 index 00000000..dde6ab5c --- /dev/null +++ b/app/src/main/res/drawable/ic_warning_yellow.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/unstable/assets/sources/youtube b/app/src/unstable/assets/sources/youtube index 51c249e9..6f9a13c7 160000 --- a/app/src/unstable/assets/sources/youtube +++ b/app/src/unstable/assets/sources/youtube @@ -1 +1 @@ -Subproject commit 51c249e9f49a880b8451121d396a60ff73ce5600 +Subproject commit 6f9a13c7ea1cb51a4548dbe7f25dc5113b02eb48