diff --git a/app/src/main/java/com/futo/platformplayer/Utility.kt b/app/src/main/java/com/futo/platformplayer/Utility.kt index 64efb992..5cd5d26f 100644 --- a/app/src/main/java/com/futo/platformplayer/Utility.kt +++ b/app/src/main/java/com/futo/platformplayer/Utility.kt @@ -27,14 +27,18 @@ import com.futo.platformplayer.logging.Logger import com.futo.platformplayer.models.PlatformVideoWithTime import com.futo.platformplayer.others.PlatformLinkMovementMethod import java.io.ByteArrayInputStream +import java.io.ByteArrayOutputStream import java.io.File import java.io.IOException import java.io.InputStream import java.io.OutputStream import java.nio.ByteBuffer import java.nio.ByteOrder +import java.time.OffsetDateTime import java.util.* import java.util.concurrent.ThreadLocalRandom +import java.util.zip.GZIPInputStream +import java.util.zip.GZIPOutputStream private val _allowedCharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz "; fun getRandomString(sizeOfRandomString: Int): String { @@ -279,3 +283,34 @@ fun ByteBuffer.toUtf8String(): String { get(remainingBytes) return String(remainingBytes, Charsets.UTF_8) } + + +fun ByteArray.toGzip(): ByteArray { + if (this == null || this.isEmpty()) return ByteArray(0) + + val gzipTimeStart = OffsetDateTime.now(); + + val outputStream = ByteArrayOutputStream() + GZIPOutputStream(outputStream).use { gzip -> + gzip.write(this) + } + val result = outputStream.toByteArray(); + Logger.i("Utility", "Gzip compression time: ${gzipTimeStart.getNowDiffMiliseconds()}ms"); + return result; +} + +fun ByteArray.fromGzip(): ByteArray { + if (this == null || this.isEmpty()) return ByteArray(0) + + val inputStream = ByteArrayInputStream(this) + val outputStream = ByteArrayOutputStream() + + GZIPInputStream(inputStream).use { gzip -> + val buffer = ByteArray(1024) + var bytesRead: Int + while (gzip.read(buffer).also { bytesRead = it } != -1) { + outputStream.write(buffer, 0, bytesRead) + } + } + return outputStream.toByteArray() +} \ No newline at end of file diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/HomeFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/HomeFragment.kt index a450a2ed..988d7a3f 100644 --- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/HomeFragment.kt +++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/HomeFragment.kt @@ -250,39 +250,53 @@ class HomeFragment : MainFragment() { layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); } - fragment._togglePluginsDisabled.clear(); + synchronized(_filterLock) { - val buttonsPlugins = (if (_togglesConfig.contains("plugins")) + var buttonsPlugins: List = listOf() + buttonsPlugins = (if (_togglesConfig.contains("plugins")) (StatePlatform.instance.getEnabledClients() .filter { it is JSClient && it.enableInHome } .map { plugin -> - ToggleBar.Toggle(if(Settings.instance.home.showHomeFiltersPluginNames) plugin.name else "", plugin.icon, !fragment._togglePluginsDisabled.contains(plugin.id), { - if (it) { + ToggleBar.Toggle(if(Settings.instance.home.showHomeFiltersPluginNames) plugin.name else "", plugin.icon, !fragment._togglePluginsDisabled.contains(plugin.id), { view, active -> + var dontSwap = false; + if (active) { if (fragment._togglePluginsDisabled.contains(plugin.id)) fragment._togglePluginsDisabled.remove(plugin.id); } else { - if (!fragment._togglePluginsDisabled.contains(plugin.id)) - fragment._togglePluginsDisabled.add(plugin.id); + if (!fragment._togglePluginsDisabled.contains(plugin.id)) { + val enabledClients = StatePlatform.instance.getEnabledClients(); + val availableAfterDisable = enabledClients.count { !fragment._togglePluginsDisabled.contains(it.id) && it.id != plugin.id }; + if(availableAfterDisable > 0) + fragment._togglePluginsDisabled.add(plugin.id); + else { + UIDialogs.appToast("Home needs atleast 1 plugin active"); + dontSwap = true; + } + } + } + if(!dontSwap) + reloadForFilters(); + else { + view.setToggle(!active); } - reloadForFilters(); }).withTag("plugins") }) else listOf()) val buttons = (listOf( (if (_togglesConfig.contains("today")) - ToggleBar.Toggle("Today", fragment._toggleRecent) { - fragment._toggleRecent = it; reloadForFilters() + ToggleBar.Toggle("Today", fragment._toggleRecent) { view, active -> + fragment._toggleRecent = active; reloadForFilters() } .withTag("today") else null), (if (_togglesConfig.contains("watched")) - ToggleBar.Toggle("Unwatched", fragment._toggleWatched) { - fragment._toggleWatched = it; reloadForFilters() + ToggleBar.Toggle("Unwatched", fragment._toggleWatched) { view, active -> + fragment._toggleWatched = active; reloadForFilters() } .withTag("watched") else null), ).filterNotNull() + buttonsPlugins) .sortedBy { _togglesConfig.indexOf(it.tag ?: "") } ?: listOf() - val buttonSettings = ToggleBar.Toggle("", R.drawable.ic_settings, true, { + val buttonSettings = ToggleBar.Toggle("", R.drawable.ic_settings, true, { view, active -> showOrderOverlay(_overlayContainer, "Visible home filters", listOf( diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/SubscriptionsFeedFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/SubscriptionsFeedFragment.kt index b4f51b14..83e39a88 100644 --- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/SubscriptionsFeedFragment.kt +++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/SubscriptionsFeedFragment.kt @@ -18,6 +18,7 @@ import com.futo.platformplayer.constructs.TaskHandler import com.futo.platformplayer.engine.exceptions.PluginException import com.futo.platformplayer.exceptions.ChannelException import com.futo.platformplayer.exceptions.RateLimitException +import com.futo.platformplayer.fragment.mainactivity.main.SubscriptionsFeedFragment.SubscriptionsFeedView.FeedFilterSettings import com.futo.platformplayer.logging.Logger import com.futo.platformplayer.models.SearchType import com.futo.platformplayer.models.SubscriptionGroup @@ -56,6 +57,9 @@ class SubscriptionsFeedFragment : MainFragment() { private var _group: SubscriptionGroup? = null; private var _cachedRecyclerData: FeedView.RecyclerData, GridLayoutManager, IPager, IPlatformContent, IPlatformContent, InsertedViewHolder>? = null; + private val _filterLock = Object(); + private val _filterSettings = FragmentedStorage.get("subFeedFilter"); + override fun onShownWithView(parameter: Any?, isBack: Boolean) { super.onShownWithView(parameter, isBack); _view?.onShown(); @@ -184,8 +188,6 @@ class SubscriptionsFeedFragment : MainFragment() { return Json.encodeToString(this); } } - private val _filterLock = Object(); - private val _filterSettings = FragmentedStorage.get("subFeedFilter"); private var _bypassRateLimit = false; private val _lastExceptions: List? = null; @@ -284,13 +286,18 @@ class SubscriptionsFeedFragment : MainFragment() { fragment.navigate(g); }; - synchronized(_filterLock) { + synchronized(fragment._filterLock) { _subscriptionBar?.setToggles( - SubscriptionBar.Toggle(context.getString(R.string.videos), _filterSettings.allowContentTypes.contains(ContentType.MEDIA)) { toggleFilterContentTypes(listOf(ContentType.MEDIA, ContentType.NESTED_VIDEO), it); }, - SubscriptionBar.Toggle(context.getString(R.string.posts), _filterSettings.allowContentTypes.contains(ContentType.POST)) { toggleFilterContentType(ContentType.POST, it); }, - SubscriptionBar.Toggle(context.getString(R.string.live), _filterSettings.allowLive) { _filterSettings.allowLive = it; _filterSettings.save(); loadResults(false); }, - SubscriptionBar.Toggle(context.getString(R.string.planned), _filterSettings.allowPlanned) { _filterSettings.allowPlanned = it; _filterSettings.save(); loadResults(false); }, - SubscriptionBar.Toggle(context.getString(R.string.watched), _filterSettings.allowWatched) { _filterSettings.allowWatched = it; _filterSettings.save(); loadResults(false); } + SubscriptionBar.Toggle(context.getString(R.string.videos), fragment._filterSettings.allowContentTypes.contains(ContentType.MEDIA)) { view, active -> + toggleFilterContentTypes(listOf(ContentType.MEDIA, ContentType.NESTED_VIDEO), active); }, + SubscriptionBar.Toggle(context.getString(R.string.posts), fragment._filterSettings.allowContentTypes.contains(ContentType.POST)) { view, active -> + toggleFilterContentType(ContentType.POST, active); }, + SubscriptionBar.Toggle(context.getString(R.string.live), fragment._filterSettings.allowLive) { view, active -> + fragment._filterSettings.allowLive = active; fragment._filterSettings.save(); loadResults(false); }, + SubscriptionBar.Toggle(context.getString(R.string.planned), fragment._filterSettings.allowPlanned) { view, active -> + fragment._filterSettings.allowPlanned = active; fragment._filterSettings.save(); loadResults(false); }, + SubscriptionBar.Toggle(context.getString(R.string.watched), fragment._filterSettings.allowWatched) { view, active -> + fragment._filterSettings.allowWatched = active; fragment._filterSettings.save(); loadResults(false); } ); } @@ -301,13 +308,13 @@ class SubscriptionsFeedFragment : MainFragment() { toggleFilterContentType(contentType, isTrue); } private fun toggleFilterContentType(contentType: ContentType, isTrue: Boolean) { - synchronized(_filterLock) { + synchronized(fragment._filterLock) { if(!isTrue) { - _filterSettings.allowContentTypes.remove(contentType); - } else if(!_filterSettings.allowContentTypes.contains(contentType)) { - _filterSettings.allowContentTypes.add(contentType) + fragment._filterSettings.allowContentTypes.remove(contentType); + } else if(!fragment._filterSettings.allowContentTypes.contains(contentType)) { + fragment._filterSettings.allowContentTypes.add(contentType) } - _filterSettings.save(); + fragment._filterSettings.save(); }; if(Settings.instance.subscriptions.fetchOnTabOpen) { //TODO: Do this different, temporary workaround loadResults(false); @@ -320,9 +327,9 @@ class SubscriptionsFeedFragment : MainFragment() { val nowSoon = OffsetDateTime.now().plusMinutes(5); val filterGroup = subGroup; return results.filter { - val allowedContentType = _filterSettings.allowContentTypes.contains(if(it.contentType == ContentType.NESTED_VIDEO || it.contentType == ContentType.LOCKED) ContentType.MEDIA else it.contentType); + val allowedContentType = fragment._filterSettings.allowContentTypes.contains(if(it.contentType == ContentType.NESTED_VIDEO || it.contentType == ContentType.LOCKED) ContentType.MEDIA else it.contentType); - if(it is IPlatformVideo && it.duration > 0 && !_filterSettings.allowWatched && StateHistory.instance.isHistoryWatched(it.url, it.duration)) + if(it is IPlatformVideo && it.duration > 0 && !fragment._filterSettings.allowWatched && StateHistory.instance.isHistoryWatched(it.url, it.duration)) return@filter false; //TODO: Check against a sub cache @@ -331,11 +338,11 @@ class SubscriptionsFeedFragment : MainFragment() { if(it.datetime?.isAfter(nowSoon) == true) { - if(!_filterSettings.allowPlanned) + if(!fragment._filterSettings.allowPlanned) return@filter false; } - if(_filterSettings.allowLive) { //If allowLive, always show live + if(fragment._filterSettings.allowLive) { //If allowLive, always show live if(it is IPlatformVideo && it.isLive) return@filter true; } diff --git a/app/src/main/java/com/futo/platformplayer/subscription/SubscriptionsTaskFetchAlgorithm.kt b/app/src/main/java/com/futo/platformplayer/subscription/SubscriptionsTaskFetchAlgorithm.kt index 1a1d503b..b72e840c 100644 --- a/app/src/main/java/com/futo/platformplayer/subscription/SubscriptionsTaskFetchAlgorithm.kt +++ b/app/src/main/java/com/futo/platformplayer/subscription/SubscriptionsTaskFetchAlgorithm.kt @@ -15,12 +15,14 @@ import com.futo.platformplayer.api.media.structures.EmptyPager import com.futo.platformplayer.api.media.structures.IPager import com.futo.platformplayer.api.media.structures.MultiChronoContentPager import com.futo.platformplayer.api.media.structures.PlatformContentPager +import com.futo.platformplayer.debug.Stopwatch import com.futo.platformplayer.engine.exceptions.PluginException import com.futo.platformplayer.engine.exceptions.ScriptCaptchaRequiredException import com.futo.platformplayer.engine.exceptions.ScriptCriticalException import com.futo.platformplayer.exceptions.ChannelException import com.futo.platformplayer.findNonRuntimeException import com.futo.platformplayer.fragment.mainactivity.main.SubscriptionsFeedFragment +import com.futo.platformplayer.getNowDiffMiliseconds import com.futo.platformplayer.logging.Logger import com.futo.platformplayer.models.Subscription import com.futo.platformplayer.states.StateApp @@ -32,6 +34,8 @@ import com.futo.platformplayer.subsexchange.ChannelRequest import com.futo.platformplayer.subsexchange.ChannelResolve import com.futo.platformplayer.subsexchange.ExchangeContract import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch import java.time.OffsetDateTime import java.util.concurrent.ExecutionException import java.util.concurrent.ForkJoinPool @@ -149,42 +153,56 @@ abstract class SubscriptionsTaskFetchAlgorithm( //Resolve Subscription Exchange if(contract != null) { - try { - resolveTime = measureTimeMillis { - val resolves = taskResults.filter { it.pager != null && (it.task.type == ResultCapabilities.TYPE_MIXED || it.task.type == ResultCapabilities.TYPE_VIDEOS) && contract!!.required.contains(it.task.url) }.map { - ChannelResolve( - it.task.url, - it.pager!!.getResults().filter { it is IPlatformVideo }.map { SerializedPlatformVideo.fromVideo(it as IPlatformVideo) } - ) - }.toTypedArray() - val resolve = subsExchangeClient?.resolveContract( - contract!!, - *resolves - ); - if (resolve != null) { - resolveCount = resolves.size; - UIDialogs.appToast("SubsExchange (Res: ${resolves.size}, Prov: ${resolve.size}") - for(result in resolve){ - val task = providedTasks?.find { it.url == result.channelUrl }; - if(task != null) { - taskResults.add(SubscriptionTaskResult(task, PlatformContentPager(result.content, result.content.size), null)); - providedTasks?.remove(task); + fun resolve() { + try { + resolveTime = measureTimeMillis { + val resolves = taskResults.filter { it.pager != null && (it.task.type == ResultCapabilities.TYPE_MIXED || it.task.type == ResultCapabilities.TYPE_VIDEOS) && contract!!.required.contains(it.task.url) }.map { + ChannelResolve( + it.task.url, + it.pager!!.getResults().filter { it is IPlatformVideo }.map { SerializedPlatformVideo.fromVideo(it as IPlatformVideo) } + ) + }.toTypedArray() + + val resolveRequestStart = OffsetDateTime.now(); + + val resolve = subsExchangeClient?.resolveContract( + contract!!, + *resolves + ); + + Logger.i(TAG, "Subscription Exchange contract resolved request in ${resolveRequestStart.getNowDiffMiliseconds()}ms"); + + if (resolve != null) { + resolveCount = resolves.size; + UIDialogs.appToast("SubsExchange (Res: ${resolves.size}, Prov: ${resolve.size}") + for(result in resolve){ + val task = providedTasks?.find { it.url == result.channelUrl }; + if(task != null) { + taskResults.add(SubscriptionTaskResult(task, PlatformContentPager(result.content, result.content.size), null)); + providedTasks?.remove(task); + } + } + } + if (providedTasks != null) { + for(task in providedTasks!!) { + taskResults.add(SubscriptionTaskResult(task, null, IllegalStateException("No data received from exchange"))); } } } - if (providedTasks != null) { - for(task in providedTasks!!) { - taskResults.add(SubscriptionTaskResult(task, null, IllegalStateException("No data received from exchange"))); - } - } - } - Logger.i(TAG, "Subscription Exchange contract resolved in ${resolveTime}ms"); + Logger.i(TAG, "Subscription Exchange contract resolved in ${resolveTime}ms"); + } + catch(ex: Throwable) { + //TODO: fetch remainder after all? + Logger.e(TAG, "Failed to resolve Subscription Exchange contract due to: " + ex.message, ex); + } } - catch(ex: Throwable) { - //TODO: fetch remainder after all? - Logger.e(TAG, "Failed to resolve Subscription Exchange contract due to: " + ex.message, ex); - } + if(providedTasks?.size ?: 0 == 0) + scope.launch(Dispatchers.IO) { + resolve(); + } + else + resolve(); } } diff --git a/app/src/main/java/com/futo/platformplayer/subsexchange/SubsExchangeClient.kt b/app/src/main/java/com/futo/platformplayer/subsexchange/SubsExchangeClient.kt index 6f38014d..b0357f56 100644 --- a/app/src/main/java/com/futo/platformplayer/subsexchange/SubsExchangeClient.kt +++ b/app/src/main/java/com/futo/platformplayer/subsexchange/SubsExchangeClient.kt @@ -1,10 +1,14 @@ import com.futo.platformplayer.api.media.Serializer +import com.futo.platformplayer.getNowDiffMiliseconds import com.futo.platformplayer.logging.Logger +import com.futo.platformplayer.subscription.SubscriptionFetchAlgorithm.Companion.TAG import com.futo.platformplayer.subsexchange.ChannelRequest import com.futo.platformplayer.subsexchange.ChannelResolve import com.futo.platformplayer.subsexchange.ChannelResult import com.futo.platformplayer.subsexchange.ExchangeContract import com.futo.platformplayer.subsexchange.ExchangeContractResolve +import com.futo.platformplayer.toGzip +import com.futo.platformplayer.toHumanBytesSize import kotlinx.serialization.* import kotlinx.serialization.json.* import kotlinx.coroutines.Dispatchers @@ -26,6 +30,7 @@ import java.nio.charset.StandardCharsets import java.security.KeyPairGenerator import java.security.spec.PKCS8EncodedKeySpec import java.security.spec.RSAPublicKeySpec +import java.time.OffsetDateTime class SubsExchangeClient(private val server: String, private val privateKey: String, private val contractTimeout: Int = 1000) { @@ -40,24 +45,27 @@ class SubsExchangeClient(private val server: String, private val privateKey: Str // Endpoint: Contract fun requestContract(vararg channels: ChannelRequest): ExchangeContract { - val data = post("/api/Channel/Contract", Json.encodeToString(channels), "application/json", contractTimeout) + val data = post("/api/Channel/Contract", Json.encodeToString(channels).toByteArray(Charsets.UTF_8), "application/json", contractTimeout) return Json.decodeFromString(data) } suspend fun requestContractAsync(vararg channels: ChannelRequest): ExchangeContract { - val data = postAsync("/api/Channel/Contract", Json.encodeToString(channels), "application/json") + val data = postAsync("/api/Channel/Contract", Json.encodeToString(channels).toByteArray(Charsets.UTF_8), "application/json") return Json.decodeFromString(data) } // Endpoint: Resolve fun resolveContract(contract: ExchangeContract, vararg resolves: ChannelResolve): Array { val contractResolve = convertResolves(*resolves) - val result = post("/api/Channel/Resolve?contractId=${contract.id}", Serializer.json.encodeToString(contractResolve), "application/json") - Logger.v("SubsExchangeClient", "Resolve:" + result); + val contractResolveJson = Serializer.json.encodeToString(contractResolve); + val contractResolveTimeStart = OffsetDateTime.now(); + val result = post("/api/Channel/Resolve?contractId=${contract.id}", contractResolveJson.toByteArray(Charsets.UTF_8), "application/json", 0, true) + val contractResolveTime = contractResolveTimeStart.getNowDiffMiliseconds(); + Logger.v("SubsExchangeClient", "Subscription Exchange Resolve Request [${contractResolveTime}ms]:" + result); return Serializer.json.decodeFromString(result) } suspend fun resolveContractAsync(contract: ExchangeContract, vararg resolves: ChannelResolve): Array { val contractResolve = convertResolves(*resolves) - val result = postAsync("/api/Channel/Resolve?contractId=${contract.id}", Serializer.json.encodeToString(contractResolve), "application/json") + val result = postAsync("/api/Channel/Resolve?contractId=${contract.id}", Serializer.json.encodeToString(contractResolve).toByteArray(Charsets.UTF_8), "application/json", true) return Serializer.json.decodeFromString(result) } @@ -74,7 +82,7 @@ class SubsExchangeClient(private val server: String, private val privateKey: Str } // IO methods - private fun post(query: String, body: String, contentType: String, timeout: Int = 0): String { + private fun post(query: String, body: ByteArray, contentType: String, timeout: Int = 0, gzip: Boolean = false): String { val url = URL("${server.trim('/')}$query") with(url.openConnection() as HttpURLConnection) { if(timeout > 0) @@ -82,7 +90,16 @@ class SubsExchangeClient(private val server: String, private val privateKey: Str requestMethod = "POST" setRequestProperty("Content-Type", contentType) doOutput = true - OutputStreamWriter(outputStream, StandardCharsets.UTF_8).use { it.write(body); it.flush() } + + + if(gzip) { + val gzipData = body.toGzip(); + setRequestProperty("Content-Encoding", "gzip"); + outputStream.write(gzipData); + Logger.i("SubsExchangeClient", "SubsExchange using gzip (${body.size.toHumanBytesSize()} => ${gzipData.size.toHumanBytesSize()}"); + } + else + outputStream.write(body); val status = responseCode; Logger.i("SubsExchangeClient", "POST [${url}]: ${status}"); @@ -105,9 +122,9 @@ class SubsExchangeClient(private val server: String, private val privateKey: Str } } } - private suspend fun postAsync(query: String, body: String, contentType: String): String { + private suspend fun postAsync(query: String, body: ByteArray, contentType: String, gzip: Boolean = false): String { return withContext(Dispatchers.IO) { - post(query, body, contentType) + post(query, body, contentType, 0, gzip) } } diff --git a/app/src/main/java/com/futo/platformplayer/views/ToggleBar.kt b/app/src/main/java/com/futo/platformplayer/views/ToggleBar.kt index ef2eadbc..4a545a26 100644 --- a/app/src/main/java/com/futo/platformplayer/views/ToggleBar.kt +++ b/app/src/main/java/com/futo/platformplayer/views/ToggleBar.kt @@ -53,7 +53,7 @@ class ToggleBar : LinearLayout { this.setInfo(button.iconVariable, button.name, button.isActive, button.isButton); else this.setInfo(button.name, button.isActive, button.isButton); - this.onClick.subscribe { button.action(it); }; + this.onClick.subscribe({ view, enabled -> button.action(view, enabled); }); }); } } @@ -62,27 +62,27 @@ class ToggleBar : LinearLayout { val name: String; val icon: Int; val iconVariable: ImageVariable?; - val action: (Boolean)->Unit; + val action: (ToggleTagView, Boolean)->Unit; val isActive: Boolean; var isButton: Boolean = false private set; var tag: String? = null; - constructor(name: String, icon: ImageVariable?, isActive: Boolean = false, action: (Boolean)->Unit) { + constructor(name: String, icon: ImageVariable?, isActive: Boolean = false, action: (ToggleTagView, Boolean)->Unit) { this.name = name; this.icon = 0; this.iconVariable = icon; this.action = action; this.isActive = isActive; } - constructor(name: String, icon: Int, isActive: Boolean = false, action: (Boolean)->Unit) { + constructor(name: String, icon: Int, isActive: Boolean = false, action: (ToggleTagView, Boolean)->Unit) { this.name = name; this.icon = icon; this.iconVariable = null; this.action = action; this.isActive = isActive; } - constructor(name: String, isActive: Boolean = false, action: (Boolean)->Unit) { + constructor(name: String, isActive: Boolean = false, action: (ToggleTagView, Boolean)->Unit) { this.name = name; this.icon = 0; this.iconVariable = null; diff --git a/app/src/main/java/com/futo/platformplayer/views/others/ToggleTagView.kt b/app/src/main/java/com/futo/platformplayer/views/others/ToggleTagView.kt index 059405ad..3ba65413 100644 --- a/app/src/main/java/com/futo/platformplayer/views/others/ToggleTagView.kt +++ b/app/src/main/java/com/futo/platformplayer/views/others/ToggleTagView.kt @@ -12,8 +12,10 @@ import android.widget.TextView import com.bumptech.glide.Glide import com.futo.platformplayer.R import com.futo.platformplayer.constructs.Event1 +import com.futo.platformplayer.constructs.Event2 import com.futo.platformplayer.images.GlideHelper import com.futo.platformplayer.models.ImageVariable +import com.futo.platformplayer.views.ToggleBar class ToggleTagView : LinearLayout { private val _root: FrameLayout; @@ -26,7 +28,7 @@ class ToggleTagView : LinearLayout { var isButton: Boolean = false private set; - var onClick = Event1(); + var onClick = Event2(); constructor(context: Context, attrs: AttributeSet? = null) : super(context, attrs) { LayoutInflater.from(context).inflate(R.layout.view_toggle_tag, this, true); @@ -36,7 +38,7 @@ class ToggleTagView : LinearLayout { _root.setOnClickListener { if(!isButton) setToggle(!isActive); - onClick.emit(isActive); + onClick.emit(this, isActive); } } @@ -52,6 +54,24 @@ class ToggleTagView : LinearLayout { } } + fun setInfo(toggle: ToggleBar.Toggle){ + _text = toggle.name; + _textTag.text = toggle.name; + setToggle(toggle.isActive); + if(toggle.iconVariable != null) { + toggle.iconVariable.setImageView(_image, R.drawable.ic_error_pred); + _image.visibility = View.GONE; + } + else if(toggle.icon > 0) { + _image.setImageResource(toggle.icon); + _image.visibility = View.GONE; + } + else + _image.visibility = View.VISIBLE; + _textTag.visibility = if(!toggle.name.isNullOrEmpty()) View.VISIBLE else View.GONE; + this.isButton = isButton; + } + fun setInfo(imageResource: Int, text: String, isActive: Boolean, isButton: Boolean = false) { _text = text; _textTag.text = text; diff --git a/app/src/main/java/com/futo/platformplayer/views/subscriptions/SubscriptionBar.kt b/app/src/main/java/com/futo/platformplayer/views/subscriptions/SubscriptionBar.kt index 97eecac4..5cd2ad85 100644 --- a/app/src/main/java/com/futo/platformplayer/views/subscriptions/SubscriptionBar.kt +++ b/app/src/main/java/com/futo/platformplayer/views/subscriptions/SubscriptionBar.kt @@ -158,7 +158,7 @@ class SubscriptionBar : LinearLayout { for(button in buttons) { _tagsContainer.addView(ToggleTagView(context).apply { this.setInfo(button.name, button.isActive); - this.onClick.subscribe { button.action(it); }; + this.onClick.subscribe({ view, value -> button.action(view, value); }); }); } } @@ -166,16 +166,16 @@ class SubscriptionBar : LinearLayout { class Toggle { val name: String; val icon: Int; - val action: (Boolean)->Unit; + val action: (ToggleTagView, Boolean)->Unit; val isActive: Boolean; - constructor(name: String, icon: Int, isActive: Boolean = false, action: (Boolean)->Unit) { + constructor(name: String, icon: Int, isActive: Boolean = false, action: (ToggleTagView, Boolean)->Unit) { this.name = name; this.icon = icon; this.action = action; this.isActive = isActive; } - constructor(name: String, isActive: Boolean = false, action: (Boolean)->Unit) { + constructor(name: String, isActive: Boolean = false, action: (ToggleTagView, Boolean)->Unit) { this.name = name; this.icon = 0; this.action = action;