New menu system

This commit is contained in:
Kelvin K
2025-11-21 19:27:28 +01:00
parent 0d70392bf0
commit 20eb53fc38
4 changed files with 267 additions and 13 deletions
@@ -13,13 +13,18 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.*
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.animation.doOnEnd
import androidx.core.view.updateLayoutParams
import androidx.lifecycle.lifecycleScope
import androidx.media3.common.util.UnstableApi
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.futo.platformplayer.R
import com.futo.platformplayer.Settings
import com.futo.platformplayer.UIDialogs
import com.futo.platformplayer.activities.MainActivity
import com.futo.platformplayer.constructs.Event1
import com.futo.platformplayer.dp
import com.futo.platformplayer.fragment.mainactivity.MainActivityFragment
import com.futo.platformplayer.fragment.mainactivity.main.*
@@ -27,6 +32,10 @@ import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.states.StateApp
import com.futo.platformplayer.states.StatePayment
import com.futo.platformplayer.states.StateSubscriptions
import com.futo.platformplayer.views.AnyAdapterView
import com.futo.platformplayer.views.AnyAdapterView.Companion.asAny
import com.futo.platformplayer.views.adapters.AnyAdapter
import com.futo.platformplayer.views.pills.RoundButton
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlin.math.floor
@@ -69,9 +78,15 @@ class MenuBottomBarFragment : MainActivityFragment() {
private val _inflater: LayoutInflater;
private val _subscribedActivity: MainActivity?;
private val _containerMoreHeader: ConstraintLayout;
private val _toggleAirplaneMode: RoundButton;
private val _togglePrivacy: RoundButton;
private var _overlayMore: FrameLayout;
private var _overlayMoreBackground: FrameLayout;
private var _layoutMoreButtons: LinearLayout;
private var _layoutMoreButtons: RecyclerView;
private val _layoutMoreButtonItems = arrayListOf<MenuButtonItem>();
private var _layoutMoreButtonsAdapter: AnyAdapterView<MenuButtonItem, MenuButtonItemViewHolder>;
private var _layoutBottomBarButtons: LinearLayout;
private var _moreVisible = false;
@@ -90,10 +105,55 @@ class MenuBottomBarFragment : MainActivityFragment() {
_inflater = inflater;
inflater.inflate(R.layout.fragment_overview_bottom_bar, this);
_containerMoreHeader = findViewById(R.id.container_more_options);
_toggleAirplaneMode = findViewById(R.id.toggle_airplane);
_togglePrivacy = findViewById(R.id.toggle_privacy);
_toggleAirplaneMode.visibility = GONE;
_toggleAirplaneMode.icon.setImageResource(R.drawable.ic_library);
_toggleAirplaneMode.onClick.subscribe {
if(StateApp.instance.privateMode) {
_togglePrivacy.icon.setImageResource(R.drawable.ic_disabled_visible);
//StateApp.instance.setPrivacyMode(false);
UIDialogs.appToast("Airplane mode disabled");
}
else {
_togglePrivacy.icon.setImageResource(R.drawable.ic_disabled_visible_purple);
//StateApp.instance.setPrivacyMode(true);
UIDialogs.appToast("Airplane mode enabled");
}
}
_togglePrivacy.icon.setImageResource(R.drawable.ic_disabled_visible)
_togglePrivacy.onClick.subscribe {
if(StateApp.instance.privateMode) {
_togglePrivacy.icon.setImageResource(R.drawable.ic_disabled_visible);
StateApp.instance.setPrivacyMode(false);
UIDialogs.appToast("Privacy mode disabled");
}
else {
_togglePrivacy.icon.setImageResource(R.drawable.ic_disabled_visible_purple);
StateApp.instance.setPrivacyMode(true);
UIDialogs.appToast("Privacy mode enabled");
}
}
_overlayMore = findViewById(R.id.more_overlay);
_overlayMoreBackground = findViewById(R.id.more_overlay_background);
_layoutMoreButtons = findViewById(R.id.more_menu_buttons);
_layoutBottomBarButtons = findViewById(R.id.bottom_bar_buttons)
_layoutBottomBarButtons = findViewById(R.id.bottom_bar_buttons);
val totalWidthDp = resources.displayMetrics.widthPixels / resources.displayMetrics.density;
val columns = MenuButtonItemViewHolder.getAutoSizeColumns(totalWidthDp);
_layoutMoreButtonsAdapter = _layoutMoreButtons.asAny<MenuButtonItem, MenuButtonItemViewHolder>(_layoutMoreButtonItems,
RecyclerView.VERTICAL, false, { button ->
button.setAutoSize(totalWidthDp);
button.parentFragment = this@MenuBottomBarView._fragment;
button.onClick.subscribe {
setMoreVisible(false);
}
})
val layoutManager = GridLayoutManager(context, columns);
_layoutMoreButtons.layoutManager = layoutManager;
_overlayMoreBackground.setOnClickListener { setMoreVisible(false); };
@@ -120,6 +180,8 @@ class MenuBottomBarFragment : MainActivityFragment() {
}
private fun setMoreVisible(visible: Boolean) {
//TODO: issues with these bools
if (_moreVisibleAnimating) {
return
}
@@ -128,9 +190,12 @@ class MenuBottomBarFragment : MainActivityFragment() {
return
}
/*
val height = _moreButtons.firstOrNull()?.let {
it.height.toFloat() + (it.layoutParams as MarginLayoutParams).bottomMargin
} ?: return
*/
_moreVisibleAnimating = true
val moreOverlayBackground = _overlayMoreBackground
@@ -142,14 +207,17 @@ class MenuBottomBarFragment : MainActivityFragment() {
moreOverlay.visibility = VISIBLE
val animations = arrayListOf<Animator>()
animations.add(ObjectAnimator.ofFloat(moreOverlayBackground, "alpha", 0.0f, 1.0f).setDuration(duration))
animations.add(ObjectAnimator.ofFloat(_layoutMoreButtons, "alpha", 0.0f, 1.0f).setDuration(duration))
animations.add(ObjectAnimator.ofFloat(_containerMoreHeader, "alpha", 0.0f, 1.0f).setDuration(duration))
_bottomButtons.find { it.definition.id == 99 }?.let {
animations.add(ObjectAnimator.ofFloat(it, "alpha", 0.5f, 1.0f)
.setDuration(duration));
}
animations.add(ObjectAnimator.ofFloat(_layoutMoreButtons, "translationY", resources.displayMetrics.heightPixels.toFloat(), 0.0f).setDuration(duration))
for ((index, button) in _moreButtons.withIndex()) {
val i = _moreButtons.size - index
animations.add(ObjectAnimator.ofFloat(button, "translationY", height * staggerFactor * (i + 1), 0.0f).setDuration(duration))
//animations.add(ObjectAnimator.ofFloat(button, "translationY", height * staggerFactor * (i + 1), 0.0f).setDuration(duration))
}
val animatorSet = AnimatorSet()
@@ -164,14 +232,21 @@ class MenuBottomBarFragment : MainActivityFragment() {
animations
.add(ObjectAnimator.ofFloat(moreOverlayBackground, "alpha", 1.0f, 0.0f)
.setDuration(duration))
animations
.add(ObjectAnimator.ofFloat(_layoutMoreButtons, "alpha", 1.0f, 0.0f)
.setDuration(duration))
animations
.add(ObjectAnimator.ofFloat(_containerMoreHeader, "alpha", 1.0f, 0.0f)
.setDuration(duration))
_bottomButtons.find { it.definition.id == 99 }?.let {
animations.add(ObjectAnimator.ofFloat(it, "alpha", 1.0f, 0.5f)
.setDuration(duration));
}
animations.add(ObjectAnimator.ofFloat(_layoutMoreButtons, "translationY", 0.0f, resources.displayMetrics.heightPixels.toFloat()).setDuration(duration))
for ((index, button) in _moreButtons.withIndex()) {
val i = _moreButtons.size - index
animations.add(ObjectAnimator.ofFloat(button, "translationY", 0.0f, height * staggerFactor * (i + 1)).setDuration(duration))
//animations.add(ObjectAnimator.ofFloat(button, "translationY", 0.0f, height * staggerFactor * (i + 1)).setDuration(duration))
}
val animatorSet = AnimatorSet()
@@ -183,11 +258,12 @@ class MenuBottomBarFragment : MainActivityFragment() {
animatorSet.playTogether(animations)
animatorSet.start()
}
}
private fun updateBottomMenuButtons(buttons: MutableList<ButtonDefinition>, hasMore: Boolean) {
if (hasMore) {
buttons.add(ButtonDefinition(99, R.drawable.ic_more, R.drawable.ic_more, R.string.more, canToggle = false, { false }, { setMoreVisible(true) }))
buttons.add(ButtonDefinition(99, R.drawable.ic_more, R.drawable.ic_more, R.string.more, canToggle = false, { false }, { setMoreVisible(!_moreVisible) }))
}
_bottomButtons.clear();
@@ -252,7 +328,9 @@ class MenuBottomBarFragment : MainActivityFragment() {
insertedButtons++;
}
val newButtons = mutableListOf<MenuButtonItem>();
for (data in buttons) {
/*
val button = MenuButton(context, data, _fragment, true);
button.setOnClickListener {
updateMenuIcons()
@@ -262,7 +340,12 @@ class MenuBottomBarFragment : MainActivityFragment() {
_moreButtons.add(button);
_layoutMoreButtons.addView(button);
*/
val buttonItem = MenuButtonItem(data);
newButtons.add(buttonItem);
}
_layoutMoreButtonsAdapter.setData(newButtons);
_layoutMoreButtonsAdapter.notifyContentChanged();
}
private fun updateMenuIcons() {
@@ -350,6 +433,71 @@ class MenuBottomBarFragment : MainActivityFragment() {
}
class MenuButtonItem(val def: ButtonDefinition);
class MenuButtonItemViewHolder(private val _viewGroup: ViewGroup): AnyAdapter.AnyViewHolder<MenuButtonItem>(
LayoutInflater.from(_viewGroup.context).inflate(R.layout.list_menu_tile,
_viewGroup, false)) {
val onClick = Event1<MenuButtonItem>();
val root: ConstraintLayout;
val imageIcon: ImageView;
val textName: TextView;
var button: MenuButtonItem? = null;
var parentFragment: MenuBottomBarFragment? = null;
init {
root = _view.findViewById(R.id.root);
imageIcon = _view.findViewById(R.id.image_icon);
textName = _view.findViewById(R.id.text_name);
root.setOnClickListener {
button?.let {
it.def.action(parentFragment ?: return@let);
onClick.emit(it);
}
}
}
override fun bind(value: MenuButtonItem) {
button = value;
textName.text = _view.context.getString(value.def.string);
imageIcon.setImageResource(value.def.iconActive);
}
fun setWidth(dp: Int) {
root.updateLayoutParams {
this.width = (dp - 12).dp(_viewGroup.context.resources);
this.height = (dp - 12).dp(_viewGroup.context.resources);
}
imageIcon.updateLayoutParams {
this.width = (dp - 46).dp(_viewGroup.context.resources);
this.height = (dp - 46).dp(_viewGroup.context.resources);
}
}
fun setAutoSize(totalWidth: Float) {
val dpWidth = totalWidth;
val columns = Math.max(((dpWidth) / viewWidthDp).toInt(), 1);
val remainder = dpWidth - columns * viewWidthDp;
val targetSize = viewWidthDp + (remainder / columns).toInt();
setWidth(targetSize);
}
companion object {
val viewWidthDp = 90;
fun getAutoSizeColumns(totalWidth: Float): Int {
val dpWidth = totalWidth;
val columns = Math.max(((dpWidth) / viewWidthDp).toInt(), 1);
return columns;
}
}
}
class MenuButton: LinearLayout {
val definition: ButtonDefinition;
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#AA111111" />
<stroke android:color="#111111" android:width="1dp" />
<corners android:radius="4dp" />
<padding android:left="0dp" android:top="0dp" android:right="0dp" android:bottom="0dp" />
</shape>
@@ -25,14 +25,65 @@
</FrameLayout>
<!--More Menu-->
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/container_more_options"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent">
<LinearLayout
android:id="@+id/more_menu_buttons"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginTop="10dp"
android:layout_marginBottom="15dp"
android:layout_marginRight="10dp"
android:gravity="right">
<com.futo.platformplayer.views.pills.RoundButton
android:id="@+id/toggle_airplane"
android:layout_marginRight="10dp"
android:layout_width="45dp"
android:layout_height="45dp" />
<com.futo.platformplayer.views.pills.RoundButton
android:id="@+id/toggle_privacy"
android:layout_marginRight="10dp"
android:layout_width="50dp"
android:layout_height="50dp" />
<ImageView
android:id="@+id/button_close"
android:layout_width="50dp"
android:layout_height="50dp"
android:src="@drawable/ic_close" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/more_menu_buttons"
android:layout_width="match_parent"
android:layout_height="0dp"
android:orientation="vertical"
android:layout_gravity="bottom|end"
android:layout_marginTop="10dp"
app:layout_constraintTop_toBottomOf="@id/container_more_options"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:gravity="end">
</LinearLayout>
</androidx.recyclerview.widget.RecyclerView>
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>
<LinearLayout
@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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="86dp"
android:layout_height="146dp"
android:layout_marginTop="4dp"
android:layout_marginBottom="5dp"
android:layout_marginLeft="6dp"
android:layout_marginRight="6dp"
android:background="@drawable/background_menu_round_4dp"
android:id="@+id/root"
android:clickable="true">
<ImageView
android:id="@+id/image_icon"
android:layout_height="54dp"
android:layout_width="0dp"
android:scaleType="centerCrop"
app:layout_constraintDimensionRatio="H,1,1"
app:shapeAppearanceOverlay="@style/roundedCorners_4dp"
app:srcCompat="@drawable/unknown_music"
android:background="@drawable/video_thumbnail_outline"
android:layout_marginLeft="18dp"
android:layout_marginRight="18dp"
android:layout_marginTop="12dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
<TextView
android:id="@+id/text_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textSize="12dp"
android:textColor="@color/white"
android:fontFamily="@font/inter_medium"
tools:text="The Beetles"
android:maxLines="2"
android:gravity="center"
app:layout_constraintLeft_toRightOf="@id/image_icon"
app:layout_constraintTop_toBottomOf="@id/image_icon"
app:layout_constraintLeft_toLeftOf="@id/image_icon"
app:layout_constraintRight_toRightOf="@id/image_icon"
android:layout_marginTop="5dp"
/>
</androidx.constraintlayout.widget.ConstraintLayout>