mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-09-17 06:52:27 +00:00
Fixes to Polycentric data display.
This commit is contained in:
parent
8241863170
commit
d6c4b730de
14 changed files with 272 additions and 120 deletions
|
@ -35,4 +35,8 @@ fun Protocol.ImageBundle?.selectHighestResolutionImage(): Protocol.ImageManifest
|
||||||
|
|
||||||
fun Protocol.Claim.resolveChannelUrl(): String? {
|
fun Protocol.Claim.resolveChannelUrl(): String? {
|
||||||
return StatePlatform.instance.resolveChannelUrlByClaimTemplates(this.claimType.toInt(), this.claimFieldsList.associate { Pair(it.key.toInt(), it.value) })
|
return StatePlatform.instance.resolveChannelUrlByClaimTemplates(this.claimType.toInt(), this.claimFieldsList.associate { Pair(it.key.toInt(), it.value) })
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Protocol.Claim.resolveChannelUrls(): List<String> {
|
||||||
|
return StatePlatform.instance.resolveChannelUrlsByClaimTemplates(this.claimType.toInt(), this.claimFieldsList.associate { Pair(it.key.toInt(), it.value) })
|
||||||
}
|
}
|
|
@ -568,6 +568,23 @@ open class JSClient : IPlatformClient {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun resolveChannelUrlsByClaimTemplates(claimType: Int, values: Map<Int, String>): List<String> {
|
||||||
|
val urls = arrayListOf<String>();
|
||||||
|
channelClaimTemplates?.let {
|
||||||
|
if(it.containsKey(claimType)) {
|
||||||
|
val templates = it[claimType];
|
||||||
|
if(templates != null)
|
||||||
|
for(value in values.keys.sortedBy { it }) {
|
||||||
|
if(templates.containsKey(value)) {
|
||||||
|
urls.add(templates[value]!!.replace("{{CLAIMVALUE}}", values[value]!!));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return urls;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun <T> isBusyWith(handle: ()->T): T {
|
private fun <T> isBusyWith(handle: ()->T): T {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -246,28 +246,45 @@ class ChannelFragment : MainFragment() {
|
||||||
|
|
||||||
if (parameter is String) {
|
if (parameter is String) {
|
||||||
_buttonSubscribe.setSubscribeChannel(parameter);
|
_buttonSubscribe.setSubscribeChannel(parameter);
|
||||||
_textChannel.text = "";
|
setPolycentricProfileOr(parameter) {
|
||||||
_textChannelSub.text = "";
|
_textChannel.text = "";
|
||||||
|
_textChannelSub.text = "";
|
||||||
|
_creatorThumbnail.setThumbnail(null, true);
|
||||||
|
Glide.with(_imageBanner)
|
||||||
|
.clear(_imageBanner);
|
||||||
|
};
|
||||||
|
|
||||||
_url = parameter;
|
_url = parameter;
|
||||||
loadChannel();
|
loadChannel();
|
||||||
} else if (parameter is SerializedChannel) {
|
} else if (parameter is SerializedChannel) {
|
||||||
showChannel(parameter);
|
showChannel(parameter);
|
||||||
_url = parameter.url;
|
_url = parameter.url;
|
||||||
_creatorThumbnail.setThumbnail(parameter.url, false);
|
|
||||||
loadChannel();
|
loadChannel();
|
||||||
} else if (parameter is IPlatformChannel)
|
} else if (parameter is IPlatformChannel)
|
||||||
showChannel(parameter);
|
showChannel(parameter);
|
||||||
else if (parameter is PlatformAuthorLink) {
|
else if (parameter is PlatformAuthorLink) {
|
||||||
_textChannel.text = parameter.name;
|
setPolycentricProfileOr(parameter.url) {
|
||||||
_textChannelSub.text = "";
|
_textChannel.text = parameter.name;
|
||||||
_creatorThumbnail.setThumbnail(parameter.url, false);
|
_textChannelSub.text = "";
|
||||||
|
_creatorThumbnail.setThumbnail(parameter.thumbnail, true);
|
||||||
|
Glide.with(_imageBanner)
|
||||||
|
.clear(_imageBanner);
|
||||||
|
|
||||||
|
_taskLoadPolycentricProfile.run(parameter.id);
|
||||||
|
};
|
||||||
|
|
||||||
_url = parameter.url;
|
_url = parameter.url;
|
||||||
loadChannel();
|
loadChannel();
|
||||||
} else if (parameter is Subscription) {
|
} else if (parameter is Subscription) {
|
||||||
_textChannel.text = parameter.channel.name;
|
setPolycentricProfileOr(parameter.channel.url) {
|
||||||
_textChannelSub.text = "";
|
_textChannel.text = parameter.channel.name;
|
||||||
_creatorThumbnail.setThumbnail(parameter.channel.thumbnail, false);
|
_textChannelSub.text = "";
|
||||||
|
_creatorThumbnail.setThumbnail(parameter.channel.thumbnail, true);
|
||||||
|
Glide.with(_imageBanner)
|
||||||
|
.clear(_imageBanner);
|
||||||
|
|
||||||
|
_taskLoadPolycentricProfile.run(parameter.channel.id);
|
||||||
|
};
|
||||||
|
|
||||||
_url = parameter.channel.url;
|
_url = parameter.channel.url;
|
||||||
loadChannel();
|
loadChannel();
|
||||||
|
@ -360,15 +377,8 @@ class ChannelFragment : MainFragment() {
|
||||||
_fragment.topBar?.assume<NavigationTopBarFragment>()?.setMenuItems(buttons);
|
_fragment.topBar?.assume<NavigationTopBarFragment>()?.setMenuItems(buttons);
|
||||||
|
|
||||||
_buttonSubscribe.setSubscribeChannel(channel);
|
_buttonSubscribe.setSubscribeChannel(channel);
|
||||||
_textChannel.text = channel.name;
|
|
||||||
_textChannelSub.text = if(channel.subscribers > 0) "${channel.subscribers.toHumanNumber()} subscribers" else "";
|
_textChannelSub.text = if(channel.subscribers > 0) "${channel.subscribers.toHumanNumber()} subscribers" else "";
|
||||||
|
|
||||||
_creatorThumbnail.setThumbnail(channel.thumbnail, true);
|
|
||||||
Glide.with(_imageBanner)
|
|
||||||
.load(channel.banner)
|
|
||||||
.crossfade()
|
|
||||||
.into(_imageBanner)
|
|
||||||
|
|
||||||
//TODO: Find a better way to access the adapter fragments..
|
//TODO: Find a better way to access the adapter fragments..
|
||||||
|
|
||||||
(_viewPager.adapter as ChannelViewPagerAdapter?)?.let {
|
(_viewPager.adapter as ChannelViewPagerAdapter?)?.let {
|
||||||
|
@ -381,51 +391,68 @@ class ChannelFragment : MainFragment() {
|
||||||
|
|
||||||
this.channel = channel;
|
this.channel = channel;
|
||||||
|
|
||||||
val cachedProfile = PolycentricCache.instance.getCachedProfile(channel.url);
|
setPolycentricProfileOr(channel.url) {
|
||||||
|
_textChannel.text = channel.name;
|
||||||
|
_creatorThumbnail.setThumbnail(channel.thumbnail, true);
|
||||||
|
Glide.with(_imageBanner)
|
||||||
|
.load(channel.banner)
|
||||||
|
.crossfade()
|
||||||
|
.into(_imageBanner);
|
||||||
|
|
||||||
|
_taskLoadPolycentricProfile.run(channel.id);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setPolycentricProfileOr(url: String, or: () -> Unit) {
|
||||||
|
val cachedProfile = channel?.let { PolycentricCache.instance.getCachedProfile(it.url) };
|
||||||
if (cachedProfile != null) {
|
if (cachedProfile != null) {
|
||||||
setPolycentricProfile(cachedProfile, animate = false);
|
setPolycentricProfile(cachedProfile, animate = false);
|
||||||
} else {
|
} else {
|
||||||
setPolycentricProfile(null, animate = false);
|
setPolycentricProfile(null, animate = false);
|
||||||
_taskLoadPolycentricProfile.run(channel.id);
|
or();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setPolycentricProfile(cachedPolycentricProfile: PolycentricCache.CachedPolycentricProfile?, animate: Boolean) {
|
private fun setPolycentricProfile(cachedPolycentricProfile: PolycentricCache.CachedPolycentricProfile?, animate: Boolean) {
|
||||||
Log.i(TAG, "setPolycentricProfile(cachedPolycentricProfile = $cachedPolycentricProfile, animate = $animate)")
|
Log.i(TAG, "setPolycentricProfile(cachedPolycentricProfile = $cachedPolycentricProfile, animate = $animate)")
|
||||||
|
|
||||||
val polycentricProfile = cachedPolycentricProfile?.profile;
|
val dp_35 = 35.dp(resources)
|
||||||
if (polycentricProfile != null) {
|
val profile = cachedPolycentricProfile?.profile;
|
||||||
_fragment.topBar?.onShown(polycentricProfile);
|
val avatar = profile?.systemState?.avatar?.selectBestImage(dp_35 * dp_35)
|
||||||
|
?.let { it.toURLInfoSystemLinkUrl(profile.system.toProto(), it.process, profile.systemState.servers.toList()) };
|
||||||
|
|
||||||
if (polycentricProfile.systemState.username.isNotBlank())
|
if (avatar != null) {
|
||||||
_textChannel.text = polycentricProfile.systemState.username;
|
_creatorThumbnail.setThumbnail(avatar, animate);
|
||||||
|
} else {
|
||||||
|
_creatorThumbnail.setThumbnail(channel?.thumbnail, animate);
|
||||||
|
_creatorThumbnail.setHarborAvailable(profile != null, animate);
|
||||||
|
}
|
||||||
|
|
||||||
val dp_35 = 35.dp(resources)
|
val banner = profile?.systemState?.banner?.selectHighestResolutionImage()
|
||||||
val avatar = polycentricProfile.systemState.avatar?.selectBestImage(dp_35 * dp_35)
|
?.let { it.toURLInfoSystemLinkUrl(profile.system.toProto(), it.process, profile.systemState.servers.toList()) };
|
||||||
?.let { it.toURLInfoSystemLinkUrl(polycentricProfile.system.toProto(), it.process, polycentricProfile.systemState.servers.toList()) };
|
|
||||||
|
|
||||||
if (avatar != null) {
|
if (banner != null) {
|
||||||
_creatorThumbnail.setThumbnail(avatar, true);
|
Glide.with(_imageBanner)
|
||||||
} else {
|
.load(banner)
|
||||||
_creatorThumbnail.setHarborAvailable(true, true);
|
.crossfade()
|
||||||
}
|
.into(_imageBanner);
|
||||||
|
} else {
|
||||||
|
Glide.with(_imageBanner)
|
||||||
|
.load(channel?.banner)
|
||||||
|
.crossfade()
|
||||||
|
.into(_imageBanner);
|
||||||
|
}
|
||||||
|
|
||||||
val banner = polycentricProfile.systemState.banner?.selectHighestResolutionImage()
|
if (profile != null) {
|
||||||
?.let { it.toURLInfoSystemLinkUrl(polycentricProfile.system.toProto(), it.process, polycentricProfile.systemState.servers.toList()) };
|
_fragment.topBar?.onShown(profile);
|
||||||
|
_textChannel.text = profile.systemState.username;
|
||||||
if (banner != null) {
|
|
||||||
Glide.with(_imageBanner)
|
|
||||||
.load(banner)
|
|
||||||
.crossfade()
|
|
||||||
.into(_imageBanner);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
(_viewPager.adapter as ChannelViewPagerAdapter?)?.let {
|
(_viewPager.adapter as ChannelViewPagerAdapter?)?.let {
|
||||||
it.getFragment<ChannelAboutFragment>().setPolycentricProfile(polycentricProfile, animate);
|
it.getFragment<ChannelAboutFragment>().setPolycentricProfile(profile, animate);
|
||||||
it.getFragment<ChannelMonetizationFragment>().setPolycentricProfile(polycentricProfile, animate);
|
it.getFragment<ChannelMonetizationFragment>().setPolycentricProfile(profile, animate);
|
||||||
it.getFragment<ChannelListFragment>().setPolycentricProfile(polycentricProfile, animate);
|
it.getFragment<ChannelListFragment>().setPolycentricProfile(profile, animate);
|
||||||
it.getFragment<ChannelContentsFragment>().setPolycentricProfile(polycentricProfile, animate);
|
it.getFragment<ChannelContentsFragment>().setPolycentricProfile(profile, animate);
|
||||||
//TODO: Call on other tabs as needed
|
//TODO: Call on other tabs as needed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,14 +101,12 @@ class ContentSearchResultsFragment : MainFragment() {
|
||||||
|
|
||||||
fun onShown(parameter: Any?, isBack: Boolean) {
|
fun onShown(parameter: Any?, isBack: Boolean) {
|
||||||
if(parameter is SuggestionsFragmentData) {
|
if(parameter is SuggestionsFragmentData) {
|
||||||
if(!isBack) {
|
setQuery(parameter.query, false);
|
||||||
setQuery(parameter.query, false);
|
setChannelUrl(parameter.channelUrl, false);
|
||||||
setChannelUrl(parameter.channelUrl, false);
|
|
||||||
|
|
||||||
fragment.topBar?.apply {
|
fragment.topBar?.apply {
|
||||||
if (this is SearchTopBarFragment) {
|
if (this is SearchTopBarFragment) {
|
||||||
this.setText(parameter.query);
|
this.setText(parameter.query);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,16 +71,14 @@ class CreatorSearchResultsFragment : MainFragment() {
|
||||||
|
|
||||||
fun onShown(parameter: Any?, isBack: Boolean) {
|
fun onShown(parameter: Any?, isBack: Boolean) {
|
||||||
if(parameter is String) {
|
if(parameter is String) {
|
||||||
if(!isBack) {
|
setQuery(parameter);
|
||||||
setQuery(parameter);
|
|
||||||
|
|
||||||
fragment.topBar?.apply {
|
fragment.topBar?.apply {
|
||||||
if (this is SearchTopBarFragment) {
|
if (this is SearchTopBarFragment) {
|
||||||
setText(parameter);
|
setText(parameter);
|
||||||
onSearch.subscribe(this) {
|
onSearch.subscribe(this) {
|
||||||
setQuery(it);
|
setQuery(it);
|
||||||
};
|
};
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,16 +73,14 @@ class PlaylistSearchResultsFragment : MainFragment() {
|
||||||
|
|
||||||
fun onShown(parameter: Any?, isBack: Boolean) {
|
fun onShown(parameter: Any?, isBack: Boolean) {
|
||||||
if(parameter is String) {
|
if(parameter is String) {
|
||||||
if(!isBack) {
|
setQuery(parameter);
|
||||||
setQuery(parameter);
|
|
||||||
|
|
||||||
fragment.topBar?.apply {
|
fragment.topBar?.apply {
|
||||||
if (this is SearchTopBarFragment) {
|
if (this is SearchTopBarFragment) {
|
||||||
setText(parameter);
|
setText(parameter);
|
||||||
onSearch.subscribe(this) {
|
onSearch.subscribe(this) {
|
||||||
setQuery(it);
|
setQuery(it);
|
||||||
};
|
};
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -870,7 +870,6 @@ class VideoDetailView : ConstraintLayout {
|
||||||
_commentsList.clear();
|
_commentsList.clear();
|
||||||
_platform.setPlatformFromClientID(video.id.pluginId);
|
_platform.setPlatformFromClientID(video.id.pluginId);
|
||||||
_subTitle.text = subTitleSegments.joinToString(" • ");
|
_subTitle.text = subTitleSegments.joinToString(" • ");
|
||||||
_channelName.text = video.author.name;
|
|
||||||
_playWhenReady = true;
|
_playWhenReady = true;
|
||||||
if(video.author.subscribers != null) {
|
if(video.author.subscribers != null) {
|
||||||
_channelMeta.text = if((video.author.subscribers ?: 0) > 0) video.author.subscribers!!.toHumanNumber() + " subscribers" else "";
|
_channelMeta.text = if((video.author.subscribers ?: 0) > 0) video.author.subscribers!!.toHumanNumber() + " subscribers" else "";
|
||||||
|
@ -897,6 +896,7 @@ class VideoDetailView : ConstraintLayout {
|
||||||
} else {
|
} else {
|
||||||
setPolycentricProfile(null, animate = false);
|
setPolycentricProfile(null, animate = false);
|
||||||
_taskLoadPolycentricProfile.run(video.author.id);
|
_taskLoadPolycentricProfile.run(video.author.id);
|
||||||
|
_channelName.text = video.author.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
_player.clear();
|
_player.clear();
|
||||||
|
@ -1971,14 +1971,24 @@ class VideoDetailView : ConstraintLayout {
|
||||||
private fun setPolycentricProfile(cachedPolycentricProfile: PolycentricCache.CachedPolycentricProfile?, animate: Boolean) {
|
private fun setPolycentricProfile(cachedPolycentricProfile: PolycentricCache.CachedPolycentricProfile?, animate: Boolean) {
|
||||||
_polycentricProfile = cachedPolycentricProfile;
|
_polycentricProfile = cachedPolycentricProfile;
|
||||||
|
|
||||||
if (cachedPolycentricProfile?.profile == null) {
|
val dp_35 = 35.dp(context.resources)
|
||||||
_layoutMonetization.visibility = View.GONE;
|
val profile = cachedPolycentricProfile?.profile;
|
||||||
_creatorThumbnail.setHarborAvailable(false, animate);
|
val avatar = profile?.systemState?.avatar?.selectBestImage(dp_35 * dp_35)
|
||||||
return;
|
?.let { it.toURLInfoSystemLinkUrl(profile.system.toProto(), it.process, profile.systemState.servers.toList()) };
|
||||||
|
|
||||||
|
if (avatar != null) {
|
||||||
|
_creatorThumbnail.setThumbnail(avatar, animate);
|
||||||
|
} else {
|
||||||
|
_creatorThumbnail.setThumbnail(video?.author?.thumbnail, animate);
|
||||||
|
_creatorThumbnail.setHarborAvailable(profile != null, animate);
|
||||||
}
|
}
|
||||||
|
|
||||||
_layoutMonetization.visibility = View.VISIBLE;
|
if (profile != null) {
|
||||||
_creatorThumbnail.setHarborAvailable(true, animate);
|
_channelName.text = cachedPolycentricProfile.profile.systemState.username;
|
||||||
|
_layoutMonetization.visibility = View.VISIBLE;
|
||||||
|
} else {
|
||||||
|
_layoutMonetization.visibility = View.GONE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setProgressBarOverlayed(isOverlayed: Boolean?) {
|
fun setProgressBarOverlayed(isOverlayed: Boolean?) {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import com.futo.platformplayer.fragment.mainactivity.main.PolycentricProfile
|
||||||
import com.futo.platformplayer.getNowDiffSeconds
|
import com.futo.platformplayer.getNowDiffSeconds
|
||||||
import com.futo.platformplayer.logging.Logger
|
import com.futo.platformplayer.logging.Logger
|
||||||
import com.futo.platformplayer.resolveChannelUrl
|
import com.futo.platformplayer.resolveChannelUrl
|
||||||
|
import com.futo.platformplayer.resolveChannelUrls
|
||||||
import com.futo.platformplayer.serializers.OffsetDateTimeSerializer
|
import com.futo.platformplayer.serializers.OffsetDateTimeSerializer
|
||||||
import com.futo.platformplayer.stores.CachedPolycentricProfileStorage
|
import com.futo.platformplayer.stores.CachedPolycentricProfileStorage
|
||||||
import com.futo.platformplayer.stores.FragmentedStorage
|
import com.futo.platformplayer.stores.FragmentedStorage
|
||||||
|
@ -37,7 +38,8 @@ class PolycentricCache {
|
||||||
ContentType.AVATAR.value,
|
ContentType.AVATAR.value,
|
||||||
ContentType.USERNAME.value,
|
ContentType.USERNAME.value,
|
||||||
ContentType.DESCRIPTION.value,
|
ContentType.DESCRIPTION.value,
|
||||||
ContentType.STORE.value
|
ContentType.STORE.value,
|
||||||
|
ContentType.SERVER.value
|
||||||
)
|
)
|
||||||
).eventsList.map { e -> SignedEvent.fromProto(e) };
|
).eventsList.map { e -> SignedEvent.fromProto(e) };
|
||||||
|
|
||||||
|
@ -88,8 +90,9 @@ class PolycentricCache {
|
||||||
|
|
||||||
if (result.profile != null) {
|
if (result.profile != null) {
|
||||||
for (claim in result.profile.ownedClaims) {
|
for (claim in result.profile.ownedClaims) {
|
||||||
val url = claim.claim.resolveChannelUrl() ?: continue;
|
val urls = claim.claim.resolveChannelUrls();
|
||||||
_profileUrlCache.map[url] = result;
|
for (url in urls)
|
||||||
|
_profileUrlCache.map[url] = result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -784,6 +784,15 @@ class StatePlatform {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun resolveChannelUrlsByClaimTemplates(claimType: Int, claimValues: Map<Int, String>): List<String> {
|
||||||
|
val urls = arrayListOf<String>();
|
||||||
|
for(client in getClientsByClaimType(claimType).filter { it is JSClient }) {
|
||||||
|
val res = (client as JSClient).resolveChannelUrlsByClaimTemplates(claimType, claimValues);
|
||||||
|
urls.addAll(res);
|
||||||
|
}
|
||||||
|
return urls;
|
||||||
|
}
|
||||||
|
|
||||||
fun getPlaylistClientOrNull(url: String): IPlatformClient? = getEnabledClients().find { it.isPlaylistUrl(url) }
|
fun getPlaylistClientOrNull(url: String): IPlatformClient? = getEnabledClients().find { it.isPlaylistUrl(url) }
|
||||||
fun getPlaylistClient(url: String): IPlatformClient = getEnabledClients().find { it.isPlaylistUrl(url) }
|
fun getPlaylistClient(url: String): IPlatformClient = getEnabledClients().find { it.isPlaylistUrl(url) }
|
||||||
?: throw NoPlatformClientException("No client enabled that supports this playlist url (${url})");
|
?: throw NoPlatformClientException("No client enabled that supports this playlist url (${url})");
|
||||||
|
|
|
@ -93,6 +93,7 @@ class CommentViewHolder : ViewHolder {
|
||||||
|
|
||||||
fun bind(comment: IPlatformComment, readonly: Boolean) {
|
fun bind(comment: IPlatformComment, readonly: Boolean) {
|
||||||
_creatorThumbnail.setThumbnail(comment.author.thumbnail, false);
|
_creatorThumbnail.setThumbnail(comment.author.thumbnail, false);
|
||||||
|
_creatorThumbnail.setHarborAvailable(comment is PolycentricPlatformComment,false);
|
||||||
_textAuthor.text = comment.author.name;
|
_textAuthor.text = comment.author.name;
|
||||||
|
|
||||||
val date = comment.date;
|
val date = comment.date;
|
||||||
|
|
|
@ -32,6 +32,7 @@ import com.futo.platformplayer.views.others.CreatorThumbnail
|
||||||
import com.futo.platformplayer.views.FeedStyle
|
import com.futo.platformplayer.views.FeedStyle
|
||||||
import com.futo.platformplayer.views.platform.PlatformIndicator
|
import com.futo.platformplayer.views.platform.PlatformIndicator
|
||||||
import com.futo.platformplayer.views.video.FutoThumbnailPlayer
|
import com.futo.platformplayer.views.video.FutoThumbnailPlayer
|
||||||
|
import com.futo.polycentric.core.toURLInfoSystemLinkUrl
|
||||||
|
|
||||||
|
|
||||||
open class PreviewVideoView : LinearLayout {
|
open class PreviewVideoView : LinearLayout {
|
||||||
|
@ -58,11 +59,12 @@ open class PreviewVideoView : LinearLayout {
|
||||||
|
|
||||||
protected val _exoPlayer: PlayerManager?;
|
protected val _exoPlayer: PlayerManager?;
|
||||||
|
|
||||||
private val _taskLoadValidClaims = TaskHandler<PlatformID, PolycentricCache.CachedOwnedClaims>(StateApp.instance.scopeGetter,
|
private val _taskLoadProfile = TaskHandler<PlatformID, PolycentricCache.CachedPolycentricProfile?>(
|
||||||
{ PolycentricCache.instance.getValidClaimsAsync(it).await() })
|
StateApp.instance.scopeGetter,
|
||||||
.success { it -> updateClaimsLayout(it, animate = true) }
|
{ PolycentricCache.instance.getProfileAsync(it) })
|
||||||
|
.success { it -> onProfileLoaded(it, true) }
|
||||||
.exception<Throwable> {
|
.exception<Throwable> {
|
||||||
Logger.w(TAG, "Failed to load claims.", it);
|
Logger.w(TAG, "Failed to load profile.", it);
|
||||||
};
|
};
|
||||||
|
|
||||||
val onVideoClicked = Event2<IPlatformVideo, Long>();
|
val onVideoClicked = Event2<IPlatformVideo, Long>();
|
||||||
|
@ -145,15 +147,7 @@ open class PreviewVideoView : LinearLayout {
|
||||||
|
|
||||||
|
|
||||||
open fun bind(content: IPlatformContent) {
|
open fun bind(content: IPlatformContent) {
|
||||||
_taskLoadValidClaims.cancel();
|
_taskLoadProfile.cancel();
|
||||||
|
|
||||||
val cachedClaims = PolycentricCache.instance.getCachedValidClaims(content.author.id);
|
|
||||||
if (cachedClaims != null) {
|
|
||||||
updateClaimsLayout(cachedClaims, animate = false);
|
|
||||||
} else {
|
|
||||||
updateClaimsLayout(null, animate = false);
|
|
||||||
_taskLoadValidClaims.run(content.author.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
isClickable = true;
|
isClickable = true;
|
||||||
|
|
||||||
|
@ -161,16 +155,25 @@ open class PreviewVideoView : LinearLayout {
|
||||||
|
|
||||||
stopPreview();
|
stopPreview();
|
||||||
|
|
||||||
if(_imageChannel != null)
|
val cachedProfile = PolycentricCache.instance.getCachedProfile(content.author.url, true);
|
||||||
Glide.with(_imageChannel)
|
if (cachedProfile != null) {
|
||||||
.load(content.author.thumbnail)
|
onProfileLoaded(cachedProfile, false);
|
||||||
.placeholder(R.drawable.placeholder_channel_thumbnail)
|
} else {
|
||||||
.into(_imageChannel);
|
_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;
|
_imageChannel?.clipToOutline = true;
|
||||||
|
|
||||||
_textVideoName.text = content.name;
|
_textVideoName.text = content.name;
|
||||||
_textChannelName.text = content.author.name
|
|
||||||
_layoutDownloaded.visibility = if (StateDownloads.instance.isDownloaded(content.id)) VISIBLE else GONE;
|
_layoutDownloaded.visibility = if (StateDownloads.instance.isDownloaded(content.id)) VISIBLE else GONE;
|
||||||
|
|
||||||
_platformIndicator.setPlatformFromClientID(content.id.pluginId);
|
_platformIndicator.setPlatformFromClientID(content.id.pluginId);
|
||||||
|
@ -296,22 +299,50 @@ open class PreviewVideoView : LinearLayout {
|
||||||
_playerVideoThumbnail?.setMuteChangedListener(callback);
|
_playerVideoThumbnail?.setMuteChangedListener(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateClaimsLayout(claims: PolycentricCache.CachedOwnedClaims?, animate: Boolean) {
|
private fun onProfileLoaded(cachedPolycentricProfile: PolycentricCache.CachedPolycentricProfile?, animate: Boolean) {
|
||||||
_neopassAnimator?.cancel();
|
_neopassAnimator?.cancel();
|
||||||
_neopassAnimator = null;
|
_neopassAnimator = null;
|
||||||
|
|
||||||
val harborAvailable = claims != null && !claims.ownedClaims.isNullOrEmpty();
|
val profile = cachedPolycentricProfile?.profile;
|
||||||
if (harborAvailable) {
|
if (_creatorThumbnail != null) {
|
||||||
_imageNeopassChannel?.visibility = View.VISIBLE
|
val dp_32 = 32.dp(context.resources);
|
||||||
if (animate) {
|
val avatar = profile?.systemState?.avatar?.selectBestImage(dp_32 * dp_32)
|
||||||
_neopassAnimator = ObjectAnimator.ofFloat(_imageNeopassChannel, "alpha", 0.0f, 1.0f).setDuration(500)
|
?.let { it.toURLInfoSystemLinkUrl(profile.system.toProto(), it.process, profile.systemState.servers.toList()) };
|
||||||
_neopassAnimator?.start()
|
|
||||||
|
if (avatar != null) {
|
||||||
|
_creatorThumbnail.setThumbnail(avatar, animate);
|
||||||
|
} else {
|
||||||
|
_creatorThumbnail.setThumbnail(content?.author?.thumbnail, animate);
|
||||||
|
_creatorThumbnail.setHarborAvailable(profile != null, animate);
|
||||||
|
}
|
||||||
|
} else if (_imageChannel != null) {
|
||||||
|
val dp_28 = 28.dp(context.resources);
|
||||||
|
val avatar = profile?.systemState?.avatar?.selectBestImage(dp_28 * dp_28)
|
||||||
|
?.let { it.toURLInfoSystemLinkUrl(profile.system.toProto(), it.process, profile.systemState.servers.toList()) };
|
||||||
|
|
||||||
|
if (avatar != null) {
|
||||||
|
_imageChannel.let {
|
||||||
|
Glide.with(_imageChannel)
|
||||||
|
.load(avatar)
|
||||||
|
.placeholder(R.drawable.placeholder_channel_thumbnail)
|
||||||
|
.into(_imageChannel);
|
||||||
|
}
|
||||||
|
|
||||||
|
_imageNeopassChannel?.visibility = View.VISIBLE
|
||||||
|
if (animate) {
|
||||||
|
_neopassAnimator = ObjectAnimator.ofFloat(_imageNeopassChannel, "alpha", 0.0f, 1.0f).setDuration(500)
|
||||||
|
_neopassAnimator?.start()
|
||||||
|
} else {
|
||||||
|
_imageNeopassChannel?.alpha = 1.0f;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_imageNeopassChannel?.visibility = View.GONE
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
_imageNeopassChannel?.visibility = View.GONE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_creatorThumbnail?.setHarborAvailable(harborAvailable, animate)
|
if (profile != null) {
|
||||||
|
_textChannelName.text = profile.systemState.username
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
|
@ -72,22 +72,27 @@ class SubscriptionViewHolder : ViewHolder {
|
||||||
} else {
|
} else {
|
||||||
_creatorThumbnail.setThumbnail(sub.channel.thumbnail, false);
|
_creatorThumbnail.setThumbnail(sub.channel.thumbnail, false);
|
||||||
_taskLoadProfile.run(sub.channel.id);
|
_taskLoadProfile.run(sub.channel.id);
|
||||||
|
_textName.text = sub.channel.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
_textName.text = sub.channel.name;
|
|
||||||
_platformIndicator.setPlatformFromClientID(sub.channel.id.pluginId);
|
_platformIndicator.setPlatformFromClientID(sub.channel.id.pluginId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onProfileLoaded(cachedPolycentricProfile: PolycentricCache.CachedPolycentricProfile?, animate: Boolean) {
|
private fun onProfileLoaded(cachedPolycentricProfile: PolycentricCache.CachedPolycentricProfile?, animate: Boolean) {
|
||||||
val dp_46 = 46.dp(itemView.context.resources);
|
val dp_46 = 46.dp(itemView.context.resources);
|
||||||
val avatar = cachedPolycentricProfile?.profile?.systemState?.avatar?.selectBestImage(dp_46 * dp_46)
|
val profile = cachedPolycentricProfile?.profile;
|
||||||
?.let { it.toURLInfoSystemLinkUrl(cachedPolycentricProfile.profile.system.toProto(), it.process, cachedPolycentricProfile.profile.systemState.servers.toList()) };
|
val avatar = profile?.systemState?.avatar?.selectBestImage(dp_46 * dp_46)
|
||||||
|
?.let { it.toURLInfoSystemLinkUrl(profile.system.toProto(), it.process, profile.systemState.servers.toList()) };
|
||||||
|
|
||||||
if (avatar != null) {
|
if (avatar != null) {
|
||||||
_creatorThumbnail.setThumbnail(avatar, animate);
|
_creatorThumbnail.setThumbnail(avatar, animate);
|
||||||
} else {
|
} else {
|
||||||
_creatorThumbnail.setThumbnail(this.subscription?.channel?.thumbnail, animate);
|
_creatorThumbnail.setThumbnail(this.subscription?.channel?.thumbnail, animate);
|
||||||
_creatorThumbnail.setHarborAvailable(cachedPolycentricProfile?.profile != null, animate);
|
_creatorThumbnail.setHarborAvailable(profile != null, animate);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (profile != null) {
|
||||||
|
_textName.text = profile.systemState.username;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,13 +6,23 @@ import android.view.ViewGroup
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
import com.futo.platformplayer.R
|
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.PlatformAuthorLink
|
||||||
import com.futo.platformplayer.constructs.Event1
|
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.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.toHumanNumber
|
||||||
import com.futo.platformplayer.views.adapters.AnyAdapter
|
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.others.CreatorThumbnail
|
||||||
import com.futo.platformplayer.views.platform.PlatformIndicator
|
import com.futo.platformplayer.views.platform.PlatformIndicator
|
||||||
import com.futo.platformplayer.views.subscriptions.SubscribeButton
|
import com.futo.platformplayer.views.subscriptions.SubscribeButton
|
||||||
|
import com.futo.polycentric.core.toURLInfoSystemLinkUrl
|
||||||
|
|
||||||
class CreatorViewHolder(private val _viewGroup: ViewGroup, private val _tiny: Boolean) : AnyAdapter.AnyViewHolder<PlatformAuthorLink>(
|
class CreatorViewHolder(private val _viewGroup: ViewGroup, private val _tiny: Boolean) : AnyAdapter.AnyViewHolder<PlatformAuthorLink>(
|
||||||
LayoutInflater.from(_viewGroup.context).inflate(R.layout.list_creator, _viewGroup, false)) {
|
LayoutInflater.from(_viewGroup.context).inflate(R.layout.list_creator, _viewGroup, false)) {
|
||||||
|
@ -25,7 +35,15 @@ class CreatorViewHolder(private val _viewGroup: ViewGroup, private val _tiny: Bo
|
||||||
private var _authorLink: PlatformAuthorLink? = null;
|
private var _authorLink: PlatformAuthorLink? = null;
|
||||||
|
|
||||||
val onClick = Event1<PlatformAuthorLink>();
|
val onClick = Event1<PlatformAuthorLink>();
|
||||||
|
|
||||||
|
private val _taskLoadProfile = TaskHandler<PlatformID, PolycentricCache.CachedPolycentricProfile?>(
|
||||||
|
StateApp.instance.scopeGetter,
|
||||||
|
{ PolycentricCache.instance.getProfileAsync(it) })
|
||||||
|
.success { it -> onProfileLoaded(it, true) }
|
||||||
|
.exception<Throwable> {
|
||||||
|
Logger.w(TAG, "Failed to load profile.", it);
|
||||||
|
};
|
||||||
|
|
||||||
init {
|
init {
|
||||||
_textName = _view.findViewById(R.id.text_channel_name);
|
_textName = _view.findViewById(R.id.text_channel_name);
|
||||||
_creatorThumbnail = _view.findViewById(R.id.creator_thumbnail);
|
_creatorThumbnail = _view.findViewById(R.id.creator_thumbnail);
|
||||||
|
@ -45,12 +63,21 @@ class CreatorViewHolder(private val _viewGroup: ViewGroup, private val _tiny: Bo
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun bind(authorLink: PlatformAuthorLink) {
|
override fun bind(authorLink: PlatformAuthorLink) {
|
||||||
_textName.text = authorLink.name;
|
_taskLoadProfile.cancel();
|
||||||
_creatorThumbnail.setThumbnail(authorLink.thumbnail, false);
|
|
||||||
|
val cachedProfile = PolycentricCache.instance.getCachedProfile(authorLink.url, true);
|
||||||
|
if (cachedProfile != null) {
|
||||||
|
onProfileLoaded(cachedProfile, false);
|
||||||
|
} else {
|
||||||
|
_creatorThumbnail.setThumbnail(authorLink.thumbnail, false);
|
||||||
|
_taskLoadProfile.run(authorLink.id);
|
||||||
|
_textName.text = authorLink.name;
|
||||||
|
}
|
||||||
|
|
||||||
if(authorLink.subscribers == null || (authorLink.subscribers ?: 0) <= 0L)
|
if(authorLink.subscribers == null || (authorLink.subscribers ?: 0) <= 0L)
|
||||||
_textMetadata.visibility = View.GONE;
|
_textMetadata.visibility = View.GONE;
|
||||||
else {
|
else {
|
||||||
_textMetadata.text = if(authorLink?.subscribers ?: 0 > 0) authorLink.subscribers!!.toHumanNumber() + " subscribers" else "";
|
_textMetadata.text = if((authorLink.subscribers ?: 0) > 0) authorLink.subscribers!!.toHumanNumber() + " subscribers" else "";
|
||||||
_textMetadata.visibility = View.VISIBLE;
|
_textMetadata.visibility = View.VISIBLE;
|
||||||
}
|
}
|
||||||
_buttonSubscribe.setSubscribeChannel(authorLink.url);
|
_buttonSubscribe.setSubscribeChannel(authorLink.url);
|
||||||
|
@ -58,6 +85,25 @@ class CreatorViewHolder(private val _viewGroup: ViewGroup, private val _tiny: Bo
|
||||||
_authorLink = authorLink;
|
_authorLink = authorLink;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun onProfileLoaded(cachedPolycentricProfile: PolycentricCache.CachedPolycentricProfile?, animate: Boolean) {
|
||||||
|
val dp_61 = 61.dp(itemView.context.resources);
|
||||||
|
|
||||||
|
val profile = cachedPolycentricProfile?.profile;
|
||||||
|
val avatar = profile?.systemState?.avatar?.selectBestImage(dp_61 * dp_61)
|
||||||
|
?.let { it.toURLInfoSystemLinkUrl(profile.system.toProto(), it.process, profile.systemState.servers.toList()) };
|
||||||
|
|
||||||
|
if (avatar != null) {
|
||||||
|
_creatorThumbnail.setThumbnail(avatar, animate);
|
||||||
|
} else {
|
||||||
|
_creatorThumbnail.setThumbnail(_authorLink?.thumbnail, animate);
|
||||||
|
_creatorThumbnail.setHarborAvailable(profile != null, animate);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (profile != null) {
|
||||||
|
_textName.text = profile.systemState.username;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "CreatorViewHolder";
|
private const val TAG = "CreatorViewHolder";
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,22 +57,27 @@ class SubscriptionBarViewHolder(private val _viewGroup: ViewGroup) : AnyAdapter.
|
||||||
} else {
|
} else {
|
||||||
_creatorThumbnail.setThumbnail(subscription.channel.thumbnail, false);
|
_creatorThumbnail.setThumbnail(subscription.channel.thumbnail, false);
|
||||||
_taskLoadProfile.run(subscription.channel.id);
|
_taskLoadProfile.run(subscription.channel.id);
|
||||||
|
_name.text = subscription.channel.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
_name.text = subscription.channel.name;
|
|
||||||
_subscription = subscription;
|
_subscription = subscription;
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onProfileLoaded(cachedPolycentricProfile: PolycentricCache.CachedPolycentricProfile?, animate: Boolean) {
|
private fun onProfileLoaded(cachedPolycentricProfile: PolycentricCache.CachedPolycentricProfile?, animate: Boolean) {
|
||||||
val dp_55 = 55.dp(itemView.context.resources)
|
val dp_55 = 55.dp(itemView.context.resources)
|
||||||
val avatar = cachedPolycentricProfile?.profile?.systemState?.avatar?.selectBestImage(dp_55 * dp_55)
|
val profile = cachedPolycentricProfile?.profile;
|
||||||
?.let { it.toURLInfoSystemLinkUrl(cachedPolycentricProfile.profile.system.toProto(), it.process, cachedPolycentricProfile.profile.systemState.servers.toList()) };
|
val avatar = profile?.systemState?.avatar?.selectBestImage(dp_55 * dp_55)
|
||||||
|
?.let { it.toURLInfoSystemLinkUrl(profile.system.toProto(), it.process, profile.systemState.servers.toList()) };
|
||||||
|
|
||||||
if (avatar != null) {
|
if (avatar != null) {
|
||||||
_creatorThumbnail.setThumbnail(avatar, animate);
|
_creatorThumbnail.setThumbnail(avatar, animate);
|
||||||
} else {
|
} else {
|
||||||
_creatorThumbnail.setThumbnail(_channel?.thumbnail, animate);
|
_creatorThumbnail.setThumbnail(_channel?.thumbnail, animate);
|
||||||
_creatorThumbnail.setHarborAvailable(cachedPolycentricProfile?.profile != null, animate);
|
_creatorThumbnail.setHarborAvailable(profile != null, animate);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (profile != null) {
|
||||||
|
_name.text = profile.systemState.username;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue