Compare commits

...

15 Commits

21 changed files with 130 additions and 147 deletions
-3
View File
@@ -1,9 +1,6 @@
[submodule "dep/polycentricandroid"]
path = dep/polycentricandroid
url = ../polycentricandroid.git
[submodule "app/src/playstore/assets/sources/peertube"]
path = app/src/playstore/assets/sources/peertube
url = ../plugins/peertube.git
[submodule "app/src/stable/assets/sources/kick"]
path = app/src/stable/assets/sources/kick
url = ../plugins/kick.git
+10 -10
View File
@@ -151,7 +151,7 @@ dependencies {
//Core
implementation 'androidx.core:core-ktx:1.12.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.10.0'
implementation 'com.google.android.material:material:1.11.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
//Images
@@ -172,15 +172,15 @@ dependencies {
implementation("com.caoccao.javet:javet-android:3.0.2")
//Exoplayer
implementation 'androidx.media3:media3-exoplayer:1.2.0'
implementation 'androidx.media3:media3-exoplayer-dash:1.2.0'
implementation 'androidx.media3:media3-ui:1.2.0'
implementation 'androidx.media3:media3-exoplayer-hls:1.2.0'
implementation 'androidx.media3:media3-exoplayer-rtsp:1.2.0'
implementation 'androidx.media3:media3-exoplayer-smoothstreaming:1.2.0'
implementation 'androidx.media3:media3-transformer:1.2.0'
implementation 'androidx.navigation:navigation-fragment-ktx:2.7.5'
implementation 'androidx.navigation:navigation-ui-ktx:2.7.5'
implementation 'androidx.media3:media3-exoplayer:1.2.1'
implementation 'androidx.media3:media3-exoplayer-dash:1.2.1'
implementation 'androidx.media3:media3-ui:1.2.1'
implementation 'androidx.media3:media3-exoplayer-hls:1.2.1'
implementation 'androidx.media3:media3-exoplayer-rtsp:1.2.1'
implementation 'androidx.media3:media3-exoplayer-smoothstreaming:1.2.1'
implementation 'androidx.media3:media3-transformer:1.2.1'
implementation 'androidx.navigation:navigation-fragment-ktx:2.7.6'
implementation 'androidx.navigation:navigation-ui-ktx:2.7.6'
implementation 'androidx.media:media:1.7.0'
//Other
@@ -686,7 +686,7 @@ class UISlideOverlays {
}
fun showAddToOverlay(video: IPlatformVideo, container: ViewGroup): SlideUpMenuOverlay {
fun showAddToOverlay(video: IPlatformVideo, container: ViewGroup, slideUpMenuOverlayUpdated: (SlideUpMenuOverlay) -> Unit): SlideUpMenuOverlay {
val items = arrayListOf<View>();
@@ -718,10 +718,10 @@ class UISlideOverlays {
val playlistItems = arrayListOf<SlideUpMenuItem>();
playlistItems.add(SlideUpMenuItem(container.context, R.drawable.ic_playlist_add, container.context.getString(R.string.new_playlist), container.context.getString(R.string.add_to_new_playlist), "add_to_new_playlist", {
showCreatePlaylistOverlay(container) {
slideUpMenuOverlayUpdated(showCreatePlaylistOverlay(container) {
val playlist = Playlist(it, arrayListOf(SerializedPlatformVideo.fromVideo(video)));
StatePlaylists.instance.createOrUpdatePlaylist(playlist);
};
});
}, false))
for (playlist in allPlaylists) {
@@ -12,6 +12,7 @@ import android.widget.ScrollView
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import com.futo.platformplayer.R
import com.futo.platformplayer.UIDialogs
@@ -37,8 +38,10 @@ class AddSourceActivity : AppCompatActivity() {
private lateinit var _sourceHeader: SourceHeaderView;
private lateinit var _sourcePermissions: LinearLayout;
private lateinit var _sourceWarnings: LinearLayout;
private lateinit var _sourceWarningsContainer: LinearLayout;
private lateinit var _container: ScrollView;
private lateinit var _loader: ImageView;
@@ -79,6 +82,7 @@ class AddSourceActivity : AppCompatActivity() {
_sourcePermissions = findViewById(R.id.source_permissions);
_sourceWarnings = findViewById(R.id.source_warnings);
_sourceWarningsContainer = findViewById(R.id.container_source_warnings);
_container = findViewById(R.id.configContainer);
_loader = findViewById(R.id.loader);
@@ -203,21 +207,28 @@ class AddSourceActivity : AppCompatActivity() {
val pastelRed = ContextCompat.getColor(this, R.color.pastel_red);
for(warning in config.getWarnings(script))
val warnings = config.getWarnings(script);
for(warning in warnings)
_sourceWarnings.addView(
SourceInfoView(this,
R.drawable.ic_security_pred,
warning.first,
warning.second)
.withDescriptionColor(pastelRed));
_sourceWarningsContainer.isVisible = warnings.isNotEmpty();
setLoading(false);
}
fun install(config: SourcePluginConfig, script: String) {
val isNew = !StatePlatform.instance.getAvailableClients().any { it.id == config.id };
StatePlugins.instance.installPlugin(this, lifecycleScope, config, script) {
if(it) {
StatePlatform.instance.clearUpdateAvailable(config)
if(isNew)
lifecycleScope.launch {
StatePlatform.instance.enableClient(listOf(config.id));
}
backToSources();
}
}
@@ -536,7 +536,15 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
}
};
"BROWSE_PLUGINS" -> {
navigate(_fragBrowser, "https://plugins.grayjay.app");
navigate(_fragBrowser, BrowserFragment.NavigateOptions("https://plugins.grayjay.app/phone.html", mapOf(
Pair("grayjay") { req ->
StateApp.instance.contextOrNull?.let {
if(it is MainActivity) {
it.handleUrlAll(req.url.toString());
}
};
}
)));
}
}
}
@@ -90,6 +90,9 @@ class SourcePluginDescriptor {
@Serializable
class AppPluginSettings {
@FormField(R.string.check_for_updates_setting, FieldForm.TOGGLE, R.string.check_for_updates_setting_description, 1)
var checkForUpdates: Boolean = true;
@FormField(R.string.visibility, "group", R.string.enable_where_this_plugins_content_are_visible, 2)
var tabEnabled = TabEnabled();
@Serializable
@@ -160,11 +160,11 @@ class HomeFragment : MainFragment() {
val pluginsExist = StatePlatform.instance.getAvailableClients().isNotEmpty();
if(StatePlatform.instance.getEnabledClients().isEmpty())
//Initial setup
return NoResultsView(context, "No enabled Sources", if(pluginsExist)
"Enable or install some Sources"
return NoResultsView(context, "No enabled sources", if(pluginsExist)
"Enable or install some sources"
else "This Grayjay version comes without any sources, install sources externally or using the button below.", R.drawable.ic_sources,
listOf(BigButton(context, "Browse Online Sources", "View official sources online", R.drawable.ic_explore) {
fragment.navigate<BrowserFragment>(BrowserFragment.NavigateOptions("https://plugins.grayjay.app/", mapOf(
fragment.navigate<BrowserFragment>(BrowserFragment.NavigateOptions("https://plugins.grayjay.app/phone.html", mapOf(
Pair("grayjay") { req ->
StateApp.instance.contextOrNull?.let {
if(it is MainActivity) {
@@ -315,7 +315,7 @@ class PostDetailFragment : MainFragment {
_rating.visibility = View.GONE;
val ref = Models.referenceFromBuffer((_post?.url ?: _postOverview?.url)?.toByteArray() ?: return)
val extraBytesRef = (_post?.id?.value ?: _postOverview?.id?.value)?.toByteArray()
val extraBytesRef = (_post?.id?.value ?: _postOverview?.id?.value)?.let { if (it.isNotEmpty()) it.toByteArray() else null }
val version = _version;
_rating.onLikeDislikeUpdated.remove(this);
@@ -663,7 +663,7 @@ class PostDetailFragment : MainFragment {
Logger.i(TAG, "fetchPolycentricComments")
val post = _post;
val ref = (_post?.url ?: _postOverview?.url)?.toByteArray()?.let { Models.referenceFromBuffer(it) }
val extraBytesRef = (_post?.id?.value ?: _postOverview?.id?.value)?.toByteArray()
val extraBytesRef = (_post?.id?.value ?: _postOverview?.id?.value)?.let { if (it.isNotEmpty()) it.toByteArray() else null }
if (ref == null) {
Logger.w(TAG, "Failed to fetch polycentric comments because url was not set null")
@@ -8,6 +8,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.core.view.isVisible
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
@@ -25,6 +26,7 @@ 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.buttons.BigButton
import com.futo.platformplayer.views.sources.SourceUnderConstructionView
import kotlinx.coroutines.runBlocking
import java.util.Collections
@@ -86,6 +88,14 @@ class SourcesFragment : MainFragment() {
_containerDisabledViews = findViewById(R.id.container_disabled_views);
_containerConstruction = findViewById(R.id.container_construction);
if(StatePlatform.instance.getAvailableClients().isEmpty()) {
findViewById<LinearLayout>(R.id.no_sources).isVisible = true;
findViewById<LinearLayout>(R.id.plugin_disclaimer).isVisible = false;
}
findViewById<BigButton>(R.id.button_add_sources).onClick.subscribe {
fragment.startActivity(Intent(context, AddSourceOptionsActivity::class.java));
};
for(inConstructSource in StatePlugins.instance.getSourcesUnderConstruction(context))
_containerConstruction.addView(SourceUnderConstructionView(context, inConstructSource.key, inConstructSource.value));
@@ -111,8 +121,6 @@ class SourcesFragment : MainFragment() {
adapterSourcesEnabled.notifyItemMoved(fromPosition, toPosition);
onEnabledChanged(enabledSources);
if(toPosition == 0)
onPrimaryChanged(enabledSources.first());
StatePlatform.instance.setPlatformOrder(enabledSources.map { it.name });
};
@@ -133,8 +141,6 @@ class SourcesFragment : MainFragment() {
updateContainerVisibility();
onEnabledChanged(enabledSources);
if(index == 0)
onPrimaryChanged(enabledSources.first());
if(enabledSources.size <= 1)
setCanRemove(false);
@@ -221,9 +227,6 @@ class SourcesFragment : MainFragment() {
_adapterSourcesEnabled.canRemove = canRemove;
}
private fun onPrimaryChanged(client: IPlatformClient) {
StatePlatform.instance.selectPrimaryClient(client.id);
}
private fun onEnabledChanged(clients: List<IPlatformClient>) {
runBlocking {
StatePlatform.instance.selectClients(*clients.map { it.id }.toTypedArray());
@@ -761,7 +761,9 @@ class VideoDetailView : ConstraintLayout {
fun updateMoreButtons() {
val buttons = listOf(RoundButton(context, R.drawable.ic_add, context.getString(R.string.add), TAG_ADD) {
(video ?: _searchVideo)?.let {
_slideUpOverlay = UISlideOverlays.showAddToOverlay(it, _overlayContainer);
_slideUpOverlay = UISlideOverlays.showAddToOverlay(it, _overlayContainer) {
_slideUpOverlay = it
};
}
},
if(video?.isLive ?: false)
@@ -1228,7 +1230,7 @@ class VideoDetailView : ConstraintLayout {
}
val ref = Models.referenceFromBuffer(video.url.toByteArray())
val extraBytesRef = video.id.value?.toByteArray()
val extraBytesRef = video.id.value?.let { if (it.isNotEmpty()) it.toByteArray() else null }
_addCommentView.setContext(video.url, ref)
_player.setMetadata(video.name, video.author.name);
@@ -1978,14 +1980,14 @@ class VideoDetailView : ConstraintLayout {
Logger.i(TAG, "fetchPolycentricComments")
val video = video;
val idValue = video?.id?.value
if (idValue == null) {
Logger.w(TAG, "Failed to fetch polycentric comments because id was null")
if (video?.url?.isEmpty() != false) {
Logger.w(TAG, "Failed to fetch polycentric comments because url was null")
_commentsList.clear()
return
}
val ref = Models.referenceFromBuffer(video.url.toByteArray())
val extraBytesRef = video.id.value?.toByteArray()
val extraBytesRef = idValue?.let { if (it.isNotEmpty()) it.toByteArray() else null }
_commentsList.load(false) { StatePolycentric.instance.getCommentPager(video.url, ref, listOfNotNull(extraBytesRef)); };
}
private fun fetchVideo() {
@@ -12,7 +12,6 @@ import kotlinx.coroutines.withContext
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import java.time.OffsetDateTime
import java.util.Random
import java.util.UUID
class StateAnnouncement {
@@ -252,41 +251,6 @@ class StateAnnouncement {
}
fun registerDidYouKnow() {
val random = Random();
val message: String? = when (random.nextInt(4 * 18 + 1)) {
0 -> "You can login to different platforms and unify your content experience. Check it out in the source settings!"
1 -> "Importing your playlists and subscriptions from other platforms to Grayjay is quick and easy. Check it out in the source settings!"
2 -> "Want to cast to a big screen? Try out FCast (https://fcast.org/)."
3 -> "Explore Grayjay's gesture controls. When in full-screen swipe on the left to change brightness, swipe on the right to change volume."
4 -> "Explore Grayjay's gesture controls. Swipe up in the center of a video to toggle full-screen."
5 -> "Grayjay's multi-platform search lets you find content from various sources."
6 -> "Grayjay's multi-platform search filters will unify filters across platforms. If your expected filters are not there, try toggling some platforms off in the search filters."
7 -> "You can share playlists with friends on the playlist page and make full-backups in the settings page."
8 -> "Discover Grayjay's offline playback feature. Save content for when you're on the go!"
9 -> "Paid content from your favorite creators gets seamlessly integrated into your Grayjay feed. Login to a platform to seamlessly see content you paid for."
10 -> "Explore Grayjay's plugin features! Login, import playlists, and tweak plugin settings for a tailored experience."
11 -> "Directly engage with content by liking, disliking, or leaving comments on the Polycentric network."
12 -> "With Grayjay's rotation lock, you can watch videos in your preferred orientation regardless of device settings. Check it out during playback!"
13 -> "Grayjay supports background play. Listen to your favorite content even while multitasking!"
14 -> "Use Grayjay's quality selection to adjust video resolution. Save data or watch in high definition it's up to you."
15 -> "Customize your Grayjay experience by changing playback speed. Watch content at your own pace."
16 -> "Save time by adding videos to your 'Watch Later' list. Perfect for catching up on content during your free time."
17 -> "On Grayjay, your playlists, subscriptions, and settings are stored offline for privacy and quick access."
18 -> "Explore and engage with live content using Grayjay's live stream feature."
else -> null
};
if (message != null) {
registerAnnouncement(
"did-you-know?",
"Did you know?",
message,
AnnouncementType.SESSION_RECURRING
);
}
}
fun registerDefaultHandlerAnnouncement() {
registerAnnouncement(
"default-url-handler",
@@ -5,7 +5,6 @@ import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.graphics.Color
import android.media.AudioManager
import android.net.ConnectivityManager
import android.net.Network
@@ -42,7 +41,6 @@ import com.futo.platformplayer.stores.v2.ManagedStore
import com.futo.platformplayer.views.ToastView
import kotlinx.coroutines.*
import java.io.File
import java.time.OffsetDateTime
import java.util.*
import java.util.concurrent.TimeUnit
import kotlin.system.measureTimeMillis
@@ -427,8 +425,6 @@ class StateApp {
}
}
StateAnnouncement.instance.registerAnnouncement("fa4647d3-36fa-4c8c-832d-85b00fc72dca", "Disclaimer", "This is an early alpha build of the application, expect bugs and unfinished features.", AnnouncementType.DELETABLE, OffsetDateTime.now())
if(SettingsDev.instance.developerMode && SettingsDev.instance.devServerSettings.devServerOnBoot)
StateDeveloper.instance.runServer();
@@ -557,7 +553,6 @@ class StateApp {
}
StateAnnouncement.instance.registerDefaultHandlerAnnouncement();
StateAnnouncement.instance.registerDidYouKnow();
Logger.i(TAG, "MainApp Started: Finished");
StatePlaylists.instance.toMigrateCheck();
@@ -580,24 +575,9 @@ class StateApp {
null,
"Plugin updates available"
));
StateAnnouncement.instance.registerAnnouncement(
"plugin-update",
"Plugin updates available",
"There are ${updateAvailable.size} plugin updates available.",
AnnouncementType.SESSION_RECURRING
)
}
}
}
/*
UIDialogs.appToast("This is a test", false);
UIDialogs.appToast("This is a test 2", false);
UIDialogs.appToastError("This is a test 3 (Error)", false);
UIDialogs.appToast(ToastView.Toast("This is a test 4, with title", false, Color.WHITE, "Test title"));
UIDialogs.appToast("This is a test 5 Long text\nWith enters\nasdh asfh fds h rwe h fxh sdfh sdf h dsfh sdf hasdfhsdhg ads as", true);
*/
}
fun mainAppStartedWithExternalFiles(context: Context) {
@@ -94,11 +94,6 @@ class StatePlatform {
private val _liveEventClientPool = PlatformMultiClientPool("LiveEvents", 1); //Used exclusively for live events
private val _primaryClientPersistent = FragmentedStorage.get<StringStorage>("primaryClient");
private var _primaryClientObj : IPlatformClient? = null;
val primaryClient : IPlatformClient get() = _primaryClientObj ?: throw IllegalStateException("PlatformState not yet initialized");
private val _icons : HashMap<String, ImageVariable> = HashMap();
val hasClients: Boolean get() = _availableClients.size > 0;
@@ -207,20 +202,6 @@ class StatePlatform {
.filter { id -> _availableClients.any { it.id == id } }
.toTypedArray();
}
val primary = _primaryClientPersistent.value;
if(primary.isEmpty() || primary == StateDeveloper.DEV_ID) {
selectPrimaryClient(enabled.firstOrNull() ?: _availableClients.first().id);
} else if(!_availableClients.any { it.id == primary }) {
selectPrimaryClient(_availableClients.firstOrNull()?.id!!);
} else {
selectPrimaryClient(primary);
}
if(!enabled.any { it == primaryClient.id }) {
enabled = enabled.concat(primaryClient.id);
}
}
selectClients(*enabled);
};
@@ -323,8 +304,6 @@ class StatePlatform {
newClient.initialize();
_enabledClients.add(newClient);
}
if (_primaryClientObj == client)
_primaryClientObj = newClient;
_availableClients.removeIf { it.id == id };
_availableClients.add(newClient);
@@ -333,6 +312,11 @@ class StatePlatform {
};
}
suspend fun enableClient(ids: List<String>) {
val currentClients = getEnabledClients().map { it.id };
selectClients(*(currentClients + ids).distinct().toTypedArray());
}
/**
* Selects the enabled clients, meaning all clients that data is actively requested from.
* If a client is disabled, NO requests are made to said client
@@ -365,17 +349,6 @@ class StatePlatform {
};
}
/**
* Selects the primary client, meaning the first target for requests.
* At the moment, since multi-client requests are not yet implemented, this is the goto client.
*/
fun selectPrimaryClient(id: String) {
synchronized(_clientsLock) {
_primaryClientObj = getClient(id);
_primaryClientPersistent.setAndSave(id);
}
}
fun getHome(): IPager<IPlatformContent> {
Logger.i(TAG, "Platform - getHome");
var clientIdsOngoing = mutableListOf<String>();
@@ -448,14 +421,12 @@ class StatePlatform {
toAwait.map { PlaceholderPager(5, { PlatformContentPlaceholder(it.first.id) }) });
}
fun getHomePrimary(): IPager<IPlatformContent> {
return primaryClient.getHome();
}
//Search
fun searchSuggestions(query: String): Array<String> {
Logger.i(TAG, "Platform - searchSuggestions");
return primaryClient.searchSuggestions(query);
//TODO: hasSearchSuggestions
return getEnabledClients().firstOrNull()?.searchSuggestions(query) ?: arrayOf();
}
fun search(query: String, type: String? = null, sort: String? = null, filters: Map<String, List<String>> = mapOf(), clientIds: List<String>? = null): IPager<IPlatformContent> {
@@ -887,7 +858,6 @@ class StatePlatform {
synchronized(_clientsLock) {
val enabledExisting = _enabledClients.filter { it is DevJSClient };
val isEnabled = !enabledExisting.isEmpty()
val isPrimary = _primaryClientObj is DevJSClient;
for (enabled in enabledExisting) {
enabled.disable();
@@ -902,11 +872,7 @@ class StatePlatform {
devId = newClient.devID;
try {
StateDeveloper.instance.initializeDev(devId!!);
if (isPrimary) {
_primaryClientObj = newClient;
_enabledClients.add(0, newClient);
newClient.initialize();
} else if (isEnabled) {
if (isEnabled) {
_enabledClients.add(newClient);
newClient.initialize();
}
@@ -945,7 +911,7 @@ class StatePlatform {
suspend fun checkForUpdates(): List<SourcePluginConfig> = withContext(Dispatchers.IO) {
var configs = mutableListOf<SourcePluginConfig>()
val updatesAvailableFor = hashSetOf<String>()
for (availableClient in getAvailableClients()) {
for (availableClient in getAvailableClients().filter { it is JSClient && it.descriptor.appSettings.checkForUpdates }) {
if (availableClient !is JSClient) {
continue
}
@@ -388,8 +388,8 @@ class GestureControlView : LinearLayout {
return Math.max(width / w, height / h)
}
private val _snapTranslationTolerance = 0.04f;
private val _snapZoomTolerance = 0.04f;
private val _snapTranslationTolerance = 0.1f;
private val _snapZoomTolerance = 0.1f;
private fun willSnapFill(): Boolean {
val surfaceView = _surfaceView
@@ -110,6 +110,7 @@
<!--Security Warnings-->
<LinearLayout
android:id="@+id/container_source_warnings"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
@@ -128,13 +128,17 @@
tools:text="(7 playlists, 85 videos)"
/>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:id="@+id/downloads_playlist_list"
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!--Fill Programmatically-->
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:id="@+id/downloads_playlist_list"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<!--Fill Programmatically-->
</LinearLayout>
</HorizontalScrollView>
</LinearLayout>
<!--Videos-->
@@ -17,6 +17,40 @@
android:orientation="vertical"
android:paddingStart="20dp"
android:paddingEnd="20dp">
<LinearLayout
android:id="@+id/no_sources"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/ic_error"
app:tint="#FFF" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#FFF"
android:textSize="12dp"
android:fontFamily="@font/inter_light"
android:text="@string/no_sources_installed"
android:layout_gravity="center"
android:layout_marginStart="8dp"/>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/container_enabled"
android:layout_width="match_parent"
@@ -91,6 +125,7 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/plugin_disclaimer"
android:orientation="horizontal"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp">
@@ -113,6 +148,15 @@
</LinearLayout>
<com.futo.platformplayer.views.buttons.BigButton
android:id="@+id/button_add_sources"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:buttonIcon="@drawable/ic_explore"
app:buttonText="Add Sources"
app:buttonSubText="Install new sources to see more content."
/>
</LinearLayout>
</ScrollView>
+3
View File
@@ -214,6 +214,7 @@
<string name="videos">Videos</string>
<string name="clear_history">Clear history</string>
<string name="nothing_to_import">Nothing to import</string>
<string name="no_sources_installed">You have no sources installed, please add sources to use the app as intended.</string>
<string name="enabling_lots_of_sources_can_reduce_the_loading_speed_of_your_application">Enabling lots of sources can reduce the loading speed of your application.</string>
<string name="support">Support</string>
<string name="membership">Membership</string>
@@ -484,6 +485,8 @@
<string name="various_tests_against_a_custom_source">Various tests against a custom source</string>
<string name="writes_to_disk_till_no_space_is_left">Writes to disk till no space is left</string>
<string name="visibility">Visibility</string>
<string name="check_for_updates_setting">Check for updates</string>
<string name="check_for_updates_setting_description">If a plugin should be checked for updates on startup</string>
<string name="ratelimit">Rate-limit</string>
<string name="ratelimit_description">Settings related to rate-limiting this plugin\'s behavior</string>
<string name="ratelimit_sub_setting">Rate-limit Subscriptions</string>
+2 -4
View File
@@ -1,7 +1,5 @@
{
"SOURCES_EMBEDDED": {
"1c291164-294c-4c2d-800d-7bc6d31d0019": "sources/peertube/PeerTubeConfig.json"
},
"SOURCES_EMBEDDED_DEFAULT": ["1c291164-294c-4c2d-800d-7bc6d31d0019"],
"SOURCES_EMBEDDED": {},
"SOURCES_EMBEDDED_DEFAULT": [],
"SOURCES_UNDER_CONSTRUCTION": {}
}
+1 -1
View File
@@ -1,7 +1,7 @@
#!/bin/bash
# Array of directories to look in
dirs=("app/src/unstable/assets/sources" "app/src/stable/assets/sources" "app/src/playstore/assets/sources")
dirs=("app/src/unstable/assets/sources" "app/src/stable/assets/sources")
# Loop through each directory
for dir in "${dirs[@]}"; do