From dd8d50e0e26ae22c60c5ae33ff310aab034cabe0 Mon Sep 17 00:00:00 2001 From: Koen Date: Tue, 5 Dec 2023 15:19:54 +0100 Subject: [PATCH] Added disable polycentric setting. --- .../java/com/futo/platformplayer/Settings.kt | 14 ++- .../mainactivity/main/ChannelFragment.kt | 3 +- .../mainactivity/main/CommentsFragment.kt | 6 ++ .../mainactivity/main/VideoDetailView.kt | 2 +- .../polycentric/PolycentricCache.kt | 20 +++- .../platformplayer/states/StatePolycentric.kt | 92 +++++++++++++------ .../views/adapters/SubscriptionViewHolder.kt | 13 ++- .../adapters/feedtypes/PreviewVideoView.kt | 22 ++--- .../adapters/viewholders/CreatorViewHolder.kt | 8 +- .../viewholders/SubscriptionBarViewHolder.kt | 8 +- app/src/main/res/layout/fragment_comments.xml | 24 ++++- app/src/main/res/values/strings.xml | 4 + 12 files changed, 150 insertions(+), 66 deletions(-) diff --git a/app/src/main/java/com/futo/platformplayer/Settings.kt b/app/src/main/java/com/futo/platformplayer/Settings.kt index db6bfd52..5fd9a052 100644 --- a/app/src/main/java/com/futo/platformplayer/Settings.kt +++ b/app/src/main/java/com/futo/platformplayer/Settings.kt @@ -30,7 +30,6 @@ import kotlinx.serialization.* import kotlinx.serialization.json.* import java.io.File import java.time.OffsetDateTime -import java.util.Locale @Serializable data class MenuBottomBarSetting(val id: Int, var enabled: Boolean); @@ -49,10 +48,14 @@ class Settings : FragmentedStorageFileJson() { @FormFieldButton(R.drawable.ic_person) fun managePolycentricIdentity() { SettingsActivity.getActivity()?.let { - if (StatePolycentric.instance.processHandle != null) { - it.startActivity(Intent(it, PolycentricProfileActivity::class.java)); + if (StatePolycentric.instance.enabled) { + if (StatePolycentric.instance.processHandle != null) { + it.startActivity(Intent(it, PolycentricProfileActivity::class.java)); + } else { + it.startActivity(Intent(it, PolycentricHomeActivity::class.java)); + } } else { - it.startActivity(Intent(it, PolycentricHomeActivity::class.java)); + UIDialogs.toast(it, "Polycentric is disabled") } } } @@ -754,6 +757,9 @@ class Settings : FragmentedStorageFileJson() { @FormField(R.string.bypass_rotation_prevention, FieldForm.TOGGLE, R.string.bypass_rotation_prevention_description, 1) @FormFieldWarning(R.string.bypass_rotation_prevention_warning) var bypassRotationPrevention: Boolean = false; + + @FormField(R.string.enable_polycentric, FieldForm.TOGGLE, R.string.can_be_disabled_when_you_are_experiencing_issues, 1) + var polycentricEnabled: Boolean = true; } @FormField(R.string.info, FieldForm.GROUP, -1, 19) 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 743648ef..a1d1ed9f 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 @@ -437,11 +437,12 @@ class ChannelFragment : MainFragment() { } private fun setPolycentricProfileOr(url: String, or: () -> Unit) { + setPolycentricProfile(null, animate = false); + val cachedProfile = channel?.let { PolycentricCache.instance.getCachedProfile(it.url) }; if (cachedProfile != null) { setPolycentricProfile(cachedProfile, animate = false); } else { - setPolycentricProfile(null, animate = false); or(); } } diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/CommentsFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/CommentsFragment.kt index 8e03e4e4..c81ac8de 100644 --- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/CommentsFragment.kt +++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/CommentsFragment.kt @@ -81,6 +81,7 @@ class CommentsFragment : MainFragment() { private val _llmReplies: LinearLayoutManager; private val _spinnerSortBy: Spinner; private val _layoutNotLoggedIn: LinearLayout; + private val _layoutPolycentricNotEnabled: LinearLayout; private val _buttonLogin: LinearLayout; private var _loading = false; private val _repliesOverlay: RepliesOverlay; @@ -146,6 +147,9 @@ class CommentsFragment : MainFragment() { _layoutNotLoggedIn = findViewById(R.id.layout_not_logged_in) _layoutNotLoggedIn.visibility = View.GONE + _layoutPolycentricNotEnabled = findViewById(R.id.layout_polycentric_disabled) + _layoutPolycentricNotEnabled.visibility = if (!StatePolycentric.instance.enabled) View.VISIBLE else View.GONE + _buttonLogin = findViewById(R.id.button_login) _buttonLogin.setOnClickListener { context.startActivity(Intent(context, PolycentricHomeActivity::class.java)); @@ -302,6 +306,8 @@ class CommentsFragment : MainFragment() { } fun onShown() { + _layoutPolycentricNotEnabled.visibility = if (!StatePolycentric.instance.enabled) View.VISIBLE else View.GONE + val processHandle = StatePolycentric.instance.processHandle if (processHandle != null) { _layoutNotLoggedIn.visibility = View.GONE 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 c65cffa2..3fb8cfd0 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 @@ -1117,7 +1117,7 @@ class VideoDetailView : ConstraintLayout { _player.setMetadata(video.name, video.author.name); - _toggleCommentType.setValue(Settings.instance.comments.defaultCommentSection == 1, false); + _toggleCommentType.setValue(!Settings.instance.other.polycentricEnabled || Settings.instance.comments.defaultCommentSection == 1, false); updateCommentType(true); //UI 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 2a4bb4b4..08a3f3da 100644 --- a/app/src/main/java/com/futo/platformplayer/polycentric/PolycentricCache.kt +++ b/app/src/main/java/com/futo/platformplayer/polycentric/PolycentricCache.kt @@ -9,6 +9,7 @@ import com.futo.platformplayer.getNowDiffSeconds import com.futo.platformplayer.logging.Logger import com.futo.platformplayer.resolveChannelUrls 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.google.protobuf.ByteString @@ -143,7 +144,7 @@ class PolycentricCache { { _, _ -> }); fun getCachedValidClaims(id: PlatformID, ignoreExpired: Boolean = false): CachedOwnedClaims? { - if (id.claimType <= 0) { + if (!StatePolycentric.instance.enabled || id.claimType <= 0) { return CachedOwnedClaims(null); } @@ -163,7 +164,7 @@ class PolycentricCache { //TODO: Review all return null in this file, perhaps it should be CachedX(null) instead fun getValidClaimsAsync(id: PlatformID): Deferred { - if (id.value == null || id.claimType <= 0) { + if (!StatePolycentric.instance.enabled || id.value == null || id.claimType <= 0) { return _scope.async { CachedOwnedClaims(null) }; } @@ -185,10 +186,15 @@ class PolycentricCache { } fun getDataAsync(url: String): Deferred { + StatePolycentric.instance.ensureEnabled() return _batchTaskGetData.execute(url); } fun getCachedProfile(url: String, ignoreExpired: Boolean = false): CachedPolycentricProfile? { + if (!StatePolycentric.instance.enabled) { + return CachedPolycentricProfile(null) + } + synchronized (_profileCache) { val cached = _profileUrlCache.get(url) ?: return null; if (!ignoreExpired && cached.expired) { @@ -200,6 +206,10 @@ class PolycentricCache { } fun getCachedProfile(system: PublicKey, ignoreExpired: Boolean = false): CachedPolycentricProfile? { + if (!StatePolycentric.instance.enabled) { + return CachedPolycentricProfile(null) + } + synchronized(_profileCache) { val cached = _profileCache[system] ?: return null; if (!ignoreExpired && cached.expired) { @@ -211,7 +221,7 @@ class PolycentricCache { } suspend fun getProfileAsync(id: PlatformID): CachedPolycentricProfile? { - if (id.claimType <= 0) { + if (!StatePolycentric.instance.enabled || id.claimType <= 0) { return CachedPolycentricProfile(null); } @@ -237,6 +247,10 @@ class PolycentricCache { } fun getProfileAsync(system: PublicKey): Deferred { + if (!StatePolycentric.instance.enabled) { + return _scope.async { CachedPolycentricProfile(null) }; + } + Logger.i(TAG, "getProfileAsync (system: ${system})") val def = _taskGetProfile.execute(system); def.invokeOnCompletion { diff --git a/app/src/main/java/com/futo/platformplayer/states/StatePolycentric.kt b/app/src/main/java/com/futo/platformplayer/states/StatePolycentric.kt index 73468d3f..373835f7 100644 --- a/app/src/main/java/com/futo/platformplayer/states/StatePolycentric.kt +++ b/app/src/main/java/com/futo/platformplayer/states/StatePolycentric.kt @@ -2,6 +2,7 @@ package com.futo.platformplayer.states import android.content.Context import android.content.Intent +import android.util.Log import com.futo.platformplayer.R import com.futo.platformplayer.Settings import com.futo.platformplayer.UIDialogs @@ -35,6 +36,8 @@ import kotlinx.coroutines.async import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext import userpackage.Protocol +import java.lang.Exception +import java.lang.Thread.State import java.time.Instant import java.time.OffsetDateTime import java.time.ZoneOffset @@ -45,23 +48,47 @@ class StatePolycentric { var processHandle: ProcessHandle? = null; private set; private var _likeDislikeMap = hashMapOf() private val _activeProcessHandle = FragmentedStorage.get("activeProcessHandle"); + private var _transientEnabled = true + val enabled = _transientEnabled && Settings.instance.other.polycentricEnabled fun load(context: Context) { - val db = SqlLiteDbHelper(context); - Store.initializeSqlLiteStore(db); + if (!enabled) { + return + } - val activeProcessHandleString = _activeProcessHandle.value; - if (activeProcessHandleString.isNotEmpty()) { - val system = PublicKey.fromProto(Protocol.PublicKey.parseFrom(activeProcessHandleString.base64ToByteArray())); - setProcessHandle(Store.instance.getProcessSecret(system)?.toProcessHandle()); + try { + val db = SqlLiteDbHelper(context); + Store.initializeSqlLiteStore(db); + + val activeProcessHandleString = _activeProcessHandle.value; + if (activeProcessHandleString.isNotEmpty()) { + val system = + PublicKey.fromProto(Protocol.PublicKey.parseFrom(activeProcessHandleString.base64ToByteArray())); + setProcessHandle(Store.instance.getProcessSecret(system)?.toProcessHandle()); + } + } catch (e: Throwable) { + _transientEnabled = false + UIDialogs.toast(context, "Polycentric failed to initialize.") + Log.i(TAG, "Failed to initialize Polycentric.", e) + } + } + + fun ensureEnabled() { + if (!enabled) { + throw Exception("Cannot set process handle when Polycentric is disdabled") } } fun getProcessHandles(): List { + if (!enabled) { + return listOf() + } + return Store.instance.getProcessSecrets().map { it.toProcessHandle(); }; } fun setProcessHandle(processHandle: ProcessHandle?) { + ensureEnabled() this.processHandle = processHandle; if (processHandle != null) { @@ -91,20 +118,34 @@ class StatePolycentric { } fun updateLikeMap(ref: Protocol.Reference, hasLiked: Boolean, hasDisliked: Boolean) { + ensureEnabled() _likeDislikeMap[ref.toByteArray().toBase64()] = LikeDislikeEntry(System.currentTimeMillis(), hasLiked, hasDisliked); } fun hasDisliked(ref: Protocol.Reference): Boolean { + if (!enabled) { + return false + } + val entry = _likeDislikeMap[ref.toByteArray().toBase64()] ?: return false; return entry.hasDisliked; } fun hasLiked(ref: Protocol.Reference): Boolean { + if (!enabled) { + return false + } + val entry = _likeDislikeMap[ref.toByteArray().toBase64()] ?: return false; return entry.hasLiked; } fun requireLogin(context: Context, text: String, action: (processHandle: ProcessHandle) -> Unit) { + if (!enabled) { + UIDialogs.toast(context, "Polycentric is disabled") + return + } + val p = processHandle; if (p == null) { Logger.i(TAG, "requireLogin preventPictureInPicture.emit()"); @@ -122,24 +163,10 @@ class StatePolycentric { } } - fun getChannelContent(profile: PolycentricProfile, isSubscriptionOptimized: Boolean = false, channelConcurrency: Int = -1, ignorePlugins: List? = null): IPager { - //TODO: Currently abusing subscription concurrency for parallelism - val concurrency = if (channelConcurrency == -1) Settings.instance.subscriptions.getSubscriptionsConcurrency() else channelConcurrency; - val pagers = profile.ownedClaims.groupBy { it.claim.claimType }.mapNotNull { - val url = it.value.firstOrNull()?.claim?.resolveChannelUrl() ?: return@mapNotNull null; - if (!StatePlatform.instance.hasEnabledChannelClient(url)) { - return@mapNotNull null; - } - - return@mapNotNull StatePlatform.instance.getChannelContent(url, isSubscriptionOptimized, concurrency, ignorePlugins); - }.toTypedArray(); - - val pager = MultiChronoContentPager(pagers); - pager.initialize(); - return DedupContentPager(pager, StatePlatform.instance.getEnabledClients().map { it.id }); - } - fun getChannelUrls(url: String, channelId: PlatformID? = null, cacheOnly: Boolean = false): List { + if (!enabled) { + return listOf(url); + } var polycentricProfile: PolycentricProfile? = null; try { @@ -167,7 +194,10 @@ class StatePolycentric { else return listOf(url); } + fun getChannelContent(scope: CoroutineScope, profile: PolycentricProfile, isSubscriptionOptimized: Boolean = false, channelConcurrency: Int = -1): IPager? { + ensureEnabled() + //TODO: Currently abusing subscription concurrency for parallelism val concurrency = if (channelConcurrency == -1) Settings.instance.subscriptions.getSubscriptionsConcurrency() else channelConcurrency; val deferred = profile.ownedClaims.groupBy { it.claim.claimType } @@ -207,13 +237,11 @@ class StatePolycentric { StatePlatform.instance.getEnabledClients().map { it.id } );*/ } - suspend fun getChannelContent(profile: PolycentricProfile): IPager { - return withContext(Dispatchers.IO) { - getChannelContent(this, profile) ?: EmptyPager(); - } - } - fun getSystemComments(context: Context, system: PublicKey): List { + if (!enabled) { + return listOf() + } + val dp_25 = 25.dp(context.resources) val systemState = SystemState.fromStorageTypeSystemState(Store.instance.getSystemState(system)) val author = system.systemToURLInfoSystemLinkUrl(systemState.servers.asIterable()) @@ -249,6 +277,8 @@ class StatePolycentric { ) suspend fun getLikesDislikesReplies(reference: Protocol.Reference): LikesDislikesReplies { + ensureEnabled() + val response = ApiMethods.getQueryReferences(PolycentricCache.SERVER, reference, null, null, listOf( @@ -275,6 +305,10 @@ class StatePolycentric { } suspend fun getCommentPager(contextUrl: String, reference: Protocol.Reference): IPager { + if (!enabled) { + return EmptyPager() + } + val response = ApiMethods.getQueryReferences(PolycentricCache.SERVER, reference, null, Protocol.QueryReferencesRequestEvents.newBuilder() .setFromType(ContentType.POST.value) diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/SubscriptionViewHolder.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/SubscriptionViewHolder.kt index 62918eed..8a28c260 100644 --- a/app/src/main/java/com/futo/platformplayer/views/adapters/SubscriptionViewHolder.kt +++ b/app/src/main/java/com/futo/platformplayer/views/adapters/SubscriptionViewHolder.kt @@ -81,20 +81,19 @@ class SubscriptionViewHolder : ViewHolder { this.subscription = sub; + _creatorThumbnail.setThumbnail(sub.channel.thumbnail, false); + _taskLoadProfile.run(sub.channel.id); + _textName.text = sub.channel.name; + bindViewMetrics(sub); + _platformIndicator.setPlatformFromClientID(sub.channel.id.pluginId); + val cachedProfile = PolycentricCache.instance.getCachedProfile(sub.channel.url, true); if (cachedProfile != null) { onProfileLoaded(sub, cachedProfile, false); if (cachedProfile.expired) { _taskLoadProfile.run(sub.channel.id); } - } else { - _creatorThumbnail.setThumbnail(sub.channel.thumbnail, false); - _taskLoadProfile.run(sub.channel.id); - _textName.text = sub.channel.name; - bindViewMetrics(sub); } - - _platformIndicator.setPlatformFromClientID(sub.channel.id.pluginId); } private fun onProfileLoaded(sub: Subscription?, cachedPolycentricProfile: PolycentricCache.CachedPolycentricProfile?, animate: Boolean) { 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 6ddf89c4..565b6113 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 @@ -175,23 +175,23 @@ open class PreviewVideoView : LinearLayout { stopPreview(); + _imageNeopassChannel?.visibility = View.GONE; + _creatorThumbnail?.setThumbnail(content.author.thumbnail, false); + _imageChannel?.let { + Glide.with(_imageChannel) + .load(content.author.thumbnail) + .placeholder(R.drawable.placeholder_channel_thumbnail) + .into(_imageChannel); + } + _taskLoadProfile.run(content.author.id); + _textChannelName.text = content.author.name + val cachedProfile = PolycentricCache.instance.getCachedProfile(content.author.url, true); if (cachedProfile != null) { onProfileLoaded(cachedProfile, false); if (cachedProfile.expired) { _taskLoadProfile.run(content.author.id); } - } else { - _imageNeopassChannel?.visibility = View.GONE; - _creatorThumbnail?.setThumbnail(content.author.thumbnail, false); - _imageChannel?.let { - Glide.with(_imageChannel) - .load(content.author.thumbnail) - .placeholder(R.drawable.placeholder_channel_thumbnail) - .into(_imageChannel); - } - _taskLoadProfile.run(content.author.id); - _textChannelName.text = content.author.name } _imageChannel?.clipToOutline = true; 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 9a59debb..845a179c 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 @@ -65,16 +65,16 @@ class CreatorViewHolder(private val _viewGroup: ViewGroup, private val _tiny: Bo override fun bind(authorLink: PlatformAuthorLink) { _taskLoadProfile.cancel(); + _creatorThumbnail.setThumbnail(authorLink.thumbnail, false); + _taskLoadProfile.run(authorLink.id); + _textName.text = authorLink.name; + val cachedProfile = PolycentricCache.instance.getCachedProfile(authorLink.url, true); if (cachedProfile != null) { onProfileLoaded(cachedProfile, false); if (cachedProfile.expired) { _taskLoadProfile.run(authorLink.id); } - } else { - _creatorThumbnail.setThumbnail(authorLink.thumbnail, false); - _taskLoadProfile.run(authorLink.id); - _textName.text = authorLink.name; } if(authorLink.subscribers == null || (authorLink.subscribers ?: 0) <= 0L) 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 fe2cb7e0..0661b28d 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 @@ -51,16 +51,16 @@ class SubscriptionBarViewHolder(private val _viewGroup: ViewGroup) : AnyAdapter. _channel = subscription.channel; + _creatorThumbnail.setThumbnail(subscription.channel.thumbnail, false); + _taskLoadProfile.run(subscription.channel.id); + _name.text = subscription.channel.name; + val cachedProfile = PolycentricCache.instance.getCachedProfile(subscription.channel.url, true); if (cachedProfile != null) { onProfileLoaded(cachedProfile, false); if (cachedProfile.expired) { _taskLoadProfile.run(subscription.channel.id); } - } else { - _creatorThumbnail.setThumbnail(subscription.channel.thumbnail, false); - _taskLoadProfile.run(subscription.channel.id); - _name.text = subscription.channel.name; } _subscription = subscription; diff --git a/app/src/main/res/layout/fragment_comments.xml b/app/src/main/res/layout/fragment_comments.xml index cbaccaeb..0e49ff19 100644 --- a/app/src/main/res/layout/fragment_comments.xml +++ b/app/src/main/res/layout/fragment_comments.xml @@ -77,7 +77,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 72462219..507a44f9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -356,6 +356,8 @@ Payment Payment Status Bypass Rotation Prevention + Enable Polycentric + Can be disabled when you are experiencing issues Allows for rotation on non-video views.\nWARNING: Not designed for it This may cause unexpected behavior, and is mostly untested. Player @@ -700,6 +702,8 @@ Open the FCast website FCast Website FCast Technical Documentation + Login to view your comments + Polycentric is disabled Recommendations Subscriptions