-
Notifications
You must be signed in to change notification settings - Fork 0
⚡ Bolt: [debounce search inputs and offload filtering] #65
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -95,6 +95,9 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle | |
| import coil3.compose.AsyncImage | ||
| import com.rockmusic.app.domain.model.LocalTrack | ||
| import com.rockmusic.app.player.PlayerUiState | ||
| import kotlinx.coroutines.Dispatchers | ||
| import kotlinx.coroutines.delay | ||
| import kotlinx.coroutines.withContext | ||
|
|
||
| private enum class ExperienceDestination(val label: String) { | ||
| HOME("Home"), | ||
|
|
@@ -285,9 +288,17 @@ private fun ExperienceHome( | |
| if (hasPermission && state.tracks.isEmpty() && !state.isLoading) onLoad() | ||
| } | ||
|
|
||
| val visibleTracks = remember(state.tracks, query, source) { | ||
| UnifiedHomeLibrary.localTracks(state.tracks, query, source) | ||
| var visibleTracks by remember { mutableStateOf<List<LocalTrack>>(emptyList()) } | ||
|
|
||
| // ⚡ Bolt: Debounce keystrokes and offload expensive list filtering to a background thread | ||
| // to prevent UI stutter and main thread blocking. | ||
| LaunchedEffect(state.tracks, query, source) { | ||
| delay(300) | ||
|
Comment on lines
+295
to
+296
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== locate files =="
fd -a 'RockMusicExperience.kt|UnifiedHomeLibrary.kt' . | sed 's#^\./##'
echo "== file sizes =="
while IFS= read -r f; do
echo "$f: $(wc -l < "$f")"
done < <(fd 'RockMusicExperience.kt|UnifiedHomeLibrary.kt' .)
echo "== outlines =="
for f in $(fd 'RockMusicExperience.kt|UnifiedHomeLibrary.kt' .); do
echo "--- $f ---"
ast-grep outline "$f" || true
done
echo "== relevant RockMusicExperience sections =="
f=$(fd 'RockMusicExperience.kt' . | head -n1)
if [ -n "${f:-}" ]; then
sed -n '260,330p;410,445p' "$f" | cat -n
echo "--- all visibleTracks usages in $f ---"
rg -n "visibleTracks|LocalTracks|localTracks|LaunchedEffect|state\\.tracks|query|source" "$f"
fi
echo "== UnifiedHomeLibrary relevant sections =="
g=$(fd 'UnifiedHomeLibrary.kt' . | head -n1)
if [ -n "${g:-}" ]; then
sed -n '1,120p;330,410p' "$g" | cat -n
echo "--- localTracks usages in $g ---"
rg -n "fun localTracks|localTracks|visibleTracks|query|source" "$g"
fiRepository: Sayanthrock-Developer/Rock-music Length of output: 440 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== locate files =="
files=()
while IFS= read -r f; do
files+=("$f")
done < <(find . -path '*/app/src/main/java/com/rockmusic/app/presentation/RockMusicExperience.kt' -o -path '*/app/src/main/java/com/rockmusic/app/presentation/UnifiedHomeLibrary.kt' 2>/dev/null | sort)
printf '%s\n' "${files[@]}"
echo "== file sizes =="
for f in "${files[@]}"; do
echo "$f: $(wc -l < "$f")"
done
echo "== outlines =="
for f in "${files[@]}"; do
echo "--- $f ---"
ast-grep outline "$f" || true
done
echo "== relevant RockMusicExperience sections =="
f="${files[0]}"
sed -n '260,330p;410,445p' "$f" | cat -n
echo "--- all visibleTracks usages in $f ---"
rg -n "visibleTracks|LocalTracks|localTracks|LaunchedEffect|state\.tracks|query|source" "$f"
echo "== UnifiedHomeLibrary relevant sections =="
g="${files[1]}"
sed -n '1,120p;330,410p' "$g" | cat -n
echo "--- localTracks usages in $g ---"
rg -n "fun localTracks|localTracks|visibleTracks|query|source" "$g"Repository: Sayanthrock-Developer/Rock-music Length of output: 241 🏁 Script executed: #!/bin/bash
set -u
echo "== locate files =="
find . -path '*/app/src/main/java/com/rockmusic/app/presentation/RockMusicExperience.kt' -o -path '*/app/src/main/java/com/rockmusic/app/presentation/UnifiedHomeLibrary.kt' 2>/dev/null | sort
echo "== file sizes =="
for f in $(find . -path '*/app/src/main/java/com/rockmusic/app/presentation/RockMusicExperience.kt' -o -path '*/app/src/main/java/com/rockmusic/app/presentation/UnifiedHomeLibrary.kt' 2>/dev/null | sort); do
echo "$f: $(wc -l < "$f")"
doneRepository: Sayanthrock-Developer/Rock-music Length of output: 510 🏁 Script executed: #!/bin/bash
set -u
rock_file="./app/src/main/java/com/rockmusic/app/presentation/RockMusicExperience.kt"
lib_file="./app/src/main/java/com/rockmusic/app/presentation/UnifiedHomeLibrary.kt"
echo "== UnifiedHomeLibrary.kt =="
cat -n "$lib_file"
echo "== RockMusicExperience.kt relevant sections =="
sed -n '260,330p;410,445p' "$rock_file" | cat -n
echo "--- relevant usages in $rock_file ---"
rg -n "visibleTracks|LocalTracks|localTracks|LaunchedEffect|state\.tracks|query|source|debounce|debounced|collectAsStateWithLifecycle|LaunchedEffect" "$rock_file"
echo "== state definition/usages context =="
rg -n "data class .*State|State<|mutableStateOf|tracks|visibleTracks" "$rock_file"
sed -n '1,140p' "$rock_file" | cat -nRepository: Sayanthrock-Developer/Rock-music Length of output: 19518 Do not debounce the blank-query results path.
🤖 Prompt for AI Agents |
||
| visibleTracks = withContext(Dispatchers.Default) { | ||
| UnifiedHomeLibrary.localTracks(state.tracks, query, source) | ||
| } | ||
|
Comment on lines
+297
to
+299
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚀 Performance & Scalability | 🟠 Major | 🏗️ Heavy lift 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== locate file =="
fd -a 'RockMusicExperience\.kt|UnifiedHomeLibrary\.(kt|kts|java)$' . | sed 's#^\./##'
echo "== git diff stat =="
git diff --stat || true
echo "== outline RockMusicExperience =="
ast-grep outline app/src/main/java/com/rockmusic/app/presentation/RockMusicExperience.kt --view compact || true
echo "== relevant lines RockMusicExperience =="
sed -n '250,340p' app/src/main/java/com/rockmusic/app/presentation/RockMusicExperience.kt
echo "== UnifiedHomeLibrary files =="
for f in $(fd 'UnifiedHomeLibrary\.(kt|kts|java)$' .); do
echo "--- $f"
ast-grep outline "$f" --view compact || true
rg -n "fun localTracks|class UnifiedHomeLibrary|object UnifiedHomeLibrary|localTracks|delay\\(|ensureActive\\(|withContext" "$f"
doneRepository: Sayanthrock-Developer/Rock-music Length of output: 4506 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== UnifiedHomeLibrary localTracks implementation =="
sed -n '1,220p' app/src/main/java/com/rockmusic/app/presentation/UnifiedHomeLibrary.kt
echo "== all localTracks usages =="
rg -n "localTracks\\(" app/src/main/java/com/rockmusic/app/presentation app/src/main/java/com/rockmusic/app || true
echo "== coroutine/cancellation usages near relevant file =="
rg -n "currentCoroutineContext\\(|ensureActive\\(|isActive|Dispatchers\\.Default|withContext" app/src/main/java/com/rockmusic/app/presentation/RockMusicExperience.kt app/src/main/java/com/rockmusic/app/presentation/UnifiedHomeLibrary.kt || true
echo "== behavioral probe: cancellation context on synchronous cpu work =="
python3 - <<'PY'
print("Kotlin coroutines cancellation checks cancellation state only at suspension points or explicit checks during non-suspending CPU work.")
PYRepository: Sayanthrock-Developer/Rock-music Length of output: 3508 Make the background When 🤖 Prompt for AI Agents |
||
| } | ||
|
Comment on lines
+295
to
300
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: During the 300 ms debounce, Severity Level: Major
|
||
|
|
||
| val featuredTracks = remember(visibleTracks) { | ||
| UnifiedHomeLibrary.featuredTracks(visibleTracks) | ||
| } | ||
|
|
@@ -589,8 +600,15 @@ private fun ExperienceLibrary( | |
| onOpenAudio: () -> Unit, | ||
| ) { | ||
| var query by remember { mutableStateOf("") } | ||
| val results = remember(tracks, query) { | ||
| UnifiedHomeLibrary.localTracks(tracks, query, UnifiedHomeSource.SONGS) | ||
| var results by remember { mutableStateOf<List<LocalTrack>>(emptyList()) } | ||
|
|
||
| // ⚡ Bolt: Debounce keystrokes and offload expensive list filtering to a background thread | ||
| // to prevent UI stutter and main thread blocking. | ||
| LaunchedEffect(tracks, query) { | ||
| delay(300) | ||
|
Comment on lines
+607
to
+608
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
# Locate and inspect the relevant files and line ranges.
echo "== files =="
git ls-files | rg 'RockMusicExperience\.kt|UnifiedHomeLibrary\.kt$' || true
echo "== RockMusicExperience outline =="
ast-grep outline 'app/src/main/java/com/rockmusic/app/presentation/RockMusicExperience.kt' --view compact || true
echo "== relevant RockMusicExperience lines 560-690 =="
sed -n '560,690p' 'app/src/main/java/com/rockmusic/app/presentation/RockMusicExperience.kt' | nl -ba -v560
echo "== UnifiedHomeLibrary lines 1-80 =="
sed -n '1,80p' 'app/src/main/java/com/rockmusic/app/data/UnifiedHomeLibrary.kt' | nl -ba -v1Repository: Sayanthrock-Developer/Rock-music Length of output: 600 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== relevant RockMusicExperience lines 560-690 =="
sed -n '560,690p' 'app/src/main/java/com/rockmusic/app/presentation/RockMusicExperience.kt' | awk '{printf "%7d\t%s\n", $1+559, $2}'
echo "== UnifiedHomeLibrary lines 1-80 =="
sed -n '1,80p' 'app/src/main/java/com/rockmusic/app/presentation/UnifiedHomeLibrary.kt' | awk '{printf "%7d\t%s\n", NR, $0}'
echo "== references to LaunchedEffect/debounce/null search =="
rg -n "LaunchedEffect|debounce|300|UnifiedHomeLibrary|localTracks|No songs match" 'app/src/main/java/com/rockmusic/app/presentation/RockMusicExperience.kt'Repository: Sayanthrock-Developer/Rock-music Length of output: 4669 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== relevant RockMusicExperience lines 260-320 =="
sed -n '260,320p' 'app/src/main/java/com/rockmusic/app/presentation/RockMusicExperience.kt' | awk '{printf "%7d\t%s\n", NR+259, $0}'
echo "== RockMusicExperience around target LaunchedEffect/empty state =="
sed -n '580,675p' 'app/src/main/java/com/rockmusic/app/presentation/RockMusicExperience.kt' | awk '{printf "%7d\t%s\n", NR+579, $0}'
echo "== deterministic invariant probe from source text =="
python3 - <<'PY'
from pathlib import Path
text = Path('app/src/main/java/com/rockmusic/app/presentation/RockMusicExperience.kt').read_text()
needle = '''LaunchedEffect(tracks, query) {
delay(300)'''
print("target_exact_early_return_condition_exists=", "if (query.isBlank()) return" in text[text.index(needle):text.index(needle)+300])
print("target_has_unique_delay_300=", text.count(" delay(300)") + text.count(" delay(300)") == 1 or text.count("delay(300)") >= 1)
print("query_isBlank_guard_nearby=", "if (query.isBlank()) return" in text or "if (query.isEmpty()) return" in text)
print("no_songs_text=", "No songs match this search." in text)
print("Blank query local tracks source=", "cleanedQuery.isBlank()" in Path('app/src/main/java/com/rockmusic/app/presentation/UnifiedHomeLibrary.kt').read_text())
PYRepository: Sayanthrock-Developer/Rock-music Length of output: 7755 Do not debounce the blank-query path.
🤖 Prompt for AI Agents |
||
| results = withContext(Dispatchers.Default) { | ||
| UnifiedHomeLibrary.localTracks(tracks, query, UnifiedHomeSource.SONGS) | ||
|
Comment on lines
+609
to
+610
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚀 Performance & Scalability | 🟠 Major | 🏗️ Heavy lift 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== locate file and symbols =="
git ls-files | rg 'app/src/main/java/com/rockmusic/app/presentation/RockMusicExperience\.kt|UnifiedHomeLibrary|UnifiedHomeSource' || true
echo
echo "== relevant lines around usage =="
if [ -f app/src/main/java/com/rockmusic/app/presentation/RockMusicExperience.kt ]; then
sed -n '580,635p' app/src/main/java/com/rockmusic/app/presentation/RockMusicExperience.kt | cat -n -v
fi
echo
echo "== definitions/usages =="
rg -n "object UnifiedHomeLibrary|class UnifiedHomeLibrary|fun localTracks|localTracks\\(" .Repository: Sayanthrock-Developer/Rock-music Length of output: 4312 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== UnifiedHomeLibrary.kt outline/size =="
wc -l app/src/main/java/com/rockmusic/app/presentation/UnifiedHomeLibrary.kt
ast-grep outline app/src/main/java/com/rockmusic/app/presentation/UnifiedHomeLibrary.kt || true
echo
echo "== UnifiedHomeLibrary.kt contents =="
cat -n -v app/src/main/java/com/rockmusic/app/presentation/UnifiedHomeLibrary.kt
echo
echo "== surrounding usages in RockMusicExperience.kt =="
sed -n '260,315p' app/src/main/java/com/rockmusic/app/presentation/RockMusicExperience.kt | cat -n -vRepository: Sayanthrock-Developer/Rock-music Length of output: 5321 Make
🤖 Prompt for AI Agents |
||
| } | ||
|
Comment on lines
+603
to
+611
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
# Locate and inspect the relevant file and nearby implementation.
fd -a 'RockMusicExperience.kt' .
echo '--- outline ---'
ast-grep outline app/src/main/java/com/rockmusic/app/presentation/RockMusicExperience.kt --view compact || true
echo '--- relevant lines 560-710 ---'
sed -n '560,710p' app/src/main/java/com/rockmusic/app/presentation/RockMusicExperience.kt | nl -ba -v560
echo '--- related search ---'
rg -n "onPlayAll|Play all|results|LaunchedEffect|UnifiedHomeLibrary|LocalTrack|search|Play all" app/src/main/java/com/rockmusic/app/presentation/RockMusicExperience.ktRepository: Sayanthrock-Developer/Rock-music Length of output: 499 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo '--- relevant lines 560-710 ---'
awk 'NR>=560 && NR<=710 { printf ("%6d\t%s\n", NR, $0) }' app/src/main/java/com/rockmusic/app/presentation/RockMusicExperience.kt
echo '--- related search ---'
rg -n "onPlayAll|Play all|results|LaunchedEffect|UnifiedHomeLibrary|LocalTrack|search|Play all" app/src/main/java/com/rockmusic/app/presentation/RockMusicExperience.kt
echo '--- outline ---'
ast-grep outline app/src/main/java/com/rockmusic/app/presentation/RockMusicExperience.kt || trueRepository: Sayanthrock-Developer/Rock-music Length of output: 9983 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo '--- inspect playAll implementation ---'
fd -a 'RockMusicExperienceViewModel.kt|*ViewModel*.kt|*Presentation*.kt' . | sed -n '1,80p'
rg -n "fun .*playAll|playAll\\s*=|fun .*Search|onSearch|playAll\\(" . -g '*.kt'
echo '--- read candidate files ---'
for f in $(fd 'RockMusicExperienceViewModel.kt|.*ViewModel.*\\.kt' . | sed -n '1,20p'); do
echo "---- $f ----"
wc -l "$f"
sed -n '1,180p' "$f"
doneRepository: Sayanthrock-Developer/Rock-music Length of output: 585 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo '--- locate files ---'
fd 'RockMusicExperienceViewModel.kt|.*ViewModel.*\.kt|.*Presentation.*\.kt' . | sed -n '1,80p'
echo '--- search playAll and search actions ---'
rg -n -n "fun .*playAll|playAll\\s*=|fun .*Search|onSearch|playAll\\(" . -g '*.kt' || true
echo '--- read candidate files ---'
while IFS= read -r f; do
echo "---- $f ----"
wc -l "$f"
sed -n '1,220p' "$f"
done < <(fd 'RockMusicExperienceViewModel.kt|.*ViewModel.*\.kt|.*Presentation.*\.kt' . | sed -n '1,20p')Repository: Sayanthrock-Developer/Rock-music Length of output: 3621 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo '--- MainViewModel playAll implementation ---'
awk 'NR>=240 && NR<=290 { printf ("%6d\t%s\n", NR, $0) }' app/src/main/java/com/rockmusic/app/presentation/MainViewModel.kt
echo '--- RockMusicRoot library composition ---'
awk 'NR>=440 && NR<=510 { printf ("%6d\t%s\n", NR, $0) }' app/src/main/java/com/rockmusic/app/presentation/RockMusicRoot.kt
echo '--- stable programmatic check for stale-result behavior ---'
python3 - <<'PY'
from pathlib import Path
p = Path('app/src/main/java/com/rockmusic/app/presentation/RockMusicExperience.kt')
s = p.read_text()
checks = {
'debounce_before_filter': 'delay(300)' in s and 'LaunchedEffect(tracks, query)' in s,
'publish_after_filter': 'results = withContext(Dispatchers.Default)' in s and 'UnifiedHomeLibrary.localTracks(tracks, query, UnifiedHomeSource.SONGS)' in s,
'play_uses_current_results': 'TextButton(onClick = { onPlayAll(results) })' in s,
'no_running_state': 'var isRunning' not in s and 'var pending' not in s,
}
for name, ok in checks.items():
print(f'{name}={ok}')
if not all(checks.values()):
print('CHECKS_FAILED')
PYRepository: Sayanthrock-Developer/Rock-music Length of output: 6085 Do not publish library search results before filtering completes.
🤖 Prompt for AI Agents |
||
| } | ||
|
Comment on lines
+607
to
612
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: The library now starts with an empty Severity Level: Major
|
||
|
|
||
| LazyColumn( | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
visibleTracks initialises as empty list, causing a brief flash of empty-state UI on first load before the 300ms debounce fires
Initialising
visibleTracks(andresultsinExperienceLibrary) asemptyList()means that on first composition — before the 300msLaunchedEffectdelay completes — the UI will briefly show the empty-state message ("No imported songs match…" or "Your library is empty") even whenstate.tracksis already populated. This is a regression from the previousremember(…)approach which computed synchronously.Consider seeding the initial value synchronously (e.g.
remember { UnifiedHomeLibrary.localTracks(state.tracks, query, source) }or usingnullas a sentinel to distinguish "not yet computed" from "genuinely empty"), so the correct list is shown immediately on first render.Why did I show this?
Category: bug
Comment Quality: high
Based on general best practices