diff --git a/app/src/main/java/com/futo/platformplayer/HorizontalSpaceItemDecoration.kt b/app/src/main/java/com/futo/platformplayer/HorizontalSpaceItemDecoration.kt new file mode 100644 index 0000000000000000000000000000000000000000..0d57ce75bc63e10a591d0760b040aab46ae158ba --- /dev/null +++ b/app/src/main/java/com/futo/platformplayer/HorizontalSpaceItemDecoration.kt @@ -0,0 +1,20 @@ +package com.futo.platformplayer + +import android.graphics.Rect +import android.view.View +import androidx.recyclerview.widget.RecyclerView + +class HorizontalSpaceItemDecoration(private val startSpace: Int, private val betweenSpace: Int, private val endSpace: Int) : RecyclerView.ItemDecoration() { + override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) { + outRect.left = betweenSpace + + val position = parent.getChildAdapterPosition(view) + if (position == 0) { + outRect.left = startSpace + } + + else if (position == state.itemCount - 1) { + outRect.right = endSpace + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/futo/platformplayer/fragment/channel/tab/ChannelMonetizationFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/channel/tab/ChannelMonetizationFragment.kt index 83a37e9a66ce9633e05451eea0b0825ec0add26b..4fbdf6074975427fef11c35b1425a8d14bc08865 100644 --- a/app/src/main/java/com/futo/platformplayer/fragment/channel/tab/ChannelMonetizationFragment.kt +++ b/app/src/main/java/com/futo/platformplayer/fragment/channel/tab/ChannelMonetizationFragment.kt @@ -11,11 +11,12 @@ import com.futo.platformplayer.R import com.futo.platformplayer.api.media.models.channels.IPlatformChannel import com.futo.platformplayer.fragment.mainactivity.main.PolycentricProfile import com.futo.platformplayer.logging.Logger +import com.futo.platformplayer.views.SupportView import com.futo.platformplayer.views.buttons.BigButton class ChannelMonetizationFragment : Fragment, IChannelTabFragment { - private var _buttonStore: BigButton? = null; + private var _supportView: SupportView? = null private var _lastChannel: IPlatformChannel? = null; private var _lastPolycentricProfile: PolycentricProfile? = null; @@ -24,20 +25,7 @@ class ChannelMonetizationFragment : Fragment, IChannelTabFragment { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val view = inflater.inflate(R.layout.fragment_channel_monetization, container, false); - _buttonStore = view.findViewById(R.id.button_store); - - _buttonStore?.onClick?.subscribe { - _lastPolycentricProfile?.systemState?.store?.let { - try { - val uri = Uri.parse(it); - val intent = Intent(Intent.ACTION_VIEW) - intent.data = uri - startActivity(intent) - } catch (e: Throwable) { - Logger.e(TAG, "Failed to open URI: '${it}'.", e); - } - } - }; + _supportView = view.findViewById(R.id.support); _lastChannel?.also { setChannel(it); @@ -52,24 +40,16 @@ class ChannelMonetizationFragment : Fragment, IChannelTabFragment { override fun onDestroyView() { super.onDestroyView(); - _buttonStore = null; + _supportView = null; } override fun setChannel(channel: IPlatformChannel) { _lastChannel = channel; - _buttonStore?.visibility = View.GONE; } fun setPolycentricProfile(polycentricProfile: PolycentricProfile?, animate: Boolean) { - _lastPolycentricProfile = polycentricProfile; - - if (polycentricProfile == null) { - return; - } - - if (polycentricProfile.systemState.store.isNotEmpty()) { - _buttonStore?.visibility = View.VISIBLE; - } + _lastPolycentricProfile = polycentricProfile + _supportView?.setPolycentricProfile(polycentricProfile, animate) } companion object { 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 308cd63c4179fca05e82a1d4131b18a5cfcc9cf8..6261b6e14e8116d0e7c727f38a2687f0704c3e56 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 @@ -70,6 +70,7 @@ import com.futo.platformplayer.receivers.MediaControlReceiver import com.futo.platformplayer.states.* import com.futo.platformplayer.stores.FragmentedStorage import com.futo.platformplayer.stores.StringArrayStorage +import com.futo.platformplayer.views.MonetizationView import com.futo.platformplayer.views.behavior.TouchInterceptFrameLayout import com.futo.platformplayer.views.casting.CastView import com.futo.platformplayer.views.comments.AddCommentView @@ -79,6 +80,7 @@ import com.futo.platformplayer.views.overlays.DescriptionOverlay import com.futo.platformplayer.views.overlays.LiveChatOverlay import com.futo.platformplayer.views.overlays.QueueEditorOverlay import com.futo.platformplayer.views.overlays.RepliesOverlay +import com.futo.platformplayer.views.overlays.SupportOverlay import com.futo.platformplayer.views.overlays.slideup.* import com.futo.platformplayer.views.pills.PillRatingLikesDislikes import com.futo.platformplayer.views.pills.RoundButton @@ -191,6 +193,7 @@ class VideoDetailView : ConstraintLayout { private val _container_content_replies: RepliesOverlay; private val _container_content_description: DescriptionOverlay; private val _container_content_liveChat: LiveChatOverlay; + private val _container_content_support: SupportOverlay; private var _container_content_current: View; @@ -200,9 +203,7 @@ class VideoDetailView : ConstraintLayout { private val _imageDislikeIcon: ImageView; private val _imageLikeIcon: ImageView; - private val _buttonSupport: LinearLayout; - private val _buttonStore: LinearLayout; - private val _layoutMonetization: LinearLayout; + private val _monetization: MonetizationView; private val _buttonMore: RoundButton; @@ -292,6 +293,7 @@ class VideoDetailView : ConstraintLayout { _container_content_replies = findViewById(R.id.videodetail_container_replies); _container_content_description = findViewById(R.id.videodetail_container_description); _container_content_liveChat = findViewById(R.id.videodetail_container_livechat); + _container_content_support = findViewById(R.id.videodetail_container_support) _textComments = findViewById(R.id.text_comments); _addCommentView = findViewById(R.id.add_comment_view); @@ -310,11 +312,7 @@ class VideoDetailView : ConstraintLayout { _imageLikeIcon = findViewById(R.id.image_like_icon); _imageDislikeIcon = findViewById(R.id.image_dislike_icon); - _buttonSupport = findViewById(R.id.button_support); - _buttonStore = findViewById(R.id.button_store); - _layoutMonetization = findViewById(R.id.layout_monetization); - - _layoutMonetization.visibility = View.GONE; + _monetization = findViewById(R.id.monetization); _player.attachPlayer(); @@ -327,16 +325,12 @@ class VideoDetailView : ConstraintLayout { fragment.navigate<VideoDetailFragment>(it.targetUrl); }; - _buttonSupport.setOnClickListener { - val author = video?.author ?: _searchVideo?.author; - author?.let { fragment.navigate<ChannelFragment>(it).selectTab(2); }; - fragment.lifecycleScope.launch { - delay(100); - fragment.minimizeVideoDetail(); - }; + _monetization.onSupportTap.subscribe { + _container_content_support.setPolycentricProfile(_polycentricProfile?.profile, false); + switchContentView(_container_content_support); }; - _buttonStore.setOnClickListener { + _monetization.onStoreTap.subscribe { _polycentricProfile?.profile?.systemState?.store?.let { try { val uri = Uri.parse(it); @@ -349,6 +343,13 @@ class VideoDetailView : ConstraintLayout { } }; + _player.attachPlayer(); + + _container_content_liveChat.onRaidNow.subscribe { + StatePlayer.instance.clearQueue(); + fragment.navigate<VideoDetailFragment>(it.targetUrl); + }; + StateApp.instance.preventPictureInPicture.subscribe(this) { Logger.i(TAG, "StateApp.instance.preventPictureInPicture.subscribe preventPictureInPicture = true"); preventPictureInPicture = true; @@ -545,6 +546,7 @@ class VideoDetailView : ConstraintLayout { _container_content_liveChat.onClose.subscribe { switchContentView(_container_content_main); }; _container_content_queue.onClose.subscribe { switchContentView(_container_content_main); }; _container_content_replies.onClose.subscribe { switchContentView(_container_content_main); }; + _container_content_support.onClose.subscribe { switchContentView(_container_content_main); }; _description_viewMore.setOnClickListener { switchContentView(_container_content_description); @@ -847,6 +849,7 @@ class VideoDetailView : ConstraintLayout { _container_content_replies.cleanup(); _container_content_queue.cleanup(); _container_content_description.cleanup(); + _container_content_support.cleanup(); StateCasting.instance.onActiveDevicePlayChanged.remove(this); StateCasting.instance.onActiveDeviceTimeChanged.remove(this); StateCasting.instance.onActiveDeviceConnectionStateChanged.remove(this); @@ -2096,12 +2099,7 @@ class VideoDetailView : ConstraintLayout { _creatorThumbnail.setHarborAvailable(profile != null, animate); } - if (profile != null) { - _channelName.text = cachedPolycentricProfile.profile.systemState.username; - _layoutMonetization.visibility = View.VISIBLE; - } else { - _layoutMonetization.visibility = View.GONE; - } + _monetization.setPolycentricProfile(cachedPolycentricProfile, animate); } fun setProgressBarOverlayed(isOverlayed: Boolean?) { diff --git a/app/src/main/java/com/futo/platformplayer/images/PolycentricModelLoader.java b/app/src/main/java/com/futo/platformplayer/images/PolycentricModelLoader.java index a521a2fb433e1d1605887705e0144d71acd3aa27..067d8fcf78fe165f168e9e4c6fc9a0ecebddbe2e 100644 --- a/app/src/main/java/com/futo/platformplayer/images/PolycentricModelLoader.java +++ b/app/src/main/java/com/futo/platformplayer/images/PolycentricModelLoader.java @@ -1,5 +1,7 @@ package com.futo.platformplayer.images; +import android.util.Log; + import androidx.annotation.NonNull; import com.bumptech.glide.Priority; 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 6e29cb3ecfd1a85060821cc5750cc816f373ff16..dc5ce5bb8615f5a3d67ce11dd327048d80197fc1 100644 --- a/app/src/main/java/com/futo/platformplayer/polycentric/PolycentricCache.kt +++ b/app/src/main/java/com/futo/platformplayer/polycentric/PolycentricCache.kt @@ -39,7 +39,12 @@ class PolycentricCache { ContentType.USERNAME.value, ContentType.DESCRIPTION.value, ContentType.STORE.value, - ContentType.SERVER.value + ContentType.SERVER.value, + ContentType.STORE_DATA.value, + ContentType.PROMOTION_BANNER.value, + ContentType.PROMOTION.value, + ContentType.MEMBERSHIP_URLS.value, + ContentType.DONATION_DESTINATIONS.value ) ).eventsList.map { e -> SignedEvent.fromProto(e) }; diff --git a/app/src/main/java/com/futo/platformplayer/views/MonetizationView.kt b/app/src/main/java/com/futo/platformplayer/views/MonetizationView.kt new file mode 100644 index 0000000000000000000000000000000000000000..b221817cf495b62fdad495cada31c63a35143f57 --- /dev/null +++ b/app/src/main/java/com/futo/platformplayer/views/MonetizationView.kt @@ -0,0 +1,145 @@ +package com.futo.platformplayer.views + +import android.content.Context +import android.net.Uri +import android.util.AttributeSet +import android.view.View +import android.widget.FrameLayout +import android.widget.LinearLayout +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import com.futo.platformplayer.R +import com.futo.platformplayer.HorizontalSpaceItemDecoration +import com.futo.platformplayer.api.http.ManagedHttpClient +import com.futo.platformplayer.constructs.Event0 +import com.futo.platformplayer.constructs.TaskHandler +import com.futo.platformplayer.logging.Logger +import com.futo.platformplayer.polycentric.PolycentricCache +import com.futo.platformplayer.states.StateApp +import com.futo.platformplayer.views.AnyAdapterView.Companion.asAny +import com.futo.platformplayer.views.adapters.viewholders.StoreItemViewHolder +import com.futo.platformplayer.views.platform.PlatformIndicator +import kotlinx.serialization.Serializable +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json + +@Serializable +data class StoreItem( + val url: String, + val name: String, + val image: String +); + +class MonetizationView : LinearLayout { + private val _buttonSupport: LinearLayout; + private val _buttonStore: LinearLayout; + private val _buttonMembership: LinearLayout; + private val _platformIndicator: PlatformIndicator; + + private val _textMerchandise: TextView; + private val _recyclerMerchandise: RecyclerView; + private val _loaderMerchandise: Loader; + private val _layoutMerchandise: FrameLayout; + private var _merchandiseAdapterView: AnyAdapterView<StoreItem, StoreItemViewHolder>? = null; + + private val _root: LinearLayout; + + private val _taskLoadMerchandise = TaskHandler<String, List<StoreItem>>(StateApp.instance.scopeGetter, { url -> + val client = ManagedHttpClient(); + val result = client.get("https://storecache.grayjay.app/StoreData?url=$url") + if (!result.isOk) { + throw Exception("Failed to retrieve store data."); + } + + return@TaskHandler result.body?.let { Json.decodeFromString<List<StoreItem>>(it.string()); } ?: listOf(); + }) + .success { setMerchandise(it) } + .exception<Throwable> { + Logger.w(TAG, "Failed to load merchandise profile.", it); + }; + + val onSupportTap = Event0(); + val onStoreTap = Event0(); + + constructor(context: Context, attrs: AttributeSet? = null) : super(context, attrs) { + inflate(context, R.layout.view_monetization, this); + _buttonSupport = findViewById(R.id.button_support); + _buttonStore = findViewById(R.id.button_store); + _buttonMembership = findViewById(R.id.button_membership); + _platformIndicator = findViewById(R.id.platform_indicator); + + _textMerchandise = findViewById(R.id.text_merchandise); + _recyclerMerchandise = findViewById(R.id.recycler_merchandise); + _loaderMerchandise = findViewById(R.id.loader_merchandise); + _layoutMerchandise = findViewById(R.id.layout_merchandise); + + _root = findViewById(R.id.root); + + _recyclerMerchandise.addItemDecoration(HorizontalSpaceItemDecoration(30, 16, 30)) + _merchandiseAdapterView = _recyclerMerchandise.asAny(orientation = RecyclerView.HORIZONTAL); + + _buttonSupport.setOnClickListener { onSupportTap.emit(); } + _buttonStore.setOnClickListener { onStoreTap.emit(); } + _buttonMembership.visibility = View.GONE; + setMerchandise(null); + } + + fun setPlatformMembership() { + //TODO: + } + + private fun setMerchandise(items: List<StoreItem>?) { + _loaderMerchandise.stop(); + + if (items == null) { + _textMerchandise.visibility = View.GONE; + _recyclerMerchandise.visibility = View.GONE; + _layoutMerchandise.visibility = View.GONE; + } else { + _textMerchandise.visibility = View.VISIBLE; + _recyclerMerchandise.visibility = View.VISIBLE; + _layoutMerchandise.visibility = View.VISIBLE; + _merchandiseAdapterView?.adapter?.setData(items.shuffled()); + } + } + + fun setPolycentricProfile(cachedPolycentricProfile: PolycentricCache.CachedPolycentricProfile?, animate: Boolean) { + val profile = cachedPolycentricProfile?.profile; + if (profile != null) { + if (profile.systemState.store.isNotEmpty()) { + _buttonStore.visibility = View.VISIBLE; + } else { + _buttonStore.visibility = View.GONE; + } + + _root.visibility = View.VISIBLE; + } else { + _root.visibility = View.GONE; + } + + setMerchandise(null); + val storeData = profile?.systemState?.storeData; + if (storeData != null) { + try { + val storeItems = Json.decodeFromString<List<StoreItem>>(storeData); + setMerchandise(storeItems); + } catch (_: Throwable) { + try { + val uri = Uri.parse(storeData); + if (uri.isAbsolute) { + _taskLoadMerchandise.run(storeData); + _loaderMerchandise.start(); + } else { + Logger.i(TAG, "Merchandise not loaded, not URL nor JSON") + } + } catch (_: Throwable) { + + } + } + } + } + + companion object { + const val TAG = "MonetizationView"; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/futo/platformplayer/views/SupportView.kt b/app/src/main/java/com/futo/platformplayer/views/SupportView.kt new file mode 100644 index 0000000000000000000000000000000000000000..0da86a64ef9c3885e30b98a6c7b0c0d1b73a83dc --- /dev/null +++ b/app/src/main/java/com/futo/platformplayer/views/SupportView.kt @@ -0,0 +1,243 @@ +package com.futo.platformplayer.views + +import android.content.ClipData +import android.content.ClipboardManager +import android.content.Context +import android.content.Intent +import android.graphics.drawable.Drawable +import android.net.Uri +import android.util.AttributeSet +import android.view.View +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import android.widget.Toast +import com.bumptech.glide.Glide +import com.bumptech.glide.request.target.CustomTarget +import com.bumptech.glide.request.transition.Transition +import com.futo.platformplayer.R +import com.futo.platformplayer.dp +import com.futo.platformplayer.fragment.mainactivity.main.PolycentricProfile +import com.futo.platformplayer.images.GlideHelper.Companion.crossfade +import com.futo.platformplayer.logging.Logger +import com.futo.platformplayer.polycentric.PolycentricCache +import com.futo.platformplayer.views.buttons.BigButton +import com.futo.polycentric.core.toURLInfoSystemLinkUrl +import com.google.android.material.imageview.ShapeableImageView +import com.google.android.material.shape.CornerFamily +import com.google.android.material.shape.ShapeAppearanceModel +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json +import userpackage.Protocol.ImageManifest + +class SupportView : LinearLayout { + private val _layoutStore: LinearLayout + private val _buttonPromotion: BigButton + private val _layoutMemberships: LinearLayout + private val _layoutMembershipEntries: LinearLayout + private val _layoutPromotions: LinearLayout + private val _layoutPromotionEntries: LinearLayout + private val _layoutDonation: LinearLayout + private val _layoutDonationEntries: LinearLayout + private val _buttonStore: BigButton + private val _imagePromotion: ShapeableImageView + private var _textNoSupportOptionsSet: TextView + private var _polycentricProfile: PolycentricProfile? = null + + constructor(context: Context, attrs: AttributeSet? = null) : super(context, attrs) { + inflate(context, R.layout.view_support, this); + + _layoutStore = findViewById(R.id.layout_store) + _buttonStore = findViewById(R.id.button_store) + _layoutMemberships = findViewById(R.id.layout_memberships) + _layoutMembershipEntries = findViewById(R.id.layout_membership_entries) + _layoutPromotions = findViewById(R.id.layout_promotions) + _layoutPromotionEntries = findViewById(R.id.layout_promotion_entries) + _layoutDonation = findViewById(R.id.layout_donation) + _layoutDonationEntries = findViewById(R.id.layout_donation_entries) + _buttonPromotion = findViewById(R.id.button_promotion) + _imagePromotion = findViewById(R.id.image_promotion) + _textNoSupportOptionsSet = findViewById(R.id.text_no_support_options_set) + + _buttonPromotion.onClick.subscribe { openPromotion() } + _imagePromotion.setOnClickListener { openPromotion() } + _buttonStore.onClick.subscribe { + val storeUrl = _polycentricProfile?.systemState?.store ?: return@subscribe + val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(storeUrl)) + context.startActivity(browserIntent) + } + } + + private fun openPromotion() { + val promotionUrl = _polycentricProfile?.systemState?.promotion ?: return + val uri = Uri.parse(promotionUrl) + if (!uri.isAbsolute && (uri.scheme == "https" || uri.scheme == "http")) { + return + } + + val browserIntent = Intent(Intent.ACTION_VIEW, uri) + context.startActivity(browserIntent) + } + + private fun setMemberships(urls: List<String>) { + _layoutMembershipEntries.removeAllViews() + for (url in urls) { + val button = createMembershipButton(url) + _layoutMembershipEntries.addView(button) + } + _layoutMemberships.visibility = if (urls.isEmpty()) View.GONE else View.VISIBLE + } + + private fun createMembershipButton(url: String): BigButton { + val uri = Uri.parse(url) + val name: String + val iconDrawableId: Int + + if (uri.host?.contains("patreon.com") == true) { + name = "Patreon" + iconDrawableId = R.drawable.patreon + } else { + name = uri.host.toString() + iconDrawableId = R.drawable.ic_web_white + } + + return BigButton(context, name, "Become a member on $name", iconDrawableId) { + val intent = Intent(Intent.ACTION_VIEW); + intent.data = uri; + context.startActivity(intent); + }.apply { + layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) + }; + } + + private fun setDonations(destinations: List<String>) { + _layoutDonationEntries.removeAllViews() + for (destination in destinations) { + val button = createDonationButton(destination) + _layoutDonationEntries.addView(button) + } + _layoutDonation.visibility = if (destinations.isEmpty()) View.GONE else View.VISIBLE + } + + private enum class CryptoType { + BITCOIN, ETHEREUM, LITECOIN, RIPPLE, UNKNOWN + } + + private fun getCryptoType(address: String): CryptoType { + val btcRegex = Regex("^(1|3)[1-9A-HJ-NP-Za-km-z]{25,34}$|^(bc1)[0-9a-zA-HJ-NP-Z]{39,59}$") + val ethRegex = Regex("^(0x)[0-9a-fA-F]{40}$") + val ltcRegex = Regex("^(L|M)[1-9A-HJ-NP-Za-km-z]{26,33}$|^(ltc1)[0-9a-zA-HJ-NP-Z]{39,59}$") + val xrpRegex = Regex("^r[1-9A-HJ-NP-Za-km-z]{24,34}$") + + return when { + ltcRegex.matches(address) -> CryptoType.LITECOIN + btcRegex.matches(address) -> CryptoType.BITCOIN + ethRegex.matches(address) -> CryptoType.ETHEREUM + xrpRegex.matches(address) -> CryptoType.RIPPLE + else -> CryptoType.UNKNOWN + } + } + + private fun createDonationButton(destination: String): BigButton { + val uri = Uri.parse(destination) + + var action: (() -> Unit)? = null + val (name, iconDrawableId, cryptoType) = if (uri.scheme == "http" || uri.scheme == "https") { + val hostName = uri.host ?: "" + + action = { + val intent = Intent(Intent.ACTION_VIEW); + intent.data = uri; + context.startActivity(intent); + } + + if (hostName.contains("paypal.com")) { + Triple("Paypal", R.drawable.paypal, null) // Replace with your actual PayPal drawable resource + } else { + Triple(hostName, R.drawable.ic_web_white, null) // Replace with your generic web drawable resource + } + } else { + action = { + val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager + val clip = ClipData.newPlainText("Donation Address", destination) + clipboard.setPrimaryClip(clip) + Toast.makeText(context, "Copied to clipboard", Toast.LENGTH_SHORT).show() + } + + when (getCryptoType(destination)) { + CryptoType.BITCOIN -> Triple("Bitcoin", R.drawable.bitcoin, CryptoType.BITCOIN) + CryptoType.ETHEREUM -> Triple("Ethereum", R.drawable.ethereum, CryptoType.ETHEREUM) + CryptoType.LITECOIN -> Triple("Litecoin", R.drawable.litecoin, CryptoType.LITECOIN) + CryptoType.RIPPLE -> Triple("Ripple", R.drawable.ripple, CryptoType.RIPPLE) + CryptoType.UNKNOWN -> Triple("Unknown", R.drawable.ic_paid, CryptoType.UNKNOWN) + } + } + + return BigButton(context, name, destination.takeIf { cryptoType != null } ?: "Donate on $name", iconDrawableId, action).apply { + layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) + }; + } + + private fun setPromotions(url: String?, imageUrl: String?) { + Logger.i(TAG, "setPromotions($url, $imageUrl)") + + if (url != null) { + _layoutPromotions.visibility = View.VISIBLE + + if (imageUrl != null) { + _buttonPromotion.visibility = View.GONE + _imagePromotion.visibility = View.VISIBLE + + Glide.with(_imagePromotion) + .load(imageUrl) + .crossfade() + .into(_imagePromotion) + } else { + _buttonPromotion.setSecondaryText(url) + _buttonPromotion.visibility = View.VISIBLE + _imagePromotion.visibility = View.GONE + } + } else { + _layoutPromotions.visibility = View.GONE + } + } + + fun setPolycentricProfile(profile: PolycentricProfile?, animate: Boolean) { + if (_polycentricProfile == profile) { + return + } + + if (profile != null) { + setDonations(profile.systemState.donationDestinations); + setMemberships(profile.systemState.membershipUrls); + + val imageManifest = profile.systemState.promotionBanner?.imageManifestsList?.firstOrNull() + if (imageManifest != null) { + val imageUrl = imageManifest.toURLInfoSystemLinkUrl(profile.system.toProto(), imageManifest.process, profile.systemState.servers.toList()); + setPromotions(profile.systemState.promotion, imageUrl); + } else { + setPromotions(null, null); + } + + if (profile.systemState.store.isNotEmpty()) { + _layoutStore.visibility = View.VISIBLE + } else { + _layoutStore.visibility = View.GONE + } + + _textNoSupportOptionsSet.visibility = View.GONE + } else { + setDonations(listOf()); + setMemberships(listOf()); + setPromotions(null, null); + _layoutStore.visibility = View.GONE + _textNoSupportOptionsSet.visibility = View.VISIBLE + } + + _polycentricProfile = profile + } + + companion object { + const val TAG = "SupportView"; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/StoreItemViewHolder.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/StoreItemViewHolder.kt new file mode 100644 index 0000000000000000000000000000000000000000..47c97acda39b31198b1e7ed3a77e53eee693ffce --- /dev/null +++ b/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/StoreItemViewHolder.kt @@ -0,0 +1,55 @@ +package com.futo.platformplayer.views.adapters.viewholders + +import android.content.Intent +import android.net.Uri +import android.view.LayoutInflater +import android.view.ViewGroup +import android.widget.LinearLayout +import android.widget.TextView +import com.bumptech.glide.Glide +import com.futo.platformplayer.R +import com.futo.platformplayer.constructs.Event1 +import com.futo.platformplayer.images.GlideHelper.Companion.crossfade +import com.futo.platformplayer.logging.Logger +import com.futo.platformplayer.views.StoreItem +import com.futo.platformplayer.views.adapters.AnyAdapter +import com.google.android.material.imageview.ShapeableImageView + +class StoreItemViewHolder(private val _viewGroup: ViewGroup) : AnyAdapter.AnyViewHolder<StoreItem>( + LayoutInflater.from(_viewGroup.context).inflate(R.layout.view_store_item, _viewGroup, false)) { + + private val _image: ShapeableImageView; + private val _name: TextView; + private var _storeItem: StoreItem? = null; + + init { + _image = _view.findViewById(R.id.image_item); + _name = _view.findViewById(R.id.text_item); + _view.findViewById<LinearLayout>(R.id.root).setOnClickListener { + val s = _storeItem ?: return@setOnClickListener; + + try { + val uri = Uri.parse(s.url); + val intent = Intent(Intent.ACTION_VIEW); + intent.data = uri; + _view.context.startActivity(intent); + } catch (e: Throwable) { + Logger.e(TAG, "Failed to open URI: '${it}'.", e); + } + } + } + + override fun bind(storeItem: StoreItem) { + Glide.with(_image) + .load(storeItem.image) + .crossfade() + .into(_image); + + _name.text = storeItem.name; + _storeItem = storeItem; + } + + companion object { + private const val TAG = "StoreItemViewHolder"; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/futo/platformplayer/views/buttons/BigButton.kt b/app/src/main/java/com/futo/platformplayer/views/buttons/BigButton.kt index 54307936da22ac1563fa64bcb19c8e772b467510..66d0b3bb994c2882a619693fec5700c8fed4046e 100644 --- a/app/src/main/java/com/futo/platformplayer/views/buttons/BigButton.kt +++ b/app/src/main/java/com/futo/platformplayer/views/buttons/BigButton.kt @@ -69,6 +69,10 @@ open class BigButton : LinearLayout { _textSecondary.text = attrTextSecondary; } + fun setSecondaryText(text: String?) { + _textSecondary.text = text + } + fun withPrimaryText(text: String): BigButton { _textPrimary.text = text; return this; diff --git a/app/src/main/java/com/futo/platformplayer/views/overlays/SupportOverlay.kt b/app/src/main/java/com/futo/platformplayer/views/overlays/SupportOverlay.kt new file mode 100644 index 0000000000000000000000000000000000000000..d43bddd48fa6fac7a379d9bbf8397d31c8c69db9 --- /dev/null +++ b/app/src/main/java/com/futo/platformplayer/views/overlays/SupportOverlay.kt @@ -0,0 +1,33 @@ +package com.futo.platformplayer.views.overlays + +import android.content.Context +import android.util.AttributeSet +import android.widget.LinearLayout +import com.futo.platformplayer.R +import com.futo.platformplayer.constructs.Event0 +import com.futo.platformplayer.fragment.mainactivity.main.PolycentricProfile +import com.futo.platformplayer.views.SupportView + +class SupportOverlay : LinearLayout { + val onClose = Event0(); + + private val _topbar: OverlayTopbar; + private val _support: SupportView; + + constructor(context: Context, attrs: AttributeSet? = null) : super(context, attrs) { + inflate(context, R.layout.overlay_support, this) + _topbar = findViewById(R.id.topbar); + _support = findViewById(R.id.support); + + _topbar.onClose.subscribe(this, onClose::emit); + } + + + fun setPolycentricProfile(profile: PolycentricProfile?, animate: Boolean) { + _support.setPolycentricProfile(profile, animate) + } + + fun cleanup() { + _topbar.onClose.remove(this); + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/background_membership.xml b/app/src/main/res/drawable/background_membership.xml new file mode 100644 index 0000000000000000000000000000000000000000..6b33ecc327c48dc38d84044e1e950bdc8c5fa75a --- /dev/null +++ b/app/src/main/res/drawable/background_membership.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <solid android:color="#232323" /> + <corners android:radius="5dp" /> + <padding android:left="0dp" android:top="0dp" android:right="0dp" android:bottom="0dp" /> +</shape> \ No newline at end of file diff --git a/app/src/main/res/drawable/background_store.xml b/app/src/main/res/drawable/background_store.xml index d7cddcfcda5b2ce7b262171eaf6b7af744385d81..3ef92416fae0f7f37de7aee27da86b95e5493adf 100644 --- a/app/src/main/res/drawable/background_store.xml +++ b/app/src/main/res/drawable/background_store.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <solid android:color="#3A1448" /> - <corners android:radius="14dp" /> + <corners android:radius="5dp" /> <padding android:left="0dp" android:top="0dp" android:right="0dp" android:bottom="0dp" /> </shape> \ No newline at end of file diff --git a/app/src/main/res/drawable/background_support.xml b/app/src/main/res/drawable/background_support.xml index 5f5d3e63ce05ad6ded366990359f71135a7a24b4..4e39889bc89147f75f125c3ac858938eb67396bd 100644 --- a/app/src/main/res/drawable/background_support.xml +++ b/app/src/main/res/drawable/background_support.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <solid android:color="#144826" /> - <corners android:radius="14dp" /> + <corners android:radius="5dp" /> <padding android:left="0dp" android:top="0dp" android:right="0dp" android:bottom="0dp" /> </shape> \ No newline at end of file diff --git a/app/src/main/res/drawable/bitcoin.xml b/app/src/main/res/drawable/bitcoin.xml new file mode 100644 index 0000000000000000000000000000000000000000..c44725506fb6153371dc372a02c7e578788289d0 --- /dev/null +++ b/app/src/main/res/drawable/bitcoin.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="273.6dp" + android:height="360dp" + android:viewportWidth="273.6" + android:viewportHeight="360"> + <path + android:pathData="M217.02,167.04c18.63,-9.48 30.29,-26.18 27.57,-54.01c-3.67,-38.02 -36.53,-50.77 -78.01,-54.4l-0.01,-52.74h-32.14l-0.01,51.35c-8.46,0 -17.08,0.17 -25.66,0.34L108.76,5.9l-32.11,-0l-0.01,52.73c-6.96,0.14 -13.79,0.28 -20.47,0.28v-0.16l-44.33,-0.02l0.01,34.28c0,0 23.73,-0.45 23.34,-0.01c13.01,0.01 17.26,7.56 18.48,14.08l0.01,60.08v84.4c-0.57,4.09 -2.98,10.63 -12.08,10.64c0.41,0.36 -23.38,-0 -23.38,-0l-6.38,38.33h41.82c7.79,0.01 15.45,0.13 22.96,0.19l0.03,53.34l32.1,0.01l-0.01,-52.78c8.83,0.18 17.36,0.26 25.68,0.25l-0.01,52.53h32.14l0.02,-53.25c54.02,-3.1 91.84,-16.7 96.54,-67.39C266.92,192.61 247.69,174.4 217.02,167.04zM109.54,95.32c18.13,0 75.13,-5.77 75.14,32.06c-0.01,36.27 -57,32.03 -75.14,32.03V95.32zM109.52,262.45l0.01,-70.67c21.78,-0.01 90.08,-6.26 90.09,35.32C199.64,266.97 131.31,262.43 109.52,262.45z" + android:fillColor="#ffffff"/> +</vector> diff --git a/app/src/main/res/drawable/divider_transparent_4dp.xml b/app/src/main/res/drawable/divider_transparent_4dp.xml new file mode 100644 index 0000000000000000000000000000000000000000..922d532cf73b1d83dd62e83826bba7598074687d --- /dev/null +++ b/app/src/main/res/drawable/divider_transparent_4dp.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <size android:height="0dp" + android:width="4dp"/> +</shape> \ No newline at end of file diff --git a/app/src/main/res/drawable/divider_transparent_8dp.xml b/app/src/main/res/drawable/divider_transparent_8dp.xml new file mode 100644 index 0000000000000000000000000000000000000000..2179f2a6f9bc17b9d7ccb6f44b83411f24bd5f88 --- /dev/null +++ b/app/src/main/res/drawable/divider_transparent_8dp.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <size android:height="0dp" + android:width="8dp"/> +</shape> \ No newline at end of file diff --git a/app/src/main/res/drawable/divider_transparent_vertical_20dp.xml b/app/src/main/res/drawable/divider_transparent_vertical_20dp.xml new file mode 100644 index 0000000000000000000000000000000000000000..16b9e0074f82e056bd6ad340e2113dcbc8c02e30 --- /dev/null +++ b/app/src/main/res/drawable/divider_transparent_vertical_20dp.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <size android:height="20dp" + android:width="0dp"/> +</shape> \ No newline at end of file diff --git a/app/src/main/res/drawable/divider_transparent_vertical_8dp.xml b/app/src/main/res/drawable/divider_transparent_vertical_8dp.xml new file mode 100644 index 0000000000000000000000000000000000000000..acbe718d89711d2dd4ded12a75b13866267cc3d9 --- /dev/null +++ b/app/src/main/res/drawable/divider_transparent_vertical_8dp.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <size android:height="8dp" + android:width="0dp"/> +</shape> \ No newline at end of file diff --git a/app/src/main/res/drawable/ethereum.xml b/app/src/main/res/drawable/ethereum.xml new file mode 100644 index 0000000000000000000000000000000000000000..bb3fbc4b6fa460560c317f9bd72cc68446f764f1 --- /dev/null +++ b/app/src/main/res/drawable/ethereum.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="800dp" + android:height="800dp" + android:viewportWidth="32" + android:viewportHeight="32"> + <path + android:pathData="M15.927,23.959l-9.823,-5.797 9.817,13.839 9.828,-13.839 -9.828,5.797zM16.073,0l-9.819,16.297 9.819,5.807 9.823,-5.801z" + android:fillColor="#ffffff"/> +</vector> diff --git a/app/src/main/res/drawable/ic_bug.xml b/app/src/main/res/drawable/ic_bug.xml index 285030ed38a812b3094c7d36b6a78ec06fb14d92..bf600b76b7ad25a5d48b5350376e0714cd9b5e8b 100644 --- a/app/src/main/res/drawable/ic_bug.xml +++ b/app/src/main/res/drawable/ic_bug.xml @@ -2,8 +2,7 @@ android:width="24dp" android:height="24dp" android:viewportWidth="960" - android:viewportHeight="960" - android:tint="?attr/colorControlNormal"> + android:viewportHeight="960"> <path android:fillColor="@android:color/white" android:pathData="M480,760Q546,760 593,713Q640,666 640,600L640,440Q640,374 593,327Q546,280 480,280Q414,280 367,327Q320,374 320,440L320,600Q320,666 367,713Q414,760 480,760ZM400,640L560,640L560,560L400,560L400,640ZM400,480L560,480L560,400L400,400L400,480ZM480,520Q480,520 480,520Q480,520 480,520L480,520Q480,520 480,520Q480,520 480,520Q480,520 480,520Q480,520 480,520L480,520Q480,520 480,520Q480,520 480,520ZM480,840Q415,840 359.5,808Q304,776 272,720L160,720L160,640L244,640Q241,620 240.5,600Q240,580 240,560L160,560L160,480L240,480Q240,460 240.5,440Q241,420 244,400L160,400L160,320L272,320Q286,297 303.5,277Q321,257 344,242L280,176L336,120L422,206Q450,197 479,197Q508,197 536,206L624,120L680,176L614,242Q637,257 655.5,276.5Q674,296 688,320L800,320L800,400L716,400Q719,420 719.5,440Q720,460 720,480L800,480L800,560L720,560Q720,580 719.5,600Q719,620 716,640L800,640L800,720L688,720Q656,776 600.5,808Q545,840 480,840Z"/> diff --git a/app/src/main/res/drawable/ic_live_tv.xml b/app/src/main/res/drawable/ic_live_tv.xml index 560d1cb7eebcf109c72637b07498689a4a1f0d4f..20523d23ec932aa449eb3d0469f037bf775d2541 100644 --- a/app/src/main/res/drawable/ic_live_tv.xml +++ b/app/src/main/res/drawable/ic_live_tv.xml @@ -2,8 +2,7 @@ android:width="24dp" android:height="24dp" android:viewportWidth="960" - android:viewportHeight="960" - android:tint="?attr/colorControlNormal"> + android:viewportHeight="960"> <path android:fillColor="@android:color/white" android:pathData="M380,620L660,440L380,260L380,620ZM320,840L320,760L160,760Q127,760 103.5,736.5Q80,713 80,680L80,200Q80,167 103.5,143.5Q127,120 160,120L800,120Q833,120 856.5,143.5Q880,167 880,200L880,680Q880,713 856.5,736.5Q833,760 800,760L640,760L640,840L320,840ZM160,680L800,680Q800,680 800,680Q800,680 800,680L800,200Q800,200 800,200Q800,200 800,200L160,200Q160,200 160,200Q160,200 160,200L160,680Q160,680 160,680Q160,680 160,680ZM160,680Q160,680 160,680Q160,680 160,680L160,200Q160,200 160,200Q160,200 160,200L160,200Q160,200 160,200Q160,200 160,200L160,680Q160,680 160,680Q160,680 160,680L160,680Z"/> diff --git a/app/src/main/res/drawable/ic_notifications.xml b/app/src/main/res/drawable/ic_notifications.xml index 77461925660575915178a45eeb0557555a7dad51..b5ac78720be054b4b99250577702720add3afe81 100644 --- a/app/src/main/res/drawable/ic_notifications.xml +++ b/app/src/main/res/drawable/ic_notifications.xml @@ -2,8 +2,7 @@ android:width="24dp" android:height="24dp" android:viewportWidth="960" - android:viewportHeight="960" - android:tint="?attr/colorControlNormal"> + android:viewportHeight="960"> <path android:fillColor="@android:color/white" android:pathData="M160,760L160,680L240,680L240,400Q240,317 290,252.5Q340,188 420,168L420,140Q420,115 437.5,97.5Q455,80 480,80Q505,80 522.5,97.5Q540,115 540,140L540,168Q620,188 670,252.5Q720,317 720,400L720,680L800,680L800,760L160,760ZM480,460L480,460L480,460L480,460Q480,460 480,460Q480,460 480,460Q480,460 480,460Q480,460 480,460ZM480,880Q447,880 423.5,856.5Q400,833 400,800L560,800Q560,833 536.5,856.5Q513,880 480,880ZM320,680L640,680L640,400Q640,334 593,287Q546,240 480,240Q414,240 367,287Q320,334 320,400L320,680Z"/> diff --git a/app/src/main/res/drawable/ic_star.xml b/app/src/main/res/drawable/ic_star.xml new file mode 100644 index 0000000000000000000000000000000000000000..e98e1d67513bf6976a841074d607ef170552f111 --- /dev/null +++ b/app/src/main/res/drawable/ic_star.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="960" + android:viewportHeight="960"> + <path + android:fillColor="@android:color/white" + android:pathData="M293,796.92L342.61,584.39L177.69,441.54L394.92,422.69L480,222.31L565.08,422.69L782.31,441.54L617.39,584.39L667,796.92L480,684.08L293,796.92Z"/> +</vector> diff --git a/app/src/main/res/drawable/litecoin.xml b/app/src/main/res/drawable/litecoin.xml new file mode 100644 index 0000000000000000000000000000000000000000..7c010ea573a45195133678c90adc42cab2f8d320 --- /dev/null +++ b/app/src/main/res/drawable/litecoin.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="82.6dp" + android:height="82.6dp" + android:viewportWidth="82.6" + android:viewportHeight="82.6"> + <path + android:pathData="M41.3,0A41.3,41.3 0,1 0,82.6 41.3h0A41.18,41.18 0,0 0,41.54 0ZM42,42.7 L37.7,57.2h23a1.16,1.16 0,0 1,1.2 1.12v0.38l-2,6.9a1.49,1.49 0,0 1,-1.5 1.1H23.2l5.9,-20.1 -6.6,2L24,44l6.6,-2 8.3,-28.2a1.51,1.51 0,0 1,1.5 -1.1h8.9a1.16,1.16 0,0 1,1.2 1.12v0.38L43.5,38l6.6,-2 -1.4,4.8Z" + android:fillColor="#ffffff"/> +</vector> diff --git a/app/src/unstable/res/drawable/logo_subscribestar.png b/app/src/main/res/drawable/logo_subscribestar.png similarity index 100% rename from app/src/unstable/res/drawable/logo_subscribestar.png rename to app/src/main/res/drawable/logo_subscribestar.png diff --git a/app/src/main/res/drawable/patreon.xml b/app/src/main/res/drawable/patreon.xml new file mode 100644 index 0000000000000000000000000000000000000000..050325a7a3c1151f79bf68bbb0cfce32b7a8c63c --- /dev/null +++ b/app/src/main/res/drawable/patreon.xml @@ -0,0 +1,12 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="180dp" + android:height="180dp" + android:viewportWidth="180" + android:viewportHeight="180"> + <path + android:pathData="M108.81,26.07c-26.47,0 -48,21.53 -48,48 0,26.39 21.53,47.85 48,47.85 26.39,0 47.85,-21.47 47.85,-47.85 0,-26.47 -21.47,-48 -47.85,-48" + android:fillColor="#ffffff"/> + <path + android:pathData="M23.33,153.93V26.07h23.47v127.87z" + android:fillColor="#ffffff"/> +</vector> diff --git a/app/src/main/res/drawable/paypal.xml b/app/src/main/res/drawable/paypal.xml new file mode 100644 index 0000000000000000000000000000000000000000..1695cd63217854066029f26346d42b81a6f0f454 --- /dev/null +++ b/app/src/main/res/drawable/paypal.xml @@ -0,0 +1,15 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="32dp" + android:height="32dp" + android:viewportWidth="32" + android:viewportHeight="32"> + <path + android:fillColor="#FF000000" + android:pathData="M12,26H7c-0.8,0 -1.6,-0.4 -2.1,-1c-0.5,-0.6 -0.7,-1.4 -0.5,-2.2L8.7,4l0,0c0.3,-1.2 1.3,-2 2.6,-2h8.6c2.3,0 4.4,1 5.9,2.8c1.4,1.8 2,4.1 1.5,6.4c-0.8,4 -4.4,6.8 -8.5,6.8h-3.2c-0.5,0 -1,0.4 -1.1,0.9L13,25.2C12.9,25.7 12.5,26 12,26z"/> + <path + android:pathData="M12,26H7c-0.8,0 -1.6,-0.4 -2.1,-1c-0.5,-0.6 -0.7,-1.4 -0.5,-2.2L8.7,4l0,0c0.3,-1.2 1.3,-2 2.6,-2h8.6c2.3,0 4.4,1 5.9,2.8c1.4,1.8 2,4.1 1.5,6.4c-0.8,4 -4.4,6.8 -8.5,6.8h-3.2c-0.5,0 -1,0.4 -1.1,0.9L13,25.2C12.9,25.7 12.5,26 12,26z" + android:fillColor="#ffffff"/> + <path + android:pathData="M29.3,11.3c0,0.1 0,0.2 0,0.3c-1,4.9 -5.4,8.4 -10.4,8.4h-2.5l-1.4,5.7C14.6,27.1 13.4,28 12,28h-2c0.1,0.4 0.2,0.7 0.5,1c0.5,0.6 1.2,0.9 2,0.9H17c0.5,0 0.9,-0.3 1,-0.7l1.4,-5.5c0.1,-0.4 0.5,-0.6 0.9,-0.6h2.9c3.7,0 7,-2.5 7.7,-6C31.3,15 30.7,12.8 29.3,11.3z" + android:fillColor="#ffffff"/> +</vector> diff --git a/app/src/main/res/drawable/ripple.xml b/app/src/main/res/drawable/ripple.xml new file mode 100644 index 0000000000000000000000000000000000000000..5d7dc10a14d697509100fbc2ad8b07d629755698 --- /dev/null +++ b/app/src/main/res/drawable/ripple.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="800dp" + android:height="800dp" + android:viewportWidth="32" + android:viewportHeight="32"> + <path + android:pathData="M27.401,19.531c-1.131,-0.645 -2.407,-0.837 -3.672,-0.885 -1.052,-0.031 -2.631,-0.724 -2.631,-2.645 0,-1.432 1.156,-2.588 2.647,-2.645 1.265,-0.048 2.541,-0.24 3.671,-0.891 3.193,-1.844 4.292,-5.928 2.448,-9.125 -1.859,-3.199 -5.952,-4.287 -9.156,-2.437 -2.072,1.187 -3.348,3.401 -3.339,5.787 0,1.296 0.464,2.484 1.052,3.599 0.496,0.927 0.735,2.661 -0.948,3.635 -1.265,0.724 -2.843,0.272 -3.624,-0.989 -0.661,-1.068 -1.459,-2.063 -2.589,-2.708 -3.197,-1.849 -7.291,-0.751 -9.124,2.437 -1.839,3.199 -0.745,7.281 2.452,9.125 2.068,1.187 4.609,1.187 6.677,0 1.125,-0.647 1.923,-1.641 2.584,-2.708 0.541,-0.871 1.911,-1.985 3.624,-0.991 1.267,0.719 1.657,2.319 0.948,3.641 -0.583,1.093 -1.052,2.297 -1.052,3.593 0,3.688 2.991,6.672 6.677,6.677 3.688,0 6.672,-2.989 6.677,-6.677 0.011,-2.385 -1.255,-4.599 -3.323,-5.792z" + android:fillColor="#ffffff"/> +</vector> diff --git a/app/src/main/res/layout/fragment_channel_monetization.xml b/app/src/main/res/layout/fragment_channel_monetization.xml index 8ada72cff665dd4968378b513d431143b2cbaa1c..0394cc7de8282ac5ad182c4bd6e9974942e58526 100644 --- a/app/src/main/res/layout/fragment_channel_monetization.xml +++ b/app/src/main/res/layout/fragment_channel_monetization.xml @@ -1,92 +1,10 @@ <?xml version="1.0" encoding="utf-8"?> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" - android:layout_height="match_parent" - xmlns:app="http://schemas.android.com/apk/res-auto" - android:orientation="vertical" - android:layout_margin="18dp"> + android:layout_height="match_parent"> - <com.futo.platformplayer.views.buttons.BigButton - android:id="@+id/button_store" + <com.futo.platformplayer.views.SupportView + android:id="@+id/support" android:layout_width="match_parent" - android:layout_height="wrap_content" - app:buttonIcon="@drawable/ic_store" - app:buttonText="@string/store" - app:buttonSubText="@string/visit_my_store" /> - - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical" - android:layout_marginTop="20dp" - android:visibility="gone"> - - <TextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textSize="16dp" - android:textColor="@color/white" - android:fontFamily="@font/inter_regular" - android:text="@string/memberships" /> - - <com.google.android.flexbox.FlexboxLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - app:flexWrap="wrap" - android:layout_marginTop="5dp"> - - <TextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textSize="14dp" - android:textColor="#909090" - android:fontFamily="@font/inter_light" - android:text="@string/a_monthly_recurring_payment_with_often" /> - - <TextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textSize="14dp" - android:textColor="#909090" - android:fontFamily="@font/inter_bold" - android:text="@string/additional_perks" /> - </com.google.android.flexbox.FlexboxLayout> - - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="8dp"> - - <com.futo.platformplayer.views.buttons.BigButton - android:layout_width="match_parent" - android:layout_height="wrap_content" /> - </LinearLayout> - - <TextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textSize="16dp" - android:textColor="@color/white" - android:fontFamily="@font/inter_regular" - android:text="@string/donation" - android:layout_marginTop="20dp"/> - - <TextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textSize="14dp" - android:textColor="#909090" - android:fontFamily="@font/inter_light" - android:text="@string/a_one_time_payment_to_support_the_creator" /> - - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="8dp"> - - <com.futo.platformplayer.views.buttons.BigButton - android:layout_width="match_parent" - android:layout_height="wrap_content" /> - </LinearLayout> - </LinearLayout> -</LinearLayout> \ No newline at end of file + android:layout_height="match_parent" /> +</FrameLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/fragview_video_detail.xml b/app/src/main/res/layout/fragview_video_detail.xml index be40a8645fec9e6106429bfb77c5806c8600f300..607de6ed34e576e9e52d3fe5e3d96e1bb4085be0 100644 --- a/app/src/main/res/layout/fragview_video_detail.xml +++ b/app/src/main/res/layout/fragview_video_detail.xml @@ -445,65 +445,10 @@ android:text="@string/click_to_read_more"/> </LinearLayout> - <LinearLayout - android:id="@+id/layout_monetization" + <com.futo.platformplayer.views.MonetizationView + android:id="@+id/monetization" android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginStart="14dp" - android:layout_marginEnd="14dp" - android:layout_marginTop="14dp"> - - <LinearLayout - android:id="@+id/button_support" - android:layout_width="0dp" - android:layout_height="30dp" - android:layout_weight="1" - android:gravity="center" - android:background="@drawable/background_support"> - - <ImageView - android:layout_width="18dp" - android:layout_height="18dp" - android:src="@drawable/ic_paid" /> - - <TextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textAppearance="@color/white" - android:fontFamily="@font/inter_light" - android:text="@string/support" - android:textSize="14dp" - android:includeFontPadding="false" - android:layout_marginStart="6dp" /> - - </LinearLayout> - - <LinearLayout - android:id="@+id/button_store" - android:layout_width="0dp" - android:layout_height="30dp" - android:layout_weight="1" - android:gravity="center" - android:layout_marginStart="8dp" - android:background="@drawable/background_store"> - - <ImageView - android:layout_width="18dp" - android:layout_height="18dp" - android:src="@drawable/ic_store" /> - - <TextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textAppearance="@color/white" - android:fontFamily="@font/inter_light" - tools:text="Store" - android:textSize="14dp" - android:includeFontPadding="false" - android:layout_marginStart="6dp" /> - - </LinearLayout> - </LinearLayout> + android:layout_height="wrap_content" /> <com.futo.platformplayer.views.videometa.UpNextView android:id="@+id/up_next" @@ -602,6 +547,12 @@ android:visibility="gone" android:layout_width="match_parent" android:layout_height="match_parent" /> + + <com.futo.platformplayer.views.overlays.SupportOverlay + android:id="@+id/videodetail_container_support" + android:visibility="gone" + android:layout_width="match_parent" + android:layout_height="match_parent" /> </FrameLayout> <FrameLayout android:id="@+id/videodetail_loading_overlay" diff --git a/app/src/main/res/layout/overlay_support.xml b/app/src/main/res/layout/overlay_support.xml new file mode 100644 index 0000000000000000000000000000000000000000..7aaaf47a3f1648f29cfcae589e3048c8b4fb39e5 --- /dev/null +++ b/app/src/main/res/layout/overlay_support.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@color/black" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <com.futo.platformplayer.views.overlays.OverlayTopbar + android:id="@+id/topbar" + android:layout_width="match_parent" + android:layout_height="40dp" + app:title="@string/support" + app:metadata="" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" /> + + <com.futo.platformplayer.views.SupportView + android:id="@+id/support" + android:layout_width="match_parent" + android:layout_height="0dp" + app:layout_constraintTop_toBottomOf="@id/topbar" + app:layout_constraintBottom_toBottomOf="parent" /> + +</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/view_monetization.xml b/app/src/main/res/layout/view_monetization.xml new file mode 100644 index 0000000000000000000000000000000000000000..76d9fd82bae3b3a62ee601c0fd305c20058a02e0 --- /dev/null +++ b/app/src/main/res/layout/view_monetization.xml @@ -0,0 +1,133 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_gravity="bottom" + android:orientation="vertical" + android:id="@+id/root"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="14dp" + android:layout_marginEnd="14dp" + android:layout_marginTop="14dp" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintTop_toTopOf="parent" + android:showDividers="middle" + android:divider="@drawable/divider_transparent_4dp"> + + <LinearLayout + android:id="@+id/button_membership" + android:layout_width="0dp" + android:layout_height="30dp" + android:layout_weight="1" + android:gravity="center" + android:background="@drawable/background_membership"> + + <com.futo.platformplayer.views.platform.PlatformIndicator + android:id="@+id/platform_indicator" + android:layout_width="18dp" + android:layout_height="18dp" /> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="@color/white" + android:fontFamily="@font/inter_light" + android:text="@string/membership" + android:textSize="14dp" + android:includeFontPadding="false" + android:layout_marginStart="6dp" /> + + </LinearLayout> + + <LinearLayout + android:id="@+id/button_support" + android:layout_width="0dp" + android:layout_height="30dp" + android:layout_weight="1" + android:gravity="center" + android:background="@drawable/background_support"> + + <ImageView + android:layout_width="18dp" + android:layout_height="18dp" + android:src="@drawable/ic_paid" /> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="@color/white" + android:fontFamily="@font/inter_light" + android:text="@string/support" + android:textSize="14dp" + android:includeFontPadding="false" + android:layout_marginStart="6dp" /> + + </LinearLayout> + + <LinearLayout + android:id="@+id/button_store" + android:layout_width="0dp" + android:layout_height="30dp" + android:layout_weight="1" + android:gravity="center" + android:background="@drawable/background_store"> + + <ImageView + android:layout_width="18dp" + android:layout_height="18dp" + android:src="@drawable/ic_store" /> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="@color/white" + android:fontFamily="@font/inter_light" + android:text="@string/store" + android:textSize="14dp" + android:includeFontPadding="false" + android:layout_marginStart="6dp" /> + + </LinearLayout> + </LinearLayout> + + <TextView + android:id="@+id/text_merchandise" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="14dp" + android:layout_marginTop="8dp" + android:fontFamily="@font/inter_medium" + android:textColor="@color/white" + android:textSize="17dp" + android:text="@string/merchandise" /> + + <FrameLayout + android:id="@+id/layout_merchandise" + android:layout_width="match_parent" + android:layout_height="140dp" + android:layout_marginTop="8dp"> + + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/recycler_merchandise" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="horizontal" + android:layout_gravity="center" /> + + <com.futo.platformplayer.views.Loader + android:id="@+id/loader_merchandise" + android:layout_width="64dp" + android:layout_height="64dp" + android:layout_gravity="center"/> + </FrameLayout> + + + + +</LinearLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/view_store_item.xml b/app/src/main/res/layout/view_store_item.xml new file mode 100644 index 0000000000000000000000000000000000000000..4db7f99a2a8e84cc1918dcef5ff7a1c7555dbc56 --- /dev/null +++ b/app/src/main/res/layout/view_store_item.xml @@ -0,0 +1,32 @@ +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="100dp" + android:layout_height="match_parent" + android:orientation="vertical" + android:clickable="true" + android:id="@+id/root" + android:gravity="center_vertical"> + + <com.google.android.material.imageview.ShapeableImageView + android:id="@+id/image_item" + android:layout_width="100dp" + android:layout_height="100dp" + android:scaleType="centerCrop" + app:shapeAppearanceOverlay="@style/roundedCorners_10dp" + android:background="#E9E9E9"/> + + <TextView + android:id="@+id/text_item" + android:layout_width="wrap_content" + android:layout_height="30dp" + tools:text="BEAST ORIGINALS HOODIE - BLACK" + android:fontFamily="@font/inter_regular" + android:textColor="#888888" + android:textSize="10dp" + android:maxLines="2" + android:layout_marginTop="8dp" + android:ellipsize="end" + android:gravity="center_horizontal" + android:layout_gravity="center_horizontal"/> +</LinearLayout> diff --git a/app/src/main/res/layout/view_support.xml b/app/src/main/res/layout/view_support.xml new file mode 100644 index 0000000000000000000000000000000000000000..392aefe91c5d9bcdfaa090b705fcd373e36f071e --- /dev/null +++ b/app/src/main/res/layout/view_support.xml @@ -0,0 +1,191 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <LinearLayout android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:layout_margin="18dp" + android:showDividers="middle" + android:divider="@drawable/divider_transparent_vertical_20dp"> + + <TextView + android:id="@+id/text_no_support_options_set" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="13dp" + android:textColor="#909090" + android:fontFamily="@font/inter_light" + android:gravity="center_horizontal" + android:text="@string/this_creator_has_not_set_any_support_options_on_harbor_polycentric" /> + + <LinearLayout + android:id="@+id/layout_store" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="16dp" + android:textColor="@color/white" + android:fontFamily="@font/inter_regular" + android:text="@string/store"/> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="13dp" + android:textColor="#909090" + android:fontFamily="@font/inter_light" + android:text="@string/a_store_by_the_creator" /> + + <com.futo.platformplayer.views.buttons.BigButton + android:id="@+id/button_store" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:buttonIcon="@drawable/ic_store" + app:buttonText="@string/store" + app:buttonSubText="@string/visit_my_store" + android:layout_marginTop="8dp" /> + + </LinearLayout> + + <LinearLayout + android:id="@+id/layout_memberships" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="16dp" + android:textColor="@color/white" + android:fontFamily="@font/inter_regular" + android:text="@string/memberships" /> + + <com.google.android.flexbox.FlexboxLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:flexWrap="wrap" + android:layout_marginTop="5dp"> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="13dp" + android:textColor="#909090" + android:fontFamily="@font/inter_light" + android:text="@string/a_monthly_recurring_payment_with_often" /> + + <Space android:layout_width="4dp" + android:layout_height="match_parent"></Space> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="13dp" + android:textColor="#909090" + android:fontFamily="@font/inter_bold" + android:text="@string/additional_perks" /> + </com.google.android.flexbox.FlexboxLayout> + + <LinearLayout + android:id="@+id/layout_membership_entries" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:orientation="vertical" + android:showDividers="middle" + android:divider="@drawable/divider_transparent_vertical_8dp"> + </LinearLayout> + </LinearLayout> + + <LinearLayout + android:id="@+id/layout_promotions" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="16dp" + android:textColor="@color/white" + android:fontFamily="@font/inter_regular" + android:text="@string/promotions" /> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="13dp" + android:textColor="#909090" + android:fontFamily="@font/inter_light" + android:text="@string/current_promotions_by_this_creator" /> + + <LinearLayout + android:id="@+id/layout_promotion_entries" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:orientation="vertical" + android:gravity="center_horizontal"> + + <com.futo.platformplayer.views.buttons.BigButton + android:id="@+id/button_promotion" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:buttonIcon="@drawable/ic_star" + app:buttonText="Promotion" + app:buttonSubText="URL" + android:layout_marginTop="8dp" /> + + <com.google.android.material.imageview.ShapeableImageView + android:id="@+id/image_promotion" + android:layout_width="300dp" + android:layout_height="100dp" + android:scaleType="centerCrop" + android:contentDescription="@string/thumbnail" + app:shapeAppearanceOverlay="@style/roundedCorners_10dp" + app:srcCompat="@drawable/placeholder_video_thumbnail" /> + </LinearLayout> + </LinearLayout> + + <LinearLayout + android:id="@+id/layout_donation" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="16dp" + android:textColor="@color/white" + android:fontFamily="@font/inter_regular" + android:text="@string/donation" /> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="13dp" + android:textColor="#909090" + android:fontFamily="@font/inter_light" + android:text="@string/a_one_time_payment_to_support_the_creator" /> + + <LinearLayout + android:id="@+id/layout_donation_entries" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:orientation="vertical" + android:showDividers="middle" + android:divider="@drawable/divider_transparent_vertical_8dp"> + </LinearLayout> + </LinearLayout> +</LinearLayout> +</androidx.core.widget.NestedScrollView> \ 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 dee4fc7d71a93bee45845884d9d1140a2be868d5..adf199dcdfc25c0bde34b96a34590619bf8419fb 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -79,6 +79,7 @@ <string name="developer">Developer</string> <string name="remove_historical_suggestion">Remove historical suggestion</string> <string name="comments">Comments</string> + <string name="merchandise">Merchandise</string> <string name="reached_the_end_of_the_playlist">Reached the end of the playlist</string> <string name="the_playlist_will_restart_after_the_video_is_finished">The playlist will restart after the video is finished</string> <string name="restart_now">Restart Now</string> @@ -192,15 +193,19 @@ <string name="i_already_paid">I Already Paid</string> <string name="memberships">Memberships</string> <string name="a_monthly_recurring_payment_with_often">A monthly recurring payment with often</string> - <string name="additional_perks">additional perks.</string> + <string name="additional_perks">additional perks</string> <string name="a_one_time_payment_to_support_the_creator">A one-time payment to support the creator</string> + <string name="a_store_by_the_creator">A store by the creator</string> <string name="donation">Donation</string> + <string name="promotions">Promotions</string> + <string name="current_promotions_by_this_creator">Current promotions by this creator</string> <string name="downloading">Downloading</string> <string name="videos">Videos</string> <string name="clear_history">Clear history</string> <string name="nothing_to_import">Nothing to import</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> <string name="store">Store</string> <string name="live_chat">Live Chat</string> <string name="remove">Remove</string> @@ -625,6 +630,7 @@ <string name="select_your_pins_in_order">Select your pins in order</string> <string name="more_options">More Options</string> <string name="save">Save</string> + <string name="this_creator_has_not_set_any_support_options_on_harbor_polycentric">This creator has not set any support options on Harbor (Polycentric)</string> <string-array name="home_screen_array"> <item>Recommendations</item> <item>Subscriptions</item> diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 37ccde2188f185ae3371fc9396c4ef313f2f1edd..d6dd18506688074fcc864b445c04eb0547d3705f 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -11,6 +11,10 @@ <item name="cornerFamily">rounded</item> <item name="cornerSize">4dp</item> </style> + <style name="roundedCorners_10dp" parent=""> + <item name="cornerFamily">rounded</item> + <item name="cornerSize">10dp</item> + </style> <style name="roundedCorners_16dp" parent=""> <item name="cornerFamily">rounded</item> <item name="cornerSize">16dp</item> diff --git a/dep/polycentricandroid b/dep/polycentricandroid index d02bf3d8e38b3dda1672866b894aea6e35643b20..3fe81ffb3c730f0dc9f645149dc20c31284cd790 160000 --- a/dep/polycentricandroid +++ b/dep/polycentricandroid @@ -1 +1 @@ -Subproject commit d02bf3d8e38b3dda1672866b894aea6e35643b20 +Subproject commit 3fe81ffb3c730f0dc9f645149dc20c31284cd790