From 29f162c80100fcb9ad51ee3103f04cf2facc17e9 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 5 Jan 2024 21:25:23 +0600 Subject: [PATCH 1/8] chore: remove the sp_key cookie requirement as no longer necessary --- lib/components/desktop_login/login_form.dart | 15 +--- lib/l10n/app_ar.arb | 2 - lib/l10n/app_bn.arb | 2 - lib/l10n/app_ca.arb | 2 - lib/l10n/app_de.arb | 2 - lib/l10n/app_en.arb | 6 +- lib/l10n/app_es.arb | 2 - lib/l10n/app_fa.arb | 2 - lib/l10n/app_fr.arb | 2 - lib/l10n/app_hi.arb | 2 - lib/l10n/app_it.arb | 2 - lib/l10n/app_ja.arb | 2 - lib/l10n/app_nl.arb | 2 - lib/l10n/app_pl.arb | 2 - lib/l10n/app_pt.arb | 2 - lib/l10n/app_ru.arb | 2 - lib/l10n/app_tr.arb | 2 - lib/l10n/app_uk.arb | 2 - lib/l10n/app_zh.arb | 2 - lib/pages/mobile_login/mobile_login.dart | 7 +- untranslated_messages.json | 87 +++++++++++++++++++- 21 files changed, 92 insertions(+), 57 deletions(-) diff --git a/lib/components/desktop_login/login_form.dart b/lib/components/desktop_login/login_form.dart index f2b183f4..5abb9524 100644 --- a/lib/components/desktop_login/login_form.dart +++ b/lib/components/desktop_login/login_form.dart @@ -17,7 +17,6 @@ class TokenLoginForm extends HookConsumerWidget { final authenticationNotifier = ref.watch(AuthenticationNotifier.provider.notifier); final directCodeController = useTextEditingController(); - final keyCodeController = useTextEditingController(); final mounted = useIsMounted(); final isLoading = useState(false); @@ -37,23 +36,13 @@ class TokenLoginForm extends HookConsumerWidget { keyboardType: TextInputType.visiblePassword, ), const SizedBox(height: 10), - TextField( - controller: keyCodeController, - decoration: InputDecoration( - hintText: context.l10n.spotify_cookie("\"sp_key (or sp_gaid)\""), - labelText: context.l10n.cookie_name_cookie("sp_key (or sp_gaid)"), - ), - keyboardType: TextInputType.visiblePassword, - ), - const SizedBox(height: 20), FilledButton( onPressed: isLoading.value ? null : () async { try { isLoading.value = true; - if (keyCodeController.text.isEmpty || - directCodeController.text.isEmpty) { + if (directCodeController.text.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(context.l10n.fill_in_all_fields), @@ -63,7 +52,7 @@ class TokenLoginForm extends HookConsumerWidget { return; } final cookieHeader = - "sp_dc=${directCodeController.text.trim()}; sp_key=${keyCodeController.text.trim()}"; + "sp_dc=${directCodeController.text.trim()}"; authenticationNotifier.setCredentials( await AuthenticationCredentials.fromCookie( diff --git a/lib/l10n/app_ar.arb b/lib/l10n/app_ar.arb index 2bdde72a..20b6a47c 100644 --- a/lib/l10n/app_ar.arb +++ b/lib/l10n/app_ar.arb @@ -177,11 +177,9 @@ "step_2": "الخطوة 2", "step_2_steps": "1. بمجرد تسجيل الدخول، اضغط على F12 أو انقر بزر الماوس الأيمن > فحص لفتح أدوات تطوير المتصفح.\n2. ثم انتقل إلى علامة التبويب \"التطبيقات\" (Chrome وEdge وBrave وما إلى ذلك.) أو علامة التبويب \"التخزين\" (Firefox وPalemoon وما إلى ذلك..)\n3. انتقل إلى قسم \"ملفات تعريف الارتباط\" ثم القسم الفرعي \"https://accounts.spotify.com\"", "step_3": "الخطوة 3", - "step_3_steps": "انسخ قيم \"sp_dc\" و \"sp_key\" (أو sp_gaid) الكويز", "success_emoji": "نجاح 🥳", "success_message": "لقد قمت الآن بتسجيل الدخول بنجاح باستخدام حساب Spotify الخاص بك. عمل جيد يا صديقي!", "step_4": "الخطوة 4", - "step_4_steps": "قم بلصق قيم \"sp_dc\" و \"sp_key\" (أو sp_gaid) المنسوخة في الحقول المعنية", "something_went_wrong": "هناك خطأ ما", "piped_instance": "مثيل خادم Piped", "piped_description": "مثيل خادم Piped الذي سيتم استخدامه لمطابقة المقطوعة", diff --git a/lib/l10n/app_bn.arb b/lib/l10n/app_bn.arb index 39f8a1ee..74dc200d 100644 --- a/lib/l10n/app_bn.arb +++ b/lib/l10n/app_bn.arb @@ -175,11 +175,9 @@ "step_2": "ধাপ 2", "step_2_steps": "১. একবার আপনি লগ ইন করলে, ব্রাউজার ডেভটুল খুলতে F12 বা মাউসের রাইট ক্লিক > \"Inspect to open Browser DevTools\" টিপুন।\n২. তারপর \"Application\" ট্যাবে যান (Chrome, Edge, Brave etc..) অথবা \"Storage\" Tab (Firefox, Palemoon etc..)\n৩. \"Cookies \" বিভাগে যান তারপর \"https://accounts.spotify.com\" উপবিভাগে যান", "step_3": "ধাপ 3", - "step_3_steps": "\"sp_dc\" এবং \"sp_key\" (অথবা sp_gaid) কুকিজের মান কপি করুন", "success_emoji": "আমরা সফল🥳", "success_message": "এখন আপনি সফলভাবে আপনার Spotify অ্যাকাউন্ট দিয়ে লগ ইন করেছেন। সাধুভাত আপনাকে", "step_4": "ধাপ 4", - "step_4_steps": "কপি করা \"sp_dc\" এবং \"sp_key\" (অথবা sp_gaid) এর মান সংশ্লিষ্ট ফিল্ডে পেস্ট করুন", "something_went_wrong": "কিছু ভুল হয়েছে", "piped_instance": "Piped সার্ভার এড্রেস", "piped_description": "গান ম্যাচ করার জন্য ব্যবহৃত পাইপড সার্ভার", diff --git a/lib/l10n/app_ca.arb b/lib/l10n/app_ca.arb index 15ca9e31..2c952457 100644 --- a/lib/l10n/app_ca.arb +++ b/lib/l10n/app_ca.arb @@ -175,11 +175,9 @@ "step_2": "Pas 2", "step_2_steps": "1. Una vegada que hagi iniciat sessió, premi F12 o faci clic dret amb el ratolí > Inspeccionar per obrir les eines de desenvolulpador del navegador.\n2. Després vagi a la pestanya \"Application\" (Chrome, Edge, Brave, etc.) o \"Storage\" (Firefox, Palemoon, etc.)\n3. Vagi a la secció \"Cookies\" i després a la subsecció \"https://accounts.spotify.com\"", "step_3": "Pas 3", - "step_3_steps": "Copiï els valors de les Cookies \"sp_dc\" i \"sp_key\" (o sp_gaid)", "success_emoji": "Èxit! 🥳", "success_message": "Ara has iniciat sessió amb èxit al teu compte de Spotify. Bona feina!", "step_4": "Pas 4", - "step_4_steps": "Enganxi els valors coppiats de \"sp_dc\" i \"sp_key\" (o sp_gaid) en els camps respectius", "something_went_wrong": "Quelcom ha sortit malament", "piped_instance": "Instància del servidor Piped", "piped_description": "La instància del servidor Piped a utilitzar per la coincidència de cançons", diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 1a13e4a1..59f832ea 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -175,11 +175,9 @@ "step_2": "Schritt 2", "step_2_steps": "1. Wenn du angemeldet bist, drücke F12 oder klicke mit der rechten Maustaste > Inspektion, um die Browser-Entwicklertools zu öffnen.\n2. Gehe dann zum \"Anwendungs\"-Tab (Chrome, Edge, Brave usw.) oder zum \"Storage\"-Tab (Firefox, Palemoon usw.)\n3. Gehe zum Abschnitt \"Cookies\" und dann zum Unterabschnitt \"https://accounts.spotify.com\"", "step_3": "Schritt 3", - "step_3_steps": "Kopiere die Werte der Cookies \"sp_dc\" und \"sp_key\" (oder sp_gaid)", "success_emoji": "Erfolg🥳", "success_message": "Jetzt bist du erfolgreich mit deinem Spotify-Konto angemeldet. Gut gemacht, Kumpel!", "step_4": "Schritt 4", - "step_4_steps": "Füge die kopierten Werte von \"sp_dc\" und \"sp_key\" (oder sp_gaid) in die entsprechenden Felder ein", "something_went_wrong": "Etwas ist schiefgelaufen", "piped_instance": "Piped-Serverinstanz", "piped_description": "Die Piped-Serverinstanz, die zur Titelzuordnung verwendet werden soll", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index bebfafac..82877ea1 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -177,11 +177,11 @@ "step_2": "Step 2", "step_2_steps": "1. Once you're logged in, press F12 or Mouse Right Click > Inspect to Open the Browser devtools.\n2. Then go the \"Application\" Tab (Chrome, Edge, Brave etc..) or \"Storage\" Tab (Firefox, Palemoon etc..)\n3. Go to the \"Cookies\" section then the \"https://accounts.spotify.com\" subsection", "step_3": "Step 3", - "step_3_steps": "Copy the values of \"sp_dc\" and \"sp_key\" (or sp_gaid) Cookies", + "step_3_steps": "Copy the value of \"sp_dc\" Cookie", "success_emoji": "Success🥳", - "success_message": "Now you're successfully Logged In with your Spotify account. Good Job, mate!", + "success_message": "Now you've successfully Logged in with your Spotify account. Good Job, mate!", "step_4": "Step 4", - "step_4_steps": "Paste the copied \"sp_dc\" and \"sp_key\" (or sp_gaid) values in the respective fields", + "step_4_steps": "Paste the copied \"sp_dc\" value", "something_went_wrong": "Something went wrong", "piped_instance": "Piped Server Instance", "piped_description": "The Piped server instance to use for track matching", diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 2fecd8f1..e04b4798 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -175,11 +175,9 @@ "step_2": "Paso 2", "step_2_steps": "1. Una vez que hayas iniciado sesión, presiona F12 o haz clic derecho con el ratón > Inspeccionar para abrir las herramientas de desarrollo del navegador.\n2. Luego ve a la pestaña \"Application\" (Chrome, Edge, Brave, etc.) o \"Storage\" (Firefox, Palemoon, etc.)\n3. Ve a la sección \"Cookies\" y luego la subsección \"https://accounts.spotify.com\"", "step_3": "Paso 3", - "step_3_steps": "Copia los valores de las Cookies \"sp_dc\" y \"sp_key\" (o sp_gaid)", "success_emoji": "¡Éxito! 🥳", "success_message": "Ahora has iniciado sesión con éxito en tu cuenta de Spotify. ¡Buen trabajo!", "step_4": "Paso 4", - "step_4_steps": "Pega los valores copiados de \"sp_dc\" y \"sp_key\" (o sp_gaid) en los campos respectivos", "something_went_wrong": "Algo salió mal", "piped_instance": "Instancia del servidor Piped", "piped_description": "La instancia del servidor Piped a utilizar para la coincidencia de pistas", diff --git a/lib/l10n/app_fa.arb b/lib/l10n/app_fa.arb index 84b9b448..c9586cde 100644 --- a/lib/l10n/app_fa.arb +++ b/lib/l10n/app_fa.arb @@ -177,11 +177,9 @@ "step_2": "گام 2", "step_2_steps": "1. پس از ورود به سیستم، F12 یا کلیک راست ماوس > Inspect را فشار دهید تا ابزارهای توسعه مرورگر باز شود..\n2. سپس به تب \"Application\" (Chrome, Edge, Brave etc..) یا \"Storage\" Tab (Firefox, Palemoon etc..)\n3. به قسمت \"Cookies\" و به پخش \"https://accounts.spotify.com\" بروید", "step_3": "گام 3", - "step_3_steps": "کپی کردن مقادیر \"sp_dc\" و \"sp_key\" (یا sp_gaid) کوکی", "success_emoji": "موفقیت🥳", "success_message": "اکنون با موفقیت با حساب اسپوتیفای خود وارد شده اید", "step_4": "مرحله 4", - "step_4_steps": "مقدار کپی شده را \"sp_dc\" and \"sp_key\" (یا sp_gaid) در فیلد مربوط پر کنید", "something_went_wrong": "اشتباهی رخ داده", "piped_instance": "مشکل در ارتباط با سرور", "piped_description": "مشکل در ارتباط با سرور در دریافت آهنگ ها", diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 82997bad..0c3eb653 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -175,11 +175,9 @@ "step_2": "Étape 2", "step_2_steps": "1. Une fois connecté, appuyez sur F12 ou clic droit de la souris > Inspecter pour ouvrir les outils de développement du navigateur.\n2. Ensuite, allez dans l'onglet \"Application\" (Chrome, Edge, Brave, etc.) ou l'onglet \"Stockage\" (Firefox, Palemoon, etc.)\n3. Allez dans la section \"Cookies\", puis dans la sous-section \"https://accounts.spotify.com\"", "step_3": "Étape 3", - "step_3_steps": "Copiez les valeurs des cookies \"sp_dc\" et \"sp_key\" (ou sp_gaid)", "success_emoji": "Succès🥳", "success_message": "Vous êtes maintenant connecté avec succès à votre compte Spotify. Bon travail, mon ami!", "step_4": "Étape 4", - "step_4_steps": "Collez les valeurs copiées de \"sp_dc\" et \"sp_key\" (ou sp_gaid) dans les champs respectifs", "something_went_wrong": "Quelque chose s'est mal passé", "piped_instance": "Instance pipée", "piped_description": "L'instance de serveur Piped à utiliser pour la correspondance des pistes", diff --git a/lib/l10n/app_hi.arb b/lib/l10n/app_hi.arb index 4bfff3da..dd27dabf 100644 --- a/lib/l10n/app_hi.arb +++ b/lib/l10n/app_hi.arb @@ -175,11 +175,9 @@ "step_2": "2 चरण", "step_2_steps": "1. जब आप लॉगिन हो जाएँ, तो F12 दबाएं या माउस राइट क्लिक> निरीक्षण करें ताकि ब्राउज़र डेवटूल्स खुलें।\n2. फिर ब्राउज़र के \"एप्लिकेशन\" टैब (Chrome, Edge, Brave आदि) या \"स्टोरेज\" टैब (Firefox, Palemoon आदि) में जाएं\n3. \"कुकीज़\" अनुभाग में जाएं फिर \"https: //accounts.spotify.com\" उप-अनुभाग में जाएं", "step_3": "स्टेप 3", - "step_3_steps": "\"sp_dc\" और \"sp_key\" (या sp_gaid) कुकीज़ के मान कॉपी करें", "success_emoji": "सफलता🥳", "success_message": "अब आप अपने स्पॉटिफाई अकाउंट से सफलतापूर्वक लॉगइन हो गए हैं। अच्छा काम किया!", "step_4": "स्टेप 4", - "step_4_steps": "कॉपी की गई \"sp_dc\" और \"sp_key\" (या sp_gaid) मानों को संबंधित फील्ड में पेस्ट करें", "something_went_wrong": "कुछ गलत हो गया", "piped_instance": "पाइप्ड सर्वर", "piped_description": "पाइप किए गए सर्वर", diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index 033bb516..3680933a 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -177,11 +177,9 @@ "step_2": "Passo 2", "step_2_steps": "1. Quando sei acceduto premi F12 o premi il tasto destro del Mouse > Ispeziona per aprire gli strumenti di sviluppo del browser.\n2. Vai quindi nel tab \"Applicazione\" (Chrome, Edge, Brave etc..) o tab \"Archiviazione\" (Firefox, Palemoon etc..)\n3. Vai nella sezione \"Cookies\" quindi nella sezione \"https://accounts.spotify.com\"", "step_3": "Passo 3", - "step_3_steps": "Copia il valore dei cookie \"sp_dc\" e \"sp_key\" (o sp_gaid)", "success_emoji": "Successo🥳", "success_message": "Ora hai correttamente effettuato il login al tuo account Spotify. Bel lavoro, amico!", "step_4": "Passo 4", - "step_4_steps": "Incolla i valori copiati di \"sp_dc\" e \"sp_key\" (o sp_gaid) nei campi rispettivi", "something_went_wrong": "Qualcosa è andato storto", "piped_instance": "Istanza Server Piped", "piped_description": "L'istanza server Piped da usare per il match della tracccia", diff --git a/lib/l10n/app_ja.arb b/lib/l10n/app_ja.arb index ac23728b..39e0dad8 100644 --- a/lib/l10n/app_ja.arb +++ b/lib/l10n/app_ja.arb @@ -175,11 +175,9 @@ "step_2": "ステップ 2", "step_2_steps": "1. ログインしたら、F12を押すか、マウス右クリック > 調査(検証)でブラウザの開発者ツール (devtools) を開きます。\n2. アプリケーション (Application) タブ (Chrome, Edge, Brave など) またはストレージタブ (Firefox, Palemoon など)\n3. Cookies 欄を選択し、https://accounts.spotify.com の枝を選びます", "step_3": "ステップ 3", - "step_3_steps": "sp_dc と sp_key (または or sp_gaid) の値 (Value) をコピーします", "success_emoji": "成功🥳", "success_message": "アカウントへのログインに成功しました。よくできました!", "step_4": "ステップ 4", - "step_4_steps": "コピーした sp_dc と sp_key (または or sp_gaid) の値をそれぞれの入力欄に貼り付けます", "something_went_wrong": "何か誤りがあります", "piped_instance": "Piped サーバーのインスタンス", "piped_description": "曲の一致に使う Piped サーバーのインスタンス", diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index 6e50c461..23eee51b 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -177,11 +177,9 @@ "step_2": "Stap 2", "step_2_steps": "1. Zodra je bent aangemeld, druk je op F12 of klik je met de rechtermuisknop > Inspect om de Browser devtools te openen.\n2. Ga vervolgens naar het tabblad \"Toepassing\" (Chrome, Edge, Brave enz..) of naar het tabblad \"Opslag\" (Firefox, Palemoon enz..).\n3. Ga naar de sectie \"Cookies\" en vervolgens naar de subsectie \"https://accounts.spotify.com\".", "step_3": "Stap 3", - "step_3_steps": "Kopieer de waarden van \"sp_dc\" en \"sp_key\" (of sp_gaid) Cookies", "success_emoji": "Succes🥳", "success_message": "Je bent nu succesvol ingelogd met je Spotify account. Goed gedaan, maat!", "step_4": "Stap 4", - "step_4_steps": "Plak de gekopieerde \"sp_dc\" en \"sp_key\" (of sp_gaid) waarden in de respectievelijke velden", "something_went_wrong": "Er ging iets mis", "piped_instance": "Piped-serverinstantie", "piped_description": "De Piped-serverinstantie die moet worden gebruikt voor het matchen van sporen", diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index dd173a37..4ae48338 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -175,11 +175,9 @@ "step_2": "Krok 2", "step_2_steps": "1. Jeśli jesteś zalogowany, naciśnij klawisz F12 lub Kliknij prawym przyciskiem myszy > Zbadaj, aby odtworzyć narzędzia developerskie.\n2. Następnie przejdź do zakładki \"Application\" (Chrome, Edge, Brave etc..) lub zakładki \"Storage\" (Firefox, Palemoon etc..)\n3. Przejdź do sekcji \"Cookies\" a następnie do pod-sekcji \"https://accounts.spotify.com\"", "step_3": "Krok 3", - "step_3_steps": "Skopiuj wartości \"sp_dc\" i \"sp_key\" (lub sp_gaid) Ciasteczek", "success_emoji": "Sukces!🥳", "success_message": "Udało ci się zalogować! Dobra robota, stary!", "step_4": "Krok 4", - "step_4_steps": "Wklej wartości \"sp_dc\" i \"sp_key\" (lub sp_gaid) do odpowiednich pul.", "something_went_wrong": "Coś poszło nie tak 🙁", "piped_instance": "Instancja serwera Piped", "piped_description": "Instancja serwera Piped używana jest do dopasowania utworów.", diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 705217c1..5ea4cca0 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -175,11 +175,9 @@ "step_2": "Passo 2", "step_2_steps": "1. Uma vez logado, pressione F12 ou clique com o botão direito do mouse > Inspecionar para abrir as ferramentas de desenvolvimento do navegador.\n2. Em seguida, vá para a guia \"Aplicativo\" (Chrome, Edge, Brave, etc.) ou \"Armazenamento\" (Firefox, Palemoon, etc.)\n3. Acesse a seção \"Cookies\" e depois a subseção \"https://accounts.spotify.com\"", "step_3": "Passo 3", - "step_3_steps": "Copie os valores dos Cookies \"sp_dc\" e \"sp_key\" (ou sp_gaid)", "success_emoji": "Sucesso🥳", "success_message": "Agora você está logado com sucesso em sua conta do Spotify. Bom trabalho!", "step_4": "Passo 4", - "step_4_steps": "Cole os valores copiados \"sp_dc\" e \"sp_key\" (ou sp_gaid) nos campos correspondentes", "something_went_wrong": "Algo deu errado", "piped_instance": "Instância do Servidor Piped", "piped_description": "A instância do servidor Piped a ser usada para correspondência de faixas", diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index 32415863..24120d62 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -175,11 +175,9 @@ "step_2": "Шаг 2", "step_2_steps": "1. После входа в систему нажмите F12 или щелкните правой кнопкой мыши > «Проверить», чтобы открыть инструменты разработчика браузера.\n2. Затем перейдите на вкладку \"Application\" (Chrome, Edge, Brave и т.д..) or \"Storage\" (Firefox, Palemoon и т.д..)\n3. Перейдите в раздел \"Cookies\", а затем в подраздел \"https://accounts.spotify.com\"", "step_3": "Шаг 3", - "step_3_steps": "Скопируйте значения \"sp_dc\" и \"sp_key\" (или sp_gaid) Cookies", "success_emoji": "Успешно 🥳", "success_message": "Теперь вы успешно вошли в свою учетную запись Spotify. Отличная работа, приятель!", "step_4": "Шаг 4", - "step_4_steps": "Вставьте скопированные \"sp_dc\" и \"sp_key\" (или sp_gaid) значения в соответствующие поля", "something_went_wrong": "Что-то пошло не так", "piped_instance": "Экземпляр сервера Piped", "piped_description": "Серверный экземпляр Piped для сопоставления треков", diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb index 63646af6..e6b0ce34 100644 --- a/lib/l10n/app_tr.arb +++ b/lib/l10n/app_tr.arb @@ -177,11 +177,9 @@ "step_2": "2. Adım", "step_2_steps": "1. Giriş yaptıktan sonra, Tarayıcı devtools.\n2'yi açmak için F12'ye basın veya Fare Sağ Tıklaması > İncele'ye basın. Ardından \"Uygulama\" Sekmesine (Chrome, Edge, Brave vb.) veya \"Depolama\" Sekmesine (Firefox, Palemoon vb.) gidin\n3. \"Çerezler\" bölümüne ve ardından \"https://accounts.spotify.com\" alt bölümüne gidin", "step_3": "3. Adım", - "step_3_steps": "\"sp_dc\" ve \"sp_key\" (veya sp_gaid) Çerezlerinin değerlerini kopyalayın", "success_emoji": "Başarılı🥳", "success_message": "Şimdi Spotify hesabınızla başarılı bir şekilde oturum açtınız. İyi iş, dostum!", "step_4": "4. Adım", - "step_4_steps": "Kopyalanan \"sp_dc\" ve \"sp_key\" (veya sp_gaid) değerlerini ilgili alanlara yapıştırın", "something_went_wrong": "Bir şeyler ters gitti", "piped_instance": "Piped Sunucu Örneği", "piped_description": "Parça eşleştirme için kullanılacak Piped sunucu örneği", diff --git a/lib/l10n/app_uk.arb b/lib/l10n/app_uk.arb index 2ae29237..a5199a04 100644 --- a/lib/l10n/app_uk.arb +++ b/lib/l10n/app_uk.arb @@ -177,11 +177,9 @@ "step_2": "Крок 2", "step_2_steps": "1. Після входу натисніть F12 або клацніть правою кнопкою миші > Інспектувати, щоб відкрити інструменти розробки браузера.\n2. Потім перейдіть на вкладку 'Програма' (Chrome, Edge, Brave тощо) або вкладку 'Сховище' (Firefox, Palemoon тощо).\n3. Перейдіть до розділу 'Кукі-файли', а потім до підрозділу 'https://accounts.spotify.com'", "step_3": "Крок 3", - "step_3_steps": "Скопіюйте значення кукі-файлів 'sp_dc' та 'sp_key' (або sp_gaid)", "success_emoji": "Успіх🥳", "success_message": "Тепер ви успішно ввійшли у свій обліковий запис Spotify. Гарна робота, друже!", "step_4": "Крок 4", - "step_4_steps": "Вставте скопійовані значення 'sp_dc' та 'sp_key' (або sp_gaid) у відповідні поля", "something_went_wrong": "Щось пішло не так", "piped_instance": "Примірник сервера Piped", "piped_description": "Примірник сервера Piped, який використовуватиметься для зіставлення треків", diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index 85b57724..30f4a82c 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -175,11 +175,9 @@ "step_2": "步骤 2", "step_2_steps": "1. 一旦你已经完成登录, 按 F12 键或者鼠标右击网页空白区域 > 选择“检查”以打开浏览器开发者工具(DevTools)\n2. 然后选择 \"应用(Application)\" 标签页(Chrome, Edge, Brave 等基于 Chromium 的浏览器) 或 \"存储(Storage)\" 标签页 (Firefox, Palemoon 等基于 Firefox 的浏览器))\n3. 选择 \"Cookies\" 栏目然后选择 \"https://accounts.spotify.com\" 子栏目", "step_3": "步骤 3", - "step_3_steps": "复制名称为 \"sp_dc\" 和 \"sp_key\" (或 sp_gaid) 的值(Cookie Value)", "success_emoji": "成功🥳", "success_message": "你已经成功使用 Spotify 登录。干得漂亮!", "step_4": "步骤 4", - "step_4_steps": "将 \"sp_dc\" 与 \"sp_key\" (或 sp_gaid) 的值分别复制后粘贴到对应的区域", "something_went_wrong": "某些地方出现了问题", "piped_instance": "管道服务器实例", "piped_description": "管道服务器实例用于匹配歌曲", diff --git a/lib/pages/mobile_login/mobile_login.dart b/lib/pages/mobile_login/mobile_login.dart index 7ab0ea2a..8b9bce4c 100644 --- a/lib/pages/mobile_login/mobile_login.dart +++ b/lib/pages/mobile_login/mobile_login.dart @@ -55,12 +55,7 @@ class WebViewLogin extends HookConsumerWidget { final cookies = await CookieManager.instance().getCookies(url: action); final cookieHeader = - cookies.fold("", (previousValue, element) { - if (element.name == "sp_dc" || element.name == "sp_key") { - return "$previousValue; ${element.name}=${element.value}"; - } - return previousValue; - }); + "sp_dc=${cookies.firstWhere((element) => element.name == "sp_dc").value}"; authenticationNotifier.setCredentials( await AuthenticationCredentials.fromCookie(cookieHeader), diff --git a/untranslated_messages.json b/untranslated_messages.json index 9e26dfee..59b26614 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -1 +1,86 @@ -{} \ No newline at end of file +{ + "ar": [ + "step_3_steps", + "step_4_steps" + ], + + "bn": [ + "step_3_steps", + "step_4_steps" + ], + + "ca": [ + "step_3_steps", + "step_4_steps" + ], + + "de": [ + "step_3_steps", + "step_4_steps" + ], + + "es": [ + "step_3_steps", + "step_4_steps" + ], + + "fa": [ + "step_3_steps", + "step_4_steps" + ], + + "fr": [ + "step_3_steps", + "step_4_steps" + ], + + "hi": [ + "step_3_steps", + "step_4_steps" + ], + + "it": [ + "step_3_steps", + "step_4_steps" + ], + + "ja": [ + "step_3_steps", + "step_4_steps" + ], + + "nl": [ + "step_3_steps", + "step_4_steps" + ], + + "pl": [ + "step_3_steps", + "step_4_steps" + ], + + "pt": [ + "step_3_steps", + "step_4_steps" + ], + + "ru": [ + "step_3_steps", + "step_4_steps" + ], + + "tr": [ + "step_3_steps", + "step_4_steps" + ], + + "uk": [ + "step_3_steps", + "step_4_steps" + ], + + "zh": [ + "step_3_steps", + "step_4_steps" + ] +} From a76ee0acf2615a41b0527163cbd7e1d20fed226d Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 8 Jan 2024 22:57:03 +0600 Subject: [PATCH 2/8] chore: new liked tracks image --- assets/liked-tracks.jpg | Bin 0 -> 27058 bytes lib/components/library/user_playlists.dart | 30 +++++++++--------- .../sections/header/flexible_header.dart | 3 +- lib/pages/playlist/liked_playlist.dart | 6 +--- 4 files changed, 17 insertions(+), 22 deletions(-) create mode 100644 assets/liked-tracks.jpg diff --git a/assets/liked-tracks.jpg b/assets/liked-tracks.jpg new file mode 100644 index 0000000000000000000000000000000000000000..62dad65ea112e49db84afab026803502c221a249 GIT binary patch literal 27058 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 literal 0 HcmV?d00001 diff --git a/lib/components/library/user_playlists.dart b/lib/components/library/user_playlists.dart index a65c6d0e..32e91ed6 100644 --- a/lib/components/library/user_playlists.dart +++ b/lib/components/library/user_playlists.dart @@ -37,21 +37,21 @@ class UserPlaylists extends HookConsumerWidget { ); final likedTracksPlaylist = useMemoized( - () => PlaylistSimple() - ..name = context.l10n.liked_tracks - ..description = context.l10n.liked_tracks_description - ..type = "playlist" - ..collaborative = false - ..public = false - ..id = "user-liked-tracks" - ..images = [ - Image() - ..height = 300 - ..width = 300 - ..url = - "https://t.scdn.co/images/3099b3803ad9496896c43f22fe9be8c4.png" - ], - [context.l10n]); + () => PlaylistSimple() + ..name = context.l10n.liked_tracks + ..description = context.l10n.liked_tracks_description + ..type = "playlist" + ..collaborative = false + ..public = false + ..id = "user-liked-tracks" + ..images = [ + Image() + ..height = 300 + ..width = 300 + ..url = "assets/liked-tracks.jpg" + ], + [context.l10n], + ); final playlists = useMemoized( () { diff --git a/lib/components/shared/tracks_view/sections/header/flexible_header.dart b/lib/components/shared/tracks_view/sections/header/flexible_header.dart index e16ccbff..19241dc6 100644 --- a/lib/components/shared/tracks_view/sections/header/flexible_header.dart +++ b/lib/components/shared/tracks_view/sections/header/flexible_header.dart @@ -1,6 +1,5 @@ import 'dart:ui'; -import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; @@ -62,7 +61,7 @@ class TrackViewFlexHeader extends HookConsumerWidget { clipBehavior: Clip.hardEdge, decoration: BoxDecoration( image: DecorationImage( - image: CachedNetworkImageProvider(props.image), + image: UniversalImage.imageProvider(props.image), fit: BoxFit.cover, ), ), diff --git a/lib/pages/playlist/liked_playlist.dart b/lib/pages/playlist/liked_playlist.dart index 5972a303..1fb2e1dc 100644 --- a/lib/pages/playlist/liked_playlist.dart +++ b/lib/pages/playlist/liked_playlist.dart @@ -4,7 +4,6 @@ import 'package:spotify/spotify.dart'; import 'package:spotube/components/shared/tracks_view/track_view.dart'; import 'package:spotube/components/shared/tracks_view/track_view_props.dart'; import 'package:spotube/services/queries/queries.dart'; -import 'package:spotube/utils/type_conversion_utils.dart'; class LikedPlaylistPage extends HookConsumerWidget { final PlaylistSimple playlist; @@ -20,10 +19,7 @@ class LikedPlaylistPage extends HookConsumerWidget { return InheritedTrackView( collectionId: playlist.id!, - image: TypeConversionUtils.image_X_UrlString( - playlist.images, - placeholder: ImagePlaceholder.collection, - ), + image: "assets/liked-tracks.jpg", pagination: PaginationProps( hasNextPage: false, isLoading: false, From 3d344bdcddb193e7faf4d292bc5a5286e858d5f6 Mon Sep 17 00:00:00 2001 From: MerkomassDev <70111455+MerkomassDev@users.noreply.github.com> Date: Thu, 11 Jan 2024 05:07:36 +0100 Subject: [PATCH 3/8] docs: Readme.md rephrasing (#914) * Rephrased README.md * Update README.md Put extra emphasis on the fact that Shows and Podcasts can ONLY be accessed with spotify premium * One line fix in README.md last change was unnecessary :) --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 2736d1f1..e637f6c6 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,10 @@ Spotube Logo An open source, cross-platform Spotify client compatible across multiple platforms
-utilizing Spotify's data API and YouTube (or Piped.video or JioSaavn) as an audio source,
+utilizing Spotify's data API and YouTube, Piped.video or JioSaavn as an audio source,
eliminating the need for Spotify Premium -Btw it's not another Electron app😉 +Btw it's not just another Electron app 😉 Visit the website Discord Server @@ -26,7 +26,7 @@ Btw it's not another Electron app😉 ## 🌃 Features - 🚫 No ads, thanks to the use of public & free Spotify and YT Music APIs¹ -- ⬇️ Downloadable tracks +- ⬇️ Freely downloadable tracks - 🖥️ 📱 Cross-platform support - 🪶 Small size & less data usage - 🕵️ Anonymous/guest login @@ -40,13 +40,13 @@ Btw it's not another Electron app😉 ### ❌ Unsupported features -- 🗣️ **Spotify Shows & Podcasts:** Shows and Podcasts can **never be supported** because the audio tracks are _only_ available on Spotify and accessing them would require Spotify Premium. +- 🗣️ **Spotify Shows & Podcasts:** Shows and Podcasts will **never be supported** because the audio tracks are _only_ available on Spotify and accessing them would require Spotify Premium. - 🎧 **Spotify Listen Along:** [Coming soon!](https://github.com/KRTirtho/spotube/issues/8) ## 📜 ⬇️ Installation guide -New releases usually appear after 3-4 months.
-This handy table lists all methods you can use to install Spotube: +New versions usually release every 3-4 months.
+This handy table lists all the methods you can use to install Spotube: From 27057ea0c8d83c9701057c18b473f1af4e4e82be Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 22 Jan 2024 17:20:30 +0600 Subject: [PATCH 4/8] fix(macos): system tray shows name and sidebar weird gap #1083 --- .vscode/launch.json | 6 + lib/collections/assets.gen.dart | 3 + lib/components/root/sidebar.dart | 2 +- .../configurators/use_init_sys_tray.dart | 2 +- macos/Podfile | 2 +- macos/Podfile.lock | 135 ++++++++++++------ macos/Runner.xcodeproj/project.pbxproj | 17 +-- .../xcshareddata/xcschemes/Runner.xcscheme | 2 +- 8 files changed, 112 insertions(+), 57 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 9add0735..7a1e8b9b 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -6,6 +6,12 @@ "type": "dart", "request": "launch", "program": "lib/main.dart", + }, + { + "name": "spotube (mobile)", + "type": "dart", + "request": "launch", + "program": "lib/main.dart", "args": [ "--flavor", "dev" diff --git a/lib/collections/assets.gen.dart b/lib/collections/assets.gen.dart index ac39cf68..d7149834 100644 --- a/lib/collections/assets.gen.dart +++ b/lib/collections/assets.gen.dart @@ -34,6 +34,8 @@ class Assets { AssetGenImage('assets/bengali-patterns-bg.jpg'); static const AssetGenImage branding = AssetGenImage('assets/branding.png'); static const AssetGenImage emptyBox = AssetGenImage('assets/empty_box.png'); + static const AssetGenImage likedTracks = + AssetGenImage('assets/liked-tracks.jpg'); static const AssetGenImage placeholder = AssetGenImage('assets/placeholder.png'); static const AssetGenImage spotubeHeroBanner = @@ -74,6 +76,7 @@ class Assets { bengaliPatternsBg, branding, emptyBox, + likedTracks, placeholder, spotubeHeroBanner, spotubeLogoForeground, diff --git a/lib/components/root/sidebar.dart b/lib/components/root/sidebar.dart index ac5233ed..9b3fd3ed 100644 --- a/lib/components/root/sidebar.dart +++ b/lib/components/root/sidebar.dart @@ -159,7 +159,7 @@ class Sidebar extends HookConsumerWidget { margin: EdgeInsets.only( bottom: 10, left: 0, - top: kIsMacOS ? 35 : 5, + top: kIsMacOS ? 0 : 5, ), padding: const EdgeInsets.symmetric(horizontal: 6), decoration: BoxDecoration( diff --git a/lib/hooks/configurators/use_init_sys_tray.dart b/lib/hooks/configurators/use_init_sys_tray.dart index db4964ce..8080bea6 100644 --- a/lib/hooks/configurators/use_init_sys_tray.dart +++ b/lib/hooks/configurators/use_init_sys_tray.dart @@ -25,7 +25,7 @@ void useInitSysTray(WidgetRef ref) { } final enabled = !playlist.isFetching; systemTray.value = await DesktopTools.createSystemTrayMenu( - title: DesktopTools.platform.isLinux ? "" : "Spotube", + title: DesktopTools.platform.isWindows ? "Spotube" : "", iconPath: "assets/spotube-logo.png", windowsIconPath: "assets/spotube-logo.ico", items: [ diff --git a/macos/Podfile b/macos/Podfile index fe733905..049abe29 100644 --- a/macos/Podfile +++ b/macos/Podfile @@ -1,4 +1,4 @@ -platform :osx, '10.13' +platform :osx, '10.14' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/macos/Podfile.lock b/macos/Podfile.lock index 99c0177d..65fe3535 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -1,101 +1,146 @@ PODS: + - app_links (1.0.0): + - FlutterMacOS - audio_service (0.14.1): - FlutterMacOS - audio_session (0.0.1): - FlutterMacOS - - audioplayers_darwin (0.0.1): + - device_info_plus (0.0.1): - FlutterMacOS - - bitsdojo_window_macos (0.0.1): + - file_selector_macos (0.0.1): - FlutterMacOS - - connectivity_plus_macos (0.0.1): + - flutter_secure_storage_macos (6.1.1): - FlutterMacOS - - ReachabilitySwift - FlutterMacOS (1.0.0) - FMDB (2.7.5): - FMDB/standard (= 2.7.5) - FMDB/standard (2.7.5) - - macos_ui (0.1.0): + - local_notifier (0.1.0): - FlutterMacOS - - metadata_god (0.0.1): + - media_kit_libs_macos_audio (1.0.4): - FlutterMacOS - - package_info_plus_macos (0.0.1): + - media_kit_native_event_loop (1.0.0): - FlutterMacOS - - path_provider_macos (0.0.1): + - metadata_god (0.0.1) + - package_info_plus (0.0.1): - FlutterMacOS - - ReachabilitySwift (5.0.0) - - shared_preferences_macos (0.0.1): + - path_provider_foundation (0.0.1): + - Flutter + - FlutterMacOS + - screen_retriever (0.0.1): + - FlutterMacOS + - shared_preferences_foundation (0.0.1): + - Flutter - FlutterMacOS - sqflite (0.0.2): - FlutterMacOS - FMDB (>= 2.7.5) + - system_theme (0.0.1): + - FlutterMacOS + - system_tray (0.0.1): + - FlutterMacOS - url_launcher_macos (0.0.1): - FlutterMacOS + - window_manager (0.2.0): + - FlutterMacOS + - window_size (0.0.2): + - FlutterMacOS DEPENDENCIES: + - app_links (from `Flutter/ephemeral/.symlinks/plugins/app_links/macos`) - audio_service (from `Flutter/ephemeral/.symlinks/plugins/audio_service/macos`) - audio_session (from `Flutter/ephemeral/.symlinks/plugins/audio_session/macos`) - - audioplayers_darwin (from `Flutter/ephemeral/.symlinks/plugins/audioplayers_darwin/macos`) - - bitsdojo_window_macos (from `Flutter/ephemeral/.symlinks/plugins/bitsdojo_window_macos/macos`) - - connectivity_plus_macos (from `Flutter/ephemeral/.symlinks/plugins/connectivity_plus_macos/macos`) + - device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`) + - file_selector_macos (from `Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos`) + - flutter_secure_storage_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos`) - FlutterMacOS (from `Flutter/ephemeral`) - - macos_ui (from `Flutter/ephemeral/.symlinks/plugins/macos_ui/macos`) + - local_notifier (from `Flutter/ephemeral/.symlinks/plugins/local_notifier/macos`) + - media_kit_libs_macos_audio (from `Flutter/ephemeral/.symlinks/plugins/media_kit_libs_macos_audio/macos`) + - media_kit_native_event_loop (from `Flutter/ephemeral/.symlinks/plugins/media_kit_native_event_loop/macos`) - metadata_god (from `Flutter/ephemeral/.symlinks/plugins/metadata_god/macos`) - - package_info_plus_macos (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus_macos/macos`) - - path_provider_macos (from `Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos`) - - shared_preferences_macos (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_macos/macos`) + - package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`) + - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) + - screen_retriever (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos`) + - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) - sqflite (from `Flutter/ephemeral/.symlinks/plugins/sqflite/macos`) + - system_theme (from `Flutter/ephemeral/.symlinks/plugins/system_theme/macos`) + - system_tray (from `Flutter/ephemeral/.symlinks/plugins/system_tray/macos`) - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) + - window_manager (from `Flutter/ephemeral/.symlinks/plugins/window_manager/macos`) + - window_size (from `Flutter/ephemeral/.symlinks/plugins/window_size/macos`) SPEC REPOS: trunk: - FMDB - - ReachabilitySwift EXTERNAL SOURCES: + app_links: + :path: Flutter/ephemeral/.symlinks/plugins/app_links/macos audio_service: :path: Flutter/ephemeral/.symlinks/plugins/audio_service/macos audio_session: :path: Flutter/ephemeral/.symlinks/plugins/audio_session/macos - audioplayers_darwin: - :path: Flutter/ephemeral/.symlinks/plugins/audioplayers_darwin/macos - bitsdojo_window_macos: - :path: Flutter/ephemeral/.symlinks/plugins/bitsdojo_window_macos/macos - connectivity_plus_macos: - :path: Flutter/ephemeral/.symlinks/plugins/connectivity_plus_macos/macos + device_info_plus: + :path: Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos + file_selector_macos: + :path: Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos + flutter_secure_storage_macos: + :path: Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos FlutterMacOS: :path: Flutter/ephemeral - macos_ui: - :path: Flutter/ephemeral/.symlinks/plugins/macos_ui/macos + local_notifier: + :path: Flutter/ephemeral/.symlinks/plugins/local_notifier/macos + media_kit_libs_macos_audio: + :path: Flutter/ephemeral/.symlinks/plugins/media_kit_libs_macos_audio/macos + media_kit_native_event_loop: + :path: Flutter/ephemeral/.symlinks/plugins/media_kit_native_event_loop/macos metadata_god: :path: Flutter/ephemeral/.symlinks/plugins/metadata_god/macos - package_info_plus_macos: - :path: Flutter/ephemeral/.symlinks/plugins/package_info_plus_macos/macos - path_provider_macos: - :path: Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos - shared_preferences_macos: - :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_macos/macos + package_info_plus: + :path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos + path_provider_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin + screen_retriever: + :path: Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos + shared_preferences_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin sqflite: :path: Flutter/ephemeral/.symlinks/plugins/sqflite/macos + system_theme: + :path: Flutter/ephemeral/.symlinks/plugins/system_theme/macos + system_tray: + :path: Flutter/ephemeral/.symlinks/plugins/system_tray/macos url_launcher_macos: :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos + window_manager: + :path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos + window_size: + :path: Flutter/ephemeral/.symlinks/plugins/window_size/macos SPEC CHECKSUMS: + app_links: 4481ed4d71f384b0c3ae5016f4633aa73d32ff67 audio_service: b88ff778e0e3915efd4cd1a5ad6f0beef0c950a9 audio_session: dea1f41890dbf1718f04a56f1d6150fd50039b72 - audioplayers_darwin: dcad41de4fbd0099cb3749f7ab3b0cb8f70b810c - bitsdojo_window_macos: 44e3b8fe3dd463820e0321f6256c5b1c16bb6a00 - connectivity_plus_macos: f6e86fd000e971d361e54b5afcadc8c8fa773308 - FlutterMacOS: ae6af50a8ea7d6103d888583d46bd8328a7e9811 + device_info_plus: 5401765fde0b8d062a2f8eb65510fb17e77cf07f + file_selector_macos: 468fb6b81fac7c0e88d71317f3eec34c3b008ff9 + flutter_secure_storage_macos: d56e2d218c1130b262bef8b4a7d64f88d7f9c9ea + FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a - macos_ui: 125c911559d646194386d84c017ad6819122e2db - metadata_god: 55a71136c95eb75ec28142f6fbfc2bcff6f881b1 - package_info_plus_macos: f010621b07802a241d96d01876d6705f15e77c1c - path_provider_macos: 3c0c3b4b0d4a76d2bf989a913c2de869c5641a19 - ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825 - shared_preferences_macos: a64dc611287ed6cbe28fd1297898db1336975727 + local_notifier: e9506bc66fc70311e8bc7291fb70f743c081e4ff + media_kit_libs_macos_audio: 3871782a4f3f84c77f04d7666c87800a781c24da + media_kit_native_event_loop: 7321675377cb9ae8596a29bddf3a3d2b5e8792c5 + metadata_god: eceae399d0020475069a5cebc35943ce8562b5d7 + package_info_plus: 02d7a575e80f194102bef286361c6c326e4c29ce + path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 + screen_retriever: 59634572a57080243dd1bf715e55b6c54f241a38 + shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126 sqflite: a5789cceda41d54d23f31d6de539d65bb14100ea - url_launcher_macos: 597e05b8e514239626bcf4a850fcf9ef5c856ec3 + system_theme: c7b9f6659a5caa26c9bc2284da096781e9a6fcbc + system_tray: e53c972838c69589ff2e77d6d3abfd71332f9e5d + url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95 + window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8 + window_size: 339dafa0b27a95a62a843042038fa6c3c48de195 -PODFILE CHECKSUM: a884f6dd3f7494f3892ee6c81feea3a3abbf9153 +PODFILE CHECKSUM: 353c8bcc5d5b0994e508d035b5431cfe18c1dea7 -COCOAPODS: 1.11.3 +COCOAPODS: 1.14.3 diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index 9b86152a..f7711c83 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 51; + objectVersion = 54; objects = { /* Begin PBXAggregateTarget section */ @@ -208,7 +208,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1430; ORGANIZATIONNAME = ""; TargetAttributes = { 33CC10EC2044A3C60003C045 = { @@ -261,6 +261,7 @@ /* Begin PBXShellScriptBuildPhase section */ 3399D490228B24CF009A79C7 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -409,7 +410,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.14; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; @@ -431,7 +432,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.14; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; @@ -489,7 +490,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.14; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; @@ -536,7 +537,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.14; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; @@ -558,7 +559,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.14; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -579,7 +580,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.14; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; diff --git a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 741e68bc..8f69f0c6 100644 --- a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ Date: Mon, 22 Jan 2024 17:51:12 +0600 Subject: [PATCH 5/8] fix: artist page error #1018 --- .../spotify_endpoints.dart | 56 +++++++++++++++++++ lib/services/queries/artist.dart | 7 ++- 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/lib/services/custom_spotify_endpoints/spotify_endpoints.dart b/lib/services/custom_spotify_endpoints/spotify_endpoints.dart index 4a55130a..0510e69a 100644 --- a/lib/services/custom_spotify_endpoints/spotify_endpoints.dart +++ b/lib/services/custom_spotify_endpoints/spotify_endpoints.dart @@ -162,4 +162,60 @@ class CustomSpotifyEndpoints { result["tracks"].map((track) => Track.fromJson(track)).toList(), ); } + + Future artist({required String id}) async { + final pathQuery = "$_baseUrl/artists/$id"; + + final res = await _client.get( + Uri.parse(pathQuery), + headers: { + "content-type": "application/json", + if (accessToken.isNotEmpty) "authorization": "Bearer $accessToken", + "accept": "application/json", + }, + ); + + final data = jsonDecode(res.body); + + return Artist.fromJson(_purifyArtistResponse(data)); + } + + Future> relatedArtists({required String id}) async { + final pathQuery = "$_baseUrl/artists/$id/related-artists"; + + final res = await _client.get( + Uri.parse(pathQuery), + headers: { + "content-type": "application/json", + if (accessToken.isNotEmpty) "authorization": "Bearer $accessToken", + "accept": "application/json", + }, + ); + + final data = jsonDecode(res.body); + + return List.castFrom( + data["artists"] + .map((artist) => Artist.fromJson(_purifyArtistResponse(artist))) + .toList(), + ); + } + + Map _purifyArtistResponse(Map data) { + if (data["popularity"] != null) { + data["popularity"] = data["popularity"].toInt(); + } + if (data["followers"]?["total"] != null) { + data["followers"]["total"] = data["followers"]["total"].toInt(); + } + if (data["images"] != null) { + data["images"] = data["images"].map((e) { + e["height"] = e["height"].toInt(); + e["width"] = e["width"].toInt(); + return e; + }).toList(); + } + + return data; + } } diff --git a/lib/services/queries/artist.dart b/lib/services/queries/artist.dart index 1b939c82..5ccc4955 100644 --- a/lib/services/queries/artist.dart +++ b/lib/services/queries/artist.dart @@ -4,6 +4,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/hooks/spotify/use_spotify_infinite_query.dart'; import 'package:spotube/hooks/spotify/use_spotify_query.dart'; +import 'package:spotube/provider/custom_spotify_endpoint_provider.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/services/wikipedia/wikipedia.dart'; import 'package:wikipedia_api/wikipedia_api.dart'; @@ -15,9 +16,10 @@ class ArtistQueries { WidgetRef ref, String artist, ) { + final customSpotify = ref.watch(customSpotifyEndpointProvider); return useSpotifyQuery( "artist-profile/$artist", - (spotify) => spotify.artists.get(artist), + (spotify) => customSpotify.artist(id: artist), ref: ref, ); } @@ -125,10 +127,11 @@ class ArtistQueries { WidgetRef ref, String artist, ) { + final customSpotify = ref.watch(customSpotifyEndpointProvider); return useSpotifyQuery, dynamic>( "artist-related-artist-query/$artist", (spotify) { - return spotify.artists.relatedArtists(artist); + return customSpotify.relatedArtists(id: artist); }, ref: ref, ); From 59e0e6bb659b70831f6e0ae064100381c57f149c Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 22 Jan 2024 18:03:08 +0600 Subject: [PATCH 6/8] fix: track pad horizontal scrolling not working --- .../horizontal_playbutton_card_view.dart | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart b/lib/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart index 2075acbb..dc9d30da 100644 --- a/lib/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart +++ b/lib/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart @@ -60,10 +60,7 @@ class HorizontalPlaybuttonCardView extends HookWidget { onNotification: (notification) => true, child: ScrollConfiguration( behavior: ScrollConfiguration.of(context).copyWith( - dragDevices: { - PointerDeviceKind.touch, - PointerDeviceKind.mouse, - }, + dragDevices: PointerDeviceKind.values.toSet(), ), child: items.isEmpty ? ListView.builder( From a8e9b824f33add8f6a83f0d147e889eb6beeb442 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 22 Jan 2024 19:02:10 +0600 Subject: [PATCH 7/8] fix: alternative searched sources doesn't play #1059 --- assets/jiosaavn.png | Bin 0 -> 14045 bytes lib/collections/assets.gen.dart | 2 + lib/collections/spotube_icons.dart | 1 + .../player/sibling_tracks_sheet.dart | 54 ++++++++++++++++-- lib/services/sourced_track/enums.dart | 2 +- .../sourced_track/sources/jiosaavn.dart | 25 ++++++-- lib/services/sourced_track/sources/piped.dart | 27 +++++++-- .../sourced_track/sources/youtube.dart | 27 +++++++-- 8 files changed, 117 insertions(+), 21 deletions(-) create mode 100644 assets/jiosaavn.png diff --git a/assets/jiosaavn.png b/assets/jiosaavn.png new file mode 100644 index 0000000000000000000000000000000000000000..4d2d46e4b079fa9d1a60ef10a3aab3dd96750b90 GIT binary patch literal 14045 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 literal 0 HcmV?d00001 diff --git a/lib/collections/assets.gen.dart b/lib/collections/assets.gen.dart index d7149834..2587800e 100644 --- a/lib/collections/assets.gen.dart +++ b/lib/collections/assets.gen.dart @@ -34,6 +34,7 @@ class Assets { AssetGenImage('assets/bengali-patterns-bg.jpg'); static const AssetGenImage branding = AssetGenImage('assets/branding.png'); static const AssetGenImage emptyBox = AssetGenImage('assets/empty_box.png'); + static const AssetGenImage jiosaavn = AssetGenImage('assets/jiosaavn.png'); static const AssetGenImage likedTracks = AssetGenImage('assets/liked-tracks.jpg'); static const AssetGenImage placeholder = @@ -76,6 +77,7 @@ class Assets { bengaliPatternsBg, branding, emptyBox, + jiosaavn, likedTracks, placeholder, spotubeHeroBanner, diff --git a/lib/collections/spotube_icons.dart b/lib/collections/spotube_icons.dart index 00010aae..c6acd669 100644 --- a/lib/collections/spotube_icons.dart +++ b/lib/collections/spotube_icons.dart @@ -109,4 +109,5 @@ abstract class SpotubeIcons { static const normalize = FeatherIcons.barChart2; static const wikipedia = SimpleIcons.wikipedia; static const discord = SimpleIcons.discord; + static const youtube = SimpleIcons.youtube; } diff --git a/lib/components/player/sibling_tracks_sheet.dart b/lib/components/player/sibling_tracks_sheet.dart index cf1429b9..181c363a 100644 --- a/lib/components/player/sibling_tracks_sheet.dart +++ b/lib/components/player/sibling_tracks_sheet.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart' hide Offset; +import 'package:spotube/collections/assets.gen.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/shared/image/universal_image.dart'; @@ -19,10 +20,28 @@ import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; import 'package:spotube/services/sourced_track/models/source_info.dart'; import 'package:spotube/services/sourced_track/models/video_info.dart'; import 'package:spotube/services/sourced_track/sourced_track.dart'; +import 'package:spotube/services/sourced_track/sources/jiosaavn.dart'; +import 'package:spotube/services/sourced_track/sources/piped.dart'; import 'package:spotube/services/sourced_track/sources/youtube.dart'; import 'package:spotube/utils/service_utils.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; +final sourceInfoToIconMap = { + YoutubeSourceInfo: const Icon(SpotubeIcons.youtube, color: Color(0xFFFF0000)), + JioSaavnSourceInfo: Container( + height: 30, + width: 30, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(90), + image: DecorationImage( + image: Assets.jiosaavn.provider(), + fit: BoxFit.cover, + ), + ), + ), + PipedSourceInfo: const Icon(SpotubeIcons.piped), +}; + class SiblingTracksSheet extends HookConsumerWidget { final bool floating; const SiblingTracksSheet({ @@ -64,17 +83,34 @@ class SiblingTracksSheet extends HookConsumerWidget { return []; } - final results = await youtubeClient.search.search(searchTerm.trim()); + final resultsYt = await youtubeClient.search.search(searchTerm.trim()); + final resultsJioSaavn = + await jiosaavnClient.search.songs(searchTerm.trim()); - return await Future.wait( - results.map(YoutubeVideoInfo.fromVideo).mapIndexed((i, video) async { + final searchResults = await Future.wait([ + ...resultsJioSaavn.results.mapIndexed((i, song) async { + final siblingType = JioSaavnSourcedTrack.toSiblingType(song); + return siblingType.info; + }), + ...resultsYt + .map(YoutubeVideoInfo.fromVideo) + .mapIndexed((i, video) async { final siblingType = await YoutubeSourcedTrack.toSiblingType(i, video); return siblingType.info; }), - ); + ]); + final activeSourceInfo = + (playlist.activeTrack! as SourcedTrack).sourceInfo; + return searchResults + ..removeWhere((element) => element.id == activeSourceInfo.id) + ..insert( + 0, + activeSourceInfo, + ); }, [ searchTerm, searchMode.value, + playlist.activeTrack, ]); final siblings = useMemoized( @@ -104,6 +140,7 @@ class SiblingTracksSheet extends HookConsumerWidget { final itemBuilder = useCallback( (SourceInfo sourceInfo) { + final icon = sourceInfoToIconMap[sourceInfo.runtimeType]; return ListTile( title: Text(sourceInfo.title), leading: Padding( @@ -118,7 +155,12 @@ class SiblingTracksSheet extends HookConsumerWidget { borderRadius: BorderRadius.circular(5), ), trailing: Text(sourceInfo.duration.toHumanReadableString()), - subtitle: Text(sourceInfo.artist), + subtitle: Row( + children: [ + if (icon != null) icon, + Text(" • ${sourceInfo.artist}"), + ], + ), enabled: playlist.isFetching != true, selected: playlist.isFetching != true && sourceInfo.id == @@ -137,7 +179,7 @@ class SiblingTracksSheet extends HookConsumerWidget { [playlist.isFetching, playlist.activeTrack, siblings], ); - var mediaQuery = MediaQuery.of(context); + final mediaQuery = MediaQuery.of(context); return SafeArea( child: ClipRRect( borderRadius: borderRadius, diff --git a/lib/services/sourced_track/enums.dart b/lib/services/sourced_track/enums.dart index 48ce1cbd..e47ee6bd 100644 --- a/lib/services/sourced_track/enums.dart +++ b/lib/services/sourced_track/enums.dart @@ -15,4 +15,4 @@ enum SourceQualities { low, } -typedef SiblingType = ({SourceInfo info, SourceMap? source}); +typedef SiblingType = ({T info, SourceMap? source}); diff --git a/lib/services/sourced_track/sources/jiosaavn.dart b/lib/services/sourced_track/sources/jiosaavn.dart index a447b0c1..281be998 100644 --- a/lib/services/sourced_track/sources/jiosaavn.dart +++ b/lib/services/sourced_track/sources/jiosaavn.dart @@ -12,6 +12,19 @@ import 'package:spotube/extensions/string.dart'; final jiosaavnClient = JioSaavnClient(); +class JioSaavnSourceInfo extends SourceInfo { + JioSaavnSourceInfo({ + required super.id, + required super.title, + required super.artist, + required super.thumbnail, + required super.pageUrl, + required super.duration, + required super.artistUrl, + required super.album, + }); +} + class JioSaavnSourcedTrack extends SourcedTrack { JioSaavnSourcedTrack({ required super.ref, @@ -70,7 +83,7 @@ class JioSaavnSourcedTrack extends SourcedTrack { static SiblingType toSiblingType(SongResponse result) { final SiblingType sibling = ( - info: SourceInfo( + info: JioSaavnSourceInfo( artist: [ result.primaryArtists, if (result.featuredArtists.isNotEmpty) ", ", @@ -155,12 +168,16 @@ class JioSaavnSourcedTrack extends SourcedTrack { @override Future swapWithSibling(SourceInfo sibling) async { - if (sibling.id == sourceInfo.id || - siblings.none((s) => s.id == sibling.id)) { + if (sibling.id == sourceInfo.id) { return null; } - final newSourceInfo = siblings.firstWhere((s) => s.id == sibling.id); + // a sibling source that was fetched from the search results + final isStepSibling = siblings.none((s) => s.id == sibling.id); + + final newSourceInfo = isStepSibling + ? sibling + : siblings.firstWhere((s) => s.id == sibling.id); final newSiblings = siblings.where((s) => s.id != sibling.id).toList() ..insert(0, sourceInfo); diff --git a/lib/services/sourced_track/sources/piped.dart b/lib/services/sourced_track/sources/piped.dart index 0778a7cf..f9e4368d 100644 --- a/lib/services/sourced_track/sources/piped.dart +++ b/lib/services/sourced_track/sources/piped.dart @@ -22,6 +22,19 @@ final pipedProvider = Provider( }, ); +class PipedSourceInfo extends SourceInfo { + PipedSourceInfo({ + required super.id, + required super.title, + required super.artist, + required super.thumbnail, + required super.pageUrl, + required super.duration, + required super.artistUrl, + required super.album, + }); +} + class PipedSourcedTrack extends SourcedTrack { PipedSourcedTrack({ required super.ref, @@ -71,7 +84,7 @@ class PipedSourcedTrack extends SourcedTrack { ref: ref, siblings: [], source: toSourceMap(manifest), - sourceInfo: SourceInfo( + sourceInfo: PipedSourceInfo( id: manifest.id, artist: manifest.uploader, artistUrl: manifest.uploaderUrl, @@ -122,7 +135,7 @@ class PipedSourcedTrack extends SourcedTrack { } final SiblingType sibling = ( - info: SourceInfo( + info: PipedSourceInfo( id: item.id, artist: item.channelName, artistUrl: "https://www.youtube.com/${item.channelId}", @@ -233,12 +246,16 @@ class PipedSourcedTrack extends SourcedTrack { @override Future swapWithSibling(SourceInfo sibling) async { - if (sibling.id == sourceInfo.id || - siblings.none((s) => s.id == sibling.id)) { + if (sibling.id == sourceInfo.id) { return null; } - final newSourceInfo = siblings.firstWhere((s) => s.id == sibling.id); + // a sibling source that was fetched from the search results + final isStepSibling = siblings.none((s) => s.id == sibling.id); + + final newSourceInfo = isStepSibling + ? sibling + : siblings.firstWhere((s) => s.id == sibling.id); final newSiblings = siblings.where((s) => s.id != sibling.id).toList() ..insert(0, sourceInfo); diff --git a/lib/services/sourced_track/sources/youtube.dart b/lib/services/sourced_track/sources/youtube.dart index 2bcd6e3e..c4105d75 100644 --- a/lib/services/sourced_track/sources/youtube.dart +++ b/lib/services/sourced_track/sources/youtube.dart @@ -17,6 +17,19 @@ final officialMusicRegex = RegExp( caseSensitive: false, ); +class YoutubeSourceInfo extends SourceInfo { + YoutubeSourceInfo({ + required super.id, + required super.title, + required super.artist, + required super.thumbnail, + required super.pageUrl, + required super.duration, + required super.artistUrl, + required super.album, + }); +} + class YoutubeSourcedTrack extends SourcedTrack { YoutubeSourcedTrack({ required super.source, @@ -64,7 +77,7 @@ class YoutubeSourcedTrack extends SourcedTrack { ref: ref, siblings: [], source: toSourceMap(manifest), - sourceInfo: SourceInfo( + sourceInfo: YoutubeSourceInfo( id: item.id.value, artist: item.author, artistUrl: "https://www.youtube.com/channel/${item.channelId}", @@ -117,7 +130,7 @@ class YoutubeSourcedTrack extends SourcedTrack { } final SiblingType sibling = ( - info: SourceInfo( + info: YoutubeSourceInfo( id: item.id, artist: item.channelName, artistUrl: "https://www.youtube.com/channel/${item.channelId}", @@ -217,12 +230,16 @@ class YoutubeSourcedTrack extends SourcedTrack { @override Future swapWithSibling(SourceInfo sibling) async { - if (sibling.id == sourceInfo.id || - siblings.none((s) => s.id == sibling.id)) { + if (sibling.id == sourceInfo.id) { return null; } - final newSourceInfo = siblings.firstWhere((s) => s.id == sibling.id); + // a sibling source that was fetched from the search results + final isStepSibling = siblings.none((s) => s.id == sibling.id); + + final newSourceInfo = isStepSibling + ? sibling + : siblings.firstWhere((s) => s.id == sibling.id); final newSiblings = siblings.where((s) => s.id != sibling.id).toList() ..insert(0, sourceInfo); From 682e88e0c55bc0f4708bc0b4681b129e5c61c999 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 22 Jan 2024 19:09:57 +0600 Subject: [PATCH 8/8] fix: releases section is empty when user doesn't follow any artists #1104 --- .../home/sections/new_releases.dart | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/lib/components/home/sections/new_releases.dart b/lib/components/home/sections/new_releases.dart index 77481de1..0f4a046a 100644 --- a/lib/components/home/sections/new_releases.dart +++ b/lib/components/home/sections/new_releases.dart @@ -21,16 +21,21 @@ class HomeNewReleasesSection extends HookConsumerWidget { userArtistsQuery.data?.map((s) => s.id!).toList() ?? const []; final albums = useMemoized( - () => newReleases.pages - .whereType>() - .expand((page) => page.items ?? const []) - .where((album) { - return album.artists - ?.any((artist) => userArtists.contains(artist.id!)) == - true; - }) - .map((album) => TypeConversionUtils.simpleAlbum_X_Album(album)) - .toList(), + () { + final allReleases = newReleases.pages + .whereType>() + .expand((page) => page.items ?? const []) + .map((album) => TypeConversionUtils.simpleAlbum_X_Album(album)); + + final userArtistReleases = allReleases.where((album) { + return album.artists + ?.any((artist) => userArtists.contains(artist.id!)) == + true; + }).toList(); + + if (userArtistReleases.isEmpty) return allReleases.toList(); + return userArtistReleases; + }, [newReleases.pages], );