diff --git a/app/src/main/java/com/futo/platformplayer/Settings.kt b/app/src/main/java/com/futo/platformplayer/Settings.kt index f2d689ed9c4d21bff14938303381d5b86676e82f..168cddfb674863820dd1085bb77b499fd5d9ccd7 100644 --- a/app/src/main/java/com/futo/platformplayer/Settings.kt +++ b/app/src/main/java/com/futo/platformplayer/Settings.kt @@ -685,7 +685,9 @@ class Settings : FragmentedStorageFileJson() { fun manualCheck() { if (!BuildConfig.IS_PLAYSTORE_BUILD) { SettingsActivity.getActivity()?.let { - StateUpdate.instance.checkForUpdates(it, true); + StateApp.instance.scopeOrNull?.launch(Dispatchers.IO) { + StateUpdate.instance.checkForUpdates(it, true) + } } } else { SettingsActivity.getActivity()?.let { 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 bc22d3dc4326a47ab8f1a0608eb3ce6b235c7f8b..067205743d0dcfc0d10c2fe278df6fb0a08babad 100644 --- a/app/src/main/java/com/futo/platformplayer/activities/AddSourceActivity.kt +++ b/app/src/main/java/com/futo/platformplayer/activities/AddSourceActivity.kt @@ -216,8 +216,10 @@ class AddSourceActivity : AppCompatActivity() { fun install(config: SourcePluginConfig, script: String) { StatePlugins.instance.installPlugin(this, lifecycleScope, config, script) { - if(it) + if(it) { + StatePlatform.instance.clearUpdateAvailable(config) backToSources(); + } } } diff --git a/app/src/main/java/com/futo/platformplayer/activities/ExceptionActivity.kt b/app/src/main/java/com/futo/platformplayer/activities/ExceptionActivity.kt index a51c0f4abcfb1902a8e9cd86519460a4ecf26a30..99a6e1b0b9835647db1b1e1beb7734c92b438c21 100644 --- a/app/src/main/java/com/futo/platformplayer/activities/ExceptionActivity.kt +++ b/app/src/main/java/com/futo/platformplayer/activities/ExceptionActivity.kt @@ -9,9 +9,11 @@ import android.widget.TextView import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.lifecycleScope -import com.futo.platformplayer.* +import com.futo.platformplayer.BuildConfig +import com.futo.platformplayer.R import com.futo.platformplayer.logging.LogLevel import com.futo.platformplayer.logging.Logging +import com.futo.platformplayer.setNavigationBarColorAndIcons import com.futo.platformplayer.states.StateApp import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch 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 3af3f01d8241678a7466ded0850616df48602b86..6a743d4e59b82e6a598e78ffdbe56829e8f0b02b 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 @@ -454,6 +454,7 @@ class SourceDetailFragment : MainFragment() { } }); } + private fun checkForUpdatesSource() { val c = _config ?: return; val sourceUrl = c.sourceUrl ?: return; 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 bcf685928e1ffd9f911558fbdfe7e84aa33f8f25..412abd555b1ffa5e90ddd35577f8f65f49e3cc03 100644 --- a/app/src/main/java/com/futo/platformplayer/states/StateApp.kt +++ b/app/src/main/java/com/futo/platformplayer/states/StateApp.kt @@ -460,7 +460,9 @@ class StateApp { //Foreground download autoUpdateEnabled -> { - StateUpdate.instance.checkForUpdates(context, false); + scopeOrNull?.launch(Dispatchers.IO) { + StateUpdate.instance.checkForUpdates(context, false) + } } else -> { @@ -558,6 +560,23 @@ class StateApp { if(StateHistory.instance.shouldMigrateLegacyHistory()) StateHistory.instance.migrateLegacyHistory(); + + StateAnnouncement.instance.deleteAnnouncement("plugin-update") + + scopeOrNull?.launch(Dispatchers.IO) { + val updateAvailableCount = StatePlatform.instance.checkForUpdates() + + withContext(Dispatchers.Main) { + if (updateAvailableCount > 0) { + StateAnnouncement.instance.registerAnnouncement( + "plugin-update", + "Plugin updates available", + "There are $updateAvailableCount plugin updates available.", + AnnouncementType.SESSION_RECURRING + ) + } + } + } } fun mainAppStartedWithExternalFiles(context: Context) { 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 a9aae85d362404bbc0b6d057e8077d78cce51359..fe06e78d6c41d79c53f03eb8dbdfbf1386d2e4fb 100644 --- a/app/src/main/java/com/futo/platformplayer/states/StatePlatform.kt +++ b/app/src/main/java/com/futo/platformplayer/states/StatePlatform.kt @@ -5,6 +5,7 @@ import androidx.collection.LruCache 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.api.media.IPlatformClient import com.futo.platformplayer.api.media.IPluginSourced import com.futo.platformplayer.api.media.PlatformMultiClientPool @@ -78,6 +79,7 @@ class StatePlatform { private val _clientsLock = Object(); private val _availableClients : ArrayList<IPlatformClient> = ArrayList(); private val _enabledClients : ArrayList<IPlatformClient> = ArrayList(); + private var _updatesAvailableMap: HashSet<String> = hashSetOf(); //ClientPools are used to isolate plugin usage of certain components from others //This prevents for example a background task like subscriptions from blocking a user from opening a video @@ -932,6 +934,67 @@ class StatePlatform { } } + fun hasUpdateAvailable(c: SourcePluginConfig): Boolean { + val updatesAvailableMap = _updatesAvailableMap + synchronized(updatesAvailableMap) { + return updatesAvailableMap.contains(c.id) + } + } + + suspend fun checkForUpdates(): Int = withContext(Dispatchers.IO) { + var updateAvailableCount = 0 + val updatesAvailableFor = hashSetOf<String>() + for (availableClient in getAvailableClients()) { + if (availableClient !is JSClient) { + continue + } + + if (checkForUpdates(availableClient.config)) { + updateAvailableCount++ + updatesAvailableFor.add(availableClient.config.id) + } + } + + _updatesAvailableMap = updatesAvailableFor + return@withContext updateAvailableCount + } + + fun clearUpdateAvailable(c: SourcePluginConfig) { + val updatesAvailableMap = _updatesAvailableMap + synchronized(updatesAvailableMap) { + updatesAvailableMap.remove(c.id) + } + } + + private suspend fun checkForUpdates(c: SourcePluginConfig): Boolean = withContext(Dispatchers.IO) { + val sourceUrl = c.sourceUrl ?: return@withContext false; + + Logger.i(TAG, "Check for source updates '${c.name}'."); + try { + val client = ManagedHttpClient(); + val response = client.get(sourceUrl); + Logger.i(TAG, "Downloading source config '$sourceUrl'."); + + if (!response.isOk || response.body == null) { + return@withContext false; + } + + val configJson = response.body.string(); + Logger.i(TAG, "Downloaded source config ($sourceUrl):\n${configJson}"); + + val config = SourcePluginConfig.fromJson(configJson); + if (config.version <= c.version) { + return@withContext false; + } + + Logger.i(TAG, "Update is available (config.version=${config.version}, source.config.version=${c.version})."); + return@withContext true; + } catch (e: Throwable) { + Logger.e(TAG, "Failed to check for updates.", e); + return@withContext false; + } + } + companion object { private var _instance : StatePlatform? = null; val instance : StatePlatform 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 2f08937d975ffca42c78a5ab7d4a064bc0b46102..34848c1d23b65807eb09942ff29cd88e0dc6f9d6 100644 --- a/app/src/main/java/com/futo/platformplayer/states/StatePlugins.kt +++ b/app/src/main/java/com/futo/platformplayer/states/StatePlugins.kt @@ -10,7 +10,6 @@ import com.futo.platformplayer.api.media.platforms.js.SourceAuth import com.futo.platformplayer.api.media.platforms.js.SourceCaptchaData import com.futo.platformplayer.api.media.platforms.js.SourcePluginConfig import com.futo.platformplayer.api.media.platforms.js.SourcePluginDescriptor -import com.futo.platformplayer.developer.DeveloperEndpoints import com.futo.platformplayer.logging.Logger import com.futo.platformplayer.models.ImageVariable import com.futo.platformplayer.stores.FragmentedStorage @@ -467,7 +466,6 @@ class StatePlugins { _plugins.save(descriptor); } - @Serializable private data class PluginConfig( val SOURCES_EMBEDDED: Map<String, String>, diff --git a/app/src/main/java/com/futo/platformplayer/states/StateUpdate.kt b/app/src/main/java/com/futo/platformplayer/states/StateUpdate.kt index 1a5e4c808aa6881992a1288cac5837adfc75f78f..7a625a1532b67ea92f6df2fb34bd97197d8968b1 100644 --- a/app/src/main/java/com/futo/platformplayer/states/StateUpdate.kt +++ b/app/src/main/java/com/futo/platformplayer/states/StateUpdate.kt @@ -2,15 +2,15 @@ package com.futo.platformplayer.states import android.content.Context import android.os.Build -import android.os.Environment -import com.futo.platformplayer.* +import com.futo.platformplayer.BuildConfig +import com.futo.platformplayer.UIDialogs import com.futo.platformplayer.api.http.ManagedHttpClient +import com.futo.platformplayer.copyToOutputStream import com.futo.platformplayer.logging.Logger import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.io.File -import java.io.FileNotFoundException import java.io.InputStream import java.io.OutputStream @@ -155,47 +155,45 @@ class StateUpdate { } } - fun checkForUpdates(context: Context, showUpToDateToast: Boolean) { - StateApp.instance.scopeOrNull?.launch(Dispatchers.IO) { - try { - val client = ManagedHttpClient(); - val latestVersion = downloadVersionCode(client); + suspend fun checkForUpdates(context: Context, showUpToDateToast: Boolean) = withContext(Dispatchers.IO) { + try { + val client = ManagedHttpClient(); + val latestVersion = downloadVersionCode(client); - if (latestVersion != null) { - val currentVersion = BuildConfig.VERSION_CODE; - Logger.i(TAG, "Current version ${currentVersion} latest version ${latestVersion}."); + if (latestVersion != null) { + val currentVersion = BuildConfig.VERSION_CODE; + Logger.i(TAG, "Current version ${currentVersion} latest version ${latestVersion}."); - if (latestVersion > currentVersion) { - withContext(Dispatchers.Main) { - try { - UIDialogs.showUpdateAvailableDialog(context, latestVersion); - } catch (e: Throwable) { - UIDialogs.toast(context, "Failed to show update dialog"); - Logger.w(TAG, "Error occurred in update dialog."); - } - } - } else { - if (showUpToDateToast) { - withContext(Dispatchers.Main) { - UIDialogs.toast(context, "Already on latest version"); - } + if (latestVersion > currentVersion) { + withContext(Dispatchers.Main) { + try { + UIDialogs.showUpdateAvailableDialog(context, latestVersion); + } catch (e: Throwable) { + UIDialogs.toast(context, "Failed to show update dialog"); + Logger.w(TAG, "Error occurred in update dialog."); } } } else { - Logger.w(TAG, "Failed to retrieve version from version URL."); - - withContext(Dispatchers.Main) { - UIDialogs.toast(context, "Failed to retrieve version"); + if (showUpToDateToast) { + withContext(Dispatchers.Main) { + UIDialogs.toast(context, "Already on latest version"); + } } } - } catch (e: Throwable) { - Logger.w(TAG, "Failed to check for updates.", e); + } else { + Logger.w(TAG, "Failed to retrieve version from version URL."); withContext(Dispatchers.Main) { - UIDialogs.toast(context, "Failed to check for updates"); + UIDialogs.toast(context, "Failed to retrieve version"); } } - }; + } catch (e: Throwable) { + Logger.w(TAG, "Failed to check for updates.", e); + + withContext(Dispatchers.Main) { + UIDialogs.toast(context, "Failed to check for updates"); + } + } } private fun downloadApkToFile(client: ManagedHttpClient, destinationFile: File, isCancelled: (() -> Boolean)? = null) { diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/DisabledSourceAdapter.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/DisabledSourceAdapter.kt deleted file mode 100644 index 4ce526461ee94efc87aec76ce41a689a25ba9811..0000000000000000000000000000000000000000 --- a/app/src/main/java/com/futo/platformplayer/views/adapters/DisabledSourceAdapter.kt +++ /dev/null @@ -1,42 +0,0 @@ -package com.futo.platformplayer.views.adapters - -import android.view.LayoutInflater -import android.view.ViewGroup -import androidx.recyclerview.widget.RecyclerView -import com.futo.platformplayer.R -import com.futo.platformplayer.api.media.IPlatformClient -import com.futo.platformplayer.constructs.Event1 - -class DisabledSourceAdapter : RecyclerView.Adapter<DisabledSourceViewHolder> { - private val _sources: MutableList<IPlatformClient>; - - var onClick = Event1<IPlatformClient>(); - var onAdd = Event1<IPlatformClient>(); - - constructor(sources: MutableList<IPlatformClient>) : super() { - _sources = sources; - } - - override fun getItemCount() = _sources.size - - override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): DisabledSourceViewHolder { - val holder = DisabledSourceViewHolder(viewGroup); - holder.onAdd.subscribe { - val source = holder.source; - if (source != null) { - onAdd.emit(source); - } - } - holder.onClick.subscribe { - val source = holder.source; - if (source != null) { - onClick.emit(source); - } - }; - return holder; - } - - override fun onBindViewHolder(viewHolder: DisabledSourceViewHolder, position: Int) { - viewHolder.bind(_sources[position]) - } -} diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/DisabledSourceView.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/DisabledSourceView.kt index 83cc2d951342f3e3db4c9fb3d37050e17f8122f3..a7194ae73eacfbbc5bdb7aeb20ea21811645d502 100644 --- a/app/src/main/java/com/futo/platformplayer/views/adapters/DisabledSourceView.kt +++ b/app/src/main/java/com/futo/platformplayer/views/adapters/DisabledSourceView.kt @@ -1,17 +1,15 @@ package com.futo.platformplayer.views.adapters import android.content.Context -import android.view.LayoutInflater -import android.view.ViewGroup import android.widget.ImageView import android.widget.LinearLayout import android.widget.TextView -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.Event0 import com.futo.platformplayer.constructs.Event1 +import com.futo.platformplayer.states.StatePlatform class DisabledSourceView : LinearLayout { private val _root: LinearLayout; @@ -38,7 +36,16 @@ class DisabledSourceView : LinearLayout { client.icon?.setImageView(_imageSource); _textSource.text = client.name; - _textSourceSubtitle.text = context.getString(R.string.tap_to_open); + + if (client is JSClient && StatePlatform.instance.hasUpdateAvailable(client.config)) { + _textSourceSubtitle.text = context.getString(R.string.update_available_exclamation) + _textSourceSubtitle.setTextColor(context.getColor(R.color.light_blue_400)) + _textSourceSubtitle.typeface = resources.getFont(R.font.inter_regular) + } else { + _textSourceSubtitle.text = context.getString(R.string.tap_to_open) + _textSourceSubtitle.setTextColor(context.getColor(R.color.gray_ac)) + _textSourceSubtitle.typeface = resources.getFont(R.font.inter_extra_light) + } _buttonAdd.setOnClickListener { onAdd.emit(source) } _root.setOnClickListener { onClick.emit(); }; diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/DisabledSourceViewHolder.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/DisabledSourceViewHolder.kt deleted file mode 100644 index ed55fe62f91d977597331408586f8d2415723452..0000000000000000000000000000000000000000 --- a/app/src/main/java/com/futo/platformplayer/views/adapters/DisabledSourceViewHolder.kt +++ /dev/null @@ -1,44 +0,0 @@ -package com.futo.platformplayer.views.adapters - -import android.view.LayoutInflater -import android.view.ViewGroup -import android.widget.ImageView -import android.widget.LinearLayout -import android.widget.TextView -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.Event0 - -class DisabledSourceViewHolder : ViewHolder { - private val _imageSource: ImageView; - private val _textSource: TextView; - private val _textSourceSubtitle: TextView; - - private val _buttonAdd: LinearLayout; - - var onClick = Event0(); - var onAdd = Event0(); - var source: IPlatformClient? = null - private set - - constructor(viewGroup: ViewGroup) : super(LayoutInflater.from(viewGroup.context).inflate(R.layout.list_source_disabled, viewGroup, false)) { - _imageSource = itemView.findViewById(R.id.image_source); - _textSource = itemView.findViewById(R.id.text_source); - _textSourceSubtitle = itemView.findViewById(R.id.text_source_subtitle); - _buttonAdd = itemView.findViewById(R.id.button_add); - - val root = itemView.findViewById<LinearLayout>(R.id.root); - _buttonAdd.setOnClickListener { onAdd.emit() } - root.setOnClickListener { onClick.emit(); }; - } - - fun bind(client: IPlatformClient) { - client.icon?.setImageView(_imageSource); - - _textSource.text = client.name; - _textSourceSubtitle.text = itemView.context.getString(R.string.tap_to_open); - source = client; - } -} \ No newline at end of file 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 78cb55c439a437ca13a50ff06a22a3be06bbfeda..9eed743bde8ff14cb4c566b821cabce4d2e322c6 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 @@ -10,7 +10,9 @@ 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 +import com.futo.platformplayer.states.StatePlatform class EnabledSourceViewHolder : ViewHolder { private val _imageSource: ImageView; @@ -57,8 +59,18 @@ class EnabledSourceViewHolder : ViewHolder { fun bind(client: IPlatformClient) { client.icon?.setImageView(_imageSource); - _textSource.text = client.name; - _textSourceSubtitle.text = itemView.context.getString(R.string.tap_to_open); + _textSource.text = client.name + + if (client is JSClient && StatePlatform.instance.hasUpdateAvailable(client.config)) { + _textSourceSubtitle.text = itemView.context.getString(R.string.update_available_exclamation) + _textSourceSubtitle.setTextColor(itemView.context.getColor(R.color.light_blue_400)) + _textSourceSubtitle.typeface = itemView.resources.getFont(R.font.inter_regular) + } else { + _textSourceSubtitle.text = itemView.context.getString(R.string.tap_to_open) + _textSourceSubtitle.setTextColor(itemView.context.getColor(R.color.gray_ac)) + _textSourceSubtitle.typeface = itemView.resources.getFont(R.font.inter_extra_light) + } + source = client } } \ No newline at end of file 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 2b0c4e10d9ba8d060be5ac3d02049225777859e3..614f7d069b20b904d73f19cbb79d051ef77fc514 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 @@ -25,6 +25,7 @@ class SourceHeaderView : LinearLayout { private val _sourcePlatformUrl: TextView; private val _sourceRepositoryUrl: TextView; private val _sourceScriptUrl: TextView; + private val _sourceScriptConfig: TextView; private val _sourceSignature: TextView; private val _sourcePlatformUrlContainer: LinearLayout; @@ -45,6 +46,7 @@ class SourceHeaderView : LinearLayout { _sourcePlatformUrl = findViewById(R.id.source_platform); _sourcePlatformUrlContainer = findViewById(R.id.source_platform_container); _sourceScriptUrl = findViewById(R.id.source_script); + _sourceScriptConfig = findViewById(R.id.source_config); _sourceSignature = findViewById(R.id.source_signature); _sourceBy.setOnClickListener { @@ -59,6 +61,10 @@ class SourceHeaderView : LinearLayout { if(!_config?.absoluteScriptUrl.isNullOrEmpty()) context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(_config?.absoluteScriptUrl))); }; + _sourceScriptConfig.setOnClickListener { + if(!_config?.sourceUrl.isNullOrEmpty()) + context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(_config?.sourceUrl))); + } _sourcePlatformUrl.setOnClickListener { if(!_config?.platformUrl.isNullOrEmpty()) context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(_config?.platformUrl))); @@ -82,6 +88,7 @@ class SourceHeaderView : LinearLayout { _sourceVersion.text = config.version.toString(); _sourceScriptUrl.text = config.absoluteScriptUrl; _sourceRepositoryUrl.text = config.repositoryUrl; + _sourceScriptConfig.text = config.sourceUrl _sourceAuthorID.text = ""; _sourcePlatformUrl.text = config.platformUrl ?: ""; diff --git a/app/src/main/res/layout/view_source_header.xml b/app/src/main/res/layout/view_source_header.xml index 2042fa4836be758883e5a88a18efd47689422561..6a62c45b25926657f1b0ffb1d116ee852ef68cc7 100644 --- a/app/src/main/res/layout/view_source_header.xml +++ b/app/src/main/res/layout/view_source_header.xml @@ -170,6 +170,28 @@ tools:text="https://some.repository.url/whatever/someScript.js" /> </LinearLayout> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="14dp" + android:textColor="@color/white" + android:layout_marginTop="10dp" + android:fontFamily="@font/inter_light" + android:text="@string/config_url" /> + <TextView + android:id="@+id/source_config" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textSize="14dp" + android:textColor="@color/colorPrimary" + android:fontFamily="@font/inter_extra_light" + tools:text="https://some.repository.url/whatever/someScript.js" /> + </LinearLayout> + <!--Script Url--> <LinearLayout android:layout_width="match_parent" diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6ae83fe2210b4d717178b0c6f5befcd28e291d02..d4f1b6d18317a8c439090e1263d11fb79a579e03 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -113,6 +113,7 @@ <string name="platform_url">Platform URL</string> <string name="repository_url">Repository URL</string> <string name="script_url">Script URL</string> + <string name="config_url">Config URL</string> <string name="source_permissions_explanation">These are the permissions the plugin requires to function</string> <string name="source_explain_eval_access">The plugin will have access to eval capacity</string> <string name="source_explain_script_url">The plugin will have access to the following domains</string> @@ -651,6 +652,7 @@ <string name="please_use_at_least_3_characters">Please use at least 3 characters</string> <string name="are_you_sure_you_want_to_delete_this_video">Are you sure you want to delete this video?</string> <string name="tap_to_open">Tap to open</string> + <string name="update_available_exclamation">Update available!</string> <string name="watching">watching</string> <string name="available_in">available in</string> <string name="seconds">seconds</string> diff --git a/app/src/stable/assets/sources/odysee b/app/src/stable/assets/sources/odysee index a21ad56829b0f0b45bbd677979f3d260e13abb34..206d996801b9734cae13093859375c70be980a8d 160000 --- a/app/src/stable/assets/sources/odysee +++ b/app/src/stable/assets/sources/odysee @@ -1 +1 @@ -Subproject commit a21ad56829b0f0b45bbd677979f3d260e13abb34 +Subproject commit 206d996801b9734cae13093859375c70be980a8d diff --git a/app/src/unstable/assets/sources/odysee b/app/src/unstable/assets/sources/odysee index a21ad56829b0f0b45bbd677979f3d260e13abb34..206d996801b9734cae13093859375c70be980a8d 160000 --- a/app/src/unstable/assets/sources/odysee +++ b/app/src/unstable/assets/sources/odysee @@ -1 +1 @@ -Subproject commit a21ad56829b0f0b45bbd677979f3d260e13abb34 +Subproject commit 206d996801b9734cae13093859375c70be980a8d