From b0cd4567538b9366effa2b369b86c3e1ac873d97 Mon Sep 17 00:00:00 2001
From: Colin Edwards <colin@recursivepenguin.com>
Date: Sat, 6 Apr 2024 20:11:01 -0500
Subject: [PATCH] android: Button to jump to bottom of log view

This adds a button that can jump to the bottom of the log view.
If the user scrolls up we now disable the auto scroll down and show the
down button. When the down button is clicked the auto scroll resumes and
the button is removed.
---
 .../src/main/java/org/musicpd/ui/LogScreen.kt | 61 ++++++++++++++++---
 .../main/java/org/musicpd/ui/MainScreen.kt    |  2 +-
 2 files changed, 53 insertions(+), 10 deletions(-)

diff --git a/android/app/src/main/java/org/musicpd/ui/LogScreen.kt b/android/app/src/main/java/org/musicpd/ui/LogScreen.kt
index 8a1c14086..d76668819 100644
--- a/android/app/src/main/java/org/musicpd/ui/LogScreen.kt
+++ b/android/app/src/main/java/org/musicpd/ui/LogScreen.kt
@@ -1,36 +1,79 @@
 package org.musicpd.ui
 
-import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.lazy.LazyColumn
 import androidx.compose.foundation.lazy.items
 import androidx.compose.foundation.lazy.rememberLazyListState
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.VerticalAlignBottom
+import androidx.compose.material3.FloatingActionButton
+import androidx.compose.material3.Icon
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.State
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.snapshotFlow
+import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.tooling.preview.Preview
 import androidx.compose.ui.unit.dp
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.launch
 
 @Composable
-fun LogView(messages: State<List<String>>) {
-    val state = rememberLazyListState()
+fun LogView(messages: List<String>) {
+    val lazyListState = rememberLazyListState()
 
-    Column(Modifier.fillMaxSize()) {
+    var userScrolled = remember { mutableStateOf(false) }
+
+    LaunchedEffect(lazyListState) {
+        snapshotFlow { lazyListState.isScrollInProgress }
+            .collect {
+                if (it) {
+                    userScrolled.value = true
+                }
+            }
+    }
+
+    Box(Modifier.fillMaxSize()) {
         LazyColumn(
             Modifier.padding(4.dp),
-            state
+            lazyListState
         ) {
-            items(messages.value) { message ->
+            items(messages) { message ->
                 Text(text = message, fontFamily = FontFamily.Monospace)
             }
             CoroutineScope(Dispatchers.Main).launch {
-                state.scrollToItem(messages.value.count(), 0)
+                lazyListState.scrollToItem(messages.count(), 0)
+            }
+        }
+
+        if (lazyListState.canScrollForward) {
+            FloatingActionButton(
+                onClick = {
+                    userScrolled.value = false
+                    CoroutineScope(Dispatchers.Main).launch {
+                        lazyListState.scrollToItem(messages.count(), 0)
+                    }
+                },
+                modifier = Modifier.padding(16.dp).align(Alignment.BottomEnd)
+            ) {
+                Icon(Icons.Filled.VerticalAlignBottom, "Scroll to bottom icon")
             }
         }
     }
-}
\ No newline at end of file
+}
+
+@Preview
+@Composable
+fun LogViewPreview() {
+    val data = listOf("test",
+        "test2",
+        "test3")
+    LogView(data)
+}
diff --git a/android/app/src/main/java/org/musicpd/ui/MainScreen.kt b/android/app/src/main/java/org/musicpd/ui/MainScreen.kt
index 54be709b1..d7dd975d4 100644
--- a/android/app/src/main/java/org/musicpd/ui/MainScreen.kt
+++ b/android/app/src/main/java/org/musicpd/ui/MainScreen.kt
@@ -69,7 +69,7 @@ fun MPDApp(
                 StatusScreen(settingsViewModel)
             }
             composable(NavigationItem.Logs.route) {
-                LogView(settingsViewModel.getLogs().collectAsStateWithLifecycle())
+                LogView(settingsViewModel.getLogs().collectAsStateWithLifecycle().value)
             }
             composable(NavigationItem.Settings.route) {
                 MPDSettings(settingsViewModel)