diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7f2db8a8..7f50269c 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,8 +7,8 @@
-
-
+
+
diff --git a/app/src/main/java/com/futo/platformplayer/Extensions_Network.kt b/app/src/main/java/com/futo/platformplayer/Extensions_Network.kt
index b99b33d5..4ea143b6 100644
--- a/app/src/main/java/com/futo/platformplayer/Extensions_Network.kt
+++ b/app/src/main/java/com/futo/platformplayer/Extensions_Network.kt
@@ -169,7 +169,7 @@ private fun parseHextet(ipString: String, start: Int, end: Int): Short {
var hextet = 0
for (i in start until end) {
hextet = hextet shl 4
- hextet = hextet or ipString[i].digitToIntOrNull(16)!! ?: -1
+ hextet = hextet or ipString[i].digitToIntOrNull(16)!!
}
return hextet.toShort()
}
diff --git a/app/src/main/java/com/futo/platformplayer/Extensions_V8.kt b/app/src/main/java/com/futo/platformplayer/Extensions_V8.kt
index daaba3f5..e31d3dac 100644
--- a/app/src/main/java/com/futo/platformplayer/Extensions_V8.kt
+++ b/app/src/main/java/com/futo/platformplayer/Extensions_V8.kt
@@ -27,7 +27,7 @@ fun V8Value?.orDefault(default: R, handler: (V8Value)->R): R {
inline fun V8Value.expectOrThrow(config: IV8PluginConfig, contextName: String): T {
if(this !is T)
throw ScriptImplementationException(config, "Expected ${contextName} to be of type ${T::class.simpleName}, but found ${this::class.simpleName}");
- return this as T;
+ return this;
}
//Singles
diff --git a/app/src/main/java/com/futo/platformplayer/SettingsDev.kt b/app/src/main/java/com/futo/platformplayer/SettingsDev.kt
index ef4f9495..91bba5e4 100644
--- a/app/src/main/java/com/futo/platformplayer/SettingsDev.kt
+++ b/app/src/main/java/com/futo/platformplayer/SettingsDev.kt
@@ -2,15 +2,9 @@ package com.futo.platformplayer
import android.content.Context
import android.webkit.CookieManager
-import androidx.lifecycle.lifecycleScope
-import androidx.work.Constraints
import androidx.work.Data
-import androidx.work.ExistingPeriodicWorkPolicy
-import androidx.work.NetworkType
import androidx.work.OneTimeWorkRequestBuilder
-import androidx.work.PeriodicWorkRequest
import androidx.work.WorkManager
-import androidx.work.WorkerParameters
import com.caoccao.javet.values.primitive.V8ValueInteger
import com.caoccao.javet.values.primitive.V8ValueString
import com.futo.platformplayer.activities.DeveloperActivity
@@ -36,7 +30,6 @@ import com.futo.platformplayer.states.StatePlatform
import com.futo.platformplayer.states.StateSubscriptions
import com.futo.platformplayer.stores.FragmentedStorage
import com.futo.platformplayer.stores.FragmentedStorageFileJson
-import com.futo.platformplayer.stores.db.types.DBHistory
import com.futo.platformplayer.views.fields.ButtonField
import com.futo.platformplayer.views.fields.FieldForm
import com.futo.platformplayer.views.fields.FormField
@@ -44,11 +37,12 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
-import kotlinx.serialization.*
-import kotlinx.serialization.json.*
+import kotlinx.serialization.Contextual
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.Transient
+import kotlinx.serialization.encodeToString
+import kotlinx.serialization.json.Json
import java.time.OffsetDateTime
-import java.util.UUID
-import java.util.concurrent.TimeUnit
import java.util.stream.IntStream.range
import kotlin.system.measureTimeMillis
@@ -109,14 +103,14 @@ class SettingsDev : FragmentedStorageFileJson() {
StateApp.instance.scope.launch(Dispatchers.IO) {
try {
val subsCache =
- StateSubscriptions.instance.getSubscriptionsFeedWithExceptions(cacheScope = this)?.first;
+ StateSubscriptions.instance.getSubscriptionsFeedWithExceptions(cacheScope = this).first;
var total = 0;
var page = 0;
var lastToast = System.currentTimeMillis();
- while(subsCache!!.hasMorePages() && total < 5000) {
- subsCache!!.nextPage();
- total += subsCache!!.getResults().size;
+ while(subsCache.hasMorePages() && total < 5000) {
+ subsCache.nextPage();
+ total += subsCache.getResults().size;
page++;
if(page % 10 == 0)
@@ -174,9 +168,9 @@ class SettingsDev : FragmentedStorageFileJson() {
var total = 0;
var page = 0;
var lastToast = System.currentTimeMillis();
- while(subsCache!!.hasMorePages() && total < 5000) {
- subsCache!!.nextPage();
- total += subsCache!!.getResults().size;
+ while(subsCache.hasMorePages() && total < 5000) {
+ subsCache.nextPage();
+ total += subsCache.getResults().size;
page++;
for(item in subsCache.getResults().filterIsInstance()) {
@@ -375,9 +369,9 @@ class SettingsDev : FragmentedStorageFileJson() {
@FormField(R.string.getHome, FieldForm.BUTTON, R.string.attempts_to_fetch_2_pages_from_getHome, 2)
fun testV8Home() {
runTestPlugin(_currentPlugin) {
- var home: IPager? = null;
- var resultPage1: String = "";
- var resultPage2: String = "";
+ var home: IPager?;
+ val resultPage1: String;
+ val resultPage2: String;
val page1Time = measureTimeMillis {
home = it.getHome();
val results = home!!.getResults();
diff --git a/app/src/main/java/com/futo/platformplayer/UISlideOverlays.kt b/app/src/main/java/com/futo/platformplayer/UISlideOverlays.kt
index ccb083a0..f1a0ea44 100644
--- a/app/src/main/java/com/futo/platformplayer/UISlideOverlays.kt
+++ b/app/src/main/java/com/futo/platformplayer/UISlideOverlays.kt
@@ -22,20 +22,25 @@ import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.models.Playlist
import com.futo.platformplayer.models.Subscription
import com.futo.platformplayer.parsers.HLS
-import com.futo.platformplayer.states.*
+import com.futo.platformplayer.states.StateApp
+import com.futo.platformplayer.states.StateDownloads
+import com.futo.platformplayer.states.StateMeta
+import com.futo.platformplayer.states.StatePlatform
+import com.futo.platformplayer.states.StatePlayer
+import com.futo.platformplayer.states.StatePlaylists
import com.futo.platformplayer.views.LoaderView
+import com.futo.platformplayer.views.overlays.slideup.SlideUpMenuFilters
import com.futo.platformplayer.views.overlays.slideup.SlideUpMenuGroup
import com.futo.platformplayer.views.overlays.slideup.SlideUpMenuItem
import com.futo.platformplayer.views.overlays.slideup.SlideUpMenuOverlay
+import com.futo.platformplayer.views.overlays.slideup.SlideUpMenuTextInput
import com.futo.platformplayer.views.pills.RoundButton
import com.futo.platformplayer.views.pills.RoundButtonGroup
-import com.futo.platformplayer.views.overlays.slideup.*
import com.futo.platformplayer.views.video.FutoVideoPlayerBase
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
-import java.lang.IllegalStateException
class UISlideOverlays {
companion object {
@@ -242,7 +247,7 @@ class UISlideOverlays {
val audioSources = if(descriptor is VideoUnMuxedSourceDescriptor) descriptor.audioSources else null;
val subtitleSources = video.subtitles;
- if(videoSources.size == 0 && (audioSources?.size ?: 0) == 0) {
+ if(videoSources.isEmpty() && (audioSources?.size ?: 0) == 0) {
UIDialogs.toast(container.context.getString(R.string.no_downloads_available), false);
return null;
}
@@ -263,24 +268,30 @@ class UISlideOverlays {
videoSources
.filter { it.isDownloadable() }
.map {
- if (it is IVideoUrlSource) {
- SlideUpMenuItem(container.context, R.drawable.ic_movie, it.name, "${it.width}x${it.height}", it, {
- selectedVideo = it
- menu?.selectOption(videoSources, it);
- if(selectedAudio != null || !requiresAudio)
- menu?.setOk(container.context.getString(R.string.download));
- }, false)
- } else if (it is IHLSManifestSource) {
- SlideUpMenuItem(container.context, R.drawable.ic_movie, it.name, "HLS", it, {
- showHlsPicker(video, it, it.url, container)
- }, false)
- } else {
- throw Exception("Unhandled source type")
+ when (it) {
+ is IVideoUrlSource -> {
+ SlideUpMenuItem(container.context, R.drawable.ic_movie, it.name, "${it.width}x${it.height}", it, {
+ selectedVideo = it
+ menu?.selectOption(videoSources, it);
+ if(selectedAudio != null || !requiresAudio)
+ menu?.setOk(container.context.getString(R.string.download));
+ }, false)
+ }
+
+ is IHLSManifestSource -> {
+ SlideUpMenuItem(container.context, R.drawable.ic_movie, it.name, "HLS", it, {
+ showHlsPicker(video, it, it.url, container)
+ }, false)
+ }
+
+ else -> {
+ throw Exception("Unhandled source type")
+ }
}
}).flatten().toList()
));
- if(Settings.instance.downloads.getDefaultVideoQualityPixels() > 0 && videoSources.size > 0) {
+ if(Settings.instance.downloads.getDefaultVideoQualityPixels() > 0 && videoSources.isNotEmpty()) {
//TODO: Add HLS support here
selectedVideo = VideoHelper.selectBestVideoSource(
videoSources.filter { it is IVideoUrlSource && it.isDownloadable() }.asIterable(),
@@ -289,30 +300,30 @@ class UISlideOverlays {
) as IVideoUrlSource;
}
- audioSources?.let { audioSources ->
+ if (audioSources != null) {
items.add(SlideUpMenuGroup(container.context, container.context.getString(R.string.audio), audioSources, audioSources
.filter { VideoHelper.isDownloadable(it) }
.map {
- if (it is IAudioUrlSource) {
- SlideUpMenuItem(container.context, R.drawable.ic_music, it.name, "${it.bitrate}", it, {
- selectedAudio = it
- menu?.selectOption(audioSources, it);
- menu?.setOk(container.context.getString(R.string.download));
- }, false);
- } else if (it is IHLSManifestAudioSource) {
- SlideUpMenuItem(container.context, R.drawable.ic_movie, it.name, "HLS Audio", it, {
- showHlsPicker(video, it, it.url, container)
- }, false)
- } else {
- throw Exception("Unhandled source type")
+ when (it) {
+ is IAudioUrlSource -> {
+ SlideUpMenuItem(container.context, R.drawable.ic_music, it.name, "${it.bitrate}", it, {
+ selectedAudio = it
+ menu?.selectOption(audioSources, it);
+ menu?.setOk(container.context.getString(R.string.download));
+ }, false);
+ }
+
+ is IHLSManifestAudioSource -> {
+ SlideUpMenuItem(container.context, R.drawable.ic_movie, it.name, "HLS Audio", it, {
+ showHlsPicker(video, it, it.url, container)
+ }, false)
+ }
+
+ else -> {
+ throw Exception("Unhandled source type")
+ }
}
}));
- val asources = audioSources;
- val preferredAudioSource = VideoHelper.selectBestAudioSource(asources.asIterable(),
- FutoVideoPlayerBase.PREFERED_AUDIO_CONTAINERS,
- Settings.instance.playback.getPrimaryLanguage(container.context),
- if(Settings.instance.downloads.isHighBitrateDefault()) 99999999 else 1);
- menu?.selectOption(asources, preferredAudioSource);
//TODO: Add HLS support here
selectedAudio = VideoHelper.selectBestAudioSource(audioSources.filter { it is IAudioUrlSource && it.isDownloadable() }.asIterable(),
@@ -321,10 +332,8 @@ class UISlideOverlays {
if(Settings.instance.downloads.isHighBitrateDefault()) 9999999 else 1) as IAudioUrlSource?;
}
- //ContentResolver is required for subtitles..
if(contentResolver != null && subtitleSources.isNotEmpty()) {
- items.add(SlideUpMenuGroup(container.context, container.context.getString(R.string.subtitles), subtitleSources, subtitleSources
- .map {
+ items.add(SlideUpMenuGroup(container.context, container.context.getString(R.string.subtitles), subtitleSources, subtitleSources.map {
SlideUpMenuItem(container.context, R.drawable.ic_edit, it.name, "", it, {
if (selectedSubtitle == it) {
selectedSubtitle = null;
@@ -334,7 +343,8 @@ class UISlideOverlays {
menu?.selectOption(subtitleSources, it);
}
}, false);
- }));
+ })
+ );
}
menu = SlideUpMenuOverlay(container.context, container, container.context.getString(R.string.download_video), null, true, items);
@@ -645,10 +655,11 @@ class UISlideOverlays {
val visible = buttonGroup.getVisibleButtons().filter { !ignoreTags.contains(it.tagRef) };
val hidden = buttonGroup.getInvisibleButtons().filter { !ignoreTags.contains(it.tagRef) };
- val views = arrayOf(hidden
- .map { btn -> SlideUpMenuItem(container.context, btn.iconResource, btn.text.text.toString(), "", "", {
- btn.handler?.invoke(btn);
- }, true) as View }.toTypedArray() ?: arrayOf(),
+ val views = arrayOf(
+ hidden
+ .map { btn -> SlideUpMenuItem(container.context, btn.iconResource, btn.text.text.toString(), "", "", {
+ btn.handler?.invoke(btn);
+ }, true) as View }.toTypedArray(),
arrayOf(SlideUpMenuItem(container.context, R.drawable.ic_pin, container.context.getString(R.string.change_pins), container.context.getString(R.string.decide_which_buttons_should_be_pinned), "", {
showOrderOverlay(container, container.context.getString(R.string.select_your_pins_in_order), (visible + hidden).map { Pair(it.text.text.toString(), it.tagRef!!) }) {
val selected = it
diff --git a/app/src/main/java/com/futo/platformplayer/Utility.kt b/app/src/main/java/com/futo/platformplayer/Utility.kt
index 0e57a220..f58a282f 100644
--- a/app/src/main/java/com/futo/platformplayer/Utility.kt
+++ b/app/src/main/java/com/futo/platformplayer/Utility.kt
@@ -143,6 +143,7 @@ fun InputStream.copyToOutputStream(inputStreamLength: Long, outputStream: Output
}
}
+@Suppress("DEPRECATION")
fun Activity.setNavigationBarColorAndIcons() {
window.navigationBarColor = ContextCompat.getColor(this, android.R.color.black);
diff --git a/app/src/main/java/com/futo/platformplayer/activities/AddSourceActivity.kt b/app/src/main/java/com/futo/platformplayer/activities/AddSourceActivity.kt
index e61ee193..bc22d3dc 100644
--- a/app/src/main/java/com/futo/platformplayer/activities/AddSourceActivity.kt
+++ b/app/src/main/java/com/futo/platformplayer/activities/AddSourceActivity.kt
@@ -5,13 +5,20 @@ import android.content.Intent
import android.graphics.drawable.Animatable
import android.os.Bundle
import android.view.View
-import android.widget.*
+import android.widget.ImageButton
+import android.widget.ImageView
+import android.widget.LinearLayout
+import android.widget.ScrollView
+import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
+import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
-import com.futo.platformplayer.*
+import com.futo.platformplayer.R
+import com.futo.platformplayer.UIDialogs
import com.futo.platformplayer.api.http.ManagedHttpClient
import com.futo.platformplayer.api.media.platforms.js.SourcePluginConfig
import com.futo.platformplayer.logging.Logger
+import com.futo.platformplayer.setNavigationBarColorAndIcons
import com.futo.platformplayer.states.StateApp
import com.futo.platformplayer.states.StatePlatform
import com.futo.platformplayer.states.StatePlugins
@@ -194,7 +201,7 @@ class AddSourceActivity : AppCompatActivity() {
config.allowUrls, true)
)
- val pastelRed = resources.getColor(R.color.pastel_red);
+ val pastelRed = ContextCompat.getColor(this, R.color.pastel_red);
for(warning in config.getWarnings(script))
_sourceWarnings.addView(
diff --git a/app/src/main/java/com/futo/platformplayer/activities/AddSourceOptionsActivity.kt b/app/src/main/java/com/futo/platformplayer/activities/AddSourceOptionsActivity.kt
index 2db44833..2c270656 100644
--- a/app/src/main/java/com/futo/platformplayer/activities/AddSourceOptionsActivity.kt
+++ b/app/src/main/java/com/futo/platformplayer/activities/AddSourceOptionsActivity.kt
@@ -11,7 +11,6 @@ import com.futo.platformplayer.*
import com.futo.platformplayer.states.StateApp
import com.futo.platformplayer.views.buttons.BigButton
import com.google.zxing.integration.android.IntentIntegrator
-import com.journeyapps.barcodescanner.CaptureActivity
class AddSourceOptionsActivity : AppCompatActivity() {
lateinit var _buttonBack: ImageButton;
diff --git a/app/src/main/java/com/futo/platformplayer/activities/DeveloperActivity.kt b/app/src/main/java/com/futo/platformplayer/activities/DeveloperActivity.kt
index f714f880..b8dbb261 100644
--- a/app/src/main/java/com/futo/platformplayer/activities/DeveloperActivity.kt
+++ b/app/src/main/java/com/futo/platformplayer/activities/DeveloperActivity.kt
@@ -26,7 +26,7 @@ class DeveloperActivity : AppCompatActivity() {
_form = findViewById(R.id.settings_form);
_form.fromObject(SettingsDev.instance);
- _form.onChanged.subscribe { field, value ->
+ _form.onChanged.subscribe { _, _ ->
_form.setObjectValues();
SettingsDev.instance.save();
};
diff --git a/app/src/main/java/com/futo/platformplayer/activities/IWithResultLauncher.kt b/app/src/main/java/com/futo/platformplayer/activities/IWithResultLauncher.kt
index 89f48a87..35cbd685 100644
--- a/app/src/main/java/com/futo/platformplayer/activities/IWithResultLauncher.kt
+++ b/app/src/main/java/com/futo/platformplayer/activities/IWithResultLauncher.kt
@@ -2,7 +2,6 @@ package com.futo.platformplayer.activities
import android.content.Intent
import androidx.activity.result.ActivityResult
-import androidx.activity.result.ActivityResultLauncher
interface IWithResultLauncher {
fun launchForResult(intent: Intent, code: Int, handler: (ActivityResult)->Unit);
diff --git a/app/src/main/java/com/futo/platformplayer/activities/LoginActivity.kt b/app/src/main/java/com/futo/platformplayer/activities/LoginActivity.kt
index 5dccdad8..a20a6743 100644
--- a/app/src/main/java/com/futo/platformplayer/activities/LoginActivity.kt
+++ b/app/src/main/java/com/futo/platformplayer/activities/LoginActivity.kt
@@ -3,24 +3,22 @@ package com.futo.platformplayer.activities
import android.content.Context
import android.content.Intent
import android.os.Bundle
-import android.webkit.ConsoleMessage
import android.webkit.CookieManager
-import android.webkit.WebChromeClient
import android.webkit.WebView
import android.widget.ImageButton
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
-import com.futo.platformplayer.*
+import com.futo.platformplayer.R
import com.futo.platformplayer.api.media.platforms.js.SourceAuth
import com.futo.platformplayer.api.media.platforms.js.SourcePluginAuthConfig
import com.futo.platformplayer.api.media.platforms.js.SourcePluginConfig
import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.others.LoginWebViewClient
+import com.futo.platformplayer.setNavigationBarColorAndIcons
import com.futo.platformplayer.states.StateApp
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
-import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
@@ -102,7 +100,7 @@ class LoginActivity : AppCompatActivity() {
override fun finish() {
lifecycleScope.launch(Dispatchers.Main) {
- _webView?.loadUrl("about:blank");
+ _webView.loadUrl("about:blank");
}
_callback?.let {
_callback = null;
diff --git a/app/src/main/java/com/futo/platformplayer/activities/MainActivity.kt b/app/src/main/java/com/futo/platformplayer/activities/MainActivity.kt
index 9f031ed5..b919c5c3 100644
--- a/app/src/main/java/com/futo/platformplayer/activities/MainActivity.kt
+++ b/app/src/main/java/com/futo/platformplayer/activities/MainActivity.kt
@@ -26,7 +26,6 @@ import androidx.lifecycle.lifecycleScope
import com.futo.platformplayer.*
import com.futo.platformplayer.casting.StateCasting
import com.futo.platformplayer.constructs.Event1
-import com.futo.platformplayer.dialogs.ConnectCastingDialog
import com.futo.platformplayer.fragment.mainactivity.bottombar.MenuBottomBarFragment
import com.futo.platformplayer.fragment.mainactivity.main.*
import com.futo.platformplayer.fragment.mainactivity.topbar.AddTopBarFragment
@@ -44,7 +43,6 @@ import com.futo.platformplayer.stores.v2.ManagedStore
import com.google.gson.JsonParser
import com.google.zxing.integration.android.IntentIntegrator
import kotlinx.coroutines.*
-import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import java.io.File
import java.io.PrintWriter
@@ -649,7 +647,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
if(file.lowercase().endsWith(".json") || mime == "application/json") {
var recon = String(data);
if(!recon.trim().startsWith("["))
- return handleUnknownJson(file, recon);
+ return handleUnknownJson(recon);
val reconLines = Json.decodeFromString>(recon);
recon = reconLines.joinToString("\n");
@@ -671,7 +669,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
if(file.lowercase().endsWith(".json")) {
val recon = String(readSharedFile(file));
if(!recon.startsWith("["))
- return handleUnknownJson(file, recon);
+ return handleUnknownJson(recon);
Logger.i(TAG, "Opened shared playlist reconstruction\n${recon}");
handleReconstruction(recon);
@@ -723,7 +721,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
}
return false;
}
- fun handleUnknownJson(name: String?, json: String): Boolean {
+ fun handleUnknownJson(json: String): Boolean {
val context = this;
@@ -832,7 +830,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
val isStop: Boolean = lifecycle.currentState == Lifecycle.State.CREATED;
Logger.v(TAG, "onPictureInPictureModeChanged isInPictureInPictureMode=$isInPictureInPictureMode isStop=$isStop")
- _fragVideoDetail?.onPictureInPictureModeChanged(isInPictureInPictureMode, isStop, newConfig);
+ _fragVideoDetail.onPictureInPictureModeChanged(isInPictureInPictureMode, isStop, newConfig);
Logger.v(TAG, "onPictureInPictureModeChanged Ready");
}
@@ -889,7 +887,6 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
transaction = transaction.replace(R.id.fragment_main, segment);
- val extraBottomDP = if(_fragVideoDetail.state == VideoDetailFragment.State.MINIMIZED) HEIGHT_VIDEO_MINIMIZED_DP else 0f
if (segment.hasBottomBar) {
if (!fragCurrent.hasBottomBar)
transaction = transaction.show(_fragBotBarMenu);
@@ -899,8 +896,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
transaction = transaction.hide(_fragBotBarMenu);
}
transaction.commitNow();
- }
- else {
+ } else {
//Special cases
if(segment is VideoDetailFragment) {
_fragContainerVideoDetail.visibility = View.VISIBLE;
diff --git a/app/src/main/java/com/futo/platformplayer/activities/PolycentricImportProfileActivity.kt b/app/src/main/java/com/futo/platformplayer/activities/PolycentricImportProfileActivity.kt
index 997b17dd..5ab51be8 100644
--- a/app/src/main/java/com/futo/platformplayer/activities/PolycentricImportProfileActivity.kt
+++ b/app/src/main/java/com/futo/platformplayer/activities/PolycentricImportProfileActivity.kt
@@ -8,20 +8,19 @@ import android.widget.ImageButton
import android.widget.LinearLayout
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
-import androidx.lifecycle.lifecycleScope
import com.futo.platformplayer.R
import com.futo.platformplayer.UIDialogs
import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.setNavigationBarColorAndIcons
import com.futo.platformplayer.states.StateApp
import com.futo.platformplayer.states.StatePolycentric
-import com.futo.polycentric.core.*
+import com.futo.polycentric.core.KeyPair
+import com.futo.polycentric.core.Process
+import com.futo.polycentric.core.ProcessSecret
+import com.futo.polycentric.core.SignedEvent
+import com.futo.polycentric.core.Store
+import com.futo.polycentric.core.base64UrlToByteArray
import com.google.zxing.integration.android.IntentIntegrator
-import com.journeyapps.barcodescanner.CaptureActivity
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.GlobalScope
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
import userpackage.Protocol
import userpackage.Protocol.ExportBundle
diff --git a/app/src/main/java/com/futo/platformplayer/activities/PolycentricProfileActivity.kt b/app/src/main/java/com/futo/platformplayer/activities/PolycentricProfileActivity.kt
index b207da44..b131b1e8 100644
--- a/app/src/main/java/com/futo/platformplayer/activities/PolycentricProfileActivity.kt
+++ b/app/src/main/java/com/futo/platformplayer/activities/PolycentricProfileActivity.kt
@@ -17,7 +17,6 @@ import androidx.lifecycle.lifecycleScope
import com.bumptech.glide.Glide
import com.futo.platformplayer.R
import com.futo.platformplayer.UIDialogs
-import com.futo.platformplayer.dialogs.CommentDialog
import com.futo.platformplayer.dp
import com.futo.platformplayer.fullyBackfillServersAnnounceExceptions
import com.futo.platformplayer.images.GlideHelper.Companion.crossfade
@@ -30,7 +29,6 @@ import com.futo.platformplayer.views.buttons.BigButton
import com.futo.polycentric.core.Store
import com.futo.polycentric.core.Synchronization
import com.futo.polycentric.core.SystemState
-import com.futo.polycentric.core.toURLInfoDataLink
import com.futo.polycentric.core.toURLInfoSystemLinkUrl
import com.github.dhaval2404.imagepicker.ImagePicker
import kotlinx.coroutines.Dispatchers
@@ -250,7 +248,7 @@ class PolycentricProfileActivity : AppCompatActivity() {
}
private fun getMimeType(contentResolver: ContentResolver, uri: Uri): String? {
- var mimeType: String? = null;
+ var mimeType: String?;
// Try to get MIME type from the content URI
mimeType = contentResolver.getType(uri);
diff --git a/app/src/main/java/com/futo/platformplayer/activities/SettingsActivity.kt b/app/src/main/java/com/futo/platformplayer/activities/SettingsActivity.kt
index e10d855a..a2aa5023 100644
--- a/app/src/main/java/com/futo/platformplayer/activities/SettingsActivity.kt
+++ b/app/src/main/java/com/futo/platformplayer/activities/SettingsActivity.kt
@@ -49,7 +49,7 @@ class SettingsActivity : AppCompatActivity(), IWithResultLauncher {
_loaderView = findViewById(R.id.loader);
overlay = findViewById(R.id.overlay_container);
- _form.onChanged.subscribe { field, value ->
+ _form.onChanged.subscribe { field, _ ->
Logger.i("SettingsActivity", "Setting [${field.field?.name}] changed, saving");
_form.setObjectValues();
Settings.instance.save();
diff --git a/app/src/main/java/com/futo/platformplayer/api/http/ManagedHttpClient.kt b/app/src/main/java/com/futo/platformplayer/api/http/ManagedHttpClient.kt
index 18e6859b..9c79b665 100644
--- a/app/src/main/java/com/futo/platformplayer/api/http/ManagedHttpClient.kt
+++ b/app/src/main/java/com/futo/platformplayer/api/http/ManagedHttpClient.kt
@@ -13,8 +13,6 @@ import okhttp3.Response
import okhttp3.ResponseBody
import okhttp3.WebSocket
import okhttp3.WebSocketListener
-import java.util.Dictionary
-import java.util.concurrent.TimeUnit
import kotlin.system.measureTimeMillis
open class ManagedHttpClient {
@@ -60,7 +58,7 @@ open class ManagedHttpClient {
val requestBuilder: okhttp3.Request.Builder = okhttp3.Request.Builder()
.url(url);
- if(user_agent != null && !user_agent.isEmpty() && !headers.any { it.key.lowercase() == "user-agent" })
+ if(user_agent.isNotEmpty() && !headers.any { it.key.lowercase() == "user-agent" })
requestBuilder.addHeader("User-Agent", user_agent)
for (pair in headers.entries)
@@ -137,7 +135,7 @@ open class ManagedHttpClient {
val requestBuilder: okhttp3.Request.Builder = okhttp3.Request.Builder()
.method(request.method, requestBody)
.url(request.url);
- if(user_agent != null && !user_agent.isEmpty() && !request.headers.any { it.key.lowercase() == "user-agent" })
+ if(user_agent.isNotEmpty() && !request.headers.any { it.key.lowercase() == "user-agent" })
requestBuilder.addHeader("User-Agent", user_agent)
for (pair in request.headers.entries)
@@ -148,7 +146,7 @@ open class ManagedHttpClient {
val time = measureTimeMillis {
val call = client.newCall(requestBuilder.build());
- request.onCallCreated?.emit(call);
+ request.onCallCreated.emit(call);
response = call.execute()
resp = Response(
response.code,
diff --git a/app/src/main/java/com/futo/platformplayer/api/http/server/ManagedHttpServer.kt b/app/src/main/java/com/futo/platformplayer/api/http/server/ManagedHttpServer.kt
index 1625186f..e4f1cb03 100644
--- a/app/src/main/java/com/futo/platformplayer/api/http/server/ManagedHttpServer.kt
+++ b/app/src/main/java/com/futo/platformplayer/api/http/server/ManagedHttpServer.kt
@@ -1,11 +1,11 @@
package com.futo.platformplayer.api.http.server
-import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.api.http.ManagedHttpClient
import com.futo.platformplayer.api.http.server.exceptions.EmptyRequestException
import com.futo.platformplayer.api.http.server.handlers.HttpFuntionHandler
import com.futo.platformplayer.api.http.server.handlers.HttpHandler
import com.futo.platformplayer.api.http.server.handlers.HttpOptionsAllowHandler
+import com.futo.platformplayer.logging.Logger
import java.io.BufferedInputStream
import java.io.OutputStream
import java.lang.reflect.Field
@@ -14,11 +14,10 @@ import java.net.InetAddress
import java.net.NetworkInterface
import java.net.ServerSocket
import java.net.Socket
-import java.util.*
+import java.util.UUID
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import java.util.stream.IntStream.range
-import kotlin.collections.HashMap
class ManagedHttpServer(private val _requestedPort: Int = 0) {
private val _client : ManagedHttpClient = ManagedHttpClient();
@@ -212,13 +211,13 @@ class ManagedHttpServer(private val _requestedPort: Int = 0) {
addHandler(HttpFuntionHandler("GET", getMethod.second.path) { getMethod.first.invoke(obj, it) }).apply {
if(!getMethod.second.contentType.isEmpty())
this.withContentType(getMethod.second.contentType);
- }.withContentType(getMethod.second.contentType ?: "");
+ }.withContentType(getMethod.second.contentType);
for(postMethod in postMethods)
if(postMethod.first.parameterTypes.firstOrNull() == HttpContext::class.java && postMethod.first.parameterCount == 1)
addHandler(HttpFuntionHandler("POST", postMethod.second.path) { postMethod.first.invoke(obj, it) }).apply {
if(!postMethod.second.contentType.isEmpty())
this.withContentType(postMethod.second.contentType);
- }.withContentType(postMethod.second.contentType ?: "");
+ }.withContentType(postMethod.second.contentType);
for(getField in getFields) {
getField.first.isAccessible = true;
@@ -232,13 +231,13 @@ class ManagedHttpServer(private val _requestedPort: Int = 0) {
}
else
it.respondCode(204);
- }).withContentType(getField.second.contentType ?: "");
+ }).withContentType(getField.second.contentType);
}
}
private fun keepAliveLoop(requestReader: BufferedInputStream, responseStream: OutputStream, requestId: String, handler: (HttpContext)->Unit) {
val stopCount = _stopCount;
- var keepAlive = false;
+ var keepAlive: Boolean;
var requestsMax = 0;
var requestsTotal = 0;
do {
@@ -288,11 +287,13 @@ class ManagedHttpServer(private val _requestedPort: Int = 0) {
for (intf in NetworkInterface.getNetworkInterfaces()) {
for (addr in intf.inetAddresses) {
if (!addr.isLoopbackAddress) {
- val ipString: String = addr.hostAddress;
- val isIPv4 = ipString.indexOf(':') < 0;
- if (!isIPv4)
- continue;
- addresses.add(addr);
+ val ipString: String = addr.hostAddress ?: continue
+ val isIPv4 = ipString.indexOf(':') < 0
+ if (!isIPv4) {
+ continue
+ }
+
+ addresses.add(addr)
}
}
}
diff --git a/app/src/main/java/com/futo/platformplayer/api/http/server/exceptions/EmptyRequestException.kt b/app/src/main/java/com/futo/platformplayer/api/http/server/exceptions/EmptyRequestException.kt
index 91182132..0b7f072c 100644
--- a/app/src/main/java/com/futo/platformplayer/api/http/server/exceptions/EmptyRequestException.kt
+++ b/app/src/main/java/com/futo/platformplayer/api/http/server/exceptions/EmptyRequestException.kt
@@ -1,6 +1,3 @@
package com.futo.platformplayer.api.http.server.exceptions
-import java.net.SocketTimeoutException
-import java.util.concurrent.TimeoutException
-
class EmptyRequestException(msg: String) : Exception(msg) {}
\ No newline at end of file
diff --git a/app/src/main/java/com/futo/platformplayer/api/media/CachedPlatformClient.kt b/app/src/main/java/com/futo/platformplayer/api/media/CachedPlatformClient.kt
index ad567a99..57f53567 100644
--- a/app/src/main/java/com/futo/platformplayer/api/media/CachedPlatformClient.kt
+++ b/app/src/main/java/com/futo/platformplayer/api/media/CachedPlatformClient.kt
@@ -10,12 +10,9 @@ import com.futo.platformplayer.api.media.models.contents.IPlatformContentDetails
import com.futo.platformplayer.api.media.models.live.ILiveChatWindowDescriptor
import com.futo.platformplayer.api.media.models.live.IPlatformLiveEvent
import com.futo.platformplayer.api.media.models.playback.IPlaybackTracker
-import com.futo.platformplayer.api.media.models.playlists.IPlatformPlaylist
import com.futo.platformplayer.api.media.models.playlists.IPlatformPlaylistDetails
-import com.futo.platformplayer.api.media.models.video.IPlatformVideoDetails
import com.futo.platformplayer.api.media.structures.IPager
import com.futo.platformplayer.models.ImageVariable
-import com.futo.platformplayer.models.Playlist
/**
* A temporary class that caches video results
@@ -44,8 +41,7 @@ class CachedPlatformClient : IPlatformClient {
var result = _cache.get(url);
if(result == null) {
result = _client.getContentDetails(url);
- if (result != null)
- _cache.put(url, result);
+ _cache.put(url, result);
}
return result;
}
diff --git a/app/src/main/java/com/futo/platformplayer/api/media/IPlatformClient.kt b/app/src/main/java/com/futo/platformplayer/api/media/IPlatformClient.kt
index 009e0c14..b527d6ff 100644
--- a/app/src/main/java/com/futo/platformplayer/api/media/IPlatformClient.kt
+++ b/app/src/main/java/com/futo/platformplayer/api/media/IPlatformClient.kt
@@ -10,11 +10,9 @@ import com.futo.platformplayer.api.media.models.contents.IPlatformContentDetails
import com.futo.platformplayer.api.media.models.live.ILiveChatWindowDescriptor
import com.futo.platformplayer.api.media.models.live.IPlatformLiveEvent
import com.futo.platformplayer.api.media.models.playback.IPlaybackTracker
-import com.futo.platformplayer.api.media.models.playlists.IPlatformPlaylist
import com.futo.platformplayer.api.media.models.playlists.IPlatformPlaylistDetails
import com.futo.platformplayer.api.media.structures.IPager
import com.futo.platformplayer.models.ImageVariable
-import com.futo.platformplayer.models.Playlist
/**
* A client for a specific platform
diff --git a/app/src/main/java/com/futo/platformplayer/api/media/LiveChatManager.kt b/app/src/main/java/com/futo/platformplayer/api/media/LiveChatManager.kt
index 3e265c10..ab903057 100644
--- a/app/src/main/java/com/futo/platformplayer/api/media/LiveChatManager.kt
+++ b/app/src/main/java/com/futo/platformplayer/api/media/LiveChatManager.kt
@@ -9,7 +9,6 @@ import com.caverock.androidsvg.SVG
import com.futo.platformplayer.api.http.ManagedHttpClient
import com.futo.platformplayer.api.media.models.live.IPlatformLiveEvent
import com.futo.platformplayer.api.media.models.live.LiveEventComment
-import com.futo.platformplayer.api.media.models.live.LiveEventDonation
import com.futo.platformplayer.api.media.models.live.LiveEventEmojis
import com.futo.platformplayer.api.media.platforms.js.models.JSLiveEventPager
import com.futo.platformplayer.api.media.structures.IPager
@@ -195,7 +194,7 @@ class LiveChatManager {
fun getEmojiDrawable(emoji: String, cb: (drawable: Drawable?)->Unit) {
var drawable: Drawable? = null;
- var url: String? = null;
+ var url: String?;
synchronized(_cache_lock) {
url = _cache_urls[emoji];
if(url != null)
diff --git a/app/src/main/java/com/futo/platformplayer/api/media/PlatformMultiClientPool.kt b/app/src/main/java/com/futo/platformplayer/api/media/PlatformMultiClientPool.kt
index 235a28b0..b77a4f35 100644
--- a/app/src/main/java/com/futo/platformplayer/api/media/PlatformMultiClientPool.kt
+++ b/app/src/main/java/com/futo/platformplayer/api/media/PlatformMultiClientPool.kt
@@ -20,7 +20,7 @@ class PlatformMultiClientPool {
val pool = synchronized(_clientPools) {
if(!_clientPools.containsKey(parentClient))
_clientPools[parentClient] = PlatformClientPool(parentClient, _name).apply {
- this.onDead.subscribe { client, pool ->
+ this.onDead.subscribe { _, pool ->
synchronized(_clientPools) {
if(_clientPools[parentClient] == pool)
_clientPools.remove(parentClient);
diff --git a/app/src/main/java/com/futo/platformplayer/api/media/models/ResultCapabilities.kt b/app/src/main/java/com/futo/platformplayer/api/media/models/ResultCapabilities.kt
index 9b328bf1..de495f6a 100644
--- a/app/src/main/java/com/futo/platformplayer/api/media/models/ResultCapabilities.kt
+++ b/app/src/main/java/com/futo/platformplayer/api/media/models/ResultCapabilities.kt
@@ -64,7 +64,6 @@ class FilterGroup(
val isMultiSelect: Boolean,
val id: String? = null
) {
- @kotlinx.serialization.Transient
val idOrName: String get() = id ?: name;
companion object {
diff --git a/app/src/main/java/com/futo/platformplayer/api/media/models/live/IPlatformLiveEvent.kt b/app/src/main/java/com/futo/platformplayer/api/media/models/live/IPlatformLiveEvent.kt
index 6ffaea35..89826b01 100644
--- a/app/src/main/java/com/futo/platformplayer/api/media/models/live/IPlatformLiveEvent.kt
+++ b/app/src/main/java/com/futo/platformplayer/api/media/models/live/IPlatformLiveEvent.kt
@@ -1,31 +1,23 @@
package com.futo.platformplayer.api.media.models.live
-import com.caoccao.javet.values.V8Value
import com.caoccao.javet.values.reference.V8ValueObject
-import com.futo.platformplayer.api.media.models.ratings.IRating
-import com.futo.platformplayer.api.media.models.ratings.RatingLikeDislikes
-import com.futo.platformplayer.api.media.models.ratings.RatingLikes
-import com.futo.platformplayer.api.media.models.ratings.RatingScaler
-import com.futo.platformplayer.api.media.models.ratings.RatingType
import com.futo.platformplayer.engine.IV8PluginConfig
import com.futo.platformplayer.getOrThrow
-import com.futo.platformplayer.orDefault
interface IPlatformLiveEvent {
val type : LiveEventType;
companion object {
- fun fromV8(config: IV8PluginConfig, obj: V8ValueObject, contextName: String = "Unknown") : IPlatformLiveEvent {
- val contextName = "LiveEvent";
- val type = LiveEventType.fromInt(obj.getOrThrow(config, "type", contextName));
- return when(type) {
+ fun fromV8(config: IV8PluginConfig, obj: V8ValueObject, contextName: String = "LiveEvent") : IPlatformLiveEvent {
+ val t = LiveEventType.fromInt(obj.getOrThrow(config, "type", contextName));
+ return when(t) {
LiveEventType.COMMENT -> LiveEventComment.fromV8(config, obj);
LiveEventType.EMOJIS -> LiveEventEmojis.fromV8(config, obj);
LiveEventType.DONATION -> LiveEventDonation.fromV8(config, obj);
LiveEventType.VIEWCOUNT -> LiveEventViewCount.fromV8(config, obj);
LiveEventType.RAID -> LiveEventRaid.fromV8(config, obj);
- else -> throw NotImplementedError("Unknown type ${type}");
+ else -> throw NotImplementedError("Unknown type $t");
}
}
}
diff --git a/app/src/main/java/com/futo/platformplayer/api/media/models/playlists/IPlatformPlaylist.kt b/app/src/main/java/com/futo/platformplayer/api/media/models/playlists/IPlatformPlaylist.kt
index d0470cfe..52fc46e0 100644
--- a/app/src/main/java/com/futo/platformplayer/api/media/models/playlists/IPlatformPlaylist.kt
+++ b/app/src/main/java/com/futo/platformplayer/api/media/models/playlists/IPlatformPlaylist.kt
@@ -1,9 +1,6 @@
package com.futo.platformplayer.api.media.models.playlists
-import com.futo.platformplayer.api.media.models.Thumbnails
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
-import com.futo.platformplayer.api.media.models.video.IPlatformVideo
-import com.futo.platformplayer.api.media.structures.IPager
interface IPlatformPlaylist : IPlatformContent {
val thumbnail: String?;
diff --git a/app/src/main/java/com/futo/platformplayer/api/media/models/post/IPlatformPostDetails.kt b/app/src/main/java/com/futo/platformplayer/api/media/models/post/IPlatformPostDetails.kt
index 985e8697..6f591407 100644
--- a/app/src/main/java/com/futo/platformplayer/api/media/models/post/IPlatformPostDetails.kt
+++ b/app/src/main/java/com/futo/platformplayer/api/media/models/post/IPlatformPostDetails.kt
@@ -2,10 +2,6 @@ package com.futo.platformplayer.api.media.models.post
import com.futo.platformplayer.api.media.models.contents.IPlatformContentDetails
import com.futo.platformplayer.api.media.models.ratings.IRating
-import com.futo.platformplayer.api.media.models.streams.IVideoSourceDescriptor
-import com.futo.platformplayer.api.media.models.streams.sources.*
-import com.futo.platformplayer.api.media.models.subtitles.ISubtitleSource
-import com.futo.platformplayer.api.media.models.video.IPlatformVideo
/**
* A detailed video model with data including video/audio sources
diff --git a/app/src/main/java/com/futo/platformplayer/api/media/models/ratings/IRating.kt b/app/src/main/java/com/futo/platformplayer/api/media/models/ratings/IRating.kt
index 4d560b9f..75286b44 100644
--- a/app/src/main/java/com/futo/platformplayer/api/media/models/ratings/IRating.kt
+++ b/app/src/main/java/com/futo/platformplayer/api/media/models/ratings/IRating.kt
@@ -14,14 +14,13 @@ interface IRating {
companion object {
fun fromV8OrDefault(config: IV8PluginConfig, obj: V8Value?, default: IRating) = obj.orDefault(default) { fromV8(config, it as V8ValueObject) };
- fun fromV8(config: IV8PluginConfig, obj: V8ValueObject, contextName: String = "Unknown") : IRating {
- val contextName = "Rating";
- val type = RatingType.fromInt(obj.getOrThrow(config, "type", contextName));
- return when(type) {
+ fun fromV8(config: IV8PluginConfig, obj: V8ValueObject, contextName: String = "Rating") : IRating {
+ val t = RatingType.fromInt(obj.getOrThrow(config, "type", contextName));
+ return when(t) {
RatingType.LIKES -> RatingLikes.fromV8(config, obj);
RatingType.LIKEDISLIKES -> RatingLikeDislikes.fromV8(config, obj);
RatingType.SCALE -> RatingScaler.fromV8(config, obj);
- else -> throw NotImplementedError("Unknown type ${type}");
+ else -> throw NotImplementedError("Unknown type $t");
}
}
}
diff --git a/app/src/main/java/com/futo/platformplayer/api/media/models/subtitles/ISubtitleSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/models/subtitles/ISubtitleSource.kt
index e210774d..fd6e423f 100644
--- a/app/src/main/java/com/futo/platformplayer/api/media/models/subtitles/ISubtitleSource.kt
+++ b/app/src/main/java/com/futo/platformplayer/api/media/models/subtitles/ISubtitleSource.kt
@@ -1,8 +1,6 @@
package com.futo.platformplayer.api.media.models.subtitles
import android.net.Uri
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Deferred
interface ISubtitleSource {
val name: String;
diff --git a/app/src/main/java/com/futo/platformplayer/api/media/models/video/IPlatformVideoDetails.kt b/app/src/main/java/com/futo/platformplayer/api/media/models/video/IPlatformVideoDetails.kt
index 433b44c4..37baf41f 100644
--- a/app/src/main/java/com/futo/platformplayer/api/media/models/video/IPlatformVideoDetails.kt
+++ b/app/src/main/java/com/futo/platformplayer/api/media/models/video/IPlatformVideoDetails.kt
@@ -1,13 +1,12 @@
package com.futo.platformplayer.api.media.models.video
-import com.futo.platformplayer.api.media.IPlatformClient
-import com.futo.platformplayer.api.media.models.comments.IPlatformComment
import com.futo.platformplayer.api.media.models.contents.IPlatformContentDetails
import com.futo.platformplayer.api.media.models.ratings.IRating
import com.futo.platformplayer.api.media.models.streams.IVideoSourceDescriptor
-import com.futo.platformplayer.api.media.models.streams.sources.*
+import com.futo.platformplayer.api.media.models.streams.sources.IDashManifestSource
+import com.futo.platformplayer.api.media.models.streams.sources.IHLSManifestSource
+import com.futo.platformplayer.api.media.models.streams.sources.IVideoSource
import com.futo.platformplayer.api.media.models.subtitles.ISubtitleSource
-import com.futo.platformplayer.api.media.structures.IPager
/**
* A detailed video model with data including video/audio sources
diff --git a/app/src/main/java/com/futo/platformplayer/api/media/models/video/SerializedVideoMuxedSourceDescriptor.kt b/app/src/main/java/com/futo/platformplayer/api/media/models/video/SerializedVideoMuxedSourceDescriptor.kt
index ad2d14ec..65b7cdc9 100644
--- a/app/src/main/java/com/futo/platformplayer/api/media/models/video/SerializedVideoMuxedSourceDescriptor.kt
+++ b/app/src/main/java/com/futo/platformplayer/api/media/models/video/SerializedVideoMuxedSourceDescriptor.kt
@@ -8,6 +8,5 @@ import com.futo.platformplayer.api.media.models.streams.sources.VideoUrlSource
class SerializedVideoMuxedSourceDescriptor(
val _videoSources: Array
): VideoMuxedSourceDescriptor(), ISerializedVideoSourceDescriptor {
- @kotlinx.serialization.Transient
override val videoSources: Array get() = _videoSources.map { it }.toTypedArray();
};
\ No newline at end of file
diff --git a/app/src/main/java/com/futo/platformplayer/api/media/models/video/SerializedVideoUnmuxedSourceDescriptor.kt b/app/src/main/java/com/futo/platformplayer/api/media/models/video/SerializedVideoUnmuxedSourceDescriptor.kt
index f7a84c05..62924647 100644
--- a/app/src/main/java/com/futo/platformplayer/api/media/models/video/SerializedVideoUnmuxedSourceDescriptor.kt
+++ b/app/src/main/java/com/futo/platformplayer/api/media/models/video/SerializedVideoUnmuxedSourceDescriptor.kt
@@ -1,15 +1,16 @@
package com.futo.platformplayer.api.media.models.video
import com.futo.platformplayer.api.media.models.streams.VideoUnMuxedSourceDescriptor
-import com.futo.platformplayer.api.media.models.streams.sources.*
+import com.futo.platformplayer.api.media.models.streams.sources.AudioUrlSource
+import com.futo.platformplayer.api.media.models.streams.sources.IAudioSource
+import com.futo.platformplayer.api.media.models.streams.sources.IVideoSource
+import com.futo.platformplayer.api.media.models.streams.sources.VideoUrlSource
@kotlinx.serialization.Serializable
class SerializedVideoNonMuxedSourceDescriptor(
val _videoSources: Array,
val _audioSources: Array
): VideoUnMuxedSourceDescriptor(), ISerializedVideoSourceDescriptor {
- @kotlinx.serialization.Transient
override val videoSources: Array get() = _videoSources.map { it }.toTypedArray();
- @kotlinx.serialization.Transient
override val audioSources: Array get() = _audioSources.map { it }.toTypedArray();
};
\ No newline at end of file
diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/DevJSClient.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/DevJSClient.kt
index 9e5ffa06..1b929293 100644
--- a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/DevJSClient.kt
+++ b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/DevJSClient.kt
@@ -1,14 +1,14 @@
package com.futo.platformplayer.api.media.platforms.js
import android.content.Context
-import com.futo.platformplayer.states.StateDeveloper
import com.futo.platformplayer.api.media.models.channels.IPlatformChannel
import com.futo.platformplayer.api.media.models.comments.IPlatformComment
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
import com.futo.platformplayer.api.media.models.contents.IPlatformContentDetails
import com.futo.platformplayer.api.media.structures.IPager
import com.futo.platformplayer.states.StateApp
-import java.util.*
+import com.futo.platformplayer.states.StateDeveloper
+import java.util.UUID
class DevJSClient : JSClient {
override val id: String
@@ -26,8 +26,8 @@ class DevJSClient : JSClient {
_captcha = captcha;
this.devID = devID ?: UUID.randomUUID().toString().substring(0, 5);
- onCaptchaException.subscribe { client, captcha ->
- StateApp.instance.handleCaptchaException(client, captcha);
+ onCaptchaException.subscribe { client, c ->
+ StateApp.instance.handleCaptchaException(client, c);
}
}
//TODO: Misisng auth/captcha pass on purpose?
@@ -37,8 +37,8 @@ class DevJSClient : JSClient {
_captcha = captcha;
this.devID = devID ?: UUID.randomUUID().toString().substring(0, 5);
- onCaptchaException.subscribe { client, captcha ->
- StateApp.instance.handleCaptchaException(client, captcha);
+ onCaptchaException.subscribe { client, c ->
+ StateApp.instance.handleCaptchaException(client, c);
}
}
diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/JSClient.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/JSClient.kt
index b3450002..f5f72686 100644
--- a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/JSClient.kt
+++ b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/JSClient.kt
@@ -4,12 +4,9 @@ import android.content.Context
import com.caoccao.javet.values.V8Value
import com.caoccao.javet.values.primitive.V8ValueBoolean
import com.caoccao.javet.values.primitive.V8ValueInteger
-import com.caoccao.javet.values.primitive.V8ValueNull
import com.caoccao.javet.values.primitive.V8ValueString
import com.caoccao.javet.values.reference.V8ValueArray
import com.caoccao.javet.values.reference.V8ValueObject
-import com.futo.platformplayer.states.StatePlatform
-import com.futo.platformplayer.states.StatePlugins
import com.futo.platformplayer.api.media.IPlatformClient
import com.futo.platformplayer.api.media.PlatformClientCapabilities
import com.futo.platformplayer.api.media.models.PlatformAuthorLink
@@ -23,23 +20,38 @@ import com.futo.platformplayer.api.media.models.live.ILiveChatWindowDescriptor
import com.futo.platformplayer.api.media.models.live.IPlatformLiveEvent
import com.futo.platformplayer.api.media.models.playback.IPlaybackTracker
import com.futo.platformplayer.api.media.models.playlists.IPlatformPlaylistDetails
-import com.futo.platformplayer.api.media.platforms.js.internal.*
-import com.futo.platformplayer.api.media.platforms.js.models.*
+import com.futo.platformplayer.api.media.platforms.js.internal.JSCallDocs
+import com.futo.platformplayer.api.media.platforms.js.internal.JSDocs
+import com.futo.platformplayer.api.media.platforms.js.internal.JSDocsParameter
+import com.futo.platformplayer.api.media.platforms.js.internal.JSHttpClient
+import com.futo.platformplayer.api.media.platforms.js.internal.JSOptional
+import com.futo.platformplayer.api.media.platforms.js.internal.JSParameterDocs
+import com.futo.platformplayer.api.media.platforms.js.models.IJSContentDetails
+import com.futo.platformplayer.api.media.platforms.js.models.JSChannel
+import com.futo.platformplayer.api.media.platforms.js.models.JSChannelPager
+import com.futo.platformplayer.api.media.platforms.js.models.JSChapter
+import com.futo.platformplayer.api.media.platforms.js.models.JSComment
+import com.futo.platformplayer.api.media.platforms.js.models.JSCommentPager
+import com.futo.platformplayer.api.media.platforms.js.models.JSContentPager
+import com.futo.platformplayer.api.media.platforms.js.models.JSLiveChatWindowDescriptor
+import com.futo.platformplayer.api.media.platforms.js.models.JSLiveEventPager
+import com.futo.platformplayer.api.media.platforms.js.models.JSPlaybackTracker
+import com.futo.platformplayer.api.media.platforms.js.models.JSPlaylistDetails
import com.futo.platformplayer.api.media.structures.EmptyPager
import com.futo.platformplayer.api.media.structures.IPager
import com.futo.platformplayer.constructs.Event1
import com.futo.platformplayer.constructs.Event2
import com.futo.platformplayer.engine.V8Plugin
import com.futo.platformplayer.engine.exceptions.PluginEngineException
-import com.futo.platformplayer.engine.exceptions.PluginEngineStoppedException
import com.futo.platformplayer.engine.exceptions.ScriptCaptchaRequiredException
import com.futo.platformplayer.engine.exceptions.ScriptImplementationException
-import com.futo.platformplayer.engine.exceptions.ScriptLoginRequiredException
import com.futo.platformplayer.engine.exceptions.ScriptValidationException
import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.models.ImageVariable
import com.futo.platformplayer.states.AnnouncementType
import com.futo.platformplayer.states.StateAnnouncement
+import com.futo.platformplayer.states.StatePlatform
+import com.futo.platformplayer.states.StatePlugins
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import java.time.OffsetDateTime
@@ -50,7 +62,7 @@ open class JSClient : IPlatformClient {
val config: SourcePluginConfig;
protected val _context: Context;
private val _plugin: V8Plugin;
- private val plugin: V8Plugin get() = _plugin ?: throw IllegalStateException("Client not enabled");
+ private val plugin: V8Plugin get() = _plugin
var descriptor: SourcePluginDescriptor
private set;
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 2d39a2a5..b35f9ade 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
@@ -5,9 +5,8 @@ import com.futo.platformplayer.SignatureProvider
import com.futo.platformplayer.api.media.Serializer
import com.futo.platformplayer.engine.IV8PluginConfig
import com.futo.platformplayer.states.StatePlugins
-import kotlinx.serialization.decodeFromString
import java.net.URL
-import java.util.*
+import java.util.UUID
@kotlinx.serialization.Serializable
class SourcePluginConfig(
@@ -149,7 +148,6 @@ class SourcePluginConfig(
val warningDialog: String? = null,
val options: List? = null
) {
- @kotlinx.serialization.Transient
val variableOrName: String get() = variable ?: name;
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/SourcePluginDescriptor.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/SourcePluginDescriptor.kt
index 8bcb51b3..5833295e 100644
--- a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/SourcePluginDescriptor.kt
+++ b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/SourcePluginDescriptor.kt
@@ -2,7 +2,6 @@ package com.futo.platformplayer.api.media.platforms.js
import com.futo.platformplayer.R
import com.futo.platformplayer.constructs.Event0
-import com.futo.platformplayer.serializers.FlexibleBooleanSerializer
import com.futo.platformplayer.views.fields.DropdownFieldOptions
import com.futo.platformplayer.views.fields.FieldForm
import com.futo.platformplayer.views.fields.FormField
@@ -107,9 +106,9 @@ class SourcePluginDescriptor {
fun loadDefaults(config: SourcePluginConfig) {
if(tabEnabled.enableHome == null)
- tabEnabled.enableHome = config.enableInHome ?: true;
+ tabEnabled.enableHome = config.enableInHome
if(tabEnabled.enableSearch == null)
- tabEnabled.enableSearch = config.enableInSearch ?: true;
+ tabEnabled.enableSearch = config.enableInSearch
}
}
diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/internal/JSHttpClient.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/internal/JSHttpClient.kt
index af7291ae..05df143f 100644
--- a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/internal/JSHttpClient.kt
+++ b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/internal/JSHttpClient.kt
@@ -1,7 +1,5 @@
package com.futo.platformplayer.api.media.platforms.js.internal
-import android.net.Uri
-import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.api.http.ManagedHttpClient
import com.futo.platformplayer.api.media.platforms.js.JSClient
import com.futo.platformplayer.api.media.platforms.js.SourceAuth
@@ -47,10 +45,7 @@ class JSHttpClient : ManagedHttpClient {
override fun clone(): ManagedHttpClient {
val newClient = JSHttpClient(_jsClient, _auth);
- newClient._currentCookieMap = if(_currentCookieMap != null)
- HashMap(_currentCookieMap.toList().associate { Pair(it.first, HashMap(it.second)) })
- else
- hashMapOf();
+ newClient._currentCookieMap = HashMap(_currentCookieMap.toList().associate { Pair(it.first, HashMap(it.second)) })
return newClient;
}
@@ -69,10 +64,10 @@ class JSHttpClient : ManagedHttpClient {
}
if(doApplyCookies) {
- if (!_currentCookieMap.isNullOrEmpty()) {
+ if (_currentCookieMap.isNotEmpty()) {
val cookiesToApply = hashMapOf();
- synchronized(_currentCookieMap!!) {
- for(cookie in _currentCookieMap!!
+ synchronized(_currentCookieMap) {
+ for(cookie in _currentCookieMap
.filter { domain.matchesDomain(it.key) }
.flatMap { it.value.toList() })
cookiesToApply[cookie.first] = cookie.second;
@@ -92,11 +87,11 @@ class JSHttpClient : ManagedHttpClient {
}
if(_jsClient != null)
- _jsClient?.validateUrlOrThrow(request.url.toString());
+ _jsClient.validateUrlOrThrow(request.url.toString());
else if (_jsConfig != null && !_jsConfig.isUrlAllowed(request.url.toString()))
throw ScriptImplementationException(_jsConfig, "Attempted to access non-whitelisted url: ${request.url.toString()}\nAdd it to your config");
- return newBuilder?.let { it.build() } ?: request;
+ return newBuilder?.build() ?: request;
}
override fun afterRequest(resp: okhttp3.Response): okhttp3.Response {
@@ -107,84 +102,48 @@ class JSHttpClient : ManagedHttpClient {
"." + domainParts.drop(domainParts.size - 2).joinToString(".");
for (header in resp.headers) {
if ((_auth != null || _currentCookieMap.isNotEmpty()) && header.first.lowercase() == "set-cookie") {
- //val newCookies = cookieStringToMap(header.second.split("; "));
val cookie = cookieStringToPair(header.second);
- //for (cookie in newCookies) {
- var cookieValue = cookie.second;
- var domainToUse = domain;
+ var cookieValue = cookie.second;
+ var domainToUse = domain;
- if (!cookie.first.isNullOrEmpty() && !cookie.second.isNullOrEmpty()) {
- val cookieParts = cookie.second.split(";");
- if (cookieParts.size == 0)
- continue;
- cookieValue = cookieParts[0].trim();
+ if (cookie.first.isNotEmpty() && cookie.second.isNotEmpty()) {
+ val cookieParts = cookie.second.split(";");
+ if (cookieParts.size == 0)
+ continue;
+ cookieValue = cookieParts[0].trim();
- val cookieVariables = cookieParts.drop(1).map {
- val splitIndex = it.indexOf("=");
- if (splitIndex < 0)
- return@map Pair(it.trim().lowercase(), "");
- return@map Pair(
- it.substring(0, splitIndex).lowercase().trim(),
- it.substring(splitIndex + 1).trim()
- );
- }.toMap();
- domainToUse = if (cookieVariables.containsKey("domain"))
- cookieVariables["domain"]!!.lowercase();
- else defaultCookieDomain;
- }
+ val cookieVariables = cookieParts.drop(1).map {
+ val splitIndex = it.indexOf("=");
+ if (splitIndex < 0)
+ return@map Pair(it.trim().lowercase(), "");
+ return@map Pair(
+ it.substring(0, splitIndex).lowercase().trim(),
+ it.substring(splitIndex + 1).trim()
+ );
+ }.toMap();
+ domainToUse = if (cookieVariables.containsKey("domain"))
+ cookieVariables["domain"]!!.lowercase();
+ else defaultCookieDomain;
+ }
- val cookieMap = if (_currentCookieMap!!.containsKey(domainToUse))
- _currentCookieMap!![domainToUse]!!;
- else {
- val newMap = hashMapOf();
- _currentCookieMap!!.put(domainToUse, newMap)
- newMap;
- }
- if(cookieMap.containsKey(cookie.first) || doAllowNewCookies)
- cookieMap.put(cookie.first, cookieValue);
- //}
+ val cookieMap = if (_currentCookieMap.containsKey(domainToUse))
+ _currentCookieMap[domainToUse]!!;
+ else {
+ val newMap = hashMapOf();
+ _currentCookieMap[domainToUse] = newMap
+ newMap;
+ }
+ if(cookieMap.containsKey(cookie.first) || doAllowNewCookies)
+ cookieMap[cookie.first] = cookieValue;
}
}
}
return resp;
}
-
- private fun cookieStringToMap(parts: List): Map {
- val map = hashMapOf();
- for(cookie in parts) {
- val pair = cookieStringToPair(cookie)
- map.put(pair.first, pair.second);
- }
- return map;
- }
private fun cookieStringToPair(cookie: String): Pair {
val cookieKey = cookie.substring(0, cookie.indexOf("="));
val cookieVal = cookie.substring(cookie.indexOf("=") + 1);
return Pair(cookieKey.trim(), cookieVal.trim());
}
-
- //Prints out code for test reproduction..
- fun printTestCode(url: String, body: ByteArray?, headers: Map, cookieString: String, allHeaders: Map? = null) {
- var code = "Code: \n";
- code += "\nurl = \"${url}\";";
- if(body != null)
- code += "\nbody = \"${String(body).replace("\"", "\\\"")}\";";
- if(headers != null)
- for(header in headers) {
- code += "\nclient.Headers.Add(\"${header.key}\", \"${header.value}\");";
- }
- if(cookieString != null)
- code += "\nclient.Headers.Add(\"Cookie\", \"${cookieString}\");";
-
- if(allHeaders != null) {
- code += "\n//OTHER HEADERS:"
- for (header in allHeaders) {
- code += "\nclient.Headers.Add(\"${header.key}\", \"${header.value}\");";
- }
- }
-
- Logger.i("Testing", code);
- }
-
}
\ No newline at end of file
diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSSource.kt
index c4cae894..fb7f05dd 100644
--- a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSSource.kt
+++ b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSSource.kt
@@ -1,3 +1,5 @@
+@file:Suppress("DEPRECATION")
+
package com.futo.platformplayer.api.media.platforms.js.models.sources
import com.caoccao.javet.values.V8Value
diff --git a/app/src/main/java/com/futo/platformplayer/api/media/structures/IAsyncPager.kt b/app/src/main/java/com/futo/platformplayer/api/media/structures/IAsyncPager.kt
index 9a9ebd65..34900c86 100644
--- a/app/src/main/java/com/futo/platformplayer/api/media/structures/IAsyncPager.kt
+++ b/app/src/main/java/com/futo/platformplayer/api/media/structures/IAsyncPager.kt
@@ -1,7 +1,5 @@
package com.futo.platformplayer.api.media.structures
-import kotlinx.coroutines.CoroutineScope
-
/**
* A Pager interface that implements a suspended manner of nextPage
*/
diff --git a/app/src/main/java/com/futo/platformplayer/api/media/structures/IRefreshPager.kt b/app/src/main/java/com/futo/platformplayer/api/media/structures/IRefreshPager.kt
index 390895bd..34a9e41a 100644
--- a/app/src/main/java/com/futo/platformplayer/api/media/structures/IRefreshPager.kt
+++ b/app/src/main/java/com/futo/platformplayer/api/media/structures/IRefreshPager.kt
@@ -1,6 +1,5 @@
package com.futo.platformplayer.api.media.structures
-import com.futo.platformplayer.api.media.models.contents.IPlatformContent
import com.futo.platformplayer.constructs.Event1
/**
diff --git a/app/src/main/java/com/futo/platformplayer/api/media/structures/MultiRefreshPager.kt b/app/src/main/java/com/futo/platformplayer/api/media/structures/MultiRefreshPager.kt
index 10f76d6e..ba98a8d1 100644
--- a/app/src/main/java/com/futo/platformplayer/api/media/structures/MultiRefreshPager.kt
+++ b/app/src/main/java/com/futo/platformplayer/api/media/structures/MultiRefreshPager.kt
@@ -5,6 +5,7 @@ import com.futo.platformplayer.api.media.structures.ReusablePager.Companion.asRe
import com.futo.platformplayer.constructs.Event1
import com.futo.platformplayer.logging.Logger
import kotlinx.coroutines.Deferred
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.runBlocking
/**
@@ -25,6 +26,7 @@ abstract class MultiRefreshPager: IRefreshPager, IPager {
private val _pending: MutableList?>>;
+ @OptIn(ExperimentalCoroutinesApi::class)
constructor(pagers: List>, pendingPagers: List?>>, placeholderPagers: List>? = null) {
_pagersReusable = pagers.map { ReusablePager(it) }.toMutableList();
_totalPagers = pagers.size + pendingPagers.size;
@@ -100,7 +102,7 @@ abstract class MultiRefreshPager: IRefreshPager, IPager {
}
private fun getCurrentSubPagers(): List> {
- val reusableWindows = _pagersReusable.map { it.getWindow() as IPager };
+ val reusableWindows = _pagersReusable.map { it.getWindow() };
val placeholderWindows = synchronized(_pending) {
_placeHolderPagersPaired.filter { _pending.contains(it.key) }.values
}
diff --git a/app/src/main/java/com/futo/platformplayer/api/media/structures/SingleAsyncItemPager.kt b/app/src/main/java/com/futo/platformplayer/api/media/structures/SingleAsyncItemPager.kt
index beb841e8..592ce2e5 100644
--- a/app/src/main/java/com/futo/platformplayer/api/media/structures/SingleAsyncItemPager.kt
+++ b/app/src/main/java/com/futo/platformplayer/api/media/structures/SingleAsyncItemPager.kt
@@ -100,7 +100,7 @@ class SingleAsyncItemPager {
private fun fillDeferredUntil(i: Int): Int {
val startPos = _requestedPageItems.size;
- for(i in _requestedPageItems.size..i) {
+ for(v in _requestedPageItems.size..i) {
_requestedPageItems.add(CompletableDeferred());
}
return startPos;
diff --git a/app/src/main/java/com/futo/platformplayer/casting/ChomecastCastingDevice.kt b/app/src/main/java/com/futo/platformplayer/casting/ChomecastCastingDevice.kt
index b0335d6d..09f4fbab 100644
--- a/app/src/main/java/com/futo/platformplayer/casting/ChomecastCastingDevice.kt
+++ b/app/src/main/java/com/futo/platformplayer/casting/ChomecastCastingDevice.kt
@@ -2,13 +2,17 @@ package com.futo.platformplayer.casting
import android.os.Looper
import android.util.Log
-import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.getConnectedSocket
+import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.models.CastingDeviceInfo
import com.futo.platformplayer.protos.ChromeCast
import com.futo.platformplayer.toHexString
import com.futo.platformplayer.toInetAddress
-import kotlinx.coroutines.*
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.isActive
+import kotlinx.coroutines.launch
import org.json.JSONObject
import java.io.DataInputStream
import java.io.DataOutputStream
@@ -502,10 +506,10 @@ class ChromecastCastingDevice : CastingDevice {
}
val volume = status.getJSONObject("volume");
- val volumeControlType = volume.getString("controlType");
+ //val volumeControlType = volume.getString("controlType");
val volumeLevel = volume.getString("level").toDouble();
val volumeMuted = volume.getBoolean("muted");
- val volumeStepInterval = volume.getString("stepInterval").toFloat();
+ //val volumeStepInterval = volume.getString("stepInterval").toFloat();
this.volume = if (volumeMuted) 0.0 else volumeLevel;
Logger.i(TAG, "Status update received volume (level: $volumeLevel, muted: $volumeMuted)");
diff --git a/app/src/main/java/com/futo/platformplayer/casting/StateCasting.kt b/app/src/main/java/com/futo/platformplayer/casting/StateCasting.kt
index 39c27308..9ecb7b9d 100644
--- a/app/src/main/java/com/futo/platformplayer/casting/StateCasting.kt
+++ b/app/src/main/java/com/futo/platformplayer/casting/StateCasting.kt
@@ -5,12 +5,23 @@ import android.content.Context
import android.net.Uri
import android.os.Looper
import android.util.Base64
-import com.futo.platformplayer.*
-import com.futo.platformplayer.activities.MainActivity
+import com.futo.platformplayer.BuildConfig
+import com.futo.platformplayer.UIDialogs
import com.futo.platformplayer.api.http.ManagedHttpClient
import com.futo.platformplayer.api.http.server.ManagedHttpServer
-import com.futo.platformplayer.api.http.server.handlers.*
-import com.futo.platformplayer.api.media.models.streams.sources.*
+import com.futo.platformplayer.api.http.server.handlers.HttpConstantHandler
+import com.futo.platformplayer.api.http.server.handlers.HttpFileHandler
+import com.futo.platformplayer.api.http.server.handlers.HttpFuntionHandler
+import com.futo.platformplayer.api.http.server.handlers.HttpProxyHandler
+import com.futo.platformplayer.api.media.models.streams.sources.IAudioSource
+import com.futo.platformplayer.api.media.models.streams.sources.IAudioUrlSource
+import com.futo.platformplayer.api.media.models.streams.sources.IHLSManifestAudioSource
+import com.futo.platformplayer.api.media.models.streams.sources.IHLSManifestSource
+import com.futo.platformplayer.api.media.models.streams.sources.IVideoSource
+import com.futo.platformplayer.api.media.models.streams.sources.IVideoUrlSource
+import com.futo.platformplayer.api.media.models.streams.sources.LocalAudioSource
+import com.futo.platformplayer.api.media.models.streams.sources.LocalSubtitleSource
+import com.futo.platformplayer.api.media.models.streams.sources.LocalVideoSource
import com.futo.platformplayer.api.media.models.subtitles.ISubtitleSource
import com.futo.platformplayer.api.media.models.video.IPlatformVideoDetails
import com.futo.platformplayer.builders.DashBuilder
@@ -21,18 +32,20 @@ import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.models.CastingDeviceInfo
import com.futo.platformplayer.parsers.HLS
import com.futo.platformplayer.states.StateApp
-import kotlinx.coroutines.*
+import com.futo.platformplayer.stores.CastingDeviceInfoStorage
+import com.futo.platformplayer.stores.FragmentedStorage
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.json.Json
import java.net.InetAddress
-import java.util.*
+import java.util.UUID
import javax.jmdns.JmDNS
import javax.jmdns.ServiceEvent
import javax.jmdns.ServiceListener
-import kotlin.collections.HashMap
-import com.futo.platformplayer.stores.CastingDeviceInfoStorage
-import com.futo.platformplayer.stores.FragmentedStorage
-import kotlinx.serialization.Serializable
-import kotlinx.serialization.decodeFromString
-import kotlinx.serialization.json.Json
import javax.jmdns.ServiceTypeListener
class StateCasting {
@@ -213,7 +226,7 @@ class StateCasting {
}
}
_castServer.start();
- enableDeveloper(context.contentResolver, true);
+ enableDeveloper(true);
Logger.i(TAG, "CastingService started.");
}
@@ -1077,7 +1090,6 @@ class StateCasting {
CastProtocolType.FCAST -> {
FCastCastingDevice(deviceInfo);
}
- else -> throw Exception("${deviceInfo.type} is not a valid casting protocol")
}
}
@@ -1172,7 +1184,7 @@ class StateCasting {
invokeEvents?.let { _scopeMain.launch { it(); }; };
}
- fun enableDeveloper(contentResolver: ContentResolver, enableDev: Boolean){
+ fun enableDeveloper(enableDev: Boolean){
_castServer.removeAllHandlers("dev");
if(enableDev) {
_castServer.addHandler(HttpFuntionHandler("GET", "/dashPlayer") { context ->
diff --git a/app/src/main/java/com/futo/platformplayer/constructs/BatchedTaskHandler.kt b/app/src/main/java/com/futo/platformplayer/constructs/BatchedTaskHandler.kt
index f656fc40..e7714e02 100644
--- a/app/src/main/java/com/futo/platformplayer/constructs/BatchedTaskHandler.kt
+++ b/app/src/main/java/com/futo/platformplayer/constructs/BatchedTaskHandler.kt
@@ -1,8 +1,10 @@
package com.futo.platformplayer.constructs
-import android.provider.Settings.Global
-import com.futo.platformplayer.states.StateApp
-import kotlinx.coroutines.*
+import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Deferred
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.async
class BatchedTaskHandler {
@@ -25,14 +27,14 @@ class BatchedTaskHandler {
}
fun execute(para : TParameter) : Deferred {
- var result: TResult? = null;
+ var result: TResult?;
var taskResult: Deferred? = null;
synchronized(_batchLock) {
result = _taskGetCache?.invoke(para);
if(result == null) {
taskResult = _batchRequest[para];
- if(taskResult?.isCancelled ?: false) {
+ if(taskResult?.isCancelled == true) {
_batchRequest.remove(para);
taskResult = null;
}
diff --git a/app/src/main/java/com/futo/platformplayer/constructs/TaskHandler.kt b/app/src/main/java/com/futo/platformplayer/constructs/TaskHandler.kt
index 3036f667..b590fe6e 100644
--- a/app/src/main/java/com/futo/platformplayer/constructs/TaskHandler.kt
+++ b/app/src/main/java/com/futo/platformplayer/constructs/TaskHandler.kt
@@ -2,7 +2,11 @@ package com.futo.platformplayer.constructs
import android.util.Log
import com.futo.platformplayer.logging.Logger
-import kotlinx.coroutines.*
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
class TaskHandler {
private val TAG = "TaskHandler"
@@ -16,7 +20,7 @@ class TaskHandler {
private val _task: suspend ((parameter: TParameter) -> TResult);
constructor(claz : Class, scope: ()->CoroutineScope) {
- _task = { claz.newInstance() };
+ _task = { claz.getDeclaredConstructor().newInstance() };
_scope = scope;
_dispatcher = Dispatchers.IO;
}
@@ -32,7 +36,7 @@ class TaskHandler {
}
inline fun exception(noinline cb : (T)->Unit) : TaskHandler {
- onError.subscribeConditional { ex, para ->
+ onError.subscribeConditional { ex, _ ->
if(ex is T) {
cb(ex);
return@subscribeConditional true;
@@ -76,8 +80,7 @@ class TaskHandler {
try {
onSuccess.emit(result);
handled = true;
- }
- catch (e: Throwable) {
+ } catch (e: Throwable) {
Logger.w(TAG, "Handled exception in TaskHandler onSuccess.", e);
onError.emit(e, parameter);
handled = true;
diff --git a/app/src/main/java/com/futo/platformplayer/debug/Stopwatch.kt b/app/src/main/java/com/futo/platformplayer/debug/Stopwatch.kt
index 0924d19b..fa0257a5 100644
--- a/app/src/main/java/com/futo/platformplayer/debug/Stopwatch.kt
+++ b/app/src/main/java/com/futo/platformplayer/debug/Stopwatch.kt
@@ -1,9 +1,10 @@
package com.futo.platformplayer.debug
-import com.google.android.exoplayer2.util.Log
+import com.futo.platformplayer.logging.Logger
+
class Stopwatch {
- var startTime = System.nanoTime()
+ private var startTime = System.nanoTime()
val elapsedMs: Double get() {
val now = System.nanoTime()
@@ -19,7 +20,7 @@ class Stopwatch {
val now = System.nanoTime()
val diff = now - startTime
val diffMs = diff / 1000000.0
- Log.d(tag, "STOPWATCH $message ${diffMs}ms")
+ Logger.i(tag, "STOPWATCH $message ${diffMs}ms")
startTime = now
return diff
}
diff --git a/app/src/main/java/com/futo/platformplayer/developer/DeveloperEndpoints.kt b/app/src/main/java/com/futo/platformplayer/developer/DeveloperEndpoints.kt
index 92a48ebf..0245d9bc 100644
--- a/app/src/main/java/com/futo/platformplayer/developer/DeveloperEndpoints.kt
+++ b/app/src/main/java/com/futo/platformplayer/developer/DeveloperEndpoints.kt
@@ -80,11 +80,11 @@ class DeveloperEndpoints(private val context: Context) {
//Files
@HttpGET("/dev", "text/html")
- val devTestHtml = StateAssets.readAsset(context, "devportal/index.html", true);
+ val devTestHtml = StateAssets.readAsset(context, "devportal/index.html");
@HttpGET("/source.js", "application/javascript")
- val devSourceJS = StateAssets.readAsset(context, "scripts/source.js", true);
+ val devSourceJS = StateAssets.readAsset(context, "scripts/source.js");
@HttpGET("/dev_bridge.js", "application/javascript")
- val devBridgeJS = StateAssets.readAsset(context, "devportal/dev_bridge.js", true);
+ val devBridgeJS = StateAssets.readAsset(context, "devportal/dev_bridge.js");
@HttpGET("/source_docs.json", "application/json")
val devSourceDocsJson = Json.encodeToString(JSClient.getJSDocs());
@HttpGET("/source_docs.js", "application/javascript")
@@ -98,7 +98,7 @@ class DeveloperEndpoints(private val context: Context) {
//@HttpGET("/dependencies/vuetify.min.css", "text/css")
//val depVuetifyCss = StateAssets.readAsset(context, "devportal/dependencies/vuetify.min.css", true);
@HttpGET("/dependencies/FutoMainLogo.svg", "image/svg+xml")
- val depFutoLogo = StateAssets.readAsset(context, "devportal/dependencies/FutoMainLogo.svg", true);
+ val depFutoLogo = StateAssets.readAsset(context, "devportal/dependencies/FutoMainLogo.svg");
@HttpGET("/reference_plugin.d.ts", "text/plain")
fun devSourceTSWithRefs(httpContext: HttpContext) {
@@ -107,7 +107,7 @@ class DeveloperEndpoints(private val context: Context) {
builder.appendLine("//Reference Scriptfile");
builder.appendLine("//Intended exclusively for auto-complete in your IDE, not for execution");
- builder.appendLine(StateAssets.readAsset(context, "devportal/plugin.d.ts", true));
+ builder.appendLine(StateAssets.readAsset(context, "devportal/plugin.d.ts"));
httpContext.respondCode(200, builder.toString(), "text/plain");
}
@@ -119,7 +119,7 @@ class DeveloperEndpoints(private val context: Context) {
builder.appendLine("//Reference Scriptfile");
builder.appendLine("//Intended exclusively for auto-complete in your IDE, not for execution");
- builder.appendLine(StateAssets.readAsset(context, "scripts/source.js", true));
+ builder.appendLine(StateAssets.readAsset(context, "scripts/source.js"));
for(pack in testPluginOrThrow.getPackages()) {
builder.appendLine();
@@ -194,7 +194,7 @@ class DeveloperEndpoints(private val context: Context) {
context.respondJson(200, testPluginOrThrow.getPackageVariables());
}
catch(ex: Throwable) {
- context.respondCode(500, (ex::class.simpleName + ":" + ex.message) ?: "", "text/plain")
+ context.respondCode(500, (ex::class.simpleName + ":" + ex.message), "text/plain")
}
}
@HttpPOST("/plugin/cleanTestPlugin")
@@ -204,7 +204,7 @@ class DeveloperEndpoints(private val context: Context) {
context.respondCode(200);
}
catch(ex: Throwable) {
- context.respondCode(500, (ex::class.simpleName + ":" + ex.message) ?: "", "text/plain")
+ context.respondCode(500, (ex::class.simpleName + ":" + ex.message), "text/plain")
}
}
@HttpPOST("/plugin/captchaTestPlugin")
@@ -226,7 +226,7 @@ class DeveloperEndpoints(private val context: Context) {
context.respondCode(200, "Captcha started");
}
catch(ex: Throwable) {
- context.respondCode(500, (ex::class.simpleName + ":" + ex.message) ?: "", "text/plain")
+ context.respondCode(500, (ex::class.simpleName + ":" + ex.message), "text/plain")
}
}
@HttpGET("/plugin/loginTestPlugin")
@@ -246,7 +246,7 @@ class DeveloperEndpoints(private val context: Context) {
context.respondCode(200, "Login started");
}
catch(ex: Throwable) {
- context.respondCode(500, (ex::class.simpleName + ":" + ex.message) ?: "", "text/plain")
+ context.respondCode(500, (ex::class.simpleName + ":" + ex.message), "text/plain")
}
}
@HttpGET("/plugin/logoutTestPlugin")
@@ -258,7 +258,7 @@ class DeveloperEndpoints(private val context: Context) {
context.respondCode(200, "Logged out");
}
catch(ex: Throwable) {
- context.respondCode(500, (ex::class.simpleName + ":" + ex.message) ?: "", "text/plain")
+ context.respondCode(500, (ex::class.simpleName + ":" + ex.message), "text/plain")
}
}
@@ -269,7 +269,7 @@ class DeveloperEndpoints(private val context: Context) {
context.respondCode(200, if(isLoggedIn) "true" else "false", "application/json");
}
catch(ex: Throwable) {
- context.respondCode(500, (ex::class.simpleName + ":" + ex.message) ?: "", "text/plain")
+ context.respondCode(500, (ex::class.simpleName + ":" + ex.message), "text/plain")
}
}
@@ -319,7 +319,7 @@ class DeveloperEndpoints(private val context: Context) {
catch(invocation: InvocationTargetException) {
val innerException = invocation.targetException;
Logger.e("DeveloperEndpoints", innerException.message, innerException);
- context.respondCode(500, innerException::class.simpleName + ":" + innerException.message ?: "", "text/plain")
+ context.respondCode(500, innerException::class.simpleName + ":" + innerException.message, "text/plain")
}
catch(ilEx: IllegalArgumentException) {
if(ilEx.message?.contains("does not exist") ?: false) {
@@ -327,12 +327,12 @@ class DeveloperEndpoints(private val context: Context) {
}
else {
Logger.e("DeveloperEndpoints", ilEx.message, ilEx);
- context.respondCode(500, ilEx::class.simpleName + ":" + ilEx.message ?: "", "text/plain")
+ context.respondCode(500, ilEx::class.simpleName + ":" + ilEx.message, "text/plain")
}
}
catch(ex: Throwable) {
Logger.e("DeveloperEndpoints", ex.message, ex);
- context.respondCode(500, ex::class.simpleName + ":" + ex.message ?: "", "text/plain")
+ context.respondCode(500, ex::class.simpleName + ":" + ex.message, "text/plain")
}
}
@HttpGET("/plugin/remoteProp")
@@ -362,12 +362,12 @@ class DeveloperEndpoints(private val context: Context) {
}
else {
Logger.e("DeveloperEndpoints", ilEx.message, ilEx);
- context.respondCode(500, ilEx::class.simpleName + ":" + ilEx.message ?: "", "text/plain")
+ context.respondCode(500, ilEx::class.simpleName + ":" + ilEx.message, "text/plain")
}
}
catch(ex: Throwable) {
Logger.e("DeveloperEndpoints", ex.message, ex);
- context.respondCode(500, ex::class.simpleName + ":" + ex.message ?: "", "text/plain")
+ context.respondCode(500, ex::class.simpleName + ":" + ex.message, "text/plain")
}
}
@@ -398,7 +398,7 @@ class DeveloperEndpoints(private val context: Context) {
fun pluginLoadDevPlugin(context: HttpContext) {
val config = context.readContentJson()
try {
- val script = _client.get(config.absoluteScriptUrl!!);
+ val script = _client.get(config.absoluteScriptUrl);
if(!script.isOk)
throw IllegalStateException("URL ${config.scriptUrl} return code ${script.code}");
if(script.body == null)
@@ -409,7 +409,7 @@ class DeveloperEndpoints(private val context: Context) {
}
catch(ex: Exception) {
Logger.e("DeveloperEndpoints", ex.message, ex);
- context.respondCode(500, ex::class.simpleName + ":" + ex.message ?: "", "text/plain")
+ context.respondCode(500, ex::class.simpleName + ":" + ex.message, "text/plain")
}
}
diff --git a/app/src/main/java/com/futo/platformplayer/dialogs/AutoUpdateDialog.kt b/app/src/main/java/com/futo/platformplayer/dialogs/AutoUpdateDialog.kt
index b8e15806..3f7fda29 100644
--- a/app/src/main/java/com/futo/platformplayer/dialogs/AutoUpdateDialog.kt
+++ b/app/src/main/java/com/futo/platformplayer/dialogs/AutoUpdateDialog.kt
@@ -1,7 +1,9 @@
package com.futo.platformplayer.dialogs
import android.app.AlertDialog
-import android.app.PendingIntent.*
+import android.app.PendingIntent.FLAG_MUTABLE
+import android.app.PendingIntent.FLAG_UPDATE_CURRENT
+import android.app.PendingIntent.getBroadcast
import android.content.Context
import android.content.Intent
import android.content.pm.PackageInstaller
@@ -14,12 +16,18 @@ import android.widget.Button
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
-import com.futo.platformplayer.*
-import com.futo.platformplayer.receivers.InstallReceiver
+import com.futo.platformplayer.R
+import com.futo.platformplayer.Settings
+import com.futo.platformplayer.UIDialogs
import com.futo.platformplayer.api.http.ManagedHttpClient
+import com.futo.platformplayer.copyToOutputStream
import com.futo.platformplayer.logging.Logger
+import com.futo.platformplayer.receivers.InstallReceiver
import com.futo.platformplayer.states.StateUpdate
-import kotlinx.coroutines.*
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import java.io.File
import java.io.InputStream
@@ -100,7 +108,7 @@ class AutoUpdateDialog(context: Context?) : AlertDialog(context) {
window?.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
_text.text = context.resources.getText(R.string.downloading_update);
- (_updateSpinner?.drawable as Animatable?)?.start();
+ (_updateSpinner.drawable as Animatable?)?.start();
GlobalScope.launch(Dispatchers.IO) {
var inputStream: InputStream? = null;
@@ -193,7 +201,7 @@ class AutoUpdateDialog(context: Context?) : AlertDialog(context) {
setCancelable(true);
setCanceledOnTouchOutside(true);
_buttonClose.visibility = View.VISIBLE;
- (_updateSpinner?.drawable as Animatable?)?.stop();
+ (_updateSpinner.drawable as Animatable?)?.stop();
if (result == null || result.isBlank()) {
_updateSpinner.setImageResource(R.drawable.ic_update_success_251dp);
diff --git a/app/src/main/java/com/futo/platformplayer/dialogs/ImportDialog.kt b/app/src/main/java/com/futo/platformplayer/dialogs/ImportDialog.kt
index 73995003..76c15ae9 100644
--- a/app/src/main/java/com/futo/platformplayer/dialogs/ImportDialog.kt
+++ b/app/src/main/java/com/futo/platformplayer/dialogs/ImportDialog.kt
@@ -7,8 +7,8 @@ import android.graphics.drawable.Animatable
import android.os.Bundle
import android.text.Spannable
import android.text.SpannableString
-import android.text.style.ForegroundColorSpan
import android.text.method.ScrollingMovementMethod
+import android.text.style.ForegroundColorSpan
import android.view.LayoutInflater
import android.view.View
import android.view.WindowManager
@@ -17,12 +17,16 @@ import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
-import com.futo.platformplayer.*
+import com.futo.platformplayer.R
+import com.futo.platformplayer.UIDialogs
import com.futo.platformplayer.api.media.exceptions.NoPlatformClientException
+import com.futo.platformplayer.assume
import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.states.StateApp
import com.futo.platformplayer.stores.v2.ManagedStore
-import kotlinx.coroutines.*
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
class ImportDialog : AlertDialog {
companion object {
@@ -99,7 +103,6 @@ class ImportDialog : AlertDialog {
_textProgress = findViewById(R.id.text_progress);
_updateSpinner = findViewById(R.id.update_spinner);
- val toMigrateCount = _store.getMissingReconstructionCount();
_import_type_text.text = _store.name;
_import_name_text.text = _name;
diff --git a/app/src/main/java/com/futo/platformplayer/dialogs/ProgressDialog.kt b/app/src/main/java/com/futo/platformplayer/dialogs/ProgressDialog.kt
index fea26588..c9a579b6 100644
--- a/app/src/main/java/com/futo/platformplayer/dialogs/ProgressDialog.kt
+++ b/app/src/main/java/com/futo/platformplayer/dialogs/ProgressDialog.kt
@@ -1,29 +1,13 @@
package com.futo.platformplayer.dialogs
import android.app.AlertDialog
-import android.app.PendingIntent.*
import android.content.Context
-import android.content.Intent
-import android.content.pm.PackageInstaller
import android.graphics.drawable.Animatable
import android.os.Bundle
-import android.util.Log
import android.view.LayoutInflater
-import android.view.View
-import android.widget.Button
import android.widget.ImageView
-import android.widget.LinearLayout
import android.widget.TextView
-import com.futo.platformplayer.receivers.InstallReceiver
import com.futo.platformplayer.R
-import com.futo.platformplayer.Settings
-import com.futo.platformplayer.activities.MainActivity
-import com.futo.platformplayer.api.http.ManagedHttpClient
-import com.futo.platformplayer.states.StateApp
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.GlobalScope
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
class ProgressDialog : AlertDialog {
companion object {
@@ -50,7 +34,7 @@ class ProgressDialog : AlertDialog {
setCancelable(false);
setCanceledOnTouchOutside(false);
_text.text = "";
- (_updateSpinner?.drawable as Animatable?)?.start();
+ (_updateSpinner.drawable as Animatable?)?.start();
_handler(this);
}
diff --git a/app/src/main/java/com/futo/platformplayer/downloads/VideoDownload.kt b/app/src/main/java/com/futo/platformplayer/downloads/VideoDownload.kt
index 048e36d3..7f2b20ee 100644
--- a/app/src/main/java/com/futo/platformplayer/downloads/VideoDownload.kt
+++ b/app/src/main/java/com/futo/platformplayer/downloads/VideoDownload.kt
@@ -6,13 +6,20 @@ import com.arthenica.ffmpegkit.FFmpegKit
import com.arthenica.ffmpegkit.ReturnCode
import com.arthenica.ffmpegkit.StatisticsCallback
import com.futo.platformplayer.Settings
-import com.futo.platformplayer.logging.Logger
-import com.futo.platformplayer.states.StateDownloads
-import com.futo.platformplayer.states.StatePlatform
import com.futo.platformplayer.api.http.ManagedHttpClient
import com.futo.platformplayer.api.media.PlatformID
import com.futo.platformplayer.api.media.models.streams.VideoUnMuxedSourceDescriptor
-import com.futo.platformplayer.api.media.models.streams.sources.*
+import com.futo.platformplayer.api.media.models.streams.sources.AudioUrlSource
+import com.futo.platformplayer.api.media.models.streams.sources.IAudioSource
+import com.futo.platformplayer.api.media.models.streams.sources.IAudioUrlSource
+import com.futo.platformplayer.api.media.models.streams.sources.IHLSManifestSource
+import com.futo.platformplayer.api.media.models.streams.sources.IVideoSource
+import com.futo.platformplayer.api.media.models.streams.sources.IVideoUrlSource
+import com.futo.platformplayer.api.media.models.streams.sources.LocalAudioSource
+import com.futo.platformplayer.api.media.models.streams.sources.LocalSubtitleSource
+import com.futo.platformplayer.api.media.models.streams.sources.LocalVideoSource
+import com.futo.platformplayer.api.media.models.streams.sources.SubtitleRawSource
+import com.futo.platformplayer.api.media.models.streams.sources.VideoUrlSource
import com.futo.platformplayer.api.media.models.streams.sources.other.IStreamMetaDataSource
import com.futo.platformplayer.api.media.models.video.IPlatformVideo
import com.futo.platformplayer.api.media.models.video.IPlatformVideoDetails
@@ -24,8 +31,11 @@ import com.futo.platformplayer.hasAnySource
import com.futo.platformplayer.helpers.FileHelper.Companion.sanitizeFileName
import com.futo.platformplayer.helpers.VideoHelper
import com.futo.platformplayer.isDownloadable
+import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.parsers.HLS
import com.futo.platformplayer.serializers.OffsetDateTimeNullableSerializer
+import com.futo.platformplayer.states.StateDownloads
+import com.futo.platformplayer.states.StatePlatform
import com.futo.platformplayer.toHumanBitrate
import com.futo.platformplayer.toHumanBytesSpeed
import kotlinx.coroutines.CancellationException
@@ -54,14 +64,9 @@ class VideoDownload {
var video: SerializedPlatformVideo? = null;
var videoDetails: SerializedPlatformVideoDetails? = null;
- @kotlinx.serialization.Transient
val videoEither: IPlatformVideo get() = videoDetails ?: video ?: throw IllegalStateException("Missing video?");
-
- @kotlinx.serialization.Transient
val id: PlatformID get() = videoEither.id
- @kotlinx.serialization.Transient
val name: String get() = videoEither.name;
- @kotlinx.serialization.Transient
val thumbnail: String? get() = videoDetails?.thumbnails?.getHQThumbnail() ?: video?.thumbnails?.getHQThumbnail();
var targetPixelCount: Long? = null;
@@ -385,7 +390,7 @@ class VideoDownload {
Logger.i(TAG, "${name} downloadSource Finished");
}
catch(ioex: IOException) {
- if(targetFile.exists() ?: false)
+ if(targetFile.exists())
targetFile.delete();
if(ioex.message?.contains("ENOSPC") ?: false)
throw Exception("Not enough space on device", ioex);
@@ -393,7 +398,7 @@ class VideoDownload {
throw ioex;
}
catch(ex: Throwable) {
- if(targetFile.exists() ?: false)
+ if(targetFile.exists())
targetFile.delete();
throw ex;
}
@@ -412,7 +417,7 @@ class VideoDownload {
val cmd = "-f concat -safe 0 -i \"${fileList.absolutePath}\" -c copy \"${targetFile.absolutePath}\""
- val statisticsCallback = StatisticsCallback { statistics ->
+ val statisticsCallback = StatisticsCallback { _ ->
//TODO: Show progress?
}
@@ -449,8 +454,7 @@ class VideoDownload {
targetFile.createNewFile();
- var sourceLength: Long? = null;
-
+ val sourceLength: Long?;
val fileStream = FileOutputStream(targetFile);
try{
@@ -458,17 +462,17 @@ class VideoDownload {
if(Settings.instance.downloads.byteRangeDownload && head?.containsKey("accept-ranges") == true && head.containsKey("content-length"))
{
val concurrency = Settings.instance.downloads.getByteRangeThreadCount();
- Logger.i(TAG, "Download ${name} ByteRange Parallel (${concurrency})");
+ Logger.i(TAG, "Download $name ByteRange Parallel (${concurrency})");
sourceLength = head["content-length"]!!.toLong();
onProgress(sourceLength, 0, 0);
downloadSource_Ranges(name, client, fileStream, videoUrl, sourceLength, 1024*512, concurrency, onProgress);
}
else {
- Logger.i(TAG, "Download ${name} Sequential");
+ Logger.i(TAG, "Download $name Sequential");
sourceLength = downloadSource_Sequential(client, fileStream, videoUrl, onProgress);
}
- Logger.i(TAG, "${name} downloadSource Finished");
+ Logger.i(TAG, "$name downloadSource Finished");
}
catch(ioex: IOException) {
if(targetFile.exists() ?: false)
@@ -484,7 +488,7 @@ class VideoDownload {
throw ex;
}
finally {
- fileStream?.close();
+ fileStream.close();
}
return sourceLength!!;
}
@@ -507,7 +511,7 @@ class VideoDownload {
val sourceStream = result.body.byteStream();
var totalRead: Long = 0;
- var read = 0;
+ var read: Int;
val buffer = ByteArray(4096);
diff --git a/app/src/main/java/com/futo/platformplayer/downloads/VideoLocal.kt b/app/src/main/java/com/futo/platformplayer/downloads/VideoLocal.kt
index bf8cb601..3b985796 100644
--- a/app/src/main/java/com/futo/platformplayer/downloads/VideoLocal.kt
+++ b/app/src/main/java/com/futo/platformplayer/downloads/VideoLocal.kt
@@ -11,7 +11,13 @@ import com.futo.platformplayer.api.media.models.ratings.IRating
import com.futo.platformplayer.api.media.models.streams.IVideoSourceDescriptor
import com.futo.platformplayer.api.media.models.streams.LocalVideoMuxedSourceDescriptor
import com.futo.platformplayer.api.media.models.streams.LocalVideoUnMuxedSourceDescriptor
-import com.futo.platformplayer.api.media.models.streams.sources.*
+import com.futo.platformplayer.api.media.models.streams.sources.IDashManifestSource
+import com.futo.platformplayer.api.media.models.streams.sources.IHLSManifestSource
+import com.futo.platformplayer.api.media.models.streams.sources.IVideoSource
+import com.futo.platformplayer.api.media.models.streams.sources.LocalAudioSource
+import com.futo.platformplayer.api.media.models.streams.sources.LocalSubtitleSource
+import com.futo.platformplayer.api.media.models.streams.sources.LocalVideoSource
+import com.futo.platformplayer.api.media.models.streams.sources.SubtitleRawSource
import com.futo.platformplayer.api.media.models.subtitles.ISubtitleSource
import com.futo.platformplayer.api.media.models.video.IPlatformVideoDetails
import com.futo.platformplayer.api.media.models.video.SerializedPlatformVideoDetails
@@ -46,7 +52,7 @@ class VideoLocal: IPlatformVideoDetails, IStoreItem {
override val shareUrl: String get() = videoSerialized.shareUrl;
@kotlinx.serialization.Transient
- override val video: IVideoSourceDescriptor get() = if(!audioSource.isEmpty())
+ override val video: IVideoSourceDescriptor get() = if(audioSource.isNotEmpty())
LocalVideoUnMuxedSourceDescriptor(this)
else
LocalVideoMuxedSourceDescriptor(this);
diff --git a/app/src/main/java/com/futo/platformplayer/engine/V8Plugin.kt b/app/src/main/java/com/futo/platformplayer/engine/V8Plugin.kt
index 65155ac3..7517bddd 100644
--- a/app/src/main/java/com/futo/platformplayer/engine/V8Plugin.kt
+++ b/app/src/main/java/com/futo/platformplayer/engine/V8Plugin.kt
@@ -10,14 +10,30 @@ import com.caoccao.javet.values.primitive.V8ValueBoolean
import com.caoccao.javet.values.primitive.V8ValueInteger
import com.caoccao.javet.values.primitive.V8ValueString
import com.caoccao.javet.values.reference.V8ValueObject
-import com.futo.platformplayer.*
import com.futo.platformplayer.api.http.ManagedHttpClient
import com.futo.platformplayer.constructs.Event1
-import com.futo.platformplayer.engine.exceptions.*
+import com.futo.platformplayer.engine.exceptions.NoInternetException
+import com.futo.platformplayer.engine.exceptions.PluginEngineStoppedException
+import com.futo.platformplayer.engine.exceptions.ScriptAgeException
+import com.futo.platformplayer.engine.exceptions.ScriptCaptchaRequiredException
+import com.futo.platformplayer.engine.exceptions.ScriptCompilationException
+import com.futo.platformplayer.engine.exceptions.ScriptCriticalException
+import com.futo.platformplayer.engine.exceptions.ScriptException
+import com.futo.platformplayer.engine.exceptions.ScriptExecutionException
+import com.futo.platformplayer.engine.exceptions.ScriptImplementationException
+import com.futo.platformplayer.engine.exceptions.ScriptLoginRequiredException
+import com.futo.platformplayer.engine.exceptions.ScriptTimeoutException
+import com.futo.platformplayer.engine.exceptions.ScriptUnavailableException
import com.futo.platformplayer.engine.internal.V8Converter
-import com.futo.platformplayer.engine.packages.*
+import com.futo.platformplayer.engine.packages.PackageBridge
+import com.futo.platformplayer.engine.packages.PackageDOMParser
+import com.futo.platformplayer.engine.packages.PackageHttp
+import com.futo.platformplayer.engine.packages.PackageUtilities
+import com.futo.platformplayer.engine.packages.V8Package
+import com.futo.platformplayer.getOrThrow
import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.states.StateAssets
+import com.futo.platformplayer.warnIfMainThread
class V8Plugin {
val config: IV8PluginConfig;
@@ -61,7 +77,7 @@ class V8Plugin {
withDependency(PackageBridge(this, config));
for(pack in config.packages)
- withDependency(getPackage(context, pack));
+ withDependency(getPackage(pack));
}
fun withDependency(context: Context, assetPath: String) : V8Plugin {
@@ -208,10 +224,10 @@ class V8Plugin {
}
}
- private fun getPackage(context: Context, packageName: String): V8Package {
+ private fun getPackage(packageName: String): V8Package {
//TODO: Auto get all package types?
return when(packageName) {
- "DOMParser" -> PackageDOMParser(context, this)
+ "DOMParser" -> PackageDOMParser(this)
"Http" -> PackageHttp(this, config)
"Utilities" -> PackageUtilities(this, config)
else -> throw ScriptCompilationException(config, "Unknown package [${packageName}] required for plugin ${config.name}");
diff --git a/app/src/main/java/com/futo/platformplayer/engine/exceptions/PluginEngineException.kt b/app/src/main/java/com/futo/platformplayer/engine/exceptions/PluginEngineException.kt
index 3ca2ec13..6569b001 100644
--- a/app/src/main/java/com/futo/platformplayer/engine/exceptions/PluginEngineException.kt
+++ b/app/src/main/java/com/futo/platformplayer/engine/exceptions/PluginEngineException.kt
@@ -1,9 +1,6 @@
package com.futo.platformplayer.engine.exceptions
-import com.caoccao.javet.values.reference.V8ValueObject
import com.futo.platformplayer.engine.IV8PluginConfig
-import com.futo.platformplayer.getOrThrow
-import java.lang.Exception
open class PluginEngineException(config: IV8PluginConfig, error: String, code: String? = null) : PluginException(config, error, null, code) {
diff --git a/app/src/main/java/com/futo/platformplayer/engine/exceptions/PluginEngineStoppedException.kt b/app/src/main/java/com/futo/platformplayer/engine/exceptions/PluginEngineStoppedException.kt
index b3f6044e..410bbd95 100644
--- a/app/src/main/java/com/futo/platformplayer/engine/exceptions/PluginEngineStoppedException.kt
+++ b/app/src/main/java/com/futo/platformplayer/engine/exceptions/PluginEngineStoppedException.kt
@@ -1,9 +1,6 @@
package com.futo.platformplayer.engine.exceptions
-import com.caoccao.javet.values.reference.V8ValueObject
import com.futo.platformplayer.engine.IV8PluginConfig
-import com.futo.platformplayer.getOrThrow
-import java.lang.Exception
class PluginEngineStoppedException(config: IV8PluginConfig, error: String, code: String? = null) : PluginEngineException(config, error, code) {
diff --git a/app/src/main/java/com/futo/platformplayer/engine/internal/V8Converter.kt b/app/src/main/java/com/futo/platformplayer/engine/internal/V8Converter.kt
index 62b6c149..5c0d8a67 100644
--- a/app/src/main/java/com/futo/platformplayer/engine/internal/V8Converter.kt
+++ b/app/src/main/java/com/futo/platformplayer/engine/internal/V8Converter.kt
@@ -1,12 +1,8 @@
package com.futo.platformplayer.engine.internal
-import com.caoccao.javet.annotations.V8Convert
import com.caoccao.javet.interop.V8Runtime
import com.caoccao.javet.interop.converters.JavetObjectConverter
-import com.caoccao.javet.interop.converters.JavetProxyConverter
import com.caoccao.javet.values.V8Value
-import com.caoccao.javet.values.reference.V8ValueObject
-import com.futo.platformplayer.engine.V8Plugin
class V8Converter : JavetObjectConverter() {
@@ -17,11 +13,11 @@ class V8Converter : JavetObjectConverter() {
return null;
val value: V8Value? = super.toV8Value(v8Runtime, obj, depth)
- if (value != null && !value.isUndefined)
+ if (value != null && !value.isUndefined) {
return value as T;
- if (obj != null) {
- if (obj is IV8Convertable)
- return obj.toV8(v8Runtime) as T;
+ }
+ if (obj is IV8Convertable) {
+ return obj.toV8(v8Runtime) as T
}
return null;
}
diff --git a/app/src/main/java/com/futo/platformplayer/engine/packages/PackageDOMParser.kt b/app/src/main/java/com/futo/platformplayer/engine/packages/PackageDOMParser.kt
index 9c5cacbd..c261487d 100644
--- a/app/src/main/java/com/futo/platformplayer/engine/packages/PackageDOMParser.kt
+++ b/app/src/main/java/com/futo/platformplayer/engine/packages/PackageDOMParser.kt
@@ -1,16 +1,11 @@
package com.futo.platformplayer.engine.packages
-import android.content.Context
-import android.util.Log
-import com.caoccao.javet.annotations.V8Allow
import com.caoccao.javet.annotations.V8Convert
import com.caoccao.javet.annotations.V8Function
import com.caoccao.javet.annotations.V8Property
import com.caoccao.javet.enums.V8ConversionMode
import com.caoccao.javet.enums.V8ProxyMode
-import com.caoccao.javet.values.reference.V8ValueObject
import com.futo.platformplayer.engine.V8Plugin
-import com.futo.platformplayer.engine.dev.V8RemoteObject
import com.futo.platformplayer.engine.internal.V8BindObject
import org.jsoup.Jsoup
import org.jsoup.nodes.Element
@@ -20,8 +15,8 @@ class PackageDOMParser : V8Package {
override val name: String get() = "DOMParser";
override val variableName: String = "domParser";
- constructor(context: Context, v8Plugin: V8Plugin): super(v8Plugin) {
- //v8Plugin.withDependency(context, "/scripts/some/package/path");
+ constructor(v8Plugin: V8Plugin): super(v8Plugin) {
+
}
@V8Function
@@ -45,8 +40,7 @@ class PackageDOMParser : V8Package {
@V8Property
fun childNodes(): List {
val results = _element.children().map { DOMNode(_package, it) }.toList();
- if(results != null)
- _children.addAll(results);
+ _children.addAll(results);
return results;
}
@V8Property
diff --git a/app/src/main/java/com/futo/platformplayer/engine/packages/PackageHttp.kt b/app/src/main/java/com/futo/platformplayer/engine/packages/PackageHttp.kt
index eadf68c6..68a74202 100644
--- a/app/src/main/java/com/futo/platformplayer/engine/packages/PackageHttp.kt
+++ b/app/src/main/java/com/futo/platformplayer/engine/packages/PackageHttp.kt
@@ -8,18 +8,15 @@ import com.caoccao.javet.enums.V8ProxyMode
import com.caoccao.javet.interop.V8Runtime
import com.caoccao.javet.values.V8Value
import com.caoccao.javet.values.reference.V8ValueObject
-import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.api.http.ManagedHttpClient
import com.futo.platformplayer.api.media.platforms.js.internal.JSHttpClient
import com.futo.platformplayer.engine.IV8PluginConfig
import com.futo.platformplayer.engine.V8Plugin
import com.futo.platformplayer.engine.internal.IV8Convertable
import com.futo.platformplayer.engine.internal.V8BindObject
-import com.futo.platformplayer.getOrThrow
-import kotlinx.coroutines.CoroutineScope
+import com.futo.platformplayer.logging.Logger
import java.net.SocketTimeoutException
import kotlin.streams.asSequence
-import kotlin.streams.toList
class PackageHttp: V8Package {
@Transient
@@ -227,10 +224,10 @@ class PackageHttp: V8Package {
return logExceptions {
return@logExceptions catchHttp {
val client = _client;
- logRequest(method, url, headers, null);
+ //logRequest(method, url, headers, null);
val resp = client.requestMethod(method, url, headers);
val responseBody = resp.body?.string();
- logResponse(method, url, resp.code, resp.headers, responseBody);
+ //logResponse(method, url, resp.code, resp.headers, responseBody);
return@catchHttp BridgeHttpResponse(resp.url, resp.code, responseBody, sanitizeResponseHeaders(resp.headers));
}
};
@@ -241,10 +238,10 @@ class PackageHttp: V8Package {
return logExceptions {
catchHttp {
val client = _client;
- logRequest(method, url, headers, body);
+ //logRequest(method, url, headers, body);
val resp = client.requestMethod(method, url, body, headers);
val responseBody = resp.body?.string();
- logResponse(method, url, resp.code, resp.headers, responseBody);
+ //logResponse(method, url, resp.code, resp.headers, responseBody);
return@catchHttp BridgeHttpResponse(resp.url, resp.code, responseBody, sanitizeResponseHeaders(resp.headers));
}
};
@@ -256,10 +253,10 @@ class PackageHttp: V8Package {
return logExceptions {
catchHttp {
val client = _client;
- logRequest("GET", url, headers, null);
+ //logRequest("GET", url, headers, null);
val resp = client.get(url, headers);
val responseBody = resp.body?.string();
- logResponse("GET", url, resp.code, resp.headers, responseBody);
+ //logResponse("GET", url, resp.code, resp.headers, responseBody);
return@catchHttp BridgeHttpResponse(resp.url, resp.code, responseBody, sanitizeResponseHeaders(resp.headers));
}
};
@@ -270,10 +267,10 @@ class PackageHttp: V8Package {
return logExceptions {
catchHttp {
val client = _client;
- logRequest("POST", url, headers, body);
+ //logRequest("POST", url, headers, body);
val resp = client.post(url, body, headers);
val responseBody = resp.body?.string();
- logResponse("POST", url, resp.code, resp.headers, responseBody);
+ //logResponse("POST", url, resp.code, resp.headers, responseBody);
return@catchHttp BridgeHttpResponse(resp.url, resp.code, responseBody, sanitizeResponseHeaders(resp.headers));
}
};
@@ -283,7 +280,7 @@ class PackageHttp: V8Package {
fun socket(url: String, headers: Map? = null): SocketResult {
val socketHeaders = headers?.toMutableMap() ?: HashMap();
applyDefaultHeaders(socketHeaders);
- return SocketResult(this, _client, url, socketHeaders ?: HashMap());
+ return SocketResult(this, _client, url, socketHeaders);
}
private fun applyDefaultHeaders(headerMap: MutableMap) {
@@ -305,9 +302,7 @@ class PackageHttp: V8Package {
return result
}
- private fun logRequest(method: String, url: String, headers: Map = HashMap(), body: String?) {
- return;
-
+ /*private fun logRequest(method: String, url: String, headers: Map = HashMap(), body: String?) {
Logger.v(TAG) {
val stringBuilder = StringBuilder();
stringBuilder.appendLine("HTTP request (useAuth = )");
@@ -324,11 +319,9 @@ class PackageHttp: V8Package {
return@v stringBuilder.toString();
};
- }
-
- private fun logResponse(method: String, url: String, responseCode: Int? = null, responseHeaders: Map> = HashMap(), responseBody: String? = null) {
- return;
+ }*/
+ /*private fun logResponse(method: String, url: String, responseCode: Int? = null, responseHeaders: Map> = HashMap(), responseBody: String? = null) {
Logger.v(TAG) {
val stringBuilder = StringBuilder();
if (responseCode != null) {
@@ -353,7 +346,7 @@ class PackageHttp: V8Package {
return@v stringBuilder.toString();
};
- }
+ }*/
fun logExceptions(handle: ()->T): T {
try {
diff --git a/app/src/main/java/com/futo/platformplayer/exceptions/RateLimitException.kt b/app/src/main/java/com/futo/platformplayer/exceptions/RateLimitException.kt
index c59910de..30720a75 100644
--- a/app/src/main/java/com/futo/platformplayer/exceptions/RateLimitException.kt
+++ b/app/src/main/java/com/futo/platformplayer/exceptions/RateLimitException.kt
@@ -4,6 +4,6 @@ class RateLimitException : Throwable {
val pluginIds: List;
constructor(pluginIds: List): super() {
- this.pluginIds = pluginIds ?: listOf();
+ this.pluginIds = pluginIds;
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/futo/platformplayer/fragment/channel/tab/ChannelAboutFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/channel/tab/ChannelAboutFragment.kt
index 1cf84c32..f7d9d9bf 100644
--- a/app/src/main/java/com/futo/platformplayer/fragment/channel/tab/ChannelAboutFragment.kt
+++ b/app/src/main/java/com/futo/platformplayer/fragment/channel/tab/ChannelAboutFragment.kt
@@ -9,11 +9,17 @@ import android.widget.LinearLayout
import android.widget.TextView
import androidx.fragment.app.Fragment
import com.bumptech.glide.Glide
-import com.futo.platformplayer.*
+import com.futo.platformplayer.R
import com.futo.platformplayer.api.media.models.channels.IPlatformChannel
+import com.futo.platformplayer.dp
+import com.futo.platformplayer.fixHtmlLinks
import com.futo.platformplayer.fragment.mainactivity.main.PolycentricProfile
import com.futo.platformplayer.logging.Logger
+import com.futo.platformplayer.resolveChannelUrl
+import com.futo.platformplayer.selectBestImage
+import com.futo.platformplayer.setPlatformPlayerLinkMovementMethod
import com.futo.platformplayer.states.StateApp
+import com.futo.platformplayer.toHumanNumber
import com.futo.platformplayer.views.platform.PlatformLinkView
import com.futo.polycentric.core.toName
import com.futo.polycentric.core.toURLInfoSystemLinkUrl
@@ -48,7 +54,7 @@ class ChannelAboutFragment : Fragment, IChannelTabFragment {
setChannel(it);
};
_lastPolycentricProfile?.also {
- setPolycentricProfile(it, animate = false);
+ setPolycentricProfile(it);
}
return view;
@@ -108,7 +114,7 @@ class ChannelAboutFragment : Fragment, IChannelTabFragment {
}
- fun setPolycentricProfile(polycentricProfile: PolycentricProfile?, animate: Boolean) {
+ fun setPolycentricProfile(polycentricProfile: PolycentricProfile?) {
_lastPolycentricProfile = polycentricProfile;
if (polycentricProfile == null) {
diff --git a/app/src/main/java/com/futo/platformplayer/fragment/channel/tab/ChannelContentsFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/channel/tab/ChannelContentsFragment.kt
index 0bf75149..1aec934b 100644
--- a/app/src/main/java/com/futo/platformplayer/fragment/channel/tab/ChannelContentsFragment.kt
+++ b/app/src/main/java/com/futo/platformplayer/fragment/channel/tab/ChannelContentsFragment.kt
@@ -8,8 +8,6 @@ import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
-import com.futo.platformplayer.logging.Logger
-import com.futo.platformplayer.states.StatePlatform
import com.futo.platformplayer.R
import com.futo.platformplayer.Settings
import com.futo.platformplayer.UIDialogs
@@ -31,13 +29,15 @@ import com.futo.platformplayer.engine.exceptions.PluginException
import com.futo.platformplayer.engine.exceptions.ScriptCaptchaRequiredException
import com.futo.platformplayer.fragment.mainactivity.main.FeedView
import com.futo.platformplayer.fragment.mainactivity.main.PolycentricProfile
+import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.states.StateCache
+import com.futo.platformplayer.states.StatePlatform
import com.futo.platformplayer.states.StatePolycentric
import com.futo.platformplayer.states.StateSubscriptions
import com.futo.platformplayer.views.FeedStyle
-import com.futo.platformplayer.views.adapters.feedtypes.PreviewContentListAdapter
import com.futo.platformplayer.views.adapters.ContentPreviewViewHolder
import com.futo.platformplayer.views.adapters.InsertedViewAdapterWithLoader
+import com.futo.platformplayer.views.adapters.feedtypes.PreviewContentListAdapter
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -215,14 +215,14 @@ class ChannelContentsFragment : Fragment(), IChannelTabFragment {
fun setPager(pager: IPager, cache: FeedView.ItemCache? = null) {
if (_pager_parent != null && _pager_parent is IRefreshPager<*>) {
- (_pager_parent as IRefreshPager<*>).onPagerError?.remove(this);
- (_pager_parent as IRefreshPager<*>).onPagerChanged?.remove(this);
+ (_pager_parent as IRefreshPager<*>).onPagerError.remove(this);
+ (_pager_parent as IRefreshPager<*>).onPagerChanged.remove(this);
_pager_parent = null;
}
if(_pager is IReplacerPager<*>)
(_pager as IReplacerPager<*>).onReplaced.remove(this);
- var pagerToSet: IPager? = null;
+ var pagerToSet: IPager?;
if(pager is IRefreshPager<*>) {
_pager_parent = pager;
pagerToSet = pager.getCurrentPager() as IPager;
@@ -305,7 +305,7 @@ class ChannelContentsFragment : Fragment(), IChannelTabFragment {
_adapterResults?.setLoading(loading);
}
- fun setPolycentricProfile(polycentricProfile: PolycentricProfile?, animate: Boolean) {
+ fun setPolycentricProfile(polycentricProfile: PolycentricProfile?) {
val p = _lastPolycentricProfile;
if (p != null && polycentricProfile != null && p.system == polycentricProfile.system) {
Logger.i(TAG, "setPolycentricProfile skipped because previous was same");
diff --git a/app/src/main/java/com/futo/platformplayer/fragment/channel/tab/ChannelListFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/channel/tab/ChannelListFragment.kt
index 4ce5337d..00ec5982 100644
--- a/app/src/main/java/com/futo/platformplayer/fragment/channel/tab/ChannelListFragment.kt
+++ b/app/src/main/java/com/futo/platformplayer/fragment/channel/tab/ChannelListFragment.kt
@@ -1,7 +1,6 @@
package com.futo.platformplayer.fragment.channel.tab
import android.os.Bundle
-import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -9,7 +8,8 @@ import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
-import com.futo.platformplayer.*
+import com.futo.platformplayer.R
+import com.futo.platformplayer.UIDialogs
import com.futo.platformplayer.api.media.models.PlatformAuthorLink
import com.futo.platformplayer.api.media.models.channels.IPlatformChannel
import com.futo.platformplayer.constructs.Event1
@@ -18,11 +18,10 @@ import com.futo.platformplayer.engine.exceptions.ScriptCaptchaRequiredException
import com.futo.platformplayer.fragment.mainactivity.main.ChannelFragment
import com.futo.platformplayer.fragment.mainactivity.main.PolycentricProfile
import com.futo.platformplayer.logging.Logger
+import com.futo.platformplayer.resolveChannelUrl
import com.futo.platformplayer.states.StatePlatform
import com.futo.platformplayer.views.adapters.InsertedViewAdapterWithLoader
import com.futo.platformplayer.views.adapters.viewholders.CreatorViewHolder
-import com.futo.polycentric.core.toUrl
-import kotlinx.coroutines.runBlocking
class ChannelListFragment : Fragment, IChannelTabFragment {
private var _channels: ArrayList = arrayListOf();
@@ -84,7 +83,7 @@ class ChannelListFragment : Fragment, IChannelTabFragment {
recyclerCreator.layoutManager = _lm;
_recyclerCreator = recyclerCreator;
_lastChannel?.also { setChannel(it); };
- _lastPolycentricProfile?.also { setPolycentricProfile(it, animate = false); }
+ _lastPolycentricProfile?.also { setPolycentricProfile(it); }
return view;
}
@@ -125,7 +124,7 @@ class ChannelListFragment : Fragment, IChannelTabFragment {
}
}
- fun setPolycentricProfile(polycentricProfile: PolycentricProfile?, animate: Boolean) {
+ fun setPolycentricProfile(polycentricProfile: PolycentricProfile?) {
_taskLoadChannel.cancel();
_lastPolycentricProfile = polycentricProfile;
diff --git a/app/src/main/java/com/futo/platformplayer/fragment/channel/tab/ChannelMonetizationFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/channel/tab/ChannelMonetizationFragment.kt
index 20b6f5b4..e2e39ee7 100644
--- a/app/src/main/java/com/futo/platformplayer/fragment/channel/tab/ChannelMonetizationFragment.kt
+++ b/app/src/main/java/com/futo/platformplayer/fragment/channel/tab/ChannelMonetizationFragment.kt
@@ -32,7 +32,7 @@ class ChannelMonetizationFragment : Fragment, IChannelTabFragment {
_supportView?.visibility = View.GONE;
_textMonetization?.visibility = View.GONE;
- setPolycentricProfile(_lastPolycentricProfile, animate = false);
+ setPolycentricProfile(_lastPolycentricProfile);
return view;
}
@@ -46,14 +46,14 @@ class ChannelMonetizationFragment : Fragment, IChannelTabFragment {
_lastChannel = channel;
}
- fun setPolycentricProfile(polycentricProfile: PolycentricProfile?, animate: Boolean) {
+ fun setPolycentricProfile(polycentricProfile: PolycentricProfile?) {
_lastPolycentricProfile = polycentricProfile
if (polycentricProfile != null) {
- _supportView?.setPolycentricProfile(polycentricProfile, animate)
+ _supportView?.setPolycentricProfile(polycentricProfile)
_supportView?.visibility = View.VISIBLE
_textMonetization?.visibility = View.GONE
} else {
- _supportView?.setPolycentricProfile(null, animate)
+ _supportView?.setPolycentricProfile(null)
_supportView?.visibility = View.GONE
_textMonetization?.visibility = View.VISIBLE
}
diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/bottombar/MenuBottomBarFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/bottombar/MenuBottomBarFragment.kt
index e96754ce..48f68590 100644
--- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/bottombar/MenuBottomBarFragment.kt
+++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/bottombar/MenuBottomBarFragment.kt
@@ -7,11 +7,8 @@ import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.Intent
-import android.graphics.Color
import android.os.Bundle
-import android.view.Gravity
import android.view.LayoutInflater
-import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.widget.*
@@ -19,7 +16,6 @@ import androidx.core.animation.doOnEnd
import androidx.lifecycle.lifecycleScope
import com.futo.platformplayer.R
import com.futo.platformplayer.Settings
-import com.futo.platformplayer.UIDialogs
import com.futo.platformplayer.activities.MainActivity
import com.futo.platformplayer.activities.SettingsActivity
import com.futo.platformplayer.dp
@@ -31,7 +27,6 @@ import com.futo.platformplayer.states.StatePayment
import com.futo.platformplayer.states.StateSubscriptions
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
-import java.util.Collections
import kotlin.math.floor
import kotlin.math.roundToInt
diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/BuyFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/BuyFragment.kt
index ca970cfb..6fca4178 100644
--- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/BuyFragment.kt
+++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/BuyFragment.kt
@@ -63,7 +63,7 @@ class BuyFragment : MainFragment() {
_overlayLoading = findViewById(R.id.overlay_loading);
_overlayPaying = findViewById(R.id.overlay_paying);
- _paymentManager = PaymentManager(StatePayment.instance, fragment, _overlayPaying) { success, purchaseId, exception ->
+ _paymentManager = PaymentManager(StatePayment.instance, fragment, _overlayPaying) { success, _, exception ->
if(success) {
UIDialogs.showDialog(context, R.drawable.ic_check, context.getString(R.string.payment_succeeded), context.getString(R.string.thanks_for_your_purchase_a_key_will_be_sent_to_your_email_after_your_payment_has_been_received), null, 0,
UIDialogs.Action("Ok", {}, UIDialogs.ActionStyle.PRIMARY));
@@ -90,7 +90,7 @@ class BuyFragment : MainFragment() {
val currencies = StatePayment.instance.getAvailableCurrencies("grayjay");
val prices = StatePayment.instance.getAvailableCurrencyPrices("grayjay");
val country = StatePayment.instance.getPaymentCountryFromIP()?.let { c -> PaymentConfigurations.COUNTRIES.find { it.id.equals(c, ignoreCase = true) } };
- val currency = country?.let { c -> PaymentConfigurations.CURRENCIES.find { it.id == c.defaultCurrencyId && (currencies.contains(it.id) ?: true) } };
+ val currency = country?.let { c -> PaymentConfigurations.CURRENCIES.find { it.id == c.defaultCurrencyId && (currencies.contains(it.id)) } };
if(currency != null && prices.containsKey(currency.id)) {
val price = prices[currency.id]!!;
diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/ChannelFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/ChannelFragment.kt
index 056cece7..ded1948b 100644
--- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/ChannelFragment.kt
+++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/ChannelFragment.kt
@@ -3,8 +3,6 @@ package com.futo.platformplayer.fragment.mainactivity.main
import android.annotation.SuppressLint
import android.graphics.drawable.Animatable
import android.os.Bundle
-import android.text.Html
-import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -30,9 +28,9 @@ import com.futo.platformplayer.api.media.models.post.IPlatformPost
import com.futo.platformplayer.api.media.models.video.IPlatformVideo
import com.futo.platformplayer.constructs.TaskHandler
import com.futo.platformplayer.fragment.channel.tab.ChannelAboutFragment
+import com.futo.platformplayer.fragment.channel.tab.ChannelContentsFragment
import com.futo.platformplayer.fragment.channel.tab.ChannelListFragment
import com.futo.platformplayer.fragment.channel.tab.ChannelMonetizationFragment
-import com.futo.platformplayer.fragment.channel.tab.ChannelContentsFragment
import com.futo.platformplayer.fragment.mainactivity.topbar.NavigationTopBarFragment
import com.futo.platformplayer.images.GlideHelper.Companion.crossfade
import com.futo.platformplayer.logging.Logger
@@ -43,10 +41,10 @@ import com.futo.platformplayer.states.StatePlatform
import com.futo.platformplayer.states.StatePlayer
import com.futo.platformplayer.states.StatePlaylists
import com.futo.platformplayer.states.StateSubscriptions
-import com.futo.platformplayer.views.others.CreatorThumbnail
-import com.futo.platformplayer.views.subscriptions.SubscribeButton
import com.futo.platformplayer.views.adapters.ChannelViewPagerAdapter
+import com.futo.platformplayer.views.others.CreatorThumbnail
import com.futo.platformplayer.views.overlays.slideup.SlideUpMenuOverlay
+import com.futo.platformplayer.views.subscriptions.SubscribeButton
import com.futo.polycentric.core.*
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator
@@ -54,7 +52,6 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.serialization.Serializable
-import okhttp3.internal.platform.Platform
@Serializable
data class PolycentricProfile(val system: PublicKey, val systemState: SystemState, val ownedClaims: List);
@@ -450,7 +447,7 @@ class ChannelFragment : MainFragment() {
private fun setPolycentricProfileOr(url: String, or: () -> Unit) {
setPolycentricProfile(null, animate = false);
- val cachedProfile = channel?.let { PolycentricCache.instance.getCachedProfile(it.url) };
+ val cachedProfile = channel?.let { PolycentricCache.instance.getCachedProfile(url) };
if (cachedProfile != null) {
setPolycentricProfile(cachedProfile, animate = false);
} else {
@@ -492,10 +489,10 @@ class ChannelFragment : MainFragment() {
}
(_viewPager.adapter as ChannelViewPagerAdapter?)?.let {
- it.getFragment().setPolycentricProfile(profile, animate);
- it.getFragment().setPolycentricProfile(profile, animate);
- it.getFragment().setPolycentricProfile(profile, animate);
- it.getFragment().setPolycentricProfile(profile, animate);
+ it.getFragment().setPolycentricProfile(profile);
+ it.getFragment().setPolycentricProfile(profile);
+ it.getFragment().setPolycentricProfile(profile);
+ it.getFragment().setPolycentricProfile(profile);
//TODO: Call on other tabs as needed
}
}
diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/ContentSearchResultsFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/ContentSearchResultsFragment.kt
index d5a2c987..e6b9be9b 100644
--- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/ContentSearchResultsFragment.kt
+++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/ContentSearchResultsFragment.kt
@@ -6,10 +6,8 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.lifecycleScope
-import com.futo.platformplayer.logging.Logger
-import com.futo.platformplayer.UIDialogs
-import com.futo.platformplayer.states.StatePlatform
import com.futo.platformplayer.Settings
+import com.futo.platformplayer.UIDialogs
import com.futo.platformplayer.UISlideOverlays
import com.futo.platformplayer.api.media.models.ResultCapabilities
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
@@ -18,6 +16,8 @@ import com.futo.platformplayer.constructs.TaskHandler
import com.futo.platformplayer.engine.exceptions.ScriptCaptchaRequiredException
import com.futo.platformplayer.fragment.mainactivity.topbar.SearchTopBarFragment
import com.futo.platformplayer.isHttpUrl
+import com.futo.platformplayer.logging.Logger
+import com.futo.platformplayer.states.StatePlatform
import com.futo.platformplayer.views.FeedStyle
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -32,7 +32,7 @@ class ContentSearchResultsFragment : MainFragment() {
override fun onShownWithView(parameter: Any?, isBack: Boolean) {
super.onShownWithView(parameter, isBack);
- _view?.onShown(parameter, isBack);
+ _view?.onShown(parameter);
}
override fun onHide() {
@@ -110,7 +110,7 @@ class ContentSearchResultsFragment : MainFragment() {
_taskSearch.cancel();
}
- fun onShown(parameter: Any?, isBack: Boolean) {
+ fun onShown(parameter: Any?) {
if(parameter is SuggestionsFragmentData) {
setQuery(parameter.query, false);
setChannelUrl(parameter.channelUrl, false);
@@ -127,7 +127,7 @@ class ContentSearchResultsFragment : MainFragment() {
setFilterButtonVisible(true);
onFilterClick.subscribe(this) {
- _overlayContainer?.let {
+ _overlayContainer.let {
val filterValuesCopy = HashMap(_filterValues);
val filtersOverlay = UISlideOverlays.showFiltersOverlay(lifecycleScope, it, _enabledClientIds!!, filterValuesCopy);
filtersOverlay.onOK.subscribe { enabledClientIds, changed ->
diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/CreatorSearchResultsFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/CreatorSearchResultsFragment.kt
index a685e73e..eac18ba9 100644
--- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/CreatorSearchResultsFragment.kt
+++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/CreatorSearchResultsFragment.kt
@@ -6,15 +6,15 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.lifecycleScope
-import com.futo.platformplayer.logging.Logger
-import com.futo.platformplayer.UIDialogs
-import com.futo.platformplayer.states.StatePlatform
import com.futo.platformplayer.Settings
+import com.futo.platformplayer.UIDialogs
import com.futo.platformplayer.api.media.models.PlatformAuthorLink
import com.futo.platformplayer.api.media.structures.IPager
import com.futo.platformplayer.constructs.TaskHandler
import com.futo.platformplayer.engine.exceptions.ScriptCaptchaRequiredException
import com.futo.platformplayer.fragment.mainactivity.topbar.SearchTopBarFragment
+import com.futo.platformplayer.logging.Logger
+import com.futo.platformplayer.states.StatePlatform
import com.futo.platformplayer.views.FeedStyle
class CreatorSearchResultsFragment : MainFragment() {
@@ -26,7 +26,7 @@ class CreatorSearchResultsFragment : MainFragment() {
override fun onShownWithView(parameter: Any?, isBack: Boolean) {
super.onShownWithView(parameter, isBack);
- _view?.onShown(parameter, isBack);
+ _view?.onShown(parameter);
}
override fun onResume() {
@@ -69,7 +69,7 @@ class CreatorSearchResultsFragment : MainFragment() {
_taskSearch.cancel();
}
- fun onShown(parameter: Any?, isBack: Boolean) {
+ fun onShown(parameter: Any?) {
if(parameter is String) {
setQuery(parameter);
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 dd5f33c3..90574133 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
@@ -8,32 +8,24 @@ import android.view.ViewGroup
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import com.futo.platformplayer.*
-import com.futo.platformplayer.activities.CaptchaActivity
-import com.futo.platformplayer.api.media.IPlatformClient
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
-import com.futo.platformplayer.api.media.models.video.IPlatformVideo
import com.futo.platformplayer.api.media.platforms.js.JSClient
-import com.futo.platformplayer.api.media.platforms.js.internal.JSHttpClient
import com.futo.platformplayer.api.media.structures.EmptyPager
import com.futo.platformplayer.api.media.structures.IPager
import com.futo.platformplayer.constructs.TaskHandler
import com.futo.platformplayer.engine.exceptions.ScriptCaptchaRequiredException
import com.futo.platformplayer.engine.exceptions.ScriptExecutionException
import com.futo.platformplayer.engine.exceptions.ScriptImplementationException
-import com.futo.platformplayer.fragment.mainactivity.topbar.ImportTopBarFragment
import com.futo.platformplayer.logging.Logger
-import com.futo.platformplayer.others.CaptchaWebViewClient
import com.futo.platformplayer.states.AnnouncementType
import com.futo.platformplayer.states.StateAnnouncement
import com.futo.platformplayer.states.StateMeta
import com.futo.platformplayer.states.StatePlatform
-import com.futo.platformplayer.states.StatePlugins
-import com.futo.platformplayer.states.StateSubscriptions
-import com.futo.platformplayer.views.announcements.AnnouncementView
import com.futo.platformplayer.views.FeedStyle
import com.futo.platformplayer.views.adapters.ContentPreviewViewHolder
import com.futo.platformplayer.views.adapters.InsertedViewAdapterWithLoader
import com.futo.platformplayer.views.adapters.InsertedViewHolder
+import com.futo.platformplayer.views.announcements.AnnouncementView
import java.time.OffsetDateTime
import java.util.UUID
@@ -159,8 +151,8 @@ class HomeFragment : MainFragment() {
loadResults();
}
- override fun filterResults(contents: List): List {
- return contents.filter { !StateMeta.instance.isVideoHidden(it.url) && !StateMeta.instance.isCreatorHidden(it.author.url) };
+ override fun filterResults(results: List): List {
+ return results.filter { !StateMeta.instance.isVideoHidden(it.url) && !StateMeta.instance.isCreatorHidden(it.author.url) };
}
private fun loadResults() {
diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/ImportPlaylistsFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/ImportPlaylistsFragment.kt
index 588d2bb8..e90a535d 100644
--- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/ImportPlaylistsFragment.kt
+++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/ImportPlaylistsFragment.kt
@@ -14,12 +14,12 @@ import androidx.recyclerview.widget.RecyclerView
import com.futo.platformplayer.*
import com.futo.platformplayer.constructs.TaskHandler
import com.futo.platformplayer.fragment.mainactivity.topbar.ImportTopBarFragment
-import com.futo.platformplayer.views.AnyAdapterView
-import com.futo.platformplayer.views.AnyAdapterView.Companion.asAny
import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.models.Playlist
import com.futo.platformplayer.states.StatePlatform
import com.futo.platformplayer.states.StatePlaylists
+import com.futo.platformplayer.views.AnyAdapterView
+import com.futo.platformplayer.views.AnyAdapterView.Companion.asAny
import com.futo.platformplayer.views.adapters.viewholders.ImportPlaylistsViewHolder
import com.futo.platformplayer.views.adapters.viewholders.SelectablePlaylist
@@ -32,7 +32,7 @@ class ImportPlaylistsFragment : MainFragment() {
override fun onShownWithView(parameter: Any?, isBack: Boolean) {
super.onShownWithView(parameter, isBack);
- _view?.onShown(parameter, isBack);
+ _view?.onShown(parameter);
}
override fun onHide() {
@@ -79,7 +79,7 @@ class ImportPlaylistsFragment : MainFragment() {
_spinner = findViewById(R.id.channel_loader);
_adapterView = findViewById(R.id.recycler_import).asAny( _items) {
- it.onSelectedChange.subscribe { c ->
+ it.onSelectedChange.subscribe {
updateSelected();
};
};
@@ -123,7 +123,7 @@ class ImportPlaylistsFragment : MainFragment() {
_taskLoadPlaylist.cancel();
}
- fun onShown(parameter: Any ?, isBack: Boolean) {
+ fun onShown(parameter: Any?) {
updateSelected();
val itemsRemoved = _items.size;
diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/ImportSubscriptionsFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/ImportSubscriptionsFragment.kt
index e245ec74..a95d96df 100644
--- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/ImportSubscriptionsFragment.kt
+++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/ImportSubscriptionsFragment.kt
@@ -15,13 +15,13 @@ import com.futo.platformplayer.*
import com.futo.platformplayer.api.media.models.channels.IPlatformChannel
import com.futo.platformplayer.constructs.TaskHandler
import com.futo.platformplayer.fragment.mainactivity.topbar.ImportTopBarFragment
+import com.futo.platformplayer.logging.Logger
+import com.futo.platformplayer.states.StatePlatform
+import com.futo.platformplayer.states.StateSubscriptions
import com.futo.platformplayer.views.AnyAdapterView
import com.futo.platformplayer.views.AnyAdapterView.Companion.asAny
import com.futo.platformplayer.views.adapters.viewholders.ImportSubscriptionViewHolder
import com.futo.platformplayer.views.adapters.viewholders.SelectableIPlatformChannel
-import com.futo.platformplayer.states.StateSubscriptions
-import com.futo.platformplayer.logging.Logger
-import com.futo.platformplayer.states.StatePlatform
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@@ -37,7 +37,7 @@ class ImportSubscriptionsFragment : MainFragment() {
override fun onShownWithView(parameter: Any?, isBack: Boolean) {
super.onShownWithView(parameter, isBack);
- _view?.onShown(parameter, isBack);
+ _view?.onShown(parameter);
}
override fun onHide() {
@@ -93,7 +93,7 @@ class ImportSubscriptionsFragment : MainFragment() {
_loadProgress = findViewById(R.id.text_load_progress);
_adapterView = findViewById(R.id.recycler_import).asAny( _items) {
- it.onSelectedChange.subscribe { c ->
+ it.onSelectedChange.subscribe {
updateSelected();
};
};
@@ -152,14 +152,14 @@ class ImportSubscriptionsFragment : MainFragment() {
_taskLoadChannel.cancel();
}
- fun onShown(parameter: Any ?, isBack: Boolean) {
+ fun onShown(parameter: Any?) {
_counter = 0;
_limitToastShown = false;
updateSelected();
val itemsRemoved = _items.size;
_items.clear();
- _adapterView?.adapter?.notifyItemRangeRemoved(0, itemsRemoved);
+ _adapterView.adapter?.notifyItemRangeRemoved(0, itemsRemoved);
_links = (parameter as List).filter { i -> !StateSubscriptions.instance.isSubscribed(i) }.toList();
_currentLoadIndex = 0;
diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/PlaylistFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/PlaylistFragment.kt
index a15e0377..38c920ef 100644
--- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/PlaylistFragment.kt
+++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/PlaylistFragment.kt
@@ -41,7 +41,7 @@ class PlaylistFragment : MainFragment() {
override fun onShownWithView(parameter: Any?, isBack: Boolean) {
super.onShownWithView(parameter, isBack);
- _view?.onShown(parameter, isBack);
+ _view?.onShown(parameter);
}
override fun onCreateMainView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
@@ -150,7 +150,7 @@ class PlaylistFragment : MainFragment() {
};
}
- fun onShown(parameter: Any ?, isBack: Boolean) {
+ fun onShown(parameter: Any?) {
_taskLoadPlaylist.cancel();
if (parameter is Playlist?) {
diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/PlaylistSearchResultsFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/PlaylistSearchResultsFragment.kt
index bf42b2d4..ec01bb80 100644
--- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/PlaylistSearchResultsFragment.kt
+++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/PlaylistSearchResultsFragment.kt
@@ -6,14 +6,14 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.lifecycleScope
-import com.futo.platformplayer.logging.Logger
-import com.futo.platformplayer.UIDialogs
-import com.futo.platformplayer.states.StatePlatform
import com.futo.platformplayer.Settings
+import com.futo.platformplayer.UIDialogs
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
import com.futo.platformplayer.api.media.structures.IPager
import com.futo.platformplayer.constructs.TaskHandler
import com.futo.platformplayer.fragment.mainactivity.topbar.SearchTopBarFragment
+import com.futo.platformplayer.logging.Logger
+import com.futo.platformplayer.states.StatePlatform
import com.futo.platformplayer.views.FeedStyle
class PlaylistSearchResultsFragment : MainFragment() {
@@ -25,7 +25,7 @@ class PlaylistSearchResultsFragment : MainFragment() {
override fun onShownWithView(parameter: Any?, isBack: Boolean) {
super.onShownWithView(parameter, isBack);
- _view?.onShown(parameter, isBack);
+ _view?.onShown(parameter);
}
override fun onResume() {
@@ -78,7 +78,7 @@ class PlaylistSearchResultsFragment : MainFragment() {
_taskSearch.cancel();
}
- fun onShown(parameter: Any?, isBack: Boolean) {
+ fun onShown(parameter: Any?) {
if(parameter is String) {
setQuery(parameter);
diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/PlaylistsFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/PlaylistsFragment.kt
index b1179940..085d7cb0 100644
--- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/PlaylistsFragment.kt
+++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/PlaylistsFragment.kt
@@ -14,21 +14,15 @@ import androidx.constraintlayout.widget.ConstraintLayout
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
-import com.futo.platformplayer.states.StatePlayer
-import com.futo.platformplayer.states.StatePlaylists
import com.futo.platformplayer.R
import com.futo.platformplayer.UISlideOverlays
import com.futo.platformplayer.api.media.models.video.IPlatformVideo
-import com.futo.platformplayer.assume
-import com.futo.platformplayer.fragment.mainactivity.topbar.NavigationTopBarFragment
import com.futo.platformplayer.models.Playlist
-import com.futo.platformplayer.models.SearchType
-import com.futo.platformplayer.states.StatePlatform
+import com.futo.platformplayer.states.StatePlayer
+import com.futo.platformplayer.states.StatePlaylists
import com.futo.platformplayer.views.adapters.*
import com.futo.platformplayer.views.overlays.slideup.SlideUpMenuOverlay
-import com.futo.platformplayer.views.overlays.slideup.SlideUpMenuTextInput
import com.google.android.material.appbar.AppBarLayout
-import kotlin.collections.ArrayList
class PlaylistsFragment : MainFragment() {
@@ -52,7 +46,7 @@ class PlaylistsFragment : MainFragment() {
override fun onShownWithView(parameter: Any?, isBack: Boolean) {
super.onShownWithView(parameter, isBack);
- _view?.onShown(parameter, isBack);
+ _view?.onShown();
}
override fun onBackPressed(): Boolean {
@@ -133,11 +127,12 @@ class PlaylistsFragment : MainFragment() {
StatePlaylists.instance.onWatchLaterChanged.remove(this);
}
- fun onShown(parameter: Any?, isBack: Boolean) {
+ @SuppressLint("NotifyDataSetChanged")
+ fun onShown() {
playlists.clear()
playlists.addAll(
- StatePlaylists.instance.getPlaylists()
- .sortedByDescending { maxOf(it.datePlayed, it.dateUpdate, it.dateCreation) });
+ StatePlaylists.instance.getPlaylists().sortedByDescending { maxOf(it.datePlayed, it.dateUpdate, it.dateCreation) }
+ );
_adapterPlaylist.notifyDataSetChanged();
updateWatchLater();
diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/PostDetailFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/PostDetailFragment.kt
index 87185ba1..3cadb47c 100644
--- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/PostDetailFragment.kt
+++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/PostDetailFragment.kt
@@ -40,15 +40,15 @@ import com.futo.platformplayer.states.StatePlatform
import com.futo.platformplayer.states.StatePolycentric
import com.futo.platformplayer.toHumanNowDiffString
import com.futo.platformplayer.toHumanNumber
-import com.futo.platformplayer.views.comments.AddCommentView
-import com.futo.platformplayer.views.segments.CommentsList
-import com.futo.platformplayer.views.others.CreatorThumbnail
-import com.futo.platformplayer.views.platform.PlatformIndicator
-import com.futo.platformplayer.views.subscriptions.SubscribeButton
-import com.futo.platformplayer.views.others.Toggle
import com.futo.platformplayer.views.adapters.feedtypes.PreviewPostView
+import com.futo.platformplayer.views.comments.AddCommentView
+import com.futo.platformplayer.views.others.CreatorThumbnail
+import com.futo.platformplayer.views.others.Toggle
import com.futo.platformplayer.views.overlays.RepliesOverlay
import com.futo.platformplayer.views.pills.PillRatingLikesDislikes
+import com.futo.platformplayer.views.platform.PlatformIndicator
+import com.futo.platformplayer.views.segments.CommentsList
+import com.futo.platformplayer.views.subscriptions.SubscribeButton
import com.futo.polycentric.core.ApiMethods
import com.futo.polycentric.core.ContentType
import com.futo.polycentric.core.Models
@@ -220,7 +220,7 @@ class PostDetailFragment : MainFragment {
root.removeView(layoutTop);
_commentsList.setPrependedView(layoutTop);
- _commentsList.onCommentsLoaded.subscribe { count ->
+ _commentsList.onCommentsLoaded.subscribe {
updateCommentType(false);
};
diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/SourceDetailFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/SourceDetailFragment.kt
index 9f8a4454..a28e8016 100644
--- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/SourceDetailFragment.kt
+++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/SourceDetailFragment.kt
@@ -13,7 +13,9 @@ import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
import androidx.lifecycle.lifecycleScope
-import com.futo.platformplayer.*
+import com.futo.platformplayer.R
+import com.futo.platformplayer.Settings
+import com.futo.platformplayer.UIDialogs
import com.futo.platformplayer.activities.AddSourceActivity
import com.futo.platformplayer.activities.LoginActivity
import com.futo.platformplayer.api.http.ManagedHttpClient
@@ -25,8 +27,8 @@ import com.futo.platformplayer.states.StatePlatform
import com.futo.platformplayer.states.StatePlugins
import com.futo.platformplayer.views.buttons.BigButton
import com.futo.platformplayer.views.buttons.BigButtonGroup
-import com.futo.platformplayer.views.sources.SourceHeaderView
import com.futo.platformplayer.views.fields.FieldForm
+import com.futo.platformplayer.views.sources.SourceHeaderView
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -40,7 +42,7 @@ class SourceDetailFragment : MainFragment() {
override fun onShownWithView(parameter: Any?, isBack: Boolean) {
super.onShownWithView(parameter, isBack);
- _view?.onShown(parameter, isBack);
+ _view?.onShown(parameter);
}
override fun onHide() {
@@ -92,7 +94,7 @@ class SourceDetailFragment : MainFragment() {
updateSourceViews();
}
- fun onShown(parameter: Any?, isBack: Boolean) {
+ fun onShown(parameter: Any?) {
if (parameter is SourcePluginConfig) {
loadConfig(parameter);
updateSourceViews();
@@ -135,7 +137,7 @@ class SourceDetailFragment : MainFragment() {
try {
_settingsAppForm.fromObject(source.descriptor.appSettings);
_settingsAppForm.onChanged.clear();
- _settingsAppForm.onChanged.subscribe { field, value ->
+ _settingsAppForm.onChanged.subscribe { _, _ ->
_settingsAppChanged = true;
}
} catch (e: Throwable) {
@@ -150,7 +152,7 @@ class SourceDetailFragment : MainFragment() {
context.getString(R.string.these_settings_are_defined_by_the_plugin)
);
_settingsForm.onChanged.clear();
- _settingsForm.onChanged.subscribe { field, value ->
+ _settingsForm.onChanged.subscribe { _, _ ->
_settingsChanged = true;
}
} catch (e: Throwable) {
@@ -478,8 +480,8 @@ class SourceDetailFragment : MainFragment() {
Logger.i(TAG, "Update is available (config.version=${config.version}, source.config.version=${c.version}).");
- val c = context ?: return@launch;
- val intent = Intent(c, AddSourceActivity::class.java).apply {
+ val ctx = context ?: return@launch;
+ val intent = Intent(ctx, AddSourceActivity::class.java).apply {
data = Uri.parse(sourceUrl)
};
diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/SourcesFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/SourcesFragment.kt
index 83e94208..bfe49af6 100644
--- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/SourcesFragment.kt
+++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/SourcesFragment.kt
@@ -1,5 +1,6 @@
package com.futo.platformplayer.fragment.mainactivity.main
+import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.os.Bundle
@@ -10,23 +11,23 @@ import android.widget.LinearLayout
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
-import com.futo.platformplayer.UIDialogs
-import com.futo.platformplayer.states.StatePlatform
import com.futo.platformplayer.R
+import com.futo.platformplayer.UIDialogs
import com.futo.platformplayer.activities.AddSourceOptionsActivity
import com.futo.platformplayer.api.media.IPlatformClient
import com.futo.platformplayer.api.media.platforms.js.JSClient
import com.futo.platformplayer.fragment.mainactivity.topbar.AddTopBarFragment
+import com.futo.platformplayer.states.StatePlatform
import com.futo.platformplayer.states.StatePlugins
import com.futo.platformplayer.stores.FragmentedStorage
import com.futo.platformplayer.stores.SubscriptionStorage
-import com.futo.platformplayer.views.sources.SourceUnderConstructionView
import com.futo.platformplayer.views.adapters.DisabledSourceView
import com.futo.platformplayer.views.adapters.EnabledSourceAdapter
import com.futo.platformplayer.views.adapters.EnabledSourceViewHolder
import com.futo.platformplayer.views.adapters.ItemMoveCallback
+import com.futo.platformplayer.views.sources.SourceUnderConstructionView
import kotlinx.coroutines.runBlocking
-import java.util.*
+import java.util.Collections
class SourcesFragment : MainFragment() {
override val isMainView : Boolean = true;
@@ -159,15 +160,15 @@ class SourcesFragment : MainFragment() {
_didCreateView = true;
}
+ @SuppressLint("NotifyDataSetChanged")
fun reloadSources() {
enabledSources.clear();
disabledSources.clear();
enabledSources.addAll(StatePlatform.instance.getSortedEnabledClient());
disabledSources.addAll(StatePlatform.instance.getAvailableClients().filter { !enabledSources.contains(it) });
- _adapterSourcesEnabled?.notifyDataSetChanged();
+ _adapterSourcesEnabled.notifyDataSetChanged();
setCanRemove(enabledSources.size > 1);
- //_adapterSourcesDisabled?.notifyDataSetChanged();
updateDisabledSources();
if(_didCreateView) {
@@ -207,18 +208,15 @@ class SourcesFragment : MainFragment() {
}
private fun setCanRemove(canRemove: Boolean) {
- val recyclerSourcesEnabled = _recyclerSourcesEnabled ?: return;
- var adapterSourcesEnabled = _adapterSourcesEnabled ?: return;
-
- for (i in 0 until recyclerSourcesEnabled.childCount) {
- val view: View = recyclerSourcesEnabled.getChildAt(i)
- val viewHolder = recyclerSourcesEnabled.getChildViewHolder(view)
+ for (i in 0 until _recyclerSourcesEnabled.childCount) {
+ val view: View = _recyclerSourcesEnabled.getChildAt(i)
+ val viewHolder = _recyclerSourcesEnabled.getChildViewHolder(view)
if (viewHolder is EnabledSourceViewHolder) {
viewHolder.setCanRemove(canRemove);
}
}
- adapterSourcesEnabled.canRemove = canRemove;
+ _adapterSourcesEnabled.canRemove = canRemove;
}
private fun onPrimaryChanged(client: IPlatformClient) {
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 fd821356..cd5dca38 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
@@ -27,12 +27,12 @@ import com.futo.platformplayer.states.StatePlatform
import com.futo.platformplayer.states.StateSubscriptions
import com.futo.platformplayer.stores.FragmentedStorage
import com.futo.platformplayer.stores.FragmentedStorageFileJson
-import com.futo.platformplayer.views.announcements.AnnouncementView
import com.futo.platformplayer.views.FeedStyle
import com.futo.platformplayer.views.NoResultsView
import com.futo.platformplayer.views.adapters.ContentPreviewViewHolder
import com.futo.platformplayer.views.adapters.InsertedViewAdapterWithLoader
import com.futo.platformplayer.views.adapters.InsertedViewHolder
+import com.futo.platformplayer.views.announcements.AnnouncementView
import com.futo.platformplayer.views.buttons.BigButton
import com.futo.platformplayer.views.subscriptions.SubscriptionBar
import kotlinx.coroutines.CancellationException
@@ -111,7 +111,7 @@ class SubscriptionsFeedFragment : MainFragment() {
}
};
- StateSubscriptions.instance.onSubscriptionsChanged.subscribe(this) { subs, added ->
+ StateSubscriptions.instance.onSubscriptionsChanged.subscribe(this) { _, added ->
if(!added)
StateSubscriptions.instance.clearSubscriptionFeed();
StateApp.instance.scopeOrNull?.let {
@@ -146,7 +146,7 @@ class SubscriptionsFeedFragment : MainFragment() {
val homeTab = Settings.instance.tabs.find { it.id == 0 };
val isHomeEnabled = homeTab?.enabled == true;
if (announcementsView != null && isHomeEnabled) {
- headerView?.removeView(announcementsView);
+ headerView.removeView(announcementsView);
_announcementsView = null;
}
@@ -154,7 +154,7 @@ class SubscriptionsFeedFragment : MainFragment() {
val c = context;
if (c != null) {
_announcementsView = AnnouncementView(c, null).apply {
- headerView?.addView(this)
+ headerView.addView(this)
};
}
}
@@ -272,17 +272,18 @@ class SubscriptionsFeedFragment : MainFragment() {
}
private fun toggleFilterContentType(contentType: ContentType, isTrue: Boolean) {
synchronized(_filterLock) {
- if(!isTrue)
+ if(!isTrue) {
_filterSettings.allowContentTypes.remove(contentType);
- else if(!_filterSettings.allowContentTypes.contains(contentType))
+ } else if(!_filterSettings.allowContentTypes.contains(contentType)) {
_filterSettings.allowContentTypes.add(contentType)
- else null;
+ }
_filterSettings.save();
};
- if(Settings.instance.subscriptions.fetchOnTabOpen) //TODO: Do this different, temporary workaround
+ if(Settings.instance.subscriptions.fetchOnTabOpen) { //TODO: Do this different, temporary workaround
loadResults(false);
- else
+ } else {
loadCache();
+ }
}
override fun filterResults(results: List): List {
@@ -381,7 +382,7 @@ class SubscriptionsFeedFragment : MainFragment() {
context?.let {
fragment.lifecycleScope.launch(Dispatchers.Main) {
try {
- if (exs!!.size <= 8) {
+ if (exs.size <= 8) {
for (ex in exs) {
var toShow = ex;
var channel: String? = null;
diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailFragment.kt
index 476acfbb..4f1b087e 100644
--- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailFragment.kt
+++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailFragment.kt
@@ -3,16 +3,17 @@ package com.futo.platformplayer.fragment.mainactivity.main
import android.content.pm.ActivityInfo
import android.content.res.Configuration
import android.os.Bundle
-import android.view.*
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
import androidx.constraintlayout.motion.widget.MotionLayout
-import androidx.core.view.*
-import com.futo.platformplayer.logging.Logger
-import com.futo.platformplayer.states.StatePlayer
+import androidx.core.view.WindowCompat
+import androidx.core.view.WindowInsetsCompat
+import androidx.core.view.WindowInsetsControllerCompat
import com.futo.platformplayer.R
import com.futo.platformplayer.Settings
import com.futo.platformplayer.UIDialogs
import com.futo.platformplayer.activities.MainActivity
-import com.futo.platformplayer.api.media.models.contents.IPlatformContent
import com.futo.platformplayer.api.media.models.video.IPlatformVideo
import com.futo.platformplayer.api.media.models.video.IPlatformVideoDetails
import com.futo.platformplayer.casting.CastConnectionState
@@ -20,8 +21,10 @@ import com.futo.platformplayer.casting.StateCasting
import com.futo.platformplayer.constructs.Event0
import com.futo.platformplayer.constructs.Event1
import com.futo.platformplayer.listeners.OrientationManager
+import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.models.PlatformVideoWithTime
import com.futo.platformplayer.models.UrlVideoWithTime
+import com.futo.platformplayer.states.StatePlayer
import com.futo.platformplayer.states.StateSaved
import com.futo.platformplayer.states.VideoToOpen
import com.futo.platformplayer.views.containers.SingleViewTouchableMotionLayout
@@ -269,7 +272,7 @@ class VideoDetailFragment : MainFragment {
val viewDetail = _viewDetail;
Logger.i(TAG, "onUserLeaveHint preventPictureInPicture=${viewDetail?.preventPictureInPicture} isCasting=${StateCasting.instance.isCasting} isBackgroundPictureInPicture=${Settings.instance.playback.isBackgroundPictureInPicture()} allowBackground=${viewDetail?.allowBackground}");
- if(viewDetail?.preventPictureInPicture == false && !StateCasting.instance.isCasting && Settings.instance.playback.isBackgroundPictureInPicture() && viewDetail?.allowBackground != true) {
+ if(viewDetail?.preventPictureInPicture == false && !StateCasting.instance.isCasting && Settings.instance.playback.isBackgroundPictureInPicture() && !viewDetail.allowBackground) {
_leavingPiP = false;
val params = _viewDetail?.getPictureInPictureParams();
diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailView.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailView.kt
index f1ef3ec4..e7bc360f 100644
--- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailView.kt
+++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailView.kt
@@ -1,3 +1,5 @@
+@file:Suppress("DEPRECATION")
+
package com.futo.platformplayer.fragment.mainactivity.main
import android.app.PictureInPictureParams
@@ -23,16 +25,21 @@ import android.view.View
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.view.WindowManager
-import android.widget.*
+import android.widget.FrameLayout
+import android.widget.ImageButton
+import android.widget.ImageView
+import android.widget.LinearLayout
+import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.lifecycle.lifecycleScope
import com.bumptech.glide.Glide
import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.transition.Transition
-import com.futo.platformplayer.*
-
-import com.futo.platformplayer.api.media.IPluginSourced
import com.futo.platformplayer.R
+import com.futo.platformplayer.Settings
+import com.futo.platformplayer.UIDialogs
+import com.futo.platformplayer.UISlideOverlays
+import com.futo.platformplayer.api.media.IPluginSourced
import com.futo.platformplayer.api.media.LiveChatManager
import com.futo.platformplayer.api.media.PlatformID
import com.futo.platformplayer.api.media.exceptions.ContentNotAvailableYetException
@@ -46,12 +53,17 @@ import com.futo.platformplayer.api.media.models.playback.IPlaybackTracker
import com.futo.platformplayer.api.media.models.ratings.RatingLikeDislikes
import com.futo.platformplayer.api.media.models.ratings.RatingLikes
import com.futo.platformplayer.api.media.models.streams.VideoUnMuxedSourceDescriptor
-import com.futo.platformplayer.api.media.models.streams.sources.*
+import com.futo.platformplayer.api.media.models.streams.sources.IAudioSource
+import com.futo.platformplayer.api.media.models.streams.sources.IDashManifestSource
+import com.futo.platformplayer.api.media.models.streams.sources.IHLSManifestSource
+import com.futo.platformplayer.api.media.models.streams.sources.IVideoSource
+import com.futo.platformplayer.api.media.models.streams.sources.LocalAudioSource
+import com.futo.platformplayer.api.media.models.streams.sources.LocalSubtitleSource
+import com.futo.platformplayer.api.media.models.streams.sources.LocalVideoSource
import com.futo.platformplayer.api.media.models.subtitles.ISubtitleSource
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.SerializedPlatformVideo
-import com.futo.platformplayer.api.media.platforms.js.JSClient
import com.futo.platformplayer.api.media.platforms.js.SourcePluginConfig
import com.futo.platformplayer.api.media.platforms.js.models.JSVideoDetails
import com.futo.platformplayer.api.media.structures.IPager
@@ -61,21 +73,41 @@ import com.futo.platformplayer.constructs.Event0
import com.futo.platformplayer.constructs.Event1
import com.futo.platformplayer.constructs.TaskHandler
import com.futo.platformplayer.downloads.VideoLocal
+import com.futo.platformplayer.dp
import com.futo.platformplayer.engine.exceptions.ScriptAgeException
import com.futo.platformplayer.engine.exceptions.ScriptException
import com.futo.platformplayer.engine.exceptions.ScriptImplementationException
import com.futo.platformplayer.engine.exceptions.ScriptLoginRequiredException
import com.futo.platformplayer.engine.exceptions.ScriptUnavailableException
import com.futo.platformplayer.exceptions.UnsupportedCastException
+import com.futo.platformplayer.fixHtmlLinks
+import com.futo.platformplayer.fixHtmlWhitespace
+import com.futo.platformplayer.fullyBackfillServersAnnounceExceptions
+import com.futo.platformplayer.getNowDiffSeconds
import com.futo.platformplayer.helpers.VideoHelper
import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.models.Subscription
import com.futo.platformplayer.polycentric.PolycentricCache
import com.futo.platformplayer.receivers.MediaControlReceiver
-import com.futo.platformplayer.states.*
+import com.futo.platformplayer.selectBestImage
+import com.futo.platformplayer.states.AnnouncementType
+import com.futo.platformplayer.states.StateAnnouncement
+import com.futo.platformplayer.states.StateApp
+import com.futo.platformplayer.states.StateDownloads
+import com.futo.platformplayer.states.StateHistory
+import com.futo.platformplayer.states.StatePlatform
+import com.futo.platformplayer.states.StatePlayer
+import com.futo.platformplayer.states.StatePlaylists
+import com.futo.platformplayer.states.StatePlugins
+import com.futo.platformplayer.states.StatePolycentric
+import com.futo.platformplayer.states.StateSubscriptions
import com.futo.platformplayer.stores.FragmentedStorage
import com.futo.platformplayer.stores.StringArrayStorage
import com.futo.platformplayer.stores.db.types.DBHistory
+import com.futo.platformplayer.toHumanBitrate
+import com.futo.platformplayer.toHumanNowDiffString
+import com.futo.platformplayer.toHumanNumber
+import com.futo.platformplayer.toHumanTime
import com.futo.platformplayer.views.MonetizationView
import com.futo.platformplayer.views.behavior.TouchInterceptFrameLayout
import com.futo.platformplayer.views.casting.CastView
@@ -87,7 +119,11 @@ import com.futo.platformplayer.views.overlays.LiveChatOverlay
import com.futo.platformplayer.views.overlays.QueueEditorOverlay
import com.futo.platformplayer.views.overlays.RepliesOverlay
import com.futo.platformplayer.views.overlays.SupportOverlay
-import com.futo.platformplayer.views.overlays.slideup.*
+import com.futo.platformplayer.views.overlays.slideup.SlideUpMenuButtonList
+import com.futo.platformplayer.views.overlays.slideup.SlideUpMenuGroup
+import com.futo.platformplayer.views.overlays.slideup.SlideUpMenuItem
+import com.futo.platformplayer.views.overlays.slideup.SlideUpMenuOverlay
+import com.futo.platformplayer.views.overlays.slideup.SlideUpMenuTitle
import com.futo.platformplayer.views.pills.PillRatingLikesDislikes
import com.futo.platformplayer.views.pills.RoundButton
import com.futo.platformplayer.views.pills.RoundButtonGroup
@@ -97,17 +133,25 @@ import com.futo.platformplayer.views.subscriptions.SubscribeButton
import com.futo.platformplayer.views.video.FutoVideoPlayer
import com.futo.platformplayer.views.video.FutoVideoPlayerBase
import com.futo.platformplayer.views.videometa.UpNextView
-import com.futo.polycentric.core.*
+import com.futo.polycentric.core.ApiMethods
+import com.futo.polycentric.core.ContentType
+import com.futo.polycentric.core.Models
+import com.futo.polycentric.core.Opinion
+import com.futo.polycentric.core.toURLInfoSystemLinkUrl
import com.google.android.exoplayer2.C
import com.google.android.exoplayer2.Format
import com.google.android.exoplayer2.ui.PlayerControlView
import com.google.android.exoplayer2.ui.TimeBar
import com.google.android.exoplayer2.upstream.HttpDataSource.InvalidResponseCodeException
import com.google.protobuf.ByteString
-import kotlinx.coroutines.*
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import userpackage.Protocol
import java.time.OffsetDateTime
-import kotlin.collections.ArrayList
import kotlin.math.abs
import kotlin.math.roundToLong
@@ -336,7 +380,7 @@ class VideoDetailView : ConstraintLayout {
};
_monetization.onSupportTap.subscribe {
- _container_content_support.setPolycentricProfile(_polycentricProfile?.profile, false);
+ _container_content_support.setPolycentricProfile(_polycentricProfile?.profile);
switchContentView(_container_content_support);
};
@@ -484,7 +528,7 @@ class VideoDetailView : ConstraintLayout {
};
if (!isInEditMode) {
- StateCasting.instance.onActiveDeviceConnectionStateChanged.subscribe(this) { d, connectionState ->
+ StateCasting.instance.onActiveDeviceConnectionStateChanged.subscribe(this) { _, connectionState ->
if (_onPauseCalled) {
return@subscribe;
}
@@ -530,7 +574,7 @@ class VideoDetailView : ConstraintLayout {
}
_playerProgress.player = _player.exoPlayer?.player;
- _playerProgress.setProgressUpdateListener { position, bufferedPosition ->
+ _playerProgress.setProgressUpdateListener { position, _ ->
StatePlayer.instance.updateMediaSessionPlaybackState(_player.exoPlayer?.getPlaybackStateCompat() ?: PlaybackStateCompat.STATE_NONE, position);
}
@@ -658,7 +702,7 @@ class VideoDetailView : ConstraintLayout {
_trackingLastVideoSubscription?.let {
Logger.i(TAG, "Subscription [${it.channel.name}] watch time delta [${delta}]" +
"(${"%.2f".format((_trackingTotalWatched / 1000) / currentVideo.duration.toDouble().coerceAtLeast(1.0))})");
- it.updatePlayback(currentVideo, (delta / 1000).toInt());
+ it.updatePlayback((delta / 1000).toInt());
_trackingTotalWatched += delta;
if(!_trackingDidCountView && currentVideo.duration > 0) {
val percentage = (_trackingTotalWatched / 1000) / currentVideo.duration.toDouble();
@@ -1048,6 +1092,7 @@ class VideoDetailView : ConstraintLayout {
switchContentView(_container_content_main);
}
+ @OptIn(ExperimentalCoroutinesApi::class)
fun setVideoDetails(videoDetail: IPlatformVideoDetails, newVideo: Boolean = false) {
Logger.i(TAG, "setVideoDetails (${videoDetail.name})")
@@ -1064,8 +1109,8 @@ class VideoDetailView : ConstraintLayout {
_player.setPlaybackRate(Settings.instance.playback.getDefaultPlaybackSpeed());
}
- var videoLocal: VideoLocal? = null;
- var video: IPlatformVideoDetails? = null;
+ val videoLocal: VideoLocal?;
+ val video: IPlatformVideoDetails?;
if(videoDetail is VideoLocal) {
videoLocal = videoDetail;
@@ -1077,7 +1122,7 @@ class VideoDetailView : ConstraintLayout {
return@invokeOnCompletion;
}
val result = videoTask.getCompleted();
- if(this.video == videoDetail && result != null && result is IPlatformVideoDetails) {
+ if(this.video == videoDetail && result is IPlatformVideoDetails) {
this.video = result;
fragment.lifecycleScope.launch(Dispatchers.Main) {
updateQualitySourcesOverlay(result, videoLocal);
@@ -1246,37 +1291,33 @@ class VideoDetailView : ConstraintLayout {
_rating.visibility = View.GONE;
}
- if (video.rating != null) {
- when (video.rating) {
- is RatingLikeDislikes -> {
- val r = video.rating as RatingLikeDislikes;
- _layoutRating.visibility = View.VISIBLE;
+ when (video.rating) {
+ is RatingLikeDislikes -> {
+ val r = video.rating as RatingLikeDislikes;
+ _layoutRating.visibility = View.VISIBLE;
- _textLikes.visibility = View.VISIBLE;
- _imageLikeIcon.visibility = View.VISIBLE;
- _textLikes.text = r.likes.toHumanNumber();
+ _textLikes.visibility = View.VISIBLE;
+ _imageLikeIcon.visibility = View.VISIBLE;
+ _textLikes.text = r.likes.toHumanNumber();
- _imageDislikeIcon.visibility = View.VISIBLE;
- _textDislikes.visibility = View.VISIBLE;
- _textDislikes.text = r.dislikes.toHumanNumber();
- }
- is RatingLikes -> {
- val r = video.rating as RatingLikes;
- _layoutRating.visibility = View.VISIBLE;
-
- _textLikes.visibility = View.VISIBLE;
- _imageLikeIcon.visibility = View.VISIBLE;
- _textLikes.text = r.likes.toHumanNumber();
-
- _imageDislikeIcon.visibility = View.GONE;
- _textDislikes.visibility = View.GONE;
- }
- else -> {
- _layoutRating.visibility = View.GONE;
- }
+ _imageDislikeIcon.visibility = View.VISIBLE;
+ _textDislikes.visibility = View.VISIBLE;
+ _textDislikes.text = r.dislikes.toHumanNumber();
+ }
+ is RatingLikes -> {
+ val r = video.rating as RatingLikes;
+ _layoutRating.visibility = View.VISIBLE;
+
+ _textLikes.visibility = View.VISIBLE;
+ _imageLikeIcon.visibility = View.VISIBLE;
+ _textLikes.text = r.likes.toHumanNumber();
+
+ _imageDislikeIcon.visibility = View.GONE;
+ _textDislikes.visibility = View.GONE;
+ }
+ else -> {
+ _layoutRating.visibility = View.GONE;
}
- } else {
- _layoutRating.visibility = View.GONE;
}
@@ -1636,7 +1677,7 @@ class VideoDetailView : ConstraintLayout {
SlideUpMenuGroup(this.context, context.getString(R.string.offline_video), "video",
*localVideoSources
.map {
- SlideUpMenuItem(this.context, R.drawable.ic_movie, it!!.name, "${it.width}x${it.height}", it,
+ SlideUpMenuItem(this.context, R.drawable.ic_movie, it.name, "${it.width}x${it.height}", it,
{ handleSelectVideoTrack(it) });
}.toList().toTypedArray())
else null,
@@ -1660,7 +1701,7 @@ class VideoDetailView : ConstraintLayout {
SlideUpMenuGroup(this.context, context.getString(R.string.stream_video), "video",
*liveStreamVideoFormats
.map {
- SlideUpMenuItem(this.context, R.drawable.ic_movie, it?.label ?: it.containerMimeType ?: it.bitrate.toString(), "${it.width}x${it.height}", it,
+ SlideUpMenuItem(this.context, R.drawable.ic_movie, it.label ?: it.containerMimeType ?: it.bitrate.toString(), "${it.width}x${it.height}", it,
{ _player.selectVideoTrack(it.height) });
}.toList().toTypedArray())
else null,
@@ -1668,7 +1709,7 @@ class VideoDetailView : ConstraintLayout {
SlideUpMenuGroup(this.context, context.getString(R.string.stream_audio), "audio",
*liveStreamAudioFormats
.map {
- SlideUpMenuItem(this.context, R.drawable.ic_music, "${it?.label ?: it.containerMimeType} ${it.bitrate}", "", it,
+ SlideUpMenuItem(this.context, R.drawable.ic_music, "${it.label ?: it.containerMimeType} ${it.bitrate}", "", it,
{ _player.selectAudioTrack(it.bitrate) });
}.toList().toTypedArray())
else null,
@@ -2216,7 +2257,7 @@ class VideoDetailView : ConstraintLayout {
_channelName.text = username
}
- _monetization.setPolycentricProfile(cachedPolycentricProfile, animate);
+ _monetization.setPolycentricProfile(cachedPolycentricProfile);
}
fun setProgressBarOverlayed(isOverlayed: Boolean?) {
@@ -2292,13 +2333,13 @@ class VideoDetailView : ConstraintLayout {
StateAnnouncement.instance.registerAnnouncement(video?.id?.value + "_Q_NOSOURCES", context.getString(R.string.video_without_source), context.getString(R.string.there_was_a_in_your_queue_videoname_by_authorname_without_the_required_source_being_enabled_playback_was_skipped).replace("{videoName}", video?.name ?: "").replace("{authorName}", video?.author?.name ?: ""), AnnouncementType.SESSION)
}
}
- .exception {
- Logger.w(TAG, "exception", it);
+ .exception { e ->
+ Logger.w(TAG, "exception", e);
- UIDialogs.showDialog(context, R.drawable.ic_security, "Authentication", it.message, null, 0,
+ UIDialogs.showDialog(context, R.drawable.ic_security, "Authentication", e.message, null, 0,
UIDialogs.Action("Cancel", {}),
UIDialogs.Action("Login", {
- val id = it.config?.let { if(it is SourcePluginConfig) it.id else null };
+ val id = e.config.let { if(it is SourcePluginConfig) it.id else null };
val didLogin = if(id == null)
false
else StatePlugins.instance.loginPlugin(context, id) {
diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoListEditorView.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoListEditorView.kt
index c43d926c..c44c6cab 100644
--- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoListEditorView.kt
+++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoListEditorView.kt
@@ -52,7 +52,7 @@ abstract class VideoListEditorView : LinearLayout {
_buttonShare.visibility = View.VISIBLE;
}
else
- _buttonShare?.visibility = View.GONE;
+ _buttonShare.visibility = View.GONE;
buttonPlayAll.setOnClickListener { onPlayAllClick(); };
buttonShuffle.setOnClickListener { onShuffleClick(); };
@@ -106,11 +106,9 @@ abstract class VideoListEditorView : LinearLayout {
};
} else {
_textMetadata.text = "0 " + context.getString(R.string.videos);
- if(_imagePlaylistThumbnail != null) {
- Glide.with(_imagePlaylistThumbnail)
- .load(R.drawable.placeholder_video_thumbnail)
- .into(_imagePlaylistThumbnail);
- }
+ Glide.with(_imagePlaylistThumbnail)
+ .load(R.drawable.placeholder_video_thumbnail)
+ .into(_imagePlaylistThumbnail)
}
_videoListEditorView.setVideos(videos, canEdit);
diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/WatchLaterFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/WatchLaterFragment.kt
index 9b1e847a..807efcbb 100644
--- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/WatchLaterFragment.kt
+++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/WatchLaterFragment.kt
@@ -5,10 +5,10 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
-import com.futo.platformplayer.states.StatePlayer
-import com.futo.platformplayer.states.StatePlaylists
import com.futo.platformplayer.api.media.models.video.IPlatformVideo
import com.futo.platformplayer.api.media.models.video.SerializedPlatformVideo
+import com.futo.platformplayer.states.StatePlayer
+import com.futo.platformplayer.states.StatePlaylists
class WatchLaterFragment : MainFragment() {
override val isMainView : Boolean = true;
@@ -19,7 +19,7 @@ class WatchLaterFragment : MainFragment() {
override fun onShownWithView(parameter: Any?, isBack: Boolean) {
super.onShownWithView(parameter, isBack);
- _view?.onShown(parameter, isBack);
+ _view?.onShown();
}
override fun onCreateMainView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
@@ -42,7 +42,7 @@ class WatchLaterFragment : MainFragment() {
}
- fun onShown(parameter: Any ?, isBack: Boolean) {
+ fun onShown() {
setName("Watch Later");
setVideos(StatePlaylists.instance.getWatchLater(), true);
}
diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/topbar/ImportTopBarFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/topbar/ImportTopBarFragment.kt
index 1d157ce5..076e2c6f 100644
--- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/topbar/ImportTopBarFragment.kt
+++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/topbar/ImportTopBarFragment.kt
@@ -6,6 +6,7 @@ import android.view.View
import android.view.ViewGroup
import android.widget.ImageButton
import android.widget.TextView
+import androidx.core.content.ContextCompat
import com.futo.platformplayer.R
import com.futo.platformplayer.api.media.IPlatformClient
import com.futo.platformplayer.constructs.Event0
@@ -73,9 +74,9 @@ class ImportTopBarFragment : TopFragment() {
fun setImportEnabled(enabled: Boolean) {
if (enabled) {
- _textImport?.setTextColor(resources.getColor(R.color.colorPrimary));
+ _textImport?.setTextColor(ContextCompat.getColor(requireContext(), R.color.colorPrimary));
} else {
- _textImport?.setTextColor(resources.getColor(R.color.gray_67));
+ _textImport?.setTextColor(ContextCompat.getColor(requireContext(), R.color.gray_67));
}
_importEnabled = enabled;
diff --git a/app/src/main/java/com/futo/platformplayer/helpers/VideoHelper.kt b/app/src/main/java/com/futo/platformplayer/helpers/VideoHelper.kt
index e40f83cb..3c03472c 100644
--- a/app/src/main/java/com/futo/platformplayer/helpers/VideoHelper.kt
+++ b/app/src/main/java/com/futo/platformplayer/helpers/VideoHelper.kt
@@ -1,9 +1,10 @@
+@file:Suppress("DEPRECATION")
+
package com.futo.platformplayer.helpers
import android.net.Uri
import com.futo.platformplayer.api.media.models.streams.IVideoSourceDescriptor
import com.futo.platformplayer.api.media.models.streams.VideoUnMuxedSourceDescriptor
-import com.futo.platformplayer.api.media.models.streams.sources.HLSManifestSource
import com.futo.platformplayer.api.media.models.streams.sources.IAudioSource
import com.futo.platformplayer.api.media.models.streams.sources.IAudioUrlSource
import com.futo.platformplayer.api.media.models.streams.sources.IHLSManifestAudioSource
@@ -19,6 +20,7 @@ import com.google.android.exoplayer2.source.MediaSource
import com.google.android.exoplayer2.source.dash.DashMediaSource
import com.google.android.exoplayer2.source.dash.manifest.DashManifestParser
import com.google.android.exoplayer2.upstream.ResolvingDataSource
+import kotlin.math.abs
class VideoHelper {
companion object {
@@ -43,19 +45,17 @@ class VideoHelper {
fun selectBestVideoSource(desc: IVideoSourceDescriptor, desiredPixelCount : Int, prefContainers : Array) : IVideoSource? = selectBestVideoSource(desc.videoSources.toList(), desiredPixelCount, prefContainers);
fun selectBestVideoSource(sources: Iterable, desiredPixelCount : Int, prefContainers : Array) : IVideoSource? {
- val targetVideo = if(desiredPixelCount > 0)
- sources.toList()
- .sortedBy { x -> Math.abs(x.height * x.width - desiredPixelCount) }
- .firstOrNull();
- else
- sources.toList()
- .lastOrNull();
+ val targetVideo = if(desiredPixelCount > 0) {
+ sources.toList().minByOrNull { x -> abs(x.height * x.width - desiredPixelCount) };
+ } else {
+ sources.toList().lastOrNull();
+ }
val hasPriority = sources.any { it.priority };
val targetPixelCount = if(targetVideo != null) targetVideo.width * targetVideo.height else desiredPixelCount;
val altSources = if(hasPriority) {
- sources.filter { it.priority }.sortedBy { x -> Math.abs(x.height * x.width - targetPixelCount) };
+ sources.filter { it.priority }.sortedBy { x -> abs(x.height * x.width - targetPixelCount) };
} else {
sources.filter { it.height == (targetVideo?.height ?: 0) };
}
@@ -76,33 +76,42 @@ class VideoHelper {
fun selectBestAudioSource(desc: IVideoSourceDescriptor, prefContainers : Array, prefLanguage: String? = null, targetBitrate: Long? = null) : IAudioSource? {
if(!desc.isUnMuxed)
return null;
- return selectBestAudioSource((desc as VideoUnMuxedSourceDescriptor).audioSources.toList(), prefContainers, prefLanguage);
+
+ return selectBestAudioSource((desc as VideoUnMuxedSourceDescriptor).audioSources.toList(), prefContainers, prefLanguage, targetBitrate);
}
fun selectBestAudioSource(altSources : Iterable, prefContainers : Array, preferredLanguage: String? = null, targetBitrate: Long? = null) : IAudioSource? {
- val languageToFilter = if(preferredLanguage != null && altSources.any { it.language == preferredLanguage })
+ val languageToFilter = if(preferredLanguage != null && altSources.any { it.language == preferredLanguage }) {
preferredLanguage
- else if(preferredLanguage == null) null
- else "Unknown";
+ } else if(preferredLanguage == null) {
+ null
+ } else {
+ "Unknown"
+ }
- var usableSources = if(languageToFilter != null && altSources.any { it.language == languageToFilter })
+ var usableSources = if(languageToFilter != null && altSources.any { it.language == languageToFilter }) {
altSources.filter { it.language == languageToFilter }.sortedBy { it.bitrate }.toList();
- else altSources.sortedBy { it.bitrate };
+ } else {
+ altSources.sortedBy { it.bitrate }
+ }
- if(usableSources.any { it.priority })
+ if(usableSources.any { it.priority }) {
usableSources = usableSources.filter { it.priority };
+ }
- var bestSource = if(targetBitrate != null)
- usableSources.minByOrNull { Math.abs(it.bitrate - targetBitrate) };
- else
+ var bestSource = if(targetBitrate != null) {
+ usableSources.minByOrNull { abs(it.bitrate - targetBitrate) };
+ } else {
usableSources.lastOrNull();
+ }
for (prefContainer in prefContainers) {
val betterSources = usableSources.filter { it.container == prefContainer };
- val betterSource = if(targetBitrate != null)
- betterSources.minByOrNull { Math.abs(it.bitrate - targetBitrate) };
- else
+ val betterSource = if(targetBitrate != null) {
+ betterSources.minByOrNull { abs(it.bitrate - targetBitrate) };
+ } else {
betterSources.lastOrNull();
+ }
if(betterSource != null) {
bestSource = betterSource;
@@ -112,17 +121,9 @@ class VideoHelper {
return bestSource;
}
- var breakOnce = hashSetOf()
+ @Suppress("DEPRECATION")
fun convertItagSourceToChunkedDashSource(videoSource: JSVideoUrlRangeSource) : MediaSource {
- var urlToUse = videoSource.getVideoUrl();
- /*
- //TODO: REMOVE THIS, PURPOSELY 403s
- if(urlToUse.contains("sig=") && !breakOnce.contains(urlToUse)) {
- breakOnce.add(urlToUse);
- val sigIndex = urlToUse.indexOf("sig=");
- urlToUse = urlToUse.substring(0, sigIndex) + "sig=0" + urlToUse.substring(sigIndex + 4);
- }*/
-
+ val urlToUse = videoSource.getVideoUrl();
val manifestConfig = ProgressiveDashManifestCreator.fromVideoProgressiveStreamingUrl(urlToUse,
videoSource.duration * 1000,
videoSource.container,
@@ -143,13 +144,10 @@ class VideoHelper {
return DashMediaSource.Factory(ResolvingDataSource.Factory(videoSource.getHttpDataSourceFactory(), ResolvingDataSource.Resolver { dataSpec ->
Logger.v("PLAYBACK", "Video REQ Range [" + dataSpec.position + "-" + (dataSpec.position + dataSpec.length) + "](" + dataSpec.length + ")", null);
return@Resolver dataSpec;
- }))
- .createMediaSource(manifest,
- MediaItem.Builder()
- .setUri(Uri.parse(videoSource.getVideoUrl()))
- .build())
+ })).createMediaSource(manifest, MediaItem.Builder().setUri(Uri.parse(videoSource.getVideoUrl())).build())
}
+ @Suppress("DEPRECATION")
fun convertItagSourceToChunkedDashSource(audioSource: JSAudioUrlRangeSource) : MediaSource {
val manifestConfig = ProgressiveDashManifestCreator.fromAudioProgressiveStreamingUrl(audioSource.getAudioUrl(),
audioSource.duration?.times(1000) ?: 0,
@@ -170,11 +168,7 @@ class VideoHelper {
return DashMediaSource.Factory(ResolvingDataSource.Factory(audioSource.getHttpDataSourceFactory(), ResolvingDataSource.Resolver { dataSpec ->
Logger.v("PLAYBACK", "Audio REQ Range [" + dataSpec.position + "-" + (dataSpec.position + dataSpec.length) + "](" + dataSpec.length + ")", null);
return@Resolver dataSpec;
- }))
- .createMediaSource(manifest,
- MediaItem.Builder()
- .setUri(Uri.parse(audioSource.getAudioUrl()))
- .build())
+ })).createMediaSource(manifest, MediaItem.Builder().setUri(Uri.parse(audioSource.getAudioUrl())).build())
}
}
}
diff --git a/app/src/main/java/com/futo/platformplayer/models/Subscription.kt b/app/src/main/java/com/futo/platformplayer/models/Subscription.kt
index b2d41b6e..0d2c5382 100644
--- a/app/src/main/java/com/futo/platformplayer/models/Subscription.kt
+++ b/app/src/main/java/com/futo/platformplayer/models/Subscription.kt
@@ -4,7 +4,6 @@ import com.futo.platformplayer.api.media.models.ResultCapabilities
import com.futo.platformplayer.api.media.models.channels.IPlatformChannel
import com.futo.platformplayer.api.media.models.channels.SerializedChannel
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
-import com.futo.platformplayer.api.media.models.contents.IPlatformContentDetails
import com.futo.platformplayer.getNowDiffDays
import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.serializers.OffsetDateTimeSerializer
@@ -74,7 +73,7 @@ class Subscription {
this.channel = SerializedChannel.fromChannel(channel);
}
- fun updatePlayback(content: IPlatformContentDetails, seconds: Int) {
+ fun updatePlayback(seconds: Int) {
playbackSeconds += seconds;
}
fun addPlaybackView() {
diff --git a/app/src/main/java/com/futo/platformplayer/others/CaptchaWebViewClient.kt b/app/src/main/java/com/futo/platformplayer/others/CaptchaWebViewClient.kt
index bf5abc50..90ae414a 100644
--- a/app/src/main/java/com/futo/platformplayer/others/CaptchaWebViewClient.kt
+++ b/app/src/main/java/com/futo/platformplayer/others/CaptchaWebViewClient.kt
@@ -3,7 +3,6 @@ package com.futo.platformplayer.others
import android.webkit.*
import com.futo.platformplayer.api.media.Serializer
import com.futo.platformplayer.api.media.platforms.js.SourceCaptchaData
-import com.futo.platformplayer.api.media.platforms.js.SourcePluginAuthConfig
import com.futo.platformplayer.api.media.platforms.js.SourcePluginCaptchaConfig
import com.futo.platformplayer.api.media.platforms.js.SourcePluginConfig
import com.futo.platformplayer.constructs.Event1
@@ -58,7 +57,7 @@ class CaptchaWebViewClient : WebViewClient {
if(request == null)
return super.shouldInterceptRequest(view, request as WebResourceRequest?);
- val extracted = _extractor.handleRequest(view, request);
+ val extracted = _extractor.handleRequest(request);
if(extracted != null && !_didNotify) {
_didNotify = true;
onCaptchaFinished.emit(SourceCaptchaData(
diff --git a/app/src/main/java/com/futo/platformplayer/others/LoginWebViewClient.kt b/app/src/main/java/com/futo/platformplayer/others/LoginWebViewClient.kt
index b442508a..0d6e5eea 100644
--- a/app/src/main/java/com/futo/platformplayer/others/LoginWebViewClient.kt
+++ b/app/src/main/java/com/futo/platformplayer/others/LoginWebViewClient.kt
@@ -1,19 +1,22 @@
package com.futo.platformplayer.others
import android.net.Uri
-import android.webkit.*
+import android.webkit.CookieManager
+import android.webkit.WebResourceRequest
+import android.webkit.WebResourceResponse
+import android.webkit.WebView
+import android.webkit.WebViewClient
import com.futo.platformplayer.BuildConfig
import com.futo.platformplayer.api.http.ManagedHttpClient
import com.futo.platformplayer.api.media.Serializer
-import com.futo.platformplayer.constructs.Event1
import com.futo.platformplayer.api.media.platforms.js.SourceAuth
import com.futo.platformplayer.api.media.platforms.js.SourcePluginAuthConfig
import com.futo.platformplayer.api.media.platforms.js.SourcePluginConfig
+import com.futo.platformplayer.constructs.Event1
import com.futo.platformplayer.constructs.Event2
import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.matchesDomain
import kotlinx.serialization.encodeToString
-import kotlinx.serialization.json.Json
class LoginWebViewClient : WebViewClient {
private val LOG_VERBOSE = false;
@@ -30,9 +33,9 @@ class LoginWebViewClient : WebViewClient {
_pluginConfig = config;
_authConfig = config.authentication!!;
Logger.i(TAG, "Login [${config.name}]" +
- "\nRequired Headers: ${config.authentication?.headersToFind?.joinToString(", ")}" +
- "\nRequired Domain Headers: ${Serializer.json.encodeToString(config.authentication?.domainHeadersToFind)}" +
- "\nRequired Cookies: ${Serializer.json.encodeToString(config.authentication?.cookiesToFind)}",);
+ "\nRequired Headers: ${config.authentication.headersToFind?.joinToString(", ")}" +
+ "\nRequired Domain Headers: ${Serializer.json.encodeToString(config.authentication.domainHeadersToFind)}" +
+ "\nRequired Cookies: ${Serializer.json.encodeToString(config.authentication.cookiesToFind)}",);
}
constructor(auth: SourcePluginAuthConfig) : super() {
_pluginConfig = null;
diff --git a/app/src/main/java/com/futo/platformplayer/others/WebViewRequirementExtractor.kt b/app/src/main/java/com/futo/platformplayer/others/WebViewRequirementExtractor.kt
index b62138a8..1722d274 100644
--- a/app/src/main/java/com/futo/platformplayer/others/WebViewRequirementExtractor.kt
+++ b/app/src/main/java/com/futo/platformplayer/others/WebViewRequirementExtractor.kt
@@ -3,8 +3,6 @@ package com.futo.platformplayer.others
import android.net.Uri
import android.webkit.CookieManager
import android.webkit.WebResourceRequest
-import android.webkit.WebView
-import com.futo.platformplayer.api.media.platforms.js.SourceAuth
import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.matchesDomain
@@ -33,13 +31,15 @@ class WebViewRequirementExtractor {
}
- fun handleRequest(view: WebView?, request: WebResourceRequest, logVerbose: Boolean = false): ExtractedData? {
+ fun handleRequest(request: WebResourceRequest, logVerbose: Boolean = false): ExtractedData? {
val domain = request.url.host;
val domainLower = request.url.host?.lowercase();
- if(completionUrl == null)
+ if (completionUrl == null) {
urlFound = true;
- else urlFound = urlFound || request.url == Uri.parse(completionUrl);
+ } else {
+ urlFound = urlFound || request.url == Uri.parse(completionUrl)
+ }
//HEADERS
if(domainLower != null) {
diff --git a/app/src/main/java/com/futo/platformplayer/parsers/HLS.kt b/app/src/main/java/com/futo/platformplayer/parsers/HLS.kt
index 57f42576..734248b2 100644
--- a/app/src/main/java/com/futo/platformplayer/parsers/HLS.kt
+++ b/app/src/main/java/com/futo/platformplayer/parsers/HLS.kt
@@ -1,22 +1,12 @@
package com.futo.platformplayer.parsers
-import android.view.View
-import com.futo.platformplayer.R
-import com.futo.platformplayer.UIDialogs
-import com.futo.platformplayer.api.http.ManagedHttpClient
import com.futo.platformplayer.api.media.models.streams.sources.HLSVariantAudioUrlSource
import com.futo.platformplayer.api.media.models.streams.sources.HLSVariantSubtitleUrlSource
import com.futo.platformplayer.api.media.models.streams.sources.HLSVariantVideoUrlSource
import com.futo.platformplayer.api.media.models.streams.sources.IHLSManifestAudioSource
import com.futo.platformplayer.api.media.models.streams.sources.IHLSManifestSource
-import com.futo.platformplayer.api.media.models.streams.sources.IVideoSource
-import com.futo.platformplayer.states.StateDownloads
import com.futo.platformplayer.toYesNo
-import com.futo.platformplayer.views.overlays.slideup.SlideUpMenuGroup
-import com.futo.platformplayer.views.overlays.slideup.SlideUpMenuItem
import com.futo.platformplayer.yesNoToBoolean
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.withContext
import java.net.URI
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
@@ -73,7 +63,7 @@ class HLS {
val segments = mutableListOf()
var currentSegment: MediaSegment? = null
- lines.forEachIndexed { index, line ->
+ lines.forEach { line ->
when {
line.startsWith("#EXTINF:") -> {
val duration = line.substringAfter(":").substringBefore(",").toDoubleOrNull()
diff --git a/app/src/main/java/com/futo/platformplayer/polycentric/PolycentricCache.kt b/app/src/main/java/com/futo/platformplayer/polycentric/PolycentricCache.kt
index ada84f6a..c80bc8f4 100644
--- a/app/src/main/java/com/futo/platformplayer/polycentric/PolycentricCache.kt
+++ b/app/src/main/java/com/futo/platformplayer/polycentric/PolycentricCache.kt
@@ -1,7 +1,5 @@
package com.futo.platformplayer.polycentric
-import com.futo.polycentric.core.*
-import userpackage.Protocol
import com.futo.platformplayer.api.media.PlatformID
import com.futo.platformplayer.constructs.BatchedTaskHandler
import com.futo.platformplayer.fragment.mainactivity.main.PolycentricProfile
@@ -12,9 +10,25 @@ import com.futo.platformplayer.serializers.OffsetDateTimeSerializer
import com.futo.platformplayer.states.StatePolycentric
import com.futo.platformplayer.stores.CachedPolycentricProfileStorage
import com.futo.platformplayer.stores.FragmentedStorage
+import com.futo.polycentric.core.ApiMethods
+import com.futo.polycentric.core.ContentType
+import com.futo.polycentric.core.OwnedClaim
+import com.futo.polycentric.core.PublicKey
+import com.futo.polycentric.core.SignedEvent
+import com.futo.polycentric.core.StorageTypeSystemState
+import com.futo.polycentric.core.SystemState
+import com.futo.polycentric.core.base64ToByteArray
+import com.futo.polycentric.core.base64UrlToByteArray
+import com.futo.polycentric.core.getClaimIfValid
+import com.futo.polycentric.core.getValidClaims
import com.google.protobuf.ByteString
-import kotlinx.coroutines.*
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Deferred
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.async
+import kotlinx.coroutines.cancel
import kotlinx.serialization.Serializable
+import userpackage.Protocol
import java.nio.ByteBuffer
import java.time.OffsetDateTime
import kotlin.system.measureTimeMillis
@@ -251,8 +265,11 @@ class PolycentricCache {
Logger.v(TAG, "getProfileAsync (id: $id) != null (with retrieved valid claims)")
return getProfileAsync(claims.ownedClaims.first().system).await()
} else {
- if(urlNullCache != null)
- _profileUrlCache.setAndSave(urlNullCache, PolycentricCache.CachedPolycentricProfile(null));
+ synchronized (_cache) {
+ if (urlNullCache != null) {
+ _profileUrlCache.setAndSave(urlNullCache, CachedPolycentricProfile(null))
+ }
+ }
return null;
}
}
diff --git a/app/src/main/java/com/futo/platformplayer/receivers/InstallReceiver.kt b/app/src/main/java/com/futo/platformplayer/receivers/InstallReceiver.kt
index abac844a..09e41150 100644
--- a/app/src/main/java/com/futo/platformplayer/receivers/InstallReceiver.kt
+++ b/app/src/main/java/com/futo/platformplayer/receivers/InstallReceiver.kt
@@ -4,9 +4,10 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.pm.PackageInstaller
-import com.futo.platformplayer.logging.Logger
+import android.os.Build
import com.futo.platformplayer.R
import com.futo.platformplayer.constructs.Event1
+import com.futo.platformplayer.logging.Logger
class InstallReceiver : BroadcastReceiver() {
@@ -16,13 +17,19 @@ class InstallReceiver : BroadcastReceiver() {
val onReceiveResult = Event1();
}
+ @Suppress("DEPRECATION")
override fun onReceive(context: Context, intent: Intent) {
val status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -1);
Logger.i(TAG, "Received status $status.");
when (status) {
PackageInstaller.STATUS_PENDING_USER_ACTION -> {
- val activityIntent = intent.getParcelableExtra(Intent.EXTRA_INTENT)
+ val activityIntent: Intent? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ intent.getParcelableExtra(Intent.EXTRA_INTENT, Intent::class.java)
+ } else {
+ intent.getParcelableExtra(Intent.EXTRA_INTENT)
+ }
+
if (activityIntent == null) {
Logger.w(TAG, "Received STATUS_PENDING_USER_ACTION and activity intent is null.")
return;
diff --git a/app/src/main/java/com/futo/platformplayer/serializers/IRatingSerializer.kt b/app/src/main/java/com/futo/platformplayer/serializers/IRatingSerializer.kt
index 66b607cb..d11714a1 100644
--- a/app/src/main/java/com/futo/platformplayer/serializers/IRatingSerializer.kt
+++ b/app/src/main/java/com/futo/platformplayer/serializers/IRatingSerializer.kt
@@ -1,39 +1,37 @@
package com.futo.platformplayer.serializers
-import com.futo.platformplayer.api.media.models.ratings.*
+import com.futo.platformplayer.api.media.models.ratings.IRating
+import com.futo.platformplayer.api.media.models.ratings.RatingLikeDislikes
+import com.futo.platformplayer.api.media.models.ratings.RatingLikes
+import com.futo.platformplayer.api.media.models.ratings.RatingScaler
+import com.futo.platformplayer.api.media.models.ratings.RatingType
import kotlinx.serialization.DeserializationStrategy
-import kotlinx.serialization.KSerializer
-import kotlinx.serialization.PolymorphicSerializer
-import kotlinx.serialization.descriptors.PrimitiveKind
-import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
-import kotlinx.serialization.descriptors.SerialDescriptor
-import kotlinx.serialization.encoding.Decoder
-import kotlinx.serialization.encoding.Encoder
-import kotlinx.serialization.encoding.decodeStructure
-import kotlinx.serialization.json.*
-import java.time.LocalDateTime
-import java.time.OffsetDateTime
-import java.time.ZoneOffset
-import kotlin.reflect.KClass
+import kotlinx.serialization.json.JsonContentPolymorphicSerializer
+import kotlinx.serialization.json.JsonElement
+import kotlinx.serialization.json.contentOrNull
+import kotlinx.serialization.json.int
+import kotlinx.serialization.json.jsonObject
+import kotlinx.serialization.json.jsonPrimitive
class IRatingSerializer() : JsonContentPolymorphicSerializer(IRating::class) {
- override fun selectDeserializer(element: JsonElement): DeserializationStrategy {
+ override fun selectDeserializer(element: JsonElement): DeserializationStrategy {
val obj = element.jsonObject["type"];
- if(obj?.jsonPrimitive?.isString ?: true)
- return when(obj?.jsonPrimitive?.contentOrNull) {
+ return if(obj?.jsonPrimitive?.isString != false) {
+ when (obj?.jsonPrimitive?.contentOrNull) {
"LIKES" -> RatingLikes.serializer();
"LIKEDISLIKES" -> RatingLikeDislikes.serializer();
"SCALE" -> RatingScaler.serializer();
else -> throw NotImplementedError("Rating Value: ${obj?.jsonPrimitive?.contentOrNull}")
};
- else
- return when(element.jsonObject["type"]?.jsonPrimitive?.int) {
+ } else {
+ when (element.jsonObject["type"]?.jsonPrimitive?.int) {
RatingType.LIKES.value -> RatingLikes.serializer();
RatingType.LIKEDISLIKES.value -> RatingLikeDislikes.serializer();
RatingType.SCALE.value -> RatingScaler.serializer();
- else -> throw NotImplementedError("Rating Value: ${obj?.jsonPrimitive?.int}")
+ else -> throw NotImplementedError("Rating Value: ${obj.jsonPrimitive.int}")
};
+ }
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/futo/platformplayer/serializers/PlatformContentSerializer.kt b/app/src/main/java/com/futo/platformplayer/serializers/PlatformContentSerializer.kt
index c2766a59..70808ba2 100644
--- a/app/src/main/java/com/futo/platformplayer/serializers/PlatformContentSerializer.kt
+++ b/app/src/main/java/com/futo/platformplayer/serializers/PlatformContentSerializer.kt
@@ -6,33 +6,40 @@ import com.futo.platformplayer.api.media.models.video.SerializedPlatformNestedCo
import com.futo.platformplayer.api.media.models.video.SerializedPlatformPost
import com.futo.platformplayer.api.media.models.video.SerializedPlatformVideo
import kotlinx.serialization.DeserializationStrategy
-import kotlinx.serialization.json.*
+import kotlinx.serialization.json.JsonContentPolymorphicSerializer
+import kotlinx.serialization.json.JsonElement
+import kotlinx.serialization.json.booleanOrNull
+import kotlinx.serialization.json.contentOrNull
+import kotlinx.serialization.json.int
+import kotlinx.serialization.json.jsonObject
+import kotlinx.serialization.json.jsonPrimitive
-class PlatformContentSerializer() : JsonContentPolymorphicSerializer(SerializedPlatformContent::class) {
+class PlatformContentSerializer : JsonContentPolymorphicSerializer(SerializedPlatformContent::class) {
- override fun selectDeserializer(element: JsonElement): DeserializationStrategy {
+ override fun selectDeserializer(element: JsonElement): DeserializationStrategy {
val obj = element.jsonObject["contentType"];
//TODO: Remove this temporary fallback..at some point
if(obj == null && element.jsonObject["isLive"]?.jsonPrimitive?.booleanOrNull != null)
return SerializedPlatformVideo.serializer();
- if(obj?.jsonPrimitive?.isString ?: true)
- return when(obj?.jsonPrimitive?.contentOrNull) {
+ if(obj?.jsonPrimitive?.isString != false) {
+ return when (obj?.jsonPrimitive?.contentOrNull) {
"MEDIA" -> SerializedPlatformVideo.serializer();
"NESTED_VIDEO" -> SerializedPlatformNestedContent.serializer();
"ARTICLE" -> throw NotImplementedError("Articles not yet implemented");
"POST" -> SerializedPlatformPost.serializer();
else -> throw NotImplementedError("Unknown Content Type Value: ${obj?.jsonPrimitive?.contentOrNull}")
};
- else
- return when(obj?.jsonPrimitive?.int) {
+ } else {
+ return when (obj.jsonPrimitive.int) {
ContentType.MEDIA.value -> SerializedPlatformVideo.serializer();
ContentType.NESTED_VIDEO.value -> SerializedPlatformNestedContent.serializer();
ContentType.ARTICLE.value -> throw NotImplementedError("Articles not yet implemented");
ContentType.POST.value -> SerializedPlatformPost.serializer();
- else -> throw NotImplementedError("Unknown Content Type Value: ${obj?.jsonPrimitive?.int}")
+ else -> throw NotImplementedError("Unknown Content Type Value: ${obj.jsonPrimitive.int}")
};
+ }
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/futo/platformplayer/serializers/VideoDescriptorSerializer.kt b/app/src/main/java/com/futo/platformplayer/serializers/VideoDescriptorSerializer.kt
index b9ffee13..5f960c1c 100644
--- a/app/src/main/java/com/futo/platformplayer/serializers/VideoDescriptorSerializer.kt
+++ b/app/src/main/java/com/futo/platformplayer/serializers/VideoDescriptorSerializer.kt
@@ -4,12 +4,16 @@ import com.futo.platformplayer.api.media.models.video.ISerializedVideoSourceDesc
import com.futo.platformplayer.api.media.models.video.SerializedVideoMuxedSourceDescriptor
import com.futo.platformplayer.api.media.models.video.SerializedVideoNonMuxedSourceDescriptor
import kotlinx.serialization.DeserializationStrategy
-import kotlinx.serialization.json.*
+import kotlinx.serialization.json.JsonContentPolymorphicSerializer
+import kotlinx.serialization.json.JsonElement
+import kotlinx.serialization.json.boolean
+import kotlinx.serialization.json.jsonObject
+import kotlinx.serialization.json.jsonPrimitive
class VideoDescriptorSerializer() : JsonContentPolymorphicSerializer(ISerializedVideoSourceDescriptor::class) {
- override fun selectDeserializer(element: JsonElement): DeserializationStrategy {
+ override fun selectDeserializer(element: JsonElement): DeserializationStrategy {
return when(element.jsonObject["isUnMuxed"]?.jsonPrimitive?.boolean) {
false -> SerializedVideoMuxedSourceDescriptor.serializer();
true -> SerializedVideoNonMuxedSourceDescriptor.serializer();
diff --git a/app/src/main/java/com/futo/platformplayer/services/DownloadService.kt b/app/src/main/java/com/futo/platformplayer/services/DownloadService.kt
index f58352ee..284328e2 100644
--- a/app/src/main/java/com/futo/platformplayer/services/DownloadService.kt
+++ b/app/src/main/java/com/futo/platformplayer/services/DownloadService.kt
@@ -7,15 +7,16 @@ import android.app.Service
import android.content.Context
import android.content.Intent
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
-import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
import android.os.Build
import android.os.IBinder
import androidx.core.app.NotificationCompat
-import com.futo.platformplayer.*
+import com.futo.platformplayer.R
+import com.futo.platformplayer.Settings
import com.futo.platformplayer.activities.MainActivity
import com.futo.platformplayer.api.http.ManagedHttpClient
import com.futo.platformplayer.downloads.VideoDownload
import com.futo.platformplayer.exceptions.DownloadException
+import com.futo.platformplayer.getNowDiffMinutes
import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.states.Announcement
import com.futo.platformplayer.states.AnnouncementType
@@ -150,10 +151,16 @@ class DownloadService : Service() {
currentVideo.changeState(VideoDownload.State.ERROR);
ignore.add(currentVideo);
- if(ex !is CancellationException)
- StateAnnouncement.instance.registerAnnouncement(currentVideo?.id?.value?:"" + currentVideo?.id?.pluginId?:"" + "_FailDownload",
+ if(ex !is CancellationException) {
+ StateAnnouncement.instance.registerAnnouncement(
+ currentVideo.id.value ?: ("" + currentVideo.id.pluginId),
"Download failed",
- "Download for [${currentVideo.name}] failed.\nDownloads are automatically retried.\nReason: ${ex.message}", AnnouncementType.SESSION, null, "download");
+ "Download for [${currentVideo.name}] failed.\nDownloads are automatically retried.\nReason: ${ex.message}",
+ AnnouncementType.SESSION,
+ null,
+ "download"
+ );
+ }
//Give it a sec
Thread.sleep(500);
@@ -262,7 +269,7 @@ class DownloadService : Service() {
fun closeDownloadSession() {
Logger.i(TAG, "closeDownloadSession");
- stopForeground(true);
+ stopForeground(STOP_FOREGROUND_DETACH);
_notificationManager?.cancel(DOWNLOAD_NOTIF_ID);
stopService();
_started = false;
diff --git a/app/src/main/java/com/futo/platformplayer/services/ExportingService.kt b/app/src/main/java/com/futo/platformplayer/services/ExportingService.kt
index 041a9552..fc5c24a3 100644
--- a/app/src/main/java/com/futo/platformplayer/services/ExportingService.kt
+++ b/app/src/main/java/com/futo/platformplayer/services/ExportingService.kt
@@ -6,23 +6,26 @@ import android.app.PendingIntent
import android.app.Service
import android.content.Context
import android.content.Intent
-import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
import android.content.pm.ServiceInfo
import android.os.Build
import android.os.IBinder
import androidx.core.app.NotificationCompat
-import androidx.core.content.FileProvider
-import com.futo.platformplayer.*
+import com.futo.platformplayer.R
import com.futo.platformplayer.activities.MainActivity
import com.futo.platformplayer.api.http.ManagedHttpClient
import com.futo.platformplayer.downloads.VideoExport
import com.futo.platformplayer.logging.Logger
+import com.futo.platformplayer.share
import com.futo.platformplayer.states.Announcement
import com.futo.platformplayer.states.AnnouncementType
import com.futo.platformplayer.states.StateAnnouncement
import com.futo.platformplayer.states.StateDownloads
import com.futo.platformplayer.stores.FragmentedStorage
-import kotlinx.coroutines.*
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import java.time.OffsetDateTime
import java.util.UUID
@@ -184,7 +187,7 @@ class ExportingService : Service() {
fun closeExportSession() {
Logger.i(TAG, "closeExportSession");
- stopForeground(true);
+ stopForeground(STOP_FOREGROUND_DETACH);
_notificationManager?.cancel(EXPORT_NOTIF_ID);
stopService();
_started = false;
diff --git a/app/src/main/java/com/futo/platformplayer/services/MediaPlaybackService.kt b/app/src/main/java/com/futo/platformplayer/services/MediaPlaybackService.kt
index 85171d2b..ba73594e 100644
--- a/app/src/main/java/com/futo/platformplayer/services/MediaPlaybackService.kt
+++ b/app/src/main/java/com/futo/platformplayer/services/MediaPlaybackService.kt
@@ -1,6 +1,10 @@
package com.futo.platformplayer.services
-import android.app.*
+import android.app.ActivityManager
+import android.app.NotificationChannel
+import android.app.NotificationManager
+import android.app.PendingIntent
+import android.app.Service
import android.content.Context
import android.content.Intent
import android.content.pm.ServiceInfo
@@ -21,14 +25,14 @@ import androidx.core.app.NotificationCompat
import com.bumptech.glide.Glide
import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.transition.Transition
-import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.R
import com.futo.platformplayer.Settings
-import com.futo.platformplayer.states.StatePlatform
-import com.futo.platformplayer.states.StatePlayer
import com.futo.platformplayer.activities.MainActivity
import com.futo.platformplayer.api.media.models.video.IPlatformVideo
+import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.receivers.MediaControlReceiver
+import com.futo.platformplayer.states.StatePlatform
+import com.futo.platformplayer.states.StatePlayer
import com.futo.platformplayer.stores.FragmentedStorage
class MediaPlaybackService : Service() {
@@ -148,7 +152,7 @@ class MediaPlaybackService : Service() {
fun closeMediaSession() {
Logger.v(TAG, "closeMediaSession");
- stopForeground(true);
+ stopForeground(STOP_FOREGROUND_DETACH);
val focusRequest = _focusRequest;
if (focusRequest != null) {
@@ -214,7 +218,7 @@ class MediaPlaybackService : Service() {
else
notifyMediaSession(video, null);
}
- private fun generateMediaAction(context: Context, icon: Int, title: String, intent: PendingIntent) : NotificationCompat.Action {
+ private fun generateMediaAction(icon: Int, title: String, intent: PendingIntent) : NotificationCompat.Action {
return NotificationCompat.Action.Builder(icon, title, intent).build();
}
private fun notifyMediaSession(video: IPlatformVideo?, desiredBitmap: Bitmap?) {
@@ -259,17 +263,37 @@ class MediaPlaybackService : Service() {
val playWhenReady = StatePlayer.instance.isPlaying;
if(hasQueue)
- builder = builder.addAction(generateMediaAction(this, R.drawable.ic_fast_rewind_notif, "Back", MediaControlReceiver.getPrevIntent(this, 3)))
+ builder = builder.addAction(generateMediaAction(
+ R.drawable.ic_fast_rewind_notif,
+ "Back",
+ MediaControlReceiver.getPrevIntent(this, 3)
+ ))
if(playWhenReady)
- builder = builder.addAction(generateMediaAction(this, R.drawable.ic_pause_notif, "Pause", MediaControlReceiver.getPauseIntent(this, 2)));
+ builder = builder.addAction(generateMediaAction(
+ R.drawable.ic_pause_notif,
+ "Pause",
+ MediaControlReceiver.getPauseIntent(this, 2)
+ ));
else
- builder = builder.addAction(generateMediaAction(this, R.drawable.ic_play_notif, "Play", MediaControlReceiver.getPlayIntent(this, 1)));
+ builder = builder.addAction(generateMediaAction(
+ R.drawable.ic_play_notif,
+ "Play",
+ MediaControlReceiver.getPlayIntent(this, 1)
+ ));
if(hasQueue)
- builder = builder.addAction(generateMediaAction(this, R.drawable.ic_fast_forward_notif, "Forward", MediaControlReceiver.getNextIntent(this, 4)));
+ builder = builder.addAction(generateMediaAction(
+ R.drawable.ic_fast_forward_notif,
+ "Forward",
+ MediaControlReceiver.getNextIntent(this, 4)
+ ));
- builder = builder.addAction(generateMediaAction(this, R.drawable.ic_stop_notif, "Stop", MediaControlReceiver.getCloseIntent(this, 5)));
+ builder = builder.addAction(generateMediaAction(
+ R.drawable.ic_stop_notif,
+ "Stop",
+ MediaControlReceiver.getCloseIntent(this, 5)
+ ));
if(bitmap?.isRecycled ?: false)
bitmap = null;
diff --git a/app/src/main/java/com/futo/platformplayer/states/StateAnnouncement.kt b/app/src/main/java/com/futo/platformplayer/states/StateAnnouncement.kt
index 9bced80b..a2304d72 100644
--- a/app/src/main/java/com/futo/platformplayer/states/StateAnnouncement.kt
+++ b/app/src/main/java/com/futo/platformplayer/states/StateAnnouncement.kt
@@ -1,19 +1,15 @@
package com.futo.platformplayer.states
-import android.content.Context
import com.futo.platformplayer.UIDialogs
import com.futo.platformplayer.api.http.ManagedHttpClient
import com.futo.platformplayer.constructs.Event0
-import com.futo.platformplayer.constructs.Event1
import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.serializers.OffsetDateTimeNullableSerializer
import com.futo.platformplayer.stores.FragmentedStorage
import com.futo.platformplayer.stores.StringHashSetStorage
-import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.serialization.Serializable
-import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import java.time.OffsetDateTime
import java.util.Random
@@ -70,9 +66,7 @@ class StateAnnouncement {
synchronized(_lock) {
val idActual = id ?: UUID.randomUUID().toString();
val announcement = SessionAnnouncement(idActual, title, msg, announceType, time, category, actionButton, idActual);
-
- if(action != null)
- _sessionActions.put(idActual, action);
+ _sessionActions[idActual] = action;
registerAnnouncementSession(announcement);
}
}
@@ -81,20 +75,21 @@ class StateAnnouncement {
val idActual = id ?: UUID.randomUUID().toString();
val announcement = SessionAnnouncement(idActual, title, msg, announceType, time, category, actionButton, idActual, cancelButton, if(cancelAction != null) idActual + "_cancel" else null);
- if(action != null)
- _sessionActions.put(idActual, action);
- if(cancelAction != null)
+ _sessionActions.put(idActual, action);
+ if(cancelAction != null) {
_sessionActions.put(idActual + "_cancel", cancelAction);
+ }
registerAnnouncementSession(announcement);
}
}
fun registerAnnouncement(id: String?, title: String, msg: String, announceType: AnnouncementType = AnnouncementType.DELETABLE, time: OffsetDateTime? = null, category: String? = null, actionButton: String? = null, actionId: String? = null) {
- val newAnnouncement = Announcement(if(id == null) UUID.randomUUID().toString() else id, title, msg, announceType, time, category, actionButton, actionId);
+ val newAnnouncement = Announcement(id ?: UUID.randomUUID().toString(), title, msg, announceType, time, category, actionButton, actionId);
- if(announceType == AnnouncementType.SESSION || announceType == AnnouncementType.SESSION_RECURRING)
+ if(announceType == AnnouncementType.SESSION || announceType == AnnouncementType.SESSION_RECURRING) {
registerAnnouncementSession(newAnnouncement);
- else
+ } else {
registerAnnouncement(newAnnouncement);
+ }
}
fun registerAnnouncementSession(announcement: Announcement) {
synchronized(_lock) {
diff --git a/app/src/main/java/com/futo/platformplayer/states/StateApp.kt b/app/src/main/java/com/futo/platformplayer/states/StateApp.kt
index 3129637c..771c98b0 100644
--- a/app/src/main/java/com/futo/platformplayer/states/StateApp.kt
+++ b/app/src/main/java/com/futo/platformplayer/states/StateApp.kt
@@ -13,7 +13,6 @@ import android.net.NetworkRequest
import android.net.Uri
import android.provider.DocumentsContract
import android.util.DisplayMetrics
-import android.util.Xml
import androidx.documentfile.provider.DocumentFile
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
@@ -23,33 +22,23 @@ import com.futo.platformplayer.R
import com.futo.platformplayer.activities.CaptchaActivity
import com.futo.platformplayer.activities.IWithResultLauncher
import com.futo.platformplayer.activities.MainActivity
-import com.futo.platformplayer.api.media.models.video.SerializedPlatformContent
-import com.futo.platformplayer.api.media.models.video.SerializedPlatformVideo
import com.futo.platformplayer.api.media.platforms.js.DevJSClient
import com.futo.platformplayer.api.media.platforms.js.JSClient
import com.futo.platformplayer.background.BackgroundWorker
import com.futo.platformplayer.casting.StateCasting
import com.futo.platformplayer.constructs.Event0
import com.futo.platformplayer.engine.exceptions.ScriptCaptchaRequiredException
-import com.futo.platformplayer.engine.exceptions.ScriptLoginRequiredException
import com.futo.platformplayer.fragment.mainactivity.main.HomeFragment
import com.futo.platformplayer.fragment.mainactivity.main.SourceDetailFragment
import com.futo.platformplayer.logging.AndroidLogConsumer
import com.futo.platformplayer.logging.FileLogConsumer
import com.futo.platformplayer.logging.LogLevel
import com.futo.platformplayer.logging.Logger
-import com.futo.platformplayer.models.HistoryVideo
import com.futo.platformplayer.receivers.AudioNoisyReceiver
-import com.futo.platformplayer.serializers.PlatformContentSerializer
import com.futo.platformplayer.services.DownloadService
import com.futo.platformplayer.stores.FragmentedStorage
-import com.futo.platformplayer.stores.db.ManagedDBStore
-import com.futo.platformplayer.stores.db.types.DBHistory
-import com.futo.platformplayer.stores.v2.JsonStoreSerializer
import com.futo.platformplayer.stores.v2.ManagedStore
import kotlinx.coroutines.*
-import kotlinx.serialization.decodeFromString
-import kotlinx.serialization.json.Json
import java.io.File
import java.time.OffsetDateTime
import java.util.*
@@ -393,7 +382,7 @@ class StateApp {
scopeOrNull?.launch(Dispatchers.Main) {
try {
if (it != null) {
- UIDialogs.toast("Uploaded " + (it ?: "null"), true);
+ UIDialogs.toast("Uploaded $it", true);
} else {
UIDialogs.toast("Failed to upload");
}
@@ -752,9 +741,6 @@ class StateApp {
})
}
}
- fun handleLoginException(client: JSClient, exception: ScriptLoginRequiredException, onSuccess: (client: JSClient)->Unit) {
-
- }
fun getLocaleContext(baseContext: Context?): Context? {
val locale = getLocaleSetting(baseContext);
diff --git a/app/src/main/java/com/futo/platformplayer/states/StateAssets.kt b/app/src/main/java/com/futo/platformplayer/states/StateAssets.kt
index 8fb08b77..605ea928 100644
--- a/app/src/main/java/com/futo/platformplayer/states/StateAssets.kt
+++ b/app/src/main/java/com/futo/platformplayer/states/StateAssets.kt
@@ -2,7 +2,6 @@ package com.futo.platformplayer.states
import android.content.Context
import kotlin.streams.asSequence
-import kotlin.streams.toList
/***
* Used to read assets
@@ -33,28 +32,28 @@ class StateAssets {
/**
* Does basic asset resolving under certain conditions
*/
- fun readAssetRelative(context: Context, base: String, path: String, cache: Boolean = false) : String? {
+ fun readAssetRelative(context: Context, base: String, path: String) : String? {
val finalPath = resolvePath(base, path);
- return readAsset(context, finalPath, cache);
+ return readAsset(context, finalPath);
}
fun readAssetBinRelative(context: Context, base: String, path: String) : ByteArray? {
val finalPath = resolvePath(base, path);
return readAssetBin(context, finalPath);
}
- fun readAsset(context: Context, path: String, cache: Boolean = false) : String? {
- var text: String? = null;
+ fun readAsset(context: Context, path: String) : String? {
+ var text: String?;
synchronized(_cache) {
if (!_cache.containsKey(path)) {
- text = context
- ?.assets
+ text = context.assets
?.open(path)
?.bufferedReader()
?.use { it.readText(); };
+
_cache.put(path, text);
+ } else {
+ text = _cache[path];
}
- else
- text = _cache.get(path);
}
return text;
}
diff --git a/app/src/main/java/com/futo/platformplayer/states/StateBackup.kt b/app/src/main/java/com/futo/platformplayer/states/StateBackup.kt
index b3a7ea3e..35bb14ce 100644
--- a/app/src/main/java/com/futo/platformplayer/states/StateBackup.kt
+++ b/app/src/main/java/com/futo/platformplayer/states/StateBackup.kt
@@ -27,19 +27,16 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
-import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileNotFoundException
-import java.lang.Exception
import java.time.OffsetDateTime
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
import java.util.zip.ZipOutputStream
-import kotlin.IllegalStateException
class StateBackup {
companion object {
@@ -102,7 +99,7 @@ class StateBackup {
val backupFiles = getAutomaticBackupDocumentFiles(context, true);
val exportFile = backupFiles.first;
if (exportFile?.exists() == true && backupFiles.second != null)
- exportFile!!.copyTo(context, backupFiles.second!!);
+ exportFile.copyTo(context, backupFiles.second!!);
exportFile!!.writeBytes(context, encryptedZip);
Settings.instance.backup.lastAutoBackupTime = OffsetDateTime.now(); //OffsetDateTime.now();
@@ -488,11 +485,11 @@ class StateBackup {
companion object {
fun fromZip(zipStream: ZipInputStream): ExportStructure {
- var entry: ZipEntry? = null
+ var entry: ZipEntry?
var exportInfo: Map = mapOf();
var settings: String? = null;
- var stores: MutableMap> = mutableMapOf();
+ val stores: MutableMap> = mutableMapOf();
var plugins: Map = mapOf();
var pluginSettings: Map> = mapOf();
diff --git a/app/src/main/java/com/futo/platformplayer/states/StateCache.kt b/app/src/main/java/com/futo/platformplayer/states/StateCache.kt
index da9f96ea..409a503c 100644
--- a/app/src/main/java/com/futo/platformplayer/states/StateCache.kt
+++ b/app/src/main/java/com/futo/platformplayer/states/StateCache.kt
@@ -1,6 +1,5 @@
package com.futo.platformplayer.states
-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.video.SerializedPlatformContent
import com.futo.platformplayer.api.media.structures.DedupContentPager
@@ -12,15 +11,10 @@ import com.futo.platformplayer.resolveChannelUrl
import com.futo.platformplayer.serializers.PlatformContentSerializer
import com.futo.platformplayer.stores.db.ManagedDBStore
import com.futo.platformplayer.stores.db.types.DBSubscriptionCache
-import com.futo.platformplayer.stores.v2.JsonStoreSerializer
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
-import kotlinx.serialization.encodeToString
-import kotlinx.serialization.json.Json
import java.time.OffsetDateTime
-import kotlin.streams.asSequence
-import kotlin.streams.toList
import kotlin.system.measureTimeMillis
class StateCache {
@@ -140,9 +134,11 @@ class StateCache {
Logger.i(TAG, "Caching ${results.size} subscription initial results [${pager.hashCode()}]");
scope.launch(Dispatchers.IO) {
try {
- val newCacheItems = StateCache.instance.cacheContents(results, true);
- if(onNewCacheItem != null)
- newCacheItems.forEach { onNewCacheItem!!(it) }
+ val newCacheItems = instance.cacheContents(results, true);
+
+ onNewCacheItem?.let { f ->
+ newCacheItems.forEach { f(it) }
+ }
} catch (e: Throwable) {
Logger.e(TAG, "Failed to cache videos.", e);
}
@@ -163,10 +159,11 @@ class StateCache {
val ms = measureTimeMillis {
val newCacheItems = instance.cacheContents(results, true);
newCacheItemsCount = newCacheItems.size;
- if(onNewCacheItem != null)
- newCacheItems.forEach { onNewCacheItem!!(it) }
+ onNewCacheItem?.let { f ->
+ newCacheItems.forEach { f(it) }
+ }
}
- Logger.i(TAG, "Caching ${results.size} subscription results, updated ${newCacheItemsCount} (${ms}ms)");
+ Logger.i(TAG, "Caching ${results.size} subscription results, updated $newCacheItemsCount (${ms}ms)");
} catch (e: Throwable) {
Logger.e(TAG, "Failed to cache ${results.size} videos.", e);
}
diff --git a/app/src/main/java/com/futo/platformplayer/states/StateDownloads.kt b/app/src/main/java/com/futo/platformplayer/states/StateDownloads.kt
index f6cbd9b7..543f62c8 100644
--- a/app/src/main/java/com/futo/platformplayer/states/StateDownloads.kt
+++ b/app/src/main/java/com/futo/platformplayer/states/StateDownloads.kt
@@ -1,7 +1,6 @@
package com.futo.platformplayer.states
import android.content.ContentResolver
-import android.net.Uri
import android.os.StatFs
import com.futo.platformplayer.R
import com.futo.platformplayer.Settings
@@ -9,24 +8,28 @@ import com.futo.platformplayer.UIDialogs
import com.futo.platformplayer.api.http.ManagedHttpClient
import com.futo.platformplayer.api.media.PlatformID
import com.futo.platformplayer.api.media.exceptions.AlreadyQueuedException
-import com.futo.platformplayer.api.media.models.streams.sources.*
+import com.futo.platformplayer.api.media.models.streams.sources.IAudioUrlSource
+import com.futo.platformplayer.api.media.models.streams.sources.IVideoUrlSource
+import com.futo.platformplayer.api.media.models.streams.sources.LocalAudioSource
+import com.futo.platformplayer.api.media.models.streams.sources.LocalSubtitleSource
+import com.futo.platformplayer.api.media.models.streams.sources.LocalVideoSource
+import com.futo.platformplayer.api.media.models.streams.sources.SubtitleRawSource
import com.futo.platformplayer.api.media.models.subtitles.ISubtitleSource
import com.futo.platformplayer.api.media.models.video.IPlatformVideo
import com.futo.platformplayer.api.media.models.video.IPlatformVideoDetails
import com.futo.platformplayer.constructs.Event0
import com.futo.platformplayer.downloads.PlaylistDownloadDescriptor
-import com.futo.platformplayer.downloads.VideoLocal
import com.futo.platformplayer.downloads.VideoDownload
import com.futo.platformplayer.downloads.VideoExport
+import com.futo.platformplayer.downloads.VideoLocal
import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.models.DiskUsage
import com.futo.platformplayer.models.Playlist
import com.futo.platformplayer.models.PlaylistDownloaded
import com.futo.platformplayer.services.DownloadService
import com.futo.platformplayer.services.ExportingService
-import com.futo.platformplayer.stores.*
+import com.futo.platformplayer.stores.FragmentedStorage
import com.futo.platformplayer.stores.v2.ManagedStore
-import okhttp3.internal.platform.Platform
import java.io.File
/***
@@ -349,17 +352,19 @@ class StateDownloads {
fun cleanupDownloads(): Pair {
val expected = getDownloadedVideos();
- val validFiles = HashSet(expected.flatMap { it.videoSource.map { it.filePath } + it.audioSource.map { it.filePath } });
+ val validFiles = HashSet(expected.flatMap { e -> e.videoSource.map { it.filePath } + e.audioSource.map { it.filePath } });
var totalDeleted: Long = 0;
var totalDeletedCount = 0;
- for(file in _downloadsDirectory.listFiles()) {
- val absUrl = file.absolutePath;
- if(!validFiles.contains(absUrl)) {
- Logger.i("StateDownloads", "Deleting unresolved ${file.name}");
- totalDeletedCount++;
- totalDeleted += file.length();
- file.delete();
+ _downloadsDirectory.listFiles()?.let {
+ for(file in it) {
+ val absUrl = file.absolutePath;
+ if(!validFiles.contains(absUrl)) {
+ Logger.i("StateDownloads", "Deleting unresolved ${file.name}");
+ totalDeletedCount++;
+ totalDeleted += file.length();
+ file.delete();
+ }
}
}
return Pair(totalDeletedCount, totalDeleted);
diff --git a/app/src/main/java/com/futo/platformplayer/states/StateHistory.kt b/app/src/main/java/com/futo/platformplayer/states/StateHistory.kt
index b1151d0c..c6d2f4bf 100644
--- a/app/src/main/java/com/futo/platformplayer/states/StateHistory.kt
+++ b/app/src/main/java/com/futo/platformplayer/states/StateHistory.kt
@@ -10,13 +10,9 @@ import com.futo.platformplayer.stores.FragmentedStorage
import com.futo.platformplayer.stores.db.ManagedDBStore
import com.futo.platformplayer.stores.db.types.DBHistory
import com.futo.platformplayer.stores.v2.ReconstructStore
-import kotlinx.serialization.decodeFromString
-import kotlinx.serialization.json.Json
import java.time.OffsetDateTime
-import java.util.UUID
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentMap
-import kotlin.system.measureTimeMillis
class StateHistory {
//Legacy
@@ -57,8 +53,7 @@ class StateHistory {
fun updateHistoryPosition(liveObj: IPlatformVideo, index: DBHistory.Index, updateExisting: Boolean, position: Long = -1L): Long {
val pos = if(position < 0) 0 else position;
- if(index.obj == null) throw IllegalStateException("Can only update history with a deserialized db item");
- val historyVideo = index.obj!!;
+ val historyVideo = index.obj;
val positionBefore = historyVideo.position;
if (updateExisting) {
@@ -72,8 +67,6 @@ class StateHistory {
}
if (shouldUpdate) {
-
- //A unrecovered item
if(historyVideo.video.author.id.value == null && historyVideo.video.duration == 0L)
historyVideo.video = SerializedPlatformVideo.fromVideo(liveObj);
@@ -88,14 +81,6 @@ class StateHistory {
return positionBefore;
}
-
- fun getHistoryLegacy(): List {
- return _historyStore.getItems();
- }
- fun getHistory() : List {
- return _historyDBStore.getAllObjects();
- //return _historyStore.getItems().sortedByDescending { it.date };
- }
fun getHistoryPager(): IPager {
return _historyDBStore.getObjectPager();
}
@@ -121,10 +106,6 @@ class StateHistory {
val hist = getHistoryIndexByUrl(url);
if(hist != null)
_historyDBStore.delete(hist.id!!);
- /*
- val hist = _historyStore.findItem { it.video.url == url };
- if(hist != null)
- _historyStore.delete(hist);*/
}
fun removeHistoryRange(minutesToDelete: Long) {
@@ -132,12 +113,6 @@ class StateHistory {
val toDelete = _historyDBStore.getAllIndexes().filter { minutesToDelete == -1L || (now - it.datetime) < minutesToDelete * 60 };
for(item in toDelete)
_historyDBStore.delete(item);
- /*
- val now = OffsetDateTime.now();
- val toDelete = _historyStore.findItems { minutesToDelete == -1L || ChronoUnit.MINUTES.between(it.date, now) < minutesToDelete };
-
- for(item in toDelete)
- _historyStore.delete(item);*/
}
@@ -157,59 +132,4 @@ class StateHistory {
}
}
}
-
-
- fun testHistoryDB(count: Int) {
- Logger.i(TAG, "TEST: Starting tests");
- _historyDBStore.deleteAll();
-
- val testHistoryItem = getHistoryLegacy().first();
- val testItemJson = testHistoryItem.video.toJson();
- val now = OffsetDateTime.now();
-
- val testSet = (0..count).map { HistoryVideo(Json.decodeFromString(testItemJson.replace(testHistoryItem.video.url, UUID.randomUUID().toString())), it.toLong(), now.minusHours(it.toLong())) }
-
-
- Logger.i(TAG, "TEST: Inserting (${testSet.size})");
- val insertMS = measureTimeMillis {
- for(item in testSet)
- _historyDBStore.insert(item);
- };
- Logger.i(TAG, "TEST: Inserting in ${insertMS}ms");
-
- var fetched: List? = null;
- val fetchMS = measureTimeMillis {
- fetched = _historyDBStore.getAll();
- Logger.i(TAG, "TEST: Fetched: ${fetched?.size}");
- };
- Logger.i(TAG, "TEST: Fetch speed ${fetchMS}MS");
- val deserializeMS = measureTimeMillis {
- val deserialized = _historyDBStore.convertObjects(fetched!!);
- Logger.i(TAG, "TEST: Deserialized: ${deserialized.size}");
- };
- Logger.i(TAG, "TEST: Deserialize speed ${deserializeMS}MS");
-
- var fetchedIndex: List? = null;
- val fetchIndexMS = measureTimeMillis {
- fetchedIndex = _historyDBStore.getAllIndexes();
- Logger.i(TAG, "TEST: Fetched Index: ${fetchedIndex!!.size}");
- };
- Logger.i(TAG, "TEST: Fetched Index speed ${fetchIndexMS}ms");
- val fetchFromIndex = measureTimeMillis {
- for(preItem in testSet) {
- val item = historyIndex[preItem.video.url];
- if(item == null)
- throw IllegalStateException("Missing item [${preItem.video.url}]");
- if(item.url != preItem.video.url)
- throw IllegalStateException("Mismatch item [${preItem.video.url}]");
- }
- };
- Logger.i(TAG, "TEST: Index Lookup speed ${fetchFromIndex}ms");
-
- val page1 = _historyDBStore.getPage(0, 20);
- val page2 = _historyDBStore.getPage(1, 20);
- val page3 = _historyDBStore.getPage(2, 20);
- }
-
-
}
\ No newline at end of file
diff --git a/app/src/main/java/com/futo/platformplayer/states/StateNotifications.kt b/app/src/main/java/com/futo/platformplayer/states/StateNotifications.kt
index b1fc2428..e5f01a84 100644
--- a/app/src/main/java/com/futo/platformplayer/states/StateNotifications.kt
+++ b/app/src/main/java/com/futo/platformplayer/states/StateNotifications.kt
@@ -16,7 +16,6 @@ import com.futo.platformplayer.activities.MainActivity
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
import com.futo.platformplayer.api.media.models.video.IPlatformVideo
import com.futo.platformplayer.api.media.models.video.SerializedPlatformContent
-import com.futo.platformplayer.api.media.models.video.SerializedPlatformVideo
import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.receivers.PlannedNotificationReceiver
import com.futo.platformplayer.serializers.PlatformContentSerializer
@@ -54,7 +53,7 @@ class StateNotifications {
_plannedContent.delete(existing);
existing = null;
}
- if(existing == null && content.datetime != null) {
+ if(content.datetime != null) {
val item = SerializedPlatformContent.fromContent(content);
_plannedContent.saveAsync(item);
@@ -92,7 +91,7 @@ class StateNotifications {
}
fun notifyNewContentWithThumbnail(context: Context, manager: NotificationManager, notificationChannel: NotificationChannel, id: Int, content: IPlatformContent) {
- val thumbnail = if(content is IPlatformVideo) (content as IPlatformVideo).thumbnails.getHQThumbnail()
+ val thumbnail = if(content is IPlatformVideo) content.thumbnails.getHQThumbnail()
else null;
if(thumbnail != null)
Glide.with(context).asBitmap()
diff --git a/app/src/main/java/com/futo/platformplayer/states/StatePlatform.kt b/app/src/main/java/com/futo/platformplayer/states/StatePlatform.kt
index a5c6d311..d82d6eff 100644
--- a/app/src/main/java/com/futo/platformplayer/states/StatePlatform.kt
+++ b/app/src/main/java/com/futo/platformplayer/states/StatePlatform.kt
@@ -7,7 +7,6 @@ import com.futo.platformplayer.Settings
import com.futo.platformplayer.UIDialogs
import com.futo.platformplayer.api.media.IPlatformClient
import com.futo.platformplayer.api.media.IPluginSourced
-import com.futo.platformplayer.api.media.PlatformClientPool
import com.futo.platformplayer.api.media.PlatformMultiClientPool
import com.futo.platformplayer.api.media.exceptions.NoPlatformClientException
import com.futo.platformplayer.api.media.models.FilterGroup
@@ -27,7 +26,13 @@ import com.futo.platformplayer.api.media.models.video.IPlatformVideo
import com.futo.platformplayer.api.media.platforms.js.DevJSClient
import com.futo.platformplayer.api.media.platforms.js.JSClient
import com.futo.platformplayer.api.media.platforms.js.SourcePluginConfig
-import com.futo.platformplayer.api.media.structures.*
+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.MultiDistributionChannelPager
+import com.futo.platformplayer.api.media.structures.MultiDistributionContentPager
+import com.futo.platformplayer.api.media.structures.PlaceholderPager
+import com.futo.platformplayer.api.media.structures.RefreshDistributionContentPager
import com.futo.platformplayer.awaitFirstNotNullDeferred
import com.futo.platformplayer.constructs.BatchedTaskHandler
import com.futo.platformplayer.constructs.Event0
@@ -37,14 +42,21 @@ import com.futo.platformplayer.getNowDiffDays
import com.futo.platformplayer.getNowDiffSeconds
import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.models.ImageVariable
-import com.futo.platformplayer.stores.*
-import kotlinx.coroutines.*
+import com.futo.platformplayer.stores.FragmentedStorage
+import com.futo.platformplayer.stores.StringArrayStorage
+import com.futo.platformplayer.stores.StringStorage
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Deferred
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.async
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import okhttp3.internal.concat
import java.lang.Thread.sleep
import java.time.OffsetDateTime
-import kotlin.reflect.jvm.internal.impl.builtins.jvm.JavaToKotlinClassMap.PlatformMutabilityMapping
import kotlin.streams.asSequence
-import kotlin.streams.toList
/***
* Used to interact with sources/clients
@@ -149,20 +161,20 @@ class StatePlatform {
suspend fun updateAvailableClients(context: Context, reloadPlugins: Boolean = false) {
- if(reloadPlugins)
+ if(reloadPlugins) {
StatePlugins.instance.reloadPluginFile();
+ }
+
withContext(Dispatchers.IO) {
var enabled: Array;
synchronized(_clientsLock) {
- for(enabled in _enabledClients) {
- enabled.disable();
- onSourceDisabled.emit(enabled);
+ for(e in _enabledClients) {
+ e.disable();
+ onSourceDisabled.emit(e);
}
_enabledClients.clear();
_availableClients.clear();
- //_availableClients.add(YoutubeClient());
- //_availableClients.add(OdyseeClient());
_icons.clear();
_icons[StateDeveloper.DEV_ID] = ImageVariable(null, R.drawable.ic_security_red);
@@ -170,40 +182,43 @@ class StatePlatform {
StatePlugins.instance.updateEmbeddedPlugins(context);
StatePlugins.instance.installMissingEmbeddedPlugins(context);
- for(plugin in StatePlugins.instance.getPlugins()) {
-
+ for (plugin in StatePlugins.instance.getPlugins()) {
_icons[plugin.config.id] = StatePlugins.instance.getPluginIconOrNull(plugin.config.id) ?:
ImageVariable(plugin.config.absoluteIconUrl, null);
val client = JSClient(context, plugin);
- client.onCaptchaException.subscribe { client, ex ->
- StateApp.instance.handleCaptchaException(client, ex);
+ client.onCaptchaException.subscribe { c, ex ->
+ StateApp.instance.handleCaptchaException(c, ex);
}
_availableClients.add(client);
}
- if(_availableClients.distinctBy { it.id }.count() < _availableClients.size)
+ if(_availableClients.distinctBy { it.id }.count() < _availableClients.size) {
throw IllegalStateException("Attempted to add 2 clients with the same ID");
+ }
enabled = _enabledClientsPersistent.getAllValues()
.filter { _availableClients.any { ac -> ac.id == it } }
.toTypedArray();
- if(enabled.isEmpty())
+ if(enabled.isEmpty()) {
enabled = StatePlugins.instance.getEmbeddedSourcesDefault(context)
.filter { id -> _availableClients.any { it.id == id } }
.toTypedArray();
+ }
val primary = _primaryClientPersistent.value;
- if(primary.isNullOrEmpty() || primary == StateDeveloper.DEV_ID)
+ if(primary.isEmpty() || primary == StateDeveloper.DEV_ID) {
selectPrimaryClient(enabled.firstOrNull() ?: _availableClients.first().id);
- else if(!_availableClients.any { it.id == primary })
+ } else if(!_availableClients.any { it.id == primary }) {
selectPrimaryClient(_availableClients.firstOrNull()?.id!!);
- else
+ } else {
selectPrimaryClient(primary);
+ }
- if(!enabled.any { it == primaryClient.id })
+ if(!enabled.any { it == primaryClient.id }) {
enabled = enabled.concat(primaryClient.id);
+ }
}
selectClients(*enabled);
};
@@ -294,8 +309,8 @@ class StatePlatform {
StatePlugins.instance.getPlugin(id)
?: throw IllegalStateException("Client existed, but plugin config didn't")
);
- newClient.onCaptchaException.subscribe { client, ex ->
- StateApp.instance.handleCaptchaException(client, ex);
+ newClient.onCaptchaException.subscribe { c, ex ->
+ StateApp.instance.handleCaptchaException(c, ex);
}
synchronized(_clientsLock) {
@@ -654,10 +669,11 @@ class StatePlatform {
fun getChannel(url: String, updateSubscriptions: Boolean = true): Deferred {
Logger.i(TAG, "Platform - getChannel");
val channel = StateSubscriptions.instance.getSubscription(url);
- if(channel != null)
- return _scope.async { getChannelLive(url, updateSubscriptions) }; //_batchTaskGetChannel.execute(channel);
- else
- return _scope.async { getChannelLive(url, updateSubscriptions) };
+ return if(channel != null) {
+ _scope.async { getChannelLive(url, updateSubscriptions) }; //_batchTaskGetChannel.execute(channel);
+ } else {
+ _scope.async { getChannelLive(url, updateSubscriptions) };
+ }
}
fun getChannelContent(baseClient: IPlatformClient, channelUrl: String, isSubscriptionOptimized: Boolean = false, usePooledClients: Int = 0, ignorePlugins: List? = null): IPager {
diff --git a/app/src/main/java/com/futo/platformplayer/states/StatePlayer.kt b/app/src/main/java/com/futo/platformplayer/states/StatePlayer.kt
index 006bbb9a..e1243a8d 100644
--- a/app/src/main/java/com/futo/platformplayer/states/StatePlayer.kt
+++ b/app/src/main/java/com/futo/platformplayer/states/StatePlayer.kt
@@ -1,16 +1,15 @@
+@file:Suppress("DEPRECATION")
+
package com.futo.platformplayer.states
import android.content.Context
-import android.util.Log
import com.futo.platformplayer.R
import com.futo.platformplayer.UIDialogs
-import com.futo.platformplayer.api.media.models.playlists.IPlatformPlaylist
import com.futo.platformplayer.api.media.models.playlists.IPlatformPlaylistDetails
import com.futo.platformplayer.api.media.models.video.IPlatformVideo
import com.futo.platformplayer.api.media.models.video.IPlatformVideoDetails
import com.futo.platformplayer.constructs.Event0
import com.futo.platformplayer.constructs.Event1
-import com.futo.platformplayer.constructs.Event2
import com.futo.platformplayer.models.Playlist
import com.futo.platformplayer.services.MediaPlaybackService
import com.futo.platformplayer.video.PlayerManager
@@ -166,7 +165,7 @@ class StatePlayer {
queueRepeat = enabled;
}
}
- fun setQueueShuffle(shuffle: Boolean, excludeCurrent: Boolean = true) {
+ fun setQueueShuffle(shuffle: Boolean) {
synchronized(_queue) {
queueShuffle = shuffle;
if (shuffle) {
@@ -317,10 +316,11 @@ class StatePlayer {
_queue.add(it);
}
}
- if(_queue.isEmpty())
+ if(_queue.isEmpty()) {
_queue.add(video);
- else
+ } else {
_queue.add(_queuePosition.coerceAtLeast(0).coerceAtMost(_queue.size - 1), video);
+ }
if (queueShuffle) {
addToShuffledQueue(video);
@@ -331,8 +331,9 @@ class StatePlayer {
}
}
onQueueChanged.emit(true);
- if(playNow)
+ if(playNow) {
setQueuePosition(video);
+ }
}
fun setQueuePosition(video: IPlatformVideo) {
synchronized(_queue) {
@@ -347,10 +348,11 @@ class StatePlayer {
fun getQueuePosition(video: IPlatformVideo): Int {
synchronized(_queue) {
val queueShuffled = _queueShuffled;
- return if (queueRepeat && queueShuffled != null)
+ return if (queueRepeat && queueShuffled != null) {
queueShuffled.indexOf(video);
- else
+ } else {
_queue.indexOf(video);
+ }
}
}
fun removeFromQueue(video: IPlatformVideo, shouldSwapCurrentItem: Boolean = false) {
@@ -384,10 +386,11 @@ class StatePlayer {
}
if(adjustIfNegative && queue.isNotEmpty()) {
- if(_queuePosition == -1)
+ if(_queuePosition == -1) {
return queue[0];
- else if(_queuePosition < queue.size)
+ } else if(_queuePosition < queue.size) {
return queue[_queuePosition];
+ }
} else if(_queuePosition >= 0 && _queuePosition < queue.size) {
return queue[_queuePosition];
}
@@ -401,8 +404,9 @@ class StatePlayer {
*/
fun getPrevQueueItem(forceLoop: Boolean = false) : IPlatformVideo? {
synchronized(_queue) {
- if(_queue.size == 1)
+ if(_queue.size == 1) {
return null;
+ }
val shuffledQueue = _queueShuffled;
val queue = if (queueShuffle && shuffledQueue != null) {
@@ -412,14 +416,17 @@ class StatePlayer {
}
//Init Behavior
- if(_queuePosition == -1 && queue.isNotEmpty())
+ if(_queuePosition == -1 && queue.isNotEmpty()) {
return queue[0];
+ }
//Standard Behavior
- if(_queuePosition - 1 >= 0)
+ if(_queuePosition - 1 >= 0) {
return queue[_queuePosition - 1];
+ }
//Repeat Behavior (End of queue)
- if(_queuePosition - 1 < 0 && queue.isNotEmpty() && (forceLoop || queueRepeat))
+ if(queue.isNotEmpty() && (forceLoop || queueRepeat)) {
return queue[_queue.size - 1];
+ }
}
return null;
}
@@ -429,8 +436,9 @@ class StatePlayer {
*/
fun getNextQueueItem(forceLoop: Boolean = false) : IPlatformVideo? {
synchronized(_queue) {
- if(_queue.size == 1)
+ if(_queue.size == 1) {
return null;
+ }
val shuffledQueue = _queueShuffled;
val queue = if (queueShuffle && shuffledQueue != null) {
@@ -440,14 +448,17 @@ class StatePlayer {
}
//Init Behavior
- if(_queuePosition == -1 && queue.isNotEmpty())
+ if(_queuePosition == -1 && queue.isNotEmpty()) {
return queue[0];
+ }
//Standard Behavior
- if(_queuePosition + 1 < queue.size)
+ if(_queuePosition + 1 < queue.size) {
return queue[_queuePosition + 1];
+ }
//Repeat Behavior (End of queue)
- if(_queuePosition + 1 == queue.size && queue.isNotEmpty() && (forceLoop || queueRepeat))
+ if(_queuePosition + 1 == queue.size && queue.isNotEmpty() && (forceLoop || queueRepeat)) {
return queue[0];
+ }
}
return null;
}
@@ -464,11 +475,14 @@ class StatePlayer {
* @param bypassVideoLoop Bypasses any single-video-looping behavior, should be true for manual user actions like next
*/
fun nextQueueItem(withoutRemoval: Boolean = false, bypassVideoLoop: Boolean = false) : IPlatformVideo? {
- if(loopVideo && !bypassVideoLoop)
+ if(loopVideo && !bypassVideoLoop) {
return currentVideo;
+ }
+
synchronized(_queue) {
- if (_queue.isEmpty())
+ if (_queue.isEmpty()) {
return null;
+ }
val nextPosition: Int;
var isRepeat = false;
@@ -510,22 +524,25 @@ class StatePlayer {
}
val currentPos = _queuePosition;
-
- if(_queueRemoveOnFinish && !withoutRemoval) {
+ _queuePosition = if(_queueRemoveOnFinish && !withoutRemoval) {
_queue.removeAt(currentPos);
- _queuePosition = (_queuePosition - 1);
+ (_queuePosition - 1);
+ } else {
+ (_queuePosition - 1);
}
- else
- _queuePosition = (_queuePosition - 1);
- if(_queuePosition < 0)
+
+ if(_queuePosition < 0) {
_queuePosition += _queue.size;
- if(_queuePosition < _queue.size)
+ }
+
+ if(_queuePosition < _queue.size) {
return _queue[_queuePosition];
+ }
}
return null;
}
- fun setQueueItem(video: IPlatformVideo) : IPlatformVideo? {
+ fun setQueueItem(video: IPlatformVideo) : IPlatformVideo {
synchronized(_queue) {
val index = _queue.indexOf(video);
if(index >= 0) {
diff --git a/app/src/main/java/com/futo/platformplayer/states/StatePlaylists.kt b/app/src/main/java/com/futo/platformplayer/states/StatePlaylists.kt
index 5c959406..5aff46e4 100644
--- a/app/src/main/java/com/futo/platformplayer/states/StatePlaylists.kt
+++ b/app/src/main/java/com/futo/platformplayer/states/StatePlaylists.kt
@@ -3,35 +3,25 @@ package com.futo.platformplayer.states
import android.content.Context
import android.net.Uri
import androidx.core.content.FileProvider
-import androidx.sqlite.db.SimpleSQLiteQuery
import com.futo.platformplayer.R
-import com.futo.platformplayer.api.media.PlatformID
import com.futo.platformplayer.api.media.exceptions.NoPlatformClientException
import com.futo.platformplayer.api.media.models.channels.IPlatformChannel
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
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.SerializedPlatformVideo
-import com.futo.platformplayer.api.media.structures.IPager
import com.futo.platformplayer.constructs.Event0
-import com.futo.platformplayer.constructs.Event2
import com.futo.platformplayer.engine.exceptions.ScriptUnavailableException
import com.futo.platformplayer.exceptions.ReconstructionException
import com.futo.platformplayer.logging.Logger
-import com.futo.platformplayer.models.HistoryVideo
import com.futo.platformplayer.models.Playlist
import com.futo.platformplayer.stores.FragmentedStorage
-import com.futo.platformplayer.stores.db.ManagedDBStore
-import com.futo.platformplayer.stores.db.types.DBHistory
import com.futo.platformplayer.stores.v2.ManagedStore
import com.futo.platformplayer.stores.v2.ReconstructStore
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import java.io.File
import java.time.OffsetDateTime
-import java.time.temporal.ChronoUnit
-import java.util.concurrent.ConcurrentHashMap
-import java.util.concurrent.ConcurrentMap
/***
* Used to maintain playlists
@@ -41,7 +31,7 @@ class StatePlaylists {
.withUnique { it.url }
.withRestore(object: ReconstructStore() {
override fun toReconstruction(obj: SerializedPlatformVideo): String = obj.url;
- override suspend fun toObject(id: String, backup: String, builder: Builder): SerializedPlatformVideo
+ override suspend fun toObject(id: String, backup: String, reconstructionBuilder: Builder): SerializedPlatformVideo
= SerializedPlatformVideo.fromVideo(StatePlatform.instance.getContentDetails(backup).await() as IPlatformVideoDetails);
})
.load();
@@ -186,22 +176,25 @@ class StatePlaylists {
items.addAll(obj.videos.map { it.url });
return items.map { it.replace("\n","") }.joinToString("\n");
}
- override suspend fun toObject(id: String, backup: String, builder: Builder): Playlist {
+ override suspend fun toObject(id: String, backup: String, reconstructionBuilder: Builder): Playlist {
val items = backup.split("\n");
- if(items.size <= 0)
+ if(items.size <= 0) {
throw IllegalStateException("Cannot reconstructor playlist ${id}");
+ }
val name = items[0];
val videos = items.drop(1).filter { it.isNotEmpty() }.map {
try {
val video = StatePlatform.instance.getContentDetails(it).await();
- if (video is IPlatformVideoDetails)
+ if (video is IPlatformVideoDetails) {
return@map SerializedPlatformVideo.fromVideo(video);
- else return@map null;
+ } else {
+ return@map null
+ }
}
catch(ex: ScriptUnavailableException) {
Logger.w(TAG, "${name}:[${it}] is no longer available");
- builder.messages.add("${name}:[${it}] is no longer available");
+ reconstructionBuilder.messages.add("${name}:[${it}] is no longer available");
return@map null;
}
catch(ex: NoPlatformClientException) {
diff --git a/app/src/main/java/com/futo/platformplayer/states/StatePlugins.kt b/app/src/main/java/com/futo/platformplayer/states/StatePlugins.kt
index 5c8a3dbd..85b16fd0 100644
--- a/app/src/main/java/com/futo/platformplayer/states/StatePlugins.kt
+++ b/app/src/main/java/com/futo/platformplayer/states/StatePlugins.kt
@@ -12,14 +12,15 @@ import com.futo.platformplayer.api.media.platforms.js.SourcePluginConfig
import com.futo.platformplayer.api.media.platforms.js.SourcePluginDescriptor
import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.models.ImageVariable
-import com.futo.platformplayer.stores.*
+import com.futo.platformplayer.stores.FragmentedStorage
+import com.futo.platformplayer.stores.PluginIconStorage
+import com.futo.platformplayer.stores.PluginScriptsDirectory
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.serialization.Serializable
import kotlinx.serialization.SerializationException
-import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
/***
@@ -134,12 +135,12 @@ class StatePlugins {
if(embeddedConfig != null) {
val existing = getPlugin(embedded.key);
if(existing != null && (existing.config.version < embeddedConfig.version || (force || FORCE_REINSTALL_EMBEDDED))) {
- Logger.i(TAG, "Outdated Embedded plugin [${existing.config.id}] ${existing.config.name} (${existing.config.version} < ${embeddedConfig?.version}), reinstalling");
- //deletePlugin(embedded.key);
+ Logger.i(TAG, "Outdated Embedded plugin [${existing.config.id}] ${existing.config.name} (${existing.config.version} < ${embeddedConfig.version}), reinstalling");
installEmbeddedPlugin(context, embedded.value)
}
- else if(existing != null && _isFirstEmbedUpdate)
- Logger.i(TAG, "Embedded plugin [${existing.config.id}] ${existing.config.name}, up to date (${existing.config.version} >= ${embeddedConfig?.version})");
+ else if(existing != null && _isFirstEmbedUpdate) {
+ Logger.i(TAG, "Embedded plugin [${existing.config.id}] ${existing.config.name}, up to date (${existing.config.version} >= ${embeddedConfig.version})");
+ }
}
}
_isFirstEmbedUpdate = false;
@@ -156,20 +157,18 @@ class StatePlugins {
}
}
fun getEmbeddedPluginConfig(context: Context, assetConfigPath: String): SourcePluginConfig? {
- val configJson = StateAssets.readAsset(context, assetConfigPath, false) ?: null;
- if(configJson == null)
- return null;
+ val configJson = StateAssets.readAsset(context, assetConfigPath) ?: return null;
return SourcePluginConfig.fromJson(configJson, "");
}
fun installEmbeddedPlugin(context: Context, assetConfigPath: String, id: String? = null): Boolean {
try {
- val configJson = StateAssets.readAsset(context, assetConfigPath, false) ?:
+ val configJson = StateAssets.readAsset(context, assetConfigPath) ?:
throw IllegalStateException("Plugin config asset [${assetConfigPath}] not found");
val config = SourcePluginConfig.fromJson(configJson, "");
if(id != null && config.id != id)
throw IllegalStateException("Attempted to install embedded plugin with different id [${config.id}]");
- val script = StateAssets.readAssetRelative(context, assetConfigPath, config.scriptUrl, false);
+ val script = StateAssets.readAssetRelative(context, assetConfigPath, config.scriptUrl);
if(script.isNullOrEmpty())
throw IllegalStateException("Plugin script asset [${config.scriptUrl}] could not be found in assets");
@@ -222,9 +221,9 @@ class StatePlugins {
catch(ex: Exception) {
Logger.e(TAG, "Failed fetch config", ex);
withContext(Dispatchers.Main) {
- UIDialogs.showGeneralErrorDialog(context, "Failed to install plugin\n(${sourceUrl})", ex, "Ok", {
+ UIDialogs.showGeneralErrorDialog(context, "Failed to install plugin\n(${sourceUrl})", ex, "Ok") {
handler?.invoke(false);
- });
+ };
};
return@launch;
}
diff --git a/app/src/main/java/com/futo/platformplayer/states/StateTelemetry.kt b/app/src/main/java/com/futo/platformplayer/states/StateTelemetry.kt
index bc26581a..ac353c55 100644
--- a/app/src/main/java/com/futo/platformplayer/states/StateTelemetry.kt
+++ b/app/src/main/java/com/futo/platformplayer/states/StateTelemetry.kt
@@ -1,6 +1,5 @@
package com.futo.platformplayer.states
-import android.content.Context
import android.os.Build
import com.futo.platformplayer.BuildConfig
import com.futo.platformplayer.api.http.ManagedHttpClient
@@ -8,13 +7,12 @@ import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.models.Telemetry
import com.futo.platformplayer.stores.FragmentedStorage
import com.futo.platformplayer.stores.StringStorage
-import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
-import java.time.Instant
import java.util.UUID
class StateTelemetry {
@@ -26,6 +24,7 @@ class StateTelemetry {
}
}
+ @OptIn(DelicateCoroutinesApi::class)
fun upload() {
GlobalScope.launch(Dispatchers.IO) {
try {
@@ -49,7 +48,6 @@ class StateTelemetry {
val json = Json.encodeToString(telemetry);
val url = "https://logs.grayjay.app/telemetry";
- //val url = "http://10.0.0.5:5413/telemetry";
val client = ManagedHttpClient();
val response = client.post(url, json, headers);
if (response.isOk) {
diff --git a/app/src/main/java/com/futo/platformplayer/stores/FragmentedStorage.kt b/app/src/main/java/com/futo/platformplayer/stores/FragmentedStorage.kt
index a940a1ea..7a5b7cf2 100644
--- a/app/src/main/java/com/futo/platformplayer/stores/FragmentedStorage.kt
+++ b/app/src/main/java/com/futo/platformplayer/stores/FragmentedStorage.kt
@@ -1,20 +1,14 @@
package com.futo.platformplayer.stores
-import com.futo.platformplayer.Settings
import com.futo.platformplayer.logging.Logger
-import com.futo.platformplayer.stores.db.ManagedDBIndex
-import com.futo.platformplayer.stores.db.ManagedDBStore
import com.futo.platformplayer.stores.v2.JsonStoreSerializer
import com.futo.platformplayer.stores.v2.ManagedStore
import com.futo.platformplayer.stores.v2.StoreSerializer
-import kotlinx.serialization.*
-import kotlinx.serialization.json.*
-import kotlinx.serialization.modules.SerializersModule
+import kotlinx.serialization.KSerializer
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.json.Json
import java.io.File
import java.util.UUID
-import kotlin.reflect.KType
-import kotlin.reflect.full.createInstance
-import kotlin.reflect.full.createType
@Serializable()
class FragmentedStorage {
@@ -46,15 +40,17 @@ class FragmentedStorage {
val tempFile = File(dir, UUID.randomUUID().toString());
tempFile.writeText(text);
- val parsed = if (FragmentedStorageFileJson::class.java.isAssignableFrom(T::class.java))
- loadJsonFile(tempFile, null)
- else if (FragmentedStorageFileString::class.java.isAssignableFrom(T::class.java))
- loadTextFile(tempFile, null)
- else
- throw NotImplementedError("Unknown file type for ${T::class.java.name}");
+ val parsed = if (FragmentedStorageFileJson::class.java.isAssignableFrom(T::class.java)) {
+ loadJsonFile(tempFile, null)
+ } else if (FragmentedStorageFileString::class.java.isAssignableFrom(T::class.java)) {
+ loadTextFile(tempFile, null)
+ } else {
+ throw NotImplementedError("Unknown file type for ${T::class.java.name}");
+ }
- if (parsed == null)
+ if (parsed == null) {
throw IllegalStateException("Failed to import type [${T::class.java.name}]");
+ }
}
val name = T::class.java.name;
@@ -71,9 +67,11 @@ class FragmentedStorage {
val name = T::class.java.name;
synchronized(_cachedFiles) {
- if(reload)
+ if(reload) {
_cachedFiles.remove(name);
- var instance = _cachedFiles.get(name);
+ }
+
+ var instance = _cachedFiles[name];
if (instance == null) {
instance = load();
_cachedFiles[name] = instance;
@@ -120,7 +118,7 @@ class FragmentedStorage {
return loadFile(storageFile, storageBakFile);
}
inline fun load(dir: File, fileName: String): T where T : FragmentedStorageFile {
- val storageFile = File(dir, "${fileName}");
+ val storageFile = File(dir, fileName);
val storageBakFile = File(dir, "${fileName}.bak");
return loadFile(storageFile, storageBakFile);
}
@@ -139,13 +137,16 @@ class FragmentedStorage {
}
fun deleteFile(dir: File, fileName: String) {
- val storageFile = File(dir, "${fileName}");
+ val storageFile = File(dir, fileName);
val storageBakFile = File(dir, "${fileName}.bak");
- if(storageFile.exists())
+ if(storageFile.exists()) {
storageFile.delete();
- if(storageBakFile.exists())
+ }
+
+ if(storageBakFile.exists()) {
storageBakFile.delete();
+ }
}
@@ -162,67 +163,75 @@ class FragmentedStorage {
inline fun loadFile(file: File, bakFile: File?): T where T : FragmentedStorageFile {
val typeName = T::class.java.name;
if (file.exists()) {
- var resp =
- if(FragmentedStorageFileJson::class.java.isAssignableFrom(T::class.java))
- loadJsonFile(file, bakFile)
- else if(FragmentedStorageFileString::class.java.isAssignableFrom(T::class.java))
- loadTextFile(file, bakFile)
- else
- throw NotImplementedError("Unknown file type for ${typeName}");
- if(resp != null)
+ val resp = if(FragmentedStorageFileJson::class.java.isAssignableFrom(T::class.java)) {
+ loadJsonFile(file, bakFile)
+ } else if(FragmentedStorageFileString::class.java.isAssignableFrom(T::class.java)) {
+ loadTextFile(file, bakFile)
+ } else {
+ throw NotImplementedError("Unknown file type for $typeName");
+ }
+
+ if(resp != null) {
return resp;
+ }
} else {
Logger.w(TAG, "Failed to fragment storage because the file does not exist. Attempting backup. [${typeName}]");
}
- if (bakFile?.exists() ?: false) {
- var resp =
- if(FragmentedStorageFileJson::class.java.isAssignableFrom(T::class.java))
- loadJsonFile(file, bakFile, true)
- else if(FragmentedStorageFileString::class.java.isAssignableFrom(T::class.java))
- loadTextFile(file, bakFile, true)
- else
- throw NotImplementedError("Unknown file type");
- if(resp != null)
+ if (bakFile?.exists() == true) {
+ val resp = if(FragmentedStorageFileJson::class.java.isAssignableFrom(T::class.java)) {
+ loadJsonFile(file, bakFile, true)
+ } else if(FragmentedStorageFileString::class.java.isAssignableFrom(T::class.java)) {
+ loadTextFile(file, bakFile, true)
+ } else {
+ throw NotImplementedError("Unknown file type");
+ }
+
+ if(resp != null) {
return resp;
+ }
} else {
Logger.w(TAG, "Failed to fragment storage because the backup file does not exist. Using default instance. [${typeName}]");
}
- return (T::class.java.newInstance() as T).withFile(file, bakFile) as T;
+ return (T::class.java.getDeclaredConstructor().newInstance() as T).withFile(file, bakFile) as T;
}
inline fun loadDirectory(file: File): T where T : IFragmentedStorageDirectory {
- return (T::class.java.newInstance() as T).withDirectory(file) as T;
+ return (T::class.java.getDeclaredConstructor().newInstance() as T).withDirectory(file) as T;
}
inline fun loadJsonFile(file: File, bakFile: File?, fromBak: Boolean = false) : T? {
try {
val json = (if(!fromBak) file else bakFile)?.readText() ?: return null;
val fileObj = jsonSerializer.decodeFromString(json);
- if(fromBak && bakFile != null)
+ if(fromBak && bakFile != null) {
bakFile.copyTo(file, true);
+ }
return fileObj.withFile(file, bakFile) as T;
} catch (e: Throwable) {
- if(!fromBak)
+ if(!fromBak) {
Logger.e(TAG, "Failed to load fragment storage. Attempting backup.", e);
- else
+ } else {
Logger.e(TAG, "Failed to load fragment storage. Using default instance.", e);
+ }
}
return null;
}
inline fun loadTextFile(file: File, bakFile: File?, fromBak: Boolean = false) : T? {
try {
val text = (if(!fromBak) file else bakFile)?.readText() ?: return null;
- val fileObj = (T::class.java.newInstance() as T).withFile(file, bakFile) as T
+ val fileObj = (T::class.java.getDeclaredConstructor().newInstance() as T).withFile(file, bakFile) as T
(fileObj as FragmentedStorageFileString).decode(text);
- if(fromBak && bakFile != null)
+ if(fromBak && bakFile != null) {
bakFile.copyTo(file, true);
+ }
return fileObj.withFile(file, bakFile) as T;
} catch (e: Throwable) {
- if(!fromBak)
+ if(!fromBak) {
Logger.w(TAG, "Failed to load fragment storage. Attempting backup.", e);
- else
+ } else {
Logger.w(TAG, "Failed to load fragment storage. Using default instance.", e);
+ }
}
return null;
}
diff --git a/app/src/main/java/com/futo/platformplayer/stores/FragmentedStorageDirectory.kt b/app/src/main/java/com/futo/platformplayer/stores/FragmentedStorageDirectory.kt
index 08b2ec10..9ecb189f 100644
--- a/app/src/main/java/com/futo/platformplayer/stores/FragmentedStorageDirectory.kt
+++ b/app/src/main/java/com/futo/platformplayer/stores/FragmentedStorageDirectory.kt
@@ -16,10 +16,11 @@ open class FragmentedStorageDirectory : IFragmentedStorageDirectory {
var directory: File? = null;
fun getFiles() : List {
- return directory!!.listFiles()
- .filter { it.extension != ".bak" }
- .map { it.name };
+ return directory?.listFiles()
+ ?.filter { it.extension != ".bak" }
+ ?.map { it.name } ?: listOf();
}
+
fun hasFile(name: String) : Boolean {
return File(directory, name).exists();
}
diff --git a/app/src/main/java/com/futo/platformplayer/stores/SubscriptionStorage.kt b/app/src/main/java/com/futo/platformplayer/stores/SubscriptionStorage.kt
index 1e047dca..647f80c7 100644
--- a/app/src/main/java/com/futo/platformplayer/stores/SubscriptionStorage.kt
+++ b/app/src/main/java/com/futo/platformplayer/stores/SubscriptionStorage.kt
@@ -1,10 +1,11 @@
package com.futo.platformplayer.stores
-import com.futo.platformplayer.states.StateSubscriptions
-import com.futo.platformplayer.models.Subscription
import com.futo.platformplayer.api.media.models.PlatformAuthorLink
import com.futo.platformplayer.api.media.models.channels.IPlatformChannel
-import kotlinx.serialization.*
+import com.futo.platformplayer.models.Subscription
+import com.futo.platformplayer.states.StateSubscriptions
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
@Serializable()
@@ -18,7 +19,6 @@ class SubscriptionStorage : FragmentedStorageFileJson() {
}
fun removeSubscription(url : String) {
- val toRemove = subscriptions.firstOrNull { it.channel.url == url };
subscriptions.removeIf { it.channel.url == url };
}
diff --git a/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBContextPaged.kt b/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBContextPaged.kt
index 3449d3c7..78539ca3 100644
--- a/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBContextPaged.kt
+++ b/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBContextPaged.kt
@@ -1,9 +1,6 @@
package com.futo.platformplayer.stores.db
import androidx.room.Dao
-import androidx.room.Delete
-import androidx.room.Insert
-import androidx.room.Update
@Dao
interface ManagedDBContextPaged> {
diff --git a/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBDAOBase.kt b/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBDAOBase.kt
index 05c19390..3341ef8b 100644
--- a/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBDAOBase.kt
+++ b/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBDAOBase.kt
@@ -3,7 +3,6 @@ package com.futo.platformplayer.stores.db
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
-import androidx.room.Query
import androidx.room.RawQuery
import androidx.room.Update
import androidx.sqlite.db.SupportSQLiteQuery
diff --git a/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBDescriptor.kt b/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBDescriptor.kt
index ce3c9c70..9d8606a1 100644
--- a/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBDescriptor.kt
+++ b/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBDescriptor.kt
@@ -1,8 +1,5 @@
package com.futo.platformplayer.stores.db
-import androidx.sqlite.db.SimpleSQLiteQuery
-import com.futo.platformplayer.models.HistoryVideo
-import com.futo.platformplayer.stores.db.types.DBHistory
import kotlin.reflect.KClass
diff --git a/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBIndex.kt b/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBIndex.kt
index c4cf5295..b95fa32d 100644
--- a/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBIndex.kt
+++ b/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBIndex.kt
@@ -3,7 +3,6 @@ package com.futo.platformplayer.stores.db
import androidx.room.ColumnInfo
import androidx.room.Ignore
import androidx.room.PrimaryKey
-import com.futo.platformplayer.api.media.Serializer
open class ManagedDBIndex {
@ColumnIndex
diff --git a/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBIndexOnly.kt b/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBIndexOnly.kt
index 0795555d..3d1551db 100644
--- a/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBIndexOnly.kt
+++ b/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBIndexOnly.kt
@@ -1,9 +1,6 @@
package com.futo.platformplayer.stores.db
import androidx.room.Dao
-import androidx.room.Delete
-import androidx.room.Insert
-import androidx.room.Update
@Dao
interface ManagedDBIndexOnly> {
diff --git a/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBStore.kt b/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBStore.kt
index e4d57744..dc873bc0 100644
--- a/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBStore.kt
+++ b/app/src/main/java/com/futo/platformplayer/stores/db/ManagedDBStore.kt
@@ -357,7 +357,7 @@ class ManagedDBStore, T, D: ManagedDBDatabase, DA
fun getPage(page: Int, length: Int): List {
if(_sqlPage == null)
throw IllegalStateException("DB Store [${name}] does not have ordered fields to provide pages");
- val query = _sqlPage!!(page, length) ?: throw IllegalStateException("Paged db not setup for ${_name}");
+ val query = _sqlPage!!(page, length);
return deserializeIndexes(dbDaoBase.getMultiple(query));
}
fun getPageObjects(page: Int, length: Int): List = convertObjects(getPage(page, length));
diff --git a/app/src/main/java/com/futo/platformplayer/stores/v2/ManagedStore.kt b/app/src/main/java/com/futo/platformplayer/stores/v2/ManagedStore.kt
index 5346d861..ec0a9fa2 100644
--- a/app/src/main/java/com/futo/platformplayer/stores/v2/ManagedStore.kt
+++ b/app/src/main/java/com/futo/platformplayer/stores/v2/ManagedStore.kt
@@ -10,13 +10,9 @@ import kotlinx.serialization.json.Json
import kotlinx.serialization.serializer
import java.io.File
import java.io.FileNotFoundException
-import java.lang.Exception
-import java.util.*
-import kotlin.collections.ArrayList
-import kotlin.collections.HashMap
+import java.util.UUID
import kotlin.reflect.KClass
import kotlin.reflect.KType
-import kotlin.reflect.javaType
class ManagedStore{
private val _class: KType;
@@ -68,8 +64,7 @@ class ManagedStore{
fun load(): ManagedStore {
synchronized(_files) {
_files.clear();
- val newObjs = _dir.listFiles().map { it.nameWithoutExtension }.distinct().toList().map { fileId ->
- //Logger.i(TAG, "FILE:" + it.name);
+ val newObjs = _dir.listFiles()?.map { it.nameWithoutExtension }?.distinct()?.toList()?.map { fileId ->
val mfile = ManagedFile(fileId, _dir);
val obj = mfile.load(this, _withBackup);
if(obj == null) {
@@ -82,10 +77,12 @@ class ManagedStore{
}
return@map Pair(obj, mfile);
- }.filter { it.first != null };
+ }?.filter { it.first != null };
- for (obj in newObjs)
- _files.put(obj.first!!, obj.second);
+ if (newObjs != null) {
+ for (obj in newObjs)
+ _files[obj.first!!] = obj.second;
+ }
}
_isLoaded = true;
return this;
diff --git a/app/src/main/java/com/futo/platformplayer/subscription/SimpleSubscriptionAlgorithm.kt b/app/src/main/java/com/futo/platformplayer/subscription/SimpleSubscriptionAlgorithm.kt
index bf40d738..f4a9818e 100644
--- a/app/src/main/java/com/futo/platformplayer/subscription/SimpleSubscriptionAlgorithm.kt
+++ b/app/src/main/java/com/futo/platformplayer/subscription/SimpleSubscriptionAlgorithm.kt
@@ -1,6 +1,5 @@
package com.futo.platformplayer.subscription
-import com.futo.platformplayer.Settings
import com.futo.platformplayer.api.media.models.ResultCapabilities
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
import com.futo.platformplayer.api.media.platforms.js.JSClient
@@ -15,15 +14,10 @@ import com.futo.platformplayer.exceptions.ChannelException
import com.futo.platformplayer.findNonRuntimeException
import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.models.Subscription
-import com.futo.platformplayer.polycentric.PolycentricCache
import com.futo.platformplayer.states.StateCache
import com.futo.platformplayer.states.StatePlatform
-import com.futo.platformplayer.states.StatePolycentric
import com.futo.platformplayer.states.StateSubscriptions
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.runBlocking
-import java.lang.Exception
-import java.lang.IllegalStateException
import java.util.concurrent.ExecutionException
import java.util.concurrent.ForkJoinPool
import java.util.concurrent.ForkJoinTask
@@ -42,14 +36,16 @@ class SimpleSubscriptionAlgorithm(
for(sub in subs) {
for(subUrl in sub.value) {
val client = StatePlatform.instance.getChannelClientOrNull(sub.key.channel.url);
- if (client !is JSClient)
+ if (client !is JSClient) {
continue;
+ }
val channelCaps = client.getChannelCapabilities();
- if (!pluginReqCounts.containsKey(client))
+ if (!pluginReqCounts.containsKey(client)) {
pluginReqCounts[client] = 1;
- else
+ } else {
pluginReqCounts[client] = pluginReqCounts[client]!! + 1;
+ }
if (channelCaps.hasType(ResultCapabilities.TYPE_STREAMS) && sub.key.shouldFetchStreams())
pluginReqCounts[client] = pluginReqCounts[client]!! + 1;
@@ -71,7 +67,6 @@ class SimpleSubscriptionAlgorithm(
val tasks = mutableListOf?>>>();
var finished = 0;
val exceptionMap: HashMap = hashMapOf();
- val concurrency = Settings.instance.subscriptions.getSubscriptionsConcurrency();
val failedPlugins = arrayListOf();
for (sub in subs.filter { StatePlatform.instance.hasEnabledChannelClient(it.key.channel.url) })
tasks.add(getSubscription(sub.key, sub.value, failedPlugins){ channelEx ->
@@ -79,7 +74,6 @@ class SimpleSubscriptionAlgorithm(
onProgress.emit(finished, tasks.size);
val ex = channelEx?.cause;
-
if(channelEx != null) {
synchronized(exceptionMap) {
exceptionMap.put(sub.key, channelEx);
@@ -107,42 +101,46 @@ class SimpleSubscriptionAlgorithm(
val timeTotal = measureTimeMillis {
val taskResults = arrayListOf>();
- for(task in tasks) {
+ for (task in tasks) {
try {
val result = task.get();
- if(result != null) {
- if(result.second != null)
+ if (result != null) {
+ if(result.second != null) {
taskResults.add(result.second!!);
- if(exceptionMap.containsKey(result.first)) {
+ }
+
+ if (exceptionMap.containsKey(result.first)) {
val ex = exceptionMap[result.first];
- if(ex != null) {
+ if (ex != null) {
val nonRuntimeEx = findNonRuntimeException(ex);
- if (nonRuntimeEx != null && (nonRuntimeEx is PluginException || nonRuntimeEx is ChannelException))
+ if (nonRuntimeEx != null && (nonRuntimeEx is PluginException || nonRuntimeEx is ChannelException)) {
exs.add(nonRuntimeEx);
- else
+ } else {
throw ex.cause ?: ex;
+ }
}
}
}
} catch (ex: ExecutionException) {
val nonRuntimeEx = findNonRuntimeException(ex.cause);
- if(nonRuntimeEx != null && (nonRuntimeEx is PluginException || nonRuntimeEx is ChannelException))
+ if (nonRuntimeEx != null && (nonRuntimeEx is PluginException || nonRuntimeEx is ChannelException)) {
exs.add(nonRuntimeEx);
- else
+ } else {
throw ex.cause ?: ex;
+ }
};
}
subsPager = taskResults.toTypedArray();
}
Logger.i("StateSubscriptions", "Subscriptions results in ${timeTotal}ms")
- if(subsPager.size <= 0 && exs.any())
+ if(subsPager.isEmpty() && exs.any()) {
throw exs.first();
+ }
Logger.i(StateSubscriptions.TAG, "Subscription pager with ${subsPager.size} channels");
val pager = MultiChronoContentPager(subsPager, allowFailure, 15);
pager.initialize();
- //return Pair(pager, exs);
return Result(DedupContentPager(pager), exs);
}
@@ -156,7 +154,6 @@ class SimpleSubscriptionAlgorithm(
val platformClient = StatePlatform.instance.getChannelClientOrNull(url, toIgnore) ?: continue;
val time = measureTimeMillis {
pager = StatePlatform.instance.getChannelContent(platformClient, url, true, threadPool.poolSize, toIgnore);
-
pager = StateCache.cachePagerResults(scope, pager!!) {
onNewCacheHit.emit(sub, it);
};
@@ -172,16 +169,19 @@ class SimpleSubscriptionAlgorithm(
Logger.e(StateSubscriptions.TAG, "Subscription [${sub.channel.name}] failed", ex);
val channelEx = ChannelException(sub.channel, ex);
onFinished(channelEx);
- if(!withCacheFallback)
+ if(!withCacheFallback) {
throw channelEx;
- else {
+ } else {
Logger.i(StateSubscriptions.TAG, "Channel ${sub.channel.name} failed, substituting with cache");
pager = StateCache.instance.getChannelCachePager(sub.channel.url);
}
}
}
- if(pager == null)
+
+ if(pager == null) {
throw IllegalStateException("Uncaught nullable pager");
+ }
+
return@submit Pair(sub, pager);
};
}
diff --git a/app/src/main/java/com/futo/platformplayer/subscription/SmartSubscriptionAlgorithm.kt b/app/src/main/java/com/futo/platformplayer/subscription/SmartSubscriptionAlgorithm.kt
index 1c3355b5..840fc288 100644
--- a/app/src/main/java/com/futo/platformplayer/subscription/SmartSubscriptionAlgorithm.kt
+++ b/app/src/main/java/com/futo/platformplayer/subscription/SmartSubscriptionAlgorithm.kt
@@ -1,10 +1,7 @@
package com.futo.platformplayer.subscription
import com.futo.platformplayer.api.media.models.ResultCapabilities
-import com.futo.platformplayer.api.media.models.contents.IPlatformContent
import com.futo.platformplayer.api.media.platforms.js.JSClient
-import com.futo.platformplayer.api.media.structures.IPager
-import com.futo.platformplayer.getNowDiffDays
import com.futo.platformplayer.getNowDiffHours
import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.models.Subscription
@@ -28,35 +25,37 @@ class SmartSubscriptionAlgorithm(
//For every platform, get all sub-queries associated with that platform
return@flatMap allPlatforms
.filter { it.value != null }
- .flatMap {
- val url = it.key;
- val client = it.value!! as JSClient;
+ .flatMap innerFlatMap@ { pair ->
+ val url = pair.key;
+ val client = pair.value!! as JSClient;
val capabilities = client.getChannelCapabilities();
if(capabilities.hasType(ResultCapabilities.TYPE_MIXED) || capabilities.types.isEmpty())
- return@flatMap listOf(SubscriptionTask(client, sub, it.key, ResultCapabilities.TYPE_MIXED));
+ return@innerFlatMap listOf(SubscriptionTask(client, sub, pair.key, ResultCapabilities.TYPE_MIXED));
else if(capabilities.hasType(ResultCapabilities.TYPE_SUBSCRIPTIONS))
- return@flatMap listOf(SubscriptionTask(client, sub, it.key, ResultCapabilities.TYPE_SUBSCRIPTIONS))
+ return@innerFlatMap listOf(SubscriptionTask(client, sub, pair.key, ResultCapabilities.TYPE_SUBSCRIPTIONS))
else {
- val types = listOf(
- if(sub.shouldFetchVideos()) ResultCapabilities.TYPE_VIDEOS else null,
- if(sub.shouldFetchStreams()) ResultCapabilities.TYPE_STREAMS else null,
- if(sub.shouldFetchPosts()) ResultCapabilities.TYPE_POSTS else null,
- if(sub.shouldFetchLiveStreams()) ResultCapabilities.TYPE_LIVE else null
- ).filterNotNull().filter { capabilities.hasType(it) };
+ val types = listOfNotNull(
+ if (sub.shouldFetchVideos()) ResultCapabilities.TYPE_VIDEOS else null,
+ if (sub.shouldFetchStreams()) ResultCapabilities.TYPE_STREAMS else null,
+ if (sub.shouldFetchPosts()) ResultCapabilities.TYPE_POSTS else null,
+ if (sub.shouldFetchLiveStreams()) ResultCapabilities.TYPE_LIVE else null
+ ).filter { capabilities.hasType(it) };
- if(!types.isEmpty())
- return@flatMap types.map {
+ if(types.isNotEmpty()) {
+ return@innerFlatMap types.map {
SubscriptionTask(client, sub, url, it);
};
- else
+ } else {
listOf(SubscriptionTask(client, sub, url, ResultCapabilities.TYPE_VIDEOS, true))
+ }
}
};
};
- for(task in allTasks)
+ for(task in allTasks) {
task.urgency = calculateUpdateUrgency(task.sub, task.type);
+ }
val ordering = allTasks.groupBy { it.client }
.map { Pair(it.key, it.value.sortedBy { it.urgency }) };
@@ -66,16 +65,16 @@ class SmartSubscriptionAlgorithm(
for(clientTasks in ordering) {
val limit = clientTasks.first.getSubscriptionRateLimit();
- if(limit == null || limit <= 0)
+ if(limit == null || limit <= 0) {
finalTasks.addAll(clientTasks.second);
- else {
+ } else {
val fetchTasks = mutableListOf();
val cacheTasks = mutableListOf();
for(task in clientTasks.second) {
- if(!task.fromCache && fetchTasks.size < limit)
+ if (!task.fromCache && fetchTasks.size < limit) {
fetchTasks.add(task);
- else {
+ } else {
task.fromCache = true;
cacheTasks.add(task);
}
diff --git a/app/src/main/java/com/futo/platformplayer/subscription/SubscriptionFetchAlgorithm.kt b/app/src/main/java/com/futo/platformplayer/subscription/SubscriptionFetchAlgorithm.kt
index 4b5dd8b7..a34f0e33 100644
--- a/app/src/main/java/com/futo/platformplayer/subscription/SubscriptionFetchAlgorithm.kt
+++ b/app/src/main/java/com/futo/platformplayer/subscription/SubscriptionFetchAlgorithm.kt
@@ -1,14 +1,11 @@
package com.futo.platformplayer.subscription
-import com.futo.platformplayer.api.media.models.channels.IPlatformChannel
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
import com.futo.platformplayer.api.media.platforms.js.JSClient
import com.futo.platformplayer.api.media.structures.IPager
import com.futo.platformplayer.constructs.Event2
import com.futo.platformplayer.models.Subscription
import kotlinx.coroutines.CoroutineScope
-import java.lang.Exception
-import java.lang.IllegalStateException
import java.util.concurrent.ForkJoinPool
abstract class SubscriptionFetchAlgorithm(
@@ -41,7 +38,6 @@ abstract class SubscriptionFetchAlgorithm(
SubscriptionFetchAlgorithms.CACHE -> CachedSubscriptionAlgorithm(scope, allowFailure, withCacheFallback, pool, 50);
SubscriptionFetchAlgorithms.SIMPLE -> SimpleSubscriptionAlgorithm(scope, allowFailure, withCacheFallback, pool);
SubscriptionFetchAlgorithms.SMART -> SmartSubscriptionAlgorithm(scope, allowFailure, withCacheFallback, pool);
- else -> throw IllegalStateException("Unknown algorithm ${algo}");
}
}
}
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 d51688df..b4b90624 100644
--- a/app/src/main/java/com/futo/platformplayer/subscription/SubscriptionsTaskFetchAlgorithm.kt
+++ b/app/src/main/java/com/futo/platformplayer/subscription/SubscriptionsTaskFetchAlgorithm.kt
@@ -1,6 +1,5 @@
package com.futo.platformplayer.subscription
-import com.futo.platformplayer.Settings
import com.futo.platformplayer.UIDialogs
import com.futo.platformplayer.activities.MainActivity
import com.futo.platformplayer.api.media.models.ResultCapabilities
@@ -24,7 +23,6 @@ import com.futo.platformplayer.states.StateCache
import com.futo.platformplayer.states.StatePlatform
import com.futo.platformplayer.states.StateSubscriptions
import kotlinx.coroutines.CoroutineScope
-import java.lang.IllegalStateException
import java.util.concurrent.ExecutionException
import java.util.concurrent.ForkJoinPool
import java.util.concurrent.ForkJoinTask
@@ -47,8 +45,6 @@ abstract class SubscriptionsTaskFetchAlgorithm(
val tasks = getSubscriptionTasks(subs);
val tasksGrouped = tasks.groupBy { it.client }
- val taskCount = tasks.filter { !it.fromCache }.size;
- val cacheCount = tasks.size - taskCount;
Logger.i(TAG, "Starting Subscriptions Fetch:\n" +
tasksGrouped.map { " ${it.key.name}: ${it.value.count { !it.fromCache }}, Cached(${it.value.count { it.fromCache } })" }.joinToString("\n"));
@@ -63,7 +59,9 @@ abstract class SubscriptionsTaskFetchAlgorithm(
}
}
- } catch (ex: Throwable){}
+ } catch (e: Throwable){
+ Logger.e(TAG, "Error occurred in task.", e)
+ }
val exs: ArrayList = arrayListOf();
@@ -78,25 +76,27 @@ abstract class SubscriptionsTaskFetchAlgorithm(
try {
val result = task.get();
if(result != null) {
- if(result.pager != null)
+ if(result.pager != null) {
taskResults.add(result);
+ }
+
if(result.exception != null) {
val ex = result.exception;
- if(ex != null) {
- val nonRuntimeEx = findNonRuntimeException(ex);
- if (nonRuntimeEx != null && (nonRuntimeEx is PluginException || nonRuntimeEx is ChannelException))
- exs.add(nonRuntimeEx);
- else
- throw ex.cause ?: ex;
+ val nonRuntimeEx = findNonRuntimeException(ex);
+ if (nonRuntimeEx != null && (nonRuntimeEx is PluginException || nonRuntimeEx is ChannelException)) {
+ exs.add(nonRuntimeEx);
+ } else {
+ throw ex.cause ?: ex;
}
}
}
} catch (ex: ExecutionException) {
val nonRuntimeEx = findNonRuntimeException(ex.cause);
- if(nonRuntimeEx != null && (nonRuntimeEx is PluginException || nonRuntimeEx is ChannelException))
+ if(nonRuntimeEx != null && (nonRuntimeEx is PluginException || nonRuntimeEx is ChannelException)) {
exs.add(nonRuntimeEx);
- else
+ } else {
throw ex.cause ?: ex;
+ }
};
}
}
@@ -108,18 +108,19 @@ abstract class SubscriptionsTaskFetchAlgorithm(
val sub = if(!entry.value.isEmpty()) entry.value[0].task.sub else null;
val liveTasks = entry.value.filter { !it.task.fromCache };
val cachedTasks = entry.value.filter { it.task.fromCache };
- val livePager = if(!liveTasks.isEmpty()) StateCache.cachePagerResults(scope, MultiChronoContentPager(liveTasks.map { it.pager!! }, true).apply { this.initialize() }, {
+ val livePager = if(liveTasks.isNotEmpty()) StateCache.cachePagerResults(scope, MultiChronoContentPager(liveTasks.map { it.pager!! }, true).apply { this.initialize() }) {
onNewCacheHit.emit(sub!!, it);
- }) else null;
- val cachedPager = if(!cachedTasks.isEmpty()) MultiChronoContentPager(cachedTasks.map { it.pager!! }, true).apply { this.initialize() } else null;
- if(livePager != null && cachedPager == null)
+ } else null;
+ val cachedPager = if(cachedTasks.isNotEmpty()) MultiChronoContentPager(cachedTasks.map { it.pager!! }, true).apply { this.initialize() } else null;
+ if(livePager != null && cachedPager == null) {
return@map livePager;
- else if(cachedPager != null && livePager == null)
+ } else if(cachedPager != null && livePager == null) {
return@map cachedPager;
- else if(cachedPager == null && livePager == null)
+ } else if(cachedPager == null) {
return@map EmptyPager();
- else
- return@map MultiChronoContentPager(listOf(livePager!!, cachedPager!!), true).apply { this.initialize() }
+ } else {
+ return@map MultiChronoContentPager(listOf(livePager!!, cachedPager), true).apply { this.initialize() }
+ }
}
val pager = MultiChronoContentPager(groupedPagers, allowFailure, 15);
@@ -138,9 +139,9 @@ abstract class SubscriptionsTaskFetchAlgorithm(
if(task.fromCache) {
finished++;
onProgress.emit(finished, forkTasks.size);
- if(cachedChannels.contains(task.url))
+ if(cachedChannels.contains(task.url)) {
return@submit SubscriptionTaskResult(task, null, null);
- else {
+ } else {
cachedChannels.add(task.url);
return@submit SubscriptionTaskResult(task, StateCache.instance.getChannelCachePager(task.url), null);
}
@@ -148,10 +149,11 @@ abstract class SubscriptionsTaskFetchAlgorithm(
}
val shouldIgnore = synchronized(failedPlugins) { failedPlugins.contains(task.client.id) };
- if(shouldIgnore)
+ if(shouldIgnore) {
return@submit SubscriptionTaskResult(task, null, null); //skipped
+ }
- var taskEx: Throwable? = null;
+ val taskEx: Throwable?;
var pager: IPager;
try {
val time = measureTimeMillis {
@@ -202,7 +204,6 @@ abstract class SubscriptionsTaskFetchAlgorithm(
return@submit SubscriptionTaskResult(task, pager, taskEx);
}
}
- return@submit SubscriptionTaskResult(task, null, taskEx);
}
forkTasks.add(forkTask);
}
@@ -211,7 +212,6 @@ abstract class SubscriptionsTaskFetchAlgorithm(
abstract fun getSubscriptionTasks(subs: Map>): List;
-
class SubscriptionTask(
val client: JSClient,
val sub: Subscription,
diff --git a/app/src/main/java/com/futo/platformplayer/video/PlayerManager.kt b/app/src/main/java/com/futo/platformplayer/video/PlayerManager.kt
index f13442a0..adce7f3a 100644
--- a/app/src/main/java/com/futo/platformplayer/video/PlayerManager.kt
+++ b/app/src/main/java/com/futo/platformplayer/video/PlayerManager.kt
@@ -1,12 +1,11 @@
+@file:Suppress("DEPRECATION")
+
package com.futo.platformplayer.video
-import android.media.MediaPlayer
import android.media.session.PlaybackState
import android.support.v4.media.session.PlaybackStateCompat
-import com.futo.platformplayer.constructs.Event1
import com.google.android.exoplayer2.ExoPlayer
import com.google.android.exoplayer2.Player
-import com.google.android.exoplayer2.ui.AspectRatioFrameLayout
import com.google.android.exoplayer2.ui.StyledPlayerView
class PlayerManager {
@@ -102,7 +101,5 @@ class PlayerManager {
var volume: Float = 1f;
var listener: Player.Listener? = null;
-
- var resizMode: Int = AspectRatioFrameLayout.RESIZE_MODE_FIT;
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/futo/platformplayer/views/MonetizationView.kt b/app/src/main/java/com/futo/platformplayer/views/MonetizationView.kt
index d9e1011c..f5cc1389 100644
--- a/app/src/main/java/com/futo/platformplayer/views/MonetizationView.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/MonetizationView.kt
@@ -9,10 +9,9 @@ import android.widget.FrameLayout
import android.widget.LinearLayout
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
-import com.futo.platformplayer.R
import com.futo.platformplayer.HorizontalSpaceItemDecoration
+import com.futo.platformplayer.R
import com.futo.platformplayer.api.http.ManagedHttpClient
-import com.futo.platformplayer.api.media.platforms.js.SourcePluginConfig
import com.futo.platformplayer.constructs.Event0
import com.futo.platformplayer.constructs.TaskHandler
import com.futo.platformplayer.logging.Logger
@@ -22,7 +21,6 @@ import com.futo.platformplayer.views.AnyAdapterView.Companion.asAny
import com.futo.platformplayer.views.adapters.viewholders.StoreItemViewHolder
import com.futo.platformplayer.views.platform.PlatformIndicator
import kotlinx.serialization.Serializable
-import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
@Serializable
@@ -122,7 +120,7 @@ class MonetizationView : LinearLayout {
}
}
- fun setPolycentricProfile(cachedPolycentricProfile: PolycentricCache.CachedPolycentricProfile?, animate: Boolean) {
+ fun setPolycentricProfile(cachedPolycentricProfile: PolycentricCache.CachedPolycentricProfile?) {
val profile = cachedPolycentricProfile?.profile;
if (profile != null) {
if (profile.systemState.store.isNotEmpty()) {
diff --git a/app/src/main/java/com/futo/platformplayer/views/SupportView.kt b/app/src/main/java/com/futo/platformplayer/views/SupportView.kt
index 0da86a64..3d846fe2 100644
--- a/app/src/main/java/com/futo/platformplayer/views/SupportView.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/SupportView.kt
@@ -4,31 +4,20 @@ import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
-import android.graphics.drawable.Drawable
import android.net.Uri
import android.util.AttributeSet
import android.view.View
-import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import android.widget.Toast
import com.bumptech.glide.Glide
-import com.bumptech.glide.request.target.CustomTarget
-import com.bumptech.glide.request.transition.Transition
import com.futo.platformplayer.R
-import com.futo.platformplayer.dp
import com.futo.platformplayer.fragment.mainactivity.main.PolycentricProfile
import com.futo.platformplayer.images.GlideHelper.Companion.crossfade
import com.futo.platformplayer.logging.Logger
-import com.futo.platformplayer.polycentric.PolycentricCache
import com.futo.platformplayer.views.buttons.BigButton
import com.futo.polycentric.core.toURLInfoSystemLinkUrl
import com.google.android.material.imageview.ShapeableImageView
-import com.google.android.material.shape.CornerFamily
-import com.google.android.material.shape.ShapeAppearanceModel
-import kotlinx.serialization.decodeFromString
-import kotlinx.serialization.json.Json
-import userpackage.Protocol.ImageManifest
class SupportView : LinearLayout {
private val _layoutStore: LinearLayout
@@ -141,7 +130,7 @@ class SupportView : LinearLayout {
private fun createDonationButton(destination: String): BigButton {
val uri = Uri.parse(destination)
- var action: (() -> Unit)? = null
+ var action: (() -> Unit)?
val (name, iconDrawableId, cryptoType) = if (uri.scheme == "http" || uri.scheme == "https") {
val hostName = uri.host ?: ""
@@ -202,7 +191,7 @@ class SupportView : LinearLayout {
}
}
- fun setPolycentricProfile(profile: PolycentricProfile?, animate: Boolean) {
+ fun setPolycentricProfile(profile: PolycentricProfile?) {
if (_polycentricProfile == profile) {
return
}
diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/AnyAdapter.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/AnyAdapter.kt
index 310b4c7e..225c498b 100644
--- a/app/src/main/java/com/futo/platformplayer/views/adapters/AnyAdapter.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/adapters/AnyAdapter.kt
@@ -3,7 +3,6 @@ package com.futo.platformplayer.views.adapters
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
-import androidx.recyclerview.widget.RecyclerView.Recycler
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import java.lang.reflect.Constructor
@@ -102,7 +101,7 @@ class AnyAdapter> : BaseAnyAdapter {
}
abstract class AnyViewHolder(protected val _view: View) : ViewHolder(_view) {
- abstract fun bind(i: I);
+ abstract fun bind(value: I);
}
companion object {
diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/CommentWithReferenceViewHolder.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/CommentWithReferenceViewHolder.kt
index c47db9f6..6da01bd3 100644
--- a/app/src/main/java/com/futo/platformplayer/views/adapters/CommentWithReferenceViewHolder.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/adapters/CommentWithReferenceViewHolder.kt
@@ -8,15 +8,20 @@ import android.widget.FrameLayout
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.recyclerview.widget.RecyclerView.ViewHolder
-import com.futo.platformplayer.*
+import com.futo.platformplayer.R
+import com.futo.platformplayer.Settings
import com.futo.platformplayer.api.media.models.comments.IPlatformComment
import com.futo.platformplayer.api.media.models.comments.PolycentricPlatformComment
import com.futo.platformplayer.api.media.models.ratings.RatingLikeDislikes
import com.futo.platformplayer.constructs.Event1
import com.futo.platformplayer.constructs.TaskHandler
+import com.futo.platformplayer.fixHtmlLinks
+import com.futo.platformplayer.fullyBackfillServersAnnounceExceptions
import com.futo.platformplayer.logging.Logger
+import com.futo.platformplayer.setPlatformPlayerLinkMovementMethod
import com.futo.platformplayer.states.StateApp
import com.futo.platformplayer.states.StatePolycentric
+import com.futo.platformplayer.toHumanNowDiffString
import com.futo.platformplayer.views.others.CreatorThumbnail
import com.futo.platformplayer.views.pills.PillButton
import com.futo.platformplayer.views.pills.PillRatingLikesDislikes
@@ -169,7 +174,7 @@ class CommentWithReferenceViewHolder : ViewHolder {
_buttonReplies.setLoading(false)
- val replies = likesDislikesReplies.replyCount ?: 0;
+ val replies = likesDislikesReplies.replyCount;
_buttonReplies.visibility = View.VISIBLE;
_buttonReplies.text.text = "$replies " + itemView.context.getString(R.string.replies);
} else {
diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/DeviceViewHolder.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/DeviceViewHolder.kt
index 8d4a6f0a..3c17617d 100644
--- a/app/src/main/java/com/futo/platformplayer/views/adapters/DeviceViewHolder.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/adapters/DeviceViewHolder.kt
@@ -7,7 +7,12 @@ import android.widget.LinearLayout
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.futo.platformplayer.R
-import com.futo.platformplayer.casting.*
+import com.futo.platformplayer.casting.AirPlayCastingDevice
+import com.futo.platformplayer.casting.CastConnectionState
+import com.futo.platformplayer.casting.CastingDevice
+import com.futo.platformplayer.casting.ChromecastCastingDevice
+import com.futo.platformplayer.casting.FCastCastingDevice
+import com.futo.platformplayer.casting.StateCasting
import com.futo.platformplayer.constructs.Event1
class DeviceViewHolder : ViewHolder {
@@ -48,15 +53,15 @@ class DeviceViewHolder : ViewHolder {
};
_buttonConnect.setOnClickListener {
- val d = device ?: return@setOnClickListener;
+ val dev = device ?: return@setOnClickListener;
StateCasting.instance.activeDevice?.stopCasting();
- StateCasting.instance.connectDevice(d);
+ StateCasting.instance.connectDevice(dev);
updateButton();
};
_buttonRemove.setOnClickListener {
- val d = device ?: return@setOnClickListener;
- onRemove.emit(d);
+ val dev = device ?: return@setOnClickListener;
+ onRemove.emit(dev);
};
setIsRememberedDevice(false);
diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/EmptyPreviewViewHolder.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/EmptyPreviewViewHolder.kt
index bfd86f56..05b33db2 100644
--- a/app/src/main/java/com/futo/platformplayer/views/adapters/EmptyPreviewViewHolder.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/adapters/EmptyPreviewViewHolder.kt
@@ -2,7 +2,6 @@ package com.futo.platformplayer.views.adapters
import android.view.View
import android.view.ViewGroup
-import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
import com.futo.platformplayer.api.media.models.contents.IPlatformContentDetails
diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/EnabledSourceViewHolder.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/EnabledSourceViewHolder.kt
index b6796e84..78cb55c4 100644
--- a/app/src/main/java/com/futo/platformplayer/views/adapters/EnabledSourceViewHolder.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/adapters/EnabledSourceViewHolder.kt
@@ -1,8 +1,8 @@
package com.futo.platformplayer.views.adapters
+import android.annotation.SuppressLint
import android.view.MotionEvent
import android.view.View
-import android.view.View.OnTouchListener
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
@@ -10,7 +10,6 @@ import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.futo.platformplayer.R
import com.futo.platformplayer.api.media.IPlatformClient
-import com.futo.platformplayer.api.media.platforms.js.JSClient
import com.futo.platformplayer.constructs.Event1
class EnabledSourceViewHolder : ViewHolder {
@@ -25,6 +24,7 @@ class EnabledSourceViewHolder : ViewHolder {
var source: IPlatformClient? = null
private set
+ @SuppressLint("ClickableViewAccessibility")
constructor(view: View, touchHelper: ItemTouchHelper) : super(view) {
_imageSource = view.findViewById(R.id.image_source);
_textSource = view.findViewById(R.id.text_source);
@@ -37,12 +37,13 @@ class EnabledSourceViewHolder : ViewHolder {
source?.let { onClick.emit(it); };
};
- _imageDragDrop.setOnTouchListener(OnTouchListener { v, event ->
+ _imageDragDrop.setOnTouchListener { _, event ->
if (event.action == MotionEvent.ACTION_DOWN) {
touchHelper.startDrag(this);
}
+
false
- });
+ };
_buttonRemove.setOnClickListener {
source?.let { onRemove.emit(it); };
diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/SubscriptionAdapter.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/SubscriptionAdapter.kt
index fe33c0da..034b6e66 100644
--- a/app/src/main/java/com/futo/platformplayer/views/adapters/SubscriptionAdapter.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/adapters/SubscriptionAdapter.kt
@@ -4,9 +4,9 @@ import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.futo.platformplayer.UIDialogs
+import com.futo.platformplayer.constructs.Event1
import com.futo.platformplayer.models.Subscription
import com.futo.platformplayer.states.StateSubscriptions
-import com.futo.platformplayer.constructs.Event1
class SubscriptionAdapter : RecyclerView.Adapter {
private lateinit var _sortedDataset: List;
@@ -30,7 +30,7 @@ class SubscriptionAdapter : RecyclerView.Adapter {
_inflater = inflater;
_confirmationMessage = confirmationMessage;
- StateSubscriptions.instance.onSubscriptionsChanged.subscribe { subs, added -> updateDataset(); }
+ StateSubscriptions.instance.onSubscriptionsChanged.subscribe { _, _ -> updateDataset(); }
updateDataset();
}
diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/VideoListEditorViewHolder.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/VideoListEditorViewHolder.kt
index 43e610db..8f94f6d2 100644
--- a/app/src/main/java/com/futo/platformplayer/views/adapters/VideoListEditorViewHolder.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/adapters/VideoListEditorViewHolder.kt
@@ -1,5 +1,6 @@
package com.futo.platformplayer.views.adapters
+import android.annotation.SuppressLint
import android.view.MotionEvent
import android.view.View
import android.widget.FrameLayout
@@ -11,8 +12,6 @@ import androidx.constraintlayout.widget.ConstraintLayout
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.bumptech.glide.Glide
-import com.bumptech.glide.RequestBuilder
-import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import com.futo.platformplayer.R
import com.futo.platformplayer.api.media.models.video.IPlatformVideo
import com.futo.platformplayer.constructs.Event1
@@ -43,6 +42,7 @@ class VideoListEditorViewHolder : ViewHolder {
val onClick = Event1();
val onRemove = Event1();
+ @SuppressLint("ClickableViewAccessibility")
constructor(view: View, touchHelper: ItemTouchHelper) : super(view) {
_root = view.findViewById(R.id.root);
_imageThumbnail = view.findViewById(R.id.image_video_thumbnail);
@@ -58,12 +58,12 @@ class VideoListEditorViewHolder : ViewHolder {
_platformIndicator = view.findViewById(R.id.thumbnail_platform);
_layoutDownloaded = view.findViewById(R.id.layout_downloaded);
- _imageDragDrop.setOnTouchListener(View.OnTouchListener { v, event ->
+ _imageDragDrop.setOnTouchListener { _, event ->
if (event.action == MotionEvent.ACTION_DOWN) {
touchHelper.startDrag(this);
}
false
- });
+ };
_root.setOnClickListener {
val v = video ?: return@setOnClickListener;
diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewContentListAdapter.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewContentListAdapter.kt
index 112fab64..2026ffd1 100644
--- a/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewContentListAdapter.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewContentListAdapter.kt
@@ -2,7 +2,8 @@ package com.futo.platformplayer.views.adapters.feedtypes
import android.content.Context
import android.util.Log
-import android.view.*
+import android.view.View
+import android.view.ViewGroup
import com.futo.platformplayer.api.media.models.PlatformAuthorLink
import com.futo.platformplayer.api.media.models.contents.ContentType
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
@@ -44,7 +45,7 @@ class PreviewContentListAdapter : InsertedViewAdapterWithLoader, exoPlayer: PlayerManager? = null,
@@ -111,15 +112,16 @@ class PreviewContentListAdapter : InsertedViewAdapterWithLoader();
-
- constructor(context: Context, feedStyle : FeedStyle) : super(context) {
+ constructor(context: Context, feedStyle: FeedStyle) : super(context) {
inflate(feedStyle);
_feedStyle = feedStyle;
_textVideoName = findViewById(R.id.text_video_name);
_textChannelName = findViewById(R.id.text_channel_name);
- //_imageNeoPassChannel = findViewById(R.id.image_neopass_channel);
_imageChannelThumbnail = findViewById(R.id.image_channel_thumbnail);
_imageVideoThumbnail = findViewById(R.id.image_video_thumbnail);
-
_platformIndicator = findViewById(R.id.thumbnail_platform)
-
_textLockedDescription = findViewById(R.id.text_locked_description);
- //_textBrowserOpen = findViewById(R.id.text_browser_open);
_textLockedUrl = findViewById(R.id.text_locked_url);
-
_textVideoMetadata = findViewById(R.id.text_video_metadata);
setOnClickListener {
@@ -82,14 +51,14 @@ class PreviewLockedView : LinearLayout {
}
}
- protected open fun inflate(feedStyle: FeedStyle) {
+ fun inflate(feedStyle: FeedStyle) {
inflate(context, when(feedStyle) {
FeedStyle.PREVIEW -> R.layout.list_locked_preview
else -> R.layout.list_locked_thumbnail
}, this)
}
- open fun bind(content: IPlatformContent) {
+ fun bind(content: IPlatformContent) {
_textVideoName.text = content.name;
_textChannelName.text = content.author.name;
_platformIndicator.setPlatformFromClientID(content.id.pluginId);
@@ -119,15 +88,11 @@ class PreviewLockedView : LinearLayout {
}
else {
_textLockedUrl.visibility = VISIBLE;
- _textVideoMetadata.text = "Tap to open in browser";
+ _textVideoMetadata.text = context.getString(R.string.tap_to_open_in_browser);
}
}
- open fun preview(video: IPlatformContentDetails?, paused: Boolean) {
-
- }
-
companion object {
private val TAG = "PreviewLockedView"
}
diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewLockedViewHolder.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewLockedViewHolder.kt
index 6d8c2cc9..2c058fa3 100644
--- a/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewLockedViewHolder.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewLockedViewHolder.kt
@@ -1,22 +1,12 @@
package com.futo.platformplayer.views.adapters.feedtypes
import android.content.Context
-import android.graphics.drawable.Animatable
-import android.view.LayoutInflater
-import android.view.View
import android.view.ViewGroup
-import android.widget.ImageView
-import android.widget.TextView
-import com.futo.platformplayer.*
-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.IPlatformContentDetails
-import com.futo.platformplayer.api.media.models.contents.PlatformContentPlaceholder
import com.futo.platformplayer.constructs.Event1
-import com.futo.platformplayer.constructs.Event2
import com.futo.platformplayer.views.FeedStyle
import com.futo.platformplayer.views.adapters.ContentPreviewViewHolder
-import com.futo.platformplayer.views.platform.PlatformIndicator
class PreviewLockedViewHolder : ContentPreviewViewHolder {
@@ -35,7 +25,7 @@ class PreviewLockedViewHolder : ContentPreviewViewHolder {
override fun bind(content: IPlatformContent) = view.bind(content);
- override fun preview(video: IPlatformContentDetails?, paused: Boolean) { }
+ override fun preview(details: IPlatformContentDetails?, paused: Boolean) { }
override fun stopPreview() { }
override fun pausePreview() { }
override fun resumePreview() { }
diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewNestedVideoView.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewNestedVideoView.kt
index d66bb466..64c28643 100644
--- a/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewNestedVideoView.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewNestedVideoView.kt
@@ -22,6 +22,7 @@ import com.futo.platformplayer.views.FeedStyle
import com.futo.platformplayer.views.LoaderView
import com.futo.platformplayer.views.platform.PlatformIndicator
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.launch
class PreviewNestedVideoView : PreviewVideoView {
@@ -50,29 +51,33 @@ class PreviewNestedVideoView : PreviewVideoView {
_textChannelName.setOnClickListener { _contentNested?.let { onChannelClicked.emit(it.author) } };
_textVideoMetadata.setOnClickListener { _contentNested?.let { onChannelClicked.emit(it.author) } };
_button_add_to.setOnClickListener {
- if(_contentNested is IPlatformVideo)
+ if(_contentNested is IPlatformVideo) {
_contentNested?.let { onAddToClicked.emit(it as IPlatformVideo) }
- else _content?.let {
- if(it is IPlatformNestedContent)
- loadNested(it) {
- if(it is IPlatformVideo)
+ } else _content?.let { c ->
+ if(c is IPlatformNestedContent) {
+ loadNested(c) {
+ if (it is IPlatformVideo) {
onAddToClicked.emit(it);
- else
+ } else {
UIDialogs.toast(context, "Content is not a video");
+ }
}
+ }
}
};
_button_add_to_queue.setOnClickListener {
- if(_contentNested is IPlatformVideo)
+ if(_contentNested is IPlatformVideo) {
_contentNested?.let { onAddToQueueClicked.emit(it as IPlatformVideo) }
- else _content?.let {
- if(it is IPlatformNestedContent)
- loadNested(it) {
- if(it is IPlatformVideo)
+ } else _content?.let { c ->
+ if(c is IPlatformNestedContent) {
+ loadNested(c) {
+ if (it is IPlatformVideo) {
onAddToQueueClicked.emit(it);
- else
+ } else {
UIDialogs.toast(context, "Content is not a video");
+ }
}
+ }
}
};
}
@@ -85,9 +90,9 @@ class PreviewNestedVideoView : PreviewVideoView {
}
override fun onOpenClicked() {
- if(_contentNested is IPlatformVideoDetails)
+ if(_contentNested is IPlatformVideoDetails) {
super.onOpenClicked();
- else if(_content is IPlatformNestedContent) {
+ } else if(_content is IPlatformNestedContent) {
(_content as IPlatformNestedContent).let {
onContentUrlClicked.emit(it.contentUrl, if(_contentSupported) it.nestedContentType else ContentType.URL);
};
@@ -111,24 +116,24 @@ class PreviewNestedVideoView : PreviewVideoView {
.into(_imageVideo);
};
-
_contentSupported = content.contentSupported;
if(!_contentSupported) {
_containerUnavailable.visibility = View.VISIBLE;
_containerLoader.visibility = View.GONE;
_loaderView.stop();
- }
- else {
- if(_feedStyle == FeedStyle.THUMBNAIL)
+ } else {
+ if(_feedStyle == FeedStyle.THUMBNAIL) {
_platformIndicator.setPlatformFromClientID(content.contentPlugin);
- else
+ } else {
_platformIndicatorNested.setPlatformFromClientID(content.contentPlugin);
+ }
+
_containerUnavailable.visibility = View.GONE;
- if(_feedStyle == FeedStyle.PREVIEW)
+ if(_feedStyle == FeedStyle.PREVIEW) {
loadNested(content);
+ }
}
- }
- else {
+ } else {
_contentSupported = false;
_containerUnavailable.visibility = View.VISIBLE;
_containerLoader.visibility = View.GONE;
@@ -136,6 +141,7 @@ class PreviewNestedVideoView : PreviewVideoView {
}
}
+ @OptIn(ExperimentalCoroutinesApi::class)
private fun loadNested(content: IPlatformNestedContent, onCompleted: ((IPlatformContentDetails)->Unit)? = null) {
Logger.i(TAG, "Loading nested content [${content.contentUrl}]");
_containerLoader.visibility = View.VISIBLE;
@@ -159,20 +165,20 @@ class PreviewNestedVideoView : PreviewVideoView {
_loaderView.stop();
val nestedContent = def.getCompleted();
_contentNested = nestedContent;
- if(nestedContent is IPlatformVideoDetails) {
+ if (nestedContent is IPlatformVideoDetails) {
super.bind(nestedContent);
if(_feedStyle == FeedStyle.PREVIEW) {
_platformIndicator.setPlatformFromClientID(content.id.pluginId);
_platformIndicatorNested.setPlatformFromClientID(nestedContent.id.pluginId);
- }
- else
+ } else {
_platformIndicatorNested.setPlatformFromClientID(content.id.pluginId);
- }
- else {
+ }
+ } else {
_containerUnavailable.visibility = View.VISIBLE;
}
- if(onCompleted != null)
+ if (onCompleted != null) {
onCompleted(nestedContent);
+ }
}
}
};
@@ -180,9 +186,9 @@ class PreviewNestedVideoView : PreviewVideoView {
}
override fun preview(video: IPlatformContentDetails?, paused: Boolean) {
- if(video != null)
+ if(video != null) {
super.preview(video, paused);
- else if(_content is IPlatformVideoDetails) _contentNested?.let {
+ } else if(_content is IPlatformVideoDetails) _contentNested?.let {
super.preview(it, paused);
};
}
diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewPlaceholderViewHolder.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewPlaceholderViewHolder.kt
index 6155717f..02fa3187 100644
--- a/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewPlaceholderViewHolder.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewPlaceholderViewHolder.kt
@@ -7,7 +7,7 @@ import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
-import com.futo.platformplayer.*
+import com.futo.platformplayer.R
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.PlatformContentPlaceholder
@@ -58,7 +58,7 @@ class PreviewPlaceholderViewHolder : ContentPreviewViewHolder {
}
}
- override fun preview(video: IPlatformContentDetails?, paused: Boolean) { }
+ override fun preview(details: IPlatformContentDetails?, paused: Boolean) { }
override fun stopPreview() { }
override fun pausePreview() { }
override fun resumePreview() { }
diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewPostViewHolder.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewPostViewHolder.kt
index 8007826c..5749e2b1 100644
--- a/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewPostViewHolder.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewPostViewHolder.kt
@@ -5,7 +5,6 @@ import com.futo.platformplayer.api.media.models.PlatformAuthorLink
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
import com.futo.platformplayer.api.media.models.contents.IPlatformContentDetails
import com.futo.platformplayer.constructs.Event1
-import com.futo.platformplayer.video.PlayerManager
import com.futo.platformplayer.views.FeedStyle
import com.futo.platformplayer.views.adapters.ContentPreviewViewHolder
@@ -19,7 +18,7 @@ class PreviewPostViewHolder : ContentPreviewViewHolder {
private val view: PreviewPostView get() = itemView as PreviewPostView;
- constructor(viewGroup: ViewGroup, feedStyle : FeedStyle, exoPlayer: PlayerManager? = null): super(
+ constructor(viewGroup: ViewGroup, feedStyle : FeedStyle): super(
PreviewPostView(viewGroup.context, feedStyle)
) {
view.onContentClicked.subscribe(onContentClicked::emit);
@@ -29,7 +28,7 @@ class PreviewPostViewHolder : ContentPreviewViewHolder {
override fun bind(content: IPlatformContent) = view.bind(content);
- override fun preview(video: IPlatformContentDetails?, paused: Boolean) {};
+ override fun preview(details: IPlatformContentDetails?, paused: Boolean) {};
override fun stopPreview() {};
override fun pausePreview() {};
override fun resumePreview() {};
diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewVideoView.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewVideoView.kt
index fad5a394..7d38b4a8 100644
--- a/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewVideoView.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewVideoView.kt
@@ -2,16 +2,14 @@ package com.futo.platformplayer.views.adapters.feedtypes
import android.animation.ObjectAnimator
import android.content.Context
-import android.content.res.Resources
import android.util.Log
-import android.util.TypedValue
import android.view.View
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import com.bumptech.glide.Glide
-import com.futo.platformplayer.*
+import com.futo.platformplayer.R
import com.futo.platformplayer.api.media.PlatformID
import com.futo.platformplayer.api.media.models.PlatformAuthorLink
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
@@ -21,17 +19,22 @@ import com.futo.platformplayer.api.media.models.video.IPlatformVideoDetails
import com.futo.platformplayer.constructs.Event1
import com.futo.platformplayer.constructs.Event2
import com.futo.platformplayer.constructs.TaskHandler
+import com.futo.platformplayer.dp
+import com.futo.platformplayer.getNowDiffSeconds
import com.futo.platformplayer.images.GlideHelper.Companion.crossfade
import com.futo.platformplayer.images.GlideHelper.Companion.loadThumbnails
import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.polycentric.PolycentricCache
+import com.futo.platformplayer.selectBestImage
import com.futo.platformplayer.states.StateApp
import com.futo.platformplayer.states.StateDownloads
import com.futo.platformplayer.states.StateHistory
-import com.futo.platformplayer.states.StatePlaylists
+import com.futo.platformplayer.toHumanNowDiffString
+import com.futo.platformplayer.toHumanNumber
+import com.futo.platformplayer.toHumanTime
import com.futo.platformplayer.video.PlayerManager
-import com.futo.platformplayer.views.others.CreatorThumbnail
import com.futo.platformplayer.views.FeedStyle
+import com.futo.platformplayer.views.others.CreatorThumbnail
import com.futo.platformplayer.views.others.ProgressBar
import com.futo.platformplayer.views.platform.PlatformIndicator
import com.futo.platformplayer.views.video.FutoThumbnailPlayer
@@ -88,26 +91,6 @@ open class PreviewVideoView : LinearLayout {
inflate(feedStyle);
_feedStyle = feedStyle;
this.shouldShowTimeBar = shouldShowTimeBar
- val playerContainer = findViewById(R.id.player_container);
-
- val displayMetrics = Resources.getSystem().displayMetrics;
- val width: Double = if (feedStyle == FeedStyle.PREVIEW) {
- displayMetrics.widthPixels.toDouble();
- } else {
- TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 177.0f, displayMetrics).toDouble();
- };
-
- /*
- val ar = 16.0 / 9.0;
- var height = width / ar;
- height += TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 6.0f, displayMetrics);
-
- val layoutParams = playerContainer.layoutParams;
- layoutParams.height = height.roundToInt();
- playerContainer.layoutParams = layoutParams;*/
-
- //Logger.i(TAG, "Player container height calculated to be $height.");
-
_playerContainer = findViewById(R.id.player_container);
_imageVideo = findViewById(R.id.image_video_thumbnail)
@@ -135,6 +118,7 @@ open class PreviewVideoView : LinearLayout {
setOnClickListener {
onOpenClicked()
};
+
_imageChannel.setOnClickListener { currentVideo?.let { onChannelClicked.emit(it.author) } };
_textChannelName.setOnClickListener { currentVideo?.let { onChannelClicked.emit(it.author) } };
_textVideoMetadata.setOnClickListener { currentVideo?.let { onChannelClicked.emit(it.author) } };
@@ -212,14 +196,12 @@ open class PreviewVideoView : LinearLayout {
metadata += "${content.viewCount.toHumanNumber()} ${context.getString(R.string.views)} • ";
}
- var timeMeta = "";
- if(isPlanned) {
+ var timeMeta = if(isPlanned) {
val ago = content.datetime?.toHumanNowDiffString(true) ?: ""
- timeMeta = context.getString(R.string.available_in) + " ${ago}";
- }
- else {
+ context.getString(R.string.available_in) + " $ago";
+ } else {
val ago = content.datetime?.toHumanNowDiffString() ?: ""
- timeMeta = if (ago.isNotBlank()) ago + " ago" else ago;
+ if (ago.isNotBlank()) ago + " ago" else ago;
}
if(content is IPlatformVideo) {
diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewVideoViewHolder.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewVideoViewHolder.kt
index 8f998365..27e76c92 100644
--- a/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewVideoViewHolder.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/adapters/feedtypes/PreviewVideoViewHolder.kt
@@ -40,7 +40,7 @@ class PreviewVideoViewHolder : ContentPreviewViewHolder {
override fun bind(content: IPlatformContent) = view.bind(content);
- override fun preview(video: IPlatformContentDetails?, paused: Boolean) = view.preview(video, paused);
+ override fun preview(details: IPlatformContentDetails?, paused: Boolean) = view.preview(details, paused);
override fun stopPreview() = view.stopPreview();
override fun pausePreview() = view.pausePreview();
override fun resumePreview() = view.resumePreview();
diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/CreatorViewHolder.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/CreatorViewHolder.kt
index 8187d21b..750b4fc2 100644
--- a/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/CreatorViewHolder.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/CreatorViewHolder.kt
@@ -15,10 +15,8 @@ import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.polycentric.PolycentricCache
import com.futo.platformplayer.selectBestImage
import com.futo.platformplayer.states.StateApp
-import com.futo.platformplayer.states.StatePolycentric
import com.futo.platformplayer.toHumanNumber
import com.futo.platformplayer.views.adapters.AnyAdapter
-import com.futo.platformplayer.views.adapters.SubscriptionViewHolder
import com.futo.platformplayer.views.others.CreatorThumbnail
import com.futo.platformplayer.views.platform.PlatformIndicator
import com.futo.platformplayer.views.subscriptions.SubscribeButton
@@ -62,31 +60,31 @@ class CreatorViewHolder(private val _viewGroup: ViewGroup, private val _tiny: Bo
}
}
- override fun bind(authorLink: PlatformAuthorLink) {
+ override fun bind(value: PlatformAuthorLink) {
_taskLoadProfile.cancel();
- _creatorThumbnail.setThumbnail(authorLink.thumbnail, false);
- _textName.text = authorLink.name;
+ _creatorThumbnail.setThumbnail(value.thumbnail, false);
+ _textName.text = value.name;
- val cachedProfile = PolycentricCache.instance.getCachedProfile(authorLink.url, true);
+ val cachedProfile = PolycentricCache.instance.getCachedProfile(value.url, true);
if (cachedProfile != null) {
onProfileLoaded(cachedProfile, false);
if (cachedProfile.expired) {
- _taskLoadProfile.run(authorLink.id);
+ _taskLoadProfile.run(value.id);
}
} else {
- _taskLoadProfile.run(authorLink.id);
+ _taskLoadProfile.run(value.id);
}
- if(authorLink.subscribers == null || (authorLink.subscribers ?: 0) <= 0L)
+ if(value.subscribers == null || (value.subscribers ?: 0) <= 0L)
_textMetadata.visibility = View.GONE;
else {
- _textMetadata.text = if((authorLink.subscribers ?: 0) > 0) authorLink.subscribers!!.toHumanNumber() + " " + _view.context.getString(R.string.subscribers) else "";
+ _textMetadata.text = if((value.subscribers ?: 0) > 0) value.subscribers!!.toHumanNumber() + " " + _view.context.getString(R.string.subscribers) else "";
_textMetadata.visibility = View.VISIBLE;
}
- _buttonSubscribe.setSubscribeChannel(authorLink.url);
- _platformIndicator.setPlatformFromClientID(authorLink.id.pluginId);
- _authorLink = authorLink;
+ _buttonSubscribe.setSubscribeChannel(value.url);
+ _platformIndicator.setPlatformFromClientID(value.id.pluginId);
+ _authorLink = value;
}
private fun onProfileLoaded(cachedPolycentricProfile: PolycentricCache.CachedPolycentricProfile?, animate: Boolean) {
diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/ImportPlaylistsViewHolder.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/ImportPlaylistsViewHolder.kt
index dc54dd3f..9cbf400c 100644
--- a/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/ImportPlaylistsViewHolder.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/ImportPlaylistsViewHolder.kt
@@ -9,8 +9,8 @@ import com.bumptech.glide.Glide
import com.futo.platformplayer.R
import com.futo.platformplayer.constructs.Event1
import com.futo.platformplayer.models.Playlist
-import com.futo.platformplayer.views.others.Checkbox
import com.futo.platformplayer.views.adapters.AnyAdapter
+import com.futo.platformplayer.views.others.Checkbox
class ImportPlaylistsViewHolder(private val _viewGroup: ViewGroup) : AnyAdapter.AnyViewHolder(
LayoutInflater.from(_viewGroup.context).inflate(R.layout.list_import_playlist, _viewGroup, false)) {
@@ -43,12 +43,12 @@ class ImportPlaylistsViewHolder(private val _viewGroup: ViewGroup) : AnyAdapter.
};
}
- override fun bind(playlist: SelectablePlaylist) {
- _textName.text = playlist.playlist.name;
- _textMetadata.text = "${playlist.playlist.videos.size} " + _view.context.getString(R.string.videos);
- _checkbox.value = playlist.selected;
+ override fun bind(value: SelectablePlaylist) {
+ _textName.text = value.playlist.name;
+ _textMetadata.text = "${value.playlist.videos.size} " + _view.context.getString(R.string.videos);
+ _checkbox.value = value.selected;
- val thumbnail = playlist.playlist.videos.firstOrNull()?.thumbnails?.getHQThumbnail();
+ val thumbnail = value.playlist.videos.firstOrNull()?.thumbnails?.getHQThumbnail();
if (thumbnail != null)
Glide.with(_imageThumbnail)
.load(thumbnail)
@@ -57,7 +57,7 @@ class ImportPlaylistsViewHolder(private val _viewGroup: ViewGroup) : AnyAdapter.
else
Glide.with(_imageThumbnail).clear(_imageThumbnail);
- _playlist = playlist;
+ _playlist = value;
}
}
diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/ImportSubscriptionViewHolder.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/ImportSubscriptionViewHolder.kt
index 499fd3e2..5992f6b7 100644
--- a/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/ImportSubscriptionViewHolder.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/ImportSubscriptionViewHolder.kt
@@ -9,9 +9,9 @@ import com.bumptech.glide.Glide
import com.futo.platformplayer.R
import com.futo.platformplayer.api.media.models.channels.IPlatformChannel
import com.futo.platformplayer.constructs.Event1
+import com.futo.platformplayer.views.adapters.AnyAdapter
import com.futo.platformplayer.views.others.Checkbox
import com.futo.platformplayer.views.platform.PlatformIndicator
-import com.futo.platformplayer.views.adapters.AnyAdapter
class ImportSubscriptionViewHolder(private val _viewGroup: ViewGroup) : AnyAdapter.AnyViewHolder(
LayoutInflater.from(_viewGroup.context).inflate(R.layout.list_import_subscription, _viewGroup, false)) {
@@ -46,11 +46,11 @@ class ImportSubscriptionViewHolder(private val _viewGroup: ViewGroup) : AnyAdapt
};
}
- override fun bind(channel: SelectableIPlatformChannel) {
- _textName.text = channel.channel.name;
- _checkbox.value = channel.selected;
+ override fun bind(value: SelectableIPlatformChannel) {
+ _textName.text = value.channel.name;
+ _checkbox.value = value.selected;
- val thumbnail = channel.channel.thumbnail;
+ val thumbnail = value.channel.thumbnail;
if (thumbnail != null)
Glide.with(_imageThumbnail)
.load(thumbnail)
@@ -59,8 +59,8 @@ class ImportSubscriptionViewHolder(private val _viewGroup: ViewGroup) : AnyAdapt
else
Glide.with(_imageThumbnail).clear(_imageThumbnail);
- _platform.setPlatformFromClientID(channel.channel.id.pluginId);
- _channel = channel;
+ _platform.setPlatformFromClientID(value.channel.id.pluginId);
+ _channel = value;
}
}
diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/StoreItemViewHolder.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/StoreItemViewHolder.kt
index 47c97acd..3faa153c 100644
--- a/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/StoreItemViewHolder.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/StoreItemViewHolder.kt
@@ -8,7 +8,6 @@ import android.widget.LinearLayout
import android.widget.TextView
import com.bumptech.glide.Glide
import com.futo.platformplayer.R
-import com.futo.platformplayer.constructs.Event1
import com.futo.platformplayer.images.GlideHelper.Companion.crossfade
import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.views.StoreItem
@@ -39,14 +38,14 @@ class StoreItemViewHolder(private val _viewGroup: ViewGroup) : AnyAdapter.AnyVie
}
}
- override fun bind(storeItem: StoreItem) {
+ override fun bind(value: StoreItem) {
Glide.with(_image)
- .load(storeItem.image)
+ .load(value.image)
.crossfade()
.into(_image);
- _name.text = storeItem.name;
- _storeItem = storeItem;
+ _name.text = value.name;
+ _storeItem = value;
}
companion object {
diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/SubscriptionBarViewHolder.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/SubscriptionBarViewHolder.kt
index c8f25f89..d92e60ae 100644
--- a/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/SubscriptionBarViewHolder.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/SubscriptionBarViewHolder.kt
@@ -4,19 +4,19 @@ import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.TextView
-import com.futo.platformplayer.logging.Logger
-import com.futo.platformplayer.polycentric.PolycentricCache
import com.futo.platformplayer.R
-import com.futo.platformplayer.states.StateApp
import com.futo.platformplayer.api.media.PlatformID
import com.futo.platformplayer.api.media.models.channels.SerializedChannel
import com.futo.platformplayer.constructs.Event1
import com.futo.platformplayer.constructs.TaskHandler
import com.futo.platformplayer.dp
+import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.models.Subscription
+import com.futo.platformplayer.polycentric.PolycentricCache
import com.futo.platformplayer.selectBestImage
-import com.futo.platformplayer.views.others.CreatorThumbnail
+import com.futo.platformplayer.states.StateApp
import com.futo.platformplayer.views.adapters.AnyAdapter
+import com.futo.platformplayer.views.others.CreatorThumbnail
import com.futo.polycentric.core.toURLInfoSystemLinkUrl
class SubscriptionBarViewHolder(private val _viewGroup: ViewGroup) : AnyAdapter.AnyViewHolder(
@@ -46,25 +46,25 @@ class SubscriptionBarViewHolder(private val _viewGroup: ViewGroup) : AnyAdapter.
}
}
- override fun bind(subscription: Subscription) {
+ override fun bind(value: Subscription) {
_taskLoadProfile.cancel();
- _channel = subscription.channel;
+ _channel = value.channel;
- _creatorThumbnail.setThumbnail(subscription.channel.thumbnail, false);
- _name.text = subscription.channel.name;
+ _creatorThumbnail.setThumbnail(value.channel.thumbnail, false);
+ _name.text = value.channel.name;
- val cachedProfile = PolycentricCache.instance.getCachedProfile(subscription.channel.url, true);
+ val cachedProfile = PolycentricCache.instance.getCachedProfile(value.channel.url, true);
if (cachedProfile != null) {
onProfileLoaded(cachedProfile, false);
if (cachedProfile.expired) {
- _taskLoadProfile.run(subscription.channel.id);
+ _taskLoadProfile.run(value.channel.id);
}
} else {
- _taskLoadProfile.run(subscription.channel.id);
+ _taskLoadProfile.run(value.channel.id);
}
- _subscription = subscription;
+ _subscription = value;
}
private fun onProfileLoaded(cachedPolycentricProfile: PolycentricCache.CachedPolycentricProfile?, animate: Boolean) {
diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/TabViewHolder.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/TabViewHolder.kt
index 262311cf..53ec72fc 100644
--- a/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/TabViewHolder.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/TabViewHolder.kt
@@ -1,5 +1,6 @@
package com.futo.platformplayer.views.adapters.viewholders
+import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
@@ -7,16 +8,17 @@ import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView.ViewHolder
-import com.futo.platformplayer.*
+import com.futo.platformplayer.R
import com.futo.platformplayer.constructs.Event1
import com.futo.platformplayer.fragment.mainactivity.bottombar.MenuBottomBarFragment
-import com.futo.platformplayer.views.others.Toggle
import com.futo.platformplayer.views.adapters.AnyAdapter
+import com.futo.platformplayer.views.others.Toggle
data class TabViewHolderData(val buttonDefinition: MenuBottomBarFragment.ButtonDefinition, var enabled: Boolean);
-class TabViewHolder(_viewGroup: ViewGroup) : AnyAdapter.AnyViewHolder(
- LayoutInflater.from(_viewGroup.context).inflate(R.layout.list_tab, _viewGroup, false)) {
+@SuppressLint("ClickableViewAccessibility")
+class TabViewHolder(viewGroup: ViewGroup) : AnyAdapter.AnyViewHolder(
+ LayoutInflater.from(viewGroup.context).inflate(R.layout.list_tab, viewGroup, false)) {
var data: TabViewHolderData? = null;
private val _imageDragDrop: ImageView = _view.findViewById(R.id.image_drag_drop);
@@ -41,18 +43,18 @@ class TabViewHolder(_viewGroup: ViewGroup) : AnyAdapter.AnyViewHolder
+ _imageDragDrop.setOnTouchListener { _, event ->
if (event.action == MotionEvent.ACTION_DOWN) {
onDragDrop.emit(this);
}
false
- });
+ };
}
- override fun bind(i: TabViewHolderData) {
- _textTabName.text = _view.context.resources.getString(i.buttonDefinition.string);
- _toggleTab.visibility = if (i.buttonDefinition.canToggle) View.VISIBLE else View.GONE;
- _toggleTab.setValue(i.enabled, false);
- data = i;
+ override fun bind(value: TabViewHolderData) {
+ _textTabName.text = _view.context.resources.getString(value.buttonDefinition.string);
+ _toggleTab.visibility = if (value.buttonDefinition.canToggle) View.VISIBLE else View.GONE;
+ _toggleTab.setValue(value.enabled, false);
+ data = value;
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/VideoDownloadViewHolder.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/VideoDownloadViewHolder.kt
index a8d58d5b..ae4e6ec9 100644
--- a/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/VideoDownloadViewHolder.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/VideoDownloadViewHolder.kt
@@ -1,6 +1,6 @@
package com.futo.platformplayer.views.adapters.viewholders
-import android.app.Activity
+import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.ImageButton
@@ -65,26 +65,26 @@ class VideoDownloadViewHolder(_viewGroup: ViewGroup) : AnyAdapter.AnyViewHolder<
}
}
- override fun bind(video: VideoLocal) {
- _video = video;
- _videoName.text = video.name;
- _videoDuration.text = video.duration.toHumanTime(false);
- _videoAuthor.text = video.author.name;
- _videoSize.text = (video.videoSource.sumOf { it.fileSize } + video.audioSource.sumOf { it.fileSize }).toHumanBytesSize(false);
+ @SuppressLint("SetTextI18n")
+ override fun bind(value: VideoLocal) {
+ _video = value;
+ _videoName.text = value.name;
+ _videoDuration.text = value.duration.toHumanTime(false);
+ _videoAuthor.text = value.author.name;
+ _videoSize.text = (value.videoSource.sumOf { it.fileSize } + value.audioSource.sumOf { it.fileSize }).toHumanBytesSize(false);
val tokens = arrayListOf();
-
- if(video.videoSource.isNotEmpty()) {
- tokens.add(video.videoSource.maxBy { it.width * it.height }.let { "${it.width}x${it.height} (${it.container})" });
+ if(value.videoSource.isNotEmpty()) {
+ tokens.add(value.videoSource.maxBy { it.width * it.height }.let { "${it.width}x${it.height} (${it.container})" });
}
- if (video.audioSource.isNotEmpty()) {
- tokens.add(video.audioSource.maxBy { it.bitrate }.let { it.bitrate.toHumanBitrate() });
+ if (value.audioSource.isNotEmpty()) {
+ tokens.add(value.audioSource.maxBy { it.bitrate }.let { it.bitrate.toHumanBitrate() });
}
- _videoInfo.text =tokens.joinToString(" • ");
+ _videoInfo.text = tokens.joinToString(" • ");
- _videoImage.loadThumbnails(video.thumbnails, true) {
+ _videoImage.loadThumbnails(value.thumbnails, true) {
it.placeholder(R.drawable.placeholder_video_thumbnail)
.into(_videoImage);
};
diff --git a/app/src/main/java/com/futo/platformplayer/views/announcements/AnnouncementView.kt b/app/src/main/java/com/futo/platformplayer/views/announcements/AnnouncementView.kt
index d1b75a5b..7767265f 100644
--- a/app/src/main/java/com/futo/platformplayer/views/announcements/AnnouncementView.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/announcements/AnnouncementView.kt
@@ -3,7 +3,9 @@ package com.futo.platformplayer.views.announcements
import android.content.Context
import android.util.AttributeSet
import android.view.View
-import android.widget.*
+import android.widget.FrameLayout
+import android.widget.LinearLayout
+import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.lifecycle.findViewTreeLifecycleOwner
import androidx.lifecycle.lifecycleScope
@@ -55,7 +57,6 @@ class AnnouncementView : LinearLayout {
_buttonAction.setOnClickListener {
val a = _currentAnnouncement ?: return@setOnClickListener;
- val scope = StateApp.instance.scopeOrNull ?: return@setOnClickListener;
StateAnnouncement.instance.actionAnnouncement(a);
};
@@ -73,6 +74,7 @@ class AnnouncementView : LinearLayout {
val attrArr = context.obtainStyledAttributes(attrs, R.styleable.AnnouncementView, 0, 0);
_category = attrArr.getText(R.styleable.AnnouncementView_category)?.toString();
+ attrArr.recycle()
refresh();
}
diff --git a/app/src/main/java/com/futo/platformplayer/views/buttons/BigButton.kt b/app/src/main/java/com/futo/platformplayer/views/buttons/BigButton.kt
index 5db79617..f3bbc7b8 100644
--- a/app/src/main/java/com/futo/platformplayer/views/buttons/BigButton.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/buttons/BigButton.kt
@@ -64,15 +64,14 @@ open class BigButton : LinearLayout {
val attrArr = context.obtainStyledAttributes(attrs, R.styleable.BigButton, 0, 0);
val attrIconRef = attrArr.getResourceId(R.styleable.BigButton_buttonIcon, -1);
- withIcon(attrIconRef);
-
val attrBackgroundRef = attrArr.getResourceId(R.styleable.BigButton_buttonBackground, -1);
- withBackground(attrBackgroundRef);
-
val attrText = attrArr.getText(R.styleable.BigButton_buttonText) ?: "";
- _textPrimary.text = attrText;
-
val attrTextSecondary = attrArr.getText(R.styleable.BigButton_buttonSubText) ?: "";
+ attrArr.recycle()
+
+ withIcon(attrIconRef);
+ withBackground(attrBackgroundRef);
+ _textPrimary.text = attrText;
_textSecondary.text = attrTextSecondary;
}
@@ -123,11 +122,8 @@ open class BigButton : LinearLayout {
fun withIcon(bitmap: Bitmap, rounded: Boolean = false): BigButton {
- if (bitmap != null) {
- _icon.visibility = View.VISIBLE;
- _icon.setImageBitmap(bitmap);
- } else
- _icon.visibility = View.GONE;
+ _icon.visibility = View.VISIBLE;
+ _icon.setImageBitmap(bitmap);
if (rounded) {
val shapeAppearanceModel = ShapeAppearanceModel().toBuilder()
diff --git a/app/src/main/java/com/futo/platformplayer/views/buttons/DescButton.kt b/app/src/main/java/com/futo/platformplayer/views/buttons/DescButton.kt
index f5e13eae..81fc89d5 100644
--- a/app/src/main/java/com/futo/platformplayer/views/buttons/DescButton.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/buttons/DescButton.kt
@@ -1,16 +1,12 @@
package com.futo.platformplayer.views.buttons
import android.content.Context
-import android.graphics.Color
import android.util.AttributeSet
-import android.view.LayoutInflater
-import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import com.futo.platformplayer.R
import com.futo.platformplayer.constructs.Event0
-import com.futo.platformplayer.constructs.Event1
class DescButton : LinearLayout {
@@ -31,6 +27,7 @@ class DescButton : LinearLayout {
imageIcon.setImageResource(attrArr.getResourceId(R.styleable.DescButton_desc_icon, 0))
textTitle.text = attrArr.getText(R.styleable.DescButton_desc_title) ?: "";
textDescription.text = attrArr.getText(R.styleable.DescButton_desc_description) ?: "";
+ attrArr.recycle()
this.setOnClickListener { onClick.emit() }
}
@@ -40,8 +37,8 @@ class DescButton : LinearLayout {
textDescription = findViewById(R.id.text_description)
imageIcon.setImageResource(icon);
- textTitle.text = title ?: "";
- textDescription.text = description ?: "";
+ textTitle.text = title;
+ textDescription.text = description;
this.setOnClickListener { onClick.emit() }
}
diff --git a/app/src/main/java/com/futo/platformplayer/views/casting/CastView.kt b/app/src/main/java/com/futo/platformplayer/views/casting/CastView.kt
index f322eaeb..535520a7 100644
--- a/app/src/main/java/com/futo/platformplayer/views/casting/CastView.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/casting/CastView.kt
@@ -1,3 +1,5 @@
+@file:Suppress("DEPRECATION")
+
package com.futo.platformplayer.views.casting
import android.content.Context
@@ -7,20 +9,29 @@ import android.util.AttributeSet
import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
-import android.widget.*
+import android.widget.FrameLayout
+import android.widget.ImageButton
+import android.widget.ImageView
+import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import com.bumptech.glide.Glide
-import com.futo.platformplayer.*
+import com.futo.platformplayer.R
import com.futo.platformplayer.api.media.models.video.IPlatformVideoDetails
import com.futo.platformplayer.casting.AirPlayCastingDevice
import com.futo.platformplayer.casting.StateCasting
import com.futo.platformplayer.constructs.Event0
import com.futo.platformplayer.states.StatePlayer
+import com.futo.platformplayer.toHumanTime
import com.futo.platformplayer.views.behavior.GestureControlView
import com.google.android.exoplayer2.ui.DefaultTimeBar
import com.google.android.exoplayer2.ui.TimeBar
import com.google.android.exoplayer2.ui.TimeBar.OnScrubListener
-import kotlinx.coroutines.*
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
class CastView : ConstraintLayout {
private val _thumbnail: ImageView;
@@ -39,7 +50,6 @@ class CastView : ConstraintLayout {
private var _scope: CoroutineScope = CoroutineScope(Dispatchers.Main);
private var _updateTimeJob: Job? = null;
private var _inPictureInPicture: Boolean = false;
- private var _originalBottomMargin: Int = 0;
val onMinimizeClick = Event0();
val onSettingsClick = Event0();
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 f2f95d1a..590335d3 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
@@ -3,9 +3,12 @@ package com.futo.platformplayer.views.fields
import android.content.Context
import android.util.AttributeSet
import android.view.View
-import android.widget.*
+import android.widget.AdapterView
+import android.widget.ArrayAdapter
+import android.widget.Spinner
+import android.widget.TableRow
+import android.widget.TextView
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
@@ -136,20 +139,19 @@ class DropdownField : TableRow, IField {
arrayOf("Unset"))
.toList().toTypedArray();
- if(_options != null){
- _spinner.adapter = ArrayAdapter(context, R.layout.spinner_item_simple, _options).also {
- it.setDropDownViewResource(R.layout.spinner_dropdownitem_simple);
- };
+ _spinner.adapter = ArrayAdapter(context, R.layout.spinner_item_simple, _options).also {
+ it.setDropDownViewResource(R.layout.spinner_dropdownitem_simple);
+ };
- if(field.type == Int::class.java)
- _selected = field.get(obj) as Int;
- else {
- val valStr = field.get(obj)?.toString();
- _selected = if (_options.contains(valStr)) _options.indexOf(valStr) else 0;
- }
- _spinner.isSelected = false;
- _spinner.setSelection(_selected, true);
+ _selected = if(field.type == Int::class.java) {
+ field.get(obj) as Int;
+ } else {
+ val valStr = field.get(obj)?.toString();
+ if (_options.contains(valStr)) _options.indexOf(valStr) else 0;
}
+
+ _spinner.isSelected = false;
+ _spinner.setSelection(_selected, true);
return this;
}
override fun setField() {
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 24ebf38e..e5b73757 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
@@ -50,15 +50,14 @@ class FieldForm : LinearLayout {
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)
+ if(field is GroupField) {
updateSettingsVisibility(field);
- else if(field is View && field.descriptor != null) {
+ } else if(field is View && field.descriptor != null) {
val txt = field.searchContent?.lowercase();
if(txt != null) {
val visible = isGroupMatch || txt.contains(query);
@@ -67,8 +66,9 @@ class FieldForm : LinearLayout {
}
}
}
- if(group != null)
- group.visibility = if(groupVisible) View.VISIBLE else View.GONE;
+ if(group != null) {
+ group.visibility = if (groupVisible) View.VISIBLE else View.GONE;
+ }
}
fun setSearchVisible(visible: Boolean) {
@@ -84,11 +84,12 @@ class FieldForm : LinearLayout {
withContext(Dispatchers.Main) {
for (field in newFields) {
- if (field !is View)
+ if (field !is View) {
throw java.lang.IllegalStateException("Only views can be IFields");
+ }
_fieldsContainer.addView(field as View);
- field.onChanged.subscribe { a1, a2, oldValue ->
+ field.onChanged.subscribe { a1, a2, _ ->
onChanged.emit(a1, a2);
};
}
@@ -102,11 +103,12 @@ class FieldForm : LinearLayout {
_fieldsContainer.removeAllViews();
val newFields = getFieldsFromObject(context, obj);
for(field in newFields) {
- if(field !is View)
+ if(field !is View) {
throw java.lang.IllegalStateException("Only views can be IFields");
+ }
_fieldsContainer.addView(field as View);
- field.onChanged.subscribe { a1, a2, oldValue ->
+ field.onChanged.subscribe { a1, a2, _ ->
onChanged.emit(a1, a2);
};
}
@@ -121,10 +123,13 @@ class FieldForm : LinearLayout {
if(groupTitle == null) {
for(field in newFields) {
- if(field.second !is View)
+ val v = field.second
+ if(v !is View) {
throw java.lang.IllegalStateException("Only views can be IFields");
- finalizePluginSettingField(field.first, field.second, newFields);
- _fieldsContainer.addView(field as View);
+ }
+
+ finalizePluginSettingField(field.first, v, newFields);
+ _fieldsContainer.addView(v);
}
_fields = newFields.map { it.second };
} else {
@@ -137,34 +142,36 @@ class FieldForm : LinearLayout {
}
}
private fun finalizePluginSettingField(setting: SourcePluginConfig.Setting, field: IField, others: List>) {
- field.onChanged.subscribe { field, value, oldValue ->
- onChanged.emit(field, value);
+ field.onChanged.subscribe { f, value, oldValue ->
+ onChanged.emit(f, value);
setting.warningDialog?.let {
- if(it.isNotBlank() && IField.isValueTrue(value))
+ if(it.isNotBlank() && IField.isValueTrue(value)) {
UIDialogs.showDialog(context, R.drawable.ic_warning_yellow, setting.warningDialog, null, null, 0,
UIDialogs.Action("Cancel", {
- field.setValue(oldValue);
+ f.setValue(oldValue);
}, UIDialogs.ActionStyle.NONE),
- UIDialogs.Action("Ok", {
-
- }, UIDialogs.ActionStyle.PRIMARY));
+ 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)
+ if (dependentField == null || dependentField.second !is View) {
(field as View).visibility = View.GONE;
- else {
+ } else {
val dependencyReady = IField.isValueTrue(dependentField.second.value);
- if(!dependencyReady)
+ if (!dependencyReady) {
(field as View).visibility = View.GONE;
- dependentField.second.onChanged.subscribe { dependentField, value, oldValue ->
+ }
+
+ dependentField.second.onChanged.subscribe { _, value, _ ->
val isValid = IField.isValueTrue(value);
- if(isValid)
+ if (isValid) {
(field as View).visibility = View.VISIBLE;
- else
+ } else {
(field as View).visibility = View.GONE;
+ }
}
}
}
@@ -172,19 +179,20 @@ class FieldForm : LinearLayout {
fun setObjectValues(){
val fields = _fields;
- for (field in fields)
+ for (field in fields) {
field.setField();
+ }
}
fun findField(id: String) : IField? {
for(field in _fields) {
- if(field?.descriptor?.id == id)
+ if(field.descriptor?.id == id) {
return field;
- else if(field is GroupField)
- {
+ } else if(field is GroupField) {
val subField = field.findField(id);
- if(subField != null)
+ if(subField != null) {
return subField;
+ }
}
}
return null;
@@ -198,7 +206,7 @@ class FieldForm : LinearLayout {
const val TOGGLE = "toggle";
const val BUTTON = "button";
- private val _json = Json {};
+ private val _json = Json;
fun getFieldsFromPluginSettings(context: Context, settings: List, values: HashMap): List> {
@@ -216,17 +224,17 @@ class FieldForm : LinearLayout {
val field = ToggleField(context).withValue(setting.name,
setting.description,
value == "true" || value == "1" || value == "True");
- field.onChanged.subscribe { field, value, oldValue ->
- values[setting.variableOrName] = _json.encodeToString (value == 1 || value == true);
+ field.onChanged.subscribe { _, v, _ ->
+ values[setting.variableOrName] = _json.encodeToString (v == 1 || v == true);
}
field;
}
"dropdown" -> {
- if(setting.options != null && !setting.options.isEmpty()) {
+ if(!setting.options.isNullOrEmpty()) {
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.onChanged.subscribe { _, v, _ ->
+ values[setting.variableOrName] = v.toString();
}
field;
}
@@ -235,8 +243,9 @@ class FieldForm : LinearLayout {
else -> null;
}
- if(field != null)
+ if(field != null) {
fields.add(Pair(setting, field));
+ }
}
return fields;
}
@@ -269,11 +278,11 @@ class FieldForm : LinearLayout {
if(field.field != null) {
val warning = propertyMap[field.field]?.findAnnotation();
if(warning != null) {
- field.onChanged.subscribe { field, value, oldValue ->
+ field.onChanged.subscribe { f, value, oldValue ->
if(IField.isValueTrue(value))
UIDialogs.showDialog(context, R.drawable.ic_warning_yellow, context.getString(warning.messageRes), null, null, 0,
UIDialogs.Action("Cancel", {
- field.setValue(oldValue);
+ f.setValue(oldValue);
}, UIDialogs.ActionStyle.NONE),
UIDialogs.Action("Ok", {
@@ -304,14 +313,18 @@ class FieldForm : LinearLayout {
.asSequence()
.asStream()
.filter { it.getAnnotation(FormField::class.java) != null && !it.name.startsWith("get") && !it.name.startsWith("set") }
- .map { Pair(it, it.getAnnotation(FormField::class.java)) }
+ .map { Pair(it, it.getAnnotation(FormField::class.java)) }
for(meth in objMethods) {
+ if (meth.second == null) {
+ continue
+ }
+
meth.first.isAccessible = true;
- val field = when(meth.second.type) {
+ val field = when(meth.second!!.type) {
BUTTON -> ButtonField(context).fromMethod(obj, meth.first);
- else -> throw java.lang.IllegalStateException("Unknown method type ${meth.second.type} for ${meth.second.title}")
+ else -> throw java.lang.IllegalStateException("Unknown method type ${meth.second!!.type} for ${meth.second!!.title}")
}
fields.add(field as IField);
}
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 6ea48ee7..133fb788 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
@@ -6,10 +6,8 @@ import android.view.View
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
-import kotlin.reflect.KProperty
class GroupField : LinearLayout, IField {
override var descriptor : FormField? = null;
@@ -39,7 +37,7 @@ class GroupField : LinearLayout, IField {
override val value: Any? = null;
- override val searchContent: String? get() = "${_title.text} ${_subtitle.text}";
+ override val searchContent: String get() = "${_title.text} ${_subtitle.text}";
constructor(context : Context, attrs : AttributeSet? = null) : super(context, attrs) {
inflate(context, R.layout.field_group, this);
@@ -59,25 +57,28 @@ class GroupField : LinearLayout, IField {
_title.text = title;
_subtitle.text = description ?: "";
- if(!(_title.text?.isEmpty() ?: true))
+ if(_title.text?.isEmpty() == false) {
_title.visibility = VISIBLE;
- else
+ } else {
_title.visibility = GONE;
- if(!(_subtitle.text?.isEmpty() ?: true))
+ }
+
+ if (_subtitle.text?.isEmpty() == false) {
_subtitle.visibility = VISIBLE;
- else
+ } else {
_subtitle.visibility = GONE;
+ }
}
fun findField(id: String) : IField? {
for(field in _fields) {
- if(field.descriptor?.id == id)
+ if(field.descriptor?.id == id) {
return field;
- else if(field is GroupField)
- {
+ } else if(field is GroupField) {
val subField = field.findField(id);
- if(subField != null)
+ if(subField != null) {
return subField;
+ }
}
}
return null;
@@ -87,7 +88,7 @@ class GroupField : LinearLayout, IField {
_container.removeAllViews();
val newFields = mutableListOf()
for(field in fields) {
- if(!(field is View))
+ if(field !is View)
throw java.lang.IllegalStateException("Only views can be IFields");
field.onChanged.subscribe(onChanged::emit);
@@ -99,7 +100,7 @@ class GroupField : LinearLayout, IField {
return this;
}
- override fun fromField(obj : Any, field : Field, formField: FormField?) : GroupField {
+ override fun fromField(obj: Any, field: Field, formField: FormField?) : GroupField {
this._field = field;
this._obj = obj;
@@ -116,21 +117,23 @@ class GroupField : LinearLayout, IField {
_container.removeAllViews();
val newFields = mutableListOf()
- for(field in FieldForm.getFieldsFromObject(context, value)) {
- if(!(field is View))
- throw java.lang.IllegalStateException("Only views can be IFields");
+ if (value != null) {
+ for (f in FieldForm.getFieldsFromObject(context, value)) {
+ if (f !is View)
+ throw java.lang.IllegalStateException("Only views can be IFields");
- field.onChanged.subscribe(onChanged::emit);
- _container.addView(field as View);
- newFields.add(field);
+ f.onChanged.subscribe(onChanged::emit);
+ _container.addView(f as View);
+ newFields.add(f);
+ }
}
_fields = newFields;
- if(!(_title.text?.isEmpty() ?: true))
+ if(_title.text?.isEmpty() == false)
_title.visibility = VISIBLE;
else
_title.visibility = GONE;
- if(!(_subtitle.text?.isEmpty() ?: true))
+ if(_subtitle.text?.isEmpty() == false)
_subtitle.visibility = VISIBLE;
else
_subtitle.visibility = GONE;
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 7b0244dc..d0cfb7dc 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
@@ -2,9 +2,9 @@ package com.futo.platformplayer.views.fields
import android.content.Context
import android.util.AttributeSet
-import android.widget.*
+import android.widget.TableRow
+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
import java.lang.reflect.Method
@@ -34,7 +34,7 @@ class ReadOnlyTextField : TableRow, IField {
override val value: Any? = null;
- override val searchContent: String?
+ override val searchContent: String
get() = "${_title.text}";
constructor(context : Context, attrs : AttributeSet? = null) : super(context, attrs){
@@ -50,17 +50,19 @@ class ReadOnlyTextField : TableRow, IField {
this._obj = obj;
val attrField = formField ?: field.getAnnotation(FormField::class.java);
- if(attrField != null) {
+ if (attrField != null) {
_title.text = context.getString(attrField.title);
descriptor = attrField;
- }
- else
+ } else {
_title.text = field.name;
+ }
- if(field.type == String::class.java)
+ if (field.type == String::class.java) {
_value.text = field.get(obj) as String;
- else
- _value.text = field.get(obj).toString();
+ } else {
+ _value.text = field.get(obj)?.toString() ?: "";
+ }
+
return this;
}
fun fromProp(obj : Any, field : Method, formField: FormField?) : ReadOnlyTextField {
@@ -68,17 +70,19 @@ class ReadOnlyTextField : TableRow, IField {
this._obj = obj;
val attrField = formField ?: field.getAnnotation(FormField::class.java);
- if(attrField != null) {
+ if (attrField != null) {
_title.text = context.getString(attrField.title);
descriptor = attrField;
- }
- else
+ } else {
_title.text = field.name;
+ }
- if(field.returnType == String::class.java)
+ if (field.returnType == String::class.java) {
_value.text = field.invoke(obj) as String;
- else
+ } else {
_value.text = field.invoke(obj)?.toString() ?: "";
+ }
+
return this;
}
override fun setField() {
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 2bbbbb21..8e1cfbbb 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
@@ -3,9 +3,9 @@ package com.futo.platformplayer.views.fields
import android.content.Context
import android.util.AttributeSet
import android.view.View
-import android.widget.*
+import android.widget.TableRow
+import android.widget.TextView
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
@@ -94,15 +94,13 @@ class ToggleField : TableRow, IField {
_description.visibility = View.VISIBLE;
}
- val value = field.get(obj);
- val toggleValue = if(value is Boolean)
- value;
- else if(value is Number)
- (value as Number).toInt() > 0;
- else if(value == null)
- false;
- else
- false;
+ val toggleValue = when (val value = field.get(obj)) {
+ is Boolean -> value
+ is Number -> value.toInt() > 0
+ null -> false
+ else -> false
+ };
+
_toggle.setValue(toggleValue, true);
_lastValue = toggleValue;
diff --git a/app/src/main/java/com/futo/platformplayer/views/livechat/LiveChatListAdapter.kt b/app/src/main/java/com/futo/platformplayer/views/livechat/LiveChatListAdapter.kt
index eecc6d7e..13d1c18e 100644
--- a/app/src/main/java/com/futo/platformplayer/views/livechat/LiveChatListAdapter.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/livechat/LiveChatListAdapter.kt
@@ -1,15 +1,10 @@
package com.futo.platformplayer.views.livechat
-import android.content.Context
-import android.view.*
+import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.recyclerview.widget.RecyclerView
-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.live.LiveEventComment
import com.futo.platformplayer.api.media.models.live.LiveEventDonation
-import com.futo.platformplayer.views.adapters.ContentPreviewViewHolder
-import com.futo.platformplayer.views.adapters.EmptyPreviewViewHolder
import com.futo.platformplayer.views.overlays.LiveChatOverlay
class LiveChatListAdapter : RecyclerView.Adapter {
@@ -17,7 +12,7 @@ class LiveChatListAdapter : RecyclerView.Adapter {
private val _dataSet: ArrayList;
- constructor(context: Context, dataSet: ArrayList): super() {
+ constructor(dataSet: ArrayList): super() {
this._dataSet = dataSet;
}
@@ -28,13 +23,11 @@ class LiveChatListAdapter : RecyclerView.Adapter {
}
val item = _dataSet.getOrNull(position) ?: return -1;
- if(item.event is LiveEventComment)
- return 1;
- else if(item.event is LiveEventDonation)
- return 2;
- else
- return -1;
-
+ return when (item.event) {
+ is LiveEventComment -> 1
+ is LiveEventDonation -> 2
+ else -> -1
+ };
}
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): LiveChatListItem {
diff --git a/app/src/main/java/com/futo/platformplayer/views/livechat/LiveChatListItem.kt b/app/src/main/java/com/futo/platformplayer/views/livechat/LiveChatListItem.kt
index 88f5a68a..bc712b16 100644
--- a/app/src/main/java/com/futo/platformplayer/views/livechat/LiveChatListItem.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/livechat/LiveChatListItem.kt
@@ -1,23 +1,8 @@
package com.futo.platformplayer.views.livechat
-import android.graphics.Color
-import android.graphics.drawable.LevelListDrawable
-import android.text.Spannable
-import android.text.style.ImageSpan
-import android.view.LayoutInflater
import android.view.View
-import android.view.ViewGroup
-import android.widget.ImageView
-import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
-import com.bumptech.glide.Glide
-import com.futo.platformplayer.R
-import com.futo.platformplayer.api.media.models.live.LiveEventComment
-import com.futo.platformplayer.dp
-import com.futo.platformplayer.views.adapters.AnyAdapter
import com.futo.platformplayer.views.overlays.LiveChatOverlay
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
abstract class LiveChatListItem(view: View): RecyclerView.ViewHolder(view) {
protected val _view = view;
diff --git a/app/src/main/java/com/futo/platformplayer/views/others/RadioView.kt b/app/src/main/java/com/futo/platformplayer/views/others/RadioView.kt
index 22ff167e..13a865a2 100644
--- a/app/src/main/java/com/futo/platformplayer/views/others/RadioView.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/others/RadioView.kt
@@ -6,6 +6,7 @@ import android.view.LayoutInflater
import android.widget.FrameLayout
import android.widget.LinearLayout
import android.widget.TextView
+import androidx.core.content.ContextCompat
import com.futo.platformplayer.R
import com.futo.platformplayer.constructs.Event0
import com.futo.platformplayer.constructs.Event1
@@ -33,7 +34,7 @@ class RadioView : LinearLayout {
};
_root.setBackgroundResource(R.drawable.background_radio_unselected);
- _textTag.setTextColor(resources.getColor(R.color.gray_67));
+ _textTag.setTextColor(ContextCompat.getColor(context, R.color.gray_67));
}
fun setInfo(text: String, selected: Boolean) {
@@ -50,7 +51,7 @@ class RadioView : LinearLayout {
_selected = selected;
_root.setBackgroundResource(if (selected) R.drawable.background_radio_selected else R.drawable.background_radio_unselected);
- _textTag.setTextColor(resources.getColor(if (selected) R.color.white else R.color.gray_67));
+ _textTag.setTextColor(ContextCompat.getColor(context, if (selected) R.color.white else R.color.gray_67));
onSelectedChange.emit(_selected);
}
diff --git a/app/src/main/java/com/futo/platformplayer/views/overlays/LiveChatOverlay.kt b/app/src/main/java/com/futo/platformplayer/views/overlays/LiveChatOverlay.kt
index 385be76d..1e6160df 100644
--- a/app/src/main/java/com/futo/platformplayer/views/overlays/LiveChatOverlay.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/overlays/LiveChatOverlay.kt
@@ -7,8 +7,6 @@ import android.graphics.PointF
import android.util.AttributeSet
import android.util.DisplayMetrics
import android.view.View
-import android.webkit.CookieManager
-import android.webkit.ValueCallback
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.Button
@@ -24,7 +22,6 @@ import androidx.recyclerview.widget.LinearSmoothScroller
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.futo.platformplayer.R
-import com.futo.platformplayer.UIDialogs
import com.futo.platformplayer.api.media.LiveChatManager
import com.futo.platformplayer.api.media.models.live.ILiveChatWindowDescriptor
import com.futo.platformplayer.api.media.models.live.ILiveEventChatMessage
@@ -38,17 +35,11 @@ import com.futo.platformplayer.constructs.Event1
import com.futo.platformplayer.dp
import com.futo.platformplayer.isHexColor
import com.futo.platformplayer.logging.Logger
-import com.futo.platformplayer.toHumanBitrate
import com.futo.platformplayer.toHumanNumber
-import com.futo.platformplayer.views.AnyAdapterView
-import com.futo.platformplayer.views.AnyAdapterView.Companion.asAny
import com.futo.platformplayer.views.livechat.LiveChatDonationPill
import com.futo.platformplayer.views.livechat.LiveChatListAdapter
-import com.futo.platformplayer.views.livechat.LiveChatMessageListItem
-import com.stripe.android.core.utils.encodeToJson
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
@@ -123,8 +114,7 @@ class LiveChatOverlay : LinearLayout {
_chatContainer = findViewById(R.id.chatContainer);
_chatLayoutManager = ChatLayoutManager(context);
- //_chatAdapter = _chatContainer.asAny(_chats);
- _chatAdapter = LiveChatListAdapter(context, _chats);
+ _chatAdapter = LiveChatListAdapter(_chats);
_chatContainer.adapter = _chatAdapter;
_chatContainer.layoutManager = _chatLayoutManager;
diff --git a/app/src/main/java/com/futo/platformplayer/views/overlays/SupportOverlay.kt b/app/src/main/java/com/futo/platformplayer/views/overlays/SupportOverlay.kt
index d43bddd4..36034d43 100644
--- a/app/src/main/java/com/futo/platformplayer/views/overlays/SupportOverlay.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/overlays/SupportOverlay.kt
@@ -23,8 +23,8 @@ class SupportOverlay : LinearLayout {
}
- fun setPolycentricProfile(profile: PolycentricProfile?, animate: Boolean) {
- _support.setPolycentricProfile(profile, animate)
+ fun setPolycentricProfile(profile: PolycentricProfile?) {
+ _support.setPolycentricProfile(profile)
}
fun cleanup() {
diff --git a/app/src/main/java/com/futo/platformplayer/views/overlays/slideup/SlideUpMenuGroup.kt b/app/src/main/java/com/futo/platformplayer/views/overlays/slideup/SlideUpMenuGroup.kt
index 32e36027..9f19018d 100644
--- a/app/src/main/java/com/futo/platformplayer/views/overlays/slideup/SlideUpMenuGroup.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/overlays/slideup/SlideUpMenuGroup.kt
@@ -61,7 +61,7 @@ class SlideUpMenuGroup : LinearLayout {
return didSelect;
}
- private fun addItems(items: List) {
+ private fun addItems(items: List) {
for (item in items) {
item.setParentClickListener { parentClickListener?.invoke() }
itemContainer.addView(item);
diff --git a/app/src/main/java/com/futo/platformplayer/views/overlays/slideup/SlideUpMenuOverlay.kt b/app/src/main/java/com/futo/platformplayer/views/overlays/slideup/SlideUpMenuOverlay.kt
index 2c34dc5e..157c13a6 100644
--- a/app/src/main/java/com/futo/platformplayer/views/overlays/slideup/SlideUpMenuOverlay.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/overlays/slideup/SlideUpMenuOverlay.kt
@@ -17,7 +17,6 @@ import com.futo.platformplayer.R
import com.futo.platformplayer.constructs.Event0
class SlideUpMenuOverlay : RelativeLayout {
-
private var _container: ViewGroup? = null;
private lateinit var _textTitle: TextView;
private lateinit var _textCancel: TextView;
@@ -27,7 +26,7 @@ class SlideUpMenuOverlay : RelativeLayout {
private lateinit var _viewContainer: LinearLayout;
private var _animated: Boolean = true;
- private lateinit var _groupItems: List;
+ private var _groupItems: List;
var isVisible = false
private set;
diff --git a/app/src/main/java/com/futo/platformplayer/views/overlays/slideup/SlideUpMenuTitle.kt b/app/src/main/java/com/futo/platformplayer/views/overlays/slideup/SlideUpMenuTitle.kt
index 25135cfa..a084aa8d 100644
--- a/app/src/main/java/com/futo/platformplayer/views/overlays/slideup/SlideUpMenuTitle.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/overlays/slideup/SlideUpMenuTitle.kt
@@ -2,15 +2,10 @@ package com.futo.platformplayer.views.overlays.slideup
import android.content.Context
import android.util.AttributeSet
-import android.util.TypedValue
-import android.view.Gravity
import android.view.LayoutInflater
import android.widget.LinearLayout
import android.widget.TextView
-import androidx.core.content.ContextCompat
-import androidx.core.content.res.ResourcesCompat
import com.futo.platformplayer.R
-import com.futo.platformplayer.constructs.Event1
class SlideUpMenuTitle : LinearLayout {
private val _title: TextView;
diff --git a/app/src/main/java/com/futo/platformplayer/views/sources/SourceHeaderView.kt b/app/src/main/java/com/futo/platformplayer/views/sources/SourceHeaderView.kt
index 7d961d77..2b0c4e10 100644
--- a/app/src/main/java/com/futo/platformplayer/views/sources/SourceHeaderView.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/sources/SourceHeaderView.kt
@@ -8,10 +8,11 @@ import android.util.AttributeSet
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
+import androidx.core.content.ContextCompat
import com.bumptech.glide.Glide
import com.futo.platformplayer.R
-import com.futo.platformplayer.states.StatePlugins
import com.futo.platformplayer.api.media.platforms.js.SourcePluginConfig
+import com.futo.platformplayer.states.StatePlugins
class SourceHeaderView : LinearLayout {
private val _sourceImage: ImageView;
@@ -89,8 +90,8 @@ class SourceHeaderView : LinearLayout {
else
_sourcePlatformUrlContainer.visibility = GONE;
- if(!config.authorUrl.isNullOrEmpty())
- _sourceBy.setTextColor(resources.getColor(R.color.colorPrimary));
+ if(config.authorUrl.isNotEmpty())
+ _sourceBy.setTextColor(ContextCompat.getColor(context, R.color.colorPrimary));
else
_sourceBy.setTextColor(Color.WHITE);
diff --git a/app/src/main/java/com/futo/platformplayer/views/sources/SourceInfoView.kt b/app/src/main/java/com/futo/platformplayer/views/sources/SourceInfoView.kt
index ec04f7ec..c8f21bae 100644
--- a/app/src/main/java/com/futo/platformplayer/views/sources/SourceInfoView.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/sources/SourceInfoView.kt
@@ -6,6 +6,7 @@ import android.util.AttributeSet
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
+import androidx.core.content.ContextCompat
import com.futo.platformplayer.R
import com.futo.platformplayer.constructs.Event1
import com.futo.platformplayer.views.others.BulletPointView
@@ -37,7 +38,7 @@ class SourceInfoView : LinearLayout {
textTitle.text = title;
textDescription.text = description;
- val primaryColor = resources.getColor(R.color.colorPrimary);
+ val primaryColor = ContextCompat.getColor(context, R.color.colorPrimary);
bulletPoints.removeAllViews();
for(point in points) {
diff --git a/app/src/main/java/com/futo/platformplayer/views/video/FutoThumbnailPlayer.kt b/app/src/main/java/com/futo/platformplayer/views/video/FutoThumbnailPlayer.kt
index e8ef2e6f..f4701155 100644
--- a/app/src/main/java/com/futo/platformplayer/views/video/FutoThumbnailPlayer.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/video/FutoThumbnailPlayer.kt
@@ -1,3 +1,5 @@
+@file:Suppress("DEPRECATION")
+
package com.futo.platformplayer.views.video
import android.content.Context
@@ -7,12 +9,13 @@ import android.view.View
import android.widget.ImageButton
import android.widget.LinearLayout
import android.widget.TextView
-import com.futo.platformplayer.*
-import com.futo.platformplayer.api.media.models.streams.VideoUnMuxedSourceDescriptor
+import com.futo.platformplayer.R
+import com.futo.platformplayer.Settings
import com.futo.platformplayer.api.media.models.streams.sources.IAudioSource
import com.futo.platformplayer.api.media.models.streams.sources.IVideoSource
import com.futo.platformplayer.api.media.models.video.IPlatformVideoDetails
import com.futo.platformplayer.helpers.VideoHelper
+import com.futo.platformplayer.toHumanTime
import com.futo.platformplayer.video.PlayerManager
import com.google.android.exoplayer2.ui.PlayerControlView
import com.google.android.exoplayer2.ui.StyledPlayerView
@@ -49,7 +52,7 @@ class FutoThumbnailPlayer : FutoVideoPlayerBase {
containerDuration = videoControls.findViewById(R.id.exo_duration_container);
containerLive = videoControls.findViewById(R.id.exo_live_container);
- videoControls.setProgressUpdateListener { position, bufferedPosition ->
+ videoControls.setProgressUpdateListener { position, _ ->
if(position < 0)
textDurationInverse.visibility = View.INVISIBLE;
else
diff --git a/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayer.kt b/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayer.kt
index 16a51e99..d306b090 100644
--- a/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayer.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayer.kt
@@ -1,3 +1,5 @@
+@file:Suppress("DEPRECATION")
+
package com.futo.platformplayer.views.video
import android.content.Context
@@ -12,11 +14,12 @@ import android.view.View
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.widget.FrameLayout
import android.widget.ImageButton
-import android.widget.RelativeLayout
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.setMargins
-import com.futo.platformplayer.*
+import com.futo.platformplayer.R
+import com.futo.platformplayer.Settings
+import com.futo.platformplayer.UIDialogs
import com.futo.platformplayer.api.media.models.chapters.IChapter
import com.futo.platformplayer.api.media.models.streams.sources.IAudioSource
import com.futo.platformplayer.api.media.models.streams.sources.IVideoSource
@@ -37,7 +40,6 @@ import com.google.android.exoplayer2.ui.TimeBar
import com.google.android.exoplayer2.video.VideoSize
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import java.util.concurrent.Executors
@@ -130,8 +132,6 @@ class FutoVideoPlayer : FutoVideoPlayerBase {
_root = findViewById(R.id.videoview_root);
_videoView = findViewById(R.id.video_player);
- val subs = _videoView.subtitleView;
-
videoControls = findViewById(R.id.video_player_controller);
_control_fullscreen = videoControls.findViewById(R.id.exo_fullscreen);
_control_videosettings = videoControls.findViewById(R.id.exo_settings);
@@ -192,22 +192,32 @@ class FutoVideoPlayer : FutoVideoPlayerBase {
if(!isInEditMode) {
_videoView.resizeMode = AspectRatioFrameLayout.RESIZE_MODE_ZOOM;
val player = StatePlayer.instance.getPlayerOrCreate(context);
- //player.modifyState(PLAYER_STATE_NAME, { it.scaleType = MediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING})
changePlayer(player);
videoControls.player = player.player;
_videoControls_fullscreen.player = player.player;
}
- val attrShowSettings = if(attrs != null)
- context.obtainStyledAttributes(attrs, R.styleable.FutoVideoPlayer, 0, 0).getBoolean(R.styleable.FutoVideoPlayer_showSettings, false) ?: false;
- else false;
- val attrShowFullScreen = if(attrs != null)
- context.obtainStyledAttributes(attrs, R.styleable.FutoVideoPlayer, 0, 0).getBoolean(R.styleable.FutoVideoPlayer_showFullScreen, false) ?: false;
- else false;
- val attrShowMinimize = if(attrs != null)
- context.obtainStyledAttributes(attrs, R.styleable.FutoVideoPlayer, 0, 0).getBoolean(R.styleable.FutoVideoPlayer_showMinimize, false) ?: false;
- else false;
+ val attrShowSettings = if(attrs != null) {
+ val attrArr = context.obtainStyledAttributes(attrs, R.styleable.FutoVideoPlayer, 0, 0)
+ val result = attrArr.getBoolean(R.styleable.FutoVideoPlayer_showSettings, false)
+ attrArr.recycle()
+ result
+ } else false;
+
+ val attrShowFullScreen = if(attrs != null) {
+ val attrArr = context.obtainStyledAttributes(attrs, R.styleable.FutoVideoPlayer, 0, 0)
+ val result = attrArr.getBoolean(R.styleable.FutoVideoPlayer_showFullScreen, false)
+ attrArr.recycle()
+ result
+ } else false;
+
+ val attrShowMinimize = if(attrs != null) {
+ val attrArr = context.obtainStyledAttributes(attrs, R.styleable.FutoVideoPlayer, 0, 0)
+ val result = attrArr.getBoolean(R.styleable.FutoVideoPlayer_showMinimize, false)
+ attrArr.recycle()
+ result
+ } else false;
if (!attrShowSettings)
_control_videosettings.visibility = View.GONE;
@@ -501,8 +511,6 @@ class FutoVideoPlayer : FutoVideoPlayerBase {
override fun onPlaybackStateChanged(playbackState: Int) {
Logger.v(TAG, "onPlaybackStateChanged $playbackState");
- val timeLeft = abs(position - duration);
-
if (playbackState == ExoPlayer.STATE_ENDED) {
if (abs(position - duration) < 2000) {
onSourceEnded.emit();
@@ -556,9 +564,9 @@ class FutoVideoPlayer : FutoVideoPlayerBase {
val maxHeight = deviceHeight * 0.6;
val determinedHeight = if(w > h)
- ((h * (viewWidth.toDouble() / w)).toInt().toInt())
+ ((h * (viewWidth.toDouble() / w)).toInt())
else
- ((h * (viewWidth.toDouble() / w)).toInt().toInt());
+ ((h * (viewWidth.toDouble() / w)).toInt());
_lastSourceFit = determinedHeight;
_lastSourceFit = Math.max(_lastSourceFit!!, 250);
_lastSourceFit = Math.min(_lastSourceFit!!, maxHeight.toInt());
@@ -572,23 +580,20 @@ class FutoVideoPlayer : FutoVideoPlayerBase {
}
val marginBottom = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 7f, resources.displayMetrics).toInt();
- val rootParams = RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, _lastSourceFit!! + marginBottom)
+ val rootParams = LayoutParams(LayoutParams.MATCH_PARENT, _lastSourceFit!! + marginBottom)
rootParams.bottomMargin = marginBottom;
_root.layoutParams = rootParams
isFitMode = true;
}
fun fillHeight(){
Logger.i(TAG, "Video Fill Height");
- val width = resources.displayMetrics.heightPixels;
- val height = resources.displayMetrics.widthPixels;
-
val layoutParams = _videoView.layoutParams as ConstraintLayout.LayoutParams;
_originalBottomMargin = if(layoutParams.bottomMargin > 0) layoutParams.bottomMargin else _originalBottomMargin;
layoutParams.setMargins(0);
_videoView.layoutParams = layoutParams;
_videoView.invalidate();
- val rootParams = RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+ val rootParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
_root.layoutParams = rootParams;
_root.invalidate();
isFitMode = false;
diff --git a/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt b/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt
index 6d8396d8..9a23b935 100644
--- a/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt
@@ -1,3 +1,5 @@
+@file:Suppress("DEPRECATION")
+
package com.futo.platformplayer.views.video
import android.content.Context
@@ -6,20 +8,31 @@ import android.util.AttributeSet
import android.widget.RelativeLayout
import com.futo.platformplayer.Settings
import com.futo.platformplayer.api.media.models.chapters.IChapter
-import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.api.media.models.streams.VideoMuxedSourceDescriptor
-import com.futo.platformplayer.helpers.VideoHelper
-import com.futo.platformplayer.api.media.models.streams.sources.*
+import com.futo.platformplayer.api.media.models.streams.sources.IAudioSource
+import com.futo.platformplayer.api.media.models.streams.sources.IAudioUrlSource
+import com.futo.platformplayer.api.media.models.streams.sources.IDashManifestSource
+import com.futo.platformplayer.api.media.models.streams.sources.IHLSManifestAudioSource
+import com.futo.platformplayer.api.media.models.streams.sources.IHLSManifestSource
+import com.futo.platformplayer.api.media.models.streams.sources.IVideoSource
+import com.futo.platformplayer.api.media.models.streams.sources.IVideoUrlSource
+import com.futo.platformplayer.api.media.models.streams.sources.LocalAudioSource
+import com.futo.platformplayer.api.media.models.streams.sources.LocalVideoSource
import com.futo.platformplayer.api.media.models.subtitles.ISubtitleSource
import com.futo.platformplayer.api.media.models.video.IPlatformVideoDetails
import com.futo.platformplayer.api.media.platforms.js.models.sources.JSAudioUrlRangeSource
import com.futo.platformplayer.api.media.platforms.js.models.sources.JSHLSManifestAudioSource
import com.futo.platformplayer.api.media.platforms.js.models.sources.JSVideoUrlRangeSource
import com.futo.platformplayer.constructs.Event1
-import com.futo.platformplayer.receivers.MediaControlReceiver
+import com.futo.platformplayer.helpers.VideoHelper
+import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.states.StateApp
import com.futo.platformplayer.video.PlayerManager
-import com.google.android.exoplayer2.*
+import com.google.android.exoplayer2.C
+import com.google.android.exoplayer2.ExoPlayer
+import com.google.android.exoplayer2.MediaItem
+import com.google.android.exoplayer2.PlaybackException
+import com.google.android.exoplayer2.Player
import com.google.android.exoplayer2.source.MediaSource
import com.google.android.exoplayer2.source.MergingMediaSource
import com.google.android.exoplayer2.source.ProgressiveMediaSource
@@ -392,10 +405,9 @@ abstract class FutoVideoPlayerBase : RelativeLayout {
}
private fun swapVideoSourceDash(videoSource: IDashManifestSource) {
Logger.i(TAG, "Loading VideoSource [Dash]");
- _lastVideoMediaSource = if (videoSource != null) DashMediaSource.Factory(DefaultHttpDataSource.Factory()
+ _lastVideoMediaSource = DashMediaSource.Factory(DefaultHttpDataSource.Factory()
.setUserAgent(DEFAULT_USER_AGENT))
- .createMediaSource(MediaItem.fromUri(videoSource.url));
- else null;
+ .createMediaSource(MediaItem.fromUri(videoSource.url))
}
private fun swapVideoSourceHLS(videoSource: IHLSManifestSource) {
Logger.i(TAG, "Loading VideoSource [HLS]");
@@ -513,7 +525,7 @@ abstract class FutoVideoPlayerBase : RelativeLayout {
this.onSourceChanged(lastVideoSource, lastAudioSource, resume);
}
else
- player.player?.stop();
+ player.player.stop();
}
fun clear() {
@@ -535,6 +547,7 @@ abstract class FutoVideoPlayerBase : RelativeLayout {
exoPlayer?.setVolume(volume);
}
+ @Suppress("DEPRECATION")
protected open fun onPlayerError(error: PlaybackException) {
Logger.i(TAG, "onPlayerError error=$error error.errorCode=${error.errorCode} connectivityLoss");
diff --git a/app/src/main/java/com/futo/platformplayer/views/videometa/UpNextView.kt b/app/src/main/java/com/futo/platformplayer/views/videometa/UpNextView.kt
index 8d9f136a..26a908c6 100644
--- a/app/src/main/java/com/futo/platformplayer/views/videometa/UpNextView.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/videometa/UpNextView.kt
@@ -145,7 +145,7 @@ class UpNextView : LinearLayout {
_layoutQueueBox.visibility = View.VISIBLE;
_layoutEndOfPlaylist.visibility = View.GONE;
- _textTitle.text = nextItem.name ?: "";
+ _textTitle.text = nextItem.name;
val metadataTokens = mutableListOf();
if (nextItem.viewCount > 0) {
@@ -157,7 +157,7 @@ class UpNextView : LinearLayout {
}
_textMetadata.text = metadataTokens.joinToString(" • ");
- _textChannelName.text = nextItem.author.name ?: "";
+ _textChannelName.text = nextItem.author.name;
Glide.with(_imageThumbnail)
.load(nextItem.thumbnails.getHQThumbnail())
.placeholder(R.drawable.placeholder_video_thumbnail)