diff --git a/android/app/src/main/kotlin/com/novasonic/app/MainActivity.kt b/android/app/src/main/kotlin/com/novasonic/app/MainActivity.kt index 4e554c4..d994565 100644 --- a/android/app/src/main/kotlin/com/novasonic/app/MainActivity.kt +++ b/android/app/src/main/kotlin/com/novasonic/app/MainActivity.kt @@ -206,10 +206,13 @@ class MainActivity : AppCompatActivity(), MusicService.StateListener { ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED -> return - // System won't show the dialog again after one denial — send user to settings. + // System won't show the dialog again after one denial — send user to settings once. !ActivityCompat.shouldShowRequestPermissionRationale( this, Manifest.permission.POST_NOTIFICATIONS - ) && _notifPermissionAskedBefore() -> openNotificationSettings() + ) && _notifPermissionAskedBefore() && !_notifSettingsShownBefore() -> { + markNotifSettingsShown() + openNotificationSettings() + } else -> { markNotifPermissionAsked() @@ -225,9 +228,10 @@ class MainActivity : AppCompatActivity(), MusicService.StateListener { ) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode == 42 && - grantResults.firstOrNull() == PackageManager.PERMISSION_DENIED + grantResults.firstOrNull() == PackageManager.PERMISSION_DENIED && + !_notifSettingsShownBefore() ) { - // Denied — open settings so the user can flip the toggle themselves. + markNotifSettingsShown() openNotificationSettings() } } @@ -247,4 +251,11 @@ class MainActivity : AppCompatActivity(), MusicService.StateListener { private fun markNotifPermissionAsked() = getSharedPreferences("ns_prefs", MODE_PRIVATE).edit() .putBoolean("notif_asked", true).apply() + + private fun _notifSettingsShownBefore() = + getSharedPreferences("ns_prefs", MODE_PRIVATE).getBoolean("notif_settings_shown", false) + + private fun markNotifSettingsShown() = + getSharedPreferences("ns_prefs", MODE_PRIVATE).edit() + .putBoolean("notif_settings_shown", true).apply() } diff --git a/src/components.js b/src/components.js index 482a14d..3ffeed2 100644 --- a/src/components.js +++ b/src/components.js @@ -55,11 +55,13 @@ export function makeSongItem(s, idx, list, { noArtistLink = false, noAlbumLink =
+
`; const btns = el.querySelectorAll('.icon-btn'); btns[0].onclick = (e) => { e.stopPropagation(); toggleStar(s, btns[0]); }; btns[1].onclick = (e) => { e.stopPropagation(); dlSongLocal(s); }; + btns[2].onclick = (e) => { e.stopPropagation(); showCtxMenu(e, s, list, idx); }; el.onclick = () => playQueue(list, idx); el.addEventListener('contextmenu', e => { e.preventDefault(); showCtxMenu(e, s, list, idx); }); return el; diff --git a/src/views.js b/src/views.js index 75b54f4..03056c8 100644 --- a/src/views.js +++ b/src/views.js @@ -735,16 +735,10 @@ export async function doLocalSearch(q) { s.appendChild(g); el.appendChild(s); } if(songs.length) { - const s = mkSection('Titel'); - const g = document.createElement('div'); g.className = 'scroll-row'; - songs.forEach((so,i) => { - const cv = coverUrl(so.coverArt, 256); - const c = makeCard(so.title, so.artist||'', cv, '🎵'); - c.querySelector('.play-btn').onclick = (e) => { e.stopPropagation(); playQueue(songs, i); }; - c.onclick = () => playQueue(songs, i); - g.appendChild(c); - }); - s.appendChild(g); el.appendChild(s); + const sec = mkSection('Titel'); + const list = document.createElement('div'); list.className = 'song-list'; + songs.forEach((so,i) => list.appendChild(makeSongItem(so, i, songs))); + sec.appendChild(list); el.appendChild(sec); } } catch(e) { el.innerHTML = `

${e.message}

`; } } diff --git a/styles.css b/styles.css index 7e4cb68..db3204e 100644 --- a/styles.css +++ b/styles.css @@ -189,6 +189,7 @@ nav{flex:1;overflow-y:auto;padding:4px 10px} .song-dur{font-size:11px;color:var(--text3);font-family:var(--mono)} .song-actions{display:flex;gap:2px;opacity:0;transition:opacity .15s} .song-item:hover .song-actions{opacity:1} +@media (hover:none){.song-actions{opacity:1}} /* ── PLAYLIST DRAG & DROP ── */ .song-list.pl-draggable .song-item{grid-template-columns:18px 32px 44px 1fr auto} .pl-drag-handle{display:flex;align-items:center;justify-content:center;color:var(--text3);opacity:0;cursor:grab;transition:opacity .15s;touch-action:none}