mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-05-29 13:00:21 +02:00
Settings search, Fix nested video events, Adding setting descriptions for metered
This commit is contained in:
parent
eb3dd854d4
commit
12b2552185
@ -307,29 +307,29 @@ class Settings : FragmentedStorageFileJson() {
|
|||||||
else -> 1.0f;
|
else -> 1.0f;
|
||||||
};
|
};
|
||||||
|
|
||||||
@FormField(R.string.preferred_quality, FieldForm.DROPDOWN, -1, 2)
|
@FormField(R.string.preferred_quality, FieldForm.DROPDOWN, R.string.preferred_quality_description, 2)
|
||||||
@DropdownFieldOptionsId(R.array.preferred_quality_array)
|
@DropdownFieldOptionsId(R.array.preferred_quality_array)
|
||||||
var preferredQuality: Int = 0;
|
var preferredQuality: Int = 0;
|
||||||
|
|
||||||
@FormField(R.string.preferred_metered_quality, FieldForm.DROPDOWN, -1, 2)
|
@FormField(R.string.preferred_metered_quality, FieldForm.DROPDOWN, R.string.preferred_metered_quality_description, 3)
|
||||||
@DropdownFieldOptionsId(R.array.preferred_quality_array)
|
@DropdownFieldOptionsId(R.array.preferred_quality_array)
|
||||||
var preferredMeteredQuality: Int = 0;
|
var preferredMeteredQuality: Int = 0;
|
||||||
fun getPreferredQualityPixelCount(): Int = preferedQualityToPixels(preferredQuality);
|
fun getPreferredQualityPixelCount(): Int = preferedQualityToPixels(preferredQuality);
|
||||||
fun getPreferredMeteredQualityPixelCount(): Int = preferedQualityToPixels(preferredMeteredQuality);
|
fun getPreferredMeteredQualityPixelCount(): Int = preferedQualityToPixels(preferredMeteredQuality);
|
||||||
fun getCurrentPreferredQualityPixelCount(): Int = if(!StateApp.instance.isCurrentMetered()) getPreferredQualityPixelCount() else getPreferredMeteredQualityPixelCount();
|
fun getCurrentPreferredQualityPixelCount(): Int = if(!StateApp.instance.isCurrentMetered()) getPreferredQualityPixelCount() else getPreferredMeteredQualityPixelCount();
|
||||||
|
|
||||||
@FormField(R.string.preferred_preview_quality, FieldForm.DROPDOWN, -1, 3)
|
@FormField(R.string.preferred_preview_quality, FieldForm.DROPDOWN, R.string.preferred_preview_quality_description, 4)
|
||||||
@DropdownFieldOptionsId(R.array.preferred_quality_array)
|
@DropdownFieldOptionsId(R.array.preferred_quality_array)
|
||||||
var preferredPreviewQuality: Int = 5;
|
var preferredPreviewQuality: Int = 5;
|
||||||
fun getPreferredPreviewQualityPixelCount(): Int = preferedQualityToPixels(preferredPreviewQuality);
|
fun getPreferredPreviewQualityPixelCount(): Int = preferedQualityToPixels(preferredPreviewQuality);
|
||||||
|
|
||||||
@FormField(R.string.auto_rotate, FieldForm.DROPDOWN, -1, 4)
|
@FormField(R.string.auto_rotate, FieldForm.DROPDOWN, -1, 5)
|
||||||
@DropdownFieldOptionsId(R.array.system_enabled_disabled_array)
|
@DropdownFieldOptionsId(R.array.system_enabled_disabled_array)
|
||||||
var autoRotate: Int = 2;
|
var autoRotate: Int = 2;
|
||||||
|
|
||||||
fun isAutoRotate() = autoRotate == 1 || (autoRotate == 2 && StateApp.instance.getCurrentSystemAutoRotate());
|
fun isAutoRotate() = autoRotate == 1 || (autoRotate == 2 && StateApp.instance.getCurrentSystemAutoRotate());
|
||||||
|
|
||||||
@FormField(R.string.auto_rotate_dead_zone, FieldForm.DROPDOWN, R.string.this_prevents_the_device_from_rotating_within_the_given_amount_of_degrees, 5)
|
@FormField(R.string.auto_rotate_dead_zone, FieldForm.DROPDOWN, R.string.this_prevents_the_device_from_rotating_within_the_given_amount_of_degrees, 6)
|
||||||
@DropdownFieldOptionsId(R.array.auto_rotate_dead_zone)
|
@DropdownFieldOptionsId(R.array.auto_rotate_dead_zone)
|
||||||
var autoRotateDeadZone: Int = 0;
|
var autoRotateDeadZone: Int = 0;
|
||||||
|
|
||||||
@ -337,7 +337,7 @@ class Settings : FragmentedStorageFileJson() {
|
|||||||
return autoRotateDeadZone * 5;
|
return autoRotateDeadZone * 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
@FormField(R.string.background_behavior, FieldForm.DROPDOWN, -1, 6)
|
@FormField(R.string.background_behavior, FieldForm.DROPDOWN, -1, 7)
|
||||||
@DropdownFieldOptionsId(R.array.player_background_behavior)
|
@DropdownFieldOptionsId(R.array.player_background_behavior)
|
||||||
var backgroundPlay: Int = 2;
|
var backgroundPlay: Int = 2;
|
||||||
|
|
||||||
|
@ -69,9 +69,11 @@ class SettingsActivity : AppCompatActivity(), IWithResultLauncher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun reloadSettings() {
|
fun reloadSettings() {
|
||||||
|
_form.setSearchVisible(false);
|
||||||
_loader.start();
|
_loader.start();
|
||||||
_form.fromObject(lifecycleScope, Settings.instance) {
|
_form.fromObject(lifecycleScope, Settings.instance) {
|
||||||
_loader.stop();
|
_loader.stop();
|
||||||
|
_form.setSearchVisible(true);
|
||||||
|
|
||||||
var devCounter = 0;
|
var devCounter = 0;
|
||||||
_form.findField("code")?.assume<ReadOnlyTextField>()?.setOnClickListener {
|
_form.findField("code")?.assume<ReadOnlyTextField>()?.setOnClickListener {
|
||||||
|
@ -5,10 +5,12 @@ import android.view.View
|
|||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import com.futo.platformplayer.R
|
import com.futo.platformplayer.R
|
||||||
|
import com.futo.platformplayer.UIDialogs
|
||||||
import com.futo.platformplayer.api.media.models.contents.ContentType
|
import com.futo.platformplayer.api.media.models.contents.ContentType
|
||||||
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
|
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
|
||||||
import com.futo.platformplayer.api.media.models.contents.IPlatformContentDetails
|
import com.futo.platformplayer.api.media.models.contents.IPlatformContentDetails
|
||||||
import com.futo.platformplayer.api.media.models.nested.IPlatformNestedContent
|
import com.futo.platformplayer.api.media.models.nested.IPlatformNestedContent
|
||||||
|
import com.futo.platformplayer.api.media.models.video.IPlatformVideo
|
||||||
import com.futo.platformplayer.api.media.models.video.IPlatformVideoDetails
|
import com.futo.platformplayer.api.media.models.video.IPlatformVideoDetails
|
||||||
import com.futo.platformplayer.constructs.Event2
|
import com.futo.platformplayer.constructs.Event2
|
||||||
import com.futo.platformplayer.images.GlideHelper.Companion.loadThumbnails
|
import com.futo.platformplayer.images.GlideHelper.Companion.loadThumbnails
|
||||||
@ -17,6 +19,7 @@ import com.futo.platformplayer.states.StateApp
|
|||||||
import com.futo.platformplayer.states.StatePlatform
|
import com.futo.platformplayer.states.StatePlatform
|
||||||
import com.futo.platformplayer.video.PlayerManager
|
import com.futo.platformplayer.video.PlayerManager
|
||||||
import com.futo.platformplayer.views.FeedStyle
|
import com.futo.platformplayer.views.FeedStyle
|
||||||
|
import com.futo.platformplayer.views.Loader
|
||||||
import com.futo.platformplayer.views.platform.PlatformIndicator
|
import com.futo.platformplayer.views.platform.PlatformIndicator
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -25,6 +28,7 @@ class PreviewNestedVideoView : PreviewVideoView {
|
|||||||
|
|
||||||
protected val _platformIndicatorNested: PlatformIndicator;
|
protected val _platformIndicatorNested: PlatformIndicator;
|
||||||
protected val _containerLoader: LinearLayout;
|
protected val _containerLoader: LinearLayout;
|
||||||
|
protected val _loader: Loader;
|
||||||
protected val _containerUnavailable: LinearLayout;
|
protected val _containerUnavailable: LinearLayout;
|
||||||
protected val _textNestedUrl: TextView;
|
protected val _textNestedUrl: TextView;
|
||||||
|
|
||||||
@ -38,8 +42,39 @@ class PreviewNestedVideoView : PreviewVideoView {
|
|||||||
constructor(context: Context, feedStyle: FeedStyle, exoPlayer: PlayerManager? = null): super(context, feedStyle, exoPlayer) {
|
constructor(context: Context, feedStyle: FeedStyle, exoPlayer: PlayerManager? = null): super(context, feedStyle, exoPlayer) {
|
||||||
_platformIndicatorNested = findViewById(R.id.thumbnail_platform_nested);
|
_platformIndicatorNested = findViewById(R.id.thumbnail_platform_nested);
|
||||||
_containerLoader = findViewById(R.id.container_loader);
|
_containerLoader = findViewById(R.id.container_loader);
|
||||||
|
_loader = findViewById(R.id.loader);
|
||||||
_containerUnavailable = findViewById(R.id.container_unavailable);
|
_containerUnavailable = findViewById(R.id.container_unavailable);
|
||||||
_textNestedUrl = findViewById(R.id.text_nested_url);
|
_textNestedUrl = findViewById(R.id.text_nested_url);
|
||||||
|
|
||||||
|
_imageChannel?.setOnClickListener { _contentNested?.let { onChannelClicked.emit(it.author) } };
|
||||||
|
_textChannelName.setOnClickListener { _contentNested?.let { onChannelClicked.emit(it.author) } };
|
||||||
|
_textVideoMetadata.setOnClickListener { _contentNested?.let { onChannelClicked.emit(it.author) } };
|
||||||
|
_button_add_to.setOnClickListener {
|
||||||
|
if(_contentNested is IPlatformVideo)
|
||||||
|
_contentNested?.let { onAddToClicked.emit(it as IPlatformVideo) }
|
||||||
|
else _content?.let {
|
||||||
|
if(it is IPlatformNestedContent)
|
||||||
|
loadNested(it) {
|
||||||
|
if(it is IPlatformVideo)
|
||||||
|
onAddToClicked.emit(it);
|
||||||
|
else
|
||||||
|
UIDialogs.toast(context, "Content is not a video");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
_button_add_to_queue.setOnClickListener {
|
||||||
|
if(_contentNested is IPlatformVideo)
|
||||||
|
_contentNested?.let { onAddToQueueClicked.emit(it as IPlatformVideo) }
|
||||||
|
else _content?.let {
|
||||||
|
if(it is IPlatformNestedContent)
|
||||||
|
loadNested(it) {
|
||||||
|
if(it is IPlatformVideo)
|
||||||
|
onAddToQueueClicked.emit(it);
|
||||||
|
else
|
||||||
|
UIDialogs.toast(context, "Content is not a video");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun inflate(feedStyle: FeedStyle) {
|
override fun inflate(feedStyle: FeedStyle) {
|
||||||
@ -81,6 +116,7 @@ class PreviewNestedVideoView : PreviewVideoView {
|
|||||||
if(!_contentSupported) {
|
if(!_contentSupported) {
|
||||||
_containerUnavailable.visibility = View.VISIBLE;
|
_containerUnavailable.visibility = View.VISIBLE;
|
||||||
_containerLoader.visibility = View.GONE;
|
_containerLoader.visibility = View.GONE;
|
||||||
|
_loader.stop();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if(_feedStyle == FeedStyle.THUMBNAIL)
|
if(_feedStyle == FeedStyle.THUMBNAIL)
|
||||||
@ -96,12 +132,14 @@ class PreviewNestedVideoView : PreviewVideoView {
|
|||||||
_contentSupported = false;
|
_contentSupported = false;
|
||||||
_containerUnavailable.visibility = View.VISIBLE;
|
_containerUnavailable.visibility = View.VISIBLE;
|
||||||
_containerLoader.visibility = View.GONE;
|
_containerLoader.visibility = View.GONE;
|
||||||
|
_loader.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadNested(content: IPlatformNestedContent) {
|
private fun loadNested(content: IPlatformNestedContent, onCompleted: ((IPlatformContentDetails)->Unit)? = null) {
|
||||||
Logger.i(TAG, "Loading nested content [${content.contentUrl}]");
|
Logger.i(TAG, "Loading nested content [${content.contentUrl}]");
|
||||||
_containerLoader.visibility = View.VISIBLE;
|
_containerLoader.visibility = View.VISIBLE;
|
||||||
|
_loader.start();
|
||||||
StateApp.instance.scopeOrNull?.launch(Dispatchers.IO) {
|
StateApp.instance.scopeOrNull?.launch(Dispatchers.IO) {
|
||||||
val def = StatePlatform.instance.getContentDetails(content.contentUrl);
|
val def = StatePlatform.instance.getContentDetails(content.contentUrl);
|
||||||
def.invokeOnCompletion {
|
def.invokeOnCompletion {
|
||||||
@ -112,11 +150,13 @@ class PreviewNestedVideoView : PreviewVideoView {
|
|||||||
if(_content == content) {
|
if(_content == content) {
|
||||||
_containerUnavailable.visibility = View.VISIBLE;
|
_containerUnavailable.visibility = View.VISIBLE;
|
||||||
_containerLoader.visibility = View.GONE;
|
_containerLoader.visibility = View.GONE;
|
||||||
|
_loader.stop();
|
||||||
}
|
}
|
||||||
//TODO: Handle exception
|
//TODO: Handle exception
|
||||||
}
|
}
|
||||||
else if(_content == content) {
|
else if(_content == content) {
|
||||||
_containerLoader.visibility = View.GONE;
|
_containerLoader.visibility = View.GONE;
|
||||||
|
_loader.stop();
|
||||||
val nestedContent = def.getCompleted();
|
val nestedContent = def.getCompleted();
|
||||||
_contentNested = nestedContent;
|
_contentNested = nestedContent;
|
||||||
if(nestedContent is IPlatformVideoDetails) {
|
if(nestedContent is IPlatformVideoDetails) {
|
||||||
@ -131,6 +171,8 @@ class PreviewNestedVideoView : PreviewVideoView {
|
|||||||
else {
|
else {
|
||||||
_containerUnavailable.visibility = View.VISIBLE;
|
_containerUnavailable.visibility = View.VISIBLE;
|
||||||
}
|
}
|
||||||
|
if(onCompleted != null)
|
||||||
|
onCompleted(nestedContent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -19,6 +19,9 @@ open class BigButton : LinearLayout {
|
|||||||
private val _textPrimary: TextView;
|
private val _textPrimary: TextView;
|
||||||
private val _textSecondary: TextView;
|
private val _textSecondary: TextView;
|
||||||
|
|
||||||
|
val title: String get() = _textPrimary.text.toString();
|
||||||
|
val description: String get() = _textSecondary.text.toString();
|
||||||
|
|
||||||
val onClick = Event0();
|
val onClick = Event0();
|
||||||
|
|
||||||
constructor(context : Context, text: String, subText: String, icon: Int, action: ()->Unit) : super(context) {
|
constructor(context : Context, text: String, subText: String, icon: Int, action: ()->Unit) : super(context) {
|
||||||
|
@ -28,6 +28,10 @@ class ButtonField : BigButton, IField {
|
|||||||
|
|
||||||
override val value: Any? = null;
|
override val value: Any? = null;
|
||||||
|
|
||||||
|
override val searchContent: String?
|
||||||
|
get() = "$title $description";
|
||||||
|
|
||||||
|
|
||||||
override val obj : Any? get() {
|
override val obj : Any? get() {
|
||||||
if(this._obj == null)
|
if(this._obj == null)
|
||||||
throw java.lang.IllegalStateException("Can only be called if fromField is used");
|
throw java.lang.IllegalStateException("Can only be called if fromField is used");
|
||||||
|
@ -41,6 +41,9 @@ class DropdownField : TableRow, IField {
|
|||||||
|
|
||||||
override val value: Any? get() = _selected;
|
override val value: Any? get() = _selected;
|
||||||
|
|
||||||
|
override val searchContent: String?
|
||||||
|
get() = "${_title.text} ${_description.text}";
|
||||||
|
|
||||||
constructor(context: Context, attrs: AttributeSet? = null) : super(context, attrs){
|
constructor(context: Context, attrs: AttributeSet? = null) : super(context, attrs){
|
||||||
inflate(context, R.layout.field_dropdown, this);
|
inflate(context, R.layout.field_dropdown, this);
|
||||||
_spinner = findViewById(R.id.field_spinner);
|
_spinner = findViewById(R.id.field_spinner);
|
||||||
|
@ -23,6 +23,8 @@ interface IField {
|
|||||||
|
|
||||||
var reference: Any?;
|
var reference: Any?;
|
||||||
|
|
||||||
|
val searchContent: String?;
|
||||||
|
|
||||||
fun fromField(obj : Any, field : Field, formField: FormField? = null) : IField;
|
fun fromField(obj : Any, field : Field, formField: FormField? = null) : IField;
|
||||||
fun setField();
|
fun setField();
|
||||||
|
|
||||||
|
@ -3,12 +3,14 @@ package com.futo.platformplayer.views.fields
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.widget.EditText
|
||||||
|
import android.widget.FrameLayout
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
|
import androidx.core.widget.addTextChangedListener
|
||||||
import com.futo.platformplayer.R
|
import com.futo.platformplayer.R
|
||||||
import com.futo.platformplayer.UIDialogs
|
import com.futo.platformplayer.UIDialogs
|
||||||
import com.futo.platformplayer.api.media.platforms.js.SourcePluginConfig
|
import com.futo.platformplayer.api.media.platforms.js.SourcePluginConfig
|
||||||
import com.futo.platformplayer.constructs.Event2
|
import com.futo.platformplayer.constructs.Event2
|
||||||
import com.futo.platformplayer.logging.Logger
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -24,11 +26,12 @@ import kotlin.reflect.full.hasAnnotation
|
|||||||
import kotlin.reflect.jvm.javaField
|
import kotlin.reflect.jvm.javaField
|
||||||
import kotlin.reflect.jvm.javaMethod
|
import kotlin.reflect.jvm.javaMethod
|
||||||
import kotlin.streams.asStream
|
import kotlin.streams.asStream
|
||||||
import kotlin.streams.toList
|
|
||||||
|
|
||||||
class FieldForm : LinearLayout {
|
class FieldForm : LinearLayout {
|
||||||
|
|
||||||
private val _root : LinearLayout;
|
private val _containerSearch: FrameLayout;
|
||||||
|
private val _editSearch: EditText;
|
||||||
|
private val _fieldsContainer : LinearLayout;
|
||||||
|
|
||||||
val onChanged = Event2<IField, Any>();
|
val onChanged = Event2<IField, Any>();
|
||||||
|
|
||||||
@ -36,11 +39,45 @@ class FieldForm : LinearLayout {
|
|||||||
|
|
||||||
constructor(context : Context, attrs : AttributeSet? = null) : super(context, attrs) {
|
constructor(context : Context, attrs : AttributeSet? = null) : super(context, attrs) {
|
||||||
inflate(context, R.layout.field_form, this);
|
inflate(context, R.layout.field_form, this);
|
||||||
_root = findViewById(R.id.field_form_root);
|
_containerSearch = findViewById(R.id.container_search);
|
||||||
|
_editSearch = findViewById(R.id.edit_search);
|
||||||
|
_fieldsContainer = findViewById(R.id.field_form_container);
|
||||||
|
|
||||||
|
_editSearch.addTextChangedListener {
|
||||||
|
updateSettingsVisibility();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateSettingsVisibility(group: GroupField? = null) {
|
||||||
|
val settings = group?.getFields() ?: _fields;
|
||||||
|
|
||||||
|
val query = _editSearch.text.toString().lowercase();
|
||||||
|
|
||||||
|
var groupVisible = false;
|
||||||
|
val isGroupMatch = query.isEmpty() || group?.searchContent?.lowercase()?.contains(query) == true;
|
||||||
|
for(field in settings) {
|
||||||
|
if(field is GroupField)
|
||||||
|
updateSettingsVisibility(field);
|
||||||
|
else if(field is View && field.descriptor != null) {
|
||||||
|
val txt = field.searchContent?.lowercase();
|
||||||
|
if(txt != null) {
|
||||||
|
val visible = isGroupMatch || txt.contains(query);
|
||||||
|
field.visibility = if (visible) View.VISIBLE else View.GONE;
|
||||||
|
groupVisible = groupVisible || visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(group != null)
|
||||||
|
group.visibility = if(groupVisible) View.VISIBLE else View.GONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setSearchVisible(visible: Boolean) {
|
||||||
|
_containerSearch.visibility = if(visible) View.VISIBLE else View.GONE;
|
||||||
|
_editSearch.setText("");
|
||||||
}
|
}
|
||||||
|
|
||||||
fun fromObject(scope: CoroutineScope, obj : Any, onLoaded: (()->Unit)? = null) {
|
fun fromObject(scope: CoroutineScope, obj : Any, onLoaded: (()->Unit)? = null) {
|
||||||
_root.removeAllViews();
|
_fieldsContainer.removeAllViews();
|
||||||
|
|
||||||
scope.launch(Dispatchers.Default) {
|
scope.launch(Dispatchers.Default) {
|
||||||
val newFields = getFieldsFromObject(context, obj);
|
val newFields = getFieldsFromObject(context, obj);
|
||||||
@ -50,7 +87,7 @@ class FieldForm : LinearLayout {
|
|||||||
if (field !is View)
|
if (field !is View)
|
||||||
throw java.lang.IllegalStateException("Only views can be IFields");
|
throw java.lang.IllegalStateException("Only views can be IFields");
|
||||||
|
|
||||||
_root.addView(field as View);
|
_fieldsContainer.addView(field as View);
|
||||||
field.onChanged.subscribe { a1, a2, oldValue ->
|
field.onChanged.subscribe { a1, a2, oldValue ->
|
||||||
onChanged.emit(a1, a2);
|
onChanged.emit(a1, a2);
|
||||||
};
|
};
|
||||||
@ -62,13 +99,13 @@ class FieldForm : LinearLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fun fromObject(obj : Any) {
|
fun fromObject(obj : Any) {
|
||||||
_root.removeAllViews();
|
_fieldsContainer.removeAllViews();
|
||||||
val newFields = getFieldsFromObject(context, obj);
|
val newFields = getFieldsFromObject(context, obj);
|
||||||
for(field in newFields) {
|
for(field in newFields) {
|
||||||
if(field !is View)
|
if(field !is View)
|
||||||
throw java.lang.IllegalStateException("Only views can be IFields");
|
throw java.lang.IllegalStateException("Only views can be IFields");
|
||||||
|
|
||||||
_root.addView(field as View);
|
_fieldsContainer.addView(field as View);
|
||||||
field.onChanged.subscribe { a1, a2, oldValue ->
|
field.onChanged.subscribe { a1, a2, oldValue ->
|
||||||
onChanged.emit(a1, a2);
|
onChanged.emit(a1, a2);
|
||||||
};
|
};
|
||||||
@ -76,7 +113,7 @@ class FieldForm : LinearLayout {
|
|||||||
_fields = newFields;
|
_fields = newFields;
|
||||||
}
|
}
|
||||||
fun fromPluginSettings(settings: List<SourcePluginConfig.Setting>, values: HashMap<String, String?>, groupTitle: String? = null, groupDescription: String? = null) {
|
fun fromPluginSettings(settings: List<SourcePluginConfig.Setting>, values: HashMap<String, String?>, groupTitle: String? = null, groupDescription: String? = null) {
|
||||||
_root.removeAllViews();
|
_fieldsContainer.removeAllViews();
|
||||||
val newFields = getFieldsFromPluginSettings(context, settings, values);
|
val newFields = getFieldsFromPluginSettings(context, settings, values);
|
||||||
if (newFields.isEmpty()) {
|
if (newFields.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
@ -87,7 +124,7 @@ class FieldForm : LinearLayout {
|
|||||||
if(field.second !is View)
|
if(field.second !is View)
|
||||||
throw java.lang.IllegalStateException("Only views can be IFields");
|
throw java.lang.IllegalStateException("Only views can be IFields");
|
||||||
finalizePluginSettingField(field.first, field.second, newFields);
|
finalizePluginSettingField(field.first, field.second, newFields);
|
||||||
_root.addView(field as View);
|
_fieldsContainer.addView(field as View);
|
||||||
}
|
}
|
||||||
_fields = newFields.map { it.second };
|
_fields = newFields.map { it.second };
|
||||||
} else {
|
} else {
|
||||||
@ -96,7 +133,7 @@ class FieldForm : LinearLayout {
|
|||||||
}
|
}
|
||||||
val group = GroupField(context, groupTitle, groupDescription)
|
val group = GroupField(context, groupTitle, groupDescription)
|
||||||
.withFields(newFields.map { it.second });
|
.withFields(newFields.map { it.second });
|
||||||
_root.addView(group as View);
|
_fieldsContainer.addView(group as View);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private fun finalizePluginSettingField(setting: SourcePluginConfig.Setting, field: IField, others: List<Pair<SourcePluginConfig.Setting, IField>>) {
|
private fun finalizePluginSettingField(setting: SourcePluginConfig.Setting, field: IField, others: List<Pair<SourcePluginConfig.Setting, IField>>) {
|
||||||
@ -210,7 +247,6 @@ class FieldForm : LinearLayout {
|
|||||||
.asStream()
|
.asStream()
|
||||||
.filter { it.hasAnnotation<FormField>() && it.javaField != null }
|
.filter { it.hasAnnotation<FormField>() && it.javaField != null }
|
||||||
.map { Pair<KProperty<*>, FormField>(it, it.findAnnotation()!!) }
|
.map { Pair<KProperty<*>, FormField>(it, it.findAnnotation()!!) }
|
||||||
.toList()
|
|
||||||
|
|
||||||
//TODO: Rewrite fields to properties so no map is required
|
//TODO: Rewrite fields to properties so no map is required
|
||||||
val propertyMap = mutableMapOf<Field, KProperty<*>>();
|
val propertyMap = mutableMapOf<Field, KProperty<*>>();
|
||||||
@ -252,7 +288,6 @@ class FieldForm : LinearLayout {
|
|||||||
.asStream()
|
.asStream()
|
||||||
.filter { it.hasAnnotation<FormField>() && it.javaField == null && it.getter.javaMethod != null}
|
.filter { it.hasAnnotation<FormField>() && it.javaField == null && it.getter.javaMethod != null}
|
||||||
.map { Pair<Method, FormField>(it.getter.javaMethod!!, it.findAnnotation()!!) }
|
.map { Pair<Method, FormField>(it.getter.javaMethod!!, it.findAnnotation()!!) }
|
||||||
.toList();
|
|
||||||
|
|
||||||
for(prop in objProps) {
|
for(prop in objProps) {
|
||||||
prop.first.isAccessible = true;
|
prop.first.isAccessible = true;
|
||||||
@ -270,7 +305,6 @@ class FieldForm : LinearLayout {
|
|||||||
.asStream()
|
.asStream()
|
||||||
.filter { it.getAnnotation(FormField::class.java) != null && !it.name.startsWith("get") && !it.name.startsWith("set") }
|
.filter { it.getAnnotation(FormField::class.java) != null && !it.name.startsWith("get") && !it.name.startsWith("set") }
|
||||||
.map { Pair<Method, FormField>(it, it.getAnnotation(FormField::class.java)) }
|
.map { Pair<Method, FormField>(it, it.getAnnotation(FormField::class.java)) }
|
||||||
.toList();
|
|
||||||
|
|
||||||
for(meth in objMethods) {
|
for(meth in objMethods) {
|
||||||
meth.first.isAccessible = true;
|
meth.first.isAccessible = true;
|
||||||
|
@ -39,6 +39,8 @@ class GroupField : LinearLayout, IField {
|
|||||||
|
|
||||||
override val value: Any? = null;
|
override val value: Any? = null;
|
||||||
|
|
||||||
|
override val searchContent: String? get() = "${_title.text} ${_subtitle.text}";
|
||||||
|
|
||||||
constructor(context : Context, attrs : AttributeSet? = null) : super(context, attrs) {
|
constructor(context : Context, attrs : AttributeSet? = null) : super(context, attrs) {
|
||||||
inflate(context, R.layout.field_group, this);
|
inflate(context, R.layout.field_group, this);
|
||||||
_title = findViewById(R.id.field_group_title);
|
_title = findViewById(R.id.field_group_title);
|
||||||
@ -142,6 +144,9 @@ class GroupField : LinearLayout, IField {
|
|||||||
field.setField();
|
field.setField();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fun getFields(): List<IField> {
|
||||||
|
return _fields;
|
||||||
|
}
|
||||||
|
|
||||||
override fun setValue(value: Any) {}
|
override fun setValue(value: Any) {}
|
||||||
}
|
}
|
@ -34,6 +34,9 @@ class ReadOnlyTextField : TableRow, IField {
|
|||||||
|
|
||||||
override val value: Any? = null;
|
override val value: Any? = null;
|
||||||
|
|
||||||
|
override val searchContent: String?
|
||||||
|
get() = "${_title.text}";
|
||||||
|
|
||||||
constructor(context : Context, attrs : AttributeSet? = null) : super(context, attrs){
|
constructor(context : Context, attrs : AttributeSet? = null) : super(context, attrs){
|
||||||
inflate(context, R.layout.field_readonly_text, this);
|
inflate(context, R.layout.field_readonly_text, this);
|
||||||
_title = findViewById(R.id.field_title);
|
_title = findViewById(R.id.field_title);
|
||||||
|
@ -38,6 +38,9 @@ class ToggleField : TableRow, IField {
|
|||||||
|
|
||||||
override val value: Any get() = _lastValue;
|
override val value: Any get() = _lastValue;
|
||||||
|
|
||||||
|
override val searchContent: String?
|
||||||
|
get() = "${_title.text} ${_description.text}";
|
||||||
|
|
||||||
constructor(context : Context, attrs : AttributeSet? = null) : super(context, attrs){
|
constructor(context : Context, attrs : AttributeSet? = null) : super(context, attrs){
|
||||||
inflate(context, R.layout.field_toggle, this);
|
inflate(context, R.layout.field_toggle, this);
|
||||||
_toggle = findViewById(R.id.field_toggle);
|
_toggle = findViewById(R.id.field_toggle);
|
||||||
|
@ -2,8 +2,44 @@
|
|||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:id="@+id/field_form_root">
|
android:id="@+id/field_form_root">
|
||||||
|
|
||||||
|
<!--Search Text-->
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/container_search"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:layout_margin="10dp">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/edit_search"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="text"
|
||||||
|
android:imeOptions="actionDone"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:hint="Search"
|
||||||
|
android:paddingEnd="46dp" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/button_clear_search"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:paddingStart="18dp"
|
||||||
|
android:paddingEnd="18dp"
|
||||||
|
android:layout_gravity="right|center_vertical"
|
||||||
|
android:visibility="invisible"
|
||||||
|
android:src="@drawable/ic_clear_16dp" />
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/field_form_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="vertical">
|
||||||
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
@ -125,7 +125,13 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="#BB000000"
|
android:background="#BB000000"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
android:orientation="vertical" />
|
android:gravity="center"
|
||||||
|
android:orientation="vertical">
|
||||||
|
<com.futo.platformplayer.views.Loader
|
||||||
|
android:id="@+id/loader"
|
||||||
|
android:layout_width="50dp"
|
||||||
|
android:layout_height="50dp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/container_unavailable"
|
android:id="@+id/container_unavailable"
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
<string name="defaults">Defaults</string>
|
<string name="defaults">Defaults</string>
|
||||||
<string name="home_screen">Home Screen</string>
|
<string name="home_screen">Home Screen</string>
|
||||||
<string name="preferred_quality">Preferred Quality</string>
|
<string name="preferred_quality">Preferred Quality</string>
|
||||||
|
<string name="preferred_quality_description">Default quality for watching a video</string>
|
||||||
<string name="update">Update</string>
|
<string name="update">Update</string>
|
||||||
<string name="close">Close</string>
|
<string name="close">Close</string>
|
||||||
<string name="never">Never</string>
|
<string name="never">Never</string>
|
||||||
@ -358,8 +359,11 @@
|
|||||||
<string name="player">Player</string>
|
<string name="player">Player</string>
|
||||||
<string name="plugins">Plugins</string>
|
<string name="plugins">Plugins</string>
|
||||||
<string name="preferred_casting_quality">Preferred Casting Quality</string>
|
<string name="preferred_casting_quality">Preferred Casting Quality</string>
|
||||||
|
<string name="preferred_casting_quality_description">Default quality while casting to an external device</string>
|
||||||
<string name="preferred_metered_quality">Preferred Metered Quality</string>
|
<string name="preferred_metered_quality">Preferred Metered Quality</string>
|
||||||
|
<string name="preferred_metered_quality_description">Default quality while on metered connections such as cellular</string>
|
||||||
<string name="preferred_preview_quality">Preferred Preview Quality</string>
|
<string name="preferred_preview_quality">Preferred Preview Quality</string>
|
||||||
|
<string name="preferred_preview_quality_description">Default quality while previewing a video in a feed</string>
|
||||||
<string name="primary_language">Primary Language</string>
|
<string name="primary_language">Primary Language</string>
|
||||||
<string name="default_comment_section">Default Comment Section</string>
|
<string name="default_comment_section">Default Comment Section</string>
|
||||||
<string name="reinstall_embedded_plugins">Reinstall Embedded Plugins</string>
|
<string name="reinstall_embedded_plugins">Reinstall Embedded Plugins</string>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user