From 0ad15ef98f2e3d3464e20297d658a52e4f62ead6 Mon Sep 17 00:00:00 2001 From: topminipie <145812405+topminipie@users.noreply.github.com> Date: Wed, 21 Feb 2024 14:46:05 +0000 Subject: [PATCH 01/82] ci: update actions --- .github/workflows/ci.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a91674a9..b65a8452 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,23 +17,23 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v1 + uses: actions/checkout@v4 - name: Validate Gradle Wrapper - uses: gradle/wrapper-validation-action@v1 + uses: gradle/wrapper-validation-action@v2 - name: Setup JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: - distribution: 'temurin' java-version: 17 + distribution: "temurin" cache: "gradle" - name: Build APK run: bash ./gradlew assembleDebug --stacktrace - name: Upload APK - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: app path: app/build/outputs/apk/debug/*.apk From 06fa609d0e47528e4c8f799f32af9ddde61be1e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?O=C4=9Fuz=20Ersen?= Date: Sun, 4 Feb 2024 08:30:02 +0000 Subject: [PATCH 02/82] Translated using Weblate (Turkish) Currently translated at 100.0% (85 of 85 strings) Translation: You Apps/Vibe You Translate-URL: https://hosted.weblate.org/projects/you-apps/vibe-you/tr/ --- app/src/main/res/values-tr/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 21ceff92..a9e53d40 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -82,4 +82,6 @@ Tüm şarkılar kütüphaneye eklendi Tüm şarkıları kütüphaneye ekle Piped Music + Özel örnek + Arama geçmişini devre dışı bırak \ No newline at end of file From 055d2ca03c56b34e71b9ef7ca03bcc7c75eb440e Mon Sep 17 00:00:00 2001 From: brochard Date: Sun, 11 Feb 2024 17:25:41 +0000 Subject: [PATCH 03/82] Translated using Weblate (French) Currently translated at 100.0% (85 of 85 strings) Translation: You Apps/Vibe You Translate-URL: https://hosted.weblate.org/projects/you-apps/vibe-you/fr/ --- app/src/main/res/values-fr/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index b5d88d72..93282b1b 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -83,4 +83,5 @@ Intensité Supprimer une liste de lecture et les chansons Effacer la liste de lecture + Désactiver l\'historique de recherche \ No newline at end of file From e9ec3c7b5b0490bb37a9a9da5355f9bc01828a44 Mon Sep 17 00:00:00 2001 From: Pere O Date: Mon, 12 Feb 2024 23:37:39 +0100 Subject: [PATCH 04/82] Added translation using Weblate (Catalan) --- app/src/main/res/values-ca/strings.xml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 app/src/main/res/values-ca/strings.xml diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml new file mode 100644 index 00000000..a6b3daec --- /dev/null +++ b/app/src/main/res/values-ca/strings.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file From d16f9b546d1e1bb543541b86ce60ad9c8ba10b50 Mon Sep 17 00:00:00 2001 From: Pere O Date: Mon, 12 Feb 2024 22:38:12 +0000 Subject: [PATCH 05/82] Translated using Weblate (Catalan) Currently translated at 2.3% (2 of 85 strings) Translation: You Apps/Vibe You Translate-URL: https://hosted.weblate.org/projects/you-apps/vibe-you/ca/ --- app/src/main/res/values-ca/strings.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index a6b3daec..3e273ef3 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -1,2 +1,4 @@ - \ No newline at end of file + + Configuració + \ No newline at end of file From 4afa50e2c3ada6566d0626fb46d297a83a647986 Mon Sep 17 00:00:00 2001 From: Pere O Date: Tue, 13 Feb 2024 14:53:08 +0000 Subject: [PATCH 06/82] Translated using Weblate (Catalan) Currently translated at 100.0% (85 of 85 strings) Translation: You Apps/Vibe You Translate-URL: https://hosted.weblate.org/projects/you-apps/vibe-you/ca/ --- app/src/main/res/values-ca/strings.xml | 83 ++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index 3e273ef3..275adf0c 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -1,4 +1,87 @@ Configuració + Cançons + Versió, Contacte + Preferits + Posa a la cua + Reprodueix la cançó + Suprimeix la cançó + Configuració + Repetició desactivada + Repeteix tot + Repeteix-ne una + Canvia el servidor + Fes una còpia de seguretat de la llista de cançons o restaura una còpia. + Còpia de seguretat + Crea un fitxer de còpia de seguretat + Restaura un fitxer de còpia de seguretat + Restaura + Caràtula de l\'àlbum + Foto de l\'artista + Seleccioneu el servidor + Mostra la cua + Artista + Àlbums + Cançons recents + Tanca la cerca + Piped Music + Música local + Artistes + D\'acord + Canvia la memòria cau de la música + Límit de memòria cau de la música + Il·limitat + Ordre de classificació + Cancel·la + Invertit + Aspecte + Personalitza l\'aspecte per adaptar-la a les teves necessitats. + Notificació de miniatura alternativa + Utilitza el color d\'accent del sistema/tema com a miniatura alternativa. + Afegeix-ho a la biblioteca + S\'han afegit totes les cançons a la biblioteca + Afegeix-ho tot a la biblioteca + Neteja la cua + Quant a + README + Consulteu el repositori i el README + Últim llançament + Versió actual + Tiquet GitHub + Envieu informes d\'errors i peticions de funcions + Neteja la cerca + Cerca cançons + Cerca una cançó + Reprodueix la següent + S\'està reproduint + Opcions de la cançó + Tanca el reproductor + Caràtula de l\'àlbum + Pausa + Reprodueix + Salta la següent + Elimina l\'element de la cua + Tanca la cua + Cua del reproductor + Aleatori + Alguna cosa ha anat malament + Configuració de xarxa + Canvieu el servidor per solucionar problemes de reproducció + Còpia de seguretat i restauració + Inicia sessió + Nom d\'usuari + Contrasenya + Velocitat de reproducció + Tons + Reprodueix-ho tot + Llistes de reproducció + Instància personalitzada + URL de l\'API + URL del servidor intermediari d\'imatges + URL no vàlid + Suprimeix la llista de reproducció + Suprimeix la llista i les cançons + Neteja la llista + Desactiva l\'historial de cerca \ No newline at end of file From 3978bfb3851857e94e4137d7724f83bf753eb4bc Mon Sep 17 00:00:00 2001 From: Nitin Khalia Date: Wed, 14 Feb 2024 16:58:38 +0000 Subject: [PATCH 07/82] Translated using Weblate (Hindi) Currently translated at 100.0% (85 of 85 strings) Translation: You Apps/Vibe You Translate-URL: https://hosted.weblate.org/projects/you-apps/vibe-you/hi/ --- app/src/main/res/values-hi/strings.xml | 86 +++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index cc08f27e..f04db5d4 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -1,7 +1,87 @@ सेटिंग्स - मुझे पढ़ें - गीत - के बारे में + README + गाने + बारे में + प्लेलिस्ट + प्लेलिस्ट हटाएँ + प्लेलिस्ट और गाने हटाएं + प्लेलिस्ट हटाएं + कस्टम इंस्टेंस + असामान्य URL + GitHub मुद्दा + बग रिपोर्ट और सुविधा अनुरोध सबमिट करें + पसंदीदा + कतार में जोड़ें + गाना बजायें + गीत हटाएं + खोज साफ़ करें + गाने खोजें + कोई गाना खोजें + अगला बजायें + सेटिंग्स + सभी दोहराएं + एक दोहराएँ + अभी बज रहा है + गाने के विकल्प + गाने की एल्बम कला + विराम + बजायें + अगला छोड़ें + कतार से आइटम हटाएँ + कतार बंद करें + प्लेयर कतार + नेटवर्क सेटिंग्स + सर्वर बदलें + एक बैकअप फ़ाइल बनाएँ + पिछली बैकअप फ़ाइल पुनर्स्थापित करें + एल्बम कला + कलाकार का अवतार + सर्वर चुनें + कतार दिखाएँ + कलाकार + लॉग इन करें + उपयोक्तानाम + हाल के गाने + खोज बंद करें + Piped संगीत + स्थानीय संगीत + एल्बम + कलाकार + ठीक है + संगीत कैशे आकार बदलें + असीमित + पिच + सभी को बजाएं + क्रमबद्ध करें + रद्द करें + उलटा + दिखावट सेटिंग्स + लाइब्रेरी में जोड़ें + सभी गाने लाइब्रेरी में जोड़ दिए गए + सभी गाने लाइब्रेरी में जोड़ें + कतार साफ़ करें + खोज इतिहास अक्षम करें + रिपॉजिटरी और README की जाँच करें + प्लेयर बंद करें + मिश्रण + प्लेबैक समस्याओं को ठीक करने के लिए सर्वर बदलें + डेटाबेस पुनर्स्थापित करें + अपनी आवश्यकताओं के अनुरूप दिखावट को अनुकूलित करें। + Api Url + नवीनतम रिलीज + वर्तमान संस्करण + दोहराएँ बंद + कुछ गलत हो गया + बैकअप और पुनर्स्थापना + अपनी गीत सूची का बैकअप लें या पुराना बैकअप पुनर्स्थापित करें। + बैकअप डेटाबेस + पासवर्ड + सूचना थंबनेल फ़ॉलबैक + यदि कोई नहीं है तो सूचना थंबनेल के रूप में सिस्टम/थीम एक्सेंट रंग का उपयोग करके वापस आएं। + छवि प्रॉक्सी URL + संस्करण, संपर्क करें + संगीत कैशे सीमा + प्लेबैक गति \ No newline at end of file From d02f0ea7a1c02448311034b439ced7263eb42958 Mon Sep 17 00:00:00 2001 From: cat <158170307+cultcats@users.noreply.github.com> Date: Sun, 17 Mar 2024 17:00:10 +0100 Subject: [PATCH 08/82] Added translation using Weblate (Danish) --- app/src/main/res/values-da/strings.xml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 app/src/main/res/values-da/strings.xml diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml new file mode 100644 index 00000000..a6b3daec --- /dev/null +++ b/app/src/main/res/values-da/strings.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file From 922e3e2ff3a73019b6643769695733a9eeb5391e Mon Sep 17 00:00:00 2001 From: Software In Interlingua Date: Sun, 17 Mar 2024 20:59:56 +0000 Subject: [PATCH 09/82] Translated using Weblate (Interlingua) Currently translated at 100.0% (85 of 85 strings) Translation: You Apps/Vibe You Translate-URL: https://hosted.weblate.org/projects/you-apps/vibe-you/ia/ --- app/src/main/res/values-ia/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values-ia/strings.xml b/app/src/main/res/values-ia/strings.xml index d110e7dc..082952a6 100644 --- a/app/src/main/res/values-ia/strings.xml +++ b/app/src/main/res/values-ia/strings.xml @@ -67,7 +67,7 @@ Repetition disactivate Musica local Adder al cauda - Problemas in GitHun + Problemas in GitHub Addeva tote le cantos al bibliotheca Face un copia de securitate de tu lista de cantos o restaura un copia de securitate ancian. Clauder le recerca From 42d3e3fa157d7ca293005e83793259c45d73ea88 Mon Sep 17 00:00:00 2001 From: cat <158170307+cultcats@users.noreply.github.com> Date: Sun, 17 Mar 2024 16:03:31 +0000 Subject: [PATCH 10/82] Translated using Weblate (Danish) Currently translated at 96.4% (82 of 85 strings) Translation: You Apps/Vibe You Translate-URL: https://hosted.weblate.org/projects/you-apps/vibe-you/da/ --- app/src/main/res/values-da/strings.xml | 84 +++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml index a6b3daec..b8ab139e 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -1,2 +1,84 @@ - \ No newline at end of file + + Afspil Sang + Fjern Sang + README + Tjek Repository og README + Seneste Udgivelse + Indsend fejlrapporter og ønsket funktioner + Version, Kontakt + Favoritter + Føj til Kø + Ryd Søgning + Gentag Alle + Gentag Én + Afspiller Nu + Sangmuligheder + Luk Afspiller + Afspil + Spring Næste Over + Fjern Element Fra Kø + Afspillerkø + Bland + Netværksindstillinger + Skift server + Sikkerhedskopiér og Gendan + Sikkerhedskopiér din sangliste, eller gendan en gammel sikkerhedskopi. + Sikkerhedskopiér Database + Gendan Database + Albumcover + Kunstner-avatar + Vis Kø + Brugernavn + Adgangskode + Nylige Sange + Luk Søgning + Piped Musik + Lokal Musik + Album + Ændr størrelse på musikcache + Grænse for musikcache + Afspilningshastighed + Tonehøjde + Annullér + Udseende Indstillinger + Tilpas udseendet efter dine behov. + Gå tilbage til systemets/temaets accentfarve som notifikationsminiature, hvis der ikke er nogen. + Notifikationsminiature-fallback + Føj til bibliotek + Tilføjede alle sangene til biblioteket + Føj alle sange til biblioteket + Ryd Kø + Playlister + Ryd Playliste + Indstillinger + Sange + Om + Nuværende Version + Github Issue + Søg efter en Sang + Søg Sange + Afspil Næste + Indstillinger + Luk Kø + Noget Gik Galt + Skift server for at løse afspilningsproblemer + Opret en sikkerhedskopi-fil + Gendan en tidligere sikkerhedskopi-fil + Vælg Server + Kunstner + Log ind + Kunstnere + OK + Ubegrænset + Afspil alle + Omvendt + Brugerdefineret instans + Ugyldig URL + Slet Playliste + Slet playliste og sange + Deaktivér søgehistorik + Gentag Slået Fra + Sangens Albumcover + Sæt på Pause + \ No newline at end of file From c19dbd14c87e0930b9725308813a04aed42277c3 Mon Sep 17 00:00:00 2001 From: Michael Moroni Date: Mon, 25 Mar 2024 09:45:12 +0100 Subject: [PATCH 11/82] Added translation using Weblate (Italian) --- app/src/main/res/values-it/strings.xml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 app/src/main/res/values-it/strings.xml diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml new file mode 100644 index 00000000..a6b3daec --- /dev/null +++ b/app/src/main/res/values-it/strings.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file From 79b98bc113f7422d174d83ef4f603ea4b92c8b57 Mon Sep 17 00:00:00 2001 From: Michael Moroni Date: Mon, 25 Mar 2024 08:45:35 +0000 Subject: [PATCH 12/82] Translated using Weblate (Italian) Currently translated at 97.6% (83 of 85 strings) Translation: You Apps/Vibe You Translate-URL: https://hosted.weblate.org/projects/you-apps/vibe-you/it/ --- app/src/main/res/values-it/strings.xml | 85 +++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index a6b3daec..9f3e7749 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -1,2 +1,85 @@ - \ No newline at end of file + + Brani + Informazioni + Controlla il codice sorgente e il LEGGIMI + Ultima pubblicazione + Attuale versione + Segnalazioni su GitHub + Versione, Contatti + Aggiungi alla coda + Riproduci brano + Rimuovi brano + Rimuovi ricerche + Cerca brani + Riproduci successivo + Impostazioni + Chiudi coda + Coda del riproduttore + Mischia + Cambia server per sistemare i problemi di riproduzione + Cambia server + Backup e ripristino + Ripristina un vecchio file di backup + Database di ripristino + Copertina dell\'album + Avatar dell\'artista + Mostra coda + Artista + Login + Nome utente + Password + Brani recenti + Chiudi ricerca + Musica su Piped + Musica locale + Album + Artisti + Limite della cache per la musica + Illimitato + Riproduci tutto + Ordina + Annulla + Inverso + Impostazioni di aspetto + Fallback per l\'immagine nella notifica + Aggiunti tutti i brani alla libreria + Rimuovi coda + URL non valido + Rimuovi playlist e brani + Svuota playlist + Disabilita la cronologia delle ricerche + Impostazioni + LEGGIMI + Invia segnalazioni di errori e richieste di funzionalità + Preferiti + Cerca un brano + Non ripetere + Ripeti tutti + Ripeti uno + In riproduzione + Opzioni del brano + Chiudi riproduttore + Copertina dell\'album del brano + Pausa + Riproduci + Salta prossimo + Rimuovi brano dalla coda + Qualcosa è andato storto + Impostazioni di rete + Fai il backup della lista dei tuoi brani o fai il ripristino da un vecchio backup. + Database del backup + Crea un file di backup + Seleziona server + Ok + Cambia la dimensione della cache per la musica + Velocità di riproduzione + Personalizza l\'aspetto per soddisfare le tue necessità. + Aggiungi alla libreria + Aggiunti tutti i brani alla libreria + Playlist + Istanza personalizzata + URL delle API + URL proxy delle immagini + Rimuovi playlist + \ No newline at end of file From e1500c5f335b590eb5d3ad9ef6008ec1c9ad8ba1 Mon Sep 17 00:00:00 2001 From: Giovanni Donisi Date: Tue, 26 Mar 2024 19:56:26 +0000 Subject: [PATCH 13/82] Translated using Weblate (Italian) Currently translated at 100.0% (85 of 85 strings) Translation: You Apps/Vibe You Translate-URL: https://hosted.weblate.org/projects/you-apps/vibe-you/it/ --- app/src/main/res/values-it/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 9f3e7749..94fd984b 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -82,4 +82,6 @@ URL delle API URL proxy delle immagini Rimuovi playlist + Tono + Torna all\'utilizzo del colore di accento del sistema/tema come miniatura di notifica se non ce n\'è uno. \ No newline at end of file From 2e373f06b97e05eaa069e9704fd1c689ced0f95b Mon Sep 17 00:00:00 2001 From: Bnyro Date: Tue, 2 Apr 2024 17:04:17 +0200 Subject: [PATCH 14/82] feat: respect track number on local playback (closes #88) --- .idea/migrations.xml | 10 ++++++++++ .../java/app/suhasdissa/vibeyou/backend/data/Song.kt | 3 ++- .../vibeyou/backend/repository/LocalMusicRepository.kt | 8 ++++++-- 3 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 .idea/migrations.xml diff --git a/.idea/migrations.xml b/.idea/migrations.xml new file mode 100644 index 00000000..f8051a6f --- /dev/null +++ b/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/java/app/suhasdissa/vibeyou/backend/data/Song.kt b/app/src/main/java/app/suhasdissa/vibeyou/backend/data/Song.kt index bd6cfa8a..dbcec2ed 100644 --- a/app/src/main/java/app/suhasdissa/vibeyou/backend/data/Song.kt +++ b/app/src/main/java/app/suhasdissa/vibeyou/backend/data/Song.kt @@ -13,7 +13,8 @@ data class Song( val artistId: Long? = null, val isLocal: Boolean = false, val creationDate: Long? = null, - val dateAdded: Long? = null + val dateAdded: Long? = null, + val trackNumber: Long? = null ) { fun toggleLike(): Song { return copy( diff --git a/app/src/main/java/app/suhasdissa/vibeyou/backend/repository/LocalMusicRepository.kt b/app/src/main/java/app/suhasdissa/vibeyou/backend/repository/LocalMusicRepository.kt index 6fdc52e2..3da40731 100644 --- a/app/src/main/java/app/suhasdissa/vibeyou/backend/repository/LocalMusicRepository.kt +++ b/app/src/main/java/app/suhasdissa/vibeyou/backend/repository/LocalMusicRepository.kt @@ -47,7 +47,8 @@ class LocalMusicRepository( MediaStore.Audio.Media.ALBUM_ID, MediaStore.Audio.Media.ARTIST_ID, MediaStore.Audio.Media.DATE_MODIFIED, - MediaStore.Audio.Media.DATE_ADDED + MediaStore.Audio.Media.DATE_ADDED, + MediaStore.Audio.Media.CD_TRACK_NUMBER ) val sortOrder = "${MediaStore.Audio.Media.TITLE} ASC" @@ -73,6 +74,7 @@ class LocalMusicRepository( MediaStore.Audio.Media.DATE_MODIFIED ) val dateAddedColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATE_ADDED) + val trackNumberColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.CD_TRACK_NUMBER) while (cursor.moveToNext()) { val id = cursor.getLong(idColumn) @@ -108,7 +110,8 @@ class LocalMusicRepository( artistId = cursor.getLong(artistIdColumn), isLocal = true, creationDate = cursor.getLong(creationDateColumn), - dateAdded = cursor.getLong(dateAddedColumn) + dateAdded = cursor.getLong(dateAddedColumn), + trackNumber = cursor.getLong(trackNumberColumn) ) ) } @@ -258,6 +261,7 @@ class LocalMusicRepository( suspend fun getAlbumInfo(albumId: Long): List { return getAllSongs() .filter { it.albumId == albumId } + .sortedBy { it.trackNumber } } suspend fun getArtistInfo(artistText: String): List { From b759ef84dccbefbf339d60205b43c82d445859eb Mon Sep 17 00:00:00 2001 From: Bnyro Date: Tue, 2 Apr 2024 17:06:31 +0200 Subject: [PATCH 15/82] fix: instances dialog has edgy ripple effect --- .../suhasdissa/vibeyou/ui/components/InstanceSelectDialog.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/app/suhasdissa/vibeyou/ui/components/InstanceSelectDialog.kt b/app/src/main/java/app/suhasdissa/vibeyou/ui/components/InstanceSelectDialog.kt index 17f4a6ea..35d5da33 100644 --- a/app/src/main/java/app/suhasdissa/vibeyou/ui/components/InstanceSelectDialog.kt +++ b/app/src/main/java/app/suhasdissa/vibeyou/ui/components/InstanceSelectDialog.kt @@ -64,13 +64,13 @@ fun InstanceSelectDialog( Row( Modifier .fillMaxWidth() + .clip(RoundedCornerShape(12.dp)) .clickable(onClick = { view.playSoundEffect(SoundEffectConstants.CLICK) selectedInstance = item onSelectionChange(item) onDismissRequest.invoke() }) - .clip(RoundedCornerShape(20.dp)) .padding(horizontal = 6.dp, vertical = 12.dp), verticalAlignment = Alignment.CenterVertically ) { From 7a4f43d1fb552f56f2e33574ff678bd148f0c639 Mon Sep 17 00:00:00 2001 From: Bnyro Date: Fri, 5 Apr 2024 21:38:04 +0200 Subject: [PATCH 16/82] feat: support for autoplay via hyperpipe --- .../vibeyou/backend/api/HyperpipeApi.kt | 18 ++++++++ .../backend/models/hyper/MediaSession.kt | 9 ++++ .../backend/models/hyper/NextSongsResponse.kt | 10 +++++ .../vibeyou/backend/models/hyper/Song.kt | 34 +++++++++++++++ .../vibeyou/backend/models/hyper/Thumbnail.kt | 10 +++++ .../repository/PipedMusicRepository.kt | 18 ++++---- .../vibeyou/backend/services/PlayerService.kt | 18 ++++++++ .../screens/settings/NetworkSettingsScreen.kt | 8 ++++ .../ui/screens/settings/TextFieldPref.kt | 42 +++++++++++++++++++ .../java/app/suhasdissa/vibeyou/utils/Pref.kt | 1 + .../vibeyou/utils/RetrofitHelper.kt | 19 +++++++-- app/src/main/res/values/strings.xml | 1 + 12 files changed, 176 insertions(+), 12 deletions(-) create mode 100644 app/src/main/java/app/suhasdissa/vibeyou/backend/api/HyperpipeApi.kt create mode 100644 app/src/main/java/app/suhasdissa/vibeyou/backend/models/hyper/MediaSession.kt create mode 100644 app/src/main/java/app/suhasdissa/vibeyou/backend/models/hyper/NextSongsResponse.kt create mode 100644 app/src/main/java/app/suhasdissa/vibeyou/backend/models/hyper/Song.kt create mode 100644 app/src/main/java/app/suhasdissa/vibeyou/backend/models/hyper/Thumbnail.kt create mode 100644 app/src/main/java/app/suhasdissa/vibeyou/ui/screens/settings/TextFieldPref.kt diff --git a/app/src/main/java/app/suhasdissa/vibeyou/backend/api/HyperpipeApi.kt b/app/src/main/java/app/suhasdissa/vibeyou/backend/api/HyperpipeApi.kt new file mode 100644 index 00000000..e5f3680a --- /dev/null +++ b/app/src/main/java/app/suhasdissa/vibeyou/backend/api/HyperpipeApi.kt @@ -0,0 +1,18 @@ +package app.suhasdissa.vibeyou.backend.api + +import app.suhasdissa.vibeyou.backend.models.hyper.NextSongsResponse +import app.suhasdissa.vibeyou.utils.Pref +import okhttp3.HttpUrl.Companion.toHttpUrlOrNull +import retrofit2.http.GET +import retrofit2.http.Path + +interface HyperpipeApi { + @GET("https://{instance}/next/{videoId}") + suspend fun getNext( + @Path("instance") instance: String = Pref.sharedPreferences + .getString(Pref.hyperpipeApiUrlKey, "") + ?.toHttpUrlOrNull() + ?.host.orEmpty(), + @Path("videoId") videoId: String + ): NextSongsResponse +} \ No newline at end of file diff --git a/app/src/main/java/app/suhasdissa/vibeyou/backend/models/hyper/MediaSession.kt b/app/src/main/java/app/suhasdissa/vibeyou/backend/models/hyper/MediaSession.kt new file mode 100644 index 00000000..18e86948 --- /dev/null +++ b/app/src/main/java/app/suhasdissa/vibeyou/backend/models/hyper/MediaSession.kt @@ -0,0 +1,9 @@ +package app.suhasdissa.vibeyou.backend.models.hyper + +import kotlinx.serialization.Serializable + +@Serializable +data class MediaSession( + val album: String, + val thumbnails: List +) \ No newline at end of file diff --git a/app/src/main/java/app/suhasdissa/vibeyou/backend/models/hyper/NextSongsResponse.kt b/app/src/main/java/app/suhasdissa/vibeyou/backend/models/hyper/NextSongsResponse.kt new file mode 100644 index 00000000..20540e87 --- /dev/null +++ b/app/src/main/java/app/suhasdissa/vibeyou/backend/models/hyper/NextSongsResponse.kt @@ -0,0 +1,10 @@ +package app.suhasdissa.vibeyou.backend.models.hyper + +import kotlinx.serialization.Serializable + +@Serializable +data class NextSongsResponse( + val lyricsId: String, + val mediaSession: MediaSession, + val songs: List +) \ No newline at end of file diff --git a/app/src/main/java/app/suhasdissa/vibeyou/backend/models/hyper/Song.kt b/app/src/main/java/app/suhasdissa/vibeyou/backend/models/hyper/Song.kt new file mode 100644 index 00000000..bd93d064 --- /dev/null +++ b/app/src/main/java/app/suhasdissa/vibeyou/backend/models/hyper/Song.kt @@ -0,0 +1,34 @@ +package app.suhasdissa.vibeyou.backend.models.hyper + +import androidx.core.net.toUri +import app.suhasdissa.vibeyou.backend.data.Song +import app.suhasdissa.vibeyou.backend.database.entities.SongEntity +import kotlinx.serialization.Serializable + +@Serializable +data class Song( + val id: String, + val subtitle: String, + val thumbnails: List, + val title: String +) { + val asSong: Song get() { + return Song( + id = id, + title = title, + artistsText = subtitle, + durationText = null, + thumbnailUri = thumbnails.maxByOrNull { it.height }?.url?.toUri() + ) + } + + val asSongEntity: SongEntity get() { + return SongEntity( + id = id, + title = title, + artistsText = subtitle, + durationText = null, + thumbnailUrl = thumbnails.maxByOrNull { it.height }?.url + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/app/suhasdissa/vibeyou/backend/models/hyper/Thumbnail.kt b/app/src/main/java/app/suhasdissa/vibeyou/backend/models/hyper/Thumbnail.kt new file mode 100644 index 00000000..2d1fdee2 --- /dev/null +++ b/app/src/main/java/app/suhasdissa/vibeyou/backend/models/hyper/Thumbnail.kt @@ -0,0 +1,10 @@ +package app.suhasdissa.vibeyou.backend.models.hyper + +import kotlinx.serialization.Serializable + +@Serializable +data class Thumbnail( + val height: Int, + val url: String, + val width: Int +) \ No newline at end of file diff --git a/app/src/main/java/app/suhasdissa/vibeyou/backend/repository/PipedMusicRepository.kt b/app/src/main/java/app/suhasdissa/vibeyou/backend/repository/PipedMusicRepository.kt index 2e216ff4..e01dcddb 100644 --- a/app/src/main/java/app/suhasdissa/vibeyou/backend/repository/PipedMusicRepository.kt +++ b/app/src/main/java/app/suhasdissa/vibeyou/backend/repository/PipedMusicRepository.kt @@ -3,6 +3,7 @@ package app.suhasdissa.vibeyou.backend.repository import android.net.Uri import android.util.Log import androidx.core.net.toUri +import androidx.media3.common.MediaItem import app.suhasdissa.vibeyou.backend.data.Album import app.suhasdissa.vibeyou.backend.data.Artist import app.suhasdissa.vibeyou.backend.data.Song @@ -17,6 +18,7 @@ import app.suhasdissa.vibeyou.utils.Pref import app.suhasdissa.vibeyou.utils.RetrofitHelper import app.suhasdissa.vibeyou.utils.asAlbum import app.suhasdissa.vibeyou.utils.asArtist +import app.suhasdissa.vibeyou.utils.asMediaItem import app.suhasdissa.vibeyou.utils.asSong import app.suhasdissa.vibeyou.utils.asSongEntity @@ -25,6 +27,7 @@ class PipedMusicRepository( private val searchDao: SearchDao ) { var pipedApi = RetrofitHelper.createPipedApi() + private val hyperApi = RetrofitHelper.createHyperpipeApi() suspend fun getAudioSource(id: String): Uri? { return runCatching { pipedApi.getStreams(vidId = id) } @@ -34,15 +37,12 @@ class PipedMusicRepository( ?.url ?.toUri() } -// -// suspend fun getRecommendedSongs(id: String): List { -// val relatedSongs = -// pipedApi.getStreams(vidId = id).relatedStreams.slice(0..1).map { -// it.asSong -// } -// songsDao.addSongs(relatedSongs) -// return relatedSongs.map { it.asMediaItem } -// } + + suspend fun getRecommendedSongs(id: String): List { + val relatedSongs = hyperApi.getNext(videoId = id).songs + songsDao.addSongs(relatedSongs.map { it.asSongEntity }) + return relatedSongs.map { it.asSong.asMediaItem } + } suspend fun getPlaylistInfo(playlistId: String): PlaylistInfo = pipedApi.getPlaylistInfo(playlistId = playlistId) diff --git a/app/src/main/java/app/suhasdissa/vibeyou/backend/services/PlayerService.kt b/app/src/main/java/app/suhasdissa/vibeyou/backend/services/PlayerService.kt index 82eec39d..046649ee 100644 --- a/app/src/main/java/app/suhasdissa/vibeyou/backend/services/PlayerService.kt +++ b/app/src/main/java/app/suhasdissa/vibeyou/backend/services/PlayerService.kt @@ -10,6 +10,7 @@ import android.graphics.Rect import android.media.audiofx.LoudnessEnhancer import android.net.Uri import android.os.Handler +import android.util.Log import androidx.annotation.ColorInt import androidx.core.graphics.drawable.toBitmap import androidx.media3.common.AudioAttributes @@ -41,6 +42,7 @@ import androidx.media3.session.MediaSessionService import app.suhasdissa.vibeyou.MellowMusicApplication import app.suhasdissa.vibeyou.utils.DynamicDataSource import app.suhasdissa.vibeyou.utils.Pref +import app.suhasdissa.vibeyou.utils.enqueue import coil.ImageLoader import coil.request.ErrorResult import coil.request.ImageRequest @@ -52,6 +54,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withContext class PlayerService : MediaSessionService(), MediaSession.Callback, Player.Listener { private var mediaSession: MediaSession? = null @@ -218,6 +221,7 @@ class PlayerService : MediaSessionService(), MediaSession.Callback, Player.Liste val url = runBlocking { container.pipedMusicRepository.getAudioSource(videoId) } + appendToQueue(videoId) url?.let { dataSpec.withUri(it).subrange(dataSpec.uriPositionOffset, chunkLength) } ?: error("Stream not found") @@ -226,6 +230,20 @@ class PlayerService : MediaSessionService(), MediaSession.Callback, Player.Liste return DynamicDataSource.Companion.Factory(resolvingDataSource, defaultDataSource) } + private fun appendToQueue(videoId: String) = CoroutineScope(Dispatchers.Main).launch { + // enough other videos left in the queue + if (player.mediaItemCount - player.currentMediaItemIndex > 5) return@launch + + try { + val nextSongs = withContext(Dispatchers.IO) { + container.pipedMusicRepository.getRecommendedSongs(videoId) + } + player.addMediaItems(nextSongs.take(3)) + } catch (e: Exception) { + Log.e("hyperpipe: error fetching next", e.stackTrace.contentToString()) + } + } + @androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class) private fun createMediaSourceFactory(): MediaSource.Factory { return DefaultMediaSourceFactory(createDataSourceFactory()) diff --git a/app/src/main/java/app/suhasdissa/vibeyou/ui/screens/settings/NetworkSettingsScreen.kt b/app/src/main/java/app/suhasdissa/vibeyou/ui/screens/settings/NetworkSettingsScreen.kt index 91dba9e3..5abc6fdf 100644 --- a/app/src/main/java/app/suhasdissa/vibeyou/ui/screens/settings/NetworkSettingsScreen.kt +++ b/app/src/main/java/app/suhasdissa/vibeyou/ui/screens/settings/NetworkSettingsScreen.kt @@ -67,6 +67,14 @@ fun NetworkSettingsScreen() { currentServer = it } } + + item { + TextFieldPref( + key = Pref.hyperpipeApiUrlKey, + defaultValue = "https://hyperpipeapi.onrender.com", + title = stringResource(id = R.string.hyperpipe_api_url) + ) + } } } if (showDialog) { diff --git a/app/src/main/java/app/suhasdissa/vibeyou/ui/screens/settings/TextFieldPref.kt b/app/src/main/java/app/suhasdissa/vibeyou/ui/screens/settings/TextFieldPref.kt new file mode 100644 index 00000000..ac863542 --- /dev/null +++ b/app/src/main/java/app/suhasdissa/vibeyou/ui/screens/settings/TextFieldPref.kt @@ -0,0 +1,42 @@ +package app.suhasdissa.vibeyou.ui.screens.settings + +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.core.content.edit +import app.suhasdissa.vibeyou.utils.Pref + +@Composable +fun TextFieldPref( + key: String, + defaultValue: String, + title: String, + onValueChange: (String) -> Unit = {} +) { + var value by remember { + mutableStateOf(Pref.sharedPreferences.getString(key, defaultValue).orEmpty()) + } + + OutlinedTextField( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 8.dp), + value = value, + onValueChange = { + value = it + Pref.sharedPreferences.edit(true) { putString(key, it) } + onValueChange(it) + }, + label = { + Text(text = title) + } + ) +} \ No newline at end of file diff --git a/app/src/main/java/app/suhasdissa/vibeyou/utils/Pref.kt b/app/src/main/java/app/suhasdissa/vibeyou/utils/Pref.kt index aa446aef..993ab235 100644 --- a/app/src/main/java/app/suhasdissa/vibeyou/utils/Pref.kt +++ b/app/src/main/java/app/suhasdissa/vibeyou/utils/Pref.kt @@ -15,6 +15,7 @@ object Pref { const val latestReverseSongsPrefKey = "LatestReverseSongsPrefKey" const val customPipedInstanceKey = "CustomPipedInstanceKey" const val disableSearchHistoryKey = "DisableSearchHistory" + const val hyperpipeApiUrlKey = "HyperpipeApiUrl" lateinit var sharedPreferences: SharedPreferences diff --git a/app/src/main/java/app/suhasdissa/vibeyou/utils/RetrofitHelper.kt b/app/src/main/java/app/suhasdissa/vibeyou/utils/RetrofitHelper.kt index 1d94aa9d..d6b62af1 100644 --- a/app/src/main/java/app/suhasdissa/vibeyou/utils/RetrofitHelper.kt +++ b/app/src/main/java/app/suhasdissa/vibeyou/utils/RetrofitHelper.kt @@ -1,20 +1,33 @@ package app.suhasdissa.vibeyou.utils +import app.suhasdissa.vibeyou.backend.api.HyperpipeApi import app.suhasdissa.vibeyou.backend.api.PipedApi import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory import kotlinx.serialization.json.Json import okhttp3.MediaType.Companion.toMediaType import retrofit2.Retrofit +import retrofit2.create object RetrofitHelper { - fun createPipedApi(): PipedApi { - val json = Json { ignoreUnknownKeys = true } + val json by lazy { + Json { ignoreUnknownKeys = true } + } + fun createPipedApi(): PipedApi { val retrofit: Retrofit = Retrofit.Builder() .baseUrl("https://pipedapi.kavin.rocks/") .addConverterFactory(json.asConverterFactory("application/json".toMediaType())) .build() - return retrofit.create(PipedApi::class.java) + return retrofit.create() + } + + fun createHyperpipeApi(): HyperpipeApi { + val retrofit = Retrofit.Builder() + .baseUrl("https://hyperpipeapi.onrender.com") + .addConverterFactory(json.asConverterFactory("application/json".toMediaType())) + .build() + + return retrofit.create() } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 776c27e3..2851b2bf 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -85,4 +85,5 @@ Delete playlist and songs Clear Playlist Disable search history + Hyperpipe API URL From 6fdd911ca2add50a438ac40e7a3926854290c2f0 Mon Sep 17 00:00:00 2001 From: Suhas Dissanayake Date: Sat, 6 Apr 2024 11:59:23 +0530 Subject: [PATCH 17/82] fix: malformed base url --- .../java/app/suhasdissa/vibeyou/utils/Pref.kt | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/app/suhasdissa/vibeyou/utils/Pref.kt b/app/src/main/java/app/suhasdissa/vibeyou/utils/Pref.kt index aa446aef..c8022afb 100644 --- a/app/src/main/java/app/suhasdissa/vibeyou/utils/Pref.kt +++ b/app/src/main/java/app/suhasdissa/vibeyou/utils/Pref.kt @@ -21,41 +21,42 @@ object Pref { val pipedInstances = listOf( PipedInstance( "kavin.rocks", - "https://pipedapi.kavin.rocks/" + "https://pipedapi.kavin.rocks" ), PipedInstance( "lunar.icu", - "https://piped-api.lunar.icu/" + "https://piped-api.lunar.icu" ), PipedInstance( "whatever.social", - "https://watchapi.whatever.social/" + "https://watchapi.whatever.social" ), PipedInstance( "tokhmi.xyz", - "https://pipedapi.tokhmi.xyz/" + "https://pipedapi.tokhmi.xyz" ), PipedInstance( "mha.fi", - "https://api-piped.mha.fi/" + "https://api-piped.mha.fi" ), PipedInstance( "garudalinux.org", - "https://piped-api.garudalinux.org/" + "https://piped-api.garudalinux.org" ), PipedInstance( "piped.yt", - "https://api.piped.yt/" + "https://api.piped.yt" ) ) - val currentInstance get() = run { - runCatching { - val instanceJsonStr = sharedPreferences.getString(pipedInstanceKey, "").orEmpty() - return@run json.decodeFromString(instanceJsonStr) + val currentInstance + get() = run { + runCatching { + val instanceJsonStr = sharedPreferences.getString(pipedInstanceKey, "").orEmpty() + return@run json.decodeFromString(instanceJsonStr) + } + pipedInstances.first() } - pipedInstances.first() - } private val json = Json { ignoreUnknownKeys = true } From f0d801fe11dabb7a0055d1ffcb57595e085629e6 Mon Sep 17 00:00:00 2001 From: Suhas Dissanayake Date: Sat, 6 Apr 2024 12:04:15 +0530 Subject: [PATCH 18/82] fix: use kavin.rocks libre as the default instance --- app/src/main/java/app/suhasdissa/vibeyou/utils/Pref.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/java/app/suhasdissa/vibeyou/utils/Pref.kt b/app/src/main/java/app/suhasdissa/vibeyou/utils/Pref.kt index c8022afb..eb9ac1e0 100644 --- a/app/src/main/java/app/suhasdissa/vibeyou/utils/Pref.kt +++ b/app/src/main/java/app/suhasdissa/vibeyou/utils/Pref.kt @@ -19,6 +19,10 @@ object Pref { lateinit var sharedPreferences: SharedPreferences val pipedInstances = listOf( + PipedInstance( + "kavin.rocks Libre", + "https://pipedapi-libre.kavin.rocks" + ), PipedInstance( "kavin.rocks", "https://pipedapi.kavin.rocks" From f03e40fb2730008d7118c4c26973a9aa59f0fa55 Mon Sep 17 00:00:00 2001 From: Suhas Dissanayake Date: Sat, 6 Apr 2024 12:38:27 +0530 Subject: [PATCH 19/82] fix: adding the same item twice when clicked on a song --- app/src/main/java/app/suhasdissa/vibeyou/utils/Player.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/app/suhasdissa/vibeyou/utils/Player.kt b/app/src/main/java/app/suhasdissa/vibeyou/utils/Player.kt index a19d0bfc..a42bb293 100644 --- a/app/src/main/java/app/suhasdissa/vibeyou/utils/Player.kt +++ b/app/src/main/java/app/suhasdissa/vibeyou/utils/Player.kt @@ -37,10 +37,11 @@ fun Player.forcePlay(mediaItem: MediaItem) { fun Player.playGracefully(mediaItem: MediaItem) { if (playbackState == Player.STATE_IDLE || playbackState == Player.STATE_ENDED) { forcePlay(mediaItem) + } else { + val newIndex = currentPeriodIndex + 1 + addMediaItem(newIndex, mediaItem) + seekTo(newIndex, C.TIME_UNSET) } - val newIndex = currentPeriodIndex + 1 - addMediaItem(newIndex, mediaItem) - seekTo(newIndex, C.TIME_UNSET) } fun Player.enqueue(mediaItem: MediaItem) { From 561625464383c950550bfed21b52e365a3b3e3c1 Mon Sep 17 00:00:00 2001 From: Suhas Dissanayake Date: Sat, 6 Apr 2024 15:15:13 +0530 Subject: [PATCH 20/82] fix: hyperpipe related issues --- .../vibeyou/backend/api/HyperpipeApi.kt | 7 +--- .../repository/PipedMusicRepository.kt | 10 +++--- .../vibeyou/backend/services/PlayerService.kt | 32 ++++++++++++++----- .../screens/settings/NetworkSettingsScreen.kt | 2 +- .../app/suhasdissa/vibeyou/utils/Mappers.kt | 1 + .../java/app/suhasdissa/vibeyou/utils/Pref.kt | 10 ++++++ 6 files changed, 42 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/app/suhasdissa/vibeyou/backend/api/HyperpipeApi.kt b/app/src/main/java/app/suhasdissa/vibeyou/backend/api/HyperpipeApi.kt index e5f3680a..8ec5565f 100644 --- a/app/src/main/java/app/suhasdissa/vibeyou/backend/api/HyperpipeApi.kt +++ b/app/src/main/java/app/suhasdissa/vibeyou/backend/api/HyperpipeApi.kt @@ -1,18 +1,13 @@ package app.suhasdissa.vibeyou.backend.api import app.suhasdissa.vibeyou.backend.models.hyper.NextSongsResponse -import app.suhasdissa.vibeyou.utils.Pref -import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import retrofit2.http.GET import retrofit2.http.Path interface HyperpipeApi { @GET("https://{instance}/next/{videoId}") suspend fun getNext( - @Path("instance") instance: String = Pref.sharedPreferences - .getString(Pref.hyperpipeApiUrlKey, "") - ?.toHttpUrlOrNull() - ?.host.orEmpty(), + @Path("instance") instance: String, @Path("videoId") videoId: String ): NextSongsResponse } \ No newline at end of file diff --git a/app/src/main/java/app/suhasdissa/vibeyou/backend/repository/PipedMusicRepository.kt b/app/src/main/java/app/suhasdissa/vibeyou/backend/repository/PipedMusicRepository.kt index e01dcddb..db82bd77 100644 --- a/app/src/main/java/app/suhasdissa/vibeyou/backend/repository/PipedMusicRepository.kt +++ b/app/src/main/java/app/suhasdissa/vibeyou/backend/repository/PipedMusicRepository.kt @@ -3,7 +3,6 @@ package app.suhasdissa.vibeyou.backend.repository import android.net.Uri import android.util.Log import androidx.core.net.toUri -import androidx.media3.common.MediaItem import app.suhasdissa.vibeyou.backend.data.Album import app.suhasdissa.vibeyou.backend.data.Artist import app.suhasdissa.vibeyou.backend.data.Song @@ -18,7 +17,6 @@ import app.suhasdissa.vibeyou.utils.Pref import app.suhasdissa.vibeyou.utils.RetrofitHelper import app.suhasdissa.vibeyou.utils.asAlbum import app.suhasdissa.vibeyou.utils.asArtist -import app.suhasdissa.vibeyou.utils.asMediaItem import app.suhasdissa.vibeyou.utils.asSong import app.suhasdissa.vibeyou.utils.asSongEntity @@ -38,10 +36,11 @@ class PipedMusicRepository( ?.toUri() } - suspend fun getRecommendedSongs(id: String): List { - val relatedSongs = hyperApi.getNext(videoId = id).songs + suspend fun getRecommendedSongs(id: String, limit: Int = 3): List { + val instance = Pref.hyperInstance ?: return emptyList() + val relatedSongs = hyperApi.getNext(instance, videoId = id).songs.subList(1, limit + 1) songsDao.addSongs(relatedSongs.map { it.asSongEntity }) - return relatedSongs.map { it.asSong.asMediaItem } + return relatedSongs.map { it.asSong } } suspend fun getPlaylistInfo(playlistId: String): PlaylistInfo = @@ -117,6 +116,7 @@ class PipedMusicRepository( searchDao.addSearchQuery(SearchQuery(id = 0, query)) } + fun deleteQuery(query: String) = searchDao.deleteQuery(query) fun getSearchHistory() = searchDao.getSearchHistory() } diff --git a/app/src/main/java/app/suhasdissa/vibeyou/backend/services/PlayerService.kt b/app/src/main/java/app/suhasdissa/vibeyou/backend/services/PlayerService.kt index 046649ee..f076f944 100644 --- a/app/src/main/java/app/suhasdissa/vibeyou/backend/services/PlayerService.kt +++ b/app/src/main/java/app/suhasdissa/vibeyou/backend/services/PlayerService.kt @@ -40,9 +40,11 @@ import androidx.media3.session.BitmapLoader import androidx.media3.session.MediaSession import androidx.media3.session.MediaSessionService import app.suhasdissa.vibeyou.MellowMusicApplication +import app.suhasdissa.vibeyou.backend.data.Song import app.suhasdissa.vibeyou.utils.DynamicDataSource +import app.suhasdissa.vibeyou.utils.IS_LOCAL_KEY import app.suhasdissa.vibeyou.utils.Pref -import app.suhasdissa.vibeyou.utils.enqueue +import app.suhasdissa.vibeyou.utils.asMediaItem import coil.ImageLoader import coil.request.ErrorResult import coil.request.ImageRequest @@ -221,7 +223,6 @@ class PlayerService : MediaSessionService(), MediaSession.Callback, Player.Liste val url = runBlocking { container.pipedMusicRepository.getAudioSource(videoId) } - appendToQueue(videoId) url?.let { dataSpec.withUri(it).subrange(dataSpec.uriPositionOffset, chunkLength) } ?: error("Stream not found") @@ -230,18 +231,33 @@ class PlayerService : MediaSessionService(), MediaSession.Callback, Player.Liste return DynamicDataSource.Companion.Factory(resolvingDataSource, defaultDataSource) } - private fun appendToQueue(videoId: String) = CoroutineScope(Dispatchers.Main).launch { + override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) { + val isLocal = mediaItem?.mediaMetadata?.extras?.getBoolean(IS_LOCAL_KEY) ?: false + if (isLocal) return + val mediaId = mediaItem?.mediaId ?: return + CoroutineScope(Dispatchers.Main).launch { + appendToQueue(mediaId) + } + super.onMediaItemTransition(mediaItem, reason) + } + + private suspend fun appendToQueue(videoId: String) { // enough other videos left in the queue - if (player.mediaItemCount - player.currentMediaItemIndex > 5) return@launch + if (player.mediaItemCount - player.currentMediaItemIndex > 5) return - try { - val nextSongs = withContext(Dispatchers.IO) { + val nextSongs = try { + withContext(Dispatchers.IO) { container.pipedMusicRepository.getRecommendedSongs(videoId) } - player.addMediaItems(nextSongs.take(3)) } catch (e: Exception) { - Log.e("hyperpipe: error fetching next", e.stackTrace.contentToString()) + Log.e("hyperpipe: error fetching next", e.message, e) + emptyList() } + + player.addMediaItems( + player.currentMediaItemIndex + 1, + nextSongs.map(Song::asMediaItem) + ) } @androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class) diff --git a/app/src/main/java/app/suhasdissa/vibeyou/ui/screens/settings/NetworkSettingsScreen.kt b/app/src/main/java/app/suhasdissa/vibeyou/ui/screens/settings/NetworkSettingsScreen.kt index 5abc6fdf..23f1dd17 100644 --- a/app/src/main/java/app/suhasdissa/vibeyou/ui/screens/settings/NetworkSettingsScreen.kt +++ b/app/src/main/java/app/suhasdissa/vibeyou/ui/screens/settings/NetworkSettingsScreen.kt @@ -71,7 +71,7 @@ fun NetworkSettingsScreen() { item { TextFieldPref( key = Pref.hyperpipeApiUrlKey, - defaultValue = "https://hyperpipeapi.onrender.com", + defaultValue = Pref.defaultHyperInstance, title = stringResource(id = R.string.hyperpipe_api_url) ) } diff --git a/app/src/main/java/app/suhasdissa/vibeyou/utils/Mappers.kt b/app/src/main/java/app/suhasdissa/vibeyou/utils/Mappers.kt index a1e96338..cb523f7a 100644 --- a/app/src/main/java/app/suhasdissa/vibeyou/utils/Mappers.kt +++ b/app/src/main/java/app/suhasdissa/vibeyou/utils/Mappers.kt @@ -100,6 +100,7 @@ val Song.asMediaItem: MediaItem ) .build() ) + .setUri(id) .setMediaId(id) .setCustomCacheKey(id) .build() diff --git a/app/src/main/java/app/suhasdissa/vibeyou/utils/Pref.kt b/app/src/main/java/app/suhasdissa/vibeyou/utils/Pref.kt index 4a24e865..27a39aff 100644 --- a/app/src/main/java/app/suhasdissa/vibeyou/utils/Pref.kt +++ b/app/src/main/java/app/suhasdissa/vibeyou/utils/Pref.kt @@ -5,6 +5,7 @@ import androidx.core.content.edit import app.suhasdissa.vibeyou.backend.models.PipedInstance import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json +import okhttp3.HttpUrl.Companion.toHttpUrlOrNull object Pref { private const val pipedInstanceKey = "SelectedPipedInstanceKey" @@ -19,6 +20,8 @@ object Pref { lateinit var sharedPreferences: SharedPreferences + val defaultHyperInstance = "https://hyperpipeapi.onrender.com" + val pipedInstances = listOf( PipedInstance( "kavin.rocks Libre", @@ -63,6 +66,13 @@ object Pref { pipedInstances.first() } + val hyperInstance: String? + get() { + val url = sharedPreferences.getString(hyperpipeApiUrlKey, defaultHyperInstance) + ?: defaultHyperInstance + return url.toHttpUrlOrNull()?.host + } + private val json = Json { ignoreUnknownKeys = true } fun setInstance(instance: PipedInstance) { From 64b8a96910df1eba0d5c501e614fc146114662a8 Mon Sep 17 00:00:00 2001 From: Suhas Dissanayake Date: Fri, 12 Apr 2024 17:45:53 +0530 Subject: [PATCH 21/82] feat: add custom color schemes --- app/build.gradle.kts | 1 + app/src/main/AndroidManifest.xml | 10 +- .../app/suhasdissa/vibeyou/MainActivity.kt | 23 ++++- .../java/app/suhasdissa/vibeyou/NavHost.kt | 4 +- .../backend/viewmodel/SettingsModel.kt | 66 +++++++++++++ .../settings/AppearanceSettingsScreen.kt | 60 ++++++++++-- .../ui/screens/settings/ButtonGroupPref.kt | 94 +++++++++++++++++++ .../vibeyou/ui/screens/settings/ColorPref.kt | 48 ++++++++++ .../app/suhasdissa/vibeyou/ui/theme/Theme.kt | 64 ++++++------- .../java/app/suhasdissa/vibeyou/utils/Pref.kt | 3 + .../app/suhasdissa/vibeyou/utils/ThemeUtil.kt | 67 +++++++++++++ app/src/main/res/values/strings.xml | 7 ++ app/src/main/res/values/themes.xml | 2 +- 13 files changed, 402 insertions(+), 47 deletions(-) create mode 100644 app/src/main/java/app/suhasdissa/vibeyou/backend/viewmodel/SettingsModel.kt create mode 100644 app/src/main/java/app/suhasdissa/vibeyou/ui/screens/settings/ButtonGroupPref.kt create mode 100644 app/src/main/java/app/suhasdissa/vibeyou/ui/screens/settings/ColorPref.kt create mode 100644 app/src/main/java/app/suhasdissa/vibeyou/utils/ThemeUtil.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 2efb2471..473bf203 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -76,6 +76,7 @@ dependencies { implementation("androidx.compose.material:material-icons-extended:1.5.3") implementation("io.coil-kt:coil-compose:2.4.0") + implementation("com.google.android.material:material:1.11.0") val media3Version = "1.1.1" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6e9ba9b2..f9cf67e2 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -12,7 +12,9 @@ - + + android:theme="@style/Theme.VibeYou" + android:windowSoftInputMode="adjustResize"> @@ -37,6 +40,7 @@ + diff --git a/app/src/main/java/app/suhasdissa/vibeyou/MainActivity.kt b/app/src/main/java/app/suhasdissa/vibeyou/MainActivity.kt index 9032314a..a6f86d32 100644 --- a/app/src/main/java/app/suhasdissa/vibeyou/MainActivity.kt +++ b/app/src/main/java/app/suhasdissa/vibeyou/MainActivity.kt @@ -8,6 +8,7 @@ import android.widget.Toast import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.viewModels +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.DrawerValue import androidx.compose.material3.MaterialTheme @@ -23,10 +24,13 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.toArgb import androidx.core.net.toUri +import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.compose.rememberNavController import app.suhasdissa.vibeyou.backend.viewmodel.PlayerViewModel +import app.suhasdissa.vibeyou.backend.viewmodel.SettingsModel import app.suhasdissa.vibeyou.ui.components.NavDrawerContent -import app.suhasdissa.vibeyou.ui.theme.LibreMusicTheme +import app.suhasdissa.vibeyou.ui.theme.VibeYouTheme +import app.suhasdissa.vibeyou.utils.ThemeUtil import kotlinx.coroutines.launch class MainActivity : ComponentActivity() { @@ -35,7 +39,22 @@ class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { - LibreMusicTheme { + val settingsModel: SettingsModel = viewModel(factory = SettingsModel.Factory) + + val darkTheme = when (settingsModel.themeMode) { + SettingsModel.Theme.SYSTEM -> isSystemInDarkTheme() + SettingsModel.Theme.DARK, SettingsModel.Theme.AMOLED -> true + else -> false + } + VibeYouTheme( + darkTheme = darkTheme, + customColorScheme = ThemeUtil.getSchemeFromSeed( + settingsModel.customColor, + darkTheme + ), + dynamicColor = settingsModel.colorTheme == SettingsModel.ColorTheme.SYSTEM, + amoledDark = settingsModel.themeMode == SettingsModel.Theme.AMOLED + ) { val navHostController = rememberNavController() val primaryColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.5f).toArgb() diff --git a/app/src/main/java/app/suhasdissa/vibeyou/NavHost.kt b/app/src/main/java/app/suhasdissa/vibeyou/NavHost.kt index 5ddcfe5b..12b799e2 100644 --- a/app/src/main/java/app/suhasdissa/vibeyou/NavHost.kt +++ b/app/src/main/java/app/suhasdissa/vibeyou/NavHost.kt @@ -75,7 +75,9 @@ fun AppNavHost(navHostController: NavHostController) { } composable(route = Destination.AppearanceSettings.route) { - AppearanceSettingsScreen() + CompositionLocalProvider(LocalViewModelStoreOwner provides viewModelStoreOwner) { + AppearanceSettingsScreen() + } } composable(Destination.Playlists.route) { diff --git a/app/src/main/java/app/suhasdissa/vibeyou/backend/viewmodel/SettingsModel.kt b/app/src/main/java/app/suhasdissa/vibeyou/backend/viewmodel/SettingsModel.kt new file mode 100644 index 00000000..12d9caae --- /dev/null +++ b/app/src/main/java/app/suhasdissa/vibeyou/backend/viewmodel/SettingsModel.kt @@ -0,0 +1,66 @@ +package app.suhasdissa.vibeyou.backend.viewmodel + +import android.content.Context +import android.content.SharedPreferences +import androidx.annotation.StringRes +import androidx.compose.runtime.getValue +import androidx.compose.runtime.setValue +import androidx.core.content.edit +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.Companion.APPLICATION_KEY +import androidx.lifecycle.viewmodel.initializer +import androidx.lifecycle.viewmodel.viewModelFactory +import app.suhasdissa.vibeyou.R +import app.suhasdissa.vibeyou.utils.Pref +import app.suhasdissa.vibeyou.utils.catpucchinLatte +import app.suhasdissa.vibeyou.utils.mutableStatePreferenceOf +import app.suhasdissa.vibeyou.utils.preferences + +class SettingsModel(preferences: SharedPreferences) : ViewModel() { + enum class Theme(@StringRes val resId: Int) { + SYSTEM(R.string.system), LIGHT(R.string.light), DARK(R.string.dark), + AMOLED(R.string.amoled) + } + + enum class ColorTheme(@StringRes val resId: Int) { + SYSTEM(R.string.system), + CATPPUCCIN(R.string.catppuccin) + } + + private val themeModePref = + preferences.getString(Pref.themeKey, Theme.SYSTEM.name) ?: Theme.SYSTEM.name + + var themeMode: Theme by mutableStatePreferenceOf( + Theme.valueOf(themeModePref.uppercase()) + ) { + preferences.edit { putString(Pref.themeKey, it.name) } + } + + private val colorThemePref = + preferences.getString(Pref.colorThemeKey, ColorTheme.SYSTEM.name) + ?: ColorTheme.SYSTEM.name + + var colorTheme: ColorTheme by mutableStatePreferenceOf( + ColorTheme.valueOf(colorThemePref.uppercase()) + ) { + preferences.edit { putString(Pref.colorThemeKey, it.name) } + } + + var customColor by mutableStatePreferenceOf( + preferences.getInt( + Pref.customColorKey, + catpucchinLatte.first() + ) + ) { + preferences.edit { putInt(Pref.customColorKey, it) } + } + + companion object { + val Factory = viewModelFactory { + initializer { + val context = this[APPLICATION_KEY] as Context + SettingsModel(preferences = context.preferences) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/app/suhasdissa/vibeyou/ui/screens/settings/AppearanceSettingsScreen.kt b/app/src/main/java/app/suhasdissa/vibeyou/ui/screens/settings/AppearanceSettingsScreen.kt index 1010b3aa..4531dadd 100644 --- a/app/src/main/java/app/suhasdissa/vibeyou/ui/screens/settings/AppearanceSettingsScreen.kt +++ b/app/src/main/java/app/suhasdissa/vibeyou/ui/screens/settings/AppearanceSettingsScreen.kt @@ -1,10 +1,16 @@ package app.suhasdissa.vibeyou.ui.screens.settings +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Divider import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.LargeTopAppBar +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarDefaults @@ -12,13 +18,17 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.lifecycle.viewmodel.compose.viewModel import app.suhasdissa.vibeyou.R +import app.suhasdissa.vibeyou.backend.viewmodel.SettingsModel import app.suhasdissa.vibeyou.utils.Pref -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class) @Composable fun AppearanceSettingsScreen() { val topBarBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior() + val settingsModel: SettingsModel = viewModel(factory = SettingsModel.Factory) Scaffold(modifier = Modifier.fillMaxSize(), topBar = { LargeTopAppBar( @@ -26,19 +36,53 @@ fun AppearanceSettingsScreen() { scrollBehavior = topBarBehavior ) }) { innerPadding -> - LazyColumn( + val state = rememberScrollState() + Column( Modifier .fillMaxSize() .padding(innerPadding) .nestedScroll(topBarBehavior.nestedScrollConnection) + .verticalScroll(state) ) { - item { - SwitchPref( - prefKey = Pref.thumbnailColorFallbackKey, - title = stringResource(R.string.fallback_thumnail_accent), - summary = stringResource(R.string.fallback_thumnail_accent_description) + ButtonGroupPref( + title = stringResource(R.string.theme), + options = SettingsModel.Theme.values().map { + stringResource(it.resId) + }, + values = SettingsModel.Theme.values().toList(), + currentValue = settingsModel.themeMode + ) { + settingsModel.themeMode = it + } + ButtonGroupPref( + title = stringResource(R.string.color_scheme), + options = SettingsModel.ColorTheme.values().map { + stringResource(it.resId) + }, + values = SettingsModel.ColorTheme.values().toList(), + currentValue = settingsModel.colorTheme + ) { + settingsModel.colorTheme = it + } + AnimatedVisibility( + visible = settingsModel.colorTheme == SettingsModel.ColorTheme.CATPPUCCIN + ) { + ColorPref( + selectedColor = settingsModel.customColor, + onSelect = { + settingsModel.customColor = it + } ) } + Divider( + modifier = Modifier.padding(top = 12.dp, bottom = 8.dp), + color = MaterialTheme.colorScheme.surfaceVariant + ) + SwitchPref( + prefKey = Pref.thumbnailColorFallbackKey, + title = stringResource(R.string.fallback_thumnail_accent), + summary = stringResource(R.string.fallback_thumnail_accent_description) + ) } } } diff --git a/app/src/main/java/app/suhasdissa/vibeyou/ui/screens/settings/ButtonGroupPref.kt b/app/src/main/java/app/suhasdissa/vibeyou/ui/screens/settings/ButtonGroupPref.kt new file mode 100644 index 00000000..f4cbf9b8 --- /dev/null +++ b/app/src/main/java/app/suhasdissa/vibeyou/ui/screens/settings/ButtonGroupPref.kt @@ -0,0 +1,94 @@ +package app.suhasdissa.vibeyou.ui.screens.settings + +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedButton +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.compose.ui.zIndex + +@Composable +fun ButtonGroupPref( + title: String, + options: List, + values: List, + currentValue: T, + onChange: (T) -> Unit +) { + Column( + modifier = Modifier + .padding(top = 8.dp) + .padding(horizontal = 12.dp) + ) { + Text(title) + Spacer(modifier = Modifier.height(8.dp)) + Row( + modifier = Modifier + .fillMaxWidth() + ) { + val cornerRadius = 20.dp + var selectedItem by remember { + mutableStateOf( + currentValue + ) + } + + values.forEachIndexed { index, value -> + val startRadius = if (index != 0) 0.dp else cornerRadius + val endRadius = if (index == values.size - 1) cornerRadius else 0.dp + + OutlinedButton( + onClick = { + selectedItem = value + onChange.invoke(values[index]) + }, + modifier = Modifier + .offset(if (index == 0) 0.dp else (-1 * index).dp, 0.dp) + .zIndex(if (selectedItem == value) 1f else 0f), + shape = RoundedCornerShape( + topStart = startRadius, + topEnd = endRadius, + bottomStart = startRadius, + bottomEnd = endRadius + ), + border = BorderStroke( + 1.dp, + if (selectedItem == value) { + MaterialTheme.colorScheme.primary + } else { + MaterialTheme.colorScheme.primary.copy(alpha = 0.75f) + } + ), + colors = if (selectedItem == value) { + ButtonDefaults.outlinedButtonColors( + containerColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.2f), + contentColor = MaterialTheme.colorScheme.primary + ) + } else { + ButtonDefaults.outlinedButtonColors( + containerColor = MaterialTheme.colorScheme.surface, + contentColor = MaterialTheme.colorScheme.onSurface + ) + } + ) { + Text(options[index]) + } + } + } + } +} diff --git a/app/src/main/java/app/suhasdissa/vibeyou/ui/screens/settings/ColorPref.kt b/app/src/main/java/app/suhasdissa/vibeyou/ui/screens/settings/ColorPref.kt new file mode 100644 index 00000000..8495a555 --- /dev/null +++ b/app/src/main/java/app/suhasdissa/vibeyou/ui/screens/settings/ColorPref.kt @@ -0,0 +1,48 @@ +package app.suhasdissa.vibeyou.ui.screens.settings + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.Check +import androidx.compose.material3.Icon +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import app.suhasdissa.vibeyou.utils.catpucchinLatte + +@Composable +fun ColorPref(selectedColor: Int, onSelect: (Int) -> Unit) { + LazyRow( + modifier = Modifier + .fillMaxWidth() + .padding(top = 8.dp) + .padding(horizontal = 12.dp), + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + items(catpucchinLatte) { color -> + Box( + modifier = Modifier + .size(48.dp) + .clip(CircleShape) + .background(Color(color)) + .clickable { onSelect(color) }, + contentAlignment = Alignment.Center + ) { + if (color == selectedColor) { + Icon(imageVector = Icons.Rounded.Check, contentDescription = null) + } + } + } + } +} diff --git a/app/src/main/java/app/suhasdissa/vibeyou/ui/theme/Theme.kt b/app/src/main/java/app/suhasdissa/vibeyou/ui/theme/Theme.kt index 47f12420..71f70edb 100644 --- a/app/src/main/java/app/suhasdissa/vibeyou/ui/theme/Theme.kt +++ b/app/src/main/java/app/suhasdissa/vibeyou/ui/theme/Theme.kt @@ -3,63 +3,63 @@ package app.suhasdissa.vibeyou.ui.theme import android.app.Activity import android.os.Build import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.ColorScheme import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.darkColorScheme import androidx.compose.material3.dynamicDarkColorScheme import androidx.compose.material3.dynamicLightColorScheme -import androidx.compose.material3.lightColorScheme +import androidx.compose.material3.surfaceColorAtElevation import androidx.compose.runtime.Composable import androidx.compose.runtime.SideEffect +import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalView +import androidx.compose.ui.unit.dp import androidx.core.view.WindowCompat -private val DarkColorScheme = darkColorScheme( - primary = Purple80, - secondary = PurpleGrey80, - tertiary = Pink80 -) - -private val LightColorScheme = lightColorScheme( - primary = Purple40, - secondary = PurpleGrey40, - tertiary = Pink40 - - /* Other default colors to override - background = Color(0xFFFFFBFE), - surface = Color(0xFFFFFBFE), - onPrimary = Color.White, - onSecondary = Color.White, - onTertiary = Color.White, - onBackground = Color(0xFF1C1B1F), - onSurface = Color(0xFF1C1B1F), - */ -) - @Composable -fun LibreMusicTheme( +fun VibeYouTheme( darkTheme: Boolean = isSystemInDarkTheme(), - // Dynamic color is available on Android 12+ + customColorScheme: ColorScheme, dynamicColor: Boolean = true, + amoledDark: Boolean = false, content: @Composable () -> Unit ) { val colorScheme = when { + amoledDark -> { + if (dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + val context = LocalContext.current + dynamicDarkColorScheme(context).copy( + background = Color.Black, + surface = Color.Black + ) + } else { + customColorScheme.copy(background = Color.Black, surface = Color.Black) + } + } + dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { val context = LocalContext.current if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) } - darkTheme -> DarkColorScheme - else -> LightColorScheme + else -> customColorScheme } val view = LocalView.current if (!view.isInEditMode) { SideEffect { - val window = (view.context as Activity).window - window.statusBarColor = colorScheme.background.toArgb() - window.navigationBarColor = colorScheme.background.toArgb() - WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = !darkTheme + val activity = view.context as Activity + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + activity.window.statusBarColor = colorScheme.background.toArgb() + activity.window.navigationBarColor = + colorScheme.surfaceColorAtElevation(5.dp).toArgb() + val insetsController = WindowCompat.getInsetsController( + activity.window, + view + ) + insetsController.isAppearanceLightStatusBars = !darkTheme + insetsController.isAppearanceLightNavigationBars = !darkTheme + } } } diff --git a/app/src/main/java/app/suhasdissa/vibeyou/utils/Pref.kt b/app/src/main/java/app/suhasdissa/vibeyou/utils/Pref.kt index 27a39aff..f0a9caee 100644 --- a/app/src/main/java/app/suhasdissa/vibeyou/utils/Pref.kt +++ b/app/src/main/java/app/suhasdissa/vibeyou/utils/Pref.kt @@ -17,6 +17,9 @@ object Pref { const val customPipedInstanceKey = "CustomPipedInstanceKey" const val disableSearchHistoryKey = "DisableSearchHistory" const val hyperpipeApiUrlKey = "HyperpipeApiUrl" + const val customColorKey = "customColor" + const val themeKey = "theme" + const val colorThemeKey = "colorTheme" lateinit var sharedPreferences: SharedPreferences diff --git a/app/src/main/java/app/suhasdissa/vibeyou/utils/ThemeUtil.kt b/app/src/main/java/app/suhasdissa/vibeyou/utils/ThemeUtil.kt new file mode 100644 index 00000000..43d99130 --- /dev/null +++ b/app/src/main/java/app/suhasdissa/vibeyou/utils/ThemeUtil.kt @@ -0,0 +1,67 @@ +package app.suhasdissa.vibeyou.utils + +import android.annotation.SuppressLint +import androidx.compose.material3.ColorScheme +import androidx.compose.ui.graphics.Color +import com.google.android.material.color.utilities.Scheme + +object ThemeUtil { + @SuppressLint("RestrictedApi") + fun getSchemeFromSeed(color: Int, dark: Boolean): ColorScheme { + return if (dark) { + Scheme.dark(color).toColorScheme() + } else { + Scheme.light(color).toColorScheme() + } + } +} + +val catpucchinLatte = arrayOf( + android.graphics.Color.rgb(220, 138, 120), + android.graphics.Color.rgb(221, 120, 120), + android.graphics.Color.rgb(234, 118, 203), + android.graphics.Color.rgb(136, 57, 239), + android.graphics.Color.rgb(210, 15, 57), + android.graphics.Color.rgb(230, 69, 83), + android.graphics.Color.rgb(254, 100, 11), + android.graphics.Color.rgb(223, 142, 29), + android.graphics.Color.rgb(64, 160, 43), + android.graphics.Color.rgb(23, 146, 153), + android.graphics.Color.rgb(4, 165, 229), + android.graphics.Color.rgb(32, 159, 181), + android.graphics.Color.rgb(30, 102, 245), + android.graphics.Color.rgb(114, 135, 253) +) + +@SuppressLint("RestrictedApi") +fun Scheme.toColorScheme() = ColorScheme( + primary = Color(primary), + onPrimary = Color(onPrimary), + primaryContainer = Color(primaryContainer), + onPrimaryContainer = Color(onPrimaryContainer), + inversePrimary = Color(inversePrimary), + secondary = Color(secondary), + onSecondary = Color(onSecondary), + secondaryContainer = Color(secondaryContainer), + onSecondaryContainer = Color(onSecondaryContainer), + tertiary = Color(tertiary), + onTertiary = Color(onTertiary), + tertiaryContainer = Color(tertiaryContainer), + onTertiaryContainer = Color(onTertiaryContainer), + background = Color(background), + onBackground = Color(onBackground), + surface = Color(surface), + onSurface = Color(onSurface), + surfaceVariant = Color(surfaceVariant), + onSurfaceVariant = Color(onSurfaceVariant), + surfaceTint = Color(primary), + inverseSurface = Color(inverseSurface), + inverseOnSurface = Color(inverseOnSurface), + error = Color(error), + onError = Color(onError), + errorContainer = Color(errorContainer), + onErrorContainer = Color(onErrorContainer), + outline = Color(outline), + outlineVariant = Color(outlineVariant), + scrim = Color(scrim) +) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2851b2bf..402c2518 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -86,4 +86,11 @@ Clear Playlist Disable search history Hyperpipe API URL + System + Light + Dark + AMOLED + Catppuccin + Color Scheme + Theme diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index b19d71aa..c5574237 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -1,7 +1,7 @@ -