From 806b22ec855301d93ac5f8f24be7979bd974af43 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 23 Aug 2023 11:13:46 +0600 Subject: [PATCH 001/112] website: upgrade to next 13 --- website/components/Navbar.tsx | 2 +- website/package.json | 42 +- website/pages/about/index.tsx | 2 +- website/pages/index.tsx | 20 +- website/pnpm-lock.yaml | 3239 ++++++++++++++++++++------------- 5 files changed, 1987 insertions(+), 1318 deletions(-) diff --git a/website/components/Navbar.tsx b/website/components/Navbar.tsx index 7084b917..2da65d77 100644 --- a/website/components/Navbar.tsx +++ b/website/components/Navbar.tsx @@ -17,7 +17,7 @@ import { import NavLink from "next/link"; import { GoLightBulb } from "react-icons/go"; import { FiGithub, FiSun } from "react-icons/fi"; -import Image from "next/image"; +import Image from "next/legacy/image"; import React from "react"; import { AiOutlineMenu } from "react-icons/ai"; import { BsHeartFill } from "react-icons/bs"; diff --git a/website/package.json b/website/package.json index de3f7033..d975154a 100644 --- a/website/package.json +++ b/website/package.json @@ -9,35 +9,35 @@ "lint": "next lint" }, "dependencies": { - "@babel/core": "^7.18.6", - "@chakra-ui/react": "^2.2.4", - "@chakra-ui/system": "^2.2.2", - "@chakra-ui/theme-tools": "^2.0.5", - "@emotion/react": "^11", - "@emotion/styled": "^11", - "@octokit/rest": "^19.0.3", + "@babel/core": "^7.22.10", + "@chakra-ui/react": "^2.8.0", + "@chakra-ui/system": "^2.6.0", + "@chakra-ui/theme-tools": "^2.1.0", + "@emotion/react": "^11.11.1", + "@emotion/styled": "^11.11.0", + "@octokit/rest": "^20.0.1", "@types/progress": "^2.0.5", "detect-browser": "^5.3.0", - "framer-motion": "^6", + "framer-motion": "^10", "gray-matter": "^4.0.3", - "next": "12.2.2", - "nextjs-progressbar": "^0.0.14", + "next": "13.4.19", + "nextjs-progressbar": "^0.0.16", "react": "18.2.0", "react-dom": "18.2.0", - "react-icons": "^4.4.0", - "react-markdown": "^8.0.3", + "react-icons": "^4.10.1", + "react-markdown": "^8.0.7", "remark-gemoji": "^7.0.1", "remark-gfm": "^3.0.1", - "swr": "^1.3.0" + "swr": "^2.2.1" }, "devDependencies": { - "@types/node": "18.0.5", - "@types/react": "18.0.15", - "@types/react-dom": "18.0.6", - "@types/react-syntax-highlighter": "^15.5.3", - "eslint": "8.20.0", - "eslint-config-next": "12.2.2", - "eslint-config-prettier": "^8.5.0", - "typescript": "4.7.4" + "@types/node": "20.5.3", + "@types/react": "18.2.21", + "@types/react-dom": "18.2.7", + "@types/react-syntax-highlighter": "^15.5.7", + "eslint": "8.47.0", + "eslint-config-next": "13.4.19", + "eslint-config-prettier": "^9.0.0", + "typescript": "5.1.6" } } diff --git a/website/pages/about/index.tsx b/website/pages/about/index.tsx index 868ee45e..a1692fd9 100644 --- a/website/pages/about/index.tsx +++ b/website/pages/about/index.tsx @@ -9,7 +9,7 @@ import UserDetailedCard from "components/UserDetailedCard"; import { octokit } from "configurations/ocotokit"; import useSwr from "swr"; -const maintainers = ["KRTirtho", "RustyApple"]; +const maintainers = ["KRTirtho", "RustyApple", "raptag"]; const About = () => { const { data } = useSwr("contributors", () => diff --git a/website/pages/index.tsx b/website/pages/index.tsx index 770ffc41..8671b773 100755 --- a/website/pages/index.tsx +++ b/website/pages/index.tsx @@ -7,7 +7,7 @@ import { useColorModeValue, } from "@chakra-ui/react"; import DownloadButton from "components/DownloadButton"; -import Image from 'next/image'; +import Image from "next/legacy/image"; const Root = () => { const textColor = useColorModeValue("#171717", "#f5f5f5"); @@ -23,7 +23,12 @@ const Root = () => { bgSize="contain" bgPos={useColorModeValue("right", "left")} > - + { {
Download Now - Download Spotube for every platform you want. It's available everywhere. + Download Spotube for every platform you want. It's available + everywhere.
diff --git a/website/pnpm-lock.yaml b/website/pnpm-lock.yaml index 0f9242d8..60410abf 100644 --- a/website/pnpm-lock.yaml +++ b/website/pnpm-lock.yaml @@ -2,26 +2,26 @@ lockfileVersion: '6.0' dependencies: '@babel/core': - specifier: ^7.18.6 - version: 7.18.6 + specifier: ^7.22.10 + version: 7.22.10 '@chakra-ui/react': - specifier: ^2.2.4 - version: 2.2.4(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(@types/react@18.0.15)(framer-motion@6.5.1)(react-dom@18.2.0)(react@18.2.0) + specifier: ^2.8.0 + version: 2.8.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.21)(framer-motion@10.0.0)(react-dom@18.2.0)(react@18.2.0) '@chakra-ui/system': - specifier: ^2.2.2 - version: 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) + specifier: ^2.6.0 + version: 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) '@chakra-ui/theme-tools': - specifier: ^2.0.5 - version: 2.0.5(@chakra-ui/system@2.2.2) + specifier: ^2.1.0 + version: 2.1.0(@chakra-ui/styled-system@2.9.1) '@emotion/react': - specifier: ^11 - version: 11.9.3(@babel/core@7.18.6)(@types/react@18.0.15)(react@18.2.0) + specifier: ^11.11.1 + version: 11.11.1(@types/react@18.2.21)(react@18.2.0) '@emotion/styled': - specifier: ^11 - version: 11.9.3(@babel/core@7.18.6)(@emotion/react@11.9.3)(@types/react@18.0.15)(react@18.2.0) + specifier: ^11.11.0 + version: 11.11.0(@emotion/react@11.11.1)(@types/react@18.2.21)(react@18.2.0) '@octokit/rest': - specifier: ^19.0.3 - version: 19.0.3 + specifier: ^20.0.1 + version: 20.0.1 '@types/progress': specifier: ^2.0.5 version: 2.0.5 @@ -29,17 +29,17 @@ dependencies: specifier: ^5.3.0 version: 5.3.0 framer-motion: - specifier: ^6 - version: 6.5.1(react-dom@18.2.0)(react@18.2.0) + specifier: ^10 + version: 10.0.0(react-dom@18.2.0)(react@18.2.0) gray-matter: specifier: ^4.0.3 version: 4.0.3 next: - specifier: 12.2.2 - version: 12.2.2(@babel/core@7.18.6)(react-dom@18.2.0)(react@18.2.0) + specifier: 13.4.19 + version: 13.4.19(@babel/core@7.22.10)(react-dom@18.2.0)(react@18.2.0) nextjs-progressbar: - specifier: ^0.0.14 - version: 0.0.14(next@12.2.2)(react@18.2.0) + specifier: ^0.0.16 + version: 0.0.16(next@13.4.19)(react@18.2.0) react: specifier: 18.2.0 version: 18.2.0 @@ -47,11 +47,11 @@ dependencies: specifier: 18.2.0 version: 18.2.0(react@18.2.0) react-icons: - specifier: ^4.4.0 - version: 4.4.0(react@18.2.0) + specifier: ^4.10.1 + version: 4.10.1(react@18.2.0) react-markdown: - specifier: ^8.0.3 - version: 8.0.3(@types/react@18.0.15)(react@18.2.0) + specifier: ^8.0.7 + version: 8.0.7(@types/react@18.2.21)(react@18.2.0) remark-gemoji: specifier: ^7.0.1 version: 7.0.1 @@ -59,37 +59,42 @@ dependencies: specifier: ^3.0.1 version: 3.0.1 swr: - specifier: ^1.3.0 - version: 1.3.0(react@18.2.0) + specifier: ^2.2.1 + version: 2.2.1(react@18.2.0) devDependencies: '@types/node': - specifier: 18.0.5 - version: 18.0.5 + specifier: 20.5.3 + version: 20.5.3 '@types/react': - specifier: 18.0.15 - version: 18.0.15 + specifier: 18.2.21 + version: 18.2.21 '@types/react-dom': - specifier: 18.0.6 - version: 18.0.6 + specifier: 18.2.7 + version: 18.2.7 '@types/react-syntax-highlighter': - specifier: ^15.5.3 - version: 15.5.3 + specifier: ^15.5.7 + version: 15.5.7 eslint: - specifier: 8.20.0 - version: 8.20.0 + specifier: 8.47.0 + version: 8.47.0 eslint-config-next: - specifier: 12.2.2 - version: 12.2.2(eslint@8.20.0)(typescript@4.7.4) + specifier: 13.4.19 + version: 13.4.19(eslint@8.47.0)(typescript@5.1.6) eslint-config-prettier: - specifier: ^8.5.0 - version: 8.5.0(eslint@8.20.0) + specifier: ^9.0.0 + version: 9.0.0(eslint@8.47.0) typescript: - specifier: 4.7.4 - version: 4.7.4 + specifier: 5.1.6 + version: 5.1.6 packages: + /@aashutoshrathi/word-wrap@1.2.6: + resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} + engines: {node: '>=0.10.0'} + dev: true + /@ampproject/remapping@2.2.0: resolution: {integrity: sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==} engines: {node: '>=6.0.0'} @@ -98,171 +103,166 @@ packages: '@jridgewell/trace-mapping': 0.3.14 dev: false - /@babel/code-frame@7.18.6: - resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==} + /@babel/code-frame@7.22.10: + resolution: {integrity: sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/highlight': 7.18.6 + '@babel/highlight': 7.22.10 + chalk: 2.4.2 dev: false - /@babel/compat-data@7.18.8: - resolution: {integrity: sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ==} + /@babel/compat-data@7.22.9: + resolution: {integrity: sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==} engines: {node: '>=6.9.0'} dev: false - /@babel/core@7.18.6: - resolution: {integrity: sha512-cQbWBpxcbbs/IUredIPkHiAGULLV8iwgNRMFzvbhEXISp4f3rUUXE5+TIw6KwUWUR3DwyI6gmBRnmAtYaWehwQ==} + /@babel/core@7.22.10: + resolution: {integrity: sha512-fTmqbbUBAwCcre6zPzNngvsI0aNrPZe77AeqvDxWM9Nm+04RrJ3CAmGHA9f7lJQY6ZMhRztNemy4uslDxTX4Qw==} engines: {node: '>=6.9.0'} dependencies: '@ampproject/remapping': 2.2.0 - '@babel/code-frame': 7.18.6 - '@babel/generator': 7.18.7 - '@babel/helper-compilation-targets': 7.18.6(@babel/core@7.18.6) - '@babel/helper-module-transforms': 7.18.8 - '@babel/helpers': 7.18.6 - '@babel/parser': 7.18.8 - '@babel/template': 7.18.6 - '@babel/traverse': 7.18.8 - '@babel/types': 7.18.8 + '@babel/code-frame': 7.22.10 + '@babel/generator': 7.22.10 + '@babel/helper-compilation-targets': 7.22.10 + '@babel/helper-module-transforms': 7.22.9(@babel/core@7.22.10) + '@babel/helpers': 7.22.10 + '@babel/parser': 7.22.10 + '@babel/template': 7.22.5 + '@babel/traverse': 7.22.10 + '@babel/types': 7.22.10 convert-source-map: 1.8.0 debug: 4.3.4 gensync: 1.0.0-beta.2 - json5: 2.2.1 - semver: 6.3.0 + json5: 2.2.3 + semver: 6.3.1 transitivePeerDependencies: - supports-color dev: false - /@babel/generator@7.18.7: - resolution: {integrity: sha512-shck+7VLlY72a2w9c3zYWuE1pwOKEiQHV7GTUbSnhyl5eu3i04t30tBY82ZRWrDfo3gkakCFtevExnxbkf2a3A==} + /@babel/generator@7.22.10: + resolution: {integrity: sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.18.8 + '@babel/types': 7.22.10 '@jridgewell/gen-mapping': 0.3.2 + '@jridgewell/trace-mapping': 0.3.19 jsesc: 2.5.2 dev: false - /@babel/helper-compilation-targets@7.18.6(@babel/core@7.18.6): - resolution: {integrity: sha512-vFjbfhNCzqdeAtZflUFrG5YIFqGTqsctrtkZ1D/NB0mDW9TwW3GmmUepYY4G9wCET5rY5ugz4OGTcLd614IzQg==} + /@babel/helper-compilation-targets@7.22.10: + resolution: {integrity: sha512-JMSwHD4J7SLod0idLq5PKgI+6g/hLD/iuWBq08ZX49xE14VpVEojJ5rHWptpirV2j020MvypRLAXAO50igCJ5Q==} engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 dependencies: - '@babel/compat-data': 7.18.8 - '@babel/core': 7.18.6 - '@babel/helper-validator-option': 7.18.6 - browserslist: 4.21.2 - semver: 6.3.0 + '@babel/compat-data': 7.22.9 + '@babel/helper-validator-option': 7.22.5 + browserslist: 4.21.10 + lru-cache: 5.1.1 + semver: 6.3.1 dev: false - /@babel/helper-environment-visitor@7.18.6: - resolution: {integrity: sha512-8n6gSfn2baOY+qlp+VSzsosjCVGFqWKmDF0cCWOybh52Dw3SEyoWR1KrhMJASjLwIEkkAufZ0xvr+SxLHSpy2Q==} + /@babel/helper-environment-visitor@7.22.5: + resolution: {integrity: sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==} engines: {node: '>=6.9.0'} dev: false - /@babel/helper-function-name@7.18.6: - resolution: {integrity: sha512-0mWMxV1aC97dhjCah5U5Ua7668r5ZmSC2DLfH2EZnf9c3/dHZKiFa5pRLMH5tjSl471tY6496ZWk/kjNONBxhw==} + /@babel/helper-function-name@7.22.5: + resolution: {integrity: sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==} engines: {node: '>=6.9.0'} dependencies: - '@babel/template': 7.18.6 - '@babel/types': 7.18.8 + '@babel/template': 7.22.5 + '@babel/types': 7.22.10 dev: false - /@babel/helper-hoist-variables@7.18.6: - resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==} + /@babel/helper-hoist-variables@7.22.5: + resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.18.8 + '@babel/types': 7.22.10 dev: false /@babel/helper-module-imports@7.18.6: resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.18.8 + '@babel/types': 7.22.10 dev: false - /@babel/helper-module-transforms@7.18.8: - resolution: {integrity: sha512-che3jvZwIcZxrwh63VfnFTUzcAM9v/lznYkkRxIBGMPt1SudOKHAEec0SIRCfiuIzTcF7VGj/CaTT6gY4eWxvA==} + /@babel/helper-module-imports@7.22.5: + resolution: {integrity: sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-environment-visitor': 7.18.6 - '@babel/helper-module-imports': 7.18.6 - '@babel/helper-simple-access': 7.18.6 - '@babel/helper-split-export-declaration': 7.18.6 - '@babel/helper-validator-identifier': 7.18.6 - '@babel/template': 7.18.6 - '@babel/traverse': 7.18.8 - '@babel/types': 7.18.8 + '@babel/types': 7.22.10 + dev: false + + /@babel/helper-module-transforms@7.22.9(@babel/core@7.22.10): + resolution: {integrity: sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.22.10 + '@babel/helper-environment-visitor': 7.22.5 + '@babel/helper-module-imports': 7.22.5 + '@babel/helper-simple-access': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/helper-validator-identifier': 7.22.5 + dev: false + + /@babel/helper-simple-access@7.22.5: + resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.22.10 + dev: false + + /@babel/helper-split-export-declaration@7.22.6: + resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.22.10 + dev: false + + /@babel/helper-string-parser@7.22.5: + resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==} + engines: {node: '>=6.9.0'} + dev: false + + /@babel/helper-validator-identifier@7.22.5: + resolution: {integrity: sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==} + engines: {node: '>=6.9.0'} + dev: false + + /@babel/helper-validator-option@7.22.5: + resolution: {integrity: sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==} + engines: {node: '>=6.9.0'} + dev: false + + /@babel/helpers@7.22.10: + resolution: {integrity: sha512-a41J4NW8HyZa1I1vAndrraTlPZ/eZoga2ZgS7fEr0tZJGVU4xqdE80CEm0CcNjha5EZ8fTBYLKHF0kqDUuAwQw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.22.5 + '@babel/traverse': 7.22.10 + '@babel/types': 7.22.10 transitivePeerDependencies: - supports-color dev: false - /@babel/helper-plugin-utils@7.18.6: - resolution: {integrity: sha512-gvZnm1YAAxh13eJdkb9EWHBnF3eAub3XTLCZEehHT2kWxiKVRL64+ae5Y6Ivne0mVHmMYKT+xWgZO+gQhuLUBg==} - engines: {node: '>=6.9.0'} - dev: false - - /@babel/helper-simple-access@7.18.6: - resolution: {integrity: sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==} + /@babel/highlight@7.22.10: + resolution: {integrity: sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.18.8 - dev: false - - /@babel/helper-split-export-declaration@7.18.6: - resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.18.8 - dev: false - - /@babel/helper-validator-identifier@7.18.6: - resolution: {integrity: sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==} - engines: {node: '>=6.9.0'} - dev: false - - /@babel/helper-validator-option@7.18.6: - resolution: {integrity: sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==} - engines: {node: '>=6.9.0'} - dev: false - - /@babel/helpers@7.18.6: - resolution: {integrity: sha512-vzSiiqbQOghPngUYt/zWGvK3LAsPhz55vc9XNN0xAl2gV4ieShI2OQli5duxWHD+72PZPTKAcfcZDE1Cwc5zsQ==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/template': 7.18.6 - '@babel/traverse': 7.18.8 - '@babel/types': 7.18.8 - transitivePeerDependencies: - - supports-color - dev: false - - /@babel/highlight@7.18.6: - resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-validator-identifier': 7.18.6 + '@babel/helper-validator-identifier': 7.22.5 chalk: 2.4.2 js-tokens: 4.0.0 dev: false - /@babel/parser@7.18.8: - resolution: {integrity: sha512-RSKRfYX20dyH+elbJK2uqAkVyucL+xXzhqlMD5/ZXx+dAAwpyB7HsvnHe/ZUGOF+xLr5Wx9/JoXVTj6BQE2/oA==} + /@babel/parser@7.22.10: + resolution: {integrity: sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ==} engines: {node: '>=6.0.0'} hasBin: true dependencies: - '@babel/types': 7.18.8 - dev: false - - /@babel/plugin-syntax-jsx@7.18.6(@babel/core@7.18.6): - resolution: {integrity: sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.18.6 - '@babel/helper-plugin-utils': 7.18.6 + '@babel/types': 7.22.10 dev: false /@babel/runtime-corejs3@7.18.6: @@ -279,515 +279,762 @@ packages: dependencies: regenerator-runtime: 0.13.9 - /@babel/template@7.18.6: - resolution: {integrity: sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw==} + /@babel/template@7.22.5: + resolution: {integrity: sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.18.6 - '@babel/parser': 7.18.8 - '@babel/types': 7.18.8 + '@babel/code-frame': 7.22.10 + '@babel/parser': 7.22.10 + '@babel/types': 7.22.10 dev: false - /@babel/traverse@7.18.8: - resolution: {integrity: sha512-UNg/AcSySJYR/+mIcJQDCv00T+AqRO7j/ZEJLzpaYtgM48rMg5MnkJgyNqkzo88+p4tfRvZJCEiwwfG6h4jkRg==} + /@babel/traverse@7.22.10: + resolution: {integrity: sha512-Q/urqV4pRByiNNpb/f5OSv28ZlGJiFiiTh+GAHktbIrkPhPbl90+uW6SmpoLyZqutrg9AEaEf3Q/ZBRHBXgxig==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.18.6 - '@babel/generator': 7.18.7 - '@babel/helper-environment-visitor': 7.18.6 - '@babel/helper-function-name': 7.18.6 - '@babel/helper-hoist-variables': 7.18.6 - '@babel/helper-split-export-declaration': 7.18.6 - '@babel/parser': 7.18.8 - '@babel/types': 7.18.8 + '@babel/code-frame': 7.22.10 + '@babel/generator': 7.22.10 + '@babel/helper-environment-visitor': 7.22.5 + '@babel/helper-function-name': 7.22.5 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/parser': 7.22.10 + '@babel/types': 7.22.10 debug: 4.3.4 globals: 11.12.0 transitivePeerDependencies: - supports-color dev: false - /@babel/types@7.18.8: - resolution: {integrity: sha512-qwpdsmraq0aJ3osLJRApsc2ouSJCdnMeZwB0DhbtHAtRpZNZCdlbRnHIgcRKzdE1g0iOGg644fzjOBcdOz9cPw==} + /@babel/types@7.22.10: + resolution: {integrity: sha512-obaoigiLrlDZ7TUQln/8m4mSqIW2QFeOrCQc9r+xsaHGNoplVNYlRVpsfE8Vj35GEm2ZH4ZhrNYogs/3fj85kg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-validator-identifier': 7.18.6 + '@babel/helper-string-parser': 7.22.5 + '@babel/helper-validator-identifier': 7.22.5 to-fast-properties: 2.0.0 dev: false - /@chakra-ui/accordion@2.0.6(@chakra-ui/system@2.2.2)(framer-motion@6.5.1)(react@18.2.0): - resolution: {integrity: sha512-1wPSSk2ZbiIHV4W/HMrv0t+jxiLMTDFVFd92ru8loFtU1AjNJ068OlJJs2V5hz4mbriC0nDctMxDJmT0zmPNaA==} + /@chakra-ui/accordion@2.3.0(@chakra-ui/system@2.6.0)(framer-motion@10.0.0)(react@18.2.0): + resolution: {integrity: sha512-A4TkRw3Jnt+Fam6dSSJ62rskdrvjF3JGctYcfXlojfFIpHPuIw4pDwfZgNAxlaxWkcj0e7JJKlQ88dnZW+QfFg==} peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' + '@chakra-ui/system': '>=2.0.0' framer-motion: '>=4.0.0' react: '>=18' dependencies: - '@chakra-ui/descendant': 3.0.3(react@18.2.0) - '@chakra-ui/hooks': 2.0.4(react@18.2.0) - '@chakra-ui/icon': 3.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/react-utils': 2.0.1(react@18.2.0) - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/transition': 2.0.4(framer-motion@6.5.1)(react@18.2.0) - '@chakra-ui/utils': 2.0.4 - framer-motion: 6.5.1(react-dom@18.2.0)(react@18.2.0) + '@chakra-ui/descendant': 3.1.0(react@18.2.0) + '@chakra-ui/icon': 3.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/react-context': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-controllable-state': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-merge-refs': 2.1.0(react@18.2.0) + '@chakra-ui/shared-utils': 2.0.5 + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) + '@chakra-ui/transition': 2.1.0(framer-motion@10.0.0)(react@18.2.0) + framer-motion: 10.0.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 dev: false - /@chakra-ui/alert@2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0): - resolution: {integrity: sha512-n9YA7IivGI5DzTeSGoqjTnI+Rvk5FHRaieAJAlCoFbj+5QQQu7oOGvWRVVbe/SAYONV0yG35PBiv0zGGV0whtg==} + /@chakra-ui/alert@2.2.0(@chakra-ui/system@2.6.0)(react@18.2.0): + resolution: {integrity: sha512-De+BT88iYOu3Con7MxQeICb1SwgAdVdgpHIYjTh3qvGlNXAQjs81rhG0fONXvwW1FIYletvr9DY2Tlg8xJe7tQ==} peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' + '@chakra-ui/system': '>=2.0.0' react: '>=18' dependencies: - '@chakra-ui/icon': 3.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/react-utils': 2.0.1(react@18.2.0) - '@chakra-ui/spinner': 2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/utils': 2.0.4 + '@chakra-ui/icon': 3.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/react-context': 2.1.0(react@18.2.0) + '@chakra-ui/shared-utils': 2.0.5 + '@chakra-ui/spinner': 2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) react: 18.2.0 dev: false - /@chakra-ui/anatomy@2.0.1(@chakra-ui/system@2.2.2): - resolution: {integrity: sha512-lbOUfPmCtgIe0G7Iu6C2MaFP3FKOHgKWxDrYc3498TQ7/z5N1r7AO6jB+gFRGDbxJNLjRGOLG7tV0bufagGTUw==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' - dependencies: - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/theme-tools': 2.0.5(@chakra-ui/system@2.2.2) + /@chakra-ui/anatomy@2.2.0: + resolution: {integrity: sha512-cD8Ms5C8+dFda0LrORMdxiFhAZwOIY1BSlCadz6/mHUIgNdQy13AHPrXiq6qWdMslqVHq10k5zH7xMPLt6kjFg==} dev: false - /@chakra-ui/avatar@2.0.5(@chakra-ui/system@2.2.2)(react@18.2.0): - resolution: {integrity: sha512-FkheIKRUY9eltGgEyiOUIrBHQdgLA3Z/6WydIAU929SuAN2JuQnDZPH8BauTsddW+R3qhRLu1+tIC+HQtOTLxA==} + /@chakra-ui/avatar@2.3.0(@chakra-ui/system@2.6.0)(react@18.2.0): + resolution: {integrity: sha512-8gKSyLfygnaotbJbDMHDiJoF38OHXUYVme4gGxZ1fLnQEdPVEaIWfH+NndIjOM0z8S+YEFnT9KyGMUtvPrBk3g==} peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' + '@chakra-ui/system': '>=2.0.0' react: '>=18' dependencies: - '@chakra-ui/image': 2.0.5(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/react-utils': 2.0.1(react@18.2.0) - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/utils': 2.0.4 + '@chakra-ui/image': 2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/react-children-utils': 2.0.6(react@18.2.0) + '@chakra-ui/react-context': 2.1.0(react@18.2.0) + '@chakra-ui/shared-utils': 2.0.5 + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) react: 18.2.0 dev: false - /@chakra-ui/breadcrumb@2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0): - resolution: {integrity: sha512-Vr4H09I03DSGuZk3aST2af2ln69S3cO3/2E9gkzeWj3Wo3AYZrwuxUTtujmERao6EWOKlMqaA1x/hNpRubW9JA==} + /@chakra-ui/breadcrumb@2.2.0(@chakra-ui/system@2.6.0)(react@18.2.0): + resolution: {integrity: sha512-4cWCG24flYBxjruRi4RJREWTGF74L/KzI2CognAW/d/zWR0CjiScuJhf37Am3LFbCySP6WSoyBOtTIoTA4yLEA==} peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' + '@chakra-ui/system': '>=2.0.0' react: '>=18' dependencies: - '@chakra-ui/react-utils': 2.0.1(react@18.2.0) - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/utils': 2.0.4 + '@chakra-ui/react-children-utils': 2.0.6(react@18.2.0) + '@chakra-ui/react-context': 2.1.0(react@18.2.0) + '@chakra-ui/shared-utils': 2.0.5 + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) react: 18.2.0 dev: false - /@chakra-ui/button@2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0): - resolution: {integrity: sha512-bhae6Vw0rrwkyz72Y0//aWO80jM6VblFf9kuMnHLtO1y+I3ptWnx7jjN3865xn/PJl3lu1AzuHn67DuNuvZ2UQ==} + /@chakra-ui/breakpoint-utils@2.0.8: + resolution: {integrity: sha512-Pq32MlEX9fwb5j5xx8s18zJMARNHlQZH2VH1RZgfgRDpp7DcEgtRW5AInfN5CfqdHLO1dGxA7I3MqEuL5JnIsA==} + dependencies: + '@chakra-ui/shared-utils': 2.0.5 + dev: false + + /@chakra-ui/button@2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0): + resolution: {integrity: sha512-95CplwlRKmmUXkdEp/21VkEWgnwcx2TOBG6NfYlsuLBDHSLlo5FKIiE2oSi4zXc4TLcopGcWPNcm/NDaSC5pvA==} peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' + '@chakra-ui/system': '>=2.0.0' react: '>=18' dependencies: - '@chakra-ui/hooks': 2.0.4(react@18.2.0) - '@chakra-ui/react-utils': 2.0.1(react@18.2.0) - '@chakra-ui/spinner': 2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/utils': 2.0.4 + '@chakra-ui/react-context': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-merge-refs': 2.1.0(react@18.2.0) + '@chakra-ui/shared-utils': 2.0.5 + '@chakra-ui/spinner': 2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) react: 18.2.0 dev: false - /@chakra-ui/checkbox@2.1.3(@chakra-ui/system@2.2.2)(framer-motion@6.5.1)(react@18.2.0): - resolution: {integrity: sha512-1Nzh4ETLEuSAYm8Godgh9i1veUz559lHtvpjOkg8nrmOoN/51yyXfon0QCTJBq/1umGcHZmXrBrJgj2Wd9f+ZQ==} + /@chakra-ui/card@2.2.0(@chakra-ui/system@2.6.0)(react@18.2.0): + resolution: {integrity: sha512-xUB/k5MURj4CtPAhdSoXZidUbm8j3hci9vnc+eZJVDqhDOShNlD6QeniQNRPRys4lWAQLCbFcrwL29C8naDi6g==} peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' - framer-motion: '>=4.0.0' + '@chakra-ui/system': '>=2.0.0' react: '>=18' dependencies: - '@chakra-ui/form-control': 2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/hooks': 2.0.4(react@18.2.0) - '@chakra-ui/react-utils': 2.0.1(react@18.2.0) - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/utils': 2.0.4 - '@chakra-ui/visually-hidden': 2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@zag-js/focus-visible': 0.1.0 - framer-motion: 6.5.1(react-dom@18.2.0)(react@18.2.0) + '@chakra-ui/shared-utils': 2.0.5 + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) react: 18.2.0 dev: false - /@chakra-ui/clickable@2.0.4(react@18.2.0): - resolution: {integrity: sha512-20otkOHNMrPMYbpRMSzX6AQBIUwbtN97ua+R0E+yG4DrgbXjOQvYyMAbSdBsKbGf0egx4c+4RlGmVf2kVA8Ahg==} + /@chakra-ui/checkbox@2.3.0(@chakra-ui/system@2.6.0)(react@18.2.0): + resolution: {integrity: sha512-fX7M5sQK27aFWoj7vqnPkf1Q3AHmML/5dIRYfm7HEIsZXYH2C1CkM6+dijeSWIk6a0mp0r3el6SNDUti2ehH8g==} + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/form-control': 2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/react-context': 2.1.0(react@18.2.0) + '@chakra-ui/react-types': 2.0.7(react@18.2.0) + '@chakra-ui/react-use-callback-ref': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-controllable-state': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-merge-refs': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-safe-layout-effect': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-update-effect': 2.1.0(react@18.2.0) + '@chakra-ui/shared-utils': 2.0.5 + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) + '@chakra-ui/visually-hidden': 2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@zag-js/focus-visible': 0.10.5 + react: 18.2.0 + dev: false + + /@chakra-ui/clickable@2.1.0(react@18.2.0): + resolution: {integrity: sha512-flRA/ClPUGPYabu+/GLREZVZr9j2uyyazCAUHAdrTUEdDYCr31SVGhgh7dgKdtq23bOvAQJpIJjw/0Bs0WvbXw==} peerDependencies: react: '>=18' dependencies: - '@chakra-ui/react-utils': 2.0.1(react@18.2.0) - '@chakra-ui/utils': 2.0.4 + '@chakra-ui/react-use-merge-refs': 2.1.0(react@18.2.0) + '@chakra-ui/shared-utils': 2.0.5 react: 18.2.0 dev: false - /@chakra-ui/close-button@2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0): - resolution: {integrity: sha512-IfRJXK3ADEnnECoyE+gKGVtiIZoxtBiu17z/EeJriswV1x82Iw5ltptNUz0JoDrTD794a9YSnX7rDPI9wR5IMw==} + /@chakra-ui/close-button@2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0): + resolution: {integrity: sha512-KfJcz6UAaR2dDWSIv6UrCGkZQS54Fjl+DEEVOUTJ7gf4KOP4FQZCkv8hqsAB9FeCtnwU43adq2oaw3aZH/Uzew==} peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' + '@chakra-ui/system': '>=2.0.0' react: '>=18' dependencies: - '@chakra-ui/icon': 3.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/utils': 2.0.4 + '@chakra-ui/icon': 3.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) react: 18.2.0 dev: false - /@chakra-ui/color-mode@2.1.2(react@18.2.0): - resolution: {integrity: sha512-HJv+Jaizsg+uyW9TIjNwvkhUdD6NEBQLabAMOAk03CNtv/k4pTc56yLwn9TCDV06pZsViDpdO+vqgbGAOXiByw==} + /@chakra-ui/color-mode@2.2.0(react@18.2.0): + resolution: {integrity: sha512-niTEA8PALtMWRI9wJ4LL0CSBDo8NBfLNp4GD6/0hstcm3IlbBHTVKxN6HwSaoNYfphDQLxCjT4yG+0BJA5tFpg==} peerDependencies: react: '>=18' dependencies: - '@chakra-ui/hooks': 2.0.4(react@18.2.0) - '@chakra-ui/utils': 2.0.4 + '@chakra-ui/react-use-safe-layout-effect': 2.1.0(react@18.2.0) react: 18.2.0 dev: false - /@chakra-ui/control-box@2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0): - resolution: {integrity: sha512-jJD+Ka827qBlagKYzTjbKENi6+wgSowb9MHIlMybwnE6AA9qBws/lHHiUEk6S7tZW9BHMJYFeSbZFVtYaQho4A==} + /@chakra-ui/control-box@2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0): + resolution: {integrity: sha512-gVrRDyXFdMd8E7rulL0SKeoljkLQiPITFnsyMO8EFHNZ+AHt5wK4LIguYVEq88APqAGZGfHFWXr79RYrNiE3Mg==} peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' + '@chakra-ui/system': '>=2.0.0' react: '>=18' dependencies: - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/utils': 2.0.4 + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) react: 18.2.0 dev: false - /@chakra-ui/counter@2.0.4(react@18.2.0): - resolution: {integrity: sha512-j1y5ZJ+QVN+QotTm6SNNE0u1YFLaPyfiLu0+gspacvC/ugH9vhDwkkzqXJolkThWLbcAdL0I7J6XuAy5XOXKjA==} + /@chakra-ui/counter@2.1.0(react@18.2.0): + resolution: {integrity: sha512-s6hZAEcWT5zzjNz2JIWUBzRubo9la/oof1W7EKZVVfPYHERnl5e16FmBC79Yfq8p09LQ+aqFKm/etYoJMMgghw==} peerDependencies: react: '>=18' dependencies: - '@chakra-ui/hooks': 2.0.4(react@18.2.0) - '@chakra-ui/utils': 2.0.4 + '@chakra-ui/number-utils': 2.0.7 + '@chakra-ui/react-use-callback-ref': 2.1.0(react@18.2.0) + '@chakra-ui/shared-utils': 2.0.5 react: 18.2.0 dev: false - /@chakra-ui/css-reset@2.0.1(@emotion/react@11.9.3)(react@18.2.0): - resolution: {integrity: sha512-8RhAC7l5RHp9hNDN2M2feZ2wPaoSrgxzqx6VqLTIul2lwucpp1LTlrDlPCBMJe8fp51Q83IOCW4882ktsXxktA==} + /@chakra-ui/css-reset@2.2.0(@emotion/react@11.11.1)(react@18.2.0): + resolution: {integrity: sha512-nn7hjquIrPwCzwI4d/Y4wzM5A5xAeswREOfT8gT0Yd+U+Qnw3pPT8NPLbNJ3DvuOfJaCV6/N5ld/6RRTgYF/sQ==} peerDependencies: '@emotion/react': '>=10.0.35' react: '>=18' dependencies: - '@emotion/react': 11.9.3(@babel/core@7.18.6)(@types/react@18.0.15)(react@18.2.0) + '@emotion/react': 11.11.1(@types/react@18.2.21)(react@18.2.0) react: 18.2.0 dev: false - /@chakra-ui/descendant@3.0.3(react@18.2.0): - resolution: {integrity: sha512-uI0B5BO7khb22UWE42W7n3oGjxQkdJl+H5lhX58lAOAjbNsbmd8XbIVXTO/Kb7LvS3sPimkyG8nRC9A1epq4tw==} + /@chakra-ui/descendant@3.1.0(react@18.2.0): + resolution: {integrity: sha512-VxCIAir08g5w27klLyi7PVo8BxhW4tgU/lxQyujkmi4zx7hT9ZdrcQLAted/dAa+aSIZ14S1oV0Q9lGjsAdxUQ==} peerDependencies: react: '>=18' dependencies: - '@chakra-ui/react-utils': 2.0.1(react@18.2.0) + '@chakra-ui/react-context': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-merge-refs': 2.1.0(react@18.2.0) react: 18.2.0 dev: false - /@chakra-ui/editable@2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0): - resolution: {integrity: sha512-Xof9NXWzs/3H5MChxcbRmttYKf7MYGDePtRrZvW4GKLhi5fjpbuhzZIeC8XV3Pm1gBCLkyG8WHj3d99SNqdNig==} + /@chakra-ui/dom-utils@2.1.0: + resolution: {integrity: sha512-ZmF2qRa1QZ0CMLU8M1zCfmw29DmPNtfjR9iTo74U5FPr3i1aoAh7fbJ4qAlZ197Xw9eAW28tvzQuoVWeL5C7fQ==} + dev: false + + /@chakra-ui/editable@3.1.0(@chakra-ui/system@2.6.0)(react@18.2.0): + resolution: {integrity: sha512-j2JLrUL9wgg4YA6jLlbU88370eCRyor7DZQD9lzpY95tSOXpTljeg3uF9eOmDnCs6fxp3zDWIfkgMm/ExhcGTg==} peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' + '@chakra-ui/system': '>=2.0.0' react: '>=18' dependencies: - '@chakra-ui/hooks': 2.0.4(react@18.2.0) - '@chakra-ui/react-utils': 2.0.1(react@18.2.0) - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/utils': 2.0.4 + '@chakra-ui/react-context': 2.1.0(react@18.2.0) + '@chakra-ui/react-types': 2.0.7(react@18.2.0) + '@chakra-ui/react-use-callback-ref': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-controllable-state': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-focus-on-pointer-down': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-merge-refs': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-safe-layout-effect': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-update-effect': 2.1.0(react@18.2.0) + '@chakra-ui/shared-utils': 2.0.5 + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) react: 18.2.0 dev: false - /@chakra-ui/focus-lock@2.0.5(@types/react@18.0.15)(react@18.2.0): - resolution: {integrity: sha512-WPseFKMTlXsc6FH2L4ZcO2PJVhEqZqUfgUMNM/1PVU/oZoa0t8A2HG/cq1EGaOf/EMGzVOGc/Gz4LE712JfZhg==} + /@chakra-ui/event-utils@2.0.8: + resolution: {integrity: sha512-IGM/yGUHS+8TOQrZGpAKOJl/xGBrmRYJrmbHfUE7zrG3PpQyXvbLDP1M+RggkCFVgHlJi2wpYIf0QtQlU0XZfw==} + dev: false + + /@chakra-ui/focus-lock@2.1.0(@types/react@18.2.21)(react@18.2.0): + resolution: {integrity: sha512-EmGx4PhWGjm4dpjRqM4Aa+rCWBxP+Rq8Uc/nAVnD4YVqkEhBkrPTpui2lnjsuxqNaZ24fIAZ10cF1hlpemte/w==} peerDependencies: react: '>=18' dependencies: - '@chakra-ui/utils': 2.0.4 + '@chakra-ui/dom-utils': 2.1.0 react: 18.2.0 - react-focus-lock: 2.9.1(@types/react@18.0.15)(react@18.2.0) + react-focus-lock: 2.9.5(@types/react@18.2.21)(react@18.2.0) transitivePeerDependencies: - '@types/react' dev: false - /@chakra-ui/form-control@2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0): - resolution: {integrity: sha512-ZPeG4gWdEcZZhROQn3NNwLEWh5meq+W1Dof5iB1L2VSgZHRpCSM1G8jeZQjxZsGV8AumEhyNq4nyLu2h+fPQAg==} + /@chakra-ui/form-control@2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0): + resolution: {integrity: sha512-3QmWG9v6Rx+JOwJP3Wt89+AWZxK0F1NkVAgXP3WVfE9VDXOKFRV/faLT0GEe2V+l7WZHF5PLdEBvKG8Cgw2mkA==} peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' + '@chakra-ui/system': '>=2.0.0' react: '>=18' dependencies: - '@chakra-ui/hooks': 2.0.4(react@18.2.0) - '@chakra-ui/icon': 3.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/react-utils': 2.0.1(react@18.2.0) - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/utils': 2.0.4 + '@chakra-ui/icon': 3.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/react-context': 2.1.0(react@18.2.0) + '@chakra-ui/react-types': 2.0.7(react@18.2.0) + '@chakra-ui/react-use-merge-refs': 2.1.0(react@18.2.0) + '@chakra-ui/shared-utils': 2.0.5 + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) react: 18.2.0 dev: false - /@chakra-ui/hooks@2.0.4(react@18.2.0): - resolution: {integrity: sha512-5FJZ6JY1449rHZdjOSq7ei8TBG5mdSeNRbGGgTxt7xteU9o6vpr3hKJy9TFjaSNPJamSMS8Lf0YXJu2R044o0w==} + /@chakra-ui/hooks@2.2.0(react@18.2.0): + resolution: {integrity: sha512-GZE64mcr20w+3KbCUPqQJHHmiFnX5Rcp8jS3YntGA4D5X2qU85jka7QkjfBwv/iduZ5Ei0YpCMYGCpi91dhD1Q==} peerDependencies: react: '>=18' dependencies: - '@chakra-ui/react-utils': 2.0.1(react@18.2.0) - '@chakra-ui/utils': 2.0.4 - compute-scroll-into-view: 1.0.14 - copy-to-clipboard: 3.3.1 + '@chakra-ui/react-utils': 2.0.12(react@18.2.0) + '@chakra-ui/utils': 2.0.15 + compute-scroll-into-view: 1.0.20 + copy-to-clipboard: 3.3.3 react: 18.2.0 dev: false - /@chakra-ui/icon@3.0.4(@chakra-ui/system@2.2.2)(react@18.2.0): - resolution: {integrity: sha512-9Ry+fa6EKRYUexffvgOJ9dRIkxCSnASgdSnb09EbQTgCTeM+47LUsxR2+r8pbY6ZT5D4m2zRLkTrv7O7icoyOw==} + /@chakra-ui/icon@3.1.0(@chakra-ui/system@2.6.0)(react@18.2.0): + resolution: {integrity: sha512-t6v0lGCXRbwUJycN8A/nDTuLktMP+LRjKbYJnd2oL6Pm2vOl99XwEQ5cAEyEa4XoseYNEgXiLR+2TfvgfNFvcw==} peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' + '@chakra-ui/system': '>=2.0.0' react: '>=18' dependencies: - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/utils': 2.0.4 + '@chakra-ui/shared-utils': 2.0.5 + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) react: 18.2.0 dev: false - /@chakra-ui/image@2.0.5(@chakra-ui/system@2.2.2)(react@18.2.0): - resolution: {integrity: sha512-1+/VjzjNv9moxrydsEryVhl3NOPxK1xr7BMd1UmPCp4g8ZZNNFmEah2FiL7GDVBdf2I4/e/2xMCUpndJJiIlCQ==} + /@chakra-ui/image@2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0): + resolution: {integrity: sha512-bskumBYKLiLMySIWDGcz0+D9Th0jPvmX6xnRMs4o92tT3Od/bW26lahmV2a2Op2ItXeCmRMY+XxJH5Gy1i46VA==} peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' + '@chakra-ui/system': '>=2.0.0' react: '>=18' dependencies: - '@chakra-ui/hooks': 2.0.4(react@18.2.0) - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/utils': 2.0.4 + '@chakra-ui/react-use-safe-layout-effect': 2.1.0(react@18.2.0) + '@chakra-ui/shared-utils': 2.0.5 + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) react: 18.2.0 dev: false - /@chakra-ui/input@2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0): - resolution: {integrity: sha512-fzRFSt7ZFfZ71Tgq0xFHR32R4km8bpfV5kSlFZe/XnmLcCI7/oRRnHK/aa7GZyz2k5QpvvBe2TkqKjVAlv3jNA==} + /@chakra-ui/input@2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0): + resolution: {integrity: sha512-HItI2vq6vupCuixdzof4sIanGdLlszhDtlR5be5z8Nrda1RkXVqI+9CTJPbNsx2nIKEfwPt01pnT9mozoOSMMw==} peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' + '@chakra-ui/system': '>=2.0.0' react: '>=18' dependencies: - '@chakra-ui/form-control': 2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/react-utils': 2.0.1(react@18.2.0) - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/utils': 2.0.4 + '@chakra-ui/form-control': 2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/object-utils': 2.1.0 + '@chakra-ui/react-children-utils': 2.0.6(react@18.2.0) + '@chakra-ui/react-context': 2.1.0(react@18.2.0) + '@chakra-ui/shared-utils': 2.0.5 + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) react: 18.2.0 dev: false - /@chakra-ui/layout@2.1.1(@chakra-ui/system@2.2.2)(react@18.2.0): - resolution: {integrity: sha512-amiwbaWUkMpTh+K9QP7a24Je+C0u9x8nvf5ELyUhnZjL+J7yEe7MNRXiWIfqFNC3gszZv/7y7HiKBzKQUw0u/Q==} + /@chakra-ui/layout@2.3.0(@chakra-ui/system@2.6.0)(react@18.2.0): + resolution: {integrity: sha512-tp1/Bn+cHn0Q4HWKY62HtOwzhpH1GUA3i5fvs23HEhOEryTps05hyuQVeJ71fLqSs6f1QEIdm+9It+5WCj64vQ==} peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' + '@chakra-ui/system': '>=2.0.0' react: '>=18' dependencies: - '@chakra-ui/icon': 3.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/react-utils': 2.0.1(react@18.2.0) - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/utils': 2.0.4 + '@chakra-ui/breakpoint-utils': 2.0.8 + '@chakra-ui/icon': 3.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/object-utils': 2.1.0 + '@chakra-ui/react-children-utils': 2.0.6(react@18.2.0) + '@chakra-ui/react-context': 2.1.0(react@18.2.0) + '@chakra-ui/shared-utils': 2.0.5 + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) react: 18.2.0 dev: false - /@chakra-ui/live-region@2.0.4(react@18.2.0): - resolution: {integrity: sha512-zOu+MzwRdgV+wMXMW+FOY7iL3vs/jdfAEJlNnfI1Lx4LFJ4FnjegvLjOOamOwtPJTh5ZkeUsyZctndrxH8agQQ==} + /@chakra-ui/lazy-utils@2.0.5: + resolution: {integrity: sha512-UULqw7FBvcckQk2n3iPO56TMJvDsNv0FKZI6PlUNJVaGsPbsYxK/8IQ60vZgaTVPtVcjY6BE+y6zg8u9HOqpyg==} + dev: false + + /@chakra-ui/live-region@2.1.0(react@18.2.0): + resolution: {integrity: sha512-ZOxFXwtaLIsXjqnszYYrVuswBhnIHHP+XIgK1vC6DePKtyK590Wg+0J0slDwThUAd4MSSIUa/nNX84x1GMphWw==} peerDependencies: react: '>=18' dependencies: - '@chakra-ui/utils': 2.0.4 react: 18.2.0 dev: false - /@chakra-ui/media-query@3.2.0(@chakra-ui/system@2.2.2)(@chakra-ui/theme@2.1.3)(react@18.2.0): - resolution: {integrity: sha512-rSqEmegTXojNtY4wJQyl7yceLK4oHMJBnTKLZOkdKnxgWTgcTgkH26MZaP/FeJJBMijRPEN5qoy2KN1lCIVEmg==} + /@chakra-ui/media-query@3.3.0(@chakra-ui/system@2.6.0)(react@18.2.0): + resolution: {integrity: sha512-IsTGgFLoICVoPRp9ykOgqmdMotJG0CnPsKvGQeSFOB/dZfIujdVb14TYxDU4+MURXry1MhJ7LzZhv+Ml7cr8/g==} peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' - '@chakra-ui/theme': '>=2.0.0-next.0' + '@chakra-ui/system': '>=2.0.0' react: '>=18' dependencies: - '@chakra-ui/react-env': 2.0.4(react@18.2.0) - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/theme': 2.1.3(@chakra-ui/system@2.2.2) - '@chakra-ui/utils': 2.0.4 + '@chakra-ui/breakpoint-utils': 2.0.8 + '@chakra-ui/react-env': 3.1.0(react@18.2.0) + '@chakra-ui/shared-utils': 2.0.5 + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) react: 18.2.0 dev: false - /@chakra-ui/menu@2.0.6(@chakra-ui/system@2.2.2)(framer-motion@6.5.1)(react@18.2.0): - resolution: {integrity: sha512-VcucCiDwOZg5iCP+7sP22H4uPz3/qE22Jo2A48hPPneb9MPmYkZxIBRJyB0wvbWmkRHAkyiLYNwHM0qk0wpp+g==} + /@chakra-ui/menu@2.2.0(@chakra-ui/system@2.6.0)(framer-motion@10.0.0)(react@18.2.0): + resolution: {integrity: sha512-l7HQjriW4JGeCyxDdguAzekwwB+kHGDLxACi0DJNp37sil51SRaN1S1OrneISbOHVpHuQB+KVNgU0rqhoglVew==} peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' + '@chakra-ui/system': '>=2.0.0' framer-motion: '>=4.0.0' react: '>=18' dependencies: - '@chakra-ui/clickable': 2.0.4(react@18.2.0) - '@chakra-ui/descendant': 3.0.3(react@18.2.0) - '@chakra-ui/hooks': 2.0.4(react@18.2.0) - '@chakra-ui/popper': 3.0.2(react@18.2.0) - '@chakra-ui/react-utils': 2.0.1(react@18.2.0) - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/transition': 2.0.4(framer-motion@6.5.1)(react@18.2.0) - '@chakra-ui/utils': 2.0.4 - framer-motion: 6.5.1(react-dom@18.2.0)(react@18.2.0) + '@chakra-ui/clickable': 2.1.0(react@18.2.0) + '@chakra-ui/descendant': 3.1.0(react@18.2.0) + '@chakra-ui/lazy-utils': 2.0.5 + '@chakra-ui/popper': 3.1.0(react@18.2.0) + '@chakra-ui/react-children-utils': 2.0.6(react@18.2.0) + '@chakra-ui/react-context': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-animation-state': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-controllable-state': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-disclosure': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-focus-effect': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-merge-refs': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-outside-click': 2.2.0(react@18.2.0) + '@chakra-ui/react-use-update-effect': 2.1.0(react@18.2.0) + '@chakra-ui/shared-utils': 2.0.5 + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) + '@chakra-ui/transition': 2.1.0(framer-motion@10.0.0)(react@18.2.0) + framer-motion: 10.0.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 dev: false - /@chakra-ui/modal@2.1.2(@chakra-ui/system@2.2.2)(@types/react@18.0.15)(framer-motion@6.5.1)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-kstt5xM8rqmSkFU1CrY6qD1iv+5tXa0IsLGAN1lyDu4MSphPSMfcBHcKTXTgrsRLHVc8bVCWWAQuJQSKt0G0jw==} + /@chakra-ui/modal@2.3.0(@chakra-ui/system@2.6.0)(@types/react@18.2.21)(framer-motion@10.0.0)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-S1sITrIeLSf21LJ0Vz8xZhj5fWEud5z5Dl2dmvOEv1ezypgOrCCBdOEnnqCkoEKZDbKvzZWZXWR5791ikLP6+g==} peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' + '@chakra-ui/system': '>=2.0.0' framer-motion: '>=4.0.0' react: '>=18' react-dom: '>=18' dependencies: - '@chakra-ui/close-button': 2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/focus-lock': 2.0.5(@types/react@18.0.15)(react@18.2.0) - '@chakra-ui/hooks': 2.0.4(react@18.2.0) - '@chakra-ui/portal': 2.0.4(react-dom@18.2.0)(react@18.2.0) - '@chakra-ui/react-utils': 2.0.1(react@18.2.0) - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/transition': 2.0.4(framer-motion@6.5.1)(react@18.2.0) - '@chakra-ui/utils': 2.0.4 - aria-hidden: 1.1.3 - framer-motion: 6.5.1(react-dom@18.2.0)(react@18.2.0) + '@chakra-ui/close-button': 2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/focus-lock': 2.1.0(@types/react@18.2.21)(react@18.2.0) + '@chakra-ui/portal': 2.1.0(react-dom@18.2.0)(react@18.2.0) + '@chakra-ui/react-context': 2.1.0(react@18.2.0) + '@chakra-ui/react-types': 2.0.7(react@18.2.0) + '@chakra-ui/react-use-merge-refs': 2.1.0(react@18.2.0) + '@chakra-ui/shared-utils': 2.0.5 + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) + '@chakra-ui/transition': 2.1.0(framer-motion@10.0.0)(react@18.2.0) + aria-hidden: 1.2.3 + framer-motion: 10.0.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - react-remove-scroll: 2.5.5(@types/react@18.0.15)(react@18.2.0) + react-remove-scroll: 2.5.5(@types/react@18.2.21)(react@18.2.0) transitivePeerDependencies: - '@types/react' dev: false - /@chakra-ui/number-input@2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0): - resolution: {integrity: sha512-VYgUhqchKFpMGE05EogTIxOIKLUdgdm+X+ciNbn1mhfoP+4zoEZlTobGUm+9xel6ojsAVVlnXPDv1jWMBQ5SJg==} + /@chakra-ui/number-input@2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0): + resolution: {integrity: sha512-/gEAzQHhrMA+1rzyCMaN8OkKtUPuER6iA+nloYEYBoT7dH/EoNlRtBkiIQhDp+E4VpgZJ0SK3OVrm9/eBbtHHg==} peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' + '@chakra-ui/system': '>=2.0.0' react: '>=18' dependencies: - '@chakra-ui/counter': 2.0.4(react@18.2.0) - '@chakra-ui/form-control': 2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/hooks': 2.0.4(react@18.2.0) - '@chakra-ui/icon': 3.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/react-utils': 2.0.1(react@18.2.0) - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/utils': 2.0.4 + '@chakra-ui/counter': 2.1.0(react@18.2.0) + '@chakra-ui/form-control': 2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/icon': 3.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/react-context': 2.1.0(react@18.2.0) + '@chakra-ui/react-types': 2.0.7(react@18.2.0) + '@chakra-ui/react-use-callback-ref': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-event-listener': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-interval': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-merge-refs': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-safe-layout-effect': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-update-effect': 2.1.0(react@18.2.0) + '@chakra-ui/shared-utils': 2.0.5 + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) react: 18.2.0 dev: false - /@chakra-ui/pin-input@2.0.6(@chakra-ui/system@2.2.2)(react@18.2.0): - resolution: {integrity: sha512-CVpgvTDqkBoVU860PHN1xHNpcj21tXaur5mjJkcMh2/HnMQ5Dq4Z+69crkQfGIG7NV5XtVasJo7+DWYRaDCZGw==} + /@chakra-ui/number-utils@2.0.7: + resolution: {integrity: sha512-yOGxBjXNvLTBvQyhMDqGU0Oj26s91mbAlqKHiuw737AXHt0aPllOthVUqQMeaYLwLCjGMg0jtI7JReRzyi94Dg==} + dev: false + + /@chakra-ui/object-utils@2.1.0: + resolution: {integrity: sha512-tgIZOgLHaoti5PYGPTwK3t/cqtcycW0owaiOXoZOcpwwX/vlVb+H1jFsQyWiiwQVPt9RkoSLtxzXamx+aHH+bQ==} + dev: false + + /@chakra-ui/pin-input@2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0): + resolution: {integrity: sha512-x4vBqLStDxJFMt+jdAHHS8jbh294O53CPQJoL4g228P513rHylV/uPscYUHrVJXRxsHfRztQO9k45jjTYaPRMw==} peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' + '@chakra-ui/system': '>=2.0.0' react: '>=18' dependencies: - '@chakra-ui/descendant': 3.0.3(react@18.2.0) - '@chakra-ui/hooks': 2.0.4(react@18.2.0) - '@chakra-ui/react-utils': 2.0.1(react@18.2.0) - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/utils': 2.0.4 + '@chakra-ui/descendant': 3.1.0(react@18.2.0) + '@chakra-ui/react-children-utils': 2.0.6(react@18.2.0) + '@chakra-ui/react-context': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-controllable-state': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-merge-refs': 2.1.0(react@18.2.0) + '@chakra-ui/shared-utils': 2.0.5 + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) react: 18.2.0 dev: false - /@chakra-ui/popover@2.0.4(@chakra-ui/system@2.2.2)(framer-motion@6.5.1)(react@18.2.0): - resolution: {integrity: sha512-sA4HHnaVBLUpgUoe/s82A+T2BRQ9Hb3+XsLvAbrqOwLc16Jh3FZfS9a02fNokbOWs6NDioslgbSoeTvv5yqOOQ==} + /@chakra-ui/popover@2.2.0(@chakra-ui/system@2.6.0)(framer-motion@10.0.0)(react@18.2.0): + resolution: {integrity: sha512-cTqXdgkU0vgK82AR1nWcC2MJYhEL/y6uTeprvO2+j4o2D0yPrzVMuIZZRl0abrQwiravQyVGEMgA5y0ZLYwbiQ==} peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' + '@chakra-ui/system': '>=2.0.0' framer-motion: '>=4.0.0' react: '>=18' dependencies: - '@chakra-ui/close-button': 2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/hooks': 2.0.4(react@18.2.0) - '@chakra-ui/popper': 3.0.2(react@18.2.0) - '@chakra-ui/react-utils': 2.0.1(react@18.2.0) - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/utils': 2.0.4 - framer-motion: 6.5.1(react-dom@18.2.0)(react@18.2.0) + '@chakra-ui/close-button': 2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/lazy-utils': 2.0.5 + '@chakra-ui/popper': 3.1.0(react@18.2.0) + '@chakra-ui/react-context': 2.1.0(react@18.2.0) + '@chakra-ui/react-types': 2.0.7(react@18.2.0) + '@chakra-ui/react-use-animation-state': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-disclosure': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-focus-effect': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-focus-on-pointer-down': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-merge-refs': 2.1.0(react@18.2.0) + '@chakra-ui/shared-utils': 2.0.5 + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) + framer-motion: 10.0.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 dev: false - /@chakra-ui/popper@3.0.2(react@18.2.0): - resolution: {integrity: sha512-oEUsaFR4EPY3CvhEVeZNoa+mA/w+TvLlG3xlicIwv/3Fcfl6LD2Jhr6utnqAvHFxE/qRcUcXLX20ovy0Zrgm/Q==} + /@chakra-ui/popper@3.1.0(react@18.2.0): + resolution: {integrity: sha512-ciDdpdYbeFG7og6/6J8lkTFxsSvwTdMLFkpVylAF6VNC22jssiWfquj2eyD4rJnzkRFPvIWJq8hvbfhsm+AjSg==} peerDependencies: react: '>=18' dependencies: - '@chakra-ui/react-utils': 2.0.1(react@18.2.0) + '@chakra-ui/react-types': 2.0.7(react@18.2.0) + '@chakra-ui/react-use-merge-refs': 2.1.0(react@18.2.0) '@popperjs/core': 2.11.5 react: 18.2.0 dev: false - /@chakra-ui/portal@2.0.4(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-4h/brmPQBMK2ZtpqqSOGIMfg/oRmfmPeDI61n4cN5WgatarkxEzrIJUoNJHIYHl8Da0TmoFzyhgV6ESm1SHLJg==} + /@chakra-ui/portal@2.1.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-9q9KWf6SArEcIq1gGofNcFPSWEyl+MfJjEUg/un1SMlQjaROOh3zYr+6JAwvcORiX7tyHosnmWC3d3wI2aPSQg==} peerDependencies: react: '>=18' react-dom: '>=18' dependencies: - '@chakra-ui/hooks': 2.0.4(react@18.2.0) - '@chakra-ui/react-utils': 2.0.1(react@18.2.0) - '@chakra-ui/utils': 2.0.4 + '@chakra-ui/react-context': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-safe-layout-effect': 2.1.0(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false - /@chakra-ui/progress@2.0.5(@chakra-ui/system@2.2.2)(react@18.2.0): - resolution: {integrity: sha512-GKeIxL6YEHrN6sX7rPce6TtYKtqkBDQ0r4b3WeOt3CaEhzSm1zMQMni0Zl5xdQp2BhaEQ3ZgEydxdsxDnr1PPQ==} + /@chakra-ui/progress@2.2.0(@chakra-ui/system@2.6.0)(react@18.2.0): + resolution: {integrity: sha512-qUXuKbuhN60EzDD9mHR7B67D7p/ZqNS2Aze4Pbl1qGGZfulPW0PY8Rof32qDtttDQBkzQIzFGE8d9QpAemToIQ==} peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' + '@chakra-ui/system': '>=2.0.0' react: '>=18' dependencies: - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/theme-tools': 2.0.5(@chakra-ui/system@2.2.2) - '@chakra-ui/utils': 2.0.4 + '@chakra-ui/react-context': 2.1.0(react@18.2.0) + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) react: 18.2.0 dev: false - /@chakra-ui/provider@2.0.9(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-RWa5lULY2yz/PbaipmYq9bjyMouyQjHBKpu/zpCsML5j13JI4QonW7D26Sm0sDE67RJVaopCzFv0I4B6X2TMCw==} + /@chakra-ui/provider@2.4.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-KJ/TNczpY+EStQXa2Y5PZ+senlBHrY7P+RpBgJLBZLGkQUCS3APw5KvCwgpA0COb2M4AZXCjw+rm+Ko7ontlgA==} peerDependencies: '@emotion/react': ^11.0.0 '@emotion/styled': ^11.0.0 react: '>=18' react-dom: '>=18' dependencies: - '@chakra-ui/css-reset': 2.0.1(@emotion/react@11.9.3)(react@18.2.0) - '@chakra-ui/portal': 2.0.4(react-dom@18.2.0)(react@18.2.0) - '@chakra-ui/react-env': 2.0.4(react@18.2.0) - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/utils': 2.0.4 - '@emotion/react': 11.9.3(@babel/core@7.18.6)(@types/react@18.0.15)(react@18.2.0) - '@emotion/styled': 11.9.3(@babel/core@7.18.6)(@emotion/react@11.9.3)(@types/react@18.0.15)(react@18.2.0) + '@chakra-ui/css-reset': 2.2.0(@emotion/react@11.11.1)(react@18.2.0) + '@chakra-ui/portal': 2.1.0(react-dom@18.2.0)(react@18.2.0) + '@chakra-ui/react-env': 3.1.0(react@18.2.0) + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) + '@chakra-ui/utils': 2.0.15 + '@emotion/react': 11.11.1(@types/react@18.2.21)(react@18.2.0) + '@emotion/styled': 11.11.0(@emotion/react@11.11.1)(@types/react@18.2.21)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false - /@chakra-ui/radio@2.0.5(@chakra-ui/system@2.2.2)(react@18.2.0): - resolution: {integrity: sha512-IF3hITdx73tOX9+9E8I9FWPnIYOEjik2aobBlAxBbts9YvIGJLpquQOEfjlf10moZh7B8hGLQMdlqE56snzwpQ==} + /@chakra-ui/radio@2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0): + resolution: {integrity: sha512-WiRlSCqKWgy4m9106w4g77kcLYqBxqGhFRO1pTTJp99rxpM6jNadOeK+moEjqj64N9mSz3njEecMJftKKcOYdg==} peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' + '@chakra-ui/system': '>=2.0.0' react: '>=18' dependencies: - '@chakra-ui/form-control': 2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/hooks': 2.0.4(react@18.2.0) - '@chakra-ui/react-utils': 2.0.1(react@18.2.0) - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/utils': 2.0.4 - '@chakra-ui/visually-hidden': 2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@zag-js/focus-visible': 0.1.0 + '@chakra-ui/form-control': 2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/react-context': 2.1.0(react@18.2.0) + '@chakra-ui/react-types': 2.0.7(react@18.2.0) + '@chakra-ui/react-use-merge-refs': 2.1.0(react@18.2.0) + '@chakra-ui/shared-utils': 2.0.5 + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) + '@zag-js/focus-visible': 0.10.5 react: 18.2.0 dev: false - /@chakra-ui/react-env@2.0.4(react@18.2.0): - resolution: {integrity: sha512-qiLQOr966BLX9zORn4UXpcfYD7zF8DphdfkzW1MPPRj9Iufsf96NliHSuz8XBmnLFdFP0cKHXs0hUOaGkkernw==} + /@chakra-ui/react-children-utils@2.0.6(react@18.2.0): + resolution: {integrity: sha512-QVR2RC7QsOsbWwEnq9YduhpqSFnZGvjjGREV8ygKi8ADhXh93C8azLECCUVgRJF2Wc+So1fgxmjLcbZfY2VmBA==} peerDependencies: react: '>=18' dependencies: - '@chakra-ui/utils': 2.0.4 react: 18.2.0 dev: false - /@chakra-ui/react-utils@2.0.1(react@18.2.0): - resolution: {integrity: sha512-xLiTn7WeUo2e3zvo8zUGpICgIGsLCPpkVbjEKhr1jAV41urqEtwlLc6uGir595OYqAC8zFDqs4HXhHouqNEtiw==} + /@chakra-ui/react-context@2.1.0(react@18.2.0): + resolution: {integrity: sha512-iahyStvzQ4AOwKwdPReLGfDesGG+vWJfEsn0X/NoGph/SkN+HXtv2sCfYFFR9k7bb+Kvc6YfpLlSuLvKMHi2+w==} peerDependencies: react: '>=18' dependencies: - '@chakra-ui/utils': 2.0.4 react: 18.2.0 dev: false - /@chakra-ui/react@2.2.4(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(@types/react@18.0.15)(framer-motion@6.5.1)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-YlpDn2nNU3HT/Smtziya7R+WyENbzSzrKFibC49zxR9v1D7LBzXHiwKJCokvDQ/NsjEVHz0zwyZiVnJtUnNXsQ==} + /@chakra-ui/react-env@3.1.0(react@18.2.0): + resolution: {integrity: sha512-Vr96GV2LNBth3+IKzr/rq1IcnkXv+MLmwjQH6C8BRtn3sNskgDFD5vLkVXcEhagzZMCh8FR3V/bzZPojBOyNhw==} + peerDependencies: + react: '>=18' + dependencies: + '@chakra-ui/react-use-safe-layout-effect': 2.1.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@chakra-ui/react-types@2.0.7(react@18.2.0): + resolution: {integrity: sha512-12zv2qIZ8EHwiytggtGvo4iLT0APris7T0qaAWqzpUGS0cdUtR8W+V1BJ5Ocq+7tA6dzQ/7+w5hmXih61TuhWQ==} + peerDependencies: + react: '>=18' + dependencies: + react: 18.2.0 + dev: false + + /@chakra-ui/react-use-animation-state@2.1.0(react@18.2.0): + resolution: {integrity: sha512-CFZkQU3gmDBwhqy0vC1ryf90BVHxVN8cTLpSyCpdmExUEtSEInSCGMydj2fvn7QXsz/za8JNdO2xxgJwxpLMtg==} + peerDependencies: + react: '>=18' + dependencies: + '@chakra-ui/dom-utils': 2.1.0 + '@chakra-ui/react-use-event-listener': 2.1.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@chakra-ui/react-use-callback-ref@2.1.0(react@18.2.0): + resolution: {integrity: sha512-efnJrBtGDa4YaxDzDE90EnKD3Vkh5a1t3w7PhnRQmsphLy3g2UieasoKTlT2Hn118TwDjIv5ZjHJW6HbzXA9wQ==} + peerDependencies: + react: '>=18' + dependencies: + react: 18.2.0 + dev: false + + /@chakra-ui/react-use-controllable-state@2.1.0(react@18.2.0): + resolution: {integrity: sha512-QR/8fKNokxZUs4PfxjXuwl0fj/d71WPrmLJvEpCTkHjnzu7LnYvzoe2wB867IdooQJL0G1zBxl0Dq+6W1P3jpg==} + peerDependencies: + react: '>=18' + dependencies: + '@chakra-ui/react-use-callback-ref': 2.1.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@chakra-ui/react-use-disclosure@2.1.0(react@18.2.0): + resolution: {integrity: sha512-Ax4pmxA9LBGMyEZJhhUZobg9C0t3qFE4jVF1tGBsrLDcdBeLR9fwOogIPY9Hf0/wqSlAryAimICbr5hkpa5GSw==} + peerDependencies: + react: '>=18' + dependencies: + '@chakra-ui/react-use-callback-ref': 2.1.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@chakra-ui/react-use-event-listener@2.1.0(react@18.2.0): + resolution: {integrity: sha512-U5greryDLS8ISP69DKDsYcsXRtAdnTQT+jjIlRYZ49K/XhUR/AqVZCK5BkR1spTDmO9H8SPhgeNKI70ODuDU/Q==} + peerDependencies: + react: '>=18' + dependencies: + '@chakra-ui/react-use-callback-ref': 2.1.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@chakra-ui/react-use-focus-effect@2.1.0(react@18.2.0): + resolution: {integrity: sha512-xzVboNy7J64xveLcxTIJ3jv+lUJKDwRM7Szwn9tNzUIPD94O3qwjV7DDCUzN2490nSYDF4OBMt/wuDBtaR3kUQ==} + peerDependencies: + react: '>=18' + dependencies: + '@chakra-ui/dom-utils': 2.1.0 + '@chakra-ui/react-use-event-listener': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-safe-layout-effect': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-update-effect': 2.1.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@chakra-ui/react-use-focus-on-pointer-down@2.1.0(react@18.2.0): + resolution: {integrity: sha512-2jzrUZ+aiCG/cfanrolsnSMDykCAbv9EK/4iUyZno6BYb3vziucmvgKuoXbMPAzWNtwUwtuMhkby8rc61Ue+Lg==} + peerDependencies: + react: '>=18' + dependencies: + '@chakra-ui/react-use-event-listener': 2.1.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@chakra-ui/react-use-interval@2.1.0(react@18.2.0): + resolution: {integrity: sha512-8iWj+I/+A0J08pgEXP1J1flcvhLBHkk0ln7ZvGIyXiEyM6XagOTJpwNhiu+Bmk59t3HoV/VyvyJTa+44sEApuw==} + peerDependencies: + react: '>=18' + dependencies: + '@chakra-ui/react-use-callback-ref': 2.1.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@chakra-ui/react-use-latest-ref@2.1.0(react@18.2.0): + resolution: {integrity: sha512-m0kxuIYqoYB0va9Z2aW4xP/5b7BzlDeWwyXCH6QpT2PpW3/281L3hLCm1G0eOUcdVlayqrQqOeD6Mglq+5/xoQ==} + peerDependencies: + react: '>=18' + dependencies: + react: 18.2.0 + dev: false + + /@chakra-ui/react-use-merge-refs@2.1.0(react@18.2.0): + resolution: {integrity: sha512-lERa6AWF1cjEtWSGjxWTaSMvneccnAVH4V4ozh8SYiN9fSPZLlSG3kNxfNzdFvMEhM7dnP60vynF7WjGdTgQbQ==} + peerDependencies: + react: '>=18' + dependencies: + react: 18.2.0 + dev: false + + /@chakra-ui/react-use-outside-click@2.2.0(react@18.2.0): + resolution: {integrity: sha512-PNX+s/JEaMneijbgAM4iFL+f3m1ga9+6QK0E5Yh4s8KZJQ/bLwZzdhMz8J/+mL+XEXQ5J0N8ivZN28B82N1kNw==} + peerDependencies: + react: '>=18' + dependencies: + '@chakra-ui/react-use-callback-ref': 2.1.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@chakra-ui/react-use-pan-event@2.1.0(react@18.2.0): + resolution: {integrity: sha512-xmL2qOHiXqfcj0q7ZK5s9UjTh4Gz0/gL9jcWPA6GVf+A0Od5imEDa/Vz+533yQKWiNSm1QGrIj0eJAokc7O4fg==} + peerDependencies: + react: '>=18' + dependencies: + '@chakra-ui/event-utils': 2.0.8 + '@chakra-ui/react-use-latest-ref': 2.1.0(react@18.2.0) + framesync: 6.1.2 + react: 18.2.0 + dev: false + + /@chakra-ui/react-use-previous@2.1.0(react@18.2.0): + resolution: {integrity: sha512-pjxGwue1hX8AFcmjZ2XfrQtIJgqbTF3Qs1Dy3d1krC77dEsiCUbQ9GzOBfDc8pfd60DrB5N2tg5JyHbypqh0Sg==} + peerDependencies: + react: '>=18' + dependencies: + react: 18.2.0 + dev: false + + /@chakra-ui/react-use-safe-layout-effect@2.1.0(react@18.2.0): + resolution: {integrity: sha512-Knbrrx/bcPwVS1TorFdzrK/zWA8yuU/eaXDkNj24IrKoRlQrSBFarcgAEzlCHtzuhufP3OULPkELTzz91b0tCw==} + peerDependencies: + react: '>=18' + dependencies: + react: 18.2.0 + dev: false + + /@chakra-ui/react-use-size@2.1.0(react@18.2.0): + resolution: {integrity: sha512-tbLqrQhbnqOjzTaMlYytp7wY8BW1JpL78iG7Ru1DlV4EWGiAmXFGvtnEt9HftU0NJ0aJyjgymkxfVGI55/1Z4A==} + peerDependencies: + react: '>=18' + dependencies: + '@zag-js/element-size': 0.10.5 + react: 18.2.0 + dev: false + + /@chakra-ui/react-use-timeout@2.1.0(react@18.2.0): + resolution: {integrity: sha512-cFN0sobKMM9hXUhyCofx3/Mjlzah6ADaEl/AXl5Y+GawB5rgedgAcu2ErAgarEkwvsKdP6c68CKjQ9dmTQlJxQ==} + peerDependencies: + react: '>=18' + dependencies: + '@chakra-ui/react-use-callback-ref': 2.1.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@chakra-ui/react-use-update-effect@2.1.0(react@18.2.0): + resolution: {integrity: sha512-ND4Q23tETaR2Qd3zwCKYOOS1dfssojPLJMLvUtUbW5M9uW1ejYWgGUobeAiOVfSplownG8QYMmHTP86p/v0lbA==} + peerDependencies: + react: '>=18' + dependencies: + react: 18.2.0 + dev: false + + /@chakra-ui/react-utils@2.0.12(react@18.2.0): + resolution: {integrity: sha512-GbSfVb283+YA3kA8w8xWmzbjNWk14uhNpntnipHCftBibl0lxtQ9YqMFQLwuFOO0U2gYVocszqqDWX+XNKq9hw==} + peerDependencies: + react: '>=18' + dependencies: + '@chakra-ui/utils': 2.0.15 + react: 18.2.0 + dev: false + + /@chakra-ui/react@2.8.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.21)(framer-motion@10.0.0)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-tV82DaqE4fMbLIWq58BYh4Ol3gAlNEn+qYOzx8bPrZudboEDnboq8aVfSBwWOY++MLWz2Nn7CkT69YRm91e5sg==} peerDependencies: '@emotion/react': ^11.0.0 '@emotion/styled': ^11.0.0 @@ -795,349 +1042,394 @@ packages: react: '>=18' react-dom: '>=18' dependencies: - '@chakra-ui/accordion': 2.0.6(@chakra-ui/system@2.2.2)(framer-motion@6.5.1)(react@18.2.0) - '@chakra-ui/alert': 2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/avatar': 2.0.5(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/breadcrumb': 2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/button': 2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/checkbox': 2.1.3(@chakra-ui/system@2.2.2)(framer-motion@6.5.1)(react@18.2.0) - '@chakra-ui/close-button': 2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/control-box': 2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/counter': 2.0.4(react@18.2.0) - '@chakra-ui/css-reset': 2.0.1(@emotion/react@11.9.3)(react@18.2.0) - '@chakra-ui/editable': 2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/form-control': 2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/hooks': 2.0.4(react@18.2.0) - '@chakra-ui/icon': 3.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/image': 2.0.5(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/input': 2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/layout': 2.1.1(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/live-region': 2.0.4(react@18.2.0) - '@chakra-ui/media-query': 3.2.0(@chakra-ui/system@2.2.2)(@chakra-ui/theme@2.1.3)(react@18.2.0) - '@chakra-ui/menu': 2.0.6(@chakra-ui/system@2.2.2)(framer-motion@6.5.1)(react@18.2.0) - '@chakra-ui/modal': 2.1.2(@chakra-ui/system@2.2.2)(@types/react@18.0.15)(framer-motion@6.5.1)(react-dom@18.2.0)(react@18.2.0) - '@chakra-ui/number-input': 2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/pin-input': 2.0.6(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/popover': 2.0.4(@chakra-ui/system@2.2.2)(framer-motion@6.5.1)(react@18.2.0) - '@chakra-ui/popper': 3.0.2(react@18.2.0) - '@chakra-ui/portal': 2.0.4(react-dom@18.2.0)(react@18.2.0) - '@chakra-ui/progress': 2.0.5(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/provider': 2.0.9(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react-dom@18.2.0)(react@18.2.0) - '@chakra-ui/radio': 2.0.5(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/react-env': 2.0.4(react@18.2.0) - '@chakra-ui/select': 2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/skeleton': 2.0.9(@chakra-ui/theme@2.1.3)(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/slider': 2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/spinner': 2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/stat': 2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/switch': 2.0.6(@chakra-ui/system@2.2.2)(framer-motion@6.5.1)(react@18.2.0) - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/table': 2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/tabs': 2.0.6(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/tag': 2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/textarea': 2.0.5(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/theme': 2.1.3(@chakra-ui/system@2.2.2) - '@chakra-ui/toast': 3.0.2(@chakra-ui/system@2.2.2)(framer-motion@6.5.1)(react-dom@18.2.0)(react@18.2.0) - '@chakra-ui/tooltip': 2.0.5(@chakra-ui/system@2.2.2)(framer-motion@6.5.1)(react-dom@18.2.0)(react@18.2.0) - '@chakra-ui/transition': 2.0.4(framer-motion@6.5.1)(react@18.2.0) - '@chakra-ui/utils': 2.0.4 - '@chakra-ui/visually-hidden': 2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@emotion/react': 11.9.3(@babel/core@7.18.6)(@types/react@18.0.15)(react@18.2.0) - '@emotion/styled': 11.9.3(@babel/core@7.18.6)(@emotion/react@11.9.3)(@types/react@18.0.15)(react@18.2.0) - framer-motion: 6.5.1(react-dom@18.2.0)(react@18.2.0) + '@chakra-ui/accordion': 2.3.0(@chakra-ui/system@2.6.0)(framer-motion@10.0.0)(react@18.2.0) + '@chakra-ui/alert': 2.2.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/avatar': 2.3.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/breadcrumb': 2.2.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/button': 2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/card': 2.2.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/checkbox': 2.3.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/close-button': 2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/control-box': 2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/counter': 2.1.0(react@18.2.0) + '@chakra-ui/css-reset': 2.2.0(@emotion/react@11.11.1)(react@18.2.0) + '@chakra-ui/editable': 3.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/focus-lock': 2.1.0(@types/react@18.2.21)(react@18.2.0) + '@chakra-ui/form-control': 2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/hooks': 2.2.0(react@18.2.0) + '@chakra-ui/icon': 3.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/image': 2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/input': 2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/layout': 2.3.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/live-region': 2.1.0(react@18.2.0) + '@chakra-ui/media-query': 3.3.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/menu': 2.2.0(@chakra-ui/system@2.6.0)(framer-motion@10.0.0)(react@18.2.0) + '@chakra-ui/modal': 2.3.0(@chakra-ui/system@2.6.0)(@types/react@18.2.21)(framer-motion@10.0.0)(react-dom@18.2.0)(react@18.2.0) + '@chakra-ui/number-input': 2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/pin-input': 2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/popover': 2.2.0(@chakra-ui/system@2.6.0)(framer-motion@10.0.0)(react@18.2.0) + '@chakra-ui/popper': 3.1.0(react@18.2.0) + '@chakra-ui/portal': 2.1.0(react-dom@18.2.0)(react@18.2.0) + '@chakra-ui/progress': 2.2.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/provider': 2.4.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react-dom@18.2.0)(react@18.2.0) + '@chakra-ui/radio': 2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/react-env': 3.1.0(react@18.2.0) + '@chakra-ui/select': 2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/skeleton': 2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/skip-nav': 2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/slider': 2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/spinner': 2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/stat': 2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/stepper': 2.3.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/styled-system': 2.9.1 + '@chakra-ui/switch': 2.1.0(@chakra-ui/system@2.6.0)(framer-motion@10.0.0)(react@18.2.0) + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) + '@chakra-ui/table': 2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/tabs': 2.2.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/tag': 3.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/textarea': 2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/theme': 3.2.0(@chakra-ui/styled-system@2.9.1) + '@chakra-ui/theme-utils': 2.0.19 + '@chakra-ui/toast': 7.0.0(@chakra-ui/system@2.6.0)(framer-motion@10.0.0)(react-dom@18.2.0)(react@18.2.0) + '@chakra-ui/tooltip': 2.3.0(@chakra-ui/system@2.6.0)(framer-motion@10.0.0)(react-dom@18.2.0)(react@18.2.0) + '@chakra-ui/transition': 2.1.0(framer-motion@10.0.0)(react@18.2.0) + '@chakra-ui/utils': 2.0.15 + '@chakra-ui/visually-hidden': 2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@emotion/react': 11.11.1(@types/react@18.2.21)(react@18.2.0) + '@emotion/styled': 11.11.0(@emotion/react@11.11.1)(@types/react@18.2.21)(react@18.2.0) + framer-motion: 10.0.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) transitivePeerDependencies: - '@types/react' dev: false - /@chakra-ui/select@2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0): - resolution: {integrity: sha512-ta1yX8EffhdH3RcNOI9RxCdYZ2hHvEwJXBnr3pW6gf7asw/jNlTyBmmSUAddHp1j9YwKfT9F5jkKmtovNdrpdA==} + /@chakra-ui/select@2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0): + resolution: {integrity: sha512-6GEjCJNOm1pS9E7XRvodoVOuSFl82Jio3MGWgmcQrLznjJAhIZVMq85vCQqzGpjjfbHys/UctfdJY75Ctas/Jg==} peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' + '@chakra-ui/system': '>=2.0.0' react: '>=18' dependencies: - '@chakra-ui/form-control': 2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/utils': 2.0.4 + '@chakra-ui/form-control': 2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/shared-utils': 2.0.5 + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) react: 18.2.0 dev: false - /@chakra-ui/skeleton@2.0.9(@chakra-ui/theme@2.1.3)(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0): - resolution: {integrity: sha512-bdblqZ/quq1GN0DBC1baj8DqpLkA3wfVnxvR6QVA9Qy/KgnvRiMWe/xiwXKAq8Tnkoxco94ACIk7M1m0tWjJZA==} + /@chakra-ui/shared-utils@2.0.5: + resolution: {integrity: sha512-4/Wur0FqDov7Y0nCXl7HbHzCg4aq86h+SXdoUeuCMD3dSj7dpsVnStLYhng1vxvlbUnLpdF4oz5Myt3i/a7N3Q==} + dev: false + + /@chakra-ui/skeleton@2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0): + resolution: {integrity: sha512-JNRuMPpdZGd6zFVKjVQ0iusu3tXAdI29n4ZENYwAJEMf/fN0l12sVeirOxkJ7oEL0yOx2AgEYFSKdbcAgfUsAQ==} peerDependencies: - '@chakra-ui/theme': '>=2.0.0-next.0' - '@emotion/react': ^11.0.0 - '@emotion/styled': ^11.0.0 + '@chakra-ui/system': '>=2.0.0' react: '>=18' dependencies: - '@chakra-ui/hooks': 2.0.4(react@18.2.0) - '@chakra-ui/media-query': 3.2.0(@chakra-ui/system@2.2.2)(@chakra-ui/theme@2.1.3)(react@18.2.0) - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/theme': 2.1.3(@chakra-ui/system@2.2.2) - '@chakra-ui/utils': 2.0.4 - '@emotion/react': 11.9.3(@babel/core@7.18.6)(@types/react@18.0.15)(react@18.2.0) - '@emotion/styled': 11.9.3(@babel/core@7.18.6)(@emotion/react@11.9.3)(@types/react@18.0.15)(react@18.2.0) + '@chakra-ui/media-query': 3.3.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/react-use-previous': 2.1.0(react@18.2.0) + '@chakra-ui/shared-utils': 2.0.5 + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) react: 18.2.0 dev: false - /@chakra-ui/slider@2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0): - resolution: {integrity: sha512-bNhysW59KTpEl88Q/kNKCmfh2KZWJipFRIYxjE0IJQ+slesET3qgRWwqtdEVl4mutmDkzTyoSKRuBYCdS6HO0A==} + /@chakra-ui/skip-nav@2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0): + resolution: {integrity: sha512-Hk+FG+vadBSH0/7hwp9LJnLjkO0RPGnx7gBJWI4/SpoJf3e4tZlWYtwGj0toYY4aGKl93jVghuwGbDBEMoHDug==} peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' + '@chakra-ui/system': '>=2.0.0' react: '>=18' dependencies: - '@chakra-ui/hooks': 2.0.4(react@18.2.0) - '@chakra-ui/react-utils': 2.0.1(react@18.2.0) - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/utils': 2.0.4 + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) react: 18.2.0 dev: false - /@chakra-ui/spinner@2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0): - resolution: {integrity: sha512-BEUBgo6/6s+D9fo5vrkxLbPYNIPPZXVQNV+h1umnHNbZx9t6BDP/j4YAadboCEySidVGFZ+kfRq1mz4/XHgKZw==} + /@chakra-ui/slider@2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0): + resolution: {integrity: sha512-lUOBcLMCnFZiA/s2NONXhELJh6sY5WtbRykPtclGfynqqOo47lwWJx+VP7xaeuhDOPcWSSecWc9Y1BfPOCz9cQ==} peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' + '@chakra-ui/system': '>=2.0.0' react: '>=18' dependencies: - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/utils': 2.0.4 - '@chakra-ui/visually-hidden': 2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) + '@chakra-ui/number-utils': 2.0.7 + '@chakra-ui/react-context': 2.1.0(react@18.2.0) + '@chakra-ui/react-types': 2.0.7(react@18.2.0) + '@chakra-ui/react-use-callback-ref': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-controllable-state': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-latest-ref': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-merge-refs': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-pan-event': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-size': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-update-effect': 2.1.0(react@18.2.0) + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) react: 18.2.0 dev: false - /@chakra-ui/stat@2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0): - resolution: {integrity: sha512-zSBZcbdlBQtB8KVPr4jhrguvubuOUoR545PjRNnMTECDyg+Ff3sWzU4tB1RG7Cy/L7hObgYvQHfpAHZ+CdoAmA==} + /@chakra-ui/spinner@2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0): + resolution: {integrity: sha512-hczbnoXt+MMv/d3gE+hjQhmkzLiKuoTo42YhUG7Bs9OSv2lg1fZHW1fGNRFP3wTi6OIbD044U1P9HK+AOgFH3g==} peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' + '@chakra-ui/system': '>=2.0.0' react: '>=18' dependencies: - '@chakra-ui/icon': 3.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/utils': 2.0.4 - '@chakra-ui/visually-hidden': 2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) + '@chakra-ui/shared-utils': 2.0.5 + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) react: 18.2.0 dev: false - /@chakra-ui/styled-system@2.2.3: - resolution: {integrity: sha512-zbXJ2ytVQC944tuDBgm+Ya+KBYFkcsK/EzKq61TBk/AAPt/BNwC9/CNF9fuEVf7+p45cZvKdCyu27UewlUiXuA==} + /@chakra-ui/stat@2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0): + resolution: {integrity: sha512-sqx0/AdFFZ80dsiM5owmhtQyYl+zON1r+IY0m70I/ABRVy+I3br06xdUhoaxh3tcP7c0O/BQgb+VCfXa9Y34CA==} + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' dependencies: - '@chakra-ui/utils': 2.0.4 + '@chakra-ui/icon': 3.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/react-context': 2.1.0(react@18.2.0) + '@chakra-ui/shared-utils': 2.0.5 + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) + react: 18.2.0 + dev: false + + /@chakra-ui/stepper@2.3.0(@chakra-ui/system@2.6.0)(react@18.2.0): + resolution: {integrity: sha512-q80QX/NLrjJQIlBP1N+Q8GVJb7/HiOpMoK1PlP4denB/KxkU2K8GEjss8U2vklR1XsWJy1fwfj03+66Q78Uk/Q==} + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/icon': 3.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/react-context': 2.1.0(react@18.2.0) + '@chakra-ui/shared-utils': 2.0.5 + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) + react: 18.2.0 + dev: false + + /@chakra-ui/styled-system@2.9.1: + resolution: {integrity: sha512-jhYKBLxwOPi9/bQt9kqV3ELa/4CjmNNruTyXlPp5M0v0+pDMUngPp48mVLoskm9RKZGE0h1qpvj/jZ3K7c7t8w==} + dependencies: + '@chakra-ui/shared-utils': 2.0.5 csstype: 3.1.0 - dev: false - - /@chakra-ui/switch@2.0.6(@chakra-ui/system@2.2.2)(framer-motion@6.5.1)(react@18.2.0): - resolution: {integrity: sha512-agjRFu0Fy5u0D8MUdckpIen7jQFkYRg08xOWX57VXQEEJN7L8Pe5hF57aig65TXZMXQTcLB2ss6pQFYYDbt3cQ==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' - framer-motion: '>=4.0.0' - react: '>=18' - dependencies: - '@chakra-ui/checkbox': 2.1.3(@chakra-ui/system@2.2.2)(framer-motion@6.5.1)(react@18.2.0) - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/utils': 2.0.4 - framer-motion: 6.5.1(react-dom@18.2.0)(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/system@2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0): - resolution: {integrity: sha512-lo7QZSGNhw0HhvVYGRdP5cCllM6j5UL0S1syYu0gHhqNVu5qUrdpxpGsYqYK0MP7T16YReUoolPdz5UNVxVuLg==} - peerDependencies: - '@emotion/react': ^11.0.0 - '@emotion/styled': ^11.0.0 - react: '>=18' - dependencies: - '@chakra-ui/color-mode': 2.1.2(react@18.2.0) - '@chakra-ui/react-utils': 2.0.1(react@18.2.0) - '@chakra-ui/styled-system': 2.2.3 - '@chakra-ui/utils': 2.0.4 - '@emotion/react': 11.9.3(@babel/core@7.18.6)(@types/react@18.0.15)(react@18.2.0) - '@emotion/styled': 11.9.3(@babel/core@7.18.6)(@emotion/react@11.9.3)(@types/react@18.0.15)(react@18.2.0) - react: 18.2.0 - react-fast-compare: 3.2.0 - dev: false - - /@chakra-ui/table@2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0): - resolution: {integrity: sha512-Y+YddfpCbmT5D/QMdqM30zWQzwIif63fOB82TSHL2/OMJ6w4Y3fbDtVOLj1MFnTjCOi774nv15/3vHELioOSwA==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' - react: '>=18' - dependencies: - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/utils': 2.0.4 - react: 18.2.0 - dev: false - - /@chakra-ui/tabs@2.0.6(@chakra-ui/system@2.2.2)(react@18.2.0): - resolution: {integrity: sha512-N9vHRJ1fW27sa+SFgPVeiOoTpmbtEQEC4EHeoBzfw9ZaJl5E3YL4FBWCRVoIVY+/HgukmJGvHpCG7DDrzfBfEA==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' - react: '>=18' - dependencies: - '@chakra-ui/clickable': 2.0.4(react@18.2.0) - '@chakra-ui/descendant': 3.0.3(react@18.2.0) - '@chakra-ui/hooks': 2.0.4(react@18.2.0) - '@chakra-ui/react-utils': 2.0.1(react@18.2.0) - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/utils': 2.0.4 - react: 18.2.0 - dev: false - - /@chakra-ui/tag@2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0): - resolution: {integrity: sha512-OF6jpaDDlgQqN58B3K+pIEbWLRWXDm3LuqzM6Z/YIYL9numMIpxO0mZgyFsJQWvC4ldpGTf3olAvI/3KEHxSvA==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' - react: '>=18' - dependencies: - '@chakra-ui/icon': 3.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/utils': 2.0.4 - react: 18.2.0 - dev: false - - /@chakra-ui/textarea@2.0.5(@chakra-ui/system@2.2.2)(react@18.2.0): - resolution: {integrity: sha512-Pwh6F0Ev1RjdyqN71VNv8LSDwaL68U27KNSCsPWry5NaRvseb0ncS5/wuvBVRCsBy2Kcc2BJxIBbNR4oxAQ1Fg==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' - react: '>=18' - dependencies: - '@chakra-ui/form-control': 2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/utils': 2.0.4 - react: 18.2.0 - dev: false - - /@chakra-ui/theme-tools@2.0.5(@chakra-ui/system@2.2.2): - resolution: {integrity: sha512-JuFKYWfVnZKnX95sM05a/0NpTzwciPTAZXfAJYwDOiy4EEqXUgEQpkHxOjC929wpzIVb3Q2Wa/HvS1v8C2f+mw==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' - dependencies: - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/utils': 2.0.4 - '@ctrl/tinycolor': 3.4.1 - dev: false - - /@chakra-ui/theme@2.1.3(@chakra-ui/system@2.2.2): - resolution: {integrity: sha512-YRuw6D1xR2r2d09PVC4o7iNhxekqTkwq0P38Vn9UyLURXKnguYwkPXcJF3+ZcIPypqaROPPaOGOdtpwO7A/CjQ==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' - dependencies: - '@chakra-ui/anatomy': 2.0.1(@chakra-ui/system@2.2.2) - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/theme-tools': 2.0.5(@chakra-ui/system@2.2.2) - '@chakra-ui/utils': 2.0.4 - dev: false - - /@chakra-ui/toast@3.0.2(@chakra-ui/system@2.2.2)(framer-motion@6.5.1)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-MGUwgNMDevys6EVoEJDMs7S+5pAefx8ikdtMzOXB21RPs6J46EaOcmtZDIgxglUPTEF1QX2NzBFA+ObS2oklWQ==} - peerDependencies: - '@chakra-ui/system': 2.2.2 - framer-motion: '>=4.0.0' - react: '>=18' - react-dom: '>=18' - dependencies: - '@chakra-ui/alert': 2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/close-button': 2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - '@chakra-ui/hooks': 2.0.4(react@18.2.0) - '@chakra-ui/portal': 2.0.4(react-dom@18.2.0)(react@18.2.0) - '@chakra-ui/react-utils': 2.0.1(react@18.2.0) - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/theme': 2.1.3(@chakra-ui/system@2.2.2) - '@chakra-ui/transition': 2.0.4(framer-motion@6.5.1)(react@18.2.0) - '@chakra-ui/utils': 2.0.4 - framer-motion: 6.5.1(react-dom@18.2.0)(react@18.2.0) - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: false - - /@chakra-ui/tooltip@2.0.5(@chakra-ui/system@2.2.2)(framer-motion@6.5.1)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-I2+sT0+jAl98ggbUikKk/5mZsLeMjQYeGF7P5OwVzD8NWjtLwjJC75bmkw7c53V5FQKGB1z76T13asWfy5vmdg==} - peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' - framer-motion: '>=4.0.0' - react: '>=18' - react-dom: '>=18' - dependencies: - '@chakra-ui/hooks': 2.0.4(react@18.2.0) - '@chakra-ui/popper': 3.0.2(react@18.2.0) - '@chakra-ui/portal': 2.0.4(react-dom@18.2.0)(react@18.2.0) - '@chakra-ui/react-utils': 2.0.1(react@18.2.0) - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/utils': 2.0.4 - '@chakra-ui/visually-hidden': 2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0) - framer-motion: 6.5.1(react-dom@18.2.0)(react@18.2.0) - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: false - - /@chakra-ui/transition@2.0.4(framer-motion@6.5.1)(react@18.2.0): - resolution: {integrity: sha512-k9/01frV/Z6iEt68lfz8PLYiPoWC9N99Uo6XYQjw17kcguVxJoliq35sUharVcQJneVi5bmKTp9974/3drFDBw==} - peerDependencies: - framer-motion: '>=4.0.0' - react: '>=18' - dependencies: - '@chakra-ui/utils': 2.0.4 - framer-motion: 6.5.1(react-dom@18.2.0)(react@18.2.0) - react: 18.2.0 - dev: false - - /@chakra-ui/utils@2.0.4: - resolution: {integrity: sha512-pr5qFTrhCja1iQTajOr2WSvb+f4lpnLnnxWOSYOuIv7k8LBEtee4LpTs0jzBBB/vycuo6ppKdXyj7db9xTqZfA==} - dependencies: - '@types/lodash.mergewith': 4.6.6 - css-box-model: 1.2.1 - framesync: 5.3.0 lodash.mergewith: 4.6.2 dev: false - /@chakra-ui/visually-hidden@2.0.4(@chakra-ui/system@2.2.2)(react@18.2.0): - resolution: {integrity: sha512-7JVHdMnyvpUnC8EkWtI7tE/NZWoVVHR35KLG/tmCEC4ZzNN7oINTYgQ70ALYKMNM3A2PrXdpbVjeBe4afn8UQQ==} + /@chakra-ui/switch@2.1.0(@chakra-ui/system@2.6.0)(framer-motion@10.0.0)(react@18.2.0): + resolution: {integrity: sha512-uWHOaIDQdGh+mszxeppj5aYVepbkSK445KZlJJkfr9Bnr6sythTwM63HSufnVDiTEE4uRqegv9jEjZK2JKA+9A==} peerDependencies: - '@chakra-ui/system': '>=2.0.0-next.0' + '@chakra-ui/system': '>=2.0.0' + framer-motion: '>=4.0.0' react: '>=18' dependencies: - '@chakra-ui/system': 2.2.2(@emotion/react@11.9.3)(@emotion/styled@11.9.3)(react@18.2.0) - '@chakra-ui/utils': 2.0.4 + '@chakra-ui/checkbox': 2.3.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/shared-utils': 2.0.5 + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) + framer-motion: 10.0.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 dev: false - /@ctrl/tinycolor@3.4.1: - resolution: {integrity: sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw==} - engines: {node: '>=10'} + /@chakra-ui/system@2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0): + resolution: {integrity: sha512-MgAFRz9V1pW0dplwWsB99hx49LCC+LsrkMala7KXcP0OvWdrkjw+iu+voBksO3626+glzgIwlZW113Eja+7JEQ==} + peerDependencies: + '@emotion/react': ^11.0.0 + '@emotion/styled': ^11.0.0 + react: '>=18' + dependencies: + '@chakra-ui/color-mode': 2.2.0(react@18.2.0) + '@chakra-ui/object-utils': 2.1.0 + '@chakra-ui/react-utils': 2.0.12(react@18.2.0) + '@chakra-ui/styled-system': 2.9.1 + '@chakra-ui/theme-utils': 2.0.19 + '@chakra-ui/utils': 2.0.15 + '@emotion/react': 11.11.1(@types/react@18.2.21)(react@18.2.0) + '@emotion/styled': 11.11.0(@emotion/react@11.11.1)(@types/react@18.2.21)(react@18.2.0) + react: 18.2.0 + react-fast-compare: 3.2.1 dev: false - /@emotion/babel-plugin@11.9.2(@babel/core@7.18.6): - resolution: {integrity: sha512-Pr/7HGH6H6yKgnVFNEj2MVlreu3ADqftqjqwUvDy/OJzKFgxKeTQ+eeUf20FOTuHVkDON2iNa25rAXVYtWJCjw==} + /@chakra-ui/table@2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0): + resolution: {integrity: sha512-o5OrjoHCh5uCLdiUb0Oc0vq9rIAeHSIRScc2ExTC9Qg/uVZl2ygLrjToCaKfaaKl1oQexIeAcZDKvPG8tVkHyQ==} peerDependencies: - '@babel/core': ^7.0.0 + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/react-context': 2.1.0(react@18.2.0) + '@chakra-ui/shared-utils': 2.0.5 + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) + react: 18.2.0 + dev: false + + /@chakra-ui/tabs@2.2.0(@chakra-ui/system@2.6.0)(react@18.2.0): + resolution: {integrity: sha512-ulN7McHZ322qlbJXg8S+IwdN8Axh8q0HzYBOHzSdcnVphEytfv9TsfJhN0Hx5yjkpekAzG5fewn33ZdIpIpKyQ==} + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/clickable': 2.1.0(react@18.2.0) + '@chakra-ui/descendant': 3.1.0(react@18.2.0) + '@chakra-ui/lazy-utils': 2.0.5 + '@chakra-ui/react-children-utils': 2.0.6(react@18.2.0) + '@chakra-ui/react-context': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-controllable-state': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-merge-refs': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-safe-layout-effect': 2.1.0(react@18.2.0) + '@chakra-ui/shared-utils': 2.0.5 + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) + react: 18.2.0 + dev: false + + /@chakra-ui/tag@3.1.0(@chakra-ui/system@2.6.0)(react@18.2.0): + resolution: {integrity: sha512-Mn2u828z5HvqEBEG+tUJWe3al5tzN87bK2U0QfThx3+zqWbBCWBSCVfnWRtkNh80m+5a1TekexDAPZqu5G8zdw==} + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/icon': 3.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/react-context': 2.1.0(react@18.2.0) + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) + react: 18.2.0 + dev: false + + /@chakra-ui/textarea@2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0): + resolution: {integrity: sha512-4F7X/lPRsY+sPxYrWGrhh1pBtdnFvVllIOapzAwnjYwsflm+vf6c+9ZgoDWobXsNezJ9fcqN0FTPwaBnDvDQRQ==} + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/form-control': 2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/shared-utils': 2.0.5 + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) + react: 18.2.0 + dev: false + + /@chakra-ui/theme-tools@2.1.0(@chakra-ui/styled-system@2.9.1): + resolution: {integrity: sha512-TKv4trAY8q8+DWdZrpSabTd3SZtZrnzFDwUdzhbWBhFEDEVR3fAkRTPpnPDtf1X9w1YErWn3QAcMACVFz4+vkw==} + peerDependencies: + '@chakra-ui/styled-system': '>=2.0.0' + dependencies: + '@chakra-ui/anatomy': 2.2.0 + '@chakra-ui/shared-utils': 2.0.5 + '@chakra-ui/styled-system': 2.9.1 + color2k: 2.0.2 + dev: false + + /@chakra-ui/theme-utils@2.0.19: + resolution: {integrity: sha512-UQ+KvozTN86+0oA80rdQd1a++4rm4ulo+DEabkgwNpkK3yaWsucOxkDQpi2sMIMvw5X0oaWvNBZJuVyK7HdOXg==} + dependencies: + '@chakra-ui/shared-utils': 2.0.5 + '@chakra-ui/styled-system': 2.9.1 + '@chakra-ui/theme': 3.2.0(@chakra-ui/styled-system@2.9.1) + lodash.mergewith: 4.6.2 + dev: false + + /@chakra-ui/theme@3.2.0(@chakra-ui/styled-system@2.9.1): + resolution: {integrity: sha512-q9mppdkhmaBnvOT8REr/lVNNBX/prwm50EzObJ+r+ErVhNQDc55gCFmtr+It3xlcCqmOteG6XUdwRCJz8qzOqg==} + peerDependencies: + '@chakra-ui/styled-system': '>=2.8.0' + dependencies: + '@chakra-ui/anatomy': 2.2.0 + '@chakra-ui/shared-utils': 2.0.5 + '@chakra-ui/styled-system': 2.9.1 + '@chakra-ui/theme-tools': 2.1.0(@chakra-ui/styled-system@2.9.1) + dev: false + + /@chakra-ui/toast@7.0.0(@chakra-ui/system@2.6.0)(framer-motion@10.0.0)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-XQgSnn4DYRgfOBzBvh8GI/AZ7SfrO8wlVSmChfp92Nfmqm7tRDUT9x8ws/iNKAvMRHkhl7fmRjJ39ipeXYrMvA==} + peerDependencies: + '@chakra-ui/system': 2.6.0 + framer-motion: '>=4.0.0' + react: '>=18' + react-dom: '>=18' + dependencies: + '@chakra-ui/alert': 2.2.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/close-button': 2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0) + '@chakra-ui/portal': 2.1.0(react-dom@18.2.0)(react@18.2.0) + '@chakra-ui/react-context': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-timeout': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-update-effect': 2.1.0(react@18.2.0) + '@chakra-ui/shared-utils': 2.0.5 + '@chakra-ui/styled-system': 2.9.1 + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) + '@chakra-ui/theme': 3.2.0(@chakra-ui/styled-system@2.9.1) + framer-motion: 10.0.0(react-dom@18.2.0)(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@chakra-ui/tooltip@2.3.0(@chakra-ui/system@2.6.0)(framer-motion@10.0.0)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-2s23f93YIij1qEDwIK//KtEu4LLYOslhR1cUhDBk/WUzyFR3Ez0Ee+HlqlGEGfGe9x77E6/UXPnSAKKdF/cpsg==} + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + framer-motion: '>=4.0.0' + react: '>=18' + react-dom: '>=18' + dependencies: + '@chakra-ui/dom-utils': 2.1.0 + '@chakra-ui/popper': 3.1.0(react@18.2.0) + '@chakra-ui/portal': 2.1.0(react-dom@18.2.0)(react@18.2.0) + '@chakra-ui/react-types': 2.0.7(react@18.2.0) + '@chakra-ui/react-use-disclosure': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-event-listener': 2.1.0(react@18.2.0) + '@chakra-ui/react-use-merge-refs': 2.1.0(react@18.2.0) + '@chakra-ui/shared-utils': 2.0.5 + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) + framer-motion: 10.0.0(react-dom@18.2.0)(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@chakra-ui/transition@2.1.0(framer-motion@10.0.0)(react@18.2.0): + resolution: {integrity: sha512-orkT6T/Dt+/+kVwJNy7zwJ+U2xAZ3EU7M3XCs45RBvUnZDr/u9vdmaM/3D/rOpmQJWgQBwKPJleUXrYWUagEDQ==} + peerDependencies: + framer-motion: '>=4.0.0' + react: '>=18' + dependencies: + '@chakra-ui/shared-utils': 2.0.5 + framer-motion: 10.0.0(react-dom@18.2.0)(react@18.2.0) + react: 18.2.0 + dev: false + + /@chakra-ui/utils@2.0.15: + resolution: {integrity: sha512-El4+jL0WSaYYs+rJbuYFDbjmfCcfGDmRY95GO4xwzit6YAPZBLcR65rOEwLps+XWluZTy1xdMrusg/hW0c1aAA==} + dependencies: + '@types/lodash.mergewith': 4.6.7 + css-box-model: 1.2.1 + framesync: 6.1.2 + lodash.mergewith: 4.6.2 + dev: false + + /@chakra-ui/visually-hidden@2.1.0(@chakra-ui/system@2.6.0)(react@18.2.0): + resolution: {integrity: sha512-3OHKqTz78PX7V4qto+a5Y6VvH6TbU3Pg6Z0Z2KnDkOBP3Po8fiz0kk+/OSPzIwdcSsQKiocLi0c1pnnUPdMZPg==} + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/system': 2.6.0(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0) + react: 18.2.0 + dev: false + + /@emotion/babel-plugin@11.11.0: + resolution: {integrity: sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==} dependencies: - '@babel/core': 7.18.6 '@babel/helper-module-imports': 7.18.6 - '@babel/plugin-syntax-jsx': 7.18.6(@babel/core@7.18.6) '@babel/runtime': 7.18.6 - '@emotion/hash': 0.8.0 - '@emotion/memoize': 0.7.5 - '@emotion/serialize': 1.0.4 - babel-plugin-macros: 2.8.0 + '@emotion/hash': 0.9.1 + '@emotion/memoize': 0.8.1 + '@emotion/serialize': 1.1.2 + babel-plugin-macros: 3.1.0 convert-source-map: 1.8.0 escape-string-regexp: 4.0.0 find-root: 1.1.0 source-map: 0.5.7 - stylis: 4.0.13 + stylis: 4.2.0 dev: false - /@emotion/cache@11.9.3: - resolution: {integrity: sha512-0dgkI/JKlCXa+lEXviaMtGBL0ynpx4osh7rjOXE71q9bIF8G+XhJgvi+wDu0B0IdCVx37BffiwXlN9I3UuzFvg==} + /@emotion/cache@11.11.0: + resolution: {integrity: sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==} dependencies: - '@emotion/memoize': 0.7.5 - '@emotion/sheet': 1.1.1 - '@emotion/utils': 1.1.0 - '@emotion/weak-memoize': 0.2.5 - stylis: 4.0.13 + '@emotion/memoize': 0.8.1 + '@emotion/sheet': 1.2.2 + '@emotion/utils': 1.2.1 + '@emotion/weak-memoize': 0.3.1 + stylis: 4.2.0 dev: false - /@emotion/hash@0.8.0: - resolution: {integrity: sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==} + /@emotion/hash@0.9.1: + resolution: {integrity: sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==} dev: false /@emotion/is-prop-valid@0.8.8: @@ -1148,10 +1440,10 @@ packages: dev: false optional: true - /@emotion/is-prop-valid@1.1.3: - resolution: {integrity: sha512-RFg04p6C+1uO19uG8N+vqanzKqiM9eeV1LDOG3bmkYmuOj7NbKNlFC/4EZq5gnwAIlcC/jOT24f8Td0iax2SXA==} + /@emotion/is-prop-valid@1.2.1: + resolution: {integrity: sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw==} dependencies: - '@emotion/memoize': 0.7.5 + '@emotion/memoize': 0.8.1 dev: false /@emotion/memoize@0.7.4: @@ -1159,92 +1451,109 @@ packages: dev: false optional: true - /@emotion/memoize@0.7.5: - resolution: {integrity: sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==} + /@emotion/memoize@0.8.1: + resolution: {integrity: sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==} dev: false - /@emotion/react@11.9.3(@babel/core@7.18.6)(@types/react@18.0.15)(react@18.2.0): - resolution: {integrity: sha512-g9Q1GcTOlzOEjqwuLF/Zd9LC+4FljjPjDfxSM7KmEakm+hsHXk+bYZ2q+/hTJzr0OUNkujo72pXLQvXj6H+GJQ==} + /@emotion/react@11.11.1(@types/react@18.2.21)(react@18.2.0): + resolution: {integrity: sha512-5mlW1DquU5HaxjLkfkGN1GA/fvVGdyHURRiX/0FHl2cfIfRxSOfmxEH5YS43edp0OldZrZ+dkBKbngxcNCdZvA==} peerDependencies: - '@babel/core': ^7.0.0 '@types/react': '*' react: '>=16.8.0' peerDependenciesMeta: - '@babel/core': - optional: true '@types/react': optional: true dependencies: - '@babel/core': 7.18.6 '@babel/runtime': 7.18.6 - '@emotion/babel-plugin': 11.9.2(@babel/core@7.18.6) - '@emotion/cache': 11.9.3 - '@emotion/serialize': 1.0.4 - '@emotion/utils': 1.1.0 - '@emotion/weak-memoize': 0.2.5 - '@types/react': 18.0.15 + '@emotion/babel-plugin': 11.11.0 + '@emotion/cache': 11.11.0 + '@emotion/serialize': 1.1.2 + '@emotion/use-insertion-effect-with-fallbacks': 1.0.1(react@18.2.0) + '@emotion/utils': 1.2.1 + '@emotion/weak-memoize': 0.3.1 + '@types/react': 18.2.21 hoist-non-react-statics: 3.3.2 react: 18.2.0 dev: false - /@emotion/serialize@1.0.4: - resolution: {integrity: sha512-1JHamSpH8PIfFwAMryO2bNka+y8+KA5yga5Ocf2d7ZEiJjb7xlLW7aknBGZqJLajuLOvJ+72vN+IBSwPlXD1Pg==} + /@emotion/serialize@1.1.2: + resolution: {integrity: sha512-zR6a/fkFP4EAcCMQtLOhIgpprZOwNmCldtpaISpvz348+DP4Mz8ZoKaGGCQpbzepNIUWbq4w6hNZkwDyKoS+HA==} dependencies: - '@emotion/hash': 0.8.0 - '@emotion/memoize': 0.7.5 - '@emotion/unitless': 0.7.5 - '@emotion/utils': 1.1.0 + '@emotion/hash': 0.9.1 + '@emotion/memoize': 0.8.1 + '@emotion/unitless': 0.8.1 + '@emotion/utils': 1.2.1 csstype: 3.1.0 dev: false - /@emotion/sheet@1.1.1: - resolution: {integrity: sha512-J3YPccVRMiTZxYAY0IOq3kd+hUP8idY8Kz6B/Cyo+JuXq52Ek+zbPbSQUrVQp95aJ+lsAW7DPL1P2Z+U1jGkKA==} + /@emotion/sheet@1.2.2: + resolution: {integrity: sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==} dev: false - /@emotion/styled@11.9.3(@babel/core@7.18.6)(@emotion/react@11.9.3)(@types/react@18.0.15)(react@18.2.0): - resolution: {integrity: sha512-o3sBNwbtoVz9v7WB1/Y/AmXl69YHmei2mrVnK7JgyBJ//Rst5yqPZCecEJlMlJrFeWHp+ki/54uN265V2pEcXA==} + /@emotion/styled@11.11.0(@emotion/react@11.11.1)(@types/react@18.2.21)(react@18.2.0): + resolution: {integrity: sha512-hM5Nnvu9P3midq5aaXj4I+lnSfNi7Pmd4EWk1fOZ3pxookaQTNew6bp4JaCBYM4HVFZF9g7UjJmsUmC2JlxOng==} peerDependencies: - '@babel/core': ^7.0.0 '@emotion/react': ^11.0.0-rc.0 '@types/react': '*' react: '>=16.8.0' peerDependenciesMeta: - '@babel/core': - optional: true '@types/react': optional: true dependencies: - '@babel/core': 7.18.6 '@babel/runtime': 7.18.6 - '@emotion/babel-plugin': 11.9.2(@babel/core@7.18.6) - '@emotion/is-prop-valid': 1.1.3 - '@emotion/react': 11.9.3(@babel/core@7.18.6)(@types/react@18.0.15)(react@18.2.0) - '@emotion/serialize': 1.0.4 - '@emotion/utils': 1.1.0 - '@types/react': 18.0.15 + '@emotion/babel-plugin': 11.11.0 + '@emotion/is-prop-valid': 1.2.1 + '@emotion/react': 11.11.1(@types/react@18.2.21)(react@18.2.0) + '@emotion/serialize': 1.1.2 + '@emotion/use-insertion-effect-with-fallbacks': 1.0.1(react@18.2.0) + '@emotion/utils': 1.2.1 + '@types/react': 18.2.21 react: 18.2.0 dev: false - /@emotion/unitless@0.7.5: - resolution: {integrity: sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==} + /@emotion/unitless@0.8.1: + resolution: {integrity: sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==} dev: false - /@emotion/utils@1.1.0: - resolution: {integrity: sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ==} + /@emotion/use-insertion-effect-with-fallbacks@1.0.1(react@18.2.0): + resolution: {integrity: sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==} + peerDependencies: + react: '>=16.8.0' + dependencies: + react: 18.2.0 dev: false - /@emotion/weak-memoize@0.2.5: - resolution: {integrity: sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==} + /@emotion/utils@1.2.1: + resolution: {integrity: sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==} dev: false - /@eslint/eslintrc@1.3.0: - resolution: {integrity: sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==} + /@emotion/weak-memoize@0.3.1: + resolution: {integrity: sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==} + dev: false + + /@eslint-community/eslint-utils@4.4.0(eslint@8.47.0): + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + dependencies: + eslint: 8.47.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /@eslint-community/regexpp@4.7.0: + resolution: {integrity: sha512-+HencqxU7CFJnQb7IKtuNBqS6Yx3Tz4kOL8BJXo+JyeiBm5MEX6pO8onXDkjrkCRlfYXS1Axro15ZjVFe9YgsA==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + dev: true + + /@eslint/eslintrc@2.1.2: + resolution: {integrity: sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: ajv: 6.12.6 debug: 4.3.4 - espree: 9.3.2 - globals: 13.16.0 + espree: 9.6.1 + globals: 13.21.0 ignore: 5.2.0 import-fresh: 3.3.0 js-yaml: 4.1.0 @@ -1254,8 +1563,13 @@ packages: - supports-color dev: true - /@humanwhocodes/config-array@0.9.5: - resolution: {integrity: sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==} + /@eslint/js@8.47.0: + resolution: {integrity: sha512-P6omY1zv5MItm93kLM8s2vr1HICJH8v0dvddDhysbIuZ+vcjOHg5Zbkf1mTkcmi2JA9oBG2anOkRnW8WJTS8Og==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /@humanwhocodes/config-array@0.11.10: + resolution: {integrity: sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==} engines: {node: '>=10.10.0'} dependencies: '@humanwhocodes/object-schema': 1.2.1 @@ -1265,6 +1579,11 @@ packages: - supports-color dev: true + /@humanwhocodes/module-importer@1.0.1: + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + dev: true + /@humanwhocodes/object-schema@1.2.1: resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} dev: true @@ -1283,7 +1602,7 @@ packages: dependencies: '@jridgewell/set-array': 1.1.2 '@jridgewell/sourcemap-codec': 1.4.14 - '@jridgewell/trace-mapping': 0.3.14 + '@jridgewell/trace-mapping': 0.3.19 dev: false /@jridgewell/resolve-uri@3.1.0: @@ -1307,83 +1626,25 @@ packages: '@jridgewell/sourcemap-codec': 1.4.14 dev: false - /@motionone/animation@10.12.0: - resolution: {integrity: sha512-SCWkVjMChQwA4Cnt1pdmhCi0OC4cAR+rqsskNEqmbgfG59zmn50TfOP6vgqjkYbaSZXXLeEb03Mez362jIEHRg==} + /@jridgewell/trace-mapping@0.3.19: + resolution: {integrity: sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==} dependencies: - '@motionone/easing': 10.12.0 - '@motionone/types': 10.12.0 - '@motionone/utils': 10.12.0 - tslib: 2.4.0 + '@jridgewell/resolve-uri': 3.1.0 + '@jridgewell/sourcemap-codec': 1.4.14 dev: false - /@motionone/dom@10.12.0: - resolution: {integrity: sha512-UdPTtLMAktHiqV0atOczNYyDd/d8Cf5fFsd1tua03PqTwwCe/6lwhLSQ8a7TbnQ5SN0gm44N1slBfj+ORIhrqw==} - dependencies: - '@motionone/animation': 10.12.0 - '@motionone/generators': 10.12.0 - '@motionone/types': 10.12.0 - '@motionone/utils': 10.12.0 - hey-listen: 1.0.8 - tslib: 2.4.0 + /@next/env@13.4.19: + resolution: {integrity: sha512-FsAT5x0jF2kkhNkKkukhsyYOrRqtSxrEhfliniIq0bwWbuXLgyt3Gv0Ml+b91XwjwArmuP7NxCiGd++GGKdNMQ==} dev: false - /@motionone/easing@10.12.0: - resolution: {integrity: sha512-kdwcn1ja/0//BBHRElX3In1yfqMEhqUoL3G0njDan8R+gfPy3DanyuCtio4VruHQ1m3XN3LcrqavbClzcGo7IA==} - dependencies: - '@motionone/utils': 10.12.0 - tslib: 2.4.0 - dev: false - - /@motionone/generators@10.12.0: - resolution: {integrity: sha512-QM8/ndOve80HLXImChwW8ogrEM/8m9xzZEl2Ci2ep1uGLAQ+ADiwzKtl11inGESrxiFDrUdD12WXacCn+y172Q==} - dependencies: - '@motionone/types': 10.12.0 - '@motionone/utils': 10.12.0 - tslib: 2.4.0 - dev: false - - /@motionone/types@10.12.0: - resolution: {integrity: sha512-D9k7ijkAT6JJOCMUVn9IgJqWolp7N3oBbWRQTIRGGO41Bmr/JzLv4GzAb00PvkYAzZX+BpnSTKqXI19zrSjC5w==} - dev: false - - /@motionone/utils@10.12.0: - resolution: {integrity: sha512-2g3tCqYYwb/tgzCDRbILbD5edXJB45HV51NbnhwKVOOl0PhFraRDtehzLKo9wLHdaTnO/IjVn6cHQsw6RjdolA==} - dependencies: - '@motionone/types': 10.12.0 - hey-listen: 1.0.8 - tslib: 2.4.0 - dev: false - - /@next/env@12.2.2: - resolution: {integrity: sha512-BqDwE4gDl1F608TpnNxZqrCn6g48MBjvmWFEmeX5wEXDXh3IkAOw6ASKUgjT8H4OUePYFqghDFUss5ZhnbOUjw==} - dev: false - - /@next/eslint-plugin-next@12.2.2: - resolution: {integrity: sha512-XOi0WzJhGH3Lk51SkSu9eZxF+IY1ZZhWcJTIGBycAbWU877IQa6+6KxMATWCOs7c+bmp6Sd8KywXJaDRxzu0JA==} + /@next/eslint-plugin-next@13.4.19: + resolution: {integrity: sha512-N/O+zGb6wZQdwu6atMZHbR7T9Np5SUFUjZqCbj0sXm+MwQO35M8TazVB4otm87GkXYs2l6OPwARd3/PUWhZBVQ==} dependencies: glob: 7.1.7 dev: true - /@next/swc-android-arm-eabi@12.2.2: - resolution: {integrity: sha512-VHjuCHeq9qCprUZbsRxxM/VqSW8MmsUtqB5nEpGEgUNnQi/BTm/2aK8tl7R4D0twGKRh6g1AAeFuWtXzk9Z/vQ==} - engines: {node: '>= 10'} - cpu: [arm] - os: [android] - requiresBuild: true - dev: false - optional: true - - /@next/swc-android-arm64@12.2.2: - resolution: {integrity: sha512-v5EYzXUOSv0r9mO/2PX6mOcF53k8ndlu9yeFHVAWW1Dhw2jaJcvTRcCAwYYN8Q3tDg0nH3NbEltJDLKmcJOuVA==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [android] - requiresBuild: true - dev: false - optional: true - - /@next/swc-darwin-arm64@12.2.2: - resolution: {integrity: sha512-JCoGySHKGt+YBk7xRTFGx1QjrnCcwYxIo3yGepcOq64MoiocTM3yllQWeOAJU2/k9MH0+B5E9WUSme4rOCBbpA==} + /@next/swc-darwin-arm64@13.4.19: + resolution: {integrity: sha512-vv1qrjXeGbuF2mOkhkdxMDtv9np7W4mcBtaDnHU+yJG+bBwa6rYsYSCI/9Xm5+TuF5SbZbrWO6G1NfTh1TMjvQ==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] @@ -1391,8 +1652,8 @@ packages: dev: false optional: true - /@next/swc-darwin-x64@12.2.2: - resolution: {integrity: sha512-dztDtvfkhUqiqpXvrWVccfGhLe44yQ5tQ7B4tBfnsOR6vxzI9DNPHTlEOgRN9qDqTAcFyPxvg86mn4l8bB9Jcw==} + /@next/swc-darwin-x64@13.4.19: + resolution: {integrity: sha512-jyzO6wwYhx6F+7gD8ddZfuqO4TtpJdw3wyOduR4fxTUCm3aLw7YmHGYNjS0xRSYGAkLpBkH1E0RcelyId6lNsw==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] @@ -1400,26 +1661,8 @@ packages: dev: false optional: true - /@next/swc-freebsd-x64@12.2.2: - resolution: {integrity: sha512-JUnXB+2xfxqsAvhFLPJpU1NeyDsvJrKoOjpV7g3Dxbno2Riu4tDKn3kKF886yleAuD/1qNTUCpqubTvbbT2VoA==} - engines: {node: '>= 10'} - cpu: [x64] - os: [freebsd] - requiresBuild: true - dev: false - optional: true - - /@next/swc-linux-arm-gnueabihf@12.2.2: - resolution: {integrity: sha512-XeYC/qqPLz58R4pjkb+x8sUUxuGLnx9QruC7/IGkK68yW4G17PHwKI/1njFYVfXTXUukpWjcfBuauWwxp9ke7Q==} - engines: {node: '>= 10'} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: false - optional: true - - /@next/swc-linux-arm64-gnu@12.2.2: - resolution: {integrity: sha512-d6jT8xgfKYFkzR7J0OHo2D+kFvY/6W8qEo6/hmdrTt6AKAqxs//rbbcdoyn3YQq1x6FVUUd39zzpezZntg9Naw==} + /@next/swc-linux-arm64-gnu@13.4.19: + resolution: {integrity: sha512-vdlnIlaAEh6H+G6HrKZB9c2zJKnpPVKnA6LBwjwT2BTjxI7e0Hx30+FoWCgi50e+YO49p6oPOtesP9mXDRiiUg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -1427,8 +1670,8 @@ packages: dev: false optional: true - /@next/swc-linux-arm64-musl@12.2.2: - resolution: {integrity: sha512-rIZRFxI9N/502auJT1i7coas0HTHUM+HaXMyJiCpnY8Rimbo0495ir24tzzHo3nQqJwcflcPTwEh/DV17sdv9A==} + /@next/swc-linux-arm64-musl@13.4.19: + resolution: {integrity: sha512-aU0HkH2XPgxqrbNRBFb3si9Ahu/CpaR5RPmN2s9GiM9qJCiBBlZtRTiEca+DC+xRPyCThTtWYgxjWHgU7ZkyvA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -1436,8 +1679,8 @@ packages: dev: false optional: true - /@next/swc-linux-x64-gnu@12.2.2: - resolution: {integrity: sha512-ir1vNadlUDj7eQk15AvfhG5BjVizuCHks9uZwBfUgT5jyeDCeRvaDCo1+Q6+0CLOAnYDR/nqSCvBgzG2UdFh9A==} + /@next/swc-linux-x64-gnu@13.4.19: + resolution: {integrity: sha512-htwOEagMa/CXNykFFeAHHvMJeqZfNQEoQvHfsA4wgg5QqGNqD5soeCer4oGlCol6NGUxknrQO6VEustcv+Md+g==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -1445,8 +1688,8 @@ packages: dev: false optional: true - /@next/swc-linux-x64-musl@12.2.2: - resolution: {integrity: sha512-bte5n2GzLN3O8JdSFYWZzMgEgDHZmRz5wiispiiDssj4ik3l8E7wq/czNi8RmIF+ioj2sYVokUNa/ekLzrESWw==} + /@next/swc-linux-x64-musl@13.4.19: + resolution: {integrity: sha512-4Gj4vvtbK1JH8ApWTT214b3GwUh9EKKQjY41hH/t+u55Knxi/0wesMzwQRhppK6Ddalhu0TEttbiJ+wRcoEj5Q==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -1454,8 +1697,8 @@ packages: dev: false optional: true - /@next/swc-win32-arm64-msvc@12.2.2: - resolution: {integrity: sha512-ZUGCmcDmdPVSAlwJ/aD+1F9lYW8vttseiv4n2+VCDv5JloxiX9aY32kYZaJJO7hmTLNrprvXkb4OvNuHdN22Jg==} + /@next/swc-win32-arm64-msvc@13.4.19: + resolution: {integrity: sha512-bUfDevQK4NsIAHXs3/JNgnvEY+LRyneDN788W2NYiRIIzmILjba7LaQTfihuFawZDhRtkYCv3JDC3B4TwnmRJw==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] @@ -1463,8 +1706,8 @@ packages: dev: false optional: true - /@next/swc-win32-ia32-msvc@12.2.2: - resolution: {integrity: sha512-v7ykeEDbr9eXiblGSZiEYYkWoig6sRhAbLKHUHQtk8vEWWVEqeXFcxmw6LRrKu5rCN1DY357UlYWToCGPQPCRA==} + /@next/swc-win32-ia32-msvc@13.4.19: + resolution: {integrity: sha512-Y5kikILFAr81LYIFaw6j/NrOtmiM4Sf3GtOc0pn50ez2GCkr+oejYuKGcwAwq3jiTKuzF6OF4iT2INPoxRycEA==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] @@ -1472,8 +1715,8 @@ packages: dev: false optional: true - /@next/swc-win32-x64-msvc@12.2.2: - resolution: {integrity: sha512-2D2iinWUL6xx8D9LYVZ5qi7FP6uLAoWymt8m8aaG2Ld/Ka8/k723fJfiklfuAcwOxfufPJI+nRbT5VcgHGzHAQ==} + /@next/swc-win32-x64-msvc@13.4.19: + resolution: {integrity: sha512-YzA78jBDXMYiINdPdJJwGgPNT3YqBNNGhsthsDoWHL9p24tEJn9ViQf/ZqTbwSpX/RrkPupLfuuTH2sf73JBAw==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -1502,120 +1745,109 @@ packages: fastq: 1.13.0 dev: true - /@octokit/auth-token@3.0.0: - resolution: {integrity: sha512-MDNFUBcJIptB9At7HiV7VCvU3NcL4GnfCQaP8C5lrxWrRPMJBnemYtehaKSOlaM7AYxeRyj9etenu8LVpSpVaQ==} - engines: {node: '>= 14'} - dependencies: - '@octokit/types': 6.40.0 + /@octokit/auth-token@4.0.0: + resolution: {integrity: sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==} + engines: {node: '>= 18'} dev: false - /@octokit/core@4.0.4: - resolution: {integrity: sha512-sUpR/hc4Gc7K34o60bWC7WUH6Q7T6ftZ2dUmepSyJr9PRF76/qqkWjE2SOEzCqLA5W83SaISymwKtxks+96hPQ==} - engines: {node: '>= 14'} + /@octokit/core@5.0.0: + resolution: {integrity: sha512-YbAtMWIrbZ9FCXbLwT9wWB8TyLjq9mxpKdgB3dUNxQcIVTf9hJ70gRPwAcqGZdY6WdJPZ0I7jLaaNDCiloGN2A==} + engines: {node: '>= 18'} dependencies: - '@octokit/auth-token': 3.0.0 - '@octokit/graphql': 5.0.0 - '@octokit/request': 6.2.0 - '@octokit/request-error': 3.0.0 - '@octokit/types': 6.40.0 + '@octokit/auth-token': 4.0.0 + '@octokit/graphql': 7.0.1 + '@octokit/request': 8.1.1 + '@octokit/request-error': 5.0.0 + '@octokit/types': 11.1.0 before-after-hook: 2.2.2 universal-user-agent: 6.0.0 - transitivePeerDependencies: - - encoding dev: false - /@octokit/endpoint@7.0.0: - resolution: {integrity: sha512-Kz/mIkOTjs9rV50hf/JK9pIDl4aGwAtT8pry6Rpy+hVXkAPhXanNQRxMoq6AeRgDCZR6t/A1zKniY2V1YhrzlQ==} - engines: {node: '>= 14'} + /@octokit/endpoint@9.0.0: + resolution: {integrity: sha512-szrQhiqJ88gghWY2Htt8MqUDO6++E/EIXqJ2ZEp5ma3uGS46o7LZAzSLt49myB7rT+Hfw5Y6gO3LmOxGzHijAQ==} + engines: {node: '>= 18'} dependencies: - '@octokit/types': 6.40.0 + '@octokit/types': 11.1.0 is-plain-object: 5.0.0 universal-user-agent: 6.0.0 dev: false - /@octokit/graphql@5.0.0: - resolution: {integrity: sha512-1ZZ8tX4lUEcLPvHagfIVu5S2xpHYXAmgN0+95eAOPoaVPzCfUXJtA5vASafcpWcO86ze0Pzn30TAx72aB2aguQ==} - engines: {node: '>= 14'} + /@octokit/graphql@7.0.1: + resolution: {integrity: sha512-T5S3oZ1JOE58gom6MIcrgwZXzTaxRnxBso58xhozxHpOqSTgDS6YNeEUvZ/kRvXgPrRz/KHnZhtb7jUMRi9E6w==} + engines: {node: '>= 18'} dependencies: - '@octokit/request': 6.2.0 - '@octokit/types': 6.40.0 + '@octokit/request': 8.1.1 + '@octokit/types': 11.1.0 universal-user-agent: 6.0.0 - transitivePeerDependencies: - - encoding dev: false - /@octokit/openapi-types@12.10.0: - resolution: {integrity: sha512-xsgA7LKuQ/2QReMZQXNlBP68ferPlqw66Jmx5/J399Cn5EgIDaHXou6Rgn1GkpDNjkPji67fTlC2rz6ABaVFKw==} + /@octokit/openapi-types@18.0.0: + resolution: {integrity: sha512-V8GImKs3TeQRxRtXFpG2wl19V7444NIOTDF24AWuIbmNaNYOQMWRbjcGDXV5B+0n887fgDcuMNOmlul+k+oJtw==} dev: false - /@octokit/plugin-paginate-rest@3.0.0(@octokit/core@4.0.4): - resolution: {integrity: sha512-fvw0Q5IXnn60D32sKeLIxgXCEZ7BTSAjJd8cFAE6QU5qUp0xo7LjFUjjX1J5D7HgN355CN4EXE4+Q1/96JaNUA==} - engines: {node: '>= 14'} + /@octokit/plugin-paginate-rest@8.0.0(@octokit/core@5.0.0): + resolution: {integrity: sha512-2xZ+baZWUg+qudVXnnvXz7qfrTmDeYPCzangBVq/1gXxii/OiS//4shJp9dnCCvj1x+JAm9ji1Egwm1BA47lPQ==} + engines: {node: '>= 18'} peerDependencies: - '@octokit/core': '>=4' + '@octokit/core': '>=5' dependencies: - '@octokit/core': 4.0.4 - '@octokit/types': 6.40.0 + '@octokit/core': 5.0.0 + '@octokit/types': 11.1.0 dev: false - /@octokit/plugin-request-log@1.0.4(@octokit/core@4.0.4): - resolution: {integrity: sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==} + /@octokit/plugin-request-log@4.0.0(@octokit/core@5.0.0): + resolution: {integrity: sha512-2uJI1COtYCq8Z4yNSnM231TgH50bRkheQ9+aH8TnZanB6QilOnx8RMD2qsnamSOXtDj0ilxvevf5fGsBhBBzKA==} + engines: {node: '>= 18'} peerDependencies: - '@octokit/core': '>=3' + '@octokit/core': '>=5' dependencies: - '@octokit/core': 4.0.4 + '@octokit/core': 5.0.0 dev: false - /@octokit/plugin-rest-endpoint-methods@6.1.0(@octokit/core@4.0.4): - resolution: {integrity: sha512-gP/yHUY0k/uKkEqXF6tZGRhCFqZNjQ0qdh9/gVo74AJ2pc3cr1rjnW/KRw1uXUKB/H9Y0rRBCBxsLXJmQjPv3A==} - engines: {node: '>= 14'} + /@octokit/plugin-rest-endpoint-methods@9.0.0(@octokit/core@5.0.0): + resolution: {integrity: sha512-KquMF/VB1IkKNiVnzJKspY5mFgGyLd7HzdJfVEGTJFzqu9BRFNWt+nwTCMuUiWc72gLQhRWYubTwOkQj+w/1PA==} + engines: {node: '>= 18'} peerDependencies: - '@octokit/core': '>=3' + '@octokit/core': '>=5' dependencies: - '@octokit/core': 4.0.4 - '@octokit/types': 6.40.0 - deprecation: 2.3.1 + '@octokit/core': 5.0.0 + '@octokit/types': 11.1.0 dev: false - /@octokit/request-error@3.0.0: - resolution: {integrity: sha512-WBtpzm9lR8z4IHIMtOqr6XwfkGvMOOILNLxsWvDwtzm/n7f5AWuqJTXQXdDtOvPfTDrH4TPhEvW2qMlR4JFA2w==} - engines: {node: '>= 14'} + /@octokit/request-error@5.0.0: + resolution: {integrity: sha512-1ue0DH0Lif5iEqT52+Rf/hf0RmGO9NWFjrzmrkArpG9trFfDM/efx00BJHdLGuro4BR/gECxCU2Twf5OKrRFsQ==} + engines: {node: '>= 18'} dependencies: - '@octokit/types': 6.40.0 + '@octokit/types': 11.1.0 deprecation: 2.3.1 once: 1.4.0 dev: false - /@octokit/request@6.2.0: - resolution: {integrity: sha512-7IAmHnaezZrgUqtRShMlByJK33MT9ZDnMRgZjnRrRV9a/jzzFwKGz0vxhFU6i7VMLraYcQ1qmcAOin37Kryq+Q==} - engines: {node: '>= 14'} + /@octokit/request@8.1.1: + resolution: {integrity: sha512-8N+tdUz4aCqQmXl8FpHYfKG9GelDFd7XGVzyN8rc6WxVlYcfpHECnuRkgquzz+WzvHTK62co5di8gSXnzASZPQ==} + engines: {node: '>= 18'} dependencies: - '@octokit/endpoint': 7.0.0 - '@octokit/request-error': 3.0.0 - '@octokit/types': 6.40.0 + '@octokit/endpoint': 9.0.0 + '@octokit/request-error': 5.0.0 + '@octokit/types': 11.1.0 is-plain-object: 5.0.0 - node-fetch: 2.6.7 universal-user-agent: 6.0.0 - transitivePeerDependencies: - - encoding dev: false - /@octokit/rest@19.0.3: - resolution: {integrity: sha512-5arkTsnnRT7/sbI4fqgSJ35KiFaN7zQm0uQiQtivNQLI8RQx8EHwJCajcTUwmaCMNDg7tdCvqAnc7uvHHPxrtQ==} - engines: {node: '>= 14'} + /@octokit/rest@20.0.1: + resolution: {integrity: sha512-wROV21RwHQIMNb2Dgd4+pY+dVy1Dwmp85pBrgr6YRRDYRBu9Gb+D73f4Bl2EukZSj5hInq2Tui9o7gAQpc2k2Q==} + engines: {node: '>= 18'} dependencies: - '@octokit/core': 4.0.4 - '@octokit/plugin-paginate-rest': 3.0.0(@octokit/core@4.0.4) - '@octokit/plugin-request-log': 1.0.4(@octokit/core@4.0.4) - '@octokit/plugin-rest-endpoint-methods': 6.1.0(@octokit/core@4.0.4) - transitivePeerDependencies: - - encoding + '@octokit/core': 5.0.0 + '@octokit/plugin-paginate-rest': 8.0.0(@octokit/core@5.0.0) + '@octokit/plugin-request-log': 4.0.0(@octokit/core@5.0.0) + '@octokit/plugin-rest-endpoint-methods': 9.0.0(@octokit/core@5.0.0) dev: false - /@octokit/types@6.40.0: - resolution: {integrity: sha512-MFZOU5r8SwgJWDMhrLUSvyJPtVsqA6VnbVI3TNbsmw+Jnvrktzvq2fYES/6RiJA/5Ykdwq4mJmtlYUfW7CGjmw==} + /@octokit/types@11.1.0: + resolution: {integrity: sha512-Fz0+7GyLm/bHt8fwEqgvRBWwIV1S6wRRyq+V6exRKLVWaKGsuy6H9QFYeBVDV7rK6fO3XwHgQOPxv+cLj2zpXQ==} dependencies: - '@octokit/openapi-types': 12.10.0 + '@octokit/openapi-types': 18.0.0 dev: false /@popperjs/core@2.11.5: @@ -1626,8 +1858,8 @@ packages: resolution: {integrity: sha512-LwzQKA4vzIct1zNZzBmRKI9QuNpLgTQMEjsQLf3BXuGYb3QPTP4Yjf6mkdX+X1mYttZ808QpOwAzZjv28kq7DA==} dev: true - /@swc/helpers@0.4.2: - resolution: {integrity: sha512-556Az0VX7WR6UdoTn4htt/l3zPQ7bsQWK+HqdG4swV7beUCxo/BqmvbOpUkTIm/9ih86LIf1qsUnywNL3obGHw==} + /@swc/helpers@0.5.1: + resolution: {integrity: sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==} dependencies: tslib: 2.4.0 dev: false @@ -1648,8 +1880,8 @@ packages: resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} dev: true - /@types/lodash.mergewith@4.6.6: - resolution: {integrity: sha512-RY/8IaVENjG19rxTZu9Nukqh0W2UrYgmBj5sdns4hWRZaV8PqR7wIKHFKzvOTjo4zVRV7sVI+yFhAJql12Kfqg==} + /@types/lodash.mergewith@4.6.7: + resolution: {integrity: sha512-3m+lkO5CLRRYU0fhGRp7zbsGi6+BZj0uTVSwvcKU+nSlhjA9/QRNfuSGnD2mX6hQA7ZbmcCkzk5h4ZYGOtk14A==} dependencies: '@types/lodash': 4.14.182 dev: false @@ -1672,8 +1904,12 @@ packages: resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==} dev: false - /@types/node@18.0.5: - resolution: {integrity: sha512-En7tneq+j0qAiVwysBD79y86MT3ModuoIJbe7JXp+sb5UAjInSShmK3nXXMioBzfF7rXC12hv12d4IyCVwN4dA==} + /@types/node@20.5.3: + resolution: {integrity: sha512-ITI7rbWczR8a/S6qjAW7DMqxqFMjjTo61qZVWJ1ubPvbIQsL5D/TvwjYEalM8Kthpe3hTzOGrF2TGbAu2uyqeA==} + + /@types/nprogress@0.2.0: + resolution: {integrity: sha512-1cYJrqq9GezNFPsWTZpFut/d4CjpZqA0vhqDUPFWYKF1oIyBz5qnoYMzR+0C/T96t3ebLAC1SSnwrVOm5/j74A==} + dev: false /@types/parse-json@4.0.0: resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==} @@ -1682,26 +1918,26 @@ packages: /@types/progress@2.0.5: resolution: {integrity: sha512-ZYYVc/kSMkhH9W/4dNK/sLNra3cnkfT2nJyOAIDY+C2u6w72wa0s1aXAezVtbTsnN8HID1uhXCrLwDE2ZXpplg==} dependencies: - '@types/node': 18.0.5 + '@types/node': 20.5.3 dev: false /@types/prop-types@15.7.5: resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==} - /@types/react-dom@18.0.6: - resolution: {integrity: sha512-/5OFZgfIPSwy+YuIBP/FgJnQnsxhZhjjrnxudMddeblOouIodEQ75X14Rr4wGSG/bknL+Omy9iWlLo1u/9GzAA==} + /@types/react-dom@18.2.7: + resolution: {integrity: sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA==} dependencies: - '@types/react': 18.0.15 + '@types/react': 18.2.21 dev: true - /@types/react-syntax-highlighter@15.5.3: - resolution: {integrity: sha512-N5bgZxolo+wFuYnx4nOvIQO2P0E+KYHt3dDwb8ydUvZ96QN8Lpq60ReT+0W0JmXKZjp4udkYkIDYt9GIygBY1Q==} + /@types/react-syntax-highlighter@15.5.7: + resolution: {integrity: sha512-bo5fEO5toQeyCp0zVHBeggclqf5SQ/Z5blfFmjwO5dkMVGPgmiwZsJh9nu/Bo5L7IHTuGWrja6LxJVE2uB5ZrQ==} dependencies: - '@types/react': 18.0.15 + '@types/react': 18.2.21 dev: true - /@types/react@18.0.15: - resolution: {integrity: sha512-iz3BtLuIYH1uWdsv6wXYdhozhqj20oD4/Hk2DNXIn1kFsmp9x8d9QB6FnPhfkbhd2PgEONt9Q1x/ebkwjfFLow==} + /@types/react@18.2.21: + resolution: {integrity: sha512-neFKG/sBAwGxHgXiIxnbm3/AAVQ/cMRS93hvBpg8xYRbeQSPVABp9U2bRnPf0iI4+Ucdv3plSxKK+3CW2ENJxA==} dependencies: '@types/prop-types': 15.7.5 '@types/scheduler': 0.16.2 @@ -1714,7 +1950,7 @@ packages: resolution: {integrity: sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==} dev: false - /@typescript-eslint/parser@5.30.6(eslint@8.20.0)(typescript@4.7.4): + /@typescript-eslint/parser@5.30.6(eslint@8.47.0)(typescript@5.1.6): resolution: {integrity: sha512-gfF9lZjT0p2ZSdxO70Xbw8w9sPPJGfAdjK7WikEjB3fcUI/yr9maUVEdqigBjKincUYNKOmf7QBMiTf719kbrA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -1726,10 +1962,10 @@ packages: dependencies: '@typescript-eslint/scope-manager': 5.30.6 '@typescript-eslint/types': 5.30.6 - '@typescript-eslint/typescript-estree': 5.30.6(typescript@4.7.4) + '@typescript-eslint/typescript-estree': 5.30.6(typescript@5.1.6) debug: 4.3.4 - eslint: 8.20.0 - typescript: 4.7.4 + eslint: 8.47.0 + typescript: 5.1.6 transitivePeerDependencies: - supports-color dev: true @@ -1747,7 +1983,7 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@typescript-eslint/typescript-estree@5.30.6(typescript@4.7.4): + /@typescript-eslint/typescript-estree@5.30.6(typescript@5.1.6): resolution: {integrity: sha512-Z7TgPoeYUm06smfEfYF0RBkpF8csMyVnqQbLYiGgmUSTaSXTP57bt8f0UFXstbGxKIreTwQCujtaH0LY9w9B+A==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -1762,8 +1998,8 @@ packages: globby: 11.1.0 is-glob: 4.0.3 semver: 7.3.7 - tsutils: 3.21.0(typescript@4.7.4) - typescript: 4.7.4 + tsutils: 3.21.0(typescript@5.1.6) + typescript: 5.1.6 transitivePeerDependencies: - supports-color dev: true @@ -1773,23 +2009,33 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: '@typescript-eslint/types': 5.30.6 - eslint-visitor-keys: 3.3.0 + eslint-visitor-keys: 3.4.3 dev: true - /@zag-js/focus-visible@0.1.0: - resolution: {integrity: sha512-PeaBcTmdZWcFf7n1aM+oiOdZc+sy14qi0emPIeUuGMTjbP0xLGrZu43kdpHnWSXy7/r4Ubp/vlg50MCV8+9Isg==} + /@zag-js/dom-query@0.10.5: + resolution: {integrity: sha512-zm6wA5+kqU48it6afNjaUhjVSixKZruTKB23z0V1xBqKbuiLOMMOZ5oK26cTPSXtZ5CPhDNZ2Qk4pliS5n9SVw==} dev: false - /acorn-jsx@5.3.2(acorn@8.7.1): + /@zag-js/element-size@0.10.5: + resolution: {integrity: sha512-uQre5IidULANvVkNOBQ1tfgwTQcGl4hliPSe69Fct1VfYb2Fd0jdAcGzqQgPhfrXFpR62MxLPB7erxJ/ngtL8w==} + dev: false + + /@zag-js/focus-visible@0.10.5: + resolution: {integrity: sha512-EhDHKLutMtvLFCjBjyIY6h1JoJJNXG3KJz7Dj1sh4tj4LWAqo/TqLvgHyUTB29XMHwoslFHDJHKVWmLGMi+ULQ==} + dependencies: + '@zag-js/dom-query': 0.10.5 + dev: false + + /acorn-jsx@5.3.2(acorn@8.10.0): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - acorn: 8.7.1 + acorn: 8.10.0 dev: true - /acorn@8.7.1: - resolution: {integrity: sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==} + /acorn@8.10.0: + resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==} engines: {node: '>=0.4.0'} hasBin: true dev: true @@ -1832,11 +2078,11 @@ packages: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} dev: true - /aria-hidden@1.1.3: - resolution: {integrity: sha512-RhVWFtKH5BiGMycI72q2RAFMLQi8JP9bLuQXgR5a8Znp7P5KOIADSJeyfI8PCVxLEp067B2HbP5JIiI/PXIZeA==} - engines: {node: '>=8.5.0'} + /aria-hidden@1.2.3: + resolution: {integrity: sha512-xcLxITLe2HYa1cnYnwCjkOO1PqUHQpozB8x9AR0OgWN2woOBi5kSDVxKfd0b7sb1hw5qFeJhXm9H1nu3xSfLeQ==} + engines: {node: '>=10'} dependencies: - tslib: 1.14.1 + tslib: 2.4.0 dev: false /aria-query@4.2.2: @@ -1847,14 +2093,32 @@ packages: '@babel/runtime-corejs3': 7.18.6 dev: true + /array-buffer-byte-length@1.0.0: + resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} + dependencies: + call-bind: 1.0.2 + is-array-buffer: 3.0.2 + dev: true + /array-includes@3.1.5: resolution: {integrity: sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.2 define-properties: 1.1.4 - es-abstract: 1.20.1 - get-intrinsic: 1.1.2 + es-abstract: 1.22.1 + get-intrinsic: 1.2.1 + is-string: 1.0.7 + dev: true + + /array-includes@3.1.6: + resolution: {integrity: sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.22.1 + get-intrinsic: 1.2.1 is-string: 1.0.7 dev: true @@ -1869,24 +2133,57 @@ packages: dependencies: call-bind: 1.0.2 define-properties: 1.1.4 - es-abstract: 1.20.1 + es-abstract: 1.22.1 es-shim-unscopables: 1.0.0 dev: true - /array.prototype.flatmap@1.3.0: - resolution: {integrity: sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg==} + /array.prototype.flatmap@1.3.1: + resolution: {integrity: sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.2 define-properties: 1.1.4 - es-abstract: 1.20.1 + es-abstract: 1.22.1 es-shim-unscopables: 1.0.0 dev: true + /array.prototype.tosorted@1.1.1: + resolution: {integrity: sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==} + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.22.1 + es-shim-unscopables: 1.0.0 + get-intrinsic: 1.2.1 + dev: true + + /arraybuffer.prototype.slice@1.0.1: + resolution: {integrity: sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.0 + call-bind: 1.0.2 + define-properties: 1.2.0 + get-intrinsic: 1.2.1 + is-array-buffer: 3.0.2 + is-shared-array-buffer: 1.0.2 + dev: true + /ast-types-flow@0.0.7: resolution: {integrity: sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==} dev: true + /asynciterator.prototype@1.0.0: + resolution: {integrity: sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==} + dependencies: + has-symbols: 1.0.3 + dev: true + + /available-typed-arrays@1.0.5: + resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} + engines: {node: '>= 0.4'} + dev: true + /axe-core@4.4.3: resolution: {integrity: sha512-32+ub6kkdhhWick/UjvEwRchgoetXqTK14INLqbGm5U2TzBkBNF3nQtLYm8ovxSkQWArjEQvftCKryjZaATu3w==} engines: {node: '>=4'} @@ -1896,11 +2193,12 @@ packages: resolution: {integrity: sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==} dev: true - /babel-plugin-macros@2.8.0: - resolution: {integrity: sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==} + /babel-plugin-macros@3.1.0: + resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} + engines: {node: '>=10', npm: '>=6'} dependencies: '@babel/runtime': 7.18.6 - cosmiconfig: 6.0.0 + cosmiconfig: 7.1.0 resolve: 1.22.1 dev: false @@ -1930,30 +2228,37 @@ packages: fill-range: 7.0.1 dev: true - /browserslist@4.21.2: - resolution: {integrity: sha512-MonuOgAtUB46uP5CezYbRaYKBNt2LxP0yX+Pmj4LkcDFGkn9Cbpi83d9sCjwQDErXsIJSzY5oKGDbgOlF/LPAA==} + /browserslist@4.21.10: + resolution: {integrity: sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001367 - electron-to-chromium: 1.4.192 - node-releases: 2.0.6 - update-browserslist-db: 1.0.4(browserslist@4.21.2) + caniuse-lite: 1.0.30001522 + electron-to-chromium: 1.4.499 + node-releases: 2.0.13 + update-browserslist-db: 1.0.11(browserslist@4.21.10) + dev: false + + /busboy@1.6.0: + resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} + engines: {node: '>=10.16.0'} + dependencies: + streamsearch: 1.1.0 dev: false /call-bind@1.0.2: resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} dependencies: function-bind: 1.1.1 - get-intrinsic: 1.1.2 + get-intrinsic: 1.2.1 dev: true /callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - /caniuse-lite@1.0.30001367: - resolution: {integrity: sha512-XDgbeOHfifWV3GEES2B8rtsrADx4Jf+juKX2SICJcaUhjYBO3bR96kvEIHa15VU6ohtOhBZuPGGYGbXMRn0NCw==} + /caniuse-lite@1.0.30001522: + resolution: {integrity: sha512-TKiyTVZxJGhsTszLuzb+6vUZSjVOAhClszBr2Ta2k9IwtNBT/4dzmL6aywt0HCgEZlmwJzXJd8yNiob6HgwTRg==} dev: false /ccount@2.0.1: @@ -1981,6 +2286,10 @@ packages: resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} dev: false + /client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + dev: false + /color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} dependencies: @@ -2002,12 +2311,16 @@ packages: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} dev: true + /color2k@2.0.2: + resolution: {integrity: sha512-kJhwH5nAwb34tmyuqq/lgjEKzlFXn1U99NlnB6Ws4qVaERcRUYeYP1cBw6BJ4vxaWStAUEef4WMr7WjOCnBt8w==} + dev: false + /comma-separated-tokens@2.0.2: resolution: {integrity: sha512-G5yTt3KQN4Yn7Yk4ed73hlZ1evrFKXeUW3086p3PRFNp7m2vIjI6Pg+Kgb+oyzhd9F2qdcoj67+y3SdxL5XWsg==} dev: false - /compute-scroll-into-view@1.0.14: - resolution: {integrity: sha512-mKDjINe3tc6hGelUMNDzuhorIUZ7kS7BwyY0r2wQd2HOH2tRuJykiC06iSEX8y1TuhNzvz4GcJnK16mM2J1NMQ==} + /compute-scroll-into-view@1.0.20: + resolution: {integrity: sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==} dev: false /concat-map@0.0.1: @@ -2020,8 +2333,8 @@ packages: safe-buffer: 5.1.2 dev: false - /copy-to-clipboard@3.3.1: - resolution: {integrity: sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw==} + /copy-to-clipboard@3.3.3: + resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==} dependencies: toggle-selection: 1.0.6 dev: false @@ -2031,9 +2344,9 @@ packages: requiresBuild: true dev: true - /cosmiconfig@6.0.0: - resolution: {integrity: sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==} - engines: {node: '>=8'} + /cosmiconfig@7.1.0: + resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} + engines: {node: '>=10'} dependencies: '@types/parse-json': 4.0.0 import-fresh: 3.3.0 @@ -2115,6 +2428,14 @@ packages: object-keys: 1.1.1 dev: true + /define-properties@1.2.0: + resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==} + engines: {node: '>= 0.4'} + dependencies: + has-property-descriptors: 1.0.0 + object-keys: 1.1.1 + dev: true + /deprecation@2.3.1: resolution: {integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==} dev: false @@ -2158,47 +2479,99 @@ packages: esutils: 2.0.3 dev: true - /electron-to-chromium@1.4.192: - resolution: {integrity: sha512-8nCXyIQY9An88NXAp+PuPy5h3/w5ZY7Iu2lag65Q0XREprcat5F8gKhoHsBUnQcFuCRnmevpR8yEBYRU3d2HDw==} + /electron-to-chromium@1.4.499: + resolution: {integrity: sha512-0NmjlYBLKVHva4GABWAaHuPJolnDuL0AhV3h1hES6rcLCWEIbRL6/8TghfsVwkx6TEroQVdliX7+aLysUpKvjw==} dev: false /emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} dev: true + /enhanced-resolve@5.15.0: + resolution: {integrity: sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==} + engines: {node: '>=10.13.0'} + dependencies: + graceful-fs: 4.2.11 + tapable: 2.2.1 + dev: true + /error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} dependencies: is-arrayish: 0.2.1 dev: false - /es-abstract@1.20.1: - resolution: {integrity: sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==} + /es-abstract@1.22.1: + resolution: {integrity: sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==} engines: {node: '>= 0.4'} dependencies: + array-buffer-byte-length: 1.0.0 + arraybuffer.prototype.slice: 1.0.1 + available-typed-arrays: 1.0.5 call-bind: 1.0.2 + es-set-tostringtag: 2.0.1 es-to-primitive: 1.2.1 - function-bind: 1.1.1 function.prototype.name: 1.1.5 - get-intrinsic: 1.1.2 + get-intrinsic: 1.2.1 get-symbol-description: 1.0.0 + globalthis: 1.0.3 + gopd: 1.0.1 has: 1.0.3 has-property-descriptors: 1.0.0 + has-proto: 1.0.1 has-symbols: 1.0.3 - internal-slot: 1.0.3 - is-callable: 1.2.4 + internal-slot: 1.0.5 + is-array-buffer: 3.0.2 + is-callable: 1.2.7 is-negative-zero: 2.0.2 is-regex: 1.1.4 is-shared-array-buffer: 1.0.2 is-string: 1.0.7 + is-typed-array: 1.1.12 is-weakref: 1.0.2 - object-inspect: 1.12.2 + object-inspect: 1.12.3 object-keys: 1.1.1 - object.assign: 4.1.2 - regexp.prototype.flags: 1.4.3 - string.prototype.trimend: 1.0.5 - string.prototype.trimstart: 1.0.5 + object.assign: 4.1.4 + regexp.prototype.flags: 1.5.0 + safe-array-concat: 1.0.0 + safe-regex-test: 1.0.0 + string.prototype.trim: 1.2.7 + string.prototype.trimend: 1.0.6 + string.prototype.trimstart: 1.0.6 + typed-array-buffer: 1.0.0 + typed-array-byte-length: 1.0.0 + typed-array-byte-offset: 1.0.0 + typed-array-length: 1.0.4 unbox-primitive: 1.0.2 + which-typed-array: 1.1.11 + dev: true + + /es-iterator-helpers@1.0.13: + resolution: {integrity: sha512-LK3VGwzvaPWobO8xzXXGRUOGw8Dcjyfk62CsY/wfHN75CwsJPbuypOYJxK6g5RyEL8YDjIWcl6jgd8foO6mmrA==} + dependencies: + asynciterator.prototype: 1.0.0 + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.1 + es-set-tostringtag: 2.0.1 + function-bind: 1.1.1 + get-intrinsic: 1.2.1 + globalthis: 1.0.3 + has-property-descriptors: 1.0.0 + has-proto: 1.0.1 + has-symbols: 1.0.3 + internal-slot: 1.0.5 + iterator.prototype: 1.1.0 + safe-array-concat: 1.0.0 + dev: true + + /es-set-tostringtag@2.0.1: + resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.1 + has: 1.0.3 + has-tostringtag: 1.0.0 dev: true /es-shim-unscopables@1.0.0: @@ -2211,7 +2584,7 @@ packages: resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} engines: {node: '>= 0.4'} dependencies: - is-callable: 1.2.4 + is-callable: 1.2.7 is-date-object: 1.0.5 is-symbol: 1.0.4 dev: true @@ -2235,8 +2608,8 @@ packages: engines: {node: '>=12'} dev: false - /eslint-config-next@12.2.2(eslint@8.20.0)(typescript@4.7.4): - resolution: {integrity: sha512-oJhWBLC4wDYYUFv/5APbjHUFd0QRFCojMdj/QnMoOEktmeTvwnnoA8F8uaXs0fQgsaTK0tbUxBRv9/Y4/rpxOA==} + /eslint-config-next@13.4.19(eslint@8.47.0)(typescript@5.1.6): + resolution: {integrity: sha512-WE8367sqMnjhWHvR5OivmfwENRQ1ixfNE9hZwQqNCsd+iM3KnuMc1V8Pt6ytgjxjf23D+xbesADv9x3xaKfT3g==} peerDependencies: eslint: ^7.23.0 || ^8.0.0 typescript: '>=3.3.1' @@ -2244,29 +2617,29 @@ packages: typescript: optional: true dependencies: - '@next/eslint-plugin-next': 12.2.2 + '@next/eslint-plugin-next': 13.4.19 '@rushstack/eslint-patch': 1.1.4 - '@typescript-eslint/parser': 5.30.6(eslint@8.20.0)(typescript@4.7.4) - eslint: 8.20.0 + '@typescript-eslint/parser': 5.30.6(eslint@8.47.0)(typescript@5.1.6) + eslint: 8.47.0 eslint-import-resolver-node: 0.3.6 - eslint-import-resolver-typescript: 2.7.1(eslint-plugin-import@2.26.0)(eslint@8.20.0) - eslint-plugin-import: 2.26.0(@typescript-eslint/parser@5.30.6)(eslint-import-resolver-typescript@2.7.1)(eslint@8.20.0) - eslint-plugin-jsx-a11y: 6.6.0(eslint@8.20.0) - eslint-plugin-react: 7.30.1(eslint@8.20.0) - eslint-plugin-react-hooks: 4.6.0(eslint@8.20.0) - typescript: 4.7.4 + eslint-import-resolver-typescript: 3.6.0(@typescript-eslint/parser@5.30.6)(eslint-import-resolver-node@0.3.6)(eslint-plugin-import@2.26.0)(eslint@8.47.0) + eslint-plugin-import: 2.26.0(@typescript-eslint/parser@5.30.6)(eslint-import-resolver-typescript@3.6.0)(eslint@8.47.0) + eslint-plugin-jsx-a11y: 6.6.0(eslint@8.47.0) + eslint-plugin-react: 7.33.2(eslint@8.47.0) + eslint-plugin-react-hooks: 4.6.0(eslint@8.47.0) + typescript: 5.1.6 transitivePeerDependencies: - eslint-import-resolver-webpack - supports-color dev: true - /eslint-config-prettier@8.5.0(eslint@8.20.0): - resolution: {integrity: sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==} + /eslint-config-prettier@9.0.0(eslint@8.47.0): + resolution: {integrity: sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==} hasBin: true peerDependencies: eslint: '>=7.0.0' dependencies: - eslint: 8.20.0 + eslint: 8.47.0 dev: true /eslint-import-resolver-node@0.3.6: @@ -2278,25 +2651,30 @@ packages: - supports-color dev: true - /eslint-import-resolver-typescript@2.7.1(eslint-plugin-import@2.26.0)(eslint@8.20.0): - resolution: {integrity: sha512-00UbgGwV8bSgUv34igBDbTOtKhqoRMy9bFjNehT40bXg6585PNIct8HhXZ0SybqB9rWtXj9crcku8ndDn/gIqQ==} - engines: {node: '>=4'} + /eslint-import-resolver-typescript@3.6.0(@typescript-eslint/parser@5.30.6)(eslint-import-resolver-node@0.3.6)(eslint-plugin-import@2.26.0)(eslint@8.47.0): + resolution: {integrity: sha512-QTHR9ddNnn35RTxlaEnx2gCxqFlF2SEN0SE2d17SqwyM7YOSI2GHWRYp5BiRkObTUNYPupC/3Fq2a0PpT+EKpg==} + engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: eslint: '*' eslint-plugin-import: '*' dependencies: debug: 4.3.4 - eslint: 8.20.0 - eslint-plugin-import: 2.26.0(@typescript-eslint/parser@5.30.6)(eslint-import-resolver-typescript@2.7.1)(eslint@8.20.0) - glob: 7.2.3 + enhanced-resolve: 5.15.0 + eslint: 8.47.0 + eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.30.6)(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@3.6.0)(eslint@8.47.0) + eslint-plugin-import: 2.26.0(@typescript-eslint/parser@5.30.6)(eslint-import-resolver-typescript@3.6.0)(eslint@8.47.0) + fast-glob: 3.3.1 + get-tsconfig: 4.7.0 + is-core-module: 2.13.0 is-glob: 4.0.3 - resolve: 1.22.1 - tsconfig-paths: 3.14.1 transitivePeerDependencies: + - '@typescript-eslint/parser' + - eslint-import-resolver-node + - eslint-import-resolver-webpack - supports-color dev: true - /eslint-module-utils@2.7.3(@typescript-eslint/parser@5.30.6)(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@2.7.1): + /eslint-module-utils@2.7.3(@typescript-eslint/parser@5.30.6)(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@3.6.0): resolution: {integrity: sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==} engines: {node: '>=4'} peerDependencies: @@ -2314,16 +2692,46 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 5.30.6(eslint@8.20.0)(typescript@4.7.4) + '@typescript-eslint/parser': 5.30.6(eslint@8.47.0)(typescript@5.1.6) debug: 3.2.7 eslint-import-resolver-node: 0.3.6 - eslint-import-resolver-typescript: 2.7.1(eslint-plugin-import@2.26.0)(eslint@8.20.0) + eslint-import-resolver-typescript: 3.6.0(@typescript-eslint/parser@5.30.6)(eslint-import-resolver-node@0.3.6)(eslint-plugin-import@2.26.0)(eslint@8.47.0) find-up: 2.1.0 transitivePeerDependencies: - supports-color dev: true - /eslint-plugin-import@2.26.0(@typescript-eslint/parser@5.30.6)(eslint-import-resolver-typescript@2.7.1)(eslint@8.20.0): + /eslint-module-utils@2.8.0(@typescript-eslint/parser@5.30.6)(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@3.6.0)(eslint@8.47.0): + resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + dependencies: + '@typescript-eslint/parser': 5.30.6(eslint@8.47.0)(typescript@5.1.6) + debug: 3.2.7 + eslint: 8.47.0 + eslint-import-resolver-node: 0.3.6 + eslint-import-resolver-typescript: 3.6.0(@typescript-eslint/parser@5.30.6)(eslint-import-resolver-node@0.3.6)(eslint-plugin-import@2.26.0)(eslint@8.47.0) + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-plugin-import@2.26.0(@typescript-eslint/parser@5.30.6)(eslint-import-resolver-typescript@3.6.0)(eslint@8.47.0): resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==} engines: {node: '>=4'} peerDependencies: @@ -2333,14 +2741,14 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 5.30.6(eslint@8.20.0)(typescript@4.7.4) + '@typescript-eslint/parser': 5.30.6(eslint@8.47.0)(typescript@5.1.6) array-includes: 3.1.5 array.prototype.flat: 1.3.0 debug: 2.6.9 doctrine: 2.1.0 - eslint: 8.20.0 + eslint: 8.47.0 eslint-import-resolver-node: 0.3.6 - eslint-module-utils: 2.7.3(@typescript-eslint/parser@5.30.6)(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@2.7.1) + eslint-module-utils: 2.7.3(@typescript-eslint/parser@5.30.6)(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@3.6.0) has: 1.0.3 is-core-module: 2.9.0 is-glob: 4.0.3 @@ -2354,7 +2762,7 @@ packages: - supports-color dev: true - /eslint-plugin-jsx-a11y@6.6.0(eslint@8.20.0): + /eslint-plugin-jsx-a11y@6.6.0(eslint@8.47.0): resolution: {integrity: sha512-kTeLuIzpNhXL2CwLlc8AHI0aFRwWHcg483yepO9VQiHzM9bZwJdzTkzBszbuPrbgGmq2rlX/FaT2fJQsjUSHsw==} engines: {node: '>=4.0'} peerDependencies: @@ -2368,125 +2776,114 @@ packages: axobject-query: 2.2.0 damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 - eslint: 8.20.0 + eslint: 8.47.0 has: 1.0.3 jsx-ast-utils: 3.3.2 language-tags: 1.0.5 minimatch: 3.1.2 - semver: 6.3.0 + semver: 6.3.1 dev: true - /eslint-plugin-react-hooks@4.6.0(eslint@8.20.0): + /eslint-plugin-react-hooks@4.6.0(eslint@8.47.0): resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==} engines: {node: '>=10'} peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 dependencies: - eslint: 8.20.0 + eslint: 8.47.0 dev: true - /eslint-plugin-react@7.30.1(eslint@8.20.0): - resolution: {integrity: sha512-NbEvI9jtqO46yJA3wcRF9Mo0lF9T/jhdHqhCHXiXtD+Zcb98812wvokjWpU7Q4QH5edo6dmqrukxVvWWXHlsUg==} + /eslint-plugin-react@7.33.2(eslint@8.47.0): + resolution: {integrity: sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==} engines: {node: '>=4'} peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 dependencies: - array-includes: 3.1.5 - array.prototype.flatmap: 1.3.0 + array-includes: 3.1.6 + array.prototype.flatmap: 1.3.1 + array.prototype.tosorted: 1.1.1 doctrine: 2.1.0 - eslint: 8.20.0 + es-iterator-helpers: 1.0.13 + eslint: 8.47.0 estraverse: 5.3.0 jsx-ast-utils: 3.3.2 minimatch: 3.1.2 - object.entries: 1.1.5 - object.fromentries: 2.0.5 - object.hasown: 1.1.1 - object.values: 1.1.5 + object.entries: 1.1.6 + object.fromentries: 2.0.6 + object.hasown: 1.1.2 + object.values: 1.1.6 prop-types: 15.8.1 resolve: 2.0.0-next.4 - semver: 6.3.0 - string.prototype.matchall: 4.0.7 + semver: 6.3.1 + string.prototype.matchall: 4.0.8 dev: true - /eslint-scope@7.1.1: - resolution: {integrity: sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==} + /eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: esrecurse: 4.3.0 estraverse: 5.3.0 dev: true - /eslint-utils@3.0.0(eslint@8.20.0): - resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} - engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} - peerDependencies: - eslint: '>=5' - dependencies: - eslint: 8.20.0 - eslint-visitor-keys: 2.1.0 - dev: true - - /eslint-visitor-keys@2.1.0: - resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} - engines: {node: '>=10'} - dev: true - - /eslint-visitor-keys@3.3.0: - resolution: {integrity: sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==} + /eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /eslint@8.20.0: - resolution: {integrity: sha512-d4ixhz5SKCa1D6SCPrivP7yYVi7nyD6A4vs6HIAul9ujBzcEmZVM3/0NN/yu5nKhmO1wjp5xQ46iRfmDGlOviA==} + /eslint@8.47.0: + resolution: {integrity: sha512-spUQWrdPt+pRVP1TTJLmfRNJJHHZryFmptzcafwSvHsceV81djHOdnEeDmkdotZyLNjDhrOasNK8nikkoG1O8Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true dependencies: - '@eslint/eslintrc': 1.3.0 - '@humanwhocodes/config-array': 0.9.5 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.47.0) + '@eslint-community/regexpp': 4.7.0 + '@eslint/eslintrc': 2.1.2 + '@eslint/js': 8.47.0 + '@humanwhocodes/config-array': 0.11.10 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 debug: 4.3.4 doctrine: 3.0.0 escape-string-regexp: 4.0.0 - eslint-scope: 7.1.1 - eslint-utils: 3.0.0(eslint@8.20.0) - eslint-visitor-keys: 3.3.0 - espree: 9.3.2 - esquery: 1.4.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.5.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 file-entry-cache: 6.0.1 - functional-red-black-tree: 1.0.1 + find-up: 5.0.0 glob-parent: 6.0.2 - globals: 13.16.0 + globals: 13.21.0 + graphemer: 1.4.0 ignore: 5.2.0 - import-fresh: 3.3.0 imurmurhash: 0.1.4 is-glob: 4.0.3 + is-path-inside: 3.0.3 js-yaml: 4.1.0 json-stable-stringify-without-jsonify: 1.0.1 levn: 0.4.1 lodash.merge: 4.6.2 minimatch: 3.1.2 natural-compare: 1.4.0 - optionator: 0.9.1 - regexpp: 3.2.0 + optionator: 0.9.3 strip-ansi: 6.0.1 - strip-json-comments: 3.1.1 text-table: 0.2.0 - v8-compile-cache: 2.3.0 transitivePeerDependencies: - supports-color dev: true - /espree@9.3.2: - resolution: {integrity: sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==} + /espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - acorn: 8.7.1 - acorn-jsx: 5.3.2(acorn@8.7.1) - eslint-visitor-keys: 3.3.0 + acorn: 8.10.0 + acorn-jsx: 5.3.2(acorn@8.10.0) + eslint-visitor-keys: 3.4.3 dev: true /esprima@4.0.1: @@ -2495,8 +2892,8 @@ packages: hasBin: true dev: false - /esquery@1.4.0: - resolution: {integrity: sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==} + /esquery@1.5.0: + resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} engines: {node: '>=0.10'} dependencies: estraverse: 5.3.0 @@ -2534,8 +2931,8 @@ packages: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} dev: true - /fast-glob@3.2.11: - resolution: {integrity: sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==} + /fast-glob@3.3.1: + resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} engines: {node: '>=8.6.0'} dependencies: '@nodelib/fs.stat': 2.0.5 @@ -2584,6 +2981,14 @@ packages: locate-path: 2.0.0 dev: true + /find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + dev: true + /flat-cache@3.0.4: resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} engines: {node: ^10.12.0 || >=12.0.0} @@ -2596,39 +3001,34 @@ packages: resolution: {integrity: sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==} dev: true - /focus-lock@0.11.2: - resolution: {integrity: sha512-pZ2bO++NWLHhiKkgP1bEXHhR1/OjVcSvlCJ98aNJDFeb7H5OOQaO+SKOZle6041O9rv2tmbrO4JzClAvDUHf0g==} + /focus-lock@0.11.6: + resolution: {integrity: sha512-KSuV3ur4gf2KqMNoZx3nXNVhqCkn42GuTYCX4tXPEwf0MjpFQmNMiN6m7dXaUXgIoivL6/65agoUMg4RLS0Vbg==} engines: {node: '>=10'} dependencies: tslib: 2.4.0 dev: false - /framer-motion@6.5.1(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-o1BGqqposwi7cgDrtg0dNONhkmPsUFDaLcKXigzuTFC5x58mE8iyTazxSudFzmT6MEyJKfjjU8ItoMe3W+3fiw==} - peerDependencies: - react: '>=16.8 || ^17.0.0 || ^18.0.0' - react-dom: '>=16.8 || ^17.0.0 || ^18.0.0' + /for-each@0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + dependencies: + is-callable: 1.2.7 + dev: true + + /framer-motion@10.0.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-qVmndcu4Z3q5ftqcbUCvVewHc5yiw4uIZyM0uvJ0/spj9lza/FnWywUUc8DNIZTG1my6nFsNLRPGDruP4o6eIw==} + peerDependencies: + react: ^18.0.0 + react-dom: ^18.0.0 dependencies: - '@motionone/dom': 10.12.0 - framesync: 6.0.1 - hey-listen: 1.0.8 - popmotion: 11.0.3 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - style-value-types: 5.0.0 tslib: 2.4.0 optionalDependencies: '@emotion/is-prop-valid': 0.8.8 dev: false - /framesync@5.3.0: - resolution: {integrity: sha512-oc5m68HDO/tuK2blj7ZcdEBRx3p1PjrgHazL8GYEpvULhrtGIFbQArN6cQS2QhW8mitffaB+VYzMjDqBxxQeoA==} - dependencies: - tslib: 2.4.0 - dev: false - - /framesync@6.0.1: - resolution: {integrity: sha512-fUY88kXvGiIItgNC7wcTOl0SNRCVXMKSWW2Yzfmn7EKNc+MpCzcz9DhdHcdjbrtN3c6R4H5dTY2jiCpPdysEjA==} + /framesync@6.1.2: + resolution: {integrity: sha512-jBTqhX6KaQVDyus8muwZbBeGGP0XgujBRbQ7gM7BRdS3CadCZIHiawyzYLnafYcvZIh5j8WE7cxZKFn7dXhu9g==} dependencies: tslib: 2.4.0 dev: false @@ -2645,15 +3045,11 @@ packages: engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.1 + define-properties: 1.2.0 + es-abstract: 1.22.1 functions-have-names: 1.2.3 dev: true - /functional-red-black-tree@1.0.1: - resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} - dev: true - /functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} dev: true @@ -2667,11 +3063,12 @@ packages: engines: {node: '>=6.9.0'} dev: false - /get-intrinsic@1.1.2: - resolution: {integrity: sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==} + /get-intrinsic@1.2.1: + resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==} dependencies: function-bind: 1.1.1 has: 1.0.3 + has-proto: 1.0.1 has-symbols: 1.0.3 dev: true @@ -2685,7 +3082,13 @@ packages: engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.2 - get-intrinsic: 1.1.2 + get-intrinsic: 1.2.1 + dev: true + + /get-tsconfig@4.7.0: + resolution: {integrity: sha512-pmjiZ7xtB8URYm74PlGJozDNyhvsVLUcpBa8DZBG3bWHwaHa9bPiRpiSfovw+fjhwONSCWKRyk+JQHEGZmMrzw==} + dependencies: + resolve-pkg-maps: 1.0.0 dev: true /glob-parent@5.1.2: @@ -2702,6 +3105,10 @@ packages: is-glob: 4.0.3 dev: true + /glob-to-regexp@0.4.1: + resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} + dev: false + /glob@7.1.7: resolution: {integrity: sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==} dependencies: @@ -2729,25 +3136,45 @@ packages: engines: {node: '>=4'} dev: false - /globals@13.16.0: - resolution: {integrity: sha512-A1lrQfpNF+McdPOnnFqY3kSN0AFTy485bTi1bkLk4mVPODIUEcSfhHgRqA+QdXPksrSTTztYXx37NFV+GpGk3Q==} + /globals@13.21.0: + resolution: {integrity: sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==} engines: {node: '>=8'} dependencies: type-fest: 0.20.2 dev: true + /globalthis@1.0.3: + resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} + engines: {node: '>= 0.4'} + dependencies: + define-properties: 1.2.0 + dev: true + /globby@11.1.0: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} dependencies: array-union: 2.1.0 dir-glob: 3.0.1 - fast-glob: 3.2.11 + fast-glob: 3.3.1 ignore: 5.2.0 merge2: 1.4.1 slash: 3.0.0 dev: true + /gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + dependencies: + get-intrinsic: 1.2.1 + dev: true + + /graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + /graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + dev: true + /gray-matter@4.0.3: resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==} engines: {node: '>=6.0'} @@ -2775,7 +3202,12 @@ packages: /has-property-descriptors@1.0.0: resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} dependencies: - get-intrinsic: 1.1.2 + get-intrinsic: 1.2.1 + dev: true + + /has-proto@1.0.1: + resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} + engines: {node: '>= 0.4'} dev: true /has-symbols@1.0.3: @@ -2800,10 +3232,6 @@ packages: resolution: {integrity: sha512-Pkw+xBHuV6xFeJprJe2BBEoDV+AvQySaz3pPDRUs5PNZEMQjpXJJueqrpcHIXxnWTcAGi/UOCgVShlkY6kLoqg==} dev: false - /hey-listen@1.0.8: - resolution: {integrity: sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==} - dev: false - /hoist-non-react-statics@3.3.2: resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} dependencies: @@ -2846,7 +3274,16 @@ packages: resolution: {integrity: sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==} engines: {node: '>= 0.4'} dependencies: - get-intrinsic: 1.1.2 + get-intrinsic: 1.2.1 + has: 1.0.3 + side-channel: 1.0.4 + dev: true + + /internal-slot@1.0.5: + resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.1 has: 1.0.3 side-channel: 1.0.4 dev: true @@ -2857,10 +3294,25 @@ packages: loose-envify: 1.4.0 dev: false + /is-array-buffer@3.0.2: + resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.1 + is-typed-array: 1.1.12 + dev: true + /is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} dev: false + /is-async-function@2.0.0: + resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + /is-bigint@1.0.4: resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} dependencies: @@ -2880,11 +3332,17 @@ packages: engines: {node: '>=4'} dev: false - /is-callable@1.2.4: - resolution: {integrity: sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==} + /is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} dev: true + /is-core-module@2.13.0: + resolution: {integrity: sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==} + dependencies: + has: 1.0.3 + dev: true + /is-core-module@2.9.0: resolution: {integrity: sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==} dependencies: @@ -2907,6 +3365,19 @@ packages: engines: {node: '>=0.10.0'} dev: true + /is-finalizationregistry@1.0.2: + resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==} + dependencies: + call-bind: 1.0.2 + dev: true + + /is-generator-function@1.0.10: + resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + /is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -2914,6 +3385,10 @@ packages: is-extglob: 2.1.1 dev: true + /is-map@2.0.2: + resolution: {integrity: sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==} + dev: true + /is-negative-zero@2.0.2: resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} engines: {node: '>= 0.4'} @@ -2931,6 +3406,11 @@ packages: engines: {node: '>=0.12.0'} dev: true + /is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + dev: true + /is-plain-obj@4.1.0: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} @@ -2949,6 +3429,10 @@ packages: has-tostringtag: 1.0.0 dev: true + /is-set@2.0.2: + resolution: {integrity: sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==} + dev: true + /is-shared-array-buffer@1.0.2: resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} dependencies: @@ -2969,16 +3453,48 @@ packages: has-symbols: 1.0.3 dev: true + /is-typed-array@1.1.12: + resolution: {integrity: sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==} + engines: {node: '>= 0.4'} + dependencies: + which-typed-array: 1.1.11 + dev: true + + /is-weakmap@2.0.1: + resolution: {integrity: sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==} + dev: true + /is-weakref@1.0.2: resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} dependencies: call-bind: 1.0.2 dev: true + /is-weakset@2.0.2: + resolution: {integrity: sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==} + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.1 + dev: true + + /isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + dev: true + /isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} dev: true + /iterator.prototype@1.1.0: + resolution: {integrity: sha512-rjuhAk1AJ1fssphHD0IFV6TWL40CwRZ53FrztKx43yk2v6rguBYsY4Bj1VU4HmoMmKwZUlx7mfnhDf9cOp4YTw==} + dependencies: + define-properties: 1.2.0 + get-intrinsic: 1.2.1 + has-symbols: 1.0.3 + has-tostringtag: 1.0.0 + reflect.getprototypeof: 1.0.3 + dev: true + /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -3022,8 +3538,8 @@ packages: minimist: 1.2.6 dev: true - /json5@2.2.1: - resolution: {integrity: sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==} + /json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} hasBin: true dev: false @@ -3032,8 +3548,8 @@ packages: resolution: {integrity: sha512-4ZCADZHRkno244xlNnn4AOG6sRQ7iBZ5BbgZ4vW4y5IZw7cVUD1PPeblm1xx/nfmMxPdt/LHsXZW8z/j58+l9Q==} engines: {node: '>=4.0'} dependencies: - array-includes: 3.1.5 - object.assign: 4.1.2 + array-includes: 3.1.6 + object.assign: 4.1.4 dev: true /kind-of@6.0.3: @@ -3076,6 +3592,13 @@ packages: path-exists: 3.0.0 dev: true + /locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + dependencies: + p-locate: 5.0.0 + dev: true + /lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true @@ -3094,6 +3617,12 @@ packages: dependencies: js-tokens: 4.0.0 + /lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + dependencies: + yallist: 3.1.1 + dev: false + /lru-cache@6.0.0: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} @@ -3529,77 +4058,61 @@ packages: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true - /next@12.2.2(@babel/core@7.18.6)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-zAYFY45aBry/PlKONqtlloRFqU/We3zWYdn2NoGvDZkoYUYQSJC8WMcalS5C19MxbCZLUVCX7D7a6gTGgl2yLg==} - engines: {node: '>=12.22.0'} + /next@13.4.19(@babel/core@7.22.10)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-HuPSzzAbJ1T4BD8e0bs6B9C1kWQ6gv8ykZoRWs5AQoiIuqbGHHdQO7Ljuvg05Q0Z24E2ABozHe6FxDvI6HfyAw==} + engines: {node: '>=16.8.0'} hasBin: true peerDependencies: - fibers: '>= 3.1.0' - node-sass: ^6.0.0 || ^7.0.0 - react: ^17.0.2 || ^18.0.0-0 - react-dom: ^17.0.2 || ^18.0.0-0 + '@opentelemetry/api': ^1.1.0 + react: ^18.2.0 + react-dom: ^18.2.0 sass: ^1.3.0 peerDependenciesMeta: - fibers: - optional: true - node-sass: + '@opentelemetry/api': optional: true sass: optional: true dependencies: - '@next/env': 12.2.2 - '@swc/helpers': 0.4.2 - caniuse-lite: 1.0.30001367 - postcss: 8.4.5 + '@next/env': 13.4.19 + '@swc/helpers': 0.5.1 + busboy: 1.6.0 + caniuse-lite: 1.0.30001522 + postcss: 8.4.14 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - styled-jsx: 5.0.2(@babel/core@7.18.6)(react@18.2.0) - use-sync-external-store: 1.1.0(react@18.2.0) + styled-jsx: 5.1.1(@babel/core@7.22.10)(react@18.2.0) + watchpack: 2.4.0 + zod: 3.21.4 optionalDependencies: - '@next/swc-android-arm-eabi': 12.2.2 - '@next/swc-android-arm64': 12.2.2 - '@next/swc-darwin-arm64': 12.2.2 - '@next/swc-darwin-x64': 12.2.2 - '@next/swc-freebsd-x64': 12.2.2 - '@next/swc-linux-arm-gnueabihf': 12.2.2 - '@next/swc-linux-arm64-gnu': 12.2.2 - '@next/swc-linux-arm64-musl': 12.2.2 - '@next/swc-linux-x64-gnu': 12.2.2 - '@next/swc-linux-x64-musl': 12.2.2 - '@next/swc-win32-arm64-msvc': 12.2.2 - '@next/swc-win32-ia32-msvc': 12.2.2 - '@next/swc-win32-x64-msvc': 12.2.2 + '@next/swc-darwin-arm64': 13.4.19 + '@next/swc-darwin-x64': 13.4.19 + '@next/swc-linux-arm64-gnu': 13.4.19 + '@next/swc-linux-arm64-musl': 13.4.19 + '@next/swc-linux-x64-gnu': 13.4.19 + '@next/swc-linux-x64-musl': 13.4.19 + '@next/swc-win32-arm64-msvc': 13.4.19 + '@next/swc-win32-ia32-msvc': 13.4.19 + '@next/swc-win32-x64-msvc': 13.4.19 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros dev: false - /nextjs-progressbar@0.0.14(next@12.2.2)(react@18.2.0): - resolution: {integrity: sha512-AXYXHDN6M52AwFnGqH/vlwyo0gbC9zM7QS/4ryOTI0RUqfze5FJl8uSrxKJMzK6hGFdDeQXcZoWsLGXeCVtTwg==} + /nextjs-progressbar@0.0.16(next@13.4.19)(react@18.2.0): + resolution: {integrity: sha512-GV0fD38EMD3vSDCmkq+tObmoup6QA91a6a9MxGuhJZuRk/9TNsrHGnIQQQ/sggkMkXuT4fBgF6jRjFwScDT3zA==} peerDependencies: next: '>= 6.0.0' react: '>= 16.0.0' dependencies: - next: 12.2.2(@babel/core@7.18.6)(react-dom@18.2.0)(react@18.2.0) + '@types/nprogress': 0.2.0 + next: 13.4.19(@babel/core@7.22.10)(react-dom@18.2.0)(react@18.2.0) nprogress: 0.2.0 prop-types: 15.8.1 react: 18.2.0 dev: false - /node-fetch@2.6.7: - resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==} - engines: {node: 4.x || >=6.0.0} - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - dependencies: - whatwg-url: 5.0.0 - dev: false - - /node-releases@2.0.6: - resolution: {integrity: sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==} + /node-releases@2.0.13: + resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} dev: false /nprogress@0.2.0: @@ -3614,44 +4127,48 @@ packages: resolution: {integrity: sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==} dev: true + /object-inspect@1.12.3: + resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} + dev: true + /object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} dev: true - /object.assign@4.1.2: - resolution: {integrity: sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==} + /object.assign@4.1.4: + resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.2 - define-properties: 1.1.4 + define-properties: 1.2.0 has-symbols: 1.0.3 object-keys: 1.1.1 dev: true - /object.entries@1.1.5: - resolution: {integrity: sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==} + /object.entries@1.1.6: + resolution: {integrity: sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.2 define-properties: 1.1.4 - es-abstract: 1.20.1 + es-abstract: 1.22.1 dev: true - /object.fromentries@2.0.5: - resolution: {integrity: sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==} + /object.fromentries@2.0.6: + resolution: {integrity: sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.2 define-properties: 1.1.4 - es-abstract: 1.20.1 + es-abstract: 1.22.1 dev: true - /object.hasown@1.1.1: - resolution: {integrity: sha512-LYLe4tivNQzq4JdaWW6WO3HMZZJWzkkH8fnI6EebWl0VZth2wL2Lovm74ep2/gZzlaTdV62JZHEqHQ2yVn8Q/A==} + /object.hasown@1.1.2: + resolution: {integrity: sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==} dependencies: define-properties: 1.1.4 - es-abstract: 1.20.1 + es-abstract: 1.22.1 dev: true /object.values@1.1.5: @@ -3660,7 +4177,16 @@ packages: dependencies: call-bind: 1.0.2 define-properties: 1.1.4 - es-abstract: 1.20.1 + es-abstract: 1.22.1 + dev: true + + /object.values@1.1.6: + resolution: {integrity: sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.22.1 dev: true /once@1.4.0: @@ -3668,16 +4194,16 @@ packages: dependencies: wrappy: 1.0.2 - /optionator@0.9.1: - resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==} + /optionator@0.9.3: + resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} engines: {node: '>= 0.8.0'} dependencies: + '@aashutoshrathi/word-wrap': 1.2.6 deep-is: 0.1.4 fast-levenshtein: 2.0.6 levn: 0.4.1 prelude-ls: 1.2.1 type-check: 0.4.0 - word-wrap: 1.2.3 dev: true /p-limit@1.3.0: @@ -3687,6 +4213,13 @@ packages: p-try: 1.0.0 dev: true + /p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + dependencies: + yocto-queue: 0.1.0 + dev: true + /p-locate@2.0.0: resolution: {integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==} engines: {node: '>=4'} @@ -3694,6 +4227,13 @@ packages: p-limit: 1.3.0 dev: true + /p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + dependencies: + p-limit: 3.1.0 + dev: true + /p-try@1.0.0: resolution: {integrity: sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==} engines: {node: '>=4'} @@ -3709,7 +4249,7 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} dependencies: - '@babel/code-frame': 7.18.6 + '@babel/code-frame': 7.22.10 error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 @@ -3720,6 +4260,11 @@ packages: engines: {node: '>=4'} dev: true + /path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + dev: true + /path-is-absolute@1.0.1: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} @@ -3746,17 +4291,8 @@ packages: engines: {node: '>=8.6'} dev: true - /popmotion@11.0.3: - resolution: {integrity: sha512-Y55FLdj3UxkR7Vl3s7Qr4e9m0onSnP8W7d/xQLsoJM40vs6UKHFdygs6SWryasTZYqugMjm3BepCF4CWXDiHgA==} - dependencies: - framesync: 6.0.1 - hey-listen: 1.0.8 - style-value-types: 5.0.0 - tslib: 2.4.0 - dev: false - - /postcss@8.4.5: - resolution: {integrity: sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==} + /postcss@8.4.14: + resolution: {integrity: sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==} engines: {node: ^10 || ^12 || >=14} dependencies: nanoid: 3.3.4 @@ -3808,12 +4344,12 @@ packages: scheduler: 0.23.0 dev: false - /react-fast-compare@3.2.0: - resolution: {integrity: sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==} + /react-fast-compare@3.2.1: + resolution: {integrity: sha512-xTYf9zFim2pEif/Fw16dBiXpe0hoy5PxcD8+OwBnTtNLfIm3g6WxhKNurY+6OmdH1u6Ta/W/Vl6vjbYP1MFnDg==} dev: false - /react-focus-lock@2.9.1(@types/react@18.0.15)(react@18.2.0): - resolution: {integrity: sha512-pSWOQrUmiKLkffPO6BpMXN7SNKXMsuOakl652IBuALAu1esk+IcpJyM+ALcYzPTTFz1rD0R54aB9A4HuP5t1Wg==} + /react-focus-lock@2.9.5(@types/react@18.2.21)(react@18.2.0): + resolution: {integrity: sha512-h6vrdgUbsH2HeD5I7I3Cx1PPrmwGuKYICS+kB9m+32X/9xHRrAbxgvaBpG7BFBN9h3tO+C3qX1QAVESmi4CiIA==} peerDependencies: '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 react: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -3822,17 +4358,17 @@ packages: optional: true dependencies: '@babel/runtime': 7.18.6 - '@types/react': 18.0.15 - focus-lock: 0.11.2 + '@types/react': 18.2.21 + focus-lock: 0.11.6 prop-types: 15.8.1 react: 18.2.0 react-clientside-effect: 1.2.6(react@18.2.0) - use-callback-ref: 1.3.0(@types/react@18.0.15)(react@18.2.0) - use-sidecar: 1.1.2(@types/react@18.0.15)(react@18.2.0) + use-callback-ref: 1.3.0(@types/react@18.2.21)(react@18.2.0) + use-sidecar: 1.1.2(@types/react@18.2.21)(react@18.2.0) dev: false - /react-icons@4.4.0(react@18.2.0): - resolution: {integrity: sha512-fSbvHeVYo/B5/L4VhB7sBA1i2tS8MkT0Hb9t2H1AVPkwGfVHLJCqyr2Py9dKMxsyM63Eng1GkdZfbWj+Fmv8Rg==} + /react-icons@4.10.1(react@18.2.0): + resolution: {integrity: sha512-/ngzDP/77tlCfqthiiGNZeYFACw85fUjZtLbedmJ5DTlNDIwETxhwBzdOJ21zj4iJdvc0J3y7yOsX3PpxAJzrw==} peerDependencies: react: '*' dependencies: @@ -3846,15 +4382,15 @@ packages: resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} dev: false - /react-markdown@8.0.3(@types/react@18.0.15)(react@18.2.0): - resolution: {integrity: sha512-We36SfqaKoVNpN1QqsZwWSv/OZt5J15LNgTLWynwAN5b265hrQrsjMtlRNwUvS+YyR3yDM8HpTNc4pK9H/Gc0A==} + /react-markdown@8.0.7(@types/react@18.2.21)(react@18.2.0): + resolution: {integrity: sha512-bvWbzG4MtOU62XqBx3Xx+zB2raaFFsq4mYiAzfjXJMEz2sixgeAfraA3tvzULF02ZdOMUOKTBFFaZJDDrq+BJQ==} peerDependencies: '@types/react': '>=16' react: '>=16' dependencies: '@types/hast': 2.3.4 '@types/prop-types': 15.7.5 - '@types/react': 18.0.15 + '@types/react': 18.2.21 '@types/unist': 2.0.6 comma-separated-tokens: 2.0.2 hast-util-whitespace: 2.0.0 @@ -3865,7 +4401,7 @@ packages: remark-parse: 10.0.1 remark-rehype: 10.1.0 space-separated-tokens: 2.0.1 - style-to-object: 0.3.0 + style-to-object: 0.4.2 unified: 10.1.2 unist-util-visit: 4.1.0 vfile: 5.3.4 @@ -3873,7 +4409,7 @@ packages: - supports-color dev: false - /react-remove-scroll-bar@2.3.3(@types/react@18.0.15)(react@18.2.0): + /react-remove-scroll-bar@2.3.3(@types/react@18.2.21)(react@18.2.0): resolution: {integrity: sha512-i9GMNWwpz8XpUpQ6QlevUtFjHGqnPG4Hxs+wlIJntu/xcsZVEpJcIV71K3ZkqNy2q3GfgvkD7y6t/Sv8ofYSbw==} engines: {node: '>=10'} peerDependencies: @@ -3883,13 +4419,13 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.0.15 + '@types/react': 18.2.21 react: 18.2.0 - react-style-singleton: 2.2.1(@types/react@18.0.15)(react@18.2.0) + react-style-singleton: 2.2.1(@types/react@18.2.21)(react@18.2.0) tslib: 2.4.0 dev: false - /react-remove-scroll@2.5.5(@types/react@18.0.15)(react@18.2.0): + /react-remove-scroll@2.5.5(@types/react@18.2.21)(react@18.2.0): resolution: {integrity: sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==} engines: {node: '>=10'} peerDependencies: @@ -3899,16 +4435,16 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.0.15 + '@types/react': 18.2.21 react: 18.2.0 - react-remove-scroll-bar: 2.3.3(@types/react@18.0.15)(react@18.2.0) - react-style-singleton: 2.2.1(@types/react@18.0.15)(react@18.2.0) + react-remove-scroll-bar: 2.3.3(@types/react@18.2.21)(react@18.2.0) + react-style-singleton: 2.2.1(@types/react@18.2.21)(react@18.2.0) tslib: 2.4.0 - use-callback-ref: 1.3.0(@types/react@18.0.15)(react@18.2.0) - use-sidecar: 1.1.2(@types/react@18.0.15)(react@18.2.0) + use-callback-ref: 1.3.0(@types/react@18.2.21)(react@18.2.0) + use-sidecar: 1.1.2(@types/react@18.2.21)(react@18.2.0) dev: false - /react-style-singleton@2.2.1(@types/react@18.0.15)(react@18.2.0): + /react-style-singleton@2.2.1(@types/react@18.2.21)(react@18.2.0): resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==} engines: {node: '>=10'} peerDependencies: @@ -3918,7 +4454,7 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.0.15 + '@types/react': 18.2.21 get-nonce: 1.0.1 invariant: 2.2.4 react: 18.2.0 @@ -3932,6 +4468,18 @@ packages: loose-envify: 1.4.0 dev: false + /reflect.getprototypeof@1.0.3: + resolution: {integrity: sha512-TTAOZpkJ2YLxl7mVHWrNo3iDMEkYlva/kgFcXndqMgbo/AZUmmavEkdXV+hXtE4P8xdyEKRzalaFqZVuwIk/Nw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.1 + get-intrinsic: 1.2.1 + globalthis: 1.0.3 + which-builtin-type: 1.1.3 + dev: true + /regenerator-runtime@0.13.9: resolution: {integrity: sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==} @@ -3940,13 +4488,17 @@ packages: engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.2 - define-properties: 1.1.4 + define-properties: 1.2.0 functions-have-names: 1.2.3 dev: true - /regexpp@3.2.0: - resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} - engines: {node: '>=8'} + /regexp.prototype.flags@1.5.0: + resolution: {integrity: sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + functions-have-names: 1.2.3 dev: true /remark-gemoji@7.0.1: @@ -3992,6 +4544,10 @@ packages: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} + /resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + dev: true + /resolve@1.22.1: resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} hasBin: true @@ -4004,7 +4560,7 @@ packages: resolution: {integrity: sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==} hasBin: true dependencies: - is-core-module: 2.9.0 + is-core-module: 2.13.0 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 dev: true @@ -4034,10 +4590,28 @@ packages: mri: 1.2.0 dev: false + /safe-array-concat@1.0.0: + resolution: {integrity: sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==} + engines: {node: '>=0.4'} + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.1 + has-symbols: 1.0.3 + isarray: 2.0.5 + dev: true + /safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} dev: false + /safe-regex-test@1.0.0: + resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.1 + is-regex: 1.1.4 + dev: true + /scheduler@0.23.0: resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} dependencies: @@ -4052,8 +4626,8 @@ packages: kind-of: 6.0.3 dev: false - /semver@6.3.0: - resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} + /semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true /semver@7.3.7: @@ -4080,7 +4654,7 @@ packages: resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} dependencies: call-bind: 1.0.2 - get-intrinsic: 1.1.2 + get-intrinsic: 1.2.1 object-inspect: 1.12.2 dev: true @@ -4107,33 +4681,47 @@ packages: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} dev: false - /string.prototype.matchall@4.0.7: - resolution: {integrity: sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==} + /streamsearch@1.1.0: + resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} + engines: {node: '>=10.0.0'} + dev: false + + /string.prototype.matchall@4.0.8: + resolution: {integrity: sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==} dependencies: call-bind: 1.0.2 define-properties: 1.1.4 - es-abstract: 1.20.1 - get-intrinsic: 1.1.2 + es-abstract: 1.22.1 + get-intrinsic: 1.2.1 has-symbols: 1.0.3 internal-slot: 1.0.3 regexp.prototype.flags: 1.4.3 side-channel: 1.0.4 dev: true - /string.prototype.trimend@1.0.5: - resolution: {integrity: sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==} + /string.prototype.trim@1.2.7: + resolution: {integrity: sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.1 + define-properties: 1.2.0 + es-abstract: 1.22.1 dev: true - /string.prototype.trimstart@1.0.5: - resolution: {integrity: sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==} + /string.prototype.trimend@1.0.6: + resolution: {integrity: sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==} dependencies: call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.1 + define-properties: 1.2.0 + es-abstract: 1.22.1 + dev: true + + /string.prototype.trimstart@1.0.6: + resolution: {integrity: sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + es-abstract: 1.22.1 dev: true /strip-ansi@6.0.1: @@ -4158,21 +4746,14 @@ packages: engines: {node: '>=8'} dev: true - /style-to-object@0.3.0: - resolution: {integrity: sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==} + /style-to-object@0.4.2: + resolution: {integrity: sha512-1JGpfPB3lo42ZX8cuPrheZbfQ6kqPPnPHlKMyeRYtfKD+0jG+QsXgXN57O/dvJlzlB2elI6dGmrPnl5VPQFPaA==} dependencies: inline-style-parser: 0.1.1 dev: false - /style-value-types@5.0.0: - resolution: {integrity: sha512-08yq36Ikn4kx4YU6RD7jWEv27v4V+PUsOGa4n/as8Et3CuODMJQ00ENeAVXAeydX4Z2j1XHZF1K2sX4mGl18fA==} - dependencies: - hey-listen: 1.0.8 - tslib: 2.4.0 - dev: false - - /styled-jsx@5.0.2(@babel/core@7.18.6)(react@18.2.0): - resolution: {integrity: sha512-LqPQrbBh3egD57NBcHET4qcgshPks+yblyhPlH2GY8oaDgKs8SK4C3dBh3oSJjgzJ3G5t1SYEZGHkP+QEpX9EQ==} + /styled-jsx@5.1.1(@babel/core@7.22.10)(react@18.2.0): + resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} engines: {node: '>= 12.0.0'} peerDependencies: '@babel/core': '*' @@ -4184,12 +4765,13 @@ packages: babel-plugin-macros: optional: true dependencies: - '@babel/core': 7.18.6 + '@babel/core': 7.22.10 + client-only: 0.0.1 react: 18.2.0 dev: false - /stylis@4.0.13: - resolution: {integrity: sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag==} + /stylis@4.2.0: + resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} dev: false /supports-color@5.5.0: @@ -4210,14 +4792,21 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - /swr@1.3.0(react@18.2.0): - resolution: {integrity: sha512-dkghQrOl2ORX9HYrMDtPa7LTVHJjCTeZoB1dqTbnnEDlSvN8JEKpYIYurDfvbQFUUS8Cg8PceFVZNkW0KNNYPw==} + /swr@2.2.1(react@18.2.0): + resolution: {integrity: sha512-KJVA7dGtOBeZ+2sycEuzUfVIP5lZ/cd0xjevv85n2YG0x1uHJQicjAtahVZL6xG3+TjqhbBqimwYzVo3saeVXQ==} peerDependencies: react: ^16.11.0 || ^17.0.0 || ^18.0.0 dependencies: + client-only: 0.0.1 react: 18.2.0 + use-sync-external-store: 1.2.0(react@18.2.0) dev: false + /tapable@2.2.1: + resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} + engines: {node: '>=6'} + dev: true + /text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true @@ -4242,10 +4831,6 @@ packages: resolution: {integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==} dev: false - /tr46@0.0.3: - resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - dev: false - /trim-lines@3.0.1: resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} dev: false @@ -4265,19 +4850,20 @@ packages: /tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + dev: true /tslib@2.4.0: resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} dev: false - /tsutils@3.21.0(typescript@4.7.4): + /tsutils@3.21.0(typescript@5.1.6): resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} peerDependencies: typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' dependencies: tslib: 1.14.1 - typescript: 4.7.4 + typescript: 5.1.6 dev: true /type-check@0.4.0: @@ -4292,9 +4878,47 @@ packages: engines: {node: '>=10'} dev: true - /typescript@4.7.4: - resolution: {integrity: sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==} - engines: {node: '>=4.2.0'} + /typed-array-buffer@1.0.0: + resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.1 + is-typed-array: 1.1.12 + dev: true + + /typed-array-byte-length@1.0.0: + resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + for-each: 0.3.3 + has-proto: 1.0.1 + is-typed-array: 1.1.12 + dev: true + + /typed-array-byte-offset@1.0.0: + resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.5 + call-bind: 1.0.2 + for-each: 0.3.3 + has-proto: 1.0.1 + is-typed-array: 1.1.12 + dev: true + + /typed-array-length@1.0.4: + resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} + dependencies: + call-bind: 1.0.2 + for-each: 0.3.3 + is-typed-array: 1.1.12 + dev: true + + /typescript@5.1.6: + resolution: {integrity: sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==} + engines: {node: '>=14.17'} hasBin: true dev: true @@ -4364,13 +4988,13 @@ packages: resolution: {integrity: sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==} dev: false - /update-browserslist-db@1.0.4(browserslist@4.21.2): - resolution: {integrity: sha512-jnmO2BEGUjsMOe/Fg9u0oczOe/ppIDZPebzccl1yDWGLFP16Pa1/RM5wEoKYPG2zstNcDuAStejyxsOuKINdGA==} + /update-browserslist-db@1.0.11(browserslist@4.21.10): + resolution: {integrity: sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' dependencies: - browserslist: 4.21.2 + browserslist: 4.21.10 escalade: 3.1.1 picocolors: 1.0.0 dev: false @@ -4381,7 +5005,7 @@ packages: punycode: 2.1.1 dev: true - /use-callback-ref@1.3.0(@types/react@18.0.15)(react@18.2.0): + /use-callback-ref@1.3.0(@types/react@18.2.21)(react@18.2.0): resolution: {integrity: sha512-3FT9PRuRdbB9HfXhEq35u4oZkvpJ5kuYbpqhCfmiZyReuRgpnhDlbr2ZEnnuS0RrJAPn6l23xjFg9kpDM+Ms7w==} engines: {node: '>=10'} peerDependencies: @@ -4391,12 +5015,12 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.0.15 + '@types/react': 18.2.21 react: 18.2.0 tslib: 2.4.0 dev: false - /use-sidecar@1.1.2(@types/react@18.0.15)(react@18.2.0): + /use-sidecar@1.1.2(@types/react@18.2.21)(react@18.2.0): resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==} engines: {node: '>=10'} peerDependencies: @@ -4406,14 +5030,14 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.0.15 + '@types/react': 18.2.21 detect-node-es: 1.1.0 react: 18.2.0 tslib: 2.4.0 dev: false - /use-sync-external-store@1.1.0(react@18.2.0): - resolution: {integrity: sha512-SEnieB2FPKEVne66NpXPd1Np4R1lTNKfjuy3XdIoPQKYBAFdzbzSZlSn1KJZUiihQLQC5Znot4SBz1EOTBwQAQ==} + /use-sync-external-store@1.2.0(react@18.2.0): + resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: @@ -4431,10 +5055,6 @@ packages: sade: 1.8.1 dev: false - /v8-compile-cache@2.3.0: - resolution: {integrity: sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==} - dev: true - /vfile-message@3.1.2: resolution: {integrity: sha512-QjSNP6Yxzyycd4SVOtmKKyTsSvClqBPJcd00Z0zuPj3hOIjg0rUPG6DbFGPvUKRgYyaIWLPKpuEclcuvb3H8qA==} dependencies: @@ -4451,15 +5071,12 @@ packages: vfile-message: 3.1.2 dev: false - /webidl-conversions@3.0.1: - resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - dev: false - - /whatwg-url@5.0.0: - resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + /watchpack@2.4.0: + resolution: {integrity: sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==} + engines: {node: '>=10.13.0'} dependencies: - tr46: 0.0.3 - webidl-conversions: 3.0.1 + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 dev: false /which-boxed-primitive@1.0.2: @@ -4472,6 +5089,44 @@ packages: is-symbol: 1.0.4 dev: true + /which-builtin-type@1.1.3: + resolution: {integrity: sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==} + engines: {node: '>= 0.4'} + dependencies: + function.prototype.name: 1.1.5 + has-tostringtag: 1.0.0 + is-async-function: 2.0.0 + is-date-object: 1.0.5 + is-finalizationregistry: 1.0.2 + is-generator-function: 1.0.10 + is-regex: 1.1.4 + is-weakref: 1.0.2 + isarray: 2.0.5 + which-boxed-primitive: 1.0.2 + which-collection: 1.0.1 + which-typed-array: 1.1.11 + dev: true + + /which-collection@1.0.1: + resolution: {integrity: sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==} + dependencies: + is-map: 2.0.2 + is-set: 2.0.2 + is-weakmap: 2.0.1 + is-weakset: 2.0.2 + dev: true + + /which-typed-array@1.1.11: + resolution: {integrity: sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.5 + call-bind: 1.0.2 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.0 + dev: true + /which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -4480,14 +5135,13 @@ packages: isexe: 2.0.0 dev: true - /word-wrap@1.2.3: - resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==} - engines: {node: '>=0.10.0'} - dev: true - /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + /yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + dev: false + /yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} dev: true @@ -4497,6 +5151,15 @@ packages: engines: {node: '>= 6'} dev: false + /yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + dev: true + + /zod@3.21.4: + resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==} + dev: false + /zwitch@2.0.2: resolution: {integrity: sha512-JZxotl7SxAJH0j7dN4pxsTV6ZLXoLdGME+PsjkL/DaBrVryK9kTGq06GfKrwcSOqypP+fdXGoCHE36b99fWVoA==} dev: false From 79a371f9b1159a194986d3673f7d09bfcacd3de2 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Thu, 14 Sep 2023 22:30:59 +0600 Subject: [PATCH 002/112] docs: update the getting-started guide --- website/posts/getting-started-with-spotube.md | 61 ++++++------------- 1 file changed, 18 insertions(+), 43 deletions(-) diff --git a/website/posts/getting-started-with-spotube.md b/website/posts/getting-started-with-spotube.md index e0da2574..249b5e57 100644 --- a/website/posts/getting-started-with-spotube.md +++ b/website/posts/getting-started-with-spotube.md @@ -1,7 +1,7 @@ --- title: Getting Started With Spotube cover_image: https://github.com/KRTirtho/spotube/raw/master/assets/spotube-screenshot.png -date: "July 16, 2022" +date: "September 14, 2023" author: Kingkor Roy Tirtho author_avatar_url: https://avatars.githubusercontent.com/u/61944859?v=4 tags: @@ -16,52 +16,27 @@ So installing Spotube is done. It’s a new app & although most of the things ca The most common issue with Spotube when someone uses it for the first is with its Login mechanism. Spotube is a Spotify client. And Spotify clients usually require *Premium Accounts* as the Spotify Server only allows premium accounts to download music. But **in Spotube you don’t need a Premium Account** -Since Spotube doesn’t require premium accounts it needs to special workarounds to supply the Music for Free. Thus, the Login mechanism in Spotube is a bit lengthy, but it’s actually more secure than any other Spotify Clients as the data stays in your Account & doesn’t need to go through a middleware unlike other Spotify Clients +### Android Login +It's super easy to login with Spotify account in Spotube Android version. Just tap on the "⚙️ Settings" > "Connect with Spotify" button & it'll navigate to official Spotify login page where user can enter their credentials safely & get logged in -Now, let’s get through the login Part. For Login, you’ll need two special things +### Desktop Login +Unfortunately, there's currently no way to run webview inside Flutter apps in desktop. Thus the user have to manually get the cookies from [accounts.spotify.com](https://accounts.spotify.com) +Just like Android, go to "⚙️ Settings" > "Connect with Spotify". Now it'll open a login page that accepts `sp_dc` & `sp_key` or `sp_gaid` cookie values +There's already a button named ***"Follow along the Step by Step guide"*** to open the tutorial on how to get these cookies +Although there's a tutorial available in the app, here's a quick guide on how to get these cookies -- Client ID -- Client Secret - -**What is a Client ID?** - -Client ID is kind of a Public key (ID) that is a unique identifier for the Spotify API client & is usually used to pair with Client Secret - -**What is a Client Secret?** - -A client secret is **a secret known only to the application instance and the authorization server**. It protects Spotify Data by only granting tokens to authorized requestors - -Now In Spotube, tap on the Settings Icon in the Sidebar/Bottom Bar & click on the **Login With Spotify** button. - -Now you’ll have to open a browser & have to go to [developers.spotify.com/dashboard](https://developers.spotify.com/dashboard) & press the Login button - -![step-1.png](https://rawcdn.githack.com/KRTirtho/spotube/0e10ddfa54113eb559308be1eb976b707dd7410c/assets/tutorial/step-1.png) - -After Login, create a Spotify Developer App by clicking on the CREATE AN APP button. Give the App a name & description & hit CREATE. Finally, the view will look somewhat similar to below - -![step-2.png](https://rawcdn.githack.com/KRTirtho/spotube/0e10ddfa54113eb559308be1eb976b707dd7410c/assets/tutorial/step-2.png) - -Now comes the **Most Important Part…** - -First Tap on the App to enter the dashboard page. In there, tap EDIT SETTINGS & a Dialog with multiple configuration will Open - -![step-3a.jpg](https://rawcdn.githack.com/KRTirtho/spotube/0e10ddfa54113eb559308be1eb976b707dd7410c/assets/tutorial/step-3a.jpg) - -Now find the **Redirect Uris** and type/paste `http://localhost:4304/auth/spotify/callback` in the field and press Add. Finally scroll down to the bottom section of the Dialog and press the SAVE button to save the changes - -![step-3b.jpg](https://rawcdn.githack.com/KRTirtho/spotube/0e10ddfa54113eb559308be1eb976b707dd7410c/assets/tutorial/step-3b.jpg) - -Now close the Dialog & see in the Left/Below of the EDIT SETTINGS button, there you’ll find **Client ID** and a SHOW CLIENT SECRET button. Copy the *Client ID* & paste it in the Spotube’s Text Field. Then tap/click on the SHOW CLIENT SECRET button to reveal the **Client Secret.** Finally, copy the **Client Secret** & paste it in the Spotube’s corresponding Text Field - -![step-4.jpg](https://rawcdn.githack.com/KRTirtho/spotube/0e10ddfa54113eb559308be1eb976b707dd7410c/assets/tutorial/step-4.jpg) - -Finally, press on the *Submit Button* which will open a Browser Window/Tab (desktop) or a Browser Application (android). Press/Click ALLOW button in that page & now you’re successfully Logged In with your Spotify Account in Spotube - -Close the Browser Tab (optional) & Go back to Spotube and Enjoy your lifetime (probably) free Music +1. Open [accounts.spotify.com](https://accounts.spotify.com) in your browser +1. Login with your Spotify account +1. Open the Developer Tools (F12) + 1. Chrome/Chrome-based browsers: Go to Application Tab + 1. Firefox: Go to Storage Tab +1. Find the Cookies section & copy the values of `sp_dc` & `sp_key` or `sp_gaid` cookies +1. Paste the values in the respective fields in Spotube & press the "Login" button +1. Done! You're logged in ## Playing Playlists & Tracks -You can play any playlists in the Home Screen of Spotube just by pressing the Play button of the playlist. But this is not just it. You can also play any playlist from starting from any track of the playlist and this available in all platform unlike Spotify which doesn't allow this kind stupid simple stuff in the Mobile App +You can play any playlists in the Home Screen of Spotube just by pressing the Play button of the playlist. But this is not just it. You can also play any playlist from starting from any track of the playlist and this available in all platform unlike Spotify which doesn't allow this kind stupid simple stuff in the Mobile App. Just tap on any Playlist's Cover Image & from the track list, tap the little Play button next to the track from which you want the playlist to start playing. ![Bpfau.png](https://s6.imgcdn.dev/Bpfau.png) @@ -69,7 +44,7 @@ Just tap on any Playlist's Cover Image & from the track list, tap the little Pla ## Sing along with any Song with **Synced Lyrics** just like Karaoke -Yes, Spotube support Synced Lyrics too (most of the popular English songs). So, if you wanna sing along with your favorite Music Track but don't know the Lyrics Spotube got you covered & now even you can sing along. Here's how, just play any playlist/album/track & press on the Lyrics Tab in the Sidebar (desktop/tablet) or Bottom Bar (mobile) & the Synced Lyrics will automatically start playing with the Audio Track +Yes, Spotube support Synced Lyrics too. So, if you wanna sing along with your favorite Music Track but don't know the Lyrics Spotube got you covered & now even you can sing along. Here's how, just play any playlist/album/track & press on the Lyrics Button in the Sidebar (desktop/tablet) or inside Player Page (mobile) & the Synced Lyrics will automatically start playing with the Audio Track ![BpttL.png](https://s6.imgcdn.dev/BpttL.png) From 12f3ec1776934326553280ac9a03f9f9d279ff1b Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 13 Dec 2024 00:17:19 +0600 Subject: [PATCH 003/112] downgrade: chose the path of ads --- website/package.json | 1 + website/pnpm-lock.yaml | 95 +++++++++++++++ website/posts/images/.gitkeep | 0 website/posts/spotube-basics.md | 1 + website/src/app.d.ts | 8 +- website/src/app.html | 3 + website/src/lib/components/ads/ads.svelte | 32 +++++ .../components/navbar/darkmode-toggle.svelte | 4 +- website/src/lib/index.ts | 115 ++++++++++++------ website/src/lib/posts.ts | 21 ++-- website/src/routes/+page.svelte | 5 + website/src/routes/blog/+page.svelte | 75 +++++++++--- website/src/routes/blog/+page.ts | 7 +- website/src/routes/blog/[slug]/+page.svelte | 26 ++-- website/src/routes/downloads/+page.svelte | 8 +- .../src/routes/downloads/packages/+page.svx | 18 +++ .../posts/images/spotube-basics/cover.jpg | Bin 0 -> 209177 bytes website/svelte.config.js | 20 +++ 18 files changed, 356 insertions(+), 83 deletions(-) delete mode 100644 website/posts/images/.gitkeep create mode 100644 website/src/lib/components/ads/ads.svelte create mode 100644 website/static/posts/images/spotube-basics/cover.jpg diff --git a/website/package.json b/website/package.json index acb9f507..b8095342 100644 --- a/website/package.json +++ b/website/package.json @@ -50,6 +50,7 @@ "highlight.js": "11.9.0", "lucide-svelte": "^0.323.0", "mdsvex-relative-images": "^1.0.3", + "rehype-auto-ads": "^1.2.0", "rehype-autolink-headings": "^7.1.0", "rehype-slug": "^6.0.0", "remark-container": "^0.1.2", diff --git a/website/pnpm-lock.yaml b/website/pnpm-lock.yaml index d2e9f5fe..7fa6b46c 100644 --- a/website/pnpm-lock.yaml +++ b/website/pnpm-lock.yaml @@ -32,6 +32,9 @@ importers: mdsvex-relative-images: specifier: ^1.0.3 version: 1.0.3 + rehype-auto-ads: + specifier: ^1.2.0 + version: 1.2.0 rehype-autolink-headings: specifier: ^7.1.0 version: 7.1.0 @@ -783,6 +786,9 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + commander@10.0.1: resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} engines: {node: '>=14'} @@ -873,6 +879,10 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + es6-promise@3.3.1: resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==} @@ -1069,15 +1079,27 @@ packages: resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==} engines: {node: '>= 0.4'} + hast-util-from-html@2.0.3: + resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==} + + hast-util-from-parse5@8.0.2: + resolution: {integrity: sha512-SfMzfdAi/zAoZ1KkFEyyeXBn7u/ShQrfd675ZEE9M3qj+PMFX05xubzRyF76CCSJu8au9jgVxDV1+okFvgZU4A==} + hast-util-heading-rank@3.0.0: resolution: {integrity: sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA==} hast-util-is-element@3.0.0: resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==} + hast-util-parse-selector@4.0.0: + resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} + hast-util-to-string@3.0.0: resolution: {integrity: sha512-OGkAxX1Ua3cbcW6EJ5pT/tslVb90uViVkcJ4ZZIMW/R33DX/AkcJcRrPebPwJkHYwlDHXz4aIwvAAaAdtrACFA==} + hastscript@9.0.0: + resolution: {integrity: sha512-jzaLBGavEDKHrc5EfFImKN7nZKKBdSLIdGvCwDZ9TfzbF2ffXiov8CKE445L2Z1Ek2t/m4SKQ2j6Ipv7NyUolw==} + highlight.js@11.9.0: resolution: {integrity: sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==} engines: {node: '>=12.0.0'} @@ -1467,6 +1489,9 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + parse5@7.2.1: + resolution: {integrity: sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -1609,6 +1634,9 @@ packages: resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==} engines: {node: '>=6'} + property-information@6.5.0: + resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -1634,6 +1662,9 @@ packages: resolution: {integrity: sha512-RSYAtP31mvYLkAHrOlh25pCNQ5hWnT106VukGaaFfuJrZFkGRX5GhUAdPqpSDXxOhA2c4akmRuplv1mRqnBn6Q==} engines: {node: '>=8'} + rehype-auto-ads@1.2.0: + resolution: {integrity: sha512-w0ysjJQginhKai13wcUF/4t1fu3UvPsVt4Y3htGGGs6ojA+J5Nz01I1NOqwrOhgSoT5Bfv7Mihww6tmtV108+g==} + rehype-autolink-headings@7.1.0: resolution: {integrity: sha512-rItO/pSdvnvsP4QRB1pmPiNHUskikqtPojZKJPPPAVx9Hj8i8TwMBhofrrAYRhYOOBZH9tgmG5lPqDLuIWPWmw==} @@ -1960,6 +1991,9 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + vfile-location@5.0.3: + resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} + vfile-message@2.0.4: resolution: {integrity: sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==} @@ -2016,6 +2050,9 @@ packages: vite: optional: true + web-namespaces@2.0.1: + resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -2660,6 +2697,8 @@ snapshots: color-name@1.1.4: {} + comma-separated-tokens@2.0.3: {} + commander@10.0.1: {} commander@4.1.1: {} @@ -2725,6 +2764,8 @@ snapshots: emoji-regex@9.2.2: {} + entities@4.5.0: {} + es6-promise@3.3.1: {} esbuild@0.19.12: @@ -2982,6 +3023,26 @@ snapshots: dependencies: function-bind: 1.1.2 + hast-util-from-html@2.0.3: + dependencies: + '@types/hast': 3.0.4 + devlop: 1.1.0 + hast-util-from-parse5: 8.0.2 + parse5: 7.2.1 + vfile: 6.0.1 + vfile-message: 4.0.2 + + hast-util-from-parse5@8.0.2: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.2 + devlop: 1.1.0 + hastscript: 9.0.0 + property-information: 6.5.0 + vfile: 6.0.1 + vfile-location: 5.0.3 + web-namespaces: 2.0.1 + hast-util-heading-rank@3.0.0: dependencies: '@types/hast': 3.0.4 @@ -2990,10 +3051,22 @@ snapshots: dependencies: '@types/hast': 3.0.4 + hast-util-parse-selector@4.0.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-to-string@3.0.0: dependencies: '@types/hast': 3.0.4 + hastscript@9.0.0: + dependencies: + '@types/hast': 3.0.4 + comma-separated-tokens: 2.0.3 + hast-util-parse-selector: 4.0.0 + property-information: 6.5.0 + space-separated-tokens: 2.0.2 + highlight.js@11.9.0: {} ignore@5.3.1: {} @@ -3510,6 +3583,10 @@ snapshots: dependencies: callsites: 3.1.0 + parse5@7.2.1: + dependencies: + entities: 4.5.0 + path-exists@4.0.0: {} path-is-absolute@1.0.1: {} @@ -3617,6 +3694,8 @@ snapshots: prismjs@1.29.0: {} + property-information@6.5.0: {} + punycode@2.3.1: {} purgecss@6.0.0-alpha.0: @@ -3640,6 +3719,15 @@ snapshots: regexparam@3.0.0: {} + rehype-auto-ads@1.2.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-from-html: 2.0.3 + hast-util-is-element: 3.0.0 + unified: 11.0.4 + unist-util-visit-parents: 6.0.1 + vfile: 6.0.1 + rehype-autolink-headings@7.1.0: dependencies: '@types/hast': 3.0.4 @@ -4072,6 +4160,11 @@ snapshots: util-deprecate@1.0.2: {} + vfile-location@5.0.3: + dependencies: + '@types/unist': 3.0.2 + vfile: 6.0.1 + vfile-message@2.0.4: dependencies: '@types/unist': 2.0.10 @@ -4119,6 +4212,8 @@ snapshots: optionalDependencies: vite: 5.1.0(@types/node@20.11.16) + web-namespaces@2.0.1: {} + which@2.0.2: dependencies: isexe: 2.0.0 diff --git a/website/posts/images/.gitkeep b/website/posts/images/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/website/posts/spotube-basics.md b/website/posts/spotube-basics.md index 841fbac9..43a33d67 100644 --- a/website/posts/spotube-basics.md +++ b/website/posts/spotube-basics.md @@ -3,6 +3,7 @@ title: Spotube Basics author: Kingkor Roy Tirtho date: 2024-02-10 published: true +cover_img: /images/spotube-basics/cover.jpg --- Spotube is an open-source Spotify client that allows users to stream music from Spotify. To use Spotube, you need to sign in with your Spotify account. Here's a step-by-step guide on how to sign in to Spotube. diff --git a/website/src/app.d.ts b/website/src/app.d.ts index c627dc68..c2f2a735 100644 --- a/website/src/app.d.ts +++ b/website/src/app.d.ts @@ -17,6 +17,10 @@ declare namespace App { } } -declare module '@fortawesome/pro-solid-svg-icons/index.es' { - export * from '@fortawesome/pro-solid-svg-icons'; +declare namespace globalThis { + declare var adsbygoogle: any[]; +} + +declare module "@fortawesome/pro-solid-svg-icons/index.es" { + export * from "@fortawesome/pro-solid-svg-icons"; } diff --git a/website/src/app.html b/website/src/app.html index 088ddd5d..470db728 100644 --- a/website/src/app.html +++ b/website/src/app.html @@ -13,6 +13,9 @@ + + %sveltekit.head% diff --git a/website/src/lib/components/ads/ads.svelte b/website/src/lib/components/ads/ads.svelte new file mode 100644 index 00000000..54cfc2c0 --- /dev/null +++ b/website/src/lib/components/ads/ads.svelte @@ -0,0 +1,32 @@ + + + diff --git a/website/src/lib/components/navbar/darkmode-toggle.svelte b/website/src/lib/components/navbar/darkmode-toggle.svelte index ec4f757c..d05622f9 100644 --- a/website/src/lib/components/navbar/darkmode-toggle.svelte +++ b/website/src/lib/components/navbar/darkmode-toggle.svelte @@ -17,10 +17,8 @@
- {#if label} - - {/if} = { - '/': ['Home', Home], - '/blog': ['Blog', Newspaper], - '/downloads': ['Downloads', Download], - '/about': ['About', null] + "/": ["Home", Home], + "/blog": ["Blog", Newspaper], + "/downloads": ["Downloads", Download], + "/about": ["About", null], }; -const releasesUrl = 'https://github.com/KRTirtho/Spotube/releases/latest/download'; +const releasesUrl = + "https://github.com/KRTirtho/Spotube/releases/latest/download"; export const downloadLinks: Record = { - 'Android Apk': [`${releasesUrl}/Spotube-android-all-arch.apk`, [faAndroid]], - 'Windows Executable': [`${releasesUrl}/Spotube-windows-x86_64-setup.exe`, [faWindows]], - 'macOS Dmg': [`${releasesUrl}/Spotube-macos-universal.dmg`, [faApple]], - 'Ubuntu, Debian': [`${releasesUrl}/Spotube-linux-x86_64.deb`, [faUbuntu, faDebian]], - 'Fedora, Redhat, Opensuse': [ - `${releasesUrl}/Spotube-linux-x86_64.rpm`, - [faFedora, faRedhat, faOpensuse] + "Android Apk": [`${releasesUrl}/Spotube-android-all-arch.apk`, [faAndroid]], + "Windows Executable": [ + `${releasesUrl}/Spotube-windows-x86_64-setup.exe`, + [faWindows], ], - 'iPhone Ipa': [`${releasesUrl}/Spotube-iOS.ipa`, [faApple]] -}; - -export const extendedDownloadLinks: Record = { - Android: [`${releasesUrl}/Spotube-android-all-arch.apk`, [faAndroid], 'apk'], - Windows: [`${releasesUrl}/Spotube-windows-x86_64-setup.exe`, [faWindows], 'exe'], - macOS: [`${releasesUrl}/Spotube-macos-universal.dmg`, [faApple], 'dmg'], - 'Ubuntu, Debian': [`${releasesUrl}/Spotube-linux-x86_64.deb`, [faUbuntu, faDebian], 'deb'], - 'Fedora, Redhat, Opensuse': [ + "macOS Dmg": [`${releasesUrl}/Spotube-macos-universal.dmg`, [faApple]], + "Ubuntu, Debian": [ + `${releasesUrl}/Spotube-linux-x86_64.deb`, + [faUbuntu, faDebian], + ], + "Fedora, Redhat, Opensuse": [ `${releasesUrl}/Spotube-linux-x86_64.rpm`, [faFedora, faRedhat, faOpensuse], - 'rpm' ], - iPhone: [`${releasesUrl}/Spotube-iOS.ipa`, [faApple], 'ipa'] + "iPhone Ipa": [`${releasesUrl}/Spotube-iOS.ipa`, [faApple]], }; -const nightlyReleaseUrl = 'https://github.com/KRTirtho/Spotube/releases/download/nightly'; +export const extendedDownloadLinks: Record< + string, + [string, IconDefinition[], string] +> = { + Android: [`${releasesUrl}/Spotube-android-all-arch.apk`, [faAndroid], "apk"], + Windows: [ + `${releasesUrl}/Spotube-windows-x86_64-setup.exe`, + [faWindows], + "exe", + ], + macOS: [`${releasesUrl}/Spotube-macos-universal.dmg`, [faApple], "dmg"], + "Ubuntu, Debian": [ + `${releasesUrl}/Spotube-linux-x86_64.deb`, + [faUbuntu, faDebian], + "deb", + ], + "Fedora, Redhat, Opensuse": [ + `${releasesUrl}/Spotube-linux-x86_64.rpm`, + [faFedora, faRedhat, faOpensuse], + "rpm", + ], + iPhone: [`${releasesUrl}/Spotube-iOS.ipa`, [faApple], "ipa"], +}; -export const extendedNightlyDownloadLinks: Record = { - Android: [`${nightlyReleaseUrl}/Spotube-android-all-arch.apk`, [faAndroid], 'apk'], - Windows: [`${nightlyReleaseUrl}/Spotube-windows-x86_64-setup.exe`, [faWindows], 'exe'], - macOS: [`${nightlyReleaseUrl}/Spotube-macos-universal.dmg`, [faApple], 'dmg'], - 'Ubuntu, Debian': [`${nightlyReleaseUrl}/Spotube-linux-x86_64.deb`, [faUbuntu, faDebian], 'deb'], - 'Fedora, Redhat, Opensuse': [ +const nightlyReleaseUrl = + "https://github.com/KRTirtho/Spotube/releases/download/nightly"; + +export const extendedNightlyDownloadLinks: Record< + string, + [string, IconDefinition[], string] +> = { + Android: [ + `${nightlyReleaseUrl}/Spotube-android-all-arch.apk`, + [faAndroid], + "apk", + ], + Windows: [ + `${nightlyReleaseUrl}/Spotube-windows-x86_64-setup.exe`, + [faWindows], + "exe", + ], + macOS: [`${nightlyReleaseUrl}/Spotube-macos-universal.dmg`, [faApple], "dmg"], + "Ubuntu, Debian": [ + `${nightlyReleaseUrl}/Spotube-linux-x86_64.deb`, + [faUbuntu, faDebian], + "deb", + ], + "Fedora, Redhat, Opensuse": [ `${nightlyReleaseUrl}/Spotube-linux-x86_64.rpm`, [faFedora, faRedhat, faOpensuse], - 'rpm' + "rpm", ], - iPhone: [`${nightlyReleaseUrl}/Spotube-iOS.ipa`, [faApple], 'ipa'] + iPhone: [`${nightlyReleaseUrl}/Spotube-iOS.ipa`, [faApple], "ipa"], }; + +export const ADS_SLOTS = Object.freeze({ + rootPageDisplay: 5979549631, + blogPageInFeed: 3386010031, + downloadPageDisplay: 9521642154, + packagePageArticle: 9119323068, + // This is being used for rehype-auto-ads in svelte.config.js + blogArticlePageArticle: 6788673194, +}); diff --git a/website/src/lib/posts.ts b/website/src/lib/posts.ts index 02fa3d07..b46c49eb 100644 --- a/website/src/lib/posts.ts +++ b/website/src/lib/posts.ts @@ -4,6 +4,7 @@ export interface Post { tags: string[]; published: boolean; author: string; + cover_img: string | null; readingTime: { text: string; minutes: number; @@ -21,21 +22,23 @@ export interface Post { export const getPosts = async () => { // Fetch posts from local Markdown files const posts: Post[] = await Promise.all( - Object.entries(import.meta.glob('../../posts/**/*.md')).map(async ([path, resolver]) => { - const resolved = (await resolver()) as { metadata: Post }; - const { metadata } = resolved; - const slug = path.split('/').pop()?.slice(0, -3) ?? ''; - return { ...metadata, slug }; - }) - ); + Object.entries(import.meta.glob("../../posts/**/*.md")).map( + async ([path, resolver]) => { + const resolved = (await resolver()) as { metadata: Post }; + const { metadata } = resolved; + const slug = path.split("/").pop()?.slice(0, -3) ?? ""; + return { ...metadata, slug }; + }, + ), + ).then((posts) => posts.filter((post) => post.published)); let sortedPosts = posts.sort((a, b) => +new Date(b.date) - +new Date(a.date)); sortedPosts = sortedPosts.map((post) => ({ - ...post + ...post, })); return { - posts: sortedPosts + posts: sortedPosts, }; }; diff --git a/website/src/routes/+page.svelte b/website/src/routes/+page.svelte index 7fe0a36f..7e26b4c2 100644 --- a/website/src/routes/+page.svelte +++ b/website/src/routes/+page.svelte @@ -10,6 +10,8 @@ import { Download, Heart } from 'lucide-svelte'; import type { PageData } from './$types'; import { Avatar } from '@skeletonlabs/skeleton'; + import Ads from '$lib/components/ads/ads.svelte'; + import { ADS_SLOTS } from '$lib'; export let data: PageData; @@ -75,6 +77,8 @@
+ +

@@ -111,4 +115,5 @@ {/each} + diff --git a/website/src/routes/blog/+page.svelte b/website/src/routes/blog/+page.svelte index 5ee98938..c800c63c 100644 --- a/website/src/routes/blog/+page.svelte +++ b/website/src/routes/blog/+page.svelte @@ -1,4 +1,7 @@

Blog Posts


-
diff --git a/website/src/routes/blog/+page.ts b/website/src/routes/blog/+page.ts index c48ac87f..fca1bb62 100644 --- a/website/src/routes/blog/+page.ts +++ b/website/src/routes/blog/+page.ts @@ -1,11 +1,10 @@ -import type { Post } from '$lib/posts.js'; +import type { Post } from "$lib/posts.js"; export const load = async ({ fetch }) => { - const res = await fetch(`api/posts`); + const res = await fetch("api/posts"); if (res.ok) { const posts: Post[] = await res.json(); return { posts }; - } else { - return { posts: [] }; } + return { posts: [] }; }; diff --git a/website/src/routes/blog/[slug]/+page.svelte b/website/src/routes/blog/[slug]/+page.svelte index 1931a991..444c3a4a 100644 --- a/website/src/routes/blog/[slug]/+page.svelte +++ b/website/src/routes/blog/[slug]/+page.svelte @@ -3,9 +3,9 @@ import type { PageData } from './$types'; export let data: PageData; - let { + const { Content, - meta: { date, title, readingTime } + meta: { date, title, readingTime, cover_img } } = data as Required; @@ -14,13 +14,19 @@
-

{title}

+
+

{title}

+
+

{new Date(date).toDateString()}

+

{readingTime?.text ?? ''}

+

-
-

{new Date(date).toDateString()}

-

{readingTime?.text ?? ''}

- - - -
+ + +
diff --git a/website/src/routes/downloads/+page.svelte b/website/src/routes/downloads/+page.svelte index 50d101ee..9ee994c8 100644 --- a/website/src/routes/downloads/+page.svelte +++ b/website/src/routes/downloads/+page.svelte @@ -1,8 +1,9 @@ -
+

Download @@ -22,7 +23,7 @@ -


+

Other Downloads



@@ -36,4 +37,5 @@ {/each} +

diff --git a/website/src/routes/downloads/packages/+page.svx b/website/src/routes/downloads/packages/+page.svx index 0ab570c2..f10c3989 100644 --- a/website/src/routes/downloads/packages/+page.svx +++ b/website/src/routes/downloads/packages/+page.svx @@ -6,6 +6,8 @@ author: Kingkor Roy Tirtho
@@ -40,6 +42,14 @@ $ pamac install spotube-bin $ paru -Sy spotube-bin ``` + + ## MacOS ### Homebrew🍻 @@ -51,6 +61,14 @@ $ brew tap krtirtho/apps $ brew install --cask spotube ``` + + ## Windows ### Chocolatey🍫 diff --git a/website/static/posts/images/spotube-basics/cover.jpg b/website/static/posts/images/spotube-basics/cover.jpg new file mode 100644 index 0000000000000000000000000000000000000000..603b3dda2521f03f955a4eac64c3dce7bba701e7 GIT binary patch literal 209177 zcmb@tdt6#)x-b5&#YL_L0SRJs0Fj_#0%S>zsWXd<1{G5@#!XD88$k^i%&ktQwWo6y zCXXh*J$9F1s zD0YJ9zw^rRcH5E8UZJ(~u;Xa8_<#Q7=VGCwqgwn|6^)9<2V%?x$2c_@i&cE;pbo9-YFJ-Q>6Duwb=ah)sMw(plWLs$G+EFEygK-)1|uOy*32zWz8%2 z&3|tmFKzp#@t1o$cK)XVJ5>rrWw}CCuG;-|&%ddE+l zO`Tr6{LbE!?T(|J9UAB1V<#QG_8y0=v9rU`{{KPh|6ekH8DW*~Bu*Hg#m4rIPT}|Q zz6kdoJ9gOFDb&=7cjD{0^WPWr>(jq*#tYlplSW~FeFGv8iDVL)Mkdqnd(8iOZ27O3|JSQO zCqNE`f^SCxBnEH}M96{uoCE~`zsCQ*-n{>QKrn$wB4<&k_~RB9fMEzClCmfiA_*n| zI)LCD0-Hz@Dao3q_7hngvC1_TD$+JvPsSHkD3V<-kB8^}nd`p#TSV8p_<634x4-}5 zYVpL)haJ?d6)p38yw&`Fqxhd_;;nu|6o07B!SCZl2{0KSGYrFoZ%8UdM7BoNMB<3s zPmH;CX+zwi<~XuI{;g!?pRKunegGKwIPk9JfbW3+rxT%`;bsK`=h_AkFDd?y7DBq> zxd(zNcjEdb_0Gy9p?uU>5sR@hBU9=GaCTew+d#fxYWKI(EW7i|*oO%@a;QSR{kaDq zD}H6P(LV|@A1+;ah6#zE-h5v{g9TIFR=h%{+mf(!w_65L_1VlJ8Cv6PJYx-QJZl@g zf^9%0@y{$(OyWOU=Dxj>7N)mve^6~CmTftF<(c>G2LvOcEq~^A_Hql!i!B0YgbowTG{%^kN>YwW4Cgv=i^gV z)|ocVbDSk_29NN!dNrK?j=V4f-B=!4|1tK|)w5LC|GFr0g_nuGQTMKIwa~lnu$ho> zfH`O2Hr5Ck^KWQ^5~2r~c6cSeMJkZ^qPecga zjYAo!G~vYAwE6Y0(Q=6Ql{S-3()UxApPhF1>pG9kmp>bkqgTAw6*{QyYc>Od{OT9x z+wirOIkuqZe{<~C5I*s`K;idr zhH@#HGk3oF>%Vv7Uq5X{63*xU?%G!i9j}MlEn5yfVLDsEmP1?5zaFGecK>YUv)98h zBjd}Tr9b?t#%6~;dp(GAz1c+g;*I%z$L0a~?)%@yN!|HMGqe<%`|zv!{Wuj-u-bFx zS?r59u6>nEv_bc9njho6V@(yV&3>gj^n?XDzhN;qTAp|0^@|^VrJvgD%f~lz;fZGx zw%E!h-tFvT^C&5PY(D?>&}BISPdq97AwI4;tnlXTuYMryyFW@ItNiONG}_xGR{CPmcW35chc+AXwHgvSH-vxG!oRx9|Dg}4W- zbTf5MdEkO38jMfp=e0_cKcFg37I?70Ou>i)`{!0HXtXs64~%97hM{@FA8M?f=9w+R z%WYnsP`=H*pddvnPJ4yJ1*aF3Zlkjm5%UO5f|RmsH|2pF>v;?NqB9sMEch=0_;oXl(Z+(!rB#jjOcWXNrEOSQT!79wQ6dDB_IY( zX1@96z0->~TfDAUV{6&%?~(&eoWOl1!Nl=hCOjaqA0j*fDR?qPv8MOAp6?_SzVr6I z;d|3&#UBi&tdV#5i`%G86*Rb`Ol{Z)GZKFfKIeQQ%=+{u`Xw+T-hd_~Tm6oDKxx1K zY4Y>4-fCXv)%dGdPbgY5kBcvkMfQo)ADwRMBYr}j+#~SKyY6sU8}cm+X7fUDwK?@VhxW+4G!rIOuOcZM_4;tX_QE$h0Gk7s0 zsI8zkY0$bg!BCK}FSxd!sKUR$OQMJj@^p)0RA+oQPqag0qZN(_=Ozk#W0nI$H)~tB zi)ZL?xo(ZOhhMIVvYuj+n@xr`Omv$�LAcMyHi>l39~Bjj9F1xs0KOczUz8l>o#s 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 (A1f!h5+G08T0&x~nkfeqE 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 + + `, + paragraphInterval: 2, + maxAds: 5, + } ] ] }) From f28fe5a682138bf755ab13ff1cdd06872bfc3fa7 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 13 Dec 2024 00:39:23 +0600 Subject: [PATCH 004/112] fix: no spacing from the ads --- .../src/lib/components/markdown/layout.svelte | 2 +- website/src/routes/+page.svelte | 166 ++++++++++-------- website/src/routes/blog/[slug]/+page.svelte | 2 +- website/src/routes/downloads/+page.svelte | 5 +- website/svelte.config.js | 2 + 5 files changed, 97 insertions(+), 80 deletions(-) diff --git a/website/src/lib/components/markdown/layout.svelte b/website/src/lib/components/markdown/layout.svelte index 54426420..a8a13182 100644 --- a/website/src/lib/components/markdown/layout.svelte +++ b/website/src/lib/components/markdown/layout.svelte @@ -1,3 +1,3 @@ -
+
diff --git a/website/src/routes/+page.svelte b/website/src/routes/+page.svelte index 7e26b4c2..53dbce4c 100644 --- a/website/src/routes/+page.svelte +++ b/website/src/routes/+page.svelte @@ -33,87 +33,99 @@ -
- - - - - - -

- -

- Supporters - -

-

- We are grateful for the support of individuals and organizations who have made Spotube possible. -

- -
- - Open Collective - -
- - + +
+ +
+ +
+

+ Supporters + +

+

+ We are grateful for the support of individuals and organizations who have made Spotube + possible. +

+
+ + Open Collective + +
+ +
+
diff --git a/website/src/routes/blog/[slug]/+page.svelte b/website/src/routes/blog/[slug]/+page.svelte index 444c3a4a..c6c3e2cb 100644 --- a/website/src/routes/blog/[slug]/+page.svelte +++ b/website/src/routes/blog/[slug]/+page.svelte @@ -13,7 +13,7 @@ Blog | {title} -
+
+
+

Other Downloads



@@ -37,5 +39,6 @@ {/each}
- +
+
diff --git a/website/svelte.config.js b/website/svelte.config.js index 2fd859f4..cecec177 100644 --- a/website/svelte.config.js +++ b/website/svelte.config.js @@ -44,6 +44,7 @@ const config = { rehypeAutoAds, { adCode: ` +
+
From f524a400625270e050262e35092ed82a37b46f2a Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 13 Dec 2024 00:43:17 +0600 Subject: [PATCH 005/112] chore: flex view --- website/src/routes/+layout.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/src/routes/+layout.svelte b/website/src/routes/+layout.svelte index 6908b77a..92768c73 100644 --- a/website/src/routes/+layout.svelte +++ b/website/src/routes/+layout.svelte @@ -31,7 +31,7 @@ const drawerStore = getDrawerStore(); -
+
{#if $drawerStore.id === 'navdrawer'} From 08f624ece113da15fdfcc8d1c031b11265a2834f Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 14 Dec 2024 09:52:53 +0600 Subject: [PATCH 006/112] chore: upgrade to flutter 3.27.0 and fix gradle errors --- .fvm/fvm_config.json | 2 +- .fvmrc | 2 +- .github/workflows/pr-lint.yml | 2 +- .github/workflows/spotube-release-binary.yml | 2 +- android/app/build.gradle | 8 +- .../res/mipmap-anydpi-v26/ic_launcher.xml | 6 +- .../gradle/wrapper/gradle-wrapper.properties | 4 +- android/settings.gradle | 2 +- flutter_launcher_icons-stable.yaml | 13 -- flutter_launcher_icons.yaml | 29 +++ .../AppIcon-nightly.appiconset/Contents.json | 2 +- pubspec.lock | 177 +++++++++--------- pubspec.yaml | 7 +- 13 files changed, 145 insertions(+), 111 deletions(-) delete mode 100644 flutter_launcher_icons-stable.yaml create mode 100644 flutter_launcher_icons.yaml diff --git a/.fvm/fvm_config.json b/.fvm/fvm_config.json index 7f89fed4..e20d18ad 100644 --- a/.fvm/fvm_config.json +++ b/.fvm/fvm_config.json @@ -1,3 +1,3 @@ { - "flutterSdkVersion": "3.24.5" + "flutterSdkVersion": "3.27.0" } \ No newline at end of file diff --git a/.fvmrc b/.fvmrc index 679f8e11..34136bbd 100644 --- a/.fvmrc +++ b/.fvmrc @@ -1,4 +1,4 @@ { - "flutter": "3.24.5", + "flutter": "3.27.0", "flavors": {} } \ No newline at end of file diff --git a/.github/workflows/pr-lint.yml b/.github/workflows/pr-lint.yml index 23e5cc74..b5afbc9e 100644 --- a/.github/workflows/pr-lint.yml +++ b/.github/workflows/pr-lint.yml @@ -4,7 +4,7 @@ on: pull_request: env: - FLUTTER_VERSION: 3.24.5 + FLUTTER_VERSION: 3.27.0 jobs: lint: diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index 89c2fedd..c27a3463 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -20,7 +20,7 @@ on: description: Dry run without uploading to release env: - FLUTTER_VERSION: 3.24.5 + FLUTTER_VERSION: 3.27.0 permissions: contents: write diff --git a/android/app/build.gradle b/android/app/build.gradle index 8ec1872e..047512f4 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -29,9 +29,11 @@ if (keystorePropertiesFile.exists()) { } android { - compileSdkVersion 34 + namespace "dev.krtirtho.spotube" + + compileSdkVersion 35 - ndkVersion "25.1.8937393" + ndkVersion "26.1.10909125" compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 @@ -49,7 +51,7 @@ android { defaultConfig { applicationId "oss.krtirtho.spotube" minSdkVersion 24 - targetSdkVersion 34 + targetSdkVersion 35 versionCode flutterVersionCode.toInteger() versionName flutterVersionName multiDexEnabled true diff --git a/android/app/src/nightly/res/mipmap-anydpi-v26/ic_launcher.xml b/android/app/src/nightly/res/mipmap-anydpi-v26/ic_launcher.xml index 5f349f7f..c79c58a3 100644 --- a/android/app/src/nightly/res/mipmap-anydpi-v26/ic_launcher.xml +++ b/android/app/src/nightly/res/mipmap-anydpi-v26/ic_launcher.xml @@ -1,5 +1,9 @@ - + + + diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 02e5f581..bf6b7385 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Fri Jun 23 08:50:38 CEST 2017 +#Fri Dec 13 21:53:13 BDT 2024 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zip diff --git a/android/settings.gradle b/android/settings.gradle index 89651748..a1961f52 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -18,7 +18,7 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "7.2.1" apply false + id "com.android.application" version "8.7.0" apply false id "org.jetbrains.kotlin.android" version "1.8.22" apply false } diff --git a/flutter_launcher_icons-stable.yaml b/flutter_launcher_icons-stable.yaml deleted file mode 100644 index 0d205cbd..00000000 --- a/flutter_launcher_icons-stable.yaml +++ /dev/null @@ -1,13 +0,0 @@ -flutter_launcher_icons: - ios: true - android: true - image_path: "assets/spotube-logo.png" - adaptive_icon_foreground: "assets/spotube-logo-foreground.jpg" - adaptive_icon_background: "#242832" - windows: - generate: true - image_path: "assets/spotube-logo.png" - icon_size: 48 # min:48, max:256, default: 48 - macos: - generate: true - image_path: "assets/spotube-logo-macos.png" diff --git a/flutter_launcher_icons.yaml b/flutter_launcher_icons.yaml new file mode 100644 index 00000000..372117b1 --- /dev/null +++ b/flutter_launcher_icons.yaml @@ -0,0 +1,29 @@ +# flutter pub run flutter_launcher_icons +flutter_launcher_icons: + image_path: "assets/spotube-logo.png" + + android: true + # image_path_android: "assets/icon/icon.png" + min_sdk_android: 21 # android min sdk min:16, default 21 + adaptive_icon_background: "#242832" + adaptive_icon_foreground: "assets/spotube-logo-foreground.jpg" + # adaptive_icon_monochrome: "assets/icon/monochrome.png" + + ios: true + # image_path_ios: "assets/icon/icon.png" + remove_alpha_channel_ios: true + # image_path_ios_dark_transparent: "assets/icon/icon_dark.png" + # image_path_ios_tinted_grayscale: "assets/icon/icon_tinted.png" + # desaturate_tinted_to_grayscale_ios: true + + web: + generate: false + + windows: + generate: true + image_path: "assets/spotube-logo.png" + icon_size: 48 # min:48, max:256, default: 48 + + macos: + generate: true + image_path: "assets/spotube-logo-macos.png" diff --git a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/Contents.json b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/Contents.json index e8947587..1ce0f517 100644 --- a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/Contents.json +++ b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/Contents.json @@ -1 +1 @@ -{"images":[{"size":"20x20","idiom":"iphone","filename":"AppIcon-nightly-20x20@2x.png","scale":"2x"},{"size":"20x20","idiom":"iphone","filename":"AppIcon-nightly-20x20@3x.png","scale":"3x"},{"size":"29x29","idiom":"iphone","filename":"AppIcon-nightly-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"iphone","filename":"AppIcon-nightly-29x29@2x.png","scale":"2x"},{"size":"29x29","idiom":"iphone","filename":"AppIcon-nightly-29x29@3x.png","scale":"3x"},{"size":"40x40","idiom":"iphone","filename":"AppIcon-nightly-40x40@2x.png","scale":"2x"},{"size":"40x40","idiom":"iphone","filename":"AppIcon-nightly-40x40@3x.png","scale":"3x"},{"size":"50x50","idiom":"ipad","filename":"AppIcon-nightly-50x50@1x.png","scale":"1x"},{"size":"50x50","idiom":"ipad","filename":"AppIcon-nightly-50x50@2x.png","scale":"2x"},{"size":"57x57","idiom":"iphone","filename":"AppIcon-nightly-57x57@1x.png","scale":"1x"},{"size":"57x57","idiom":"iphone","filename":"AppIcon-nightly-57x57@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"AppIcon-nightly-60x60@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"AppIcon-nightly-60x60@3x.png","scale":"3x"},{"size":"20x20","idiom":"ipad","filename":"AppIcon-nightly-20x20@1x.png","scale":"1x"},{"size":"20x20","idiom":"ipad","filename":"AppIcon-nightly-20x20@2x.png","scale":"2x"},{"size":"29x29","idiom":"ipad","filename":"AppIcon-nightly-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"ipad","filename":"AppIcon-nightly-29x29@2x.png","scale":"2x"},{"size":"40x40","idiom":"ipad","filename":"AppIcon-nightly-40x40@1x.png","scale":"1x"},{"size":"40x40","idiom":"ipad","filename":"AppIcon-nightly-40x40@2x.png","scale":"2x"},{"size":"72x72","idiom":"ipad","filename":"AppIcon-nightly-72x72@1x.png","scale":"1x"},{"size":"72x72","idiom":"ipad","filename":"AppIcon-nightly-72x72@2x.png","scale":"2x"},{"size":"76x76","idiom":"ipad","filename":"AppIcon-nightly-76x76@1x.png","scale":"1x"},{"size":"76x76","idiom":"ipad","filename":"AppIcon-nightly-76x76@2x.png","scale":"2x"},{"size":"83.5x83.5","idiom":"ipad","filename":"AppIcon-nightly-83.5x83.5@2x.png","scale":"2x"},{"size":"1024x1024","idiom":"ios-marketing","filename":"AppIcon-nightly-1024x1024@1x.png","scale":"1x"}],"info":{"version":1,"author":"xcode"}} \ No newline at end of file +{"images":[{"size":"20x20","idiom":"iphone","filename":"AppIcon-nightly-20x20@2x.png","scale":"2x"},{"size":"20x20","idiom":"iphone","filename":"AppIcon-nightly-20x20@3x.png","scale":"3x"},{"size":"29x29","idiom":"iphone","filename":"AppIcon-nightly-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"iphone","filename":"AppIcon-nightly-29x29@2x.png","scale":"2x"},{"size":"29x29","idiom":"iphone","filename":"AppIcon-nightly-29x29@3x.png","scale":"3x"},{"size":"40x40","idiom":"iphone","filename":"AppIcon-nightly-40x40@2x.png","scale":"2x"},{"size":"40x40","idiom":"iphone","filename":"AppIcon-nightly-40x40@3x.png","scale":"3x"},{"size":"57x57","idiom":"iphone","filename":"AppIcon-nightly-57x57@1x.png","scale":"1x"},{"size":"57x57","idiom":"iphone","filename":"AppIcon-nightly-57x57@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"AppIcon-nightly-60x60@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"AppIcon-nightly-60x60@3x.png","scale":"3x"},{"size":"20x20","idiom":"ipad","filename":"AppIcon-nightly-20x20@1x.png","scale":"1x"},{"size":"20x20","idiom":"ipad","filename":"AppIcon-nightly-20x20@2x.png","scale":"2x"},{"size":"29x29","idiom":"ipad","filename":"AppIcon-nightly-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"ipad","filename":"AppIcon-nightly-29x29@2x.png","scale":"2x"},{"size":"40x40","idiom":"ipad","filename":"AppIcon-nightly-40x40@1x.png","scale":"1x"},{"size":"40x40","idiom":"ipad","filename":"AppIcon-nightly-40x40@2x.png","scale":"2x"},{"size":"50x50","idiom":"ipad","filename":"AppIcon-nightly-50x50@1x.png","scale":"1x"},{"size":"50x50","idiom":"ipad","filename":"AppIcon-nightly-50x50@2x.png","scale":"2x"},{"size":"72x72","idiom":"ipad","filename":"AppIcon-nightly-72x72@1x.png","scale":"1x"},{"size":"72x72","idiom":"ipad","filename":"AppIcon-nightly-72x72@2x.png","scale":"2x"},{"size":"76x76","idiom":"ipad","filename":"AppIcon-nightly-76x76@1x.png","scale":"1x"},{"size":"76x76","idiom":"ipad","filename":"AppIcon-nightly-76x76@2x.png","scale":"2x"},{"size":"83.5x83.5","idiom":"ipad","filename":"AppIcon-nightly-83.5x83.5@2x.png","scale":"2x"},{"size":"1024x1024","idiom":"ios-marketing","filename":"AppIcon-nightly-1024x1024@1x.png","scale":"1x"}],"info":{"version":1,"author":"xcode"}} \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index b7d41ce0..fbbca0b3 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,23 +5,23 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834 + sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab" url: "https://pub.dev" source: hosted - version: "72.0.0" + version: "76.0.0" _macros: dependency: transitive description: dart source: sdk - version: "0.3.2" + version: "0.3.3" analyzer: dependency: transitive description: name: analyzer - sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139 + sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e" url: "https://pub.dev" source: hosted - version: "6.7.0" + version: "6.11.0" analyzer_plugin: dependency: transitive description: @@ -42,10 +42,10 @@ packages: dependency: "direct main" description: name: app_links - sha256: ad1a6d598e7e39b46a34f746f9a8b011ee147e4c275d407fa457e7a62f84dd99 + sha256: "433df2e61b10519407475d7f69e470789d23d593f28224c38ba1068597be7950" url: "https://pub.dev" source: hosted - version: "6.3.2" + version: "6.3.3" app_links_linux: dependency: transitive description: @@ -74,10 +74,10 @@ packages: dependency: transitive description: name: archive - sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d + sha256: "08064924cbf0ab88280a0c3f60db9dd24fec693927e725ecb176f16c629d1cb8" url: "https://pub.dev" source: hosted - version: "3.6.1" + version: "4.0.1" args: dependency: "direct main" description: @@ -378,10 +378,10 @@ packages: dependency: "direct main" description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.0" color: dependency: transitive description: @@ -402,10 +402,10 @@ packages: dependency: transitive description: name: coverage - sha256: "4b03e11f6d5b8f6e5bb5e9f7889a56fe6c5cbe942da5378ea4d4d7f73ef9dfe5" + sha256: e3493833ea012784c740e341952298f1cc77f1f01b1bbc3eb4eecf6984fb7f43 url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.11.1" cross_file: dependency: transitive description: @@ -466,10 +466,10 @@ packages: dependency: transitive description: name: custom_lint_visitor - sha256: "8aeb3b6ae2bb765e7716b93d1d10e8356d04e0ff6d7592de6ee04e0dd7d6587d" + sha256: bfe9b7a09c4775a587b58d10ebb871d4fe618237639b1e84d5ec62d7dfef25f9 url: "https://pub.dev" source: hosted - version: "1.0.0+6.7.0" + version: "1.0.0+6.11.0" dart_des: dependency: transitive description: @@ -523,18 +523,18 @@ packages: dependency: "direct main" description: name: device_info_plus - sha256: f545ffbadee826f26f2e1a0f0cbd667ae9a6011cc0f77c0f8f00a969655e6e95 + sha256: "4fa68e53e26ab17b70ca39f072c285562cfc1589df5bb1e9295db90f6645f431" url: "https://pub.dev" source: hosted - version: "11.1.1" + version: "11.2.0" device_info_plus_platform_interface: dependency: transitive description: name: device_info_plus_platform_interface - sha256: "282d3cf731045a2feb66abfe61bbc40870ae50a3ed10a4d3d217556c35c8c2ba" + sha256: "0b04e02b30791224b31969eb1b50d723498f402971bff3630bca2ba839bd1ed2" url: "https://pub.dev" source: hosted - version: "7.0.1" + version: "7.0.2" dio: dependency: "direct main" description: @@ -580,10 +580,10 @@ packages: dependency: "direct dev" description: name: drift_dev - sha256: "488263d85d027333fc602eb7714125de317e8c7db064aa6c2f208a8f79139e7b" + sha256: f4ab5d6976b1e31551ceb82ff597a505bda7818ff4f7be08a1da9d55eb6e730c url: "https://pub.dev" source: hosted - version: "2.22.0" + version: "2.22.1" duration: dependency: "direct main" description: @@ -652,10 +652,10 @@ packages: dependency: "direct main" description: name: file_picker - sha256: "16dc141db5a2ccc6520ebb6a2eb5945b1b09e95085c021d9f914f8ded7f1465c" + sha256: "89500471922dd3a89ab0d6e13ab4a2268c25474bff4ca7c628f55c76e0ced1de" url: "https://pub.dev" source: hosted - version: "8.1.4" + version: "8.1.5" file_selector: dependency: "direct main" description: @@ -732,10 +732,10 @@ packages: dependency: "direct main" description: name: fluentui_system_icons - sha256: d637972e7e0b34e7accf6a34bf757494a35559959b69ffd0f8926804421faa60 + sha256: "721a4d2edf31d44f13de917b3098c75faccd98854632619e858164700211184f" url: "https://pub.dev" source: hosted - version: "1.1.265" + version: "1.1.266" flutter: dependency: "direct main" description: flutter @@ -744,10 +744,11 @@ packages: flutter_broadcasts: dependency: "direct main" description: - name: flutter_broadcasts - sha256: "9e76eeeda4a9faef63e3b08af5664c79219a2eabffc8ce95296858ea70423b1e" - url: "https://pub.dev" - source: hosted + path: "." + ref: main + resolved-ref: "10ded509b2bf50870114a88d7d61d4817bc36fd6" + url: "https://github.com/KRTirtho/flutter_broadcasts.git" + source: git version: "0.4.0" flutter_cache_manager: dependency: "direct main" @@ -878,10 +879,10 @@ packages: dependency: "direct dev" description: name: flutter_launcher_icons - sha256: "526faf84284b86a4cb36d20a5e45147747b7563d921373d4ee0559c54fcdbcea" + sha256: "31cd0885738e87c72d6f055564d37fabcdacee743b396b78c7636c169cac64f5" url: "https://pub.dev" source: hosted - version: "0.13.1" + version: "0.14.2" flutter_lints: dependency: "direct dev" description: @@ -1066,10 +1067,10 @@ packages: dependency: "direct main" description: name: go_router - sha256: "8660b74171fafae4aa8202100fa2e55349e078281dadc73a241eb8e758534d9d" + sha256: "2fd11229f59e23e967b0775df8d5948a519cd7e1e8b6e849729e010587b46539" url: "https://pub.dev" source: hosted - version: "14.6.1" + version: "14.6.2" google_fonts: dependency: "direct main" description: @@ -1194,18 +1195,18 @@ packages: dependency: transitive description: name: http_parser - sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + sha256: "76d306a1c3afb33fe82e2bbacad62a61f409b5634c915fceb0d799de1a913360" url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "4.1.1" image: dependency: transitive description: name: image - sha256: f31d52537dc417fdcde36088fdf11d191026fd5e4fae742491ebd40e5a8bea7d + sha256: "599d08e369969bdf83138f5b4e0a7e823d3f992f23b8a64dd626877c37013533" url: "https://pub.dev" source: hosted - version: "4.3.0" + version: "4.4.0" image_picker: dependency: "direct main" description: @@ -1303,10 +1304,10 @@ packages: dependency: "direct dev" description: name: io - sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.0.5" jiosaavn: dependency: "direct main" description: @@ -1343,18 +1344,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" url: "https://pub.dev" source: hosted - version: "10.0.5" + version: "10.0.7" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.8" leak_tracker_testing: dependency: transitive description: @@ -1415,10 +1416,10 @@ packages: dependency: transitive description: name: macros - sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536" + sha256: "1d9e801cd66f7ea3663c45fc708450db1fa57f988142c64289142c9b7ee80656" url: "https://pub.dev" source: hosted - version: "0.1.2-main.4" + version: "0.1.3-main.0" matcher: dependency: transitive description: @@ -1623,10 +1624,10 @@ packages: dependency: transitive description: name: package_config - sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + sha256: "92d4488434b520a62570293fbd33bb556c7d49230791c1b4bbd973baf6d2dc67" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" package_info_plus: dependency: "direct main" description: @@ -1687,18 +1688,18 @@ packages: dependency: transitive description: name: path_provider_android - sha256: "8c4967f8b7cb46dc914e178daa29813d83ae502e0529d7b0478330616a691ef7" + sha256: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2" url: "https://pub.dev" source: hosted - version: "2.2.14" + version: "2.2.15" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 + sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.1" path_provider_linux: dependency: transitive description: @@ -1827,6 +1828,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.3.1" + posix: + dependency: transitive + description: + name: posix + sha256: a0117dc2167805aa9125b82eee515cc891819bac2f538c83646d355b16f58b9a + url: "https://pub.dev" + source: hosted + version: "6.0.1" process: dependency: transitive description: @@ -1855,10 +1864,10 @@ packages: dependency: transitive description: name: pub_semver - sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + sha256: "7b3cfbf654f3edd0c6298ecd5be782ce997ddf0e00531b9464b55245185bbbbd" url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.1.5" pubspec_parse: dependency: "direct dev" description: @@ -1984,10 +1993,10 @@ packages: dependency: transitive description: name: shared_preferences_android - sha256: "3b9febd815c9ca29c9e3520d50ec32f49157711e143b7a4ca039eb87e8ade5ab" + sha256: "7f172d1b06de5da47b6264c2692ee2ead20bbbc246690427cdb4fc301cd0c549" url: "https://pub.dev" source: hosted - version: "2.3.3" + version: "2.3.4" shared_preferences_foundation: dependency: transitive description: @@ -2032,10 +2041,10 @@ packages: dependency: "direct main" description: name: shelf - sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 url: "https://pub.dev" source: hosted - version: "1.4.1" + version: "1.4.2" shelf_packages_handler: dependency: transitive description: @@ -2104,7 +2113,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" sliver_tools: dependency: "direct main" description: @@ -2149,10 +2158,10 @@ packages: dependency: transitive description: name: source_maps - sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" + sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812" url: "https://pub.dev" source: hosted - version: "0.10.12" + version: "0.10.13" source_span: dependency: transitive description: @@ -2229,10 +2238,10 @@ packages: dependency: "direct main" description: name: sqlite3_flutter_libs - sha256: "7ae52b23366e5295005022e62fa093f64bfe190810223ea0ebf733a4cd140bce" + sha256: "636b0fe8a2de894e5455572f6cbbc458f4ffecfe9f860b79439e27041ea4f0b9" url: "https://pub.dev" source: hosted - version: "0.5.26" + version: "0.5.27" sqlparser: dependency: transitive description: @@ -2245,10 +2254,10 @@ packages: dependency: transitive description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.12.0" state_notifier: dependency: transitive description: @@ -2277,10 +2286,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" stroke_text: dependency: "direct main" description: @@ -2333,26 +2342,26 @@ packages: dependency: "direct main" description: name: test - sha256: "7ee44229615f8f642b68120165ae4c2a75fe77ae2065b1e55ae4711f6cf0899e" + sha256: "713a8789d62f3233c46b4a90b174737b2c04cb6ae4500f2aa8b1be8f03f5e67f" url: "https://pub.dev" source: hosted - version: "1.25.7" + version: "1.25.8" test_api: dependency: transitive description: name: test_api - sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" url: "https://pub.dev" source: hosted - version: "0.7.2" + version: "0.7.3" test_core: dependency: transitive description: name: test_core - sha256: "55ea5a652e38a1dfb32943a7973f3681a60f872f8c3a05a14664ad54ef9c6696" + sha256: "12391302411737c176b0b5d6491f466b0dd56d4763e347b6714efbaa74d7953d" url: "https://pub.dev" source: hosted - version: "0.6.4" + version: "0.6.5" time: dependency: transitive description: @@ -2373,10 +2382,10 @@ packages: dependency: transitive description: name: timing - sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" + sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "1.0.2" titlebar_buttons: dependency: "direct main" description: @@ -2389,10 +2398,10 @@ packages: dependency: "direct main" description: name: tray_manager - sha256: "3c03c70a9b14e89b17c15275c05f67fdd30950f3073ae523755ad9beb2ac7e35" + sha256: f231031c5c0eb4ad514e18ddaab27a912ddbe50335c594bc28fb0f9972ab6a84 url: "https://pub.dev" source: hosted - version: "0.3.0" + version: "0.3.1" type_plus: dependency: transitive description: @@ -2461,10 +2470,10 @@ packages: dependency: transitive description: name: url_launcher_ios - sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e + sha256: "16a513b6c12bb419304e72ea0ae2ab4fed569920d1c7cb850263fe3acc824626" url: "https://pub.dev" source: hosted - version: "6.3.1" + version: "6.3.2" url_launcher_linux: dependency: transitive description: @@ -2477,10 +2486,10 @@ packages: dependency: transitive description: name: url_launcher_macos - sha256: "769549c999acdb42b8bcfa7c43d72bf79a382ca7441ab18a808e101149daf672" + sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2" url: "https://pub.dev" source: hosted - version: "3.2.1" + version: "3.2.2" url_launcher_platform_interface: dependency: transitive description: @@ -2565,10 +2574,10 @@ packages: dependency: transitive description: name: vm_service - sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" + sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b url: "https://pub.dev" source: hosted - version: "14.2.5" + version: "14.3.0" watcher: dependency: transitive description: @@ -2605,10 +2614,10 @@ packages: dependency: transitive description: name: webdriver - sha256: "003d7da9519e1e5f329422b36c4dcdf18d7d2978d1ba099ea4e45ba490ed845e" + sha256: "3d773670966f02a646319410766d3b5e1037efb7f07cc68f844d5e06cd4d61c8" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.4" webkit_inspection_protocol: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index b192ee5e..5b123149 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -46,7 +46,10 @@ dependencies: fluentui_system_icons: ^1.1.234 flutter: sdk: flutter - flutter_broadcasts: ^0.4.0 + flutter_broadcasts: + git: + url: https://github.com/KRTirtho/flutter_broadcasts.git + ref: main flutter_cache_manager: ^3.3.0 flutter_discord_rpc: ^1.0.0 flutter_displaymode: ^0.6.0 @@ -132,7 +135,7 @@ dev_dependencies: crypto: ^3.0.3 envied_generator: ^1.0.0 flutter_gen_runner: ^5.4.0 - flutter_launcher_icons: ^0.13.1 + flutter_launcher_icons: ^0.14.2 flutter_lints: ^3.0.1 flutter_test: sdk: flutter From 4595eb169fd6e222259010e30d0df8723f9c71fb Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 14 Dec 2024 12:05:25 +0600 Subject: [PATCH 007/112] fix: finally fix gradle build --- analysis_options.yaml | 2 - android/app/build.gradle | 2 +- android/app/src/debug/AndroidManifest.xml | 9 ++- android/app/src/main/AndroidManifest.xml | 2 +- android/app/src/profile/AndroidManifest.xml | 9 ++- pubspec.lock | 76 ++------------------- pubspec.yaml | 8 +-- 7 files changed, 19 insertions(+), 89 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 1eda286e..af222653 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -32,8 +32,6 @@ linter: analyzer: errors: invalid_annotation_target: ignore - plugins: - - custom_lint exclude: - "**.freezed.dart" - "**.g.dart" diff --git a/android/app/build.gradle b/android/app/build.gradle index 047512f4..7c1a6356 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -33,7 +33,7 @@ android { compileSdkVersion 35 - ndkVersion "26.1.10909125" + ndkVersion = "27.0.12077973" compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml index 1041f6ca..a32d12af 100644 --- a/android/app/src/debug/AndroidManifest.xml +++ b/android/app/src/debug/AndroidManifest.xml @@ -1,7 +1,6 @@ - - - - + + \ No newline at end of file diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 64c32e28..78f744c4 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,4 +1,4 @@ - + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml index 1041f6ca..a32d12af 100644 --- a/android/app/src/profile/AndroidManifest.xml +++ b/android/app/src/profile/AndroidManifest.xml @@ -1,7 +1,6 @@ - - - - + + \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index fbbca0b3..e6e365a6 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -342,14 +342,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.3" - ci: - dependency: transitive - description: - name: ci - sha256: "145d095ce05cddac4d797a158bc4cf3b6016d1fe63d8c3d2fbd7212590adca13" - url: "https://pub.dev" - source: hosted - version: "0.1.0" cli_util: dependency: transitive description: @@ -438,38 +430,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.6" - custom_lint: - dependency: "direct dev" - description: - name: custom_lint - sha256: "3486c470bb93313a9417f926c7dd694a2e349220992d7b9d14534dc49c15bba9" - url: "https://pub.dev" - source: hosted - version: "0.7.0" - custom_lint_builder: - dependency: transitive - description: - name: custom_lint_builder - sha256: "42cdc41994eeeddab0d7a722c7093ec52bd0761921eeb2cbdbf33d192a234759" - url: "https://pub.dev" - source: hosted - version: "0.7.0" - custom_lint_core: - dependency: transitive - description: - name: custom_lint_core - sha256: "02450c3e45e2a6e8b26c4d16687596ab3c4644dd5792e3313aa9ceba5a49b7f5" - url: "https://pub.dev" - source: hosted - version: "0.7.0" - custom_lint_visitor: - dependency: transitive - description: - name: custom_lint_visitor - sha256: bfe9b7a09c4775a587b58d10ebb871d4fe618237639b1e84d5ec62d7dfef25f9 - url: "https://pub.dev" - source: hosted - version: "1.0.0+6.11.0" dart_des: dependency: transitive description: @@ -652,10 +612,10 @@ packages: dependency: "direct main" description: name: file_picker - sha256: "89500471922dd3a89ab0d6e13ab4a2268c25474bff4ca7c628f55c76e0ced1de" + sha256: "16dc141db5a2ccc6520ebb6a2eb5945b1b09e95085c021d9f914f8ded7f1465c" url: "https://pub.dev" source: hosted - version: "8.1.5" + version: "8.1.4" file_selector: dependency: "direct main" description: @@ -745,8 +705,8 @@ packages: dependency: "direct main" description: path: "." - ref: main - resolved-ref: "10ded509b2bf50870114a88d7d61d4817bc36fd6" + ref: "63931dfe06733d4fb7452e9981e1f0b23414d97a" + resolved-ref: "63931dfe06733d4fb7452e9981e1f0b23414d97a" url: "https://github.com/KRTirtho/flutter_broadcasts.git" source: git version: "0.4.0" @@ -1143,14 +1103,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.6.1" - hotreloader: - dependency: transitive - description: - name: hotreloader - sha256: ed56fdc1f3a8ac924e717257621d09e9ec20e308ab6352a73a50a1d7a4d9158e - url: "https://pub.dev" - source: hosted - version: "4.2.0" html: dependency: "direct main" description: @@ -1892,22 +1844,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.6.1" - riverpod_analyzer_utils: - dependency: transitive - description: - name: riverpod_analyzer_utils - sha256: c6b8222b2b483cb87ae77ad147d6408f400c64f060df7a225b127f4afef4f8c8 - url: "https://pub.dev" - source: hosted - version: "0.5.8" - riverpod_lint: - dependency: "direct dev" - description: - name: riverpod_lint - sha256: "83e4caa337a9840469b7b9bd8c2351ce85abad80f570d84146911b32086fbd99" - url: "https://pub.dev" - source: hosted - version: "2.6.3" rxdart: dependency: transitive description: @@ -2318,10 +2254,10 @@ packages: dependency: "direct main" description: name: system_theme - sha256: "1f208db140a3d1e1eac2034b54920d95699c1534df576ced44b3312c5de3975f" + sha256: "5f93485401689601d4636a695f99f7c70a30873ee68c1d95025d908a3386be7e" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "3.1.2" system_theme_web: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 5b123149..072c9a0a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -41,7 +41,7 @@ dependencies: duration: ^3.0.12 encrypt: ^5.0.3 envied: ^1.0.0 - file_picker: ^8.0.0+1 + file_picker: 8.1.4 file_selector: ^1.0.3 fluentui_system_icons: ^1.1.234 flutter: @@ -49,7 +49,7 @@ dependencies: flutter_broadcasts: git: url: https://github.com/KRTirtho/flutter_broadcasts.git - ref: main + ref: 63931dfe06733d4fb7452e9981e1f0b23414d97a flutter_cache_manager: ^3.3.0 flutter_discord_rpc: ^1.0.0 flutter_displaymode: ^0.6.0 @@ -114,7 +114,7 @@ dependencies: sqlite3: ^2.4.3 sqlite3_flutter_libs: ^0.5.23 stroke_text: ^0.0.2 - system_theme: ^2.1.0 + system_theme: ^3.1.2 test: ^1.25.7 timezone: ^0.10.0 titlebar_buttons: ^1.0.0 @@ -144,8 +144,6 @@ dev_dependencies: hive_generator: ^2.0.0 json_serializable: ^6.6.2 freezed: ^2.5.2 - custom_lint: ^0.7.0 - riverpod_lint: ^2.6.3 process_run: ^0.14.2 pubspec_parse: ^1.3.0 pub_api_client: ^3.0.0 From b52bf0f448a5c9bfebd2fa3edf2cbd9450875156 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 16 Dec 2024 22:47:44 +0600 Subject: [PATCH 008/112] feat(android): home widget support (#2148) * feat: add android home widget support * feat: style widget player and add intent and callbacks on action * feat: responsive and working android home widget * fix(android): models stripping causing it to not work for release apks * chore: ios lockfile update * feat: config for iOS widget * cd: upgrade xcode * cd: reduce xcode version * feat: add a christmas background --- .github/workflows/spotube-release-binary.yml | 6 + .gitignore | 4 +- .vscode/settings.json | 2 +- android/app/build.gradle | 28 +- android/app/proguard-rules.pro | 9 +- android/app/src/main/AndroidManifest.xml | 87 ++- .../spotube/glance/HomePlayerWidget.kt | 216 ++++++ .../glance/HomePlayerWidgetReceiver.kt | 7 + .../spotube/glance/models/AlbumSimple.kt | 40 + .../krtirtho/spotube/glance/models/Artist.kt | 25 + .../krtirtho/spotube/glance/models/Image.kt | 10 + .../krtirtho/spotube/glance/models/Track.kt | 37 + .../glance/widgets/Base64ImageProvider.kt | 14 + .../widgets/FlutterAssetImageProvider.kt | 14 + .../glance/widgets/TrackDetailsView.kt | 78 ++ .../spotube/glance/widgets/TrackProgress.kt | 77 ++ .../res/xml/home_player_widget_config.xml | 7 + android/build.gradle | 2 +- android/settings.gradle | 4 +- assets/backgrounds/xmas-effect.png | Bin 0 -> 180027 bytes .../AccentColor.colorset/Contents.json | 11 + .../AppIcon.appiconset/Contents.json | 35 + .../Assets.xcassets/Contents.json | 6 + .../WidgetBackground.colorset/Contents.json | 11 + ios/HomePlayerWidget/HomePlayerWidget.swift | 86 +++ .../HomePlayerWidgetBundle.swift | 16 + ios/HomePlayerWidget/Info.plist | 11 + ios/HomePlayerWidgetExtension.entitlements | 10 + ios/Podfile.lock | 21 +- ios/Runner.xcodeproj/project.pbxproj | 696 +++++++++++++++++- ios/Runner/Runner.entitlements | 10 + ios/dev.entitlements | 10 + ios/nightly.entitlements | 10 + ios/stable.entitlements | 10 + lib/main.dart | 10 + lib/pages/root/root_app.dart | 3 + lib/provider/glance/glance.dart | 169 +++++ lib/provider/server/router.dart | 4 + lib/provider/server/routes/playback.dart | 21 + pubspec.lock | 12 +- pubspec.yaml | 2 + 41 files changed, 1789 insertions(+), 42 deletions(-) create mode 100644 android/app/src/main/kotlin/oss/krtirtho/spotube/glance/HomePlayerWidget.kt create mode 100644 android/app/src/main/kotlin/oss/krtirtho/spotube/glance/HomePlayerWidgetReceiver.kt create mode 100644 android/app/src/main/kotlin/oss/krtirtho/spotube/glance/models/AlbumSimple.kt create mode 100644 android/app/src/main/kotlin/oss/krtirtho/spotube/glance/models/Artist.kt create mode 100644 android/app/src/main/kotlin/oss/krtirtho/spotube/glance/models/Image.kt create mode 100644 android/app/src/main/kotlin/oss/krtirtho/spotube/glance/models/Track.kt create mode 100644 android/app/src/main/kotlin/oss/krtirtho/spotube/glance/widgets/Base64ImageProvider.kt create mode 100644 android/app/src/main/kotlin/oss/krtirtho/spotube/glance/widgets/FlutterAssetImageProvider.kt create mode 100644 android/app/src/main/kotlin/oss/krtirtho/spotube/glance/widgets/TrackDetailsView.kt create mode 100644 android/app/src/main/kotlin/oss/krtirtho/spotube/glance/widgets/TrackProgress.kt create mode 100644 android/app/src/main/res/xml/home_player_widget_config.xml create mode 100644 assets/backgrounds/xmas-effect.png create mode 100644 ios/HomePlayerWidget/Assets.xcassets/AccentColor.colorset/Contents.json create mode 100644 ios/HomePlayerWidget/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 ios/HomePlayerWidget/Assets.xcassets/Contents.json create mode 100644 ios/HomePlayerWidget/Assets.xcassets/WidgetBackground.colorset/Contents.json create mode 100644 ios/HomePlayerWidget/HomePlayerWidget.swift create mode 100644 ios/HomePlayerWidget/HomePlayerWidgetBundle.swift create mode 100644 ios/HomePlayerWidget/Info.plist create mode 100644 ios/HomePlayerWidgetExtension.entitlements create mode 100644 ios/Runner/Runner.entitlements create mode 100644 ios/dev.entitlements create mode 100644 ios/nightly.entitlements create mode 100644 ios/stable.entitlements create mode 100644 lib/provider/glance/glance.dart diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index c27a3463..6a1c713f 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -87,6 +87,12 @@ jobs: uses: dtolnay/rust-toolchain@stable with: toolchain: stable + + - name: Install Xcode + if: ${{matrix.platform == 'ios'}} + uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: '16.1' - name: Install ${{matrix.platform}} dependencies run: | diff --git a/.gitignore b/.gitignore index f9bd15f8..97b5c03c 100644 --- a/.gitignore +++ b/.gitignore @@ -79,4 +79,6 @@ android/key.properties tm.json # FVM Version Cache -.fvm/ \ No newline at end of file +.fvm/ + +android/build diff --git a/.vscode/settings.json b/.vscode/settings.json index 11fae610..1f47bada 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -27,5 +27,5 @@ "README.md": "LICENSE,CODE_OF_CONDUCT.md,CONTRIBUTING.md,SECURITY.md,CONTRIBUTION.md,CHANGELOG.md,PRIVACY_POLICY.md", "*.dart": "${capture}.g.dart,${capture}.freezed.dart" }, - "dart.flutterSdkPath": ".fvm/flutter_sdk" + "dart.flutterSdkPath": ".fvm/versions/3.27.0" } \ No newline at end of file diff --git a/android/app/build.gradle b/android/app/build.gradle index 7c1a6356..74f6efea 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -28,8 +28,10 @@ if (keystorePropertiesFile.exists()) { keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) } +def composeVersion = "1.4.8" + android { - namespace "dev.krtirtho.spotube" + namespace "oss.krtirtho.spotube" compileSdkVersion 35 @@ -48,6 +50,14 @@ android { main.java.srcDirs += 'src/main/kotlin' } + buildFeatures { + compose true + } + + composeOptions { + kotlinCompilerExtensionVersion "$composeVersion" // Correlates with org.jetbrains.kotlin.android plugin in settings.gradle + } + defaultConfig { applicationId "oss.krtirtho.spotube" minSdkVersion 24 @@ -65,6 +75,7 @@ android { storePassword keystoreProperties['storePassword'] } } + buildTypes { release { signingConfig signingConfigs.release @@ -98,15 +109,28 @@ android { } } + packagingOptions { + resources.excludes += "DebugProbesKt.bin" + } } flutter { source '../..' } +def glanceVersion = "1.1.1" dependencies { implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1' - // other deps so just ignore implementation 'com.android.support:multidex:2.0.1' + + implementation "androidx.glance:glance-appwidget:$glanceVersion" + implementation "androidx.glance:glance-appwidget-preview:$glanceVersion" + implementation "androidx.glance:glance-preview:$glanceVersion" + implementation "androidx.glance:glance-material3:$glanceVersion" + implementation "androidx.glance:glance-material:$glanceVersion" + implementation "androidx.work:work-runtime-ktx:2.8.1" + + implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3" + implementation 'com.google.code.gson:gson:2.11.0' } \ No newline at end of file diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro index 116bc22f..ee867c13 100644 --- a/android/app/proguard-rules.pro +++ b/android/app/proguard-rules.pro @@ -1 +1,8 @@ --keep class androidx.lifecycle.DefaultLifecycleObserver \ No newline at end of file +-keep class androidx.lifecycle.DefaultLifecycleObserver + +-keepnames class kotlinx.serialization.** { *; } +-keepnames class oss.krtirtho.spotube.glance.models.** { *; } +-keep @kotlinx.serialization.Serializable class * +-keepclassmembers class ** { + @kotlinx.serialization.* ; +} diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 78f744c4..8c676896 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -17,38 +17,36 @@ + android:usesCleartextTraffic="true"> + android:name="io.flutter.embedding.android.EnableImpeller" + android:value="true" /> --> + android:windowSoftInputMode="adjustResize"> + Specifies an Android theme to apply to this Activity as soon as + the Android process has started. This theme is visible to the user + while the Flutter UI initializes. After that, this theme continues + to determine the Window background behind the Flutter UI. + --> + android:resource="@style/NormalTheme" /> + @@ -56,12 +54,13 @@ + + + android:scheme="https" /> @@ -72,23 +71,30 @@ + + + + + - + - @@ -96,11 +102,40 @@ - + + + + + + + + + + + + + + + + + - + This is used by the Flutter tool to generate GeneratedPluginRegistrant.java --> + \ No newline at end of file diff --git a/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/HomePlayerWidget.kt b/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/HomePlayerWidget.kt new file mode 100644 index 00000000..a04a0508 --- /dev/null +++ b/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/HomePlayerWidget.kt @@ -0,0 +1,216 @@ +package oss.krtirtho.spotube.glance + +import HomeWidgetGlanceState +import HomeWidgetGlanceStateDefinition +import android.content.Context +import android.graphics.drawable.Icon +import android.net.Uri +import android.util.Log +import androidx.compose.runtime.Composable +import androidx.compose.ui.unit.DpSize +import androidx.compose.ui.unit.dp +import androidx.glance.GlanceId +import androidx.glance.GlanceModifier +import androidx.glance.GlanceTheme +import androidx.glance.Image +import androidx.glance.ImageProvider +import androidx.glance.LocalSize +import androidx.glance.action.ActionParameters +import androidx.glance.action.actionParametersOf +import androidx.glance.action.clickable +import androidx.glance.background +import androidx.glance.appwidget.GlanceAppWidget +import androidx.glance.appwidget.SizeMode +import androidx.glance.appwidget.action.ActionCallback +import androidx.glance.appwidget.action.actionRunCallback +import androidx.glance.appwidget.background +import androidx.glance.appwidget.components.CircleIconButton +import androidx.glance.appwidget.components.Scaffold +import androidx.glance.appwidget.cornerRadius +import androidx.glance.appwidget.provideContent +import androidx.glance.background +import androidx.glance.currentState +import androidx.glance.layout.Alignment +import androidx.glance.layout.Box +import androidx.glance.layout.Column +import androidx.glance.layout.ContentScale +import androidx.glance.layout.Row +import androidx.glance.layout.Spacer +import androidx.glance.layout.fillMaxSize +import androidx.glance.layout.fillMaxWidth +import androidx.glance.layout.padding +import androidx.glance.layout.size +import androidx.glance.preview.ExperimentalGlancePreviewApi +import androidx.glance.preview.Preview +import androidx.glance.state.GlanceStateDefinition +import com.google.gson.Gson +import es.antonborri.home_widget.HomeWidgetBackgroundIntent +import es.antonborri.home_widget.actionStartActivity +import oss.krtirtho.spotube.MainActivity +import oss.krtirtho.spotube.glance.models.Track +import oss.krtirtho.spotube.glance.widgets.FlutterAssetImageProvider +import oss.krtirtho.spotube.glance.widgets.TrackDetailsView +import oss.krtirtho.spotube.glance.widgets.TrackProgress + +val gson = Gson() +val serverAddressKey = ActionParameters.Key("serverAddress") + +class Breakpoints { + companion object { + val SMALL_SQUARE = DpSize(100.dp, 100.dp) + val HORIZONTAL_RECTANGLE = DpSize(250.dp, 100.dp) + val BIG_SQUARE = DpSize(250.dp, 250.dp) + } +} + +class HomePlayerWidget : GlanceAppWidget() { + + override val sizeMode = SizeMode.Responsive( + setOf( + Breakpoints.SMALL_SQUARE, + Breakpoints.HORIZONTAL_RECTANGLE, + Breakpoints.BIG_SQUARE + ) + ) + + override val stateDefinition: GlanceStateDefinition<*>? + get() = HomeWidgetGlanceStateDefinition() + + override suspend fun provideGlance(context: Context, id: GlanceId) { + provideContent { + GlanceContent(context, currentState()) + } + } + + + @OptIn(ExperimentalGlancePreviewApi::class) + @Preview(widthDp = 100, heightDp = 100) + @Composable + private fun GlanceContent(context: Context, currentState: HomeWidgetGlanceState) { + val prefs = currentState.preferences + val size = LocalSize.current + + val activeTrackStr = prefs.getString("activeTrack", null) + + val isPlaying = prefs.getBoolean("isPlaying", false) + val playbackServerAddress = prefs.getString("playbackServerAddress", null) ?: "" + + var activeTrack: Track? = null + if (activeTrackStr != null) { + activeTrack = gson.fromJson(activeTrackStr, Track::class.java) + } + + + val playIcon = Icon.createWithResource(context, R.drawable.ic_media_play); + val pauseIcon = Icon.createWithResource(context, R.drawable.ic_media_pause); + val previousIcon = Icon.createWithResource(context, R.drawable.ic_media_previous); + val nextIcon = Icon.createWithResource(context, R.drawable.ic_media_next); + + GlanceTheme { + Box( + modifier = GlanceModifier + .fillMaxSize() + .cornerRadius(8.dp) + .background( + color = GlanceTheme.colors.surface.getColor(context) + ) + .clickable { + actionStartActivity(context) + } + , + ) { + Image( + provider = FlutterAssetImageProvider( + context, + "assets/backgrounds/xmas-effect.png" + ), + contentDescription = "Background", + modifier = GlanceModifier + .fillMaxSize(), + contentScale = ContentScale.Crop + ) + Box( + modifier = GlanceModifier + .background( + color = + GlanceTheme.colors.surface.getColor(context) + .copy(alpha = 0.5f), + ) + .fillMaxSize(), + ) {} + Column( + modifier = GlanceModifier.padding(top = 10.dp, start = 10.dp, end = 10.dp) + ) { + Row(verticalAlignment = Alignment.Vertical.CenterVertically) { + TrackDetailsView(activeTrack) + } + Spacer(modifier = GlanceModifier.size(6.dp)) + if (size != Breakpoints.SMALL_SQUARE) { + TrackProgress(prefs) + } + Spacer(modifier = GlanceModifier.size(6.dp)) + Row( + modifier = GlanceModifier.fillMaxWidth(), + horizontalAlignment = Alignment.Horizontal.CenterHorizontally + ) { + CircleIconButton( + imageProvider = ImageProvider(previousIcon), + contentDescription = "Previous", + onClick = actionRunCallback( + parameters = actionParametersOf(serverAddressKey to playbackServerAddress) + ) + ) + Spacer(modifier = GlanceModifier.size(6.dp)) + CircleIconButton( + imageProvider = + if (isPlaying) ImageProvider(pauseIcon) + else ImageProvider(playIcon), + contentDescription = "Play/Pause", + onClick = actionRunCallback( + parameters = actionParametersOf(serverAddressKey to playbackServerAddress) + ) + ) + Spacer(modifier = GlanceModifier.size(6.dp)) + CircleIconButton( + imageProvider = ImageProvider(nextIcon), + contentDescription = "Previous", + onClick = actionRunCallback( + parameters = actionParametersOf( + serverAddressKey to playbackServerAddress + ) + ) + ) + } + } + } + } + } +} + +class PlayPauseAction : InteractiveAction("toggle-playback") +class NextAction : InteractiveAction("next") +class PreviousAction : InteractiveAction("previous") + + +abstract class InteractiveAction(val command: String) : ActionCallback { + override suspend fun onAction( + context: Context, + glanceId: GlanceId, + parameters: ActionParameters + ) { + val serverAddress = parameters[serverAddressKey] ?: "" + + Log.d("HomePlayerWidget", "Sending command $command to $serverAddress") + + if (serverAddress == null || serverAddress.isEmpty()) { + return + } + + + val backgroundIntent = HomeWidgetBackgroundIntent.getBroadcast( + context, + Uri.parse("spotube://playback/$command?serverAddress=$serverAddress") + ) + backgroundIntent.send() + } +} diff --git a/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/HomePlayerWidgetReceiver.kt b/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/HomePlayerWidgetReceiver.kt new file mode 100644 index 00000000..2d23c64f --- /dev/null +++ b/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/HomePlayerWidgetReceiver.kt @@ -0,0 +1,7 @@ +package oss.krtirtho.spotube.glance + +import HomeWidgetGlanceWidgetReceiver + +class HomePlayerWidgetReceiver : HomeWidgetGlanceWidgetReceiver() { + override val glanceAppWidget = HomePlayerWidget() +} diff --git a/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/models/AlbumSimple.kt b/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/models/AlbumSimple.kt new file mode 100644 index 00000000..4edd69f6 --- /dev/null +++ b/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/models/AlbumSimple.kt @@ -0,0 +1,40 @@ +package oss.krtirtho.spotube.glance.models + +import com.google.gson.annotations.SerializedName +import kotlinx.serialization.Serializable + +@Serializable +data class AlbumSimple( + @SerializedName("album_type") + val albumType: AlbumType?, + + @SerializedName("available_markets") + val availableMarkets: List?, + + val href: String?, + val id: String?, + val images: List?, + val name: String?, + + @SerializedName("release_date") + val releaseDate: String?, + + @SerializedName("release_date_precision") + val releaseDatePrecision: DatePrecision?, + + val type: String?, + val uri: String?, +) + +@Serializable +enum class AlbumType { + album, + single, + compilation +} + +enum class DatePrecision { + year, + month, + day +} \ No newline at end of file diff --git a/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/models/Artist.kt b/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/models/Artist.kt new file mode 100644 index 00000000..ef43ecc8 --- /dev/null +++ b/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/models/Artist.kt @@ -0,0 +1,25 @@ +package oss.krtirtho.spotube.glance.models + +import com.google.gson.annotations.SerializedName +import kotlinx.serialization.Serializable + +@Serializable +data class Artist( + val href: String?, + val id: String?, + val name: String?, + val type: String?, + val uri: String?, + + val followers: Followers?, + val genres: List?, + val images: List?, + + @SerializedName("popularity") + val popularity: Int? +) + +@Serializable +data class Followers( + val total: Int? +) diff --git a/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/models/Image.kt b/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/models/Image.kt new file mode 100644 index 00000000..de7d5521 --- /dev/null +++ b/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/models/Image.kt @@ -0,0 +1,10 @@ +package oss.krtirtho.spotube.glance.models + +import kotlinx.serialization.Serializable + +@Serializable +data class Image( + val height: Int?, + val width: Int?, + val path: String, +) \ No newline at end of file diff --git a/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/models/Track.kt b/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/models/Track.kt new file mode 100644 index 00000000..717b790f --- /dev/null +++ b/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/models/Track.kt @@ -0,0 +1,37 @@ +package oss.krtirtho.spotube.glance.models + +import com.google.gson.annotations.SerializedName +import kotlinx.serialization.Serializable +import kotlin.time.Duration.Companion.milliseconds + +@Serializable +data class Track( + val album: AlbumSimple?, val artists: List?, + + @SerializedName("available_markets") val availableMarkets: List?, + + @SerializedName("disc_number") val discNumber: Int?, + + @SerializedName("duration_ms") val durationMs: Int, + + val explicit: Boolean?, val href: String?, val id: String?, + + @SerializedName("is_playable") val isPlayable: Boolean?, + + val name: String?, + + @SerializedName("popularity") val popularity: Int?, + + @SerializedName("preview_url") val previewUrl: String?, + + @SerializedName("track_number") val trackNumber: Int?, + + val type: String?, val uri: String? +) { + val duration: kotlin.time.Duration + get() = durationMs.toLong().milliseconds +} + +enum class Market { + AD, AE, AF, AG, AI, AL, AM, AO, AQ, AR, AS, AT, AU, AW, AX, AZ, BA, BB, BD, BE, BF, BG, BH, BI, BJ, BL, BM, BN, BO, BQ, BR, BS, BT, BV, BW, BY, BZ, CA, CC, CD, CF, CG, CH, CI, CK, CL, CM, CN, CO, CR, CU, CV, CW, CX, CY, CZ, DE, DJ, DK, DM, DO, DZ, EC, EE, EG, EH, ER, ES, ET, FI, FJ, FK, FM, FO, FR, GA, GB, GD, GE, GF, GG, GH, GI, GL, GM, GN, GP, GQ, GR, GS, GT, GU, GW, GY, HK, HM, HN, HR, HT, HU, ID, IE, IL, IM, IN, IO, IQ, IR, IS, IT, JE, JM, JO, JP, KE, KG, KH, KI, KM, KN, KP, KR, KW, KY, KZ, LA, LB, LC, LI, LK, LR, LS, LT, LU, LV, LY, MA, MC, MD, ME, MF, MG, MH, MK, ML, MM, MN, MO, MP, MQ, MR, MS, MT, MU, MV, MW, MX, MY, MZ, NA, NC, NE, NF, NG, NI, NL, NO, NP, NR, NU, NZ, OM, PA, PE, PF, PG, PH, PK, PL, PM, PN, PR, PS, PT, PW, PY, QA, RE, RO, RS, RU, RW, SA, SB, SC, SD, SE, SG, SH, SI, SJ, SK, SL, SM, SN, SO, SR, SS, ST, SV, SX, SY, SZ, TC, TD, TF, TG, TH, TJ, TK, TL, TM, TN, TO, TR, TT, TV, TW, TZ, UA, UG, UM, US, UY, UZ, VA, VC, VE, VG, VI, VN, VU, WF, WS, XK, YE, YT, ZA, ZM, ZW, +} diff --git a/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/widgets/Base64ImageProvider.kt b/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/widgets/Base64ImageProvider.kt new file mode 100644 index 00000000..79339cea --- /dev/null +++ b/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/widgets/Base64ImageProvider.kt @@ -0,0 +1,14 @@ +package oss.krtirtho.spotube.glance.widgets + +import android.graphics.BitmapFactory +import android.util.Base64 +import androidx.glance.ImageProvider + +@Suppress("FunctionName") +fun Base64ImageProvider(base64: String): ImageProvider { + var bytes = Base64.decode(base64, Base64.DEFAULT); + + var bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.size); + + return ImageProvider(bitmap) +} \ No newline at end of file diff --git a/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/widgets/FlutterAssetImageProvider.kt b/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/widgets/FlutterAssetImageProvider.kt new file mode 100644 index 00000000..ad51ca3c --- /dev/null +++ b/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/widgets/FlutterAssetImageProvider.kt @@ -0,0 +1,14 @@ +package oss.krtirtho.spotube.glance.widgets + +import android.content.Context +import android.graphics.BitmapFactory +import androidx.glance.ImageProvider + +@Suppress("FunctionName") +fun FlutterAssetImageProvider(context: Context, path: String): ImageProvider { + var inputStream = context.assets.open("flutter_assets/$path") + + return ImageProvider( + BitmapFactory.decodeStream(inputStream) + ) +} \ No newline at end of file diff --git a/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/widgets/TrackDetailsView.kt b/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/widgets/TrackDetailsView.kt new file mode 100644 index 00000000..fdfe8e4b --- /dev/null +++ b/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/widgets/TrackDetailsView.kt @@ -0,0 +1,78 @@ +package oss.krtirtho.spotube.glance.widgets + +import android.graphics.BitmapFactory +import android.net.Uri +import android.util.Log +import androidx.compose.runtime.Composable +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.glance.GlanceModifier +import androidx.glance.GlanceTheme +import androidx.glance.Image +import androidx.glance.ImageProvider +import androidx.glance.LocalContext +import androidx.glance.LocalSize +import androidx.glance.appwidget.cornerRadius +import androidx.glance.layout.Alignment +import androidx.glance.layout.Row +import androidx.glance.layout.Column +import androidx.glance.layout.ContentScale +import androidx.glance.layout.Spacer +import androidx.glance.layout.size +import androidx.glance.text.FontWeight +import androidx.glance.text.Text +import androidx.glance.text.TextStyle +import oss.krtirtho.spotube.glance.Breakpoints +import oss.krtirtho.spotube.glance.models.Track + +@Composable +fun TrackDetailsView(activeTrack: Track?) { + val context = LocalContext.current + + val size = LocalSize.current + + val artistStr = activeTrack?.artists?.map { it.name }?.joinToString(", ") ?: "" + val imgLocalPath = activeTrack?.album?.images?.get(0)?.path; + val title = activeTrack?.name ?: "" + + + Image( + provider = + if (imgLocalPath == null) + ImageProvider( + BitmapFactory.decodeResource( + context.resources, + android.R.drawable.ic_delete + ) + ) + else ImageProvider(BitmapFactory.decodeFile(imgLocalPath)), + contentDescription = "Album Art", + modifier = GlanceModifier.cornerRadius(8.dp) + .size( + if (size.height < 200.dp) 50.dp + else 100.dp + ), + contentScale = ContentScale.Fit + ) + Spacer(modifier = GlanceModifier.size(6.dp)) + Column { + Text( + text = title, + style = TextStyle( + fontSize = 16.sp, + fontWeight = FontWeight.Bold, + color = GlanceTheme.colors.onBackground + ), + ) + if (size != Breakpoints.SMALL_SQUARE) { + Spacer(modifier = GlanceModifier.size(6.dp)) + Text( + text = artistStr, + style = TextStyle( + fontSize = 14.sp, + color = GlanceTheme.colors.onBackground + ), + ) + } + } +} \ No newline at end of file diff --git a/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/widgets/TrackProgress.kt b/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/widgets/TrackProgress.kt new file mode 100644 index 00000000..b54059b1 --- /dev/null +++ b/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/widgets/TrackProgress.kt @@ -0,0 +1,77 @@ +package oss.krtirtho.spotube.glance.widgets + +import android.content.SharedPreferences +import androidx.compose.runtime.Composable +import androidx.compose.ui.unit.dp +import androidx.glance.GlanceModifier +import androidx.glance.GlanceTheme +import androidx.glance.LocalSize +import androidx.glance.appwidget.LinearProgressIndicator +import androidx.glance.layout.Column +import androidx.glance.layout.Row +import androidx.glance.layout.Spacer +import androidx.glance.layout.fillMaxWidth +import androidx.glance.layout.size +import androidx.glance.text.Text +import androidx.glance.text.TextStyle +import kotlin.math.max +import kotlin.time.Duration +import kotlin.time.Duration.Companion.seconds +import oss.krtirtho.spotube.glance.Breakpoints + +fun Duration.format(): String { + return this.toComponents { hour, minutes, seconds, nanoseconds -> + var paddedSeconds = seconds.toString().padStart(2, '0') + var paddedMinutes = minutes.toString().padStart(2, '0') + var paddedHour = hour.toString().padStart(2, '0') + if (hour == 0L) { + "$paddedMinutes:$paddedSeconds" + } else { + "$paddedHour:$paddedMinutes:$paddedSeconds" + } + } +} + +@Composable +fun TrackProgress(prefs: SharedPreferences) { + val size = LocalSize.current + val position = prefs.getInt("position", 0).seconds + var duration = prefs.getInt("duration", 0).seconds + + var progress = position.inWholeSeconds.toFloat() / max(duration.inWholeSeconds.toFloat(), 1.0f) + + var textStyle = + TextStyle( + color = GlanceTheme.colors.onBackground, + ) + + if (size == Breakpoints.HORIZONTAL_RECTANGLE) { + Row(modifier = GlanceModifier.fillMaxWidth()) { + Text(text = position.format(), style = textStyle) + Spacer(modifier = GlanceModifier.size(6.dp)) + LinearProgressIndicator( + progress = progress, + modifier = GlanceModifier.defaultWeight(), + color = GlanceTheme.colors.primary, + backgroundColor = GlanceTheme.colors.primaryContainer, + ) + Spacer(modifier = GlanceModifier.size(6.dp)) + Text(text = duration.format(), style = textStyle) + } + } else { + Column(modifier = GlanceModifier.fillMaxWidth()) { + LinearProgressIndicator( + progress = progress, + modifier = GlanceModifier.fillMaxWidth(), + color = GlanceTheme.colors.primary, + backgroundColor = GlanceTheme.colors.primaryContainer, + ) + Spacer(modifier = GlanceModifier.size(6.dp)) + Row(modifier = GlanceModifier.fillMaxWidth()) { + Text(text = position.format(), style = textStyle) + Spacer(modifier = GlanceModifier.defaultWeight()) + Text(text = duration.format(), style = textStyle) + } + } + } +} diff --git a/android/app/src/main/res/xml/home_player_widget_config.xml b/android/app/src/main/res/xml/home_player_widget_config.xml new file mode 100644 index 00000000..c8ec7048 --- /dev/null +++ b/android/app/src/main/res/xml/home_player_widget_config.xml @@ -0,0 +1,7 @@ + + diff --git a/android/build.gradle b/android/build.gradle index bc157bd1..8f31e8ca 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -15,4 +15,4 @@ subprojects { tasks.register("clean", Delete) { delete rootProject.buildDir -} +} \ No newline at end of file diff --git a/android/settings.gradle b/android/settings.gradle index a1961f52..1e8ffbe3 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -18,8 +18,8 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.7.0" apply false + id "com.android.application" version '8.7.0' apply false id "org.jetbrains.kotlin.android" version "1.8.22" apply false } -include ":app" \ No newline at end of file +include ':app' \ No newline at end of file diff --git a/assets/backgrounds/xmas-effect.png b/assets/backgrounds/xmas-effect.png new file mode 100644 index 0000000000000000000000000000000000000000..e7c8eeef4717f5fb5893e63fa89910bbc7d7fc46 GIT binary patch literal 180027 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%0D9z^ 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

3!>|&$u@TDB~yU&fbTYW{1 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 SimpleEntry { + SimpleEntry(date: Date(), emoji: "😀") + } + + func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) { + let entry = SimpleEntry(date: Date(), emoji: "😀") + completion(entry) + } + + func getTimeline(in context: Context, completion: @escaping (Timeline) -> ()) { + var entries: [SimpleEntry] = [] + + // Generate a timeline consisting of five entries an hour apart, starting from the current date. + let currentDate = Date() + for hourOffset in 0 ..< 5 { + let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)! + let entry = SimpleEntry(date: entryDate, emoji: "😀") + entries.append(entry) + } + + let timeline = Timeline(entries: entries, policy: .atEnd) + completion(timeline) + } + +// func relevances() async -> WidgetRelevances { +// // Generate a list containing the contexts this widget is relevant in. +// } +} + +struct SimpleEntry: TimelineEntry { + let date: Date + let emoji: String +} + +struct HomePlayerWidgetEntryView : View { + var entry: Provider.Entry + + var body: some View { + VStack { + Text("Time:") + Text(entry.date, style: .time) + + Text("Emoji:") + Text(entry.emoji) + } + } +} + +struct HomePlayerWidget: Widget { + let kind: String = "HomePlayerWidget" + + var body: some WidgetConfiguration { + StaticConfiguration(kind: kind, provider: Provider()) { entry in + if #available(iOS 17.0, *) { + HomePlayerWidgetEntryView(entry: entry) + .containerBackground(.fill.tertiary, for: .widget) + } else { + HomePlayerWidgetEntryView(entry: entry) + .padding() + .background() + } + } + .configurationDisplayName("My Widget") + .description("This is an example widget.") + } +} + +#Preview(as: .systemSmall) { + HomePlayerWidget() +} timeline: { + SimpleEntry(date: .now, emoji: "😀") + SimpleEntry(date: .now, emoji: "🤩") +} diff --git a/ios/HomePlayerWidget/HomePlayerWidgetBundle.swift b/ios/HomePlayerWidget/HomePlayerWidgetBundle.swift new file mode 100644 index 00000000..68158b53 --- /dev/null +++ b/ios/HomePlayerWidget/HomePlayerWidgetBundle.swift @@ -0,0 +1,16 @@ +// +// HomePlayerWidgetBundle.swift +// HomePlayerWidget +// +// Created by Kingkor Roy Tirtho on 15/12/24. +// + +import WidgetKit +import SwiftUI + +@main +struct HomePlayerWidgetBundle: WidgetBundle { + var body: some Widget { + HomePlayerWidget() + } +} diff --git a/ios/HomePlayerWidget/Info.plist b/ios/HomePlayerWidget/Info.plist new file mode 100644 index 00000000..0f118fb7 --- /dev/null +++ b/ios/HomePlayerWidget/Info.plist @@ -0,0 +1,11 @@ + + + + + NSExtension + + NSExtensionPointIdentifier + com.apple.widgetkit-extension + + + diff --git a/ios/HomePlayerWidgetExtension.entitlements b/ios/HomePlayerWidgetExtension.entitlements new file mode 100644 index 00000000..58165678 --- /dev/null +++ b/ios/HomePlayerWidgetExtension.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.application-groups + + group.spotube_home_player_widget + + + diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 104ff767..31ffe436 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -64,6 +64,8 @@ PODS: - Flutter - flutter_sharing_intent (0.0.1): - Flutter + - home_widget (0.0.1): + - Flutter - image_picker_ios (0.0.1): - Flutter - integration_test (0.0.1): @@ -106,12 +108,15 @@ PODS: - sqlite3/common - sqlite3_flutter_libs (0.0.1): - Flutter - - sqlite3 (~> 3.47.0) + - FlutterMacOS + - sqlite3 (~> 3.47.1) - sqlite3/dbstatvtab - sqlite3/fts5 - sqlite3/perf-threadsafe - sqlite3/rtree - SwiftyGif (5.4.4) + - system_theme (0.0.1): + - Flutter - url_launcher_ios (0.0.1): - Flutter @@ -130,6 +135,7 @@ DEPENDENCIES: - flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`) - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) - flutter_sharing_intent (from `.symlinks/plugins/flutter_sharing_intent/ios`) + - home_widget (from `.symlinks/plugins/home_widget/ios`) - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) - integration_test (from `.symlinks/plugins/integration_test/ios`) - media_kit_libs_ios_audio (from `.symlinks/plugins/media_kit_libs_ios_audio/ios`) @@ -141,7 +147,8 @@ DEPENDENCIES: - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`) - - sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/ios`) + - sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/darwin`) + - system_theme (from `.symlinks/plugins/system_theme/ios`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) SPEC REPOS: @@ -182,6 +189,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/flutter_secure_storage/ios" flutter_sharing_intent: :path: ".symlinks/plugins/flutter_sharing_intent/ios" + home_widget: + :path: ".symlinks/plugins/home_widget/ios" image_picker_ios: :path: ".symlinks/plugins/image_picker_ios/ios" integration_test: @@ -205,7 +214,9 @@ EXTERNAL SOURCES: sqflite_darwin: :path: ".symlinks/plugins/sqflite_darwin/darwin" sqlite3_flutter_libs: - :path: ".symlinks/plugins/sqlite3_flutter_libs/ios" + :path: ".symlinks/plugins/sqlite3_flutter_libs/darwin" + system_theme: + :path: ".symlinks/plugins/system_theme/ios" url_launcher_ios: :path: ".symlinks/plugins/url_launcher_ios/ios" @@ -226,6 +237,7 @@ SPEC CHECKSUMS: flutter_native_splash: e8a1e01082d97a8099d973f919f57904c925008a flutter_secure_storage: d33dac7ae2ea08509be337e775f6b59f1ff45f12 flutter_sharing_intent: e35380d0e1501d7111dbb7e46d5ac6339da6da98 + home_widget: 0434835a4c9a75704264feff6be17ea40e0f0d57 image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1 integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573 media_kit_libs_ios_audio: 8f39d96a9c630685dfb844c289bd1d114c486fb3 @@ -240,8 +252,9 @@ SPEC CHECKSUMS: shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d sqlite3: 1e522f0938463e44b7faf50393b40bdc1e1e456d - sqlite3_flutter_libs: b55ef23cfafea5318ae5081e0bf3fbbce8417c94 + sqlite3_flutter_libs: 1b4e98da20ebd4e9b1240269b78cdcf492dbe9f3 SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f + system_theme: bfc1b0913d08f38d8c6bbe94b202a58df599d9f7 url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe PODFILE CHECKSUM: 0659b64ac6e9e96b61d8550decffa8bff51a957e diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 34793f68..63871a3d 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 54; + objectVersion = 70; objects = { /* Begin PBXBuildFile section */ @@ -36,8 +36,21 @@ B536BDD62B4060B3009B3CE4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; B536BDD72B4060B3009B3CE4 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; C36A05AD330BBFAED75A62D5 /* Pods_dev.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4238A4985255EC9F93067739 /* Pods_dev.framework */; }; + E612EC3B2D0F07A90022720C /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E612EC3A2D0F07A90022720C /* WidgetKit.framework */; }; + E612EC3D2D0F07A90022720C /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E612EC3C2D0F07A90022720C /* SwiftUI.framework */; }; + E612EC482D0F07AD0022720C /* HomePlayerWidgetExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = E612EC392D0F07A90022720C /* HomePlayerWidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + E612EC462D0F07AD0022720C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = E612EC382D0F07A80022720C; + remoteInfo = HomePlayerWidgetExtension; + }; +/* End PBXContainerItemProxy section */ + /* Begin PBXCopyFilesBuildPhase section */ 9705A1C41CF9048500538489 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; @@ -79,6 +92,17 @@ name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; + E612EC492D0F07AD0022720C /* Embed Foundation Extensions */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 13; + files = ( + E612EC482D0F07AD0022720C /* HomePlayerWidgetExtension.appex in Embed Foundation Extensions */, + ); + name = "Embed Foundation Extensions"; + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ @@ -148,6 +172,14 @@ D32BAE0F55672DD7669755B8 /* Pods-Runner.debug-stable.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug-stable.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug-stable.xcconfig"; sourceTree = ""; }; D9A69004587D01A7C68666CF /* Pods-dev.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-dev.release.xcconfig"; path = "Target Support Files/Pods-dev/Pods-dev.release.xcconfig"; sourceTree = ""; }; E0EAB4380EE7C7EA7A350B6F /* Pods-stable.release-nightly.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-stable.release-nightly.xcconfig"; path = "Target Support Files/Pods-stable/Pods-stable.release-nightly.xcconfig"; sourceTree = ""; }; + E612EC392D0F07A90022720C /* HomePlayerWidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = HomePlayerWidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + E612EC3A2D0F07A90022720C /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; }; + E612EC3C2D0F07A90022720C /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; }; + E6F17DB92D0F34E500BC2FA2 /* HomePlayerWidgetExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = HomePlayerWidgetExtension.entitlements; sourceTree = ""; }; + E6F17DBA2D0F352C00BC2FA2 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; }; + E6F17DBB2D0F356700BC2FA2 /* stable.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = stable.entitlements; sourceTree = ""; }; + E6F17DBC2D0F357500BC2FA2 /* dev.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = dev.entitlements; sourceTree = ""; }; + E6F17DBD2D0F357F00BC2FA2 /* nightly.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = nightly.entitlements; sourceTree = ""; }; E81F11471FD7D807286E33D6 /* Pods-dev.debug-dev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-dev.debug-dev.xcconfig"; path = "Target Support Files/Pods-dev/Pods-dev.debug-dev.xcconfig"; sourceTree = ""; }; EB7783C1029CEC13F4B05D36 /* Pods-nightly.debug-nightly.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-nightly.debug-nightly.xcconfig"; path = "Target Support Files/Pods-nightly/Pods-nightly.debug-nightly.xcconfig"; sourceTree = ""; }; EBBED0A8DE0D0E230CD03613 /* Pods-dev.release-stable.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-dev.release-stable.xcconfig"; path = "Target Support Files/Pods-dev/Pods-dev.release-stable.xcconfig"; sourceTree = ""; }; @@ -155,6 +187,20 @@ F7E9EBDD27997A73A4D38EE1 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ +/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ + E612EC562D0F07AD0022720C /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = { + isa = PBXFileSystemSynchronizedBuildFileExceptionSet; + membershipExceptions = ( + Info.plist, + ); + target = E612EC382D0F07A80022720C /* HomePlayerWidgetExtension */; + }; +/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ + +/* Begin PBXFileSystemSynchronizedRootGroup section */ + E612EC3E2D0F07A90022720C /* HomePlayerWidget */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (E612EC562D0F07AD0022720C /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = HomePlayerWidget; sourceTree = ""; }; +/* End PBXFileSystemSynchronizedRootGroup section */ + /* Begin PBXFrameworksBuildPhase section */ 97C146EB1CF9000F007C117D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; @@ -189,6 +235,15 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + E612EC362D0F07A80022720C /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + E612EC3D2D0F07A90022720C /* SwiftUI.framework in Frameworks */, + E612EC3B2D0F07A90022720C /* WidgetKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -199,6 +254,8 @@ 4238A4985255EC9F93067739 /* Pods_dev.framework */, BAC36FC304DBD4E8A8C00694 /* Pods_nightly.framework */, B5F91A319C771EEC978B238A /* Pods_stable.framework */, + E612EC3A2D0F07A90022720C /* WidgetKit.framework */, + E612EC3C2D0F07A90022720C /* SwiftUI.framework */, ); name = Frameworks; sourceTree = ""; @@ -272,8 +329,13 @@ 97C146E51CF9000F007C117D = { isa = PBXGroup; children = ( + E6F17DBD2D0F357F00BC2FA2 /* nightly.entitlements */, + E6F17DBC2D0F357500BC2FA2 /* dev.entitlements */, + E6F17DBB2D0F356700BC2FA2 /* stable.entitlements */, + E6F17DB92D0F34E500BC2FA2 /* HomePlayerWidgetExtension.entitlements */, 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, + E612EC3E2D0F07A90022720C /* HomePlayerWidget */, 97C146EF1CF9000F007C117D /* Products */, 67CBFE209DF24C94A9837AD5 /* Pods */, 0E0B839C4E103F896209E822 /* Frameworks */, @@ -290,6 +352,7 @@ B536BDA02B405DB1009B3CE4 /* stable.app */, B536BDBF2B405FDE009B3CE4 /* dev.app */, B536BDE42B4060B3009B3CE4 /* nightly.app */, + E612EC392D0F07A90022720C /* HomePlayerWidgetExtension.appex */, ); name = Products; sourceTree = ""; @@ -297,6 +360,7 @@ 97C146F01CF9000F007C117D /* Runner */ = { isa = PBXGroup; children = ( + E6F17DBA2D0F352C00BC2FA2 /* Runner.entitlements */, 97C146FA1CF9000F007C117D /* Main.storyboard */, 97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, @@ -325,10 +389,13 @@ 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 6E9FEF583EA597C8B76255B2 /* [CP] Embed Pods Frameworks */, 46F6EB27C31C41D86428A28B /* [CP] Copy Pods Resources */, + E612EC492D0F07AD0022720C /* Embed Foundation Extensions */, + E63F9CBC2D10709D00CD9E72 /* ShellScript */, ); buildRules = ( ); dependencies = ( + E612EC472D0F07AD0022720C /* PBXTargetDependency */, ); name = Runner; productName = Runner; @@ -404,12 +471,35 @@ productReference = B536BDE42B4060B3009B3CE4 /* nightly.app */; productType = "com.apple.product-type.application"; }; + E612EC382D0F07A80022720C /* HomePlayerWidgetExtension */ = { + isa = PBXNativeTarget; + buildConfigurationList = E612EC572D0F07AD0022720C /* Build configuration list for PBXNativeTarget "HomePlayerWidgetExtension" */; + buildPhases = ( + E612EC352D0F07A80022720C /* Sources */, + E612EC362D0F07A80022720C /* Frameworks */, + E612EC372D0F07A80022720C /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + fileSystemSynchronizedGroups = ( + E612EC3E2D0F07A90022720C /* HomePlayerWidget */, + ); + name = HomePlayerWidgetExtension; + packageProductDependencies = ( + ); + productName = HomePlayerWidgetExtension; + productReference = E612EC392D0F07A90022720C /* HomePlayerWidgetExtension.appex */; + productType = "com.apple.product-type.app-extension"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { + LastSwiftUpdateCheck = 1620; LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { @@ -417,6 +507,9 @@ CreatedOnToolsVersion = 7.3.1; LastSwiftMigration = 1100; }; + E612EC382D0F07A80022720C = { + CreatedOnToolsVersion = 16.2; + }; }; }; buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; @@ -436,6 +529,7 @@ B536BD8C2B405DB1009B3CE4 /* stable */, B536BDAB2B405FDE009B3CE4 /* dev */, B536BDCD2B4060B3009B3CE4 /* nightly */, + E612EC382D0F07A80022720C /* HomePlayerWidgetExtension */, ); }; /* End PBXProject section */ @@ -485,6 +579,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + E612EC372D0F07A80022720C /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ @@ -685,7 +786,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n"; }; A6D446F111DE4C4A202BE7F7 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; @@ -814,6 +915,23 @@ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-nightly/Pods-nightly-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; + E63F9CBC2D10709D00CD9E72 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "# Type a script or drag a sgeneratedPath=\"$SRCROOT/Flutter/Generated.xcconfig\"\n\n# Read and trim versionNumber and buildNumber\nversionNumber=$(grep FLUTTER_BUILD_NAME \"$generatedPath\" | cut -d '=' -f2 | xargs)\nbuildNumber=$(grep FLUTTER_BUILD_NUMBER \"$generatedPath\" | cut -d '=' -f2 | xargs)\n\ninfoPlistPath=\"$SRCROOT/HomePlayerWidget/Info.plist\"\n\n# Check and add CFBundleVersion if it does not exist\n/usr/libexec/PlistBuddy -c \"Print :CFBundleVersion\" \"$infoPlistPath\" 2>/dev/null\nif [ $? != 0 ]; then\n /usr/libexec/PlistBuddy -c \"Add :CFBundleVersion string $buildNumber\" \"$infoPlistPath\"\nelse\n /usr/libexec/PlistBuddy -c \"Set :CFBundleVersion $buildNumber\" \"$infoPlistPath\"\nfi\n\n# Check and add CFBundleShortVersionString if it does not exist\n/usr/libexec/PlistBuddy -c \"Print :CFBundleShortVersionString\" \"$infoPlistPath\" 2>/dev/null\nif [ $? != 0 ]; then\n /usr/libexec/PlistBuddy -c \"Add :CFBundleShortVersionString string $versionNumber\" \"$infoPlistPath\"\nelse\n /usr/libexec/PlistBuddy -c \"Set :CFBundleShortVersionString $versionNumber\" \"$infoPlistPath\"\nfi\n\ncript file from your workspace to insert its path.\n"; + }; F0C8BA10A27CA77E18F842E7 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -875,8 +993,23 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + E612EC352D0F07A80022720C /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + E612EC472D0F07AD0022720C /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = E612EC382D0F07A80022720C /* HomePlayerWidgetExtension */; + targetProxy = E612EC462D0F07AD0022720C /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin PBXVariantGroup section */ 97C146FA1CF9000F007C117D /* Main.storyboard */ = { isa = PBXVariantGroup; @@ -953,6 +1086,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -1082,6 +1216,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -1105,6 +1240,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -1127,6 +1263,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = stable.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -1150,6 +1287,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = stable.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -1172,6 +1310,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = stable.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -1249,6 +1388,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -1272,6 +1412,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = stable.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -1347,6 +1488,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -1369,6 +1511,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = stable.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -1441,6 +1584,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -1463,6 +1607,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = stable.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -1485,6 +1630,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = dev.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -1508,6 +1654,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = dev.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -1531,6 +1678,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = dev.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -1553,6 +1701,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = dev.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -1575,6 +1724,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = dev.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -1597,6 +1747,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = dev.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -1674,6 +1825,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -1697,6 +1849,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = stable.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -1720,6 +1873,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = dev.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -1795,6 +1949,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -1817,6 +1972,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = stable.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -1839,6 +1995,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = dev.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -1911,6 +2068,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -1933,6 +2091,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = stable.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -1955,6 +2114,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = dev.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -1977,6 +2137,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = nightly.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -2000,6 +2161,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = nightly.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -2023,6 +2185,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = nightly.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -2046,6 +2209,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = nightly.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -2068,6 +2232,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = nightly.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -2090,6 +2255,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = nightly.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -2112,6 +2278,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = nightly.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -2134,6 +2301,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = nightly.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -2156,6 +2324,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = nightly.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -2233,6 +2402,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -2256,6 +2426,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = stable.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -2279,6 +2450,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = dev.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -2302,6 +2474,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = nightly.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -2377,6 +2550,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -2399,6 +2573,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = stable.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -2421,6 +2596,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = dev.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -2443,6 +2619,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = nightly.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -2515,6 +2692,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -2537,6 +2715,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = stable.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -2559,6 +2738,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = dev.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -2581,6 +2761,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = nightly.entitlements; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; @@ -2597,6 +2778,498 @@ }; name = "Profile-nightly"; }; + E612EC4A2D0F07AD0022720C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = HomePlayerWidgetExtension.entitlements; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 88NVGSJ5N3; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = HomePlayerWidget/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = HomePlayerWidget; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 18.2; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.HomePlayerWidget; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + E612EC4B2D0F07AD0022720C /* Debug-nightly */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = HomePlayerWidgetExtension.entitlements; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 88NVGSJ5N3; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = HomePlayerWidget/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = HomePlayerWidget; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 18.2; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.HomePlayerWidget; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Debug-nightly"; + }; + E612EC4C2D0F07AD0022720C /* Debug-dev */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = HomePlayerWidgetExtension.entitlements; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 88NVGSJ5N3; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = HomePlayerWidget/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = HomePlayerWidget; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 18.2; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.HomePlayerWidget; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Debug-dev"; + }; + E612EC4D2D0F07AD0022720C /* Debug-stable */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = HomePlayerWidgetExtension.entitlements; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 88NVGSJ5N3; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = HomePlayerWidget/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = HomePlayerWidget; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 18.2; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.HomePlayerWidget; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Debug-stable"; + }; + E612EC4E2D0F07AD0022720C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = HomePlayerWidgetExtension.entitlements; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 88NVGSJ5N3; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = HomePlayerWidget/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = HomePlayerWidget; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 18.2; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.HomePlayerWidget; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + E612EC4F2D0F07AD0022720C /* Release-nightly */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = HomePlayerWidgetExtension.entitlements; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 88NVGSJ5N3; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = HomePlayerWidget/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = HomePlayerWidget; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 18.2; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.HomePlayerWidget; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Release-nightly"; + }; + E612EC502D0F07AD0022720C /* Release-dev */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = HomePlayerWidgetExtension.entitlements; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 88NVGSJ5N3; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = HomePlayerWidget/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = HomePlayerWidget; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 18.2; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.HomePlayerWidget; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Release-dev"; + }; + E612EC512D0F07AD0022720C /* Release-stable */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = HomePlayerWidgetExtension.entitlements; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 88NVGSJ5N3; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = HomePlayerWidget/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = HomePlayerWidget; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 18.2; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.HomePlayerWidget; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Release-stable"; + }; + E612EC522D0F07AD0022720C /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = HomePlayerWidgetExtension.entitlements; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 88NVGSJ5N3; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = HomePlayerWidget/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = HomePlayerWidget; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 18.2; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.HomePlayerWidget; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Profile; + }; + E612EC532D0F07AD0022720C /* Profile-nightly */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = HomePlayerWidgetExtension.entitlements; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 88NVGSJ5N3; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = HomePlayerWidget/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = HomePlayerWidget; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 18.2; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.HomePlayerWidget; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Profile-nightly"; + }; + E612EC542D0F07AD0022720C /* Profile-dev */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = HomePlayerWidgetExtension.entitlements; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 88NVGSJ5N3; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = HomePlayerWidget/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = HomePlayerWidget; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 18.2; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.HomePlayerWidget; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Profile-dev"; + }; + E612EC552D0F07AD0022720C /* Profile-stable */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = HomePlayerWidgetExtension.entitlements; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 88NVGSJ5N3; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = HomePlayerWidget/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = HomePlayerWidget; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 18.2; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.HomePlayerWidget; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Profile-stable"; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -2695,6 +3368,25 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + E612EC572D0F07AD0022720C /* Build configuration list for PBXNativeTarget "HomePlayerWidgetExtension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + E612EC4A2D0F07AD0022720C /* Debug */, + E612EC4B2D0F07AD0022720C /* Debug-nightly */, + E612EC4C2D0F07AD0022720C /* Debug-dev */, + E612EC4D2D0F07AD0022720C /* Debug-stable */, + E612EC4E2D0F07AD0022720C /* Release */, + E612EC4F2D0F07AD0022720C /* Release-nightly */, + E612EC502D0F07AD0022720C /* Release-dev */, + E612EC512D0F07AD0022720C /* Release-stable */, + E612EC522D0F07AD0022720C /* Profile */, + E612EC532D0F07AD0022720C /* Profile-nightly */, + E612EC542D0F07AD0022720C /* Profile-dev */, + E612EC552D0F07AD0022720C /* Profile-stable */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ }; rootObject = 97C146E61CF9000F007C117D /* Project object */; diff --git a/ios/Runner/Runner.entitlements b/ios/Runner/Runner.entitlements new file mode 100644 index 00000000..58165678 --- /dev/null +++ b/ios/Runner/Runner.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.application-groups + + group.spotube_home_player_widget + + + diff --git a/ios/dev.entitlements b/ios/dev.entitlements new file mode 100644 index 00000000..58165678 --- /dev/null +++ b/ios/dev.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.application-groups + + group.spotube_home_player_widget + + + diff --git a/ios/nightly.entitlements b/ios/nightly.entitlements new file mode 100644 index 00000000..58165678 --- /dev/null +++ b/ios/nightly.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.application-groups + + group.spotube_home_player_widget + + + diff --git a/ios/stable.entitlements b/ios/stable.entitlements new file mode 100644 index 00000000..58165678 --- /dev/null +++ b/ios/stable.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.application-groups + + group.spotube_home_player_widget + + + diff --git a/lib/main.dart b/lib/main.dart index f13991e2..fa567129 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -9,6 +9,7 @@ import 'package:flutter_discord_rpc/flutter_discord_rpc.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:hive/hive.dart'; +import 'package:home_widget/home_widget.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:local_notifier/local_notifier.dart'; import 'package:media_kit/media_kit.dart'; @@ -27,6 +28,7 @@ import 'package:spotube/hooks/configurators/use_has_touch.dart'; import 'package:spotube/models/database/database.dart'; import 'package:spotube/provider/audio_player/audio_player_streams.dart'; import 'package:spotube/provider/database/database.dart'; +import 'package:spotube/provider/glance/glance.dart'; import 'package:spotube/provider/server/bonsoir.dart'; import 'package:spotube/provider/server/server.dart'; import 'package:spotube/provider/tray_manager/tray_manager.dart'; @@ -115,6 +117,10 @@ Future main(List rawArgs) async { await WindowManagerTools.initialize(); } + if (kIsIOS) { + HomeWidget.setAppGroupId("group.spotube_home_player_widget"); + } + runApp( ProviderScope( overrides: [ @@ -161,6 +167,10 @@ class Spotube extends HookConsumerWidget { useEffect(() { FlutterNativeSplash.remove(); + if (kIsMobile) { + HomeWidget.registerInteractivityCallback(glanceBackgroundCallback); + } + return () { /// For enabling hot reload for audio player if (!kDebugMode) return; diff --git a/lib/pages/root/root_app.dart b/lib/pages/root/root_app.dart index 0274de00..2a6c36f0 100644 --- a/lib/pages/root/root_app.dart +++ b/lib/pages/root/root_app.dart @@ -18,6 +18,7 @@ import 'package:spotube/hooks/configurators/use_endless_playback.dart'; import 'package:spotube/pages/home/home.dart'; import 'package:spotube/provider/download_manager_provider.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; +import 'package:spotube/provider/glance/glance.dart'; import 'package:spotube/provider/server/routes/connect.dart'; import 'package:spotube/services/connectivity_adapter.dart'; import 'package:spotube/utils/platform.dart'; @@ -39,6 +40,8 @@ class RootApp extends HookConsumerWidget { final scaffoldMessenger = ScaffoldMessenger.of(context); final connectRoutes = ref.watch(serverConnectRoutesProvider); + ref.listen(glanceProvider, (_, __) {}); + useEffect(() { WidgetsBinding.instance.addPostFrameCallback((_) async { ServiceUtils.checkForUpdates(context, ref); diff --git a/lib/provider/glance/glance.dart b/lib/provider/glance/glance.dart new file mode 100644 index 00000000..22faa13f --- /dev/null +++ b/lib/provider/glance/glance.dart @@ -0,0 +1,169 @@ +import 'dart:convert'; + +import 'package:flutter_cache_manager/flutter_cache_manager.dart'; +import 'package:home_widget/home_widget.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:http/http.dart'; +import 'package:logger/logger.dart'; +import 'package:spotify/spotify.dart'; +import 'package:spotube/provider/audio_player/audio_player.dart'; +import 'package:spotube/provider/server/server.dart'; +import 'package:spotube/services/audio_player/audio_player.dart'; +import 'package:spotube/services/logger/logger.dart'; +import 'package:spotube/utils/platform.dart'; + +@pragma("vm:entry-point") +Future glanceBackgroundCallback(Uri? data) async { + final logger = Logger(); + try { + if (data == null || + data.host != "playback" || + data.pathSegments.isEmpty || + data.queryParameters["serverAddress"] == null) { + return; + } + + final command = data.pathSegments.first; + final res = await get( + Uri.parse( + "http://${data.queryParameters["serverAddress"]}/playback/$command", + ), + ); + + if (res.statusCode != 200) { + throw Exception("Failed to execute command: $command\nBody: ${res.body}"); + } + } catch (e) { + logger.e("[GlanceBackgroundCallback] $e"); + } +} + +Future _saveWidgetData(String key, T? value) async { + try { + if (!kIsMobile) return null; + + return await HomeWidget.saveWidgetData(key, value); + } catch (e, stack) { + AppLogger.reportError(e, stack); + return null; + } +} + +Future _updateWidget() async { + try { + if (!kIsMobile) return; + + if (kIsAndroid) { + await HomeWidget.updateWidget( + androidName: 'HomePlayerWidgetReceiver', + qualifiedAndroidName: + 'oss.krtirtho.spotube.glance.HomePlayerWidgetReceiver', + ); + } + if (kIsIOS) { + await HomeWidget.updateWidget( + name: 'HomePlayerWidget', + iOSName: 'HomePlayerWidget', + ); + } + } on Exception catch (e, stack) { + AppLogger.reportError(e, stack); + } +} + +Future _sendActiveTrack(Track? track) async { + if (track == null) { + await _saveWidgetData("activeTrack", null); + await _updateWidget(); + return; + } + + final jsonTrack = track.toJson(); + + final image = track.album?.images?.first; + final cachedImage = await DefaultCacheManager().getSingleFile(image!.url!); + final data = { + ...jsonTrack, + "album": { + ...jsonTrack["album"], + "images": [ + { + ...image.toJson(), + "path": cachedImage.path, + } + ] + } + }; + + await _saveWidgetData("activeTrack", jsonEncode(data)); + + await _updateWidget(); +} + +final glanceProvider = Provider((ref) { + final server = ref.read(serverProvider); + final activeTrack = ref.read(audioPlayerProvider).activeTrack; + + server.whenData( + (value) async { + final (:server, :port) = value; + + await _saveWidgetData( + "playbackServerAddress", + "${server.address.host}:$port", + ); + await _updateWidget(); + }, + ); + + _sendActiveTrack(activeTrack); + + ref.listen(serverProvider, (prev, next) async { + next.whenData( + (value) async { + final (:server, :port) = value; + + await _saveWidgetData( + "playbackServerAddress", + "${server.address.host}:$port", + ); + await _updateWidget(); + }, + ); + }); + + ref.listen( + audioPlayerProvider, + (previous, next) async { + try { + if (previous?.activeTrack != next.activeTrack && + next.activeTrack != null) { + await _sendActiveTrack(next.activeTrack); + } + } catch (e, stack) { + AppLogger.reportError(e, stack); + } + }, + ); + + final subscriptions = [ + audioPlayer.playingStream.listen((playing) async { + await _saveWidgetData("isPlaying", playing); + await _updateWidget(); + }), + audioPlayer.positionStream.listen((position) async { + await _saveWidgetData("position", position.inSeconds); + await _updateWidget(); + }), + audioPlayer.durationStream.listen((duration) async { + await _saveWidgetData("duration", duration.inSeconds); + await _updateWidget(); + }), + ]; + + ref.onDispose(() { + for (final subscription in subscriptions) { + subscription.cancel(); + } + }); +}); diff --git a/lib/provider/server/router.dart b/lib/provider/server/router.dart index e2a579cc..06ff4a24 100644 --- a/lib/provider/server/router.dart +++ b/lib/provider/server/router.dart @@ -14,6 +14,10 @@ final serverRouterProvider = Provider((ref) { router.get("/stream/", playbackRoutes.getStreamTrackId); + router.get("/playback/toggle-playback", playbackRoutes.togglePlayback); + router.get("/playback/previous", playbackRoutes.previousTrack); + router.get("/playback/next", playbackRoutes.nextTrack); + router.all("/ws", connectRoutes.websocket); return router; diff --git a/lib/provider/server/routes/playback.dart b/lib/provider/server/routes/playback.dart index 34317aa1..289da0e3 100644 --- a/lib/provider/server/routes/playback.dart +++ b/lib/provider/server/routes/playback.dart @@ -188,6 +188,27 @@ class ServerPlaybackRoutes { return Response.internalServerError(); } } + + /// @get('/playback/toggle-playback') + Future togglePlayback(Request request) async { + audioPlayer.isPlaying + ? await audioPlayer.pause() + : await audioPlayer.resume(); + + return Response.ok("Playback toggled"); + } + + /// @get('/playback/previous') + Future previousTrack(Request request) async { + await audioPlayer.skipToPrevious(); + return Response.ok("Previous track"); + } + + /// @get('/playback/next') + Future nextTrack(Request request) async { + await audioPlayer.skipToNext(); + return Response.ok("Next track"); + } } final serverPlaybackRoutesProvider = diff --git a/pubspec.lock b/pubspec.lock index e6e365a6..5aa4f9b4 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -42,10 +42,10 @@ packages: dependency: "direct main" description: name: app_links - sha256: "433df2e61b10519407475d7f69e470789d23d593f28224c38ba1068597be7950" + sha256: ad1a6d598e7e39b46a34f746f9a8b011ee147e4c275d407fa457e7a62f84dd99 url: "https://pub.dev" source: hosted - version: "6.3.3" + version: "6.3.2" app_links_linux: dependency: transitive description: @@ -1095,6 +1095,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.1" + home_widget: + dependency: "direct main" + description: + name: home_widget + sha256: b313e3304c0429669fddf1286e1fbf61a64b873f38ba30b3eb890ef0d7560b12 + url: "https://pub.dev" + source: hosted + version: "0.7.0" hooks_riverpod: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 072c9a0a..3866e410 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -71,6 +71,7 @@ dependencies: google_fonts: ^6.2.1 hive: ^2.2.3 hive_flutter: ^1.1.0 + home_widget: ^0.7.0 hooks_riverpod: ^2.5.1 html: ^0.15.1 html_unescape: ^2.0.0 @@ -162,6 +163,7 @@ flutter: - assets/ - assets/tutorial/ - assets/logos/ + - assets/backgrounds/ - LICENSE flutter_gen: From 5ad151932ab6684e3fe1c1ba2a22a8a8d64bb05b Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 21 Dec 2024 09:22:30 +0600 Subject: [PATCH 009/112] feat: initial integration of shadcn-ui --- lib/main.dart | 57 ++-- lib/models/database/database.dart | 3 +- lib/modules/root/sidebar.dart | 250 ++++---------- lib/pages/settings/sections/appearance.dart | 3 +- .../user_preferences_provider.dart | 3 +- lib/utils/migrations/hive.dart | 319 ------------------ linux/flutter/generated_plugin_registrant.cc | 4 + linux/flutter/generated_plugins.cmake | 1 + macos/Flutter/GeneratedPluginRegistrant.swift | 2 + macos/Podfile.lock | 31 +- pubspec.lock | 128 +++++++ pubspec.yaml | 48 +++ web/flutter_bootstrap.js | 238 +++++++++++++ .../flutter/generated_plugin_registrant.cc | 3 + windows/flutter/generated_plugins.cmake | 1 + 15 files changed, 549 insertions(+), 542 deletions(-) delete mode 100644 lib/utils/migrations/hive.dart create mode 100644 web/flutter_bootstrap.js diff --git a/lib/main.dart b/lib/main.dart index fa567129..3ed4314b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,7 +3,6 @@ import 'dart:ui'; import 'package:desktop_webview_window/desktop_webview_window.dart'; import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_discord_rpc/flutter_discord_rpc.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; @@ -34,7 +33,6 @@ import 'package:spotube/provider/server/server.dart'; import 'package:spotube/provider/tray_manager/tray_manager.dart'; import 'package:spotube/l10n/l10n.dart'; import 'package:spotube/provider/connect/clients.dart'; -import 'package:spotube/provider/palette_provider.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/services/audio_player/audio_player.dart'; import 'package:spotube/services/cli/cli.dart'; @@ -42,8 +40,6 @@ import 'package:spotube/services/kv_store/encrypted_kv_store.dart'; import 'package:spotube/services/kv_store/kv_store.dart'; import 'package:spotube/services/logger/logger.dart'; import 'package:spotube/services/wm_tools/wm_tools.dart'; -import 'package:spotube/themes/theme.dart'; -import 'package:spotube/utils/migrations/hive.dart'; import 'package:spotube/utils/migrations/sandbox.dart'; import 'package:spotube/utils/platform.dart'; import 'package:system_theme/system_theme.dart'; @@ -53,6 +49,7 @@ import 'package:flutter_native_splash/flutter_native_splash.dart'; import 'package:flutter_displaymode/flutter_displaymode.dart'; import 'package:timezone/data/latest.dart' as tz; import 'package:window_manager/window_manager.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; Future main(List rawArgs) async { if (rawArgs.contains("web_view_title_bar")) { @@ -110,8 +107,6 @@ Future main(List rawArgs) async { final database = AppDatabase(); - await migrateFromHiveToDrift(database); - if (kIsDesktop) { await localNotifier.setup(appName: "Spotube"); await WindowManagerTools.initialize(); @@ -142,13 +137,13 @@ class Spotube extends HookConsumerWidget { Widget build(BuildContext context, ref) { final themeMode = ref.watch(userPreferencesProvider.select((s) => s.themeMode)); - final accentMaterialColor = - ref.watch(userPreferencesProvider.select((s) => s.accentColorScheme)); - final isAmoledTheme = - ref.watch(userPreferencesProvider.select((s) => s.amoledDarkTheme)); final locale = ref.watch(userPreferencesProvider.select((s) => s.locale)); - final paletteColor = - ref.watch(paletteProvider.select((s) => s?.dominantColor?.color)); + // final accentMaterialColor = + // ref.watch(userPreferencesProvider.select((s) => s.accentColorScheme)); + // final isAmoledTheme = + // ref.watch(userPreferencesProvider.select((s) => s.amoledDarkTheme)); + // final paletteColor = + // ref.watch(paletteProvider.select((s) => s?.dominantColor?.color)); final router = ref.watch(routerProvider); final hasTouchSupport = useHasTouch(); @@ -178,20 +173,20 @@ class Spotube extends HookConsumerWidget { }; }, []); - final lightTheme = useMemoized( - () => theme(paletteColor ?? accentMaterialColor, Brightness.light, false), - [paletteColor, accentMaterialColor], - ); - final darkTheme = useMemoized( - () => theme( - paletteColor ?? accentMaterialColor, - Brightness.dark, - isAmoledTheme, - ), - [paletteColor, accentMaterialColor, isAmoledTheme], - ); + // final lightTheme = useMemoized( + // () => theme(paletteColor ?? accentMaterialColor, Brightness.light, false), + // [paletteColor, accentMaterialColor], + // ); + // final darkTheme = useMemoized( + // () => theme( + // paletteColor ?? accentMaterialColor, + // Brightness.dark, + // isAmoledTheme, + // ), + // [paletteColor, accentMaterialColor, isAmoledTheme], + // ); - return MaterialApp.router( + return ShadcnApp.router( supportedLocales: L10n.all, locale: locale.languageCode == "system" ? null : locale, localizationsDelegates: const [ @@ -221,9 +216,17 @@ class Spotube extends HookConsumerWidget { return child; }, + theme: ThemeData( + radius: .5, + iconTheme: const IconThemeProperties(), + colorScheme: ColorSchemes.lightNeutral(), + ), + darkTheme: ThemeData( + radius: .5, + iconTheme: const IconThemeProperties(), + colorScheme: ColorSchemes.darkNeutral(), + ), themeMode: themeMode, - theme: lightTheme, - darkTheme: darkTheme, shortcuts: { ...WidgetsApp.defaultShortcuts.map((key, value) { return MapEntry( diff --git a/lib/models/database/database.dart b/lib/models/database/database.dart index 0f30df19..f76d25bc 100644 --- a/lib/models/database/database.dart +++ b/lib/models/database/database.dart @@ -8,13 +8,14 @@ import 'package:encrypt/encrypt.dart'; import 'package:media_kit/media_kit.dart' hide Track; import 'package:path/path.dart'; import 'package:path_provider/path_provider.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart' show ThemeMode, Colors; import 'package:spotify/spotify.dart' hide Playlist; import 'package:spotube/models/database/database.steps.dart'; import 'package:spotube/models/lyrics.dart'; import 'package:spotube/services/kv_store/encrypted_kv_store.dart'; import 'package:spotube/services/kv_store/kv_store.dart'; import 'package:spotube/services/sourced_track/enums.dart'; -import 'package:flutter/material.dart' hide Table, Key, View; +import 'package:flutter/widgets.dart' hide Table, Key, View; import 'package:spotube/modules/settings/color_scheme_picker_dialog.dart'; import 'package:drift/native.dart'; import 'package:sqlite3/sqlite3.dart'; diff --git a/lib/modules/root/sidebar.dart b/lib/modules/root/sidebar.dart index f29644fb..4f3c4442 100644 --- a/lib/modules/root/sidebar.dart +++ b/lib/modules/root/sidebar.dart @@ -1,33 +1,28 @@ -import 'package:collection/collection.dart'; +import 'package:flutter/material.dart' show Badge; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:gap/gap.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:flutter/material.dart'; -import 'package:sidebarx/sidebarx.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/collections/assets.gen.dart'; import 'package:spotube/collections/side_bar_tiles.dart'; import 'package:spotube/collections/spotube_icons.dart'; -import 'package:spotube/models/database/database.dart'; -import 'package:spotube/modules/connect/connect_device.dart'; import 'package:spotube/components/image/universal_image.dart'; +import 'package:spotube/extensions/image.dart'; +import 'package:spotube/models/database/database.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/extensions/image.dart'; -import 'package:spotube/hooks/utils/use_brightness_value.dart'; -import 'package:spotube/hooks/controllers/use_sidebarx_controller.dart'; +import 'package:spotube/modules/connect/connect_device.dart'; import 'package:spotube/pages/profile/profile.dart'; import 'package:spotube/pages/settings/settings.dart'; -import 'package:spotube/provider/download_manager_provider.dart'; import 'package:spotube/provider/authentication/authentication.dart'; +import 'package:spotube/provider/download_manager_provider.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; -import 'package:spotube/utils/platform.dart'; import 'package:spotube/utils/service_utils.dart'; -import 'package:window_manager/window_manager.dart'; class Sidebar extends HookConsumerWidget { final Widget child; @@ -66,173 +61,65 @@ class Sidebar extends HookConsumerWidget { (e) => routerState.namedLocation(e.name) == routerState.matchedLocation, ); - final controller = useSidebarXController( - selectedIndex: selectedIndex, - extended: mediaQuery.lgAndUp, - ); - - final theme = Theme.of(context); - final bg = theme.colorScheme.surfaceContainerHighest; - - final bgColor = useBrightnessValue( - Color.lerp(bg, Colors.white, 0.6), - Color.lerp(bg, Colors.black, 0.45)!, - ); - - useEffect(() { - if (!context.mounted) return; - if (mediaQuery.lgAndUp && !controller.extended) { - controller.setExtended(true); - } else if (mediaQuery.mdAndDown && controller.extended) { - controller.setExtended(false); - } - return null; - }, [mediaQuery, controller]); - - useEffect(() { - if (controller.selectedIndex != selectedIndex) { - controller.selectIndex(selectedIndex); - } - return null; - }, [selectedIndex]); - if (layoutMode == LayoutMode.compact || (mediaQuery.smAndDown && layoutMode == LayoutMode.adaptive)) { - return Scaffold(body: child); + return Scaffold(child: child); } - return Row( - children: [ - SafeArea( - child: SidebarX( - controller: controller, - items: sidebarTileList.mapIndexed( - (index, e) { - return SidebarXItem( - onTap: () { - context.goNamed(e.name); - }, - iconBuilder: (selected, hovered) { - return Badge( - backgroundColor: theme.colorScheme.primary, - isLabelVisible: e.title == "Library" && downloadCount > 0, - label: Text( - downloadCount.toString(), - style: const TextStyle( - color: Colors.white, - fontSize: 10, - ), - ), - child: Icon( - e.icon, - color: selected || hovered - ? theme.colorScheme.primary - : null, - ), - ); - }, - label: e.title, - ); - }, - ).toList(), - headerBuilder: (_, __) => const SidebarHeader(), - footerBuilder: (_, __) => const Padding( - padding: EdgeInsets.only(bottom: 5), - child: SidebarFooter(), - ), - showToggleButton: false, - theme: SidebarXTheme( - width: 50, - margin: EdgeInsets.only(bottom: 10, top: kIsMacOS ? 35 : 5), - selectedItemDecoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - color: theme.colorScheme.primary.withOpacity(0.1), - ), - selectedIconTheme: IconThemeData( - color: theme.colorScheme.primary, - ), - ), - extendedTheme: SidebarXTheme( - width: 250, - margin: EdgeInsets.only( - bottom: 10, - left: 0, - top: kIsMacOS ? 0 : 5, - ), - padding: const EdgeInsets.symmetric(horizontal: 6), - decoration: BoxDecoration( - color: bgColor?.withOpacity(0.8), - borderRadius: const BorderRadius.only( - topRight: Radius.circular(10), - bottomRight: Radius.circular(10), - ), - ), - selectedItemDecoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - color: theme.colorScheme.primary.withOpacity(0.1), - ), - selectedIconTheme: IconThemeData( - color: theme.colorScheme.primary, - ), - selectedTextStyle: theme.textTheme.bodyMedium?.copyWith( - color: theme.colorScheme.primary, - fontWeight: FontWeight.w600, - ), - itemTextPadding: const EdgeInsets.only(left: 10), - selectedItemTextPadding: const EdgeInsets.only(left: 10), - hoverTextStyle: theme.textTheme.bodyMedium?.copyWith( - color: theme.colorScheme.primary, - ), - ), - ), - ), - Expanded(child: child) - ], - ); - } -} - -class SidebarHeader extends HookWidget { - const SidebarHeader({super.key}); - - @override - Widget build(BuildContext context) { - final mediaQuery = MediaQuery.of(context); - final theme = Theme.of(context); - - if (mediaQuery.mdAndDown) { - return Container( - height: 40, - width: 40, - margin: const EdgeInsets.only(bottom: 5), - child: Sidebar.brandLogo(), - ); - } - - return DragToMoveArea( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - children: [ - if (kIsMacOS) const SizedBox(height: 25), - Row( + return LayoutBuilder(builder: (context, constrains) { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SafeArea( + child: Column( children: [ - Sidebar.brandLogo(), - const SizedBox(width: 10), - Text( - "Spotube", - style: theme.textTheme.titleLarge, + Expanded( + child: NavigationSidebar( + index: selectedIndex, + onSelected: (index) { + final tile = sidebarTileList[index]; + ServiceUtils.pushNamed(context, tile.name); + }, + children: [ + const NavigationLabel(child: Text("Spotube")), + for (final tile in sidebarTileList) + NavigationButton( + label: Text(tile.title), + child: Badge( + backgroundColor: context.theme.colorScheme.primary, + isLabelVisible: + tile.title == "Library" && downloadCount > 0, + label: Text( + downloadCount.toString(), + style: const TextStyle( + color: Colors.white, + fontSize: 10, + ), + ), + child: Icon(tile.icon), + ), + onChanged: (value) { + if (value) { + context.goNamed(tile.name); + } + }, + ), + ], + ), ), + const SidebarFooter(), ], ), - ], - ), - ), - ); + ), + const VerticalDivider(), + Expanded(child: child), + ], + ); + }); } } -class SidebarFooter extends HookConsumerWidget { +class SidebarFooter extends HookConsumerWidget implements NavigationBarItem { const SidebarFooter({ super.key, }); @@ -253,6 +140,7 @@ class SidebarFooter extends HookConsumerWidget { if (mediaQuery.mdAndDown) { return IconButton( + variance: ButtonVariance.ghost, icon: const Icon(SpotubeIcons.settings), onPressed: () => ServiceUtils.navigateNamed(context, SettingsPage.name), ); @@ -260,8 +148,9 @@ class SidebarFooter extends HookConsumerWidget { return Container( padding: const EdgeInsets.only(left: 12), - width: 250, + width: 180, child: Column( + mainAxisSize: MainAxisSize.min, children: [ const ConnectDeviceButton.sidebar(), const Gap(10), @@ -273,21 +162,16 @@ class SidebarFooter extends HookConsumerWidget { const CircularProgressIndicator() else if (data != null) Flexible( - child: InkWell( + child: GestureDetector( onTap: () { ServiceUtils.pushNamed(context, ProfilePage.name); }, - borderRadius: BorderRadius.circular(30), child: Row( children: [ - CircleAvatar( - backgroundImage: - UniversalImage.imageProvider(avatarImg), - onBackgroundImageError: (exception, stackTrace) => - Assets.userPlaceholder.image( - height: 16, - width: 16, - ), + Avatar( + initials: + Avatar.getInitials(data.displayName ?? "User"), + provider: UniversalImage.imageProvider(avatarImg), ), const SizedBox(width: 10), Flexible( @@ -296,8 +180,8 @@ class SidebarFooter extends HookConsumerWidget { maxLines: 1, softWrap: false, overflow: TextOverflow.fade, - style: theme.textTheme.bodyMedium - ?.copyWith(fontWeight: FontWeight.bold), + style: theme.typography.normal + .copyWith(fontWeight: FontWeight.bold), ), ), ], @@ -305,6 +189,7 @@ class SidebarFooter extends HookConsumerWidget { ), ), IconButton( + variance: ButtonVariance.ghost, icon: const Icon(SpotubeIcons.settings), onPressed: () { ServiceUtils.pushNamed(context, SettingsPage.name); @@ -316,4 +201,7 @@ class SidebarFooter extends HookConsumerWidget { ), ); } + + @override + bool get selectable => false; } diff --git a/lib/pages/settings/sections/appearance.dart b/lib/pages/settings/sections/appearance.dart index f97add42..9a95e60b 100644 --- a/lib/pages/settings/sections/appearance.dart +++ b/lib/pages/settings/sections/appearance.dart @@ -1,4 +1,5 @@ -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart' hide ThemeMode; +import 'package:shadcn_flutter/shadcn_flutter.dart' show ThemeMode; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; diff --git a/lib/provider/user_preferences/user_preferences_provider.dart b/lib/provider/user_preferences/user_preferences_provider.dart index 053f0994..0f9efce1 100644 --- a/lib/provider/user_preferences/user_preferences_provider.dart +++ b/lib/provider/user_preferences/user_preferences_provider.dart @@ -1,8 +1,9 @@ import 'package:drift/drift.dart'; -import 'package:flutter/material.dart'; + import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:path/path.dart'; import 'package:path_provider/path_provider.dart' as paths; +import 'package:shadcn_flutter/shadcn_flutter.dart' hide join; import 'package:spotify/spotify.dart'; import 'package:spotube/models/database/database.dart'; import 'package:spotube/modules/settings/color_scheme_picker_dialog.dart'; diff --git a/lib/utils/migrations/hive.dart b/lib/utils/migrations/hive.dart deleted file mode 100644 index e5781931..00000000 --- a/lib/utils/migrations/hive.dart +++ /dev/null @@ -1,319 +0,0 @@ -import 'package:drift/drift.dart'; -import 'package:flutter/foundation.dart'; -import 'package:hive/hive.dart'; -import 'package:path_provider/path_provider.dart'; -import 'package:spotube/models/database/database.dart' - hide - SourceType, - AudioSource, - CloseBehavior, - MusicCodec, - LayoutMode, - SearchMode, - BlacklistedType; -import 'package:spotube/models/database/database.dart' as db; -import 'package:spotube/services/kv_store/kv_store.dart'; -import 'package:spotube/services/logger/logger.dart'; -import 'package:spotube/utils/migrations/adapters.dart'; -import 'package:spotube/utils/migrations/cache_box.dart'; - -late AppDatabase _database; - -Future getHiveCacheDir() async => - kIsWeb ? null : (await getApplicationSupportDirectory()).path; - -Future migrateAuthenticationInfo() async { - AppLogger.log.i("🔵 Migrating authentication info.."); - - final box = PersistenceCacheBox( - "authentication", - encrypted: true, - fromJson: (json) => AuthenticationCredentials.fromJson(json), - ); - - final credentials = await box.getData(); - - if (credentials == null) return; - - await _database.into(_database.authenticationTable).insert( - AuthenticationTableCompanion.insert( - accessToken: DecryptedText(credentials.accessToken), - cookie: DecryptedText(credentials.cookie), - expiration: credentials.expiration, - id: const Value(0), - ), - mode: InsertMode.insertOrReplace, - ); - - AppLogger.log.i("✅ Migrated authentication info"); -} - -Future migratePreferences() async { - AppLogger.log.i("🔵 Migrating preferences.."); - final box = PersistenceCacheBox( - "preferences", - fromJson: (json) => UserPreferences.fromJson(json), - ); - - final preferences = await box.getData(); - - if (preferences == null) return; - - await _database.into(_database.preferencesTable).insert( - PreferencesTableCompanion.insert( - id: const Value(0), - accentColorScheme: Value(preferences.accentColorScheme), - albumColorSync: Value(preferences.albumColorSync), - amoledDarkTheme: Value(preferences.amoledDarkTheme), - audioQuality: Value(preferences.audioQuality), - audioSource: Value( - switch (preferences.audioSource) { - AudioSource.youtube => db.AudioSource.youtube, - AudioSource.piped => db.AudioSource.piped, - AudioSource.jiosaavn => db.AudioSource.jiosaavn, - }, - ), - checkUpdate: Value(preferences.checkUpdate), - closeBehavior: Value( - switch (preferences.closeBehavior) { - CloseBehavior.minimizeToTray => db.CloseBehavior.minimizeToTray, - CloseBehavior.close => db.CloseBehavior.close, - }, - ), - discordPresence: Value(preferences.discordPresence), - downloadLocation: Value(preferences.downloadLocation), - downloadMusicCodec: Value(preferences.downloadMusicCodec), - enableConnect: Value(preferences.enableConnect), - endlessPlayback: Value(preferences.endlessPlayback), - layoutMode: Value( - switch (preferences.layoutMode) { - LayoutMode.adaptive => db.LayoutMode.adaptive, - LayoutMode.compact => db.LayoutMode.compact, - LayoutMode.extended => db.LayoutMode.extended, - }, - ), - localLibraryLocation: Value(preferences.localLibraryLocation), - locale: Value(preferences.locale), - market: Value(preferences.recommendationMarket), - normalizeAudio: Value(preferences.normalizeAudio), - pipedInstance: Value(preferences.pipedInstance), - searchMode: Value( - switch (preferences.searchMode) { - SearchMode.youtube => db.SearchMode.youtube, - SearchMode.youtubeMusic => db.SearchMode.youtubeMusic, - }, - ), - showSystemTrayIcon: Value(preferences.showSystemTrayIcon), - skipNonMusic: Value(preferences.skipNonMusic), - streamMusicCodec: Value(preferences.streamMusicCodec), - systemTitleBar: Value(preferences.systemTitleBar), - themeMode: Value(preferences.themeMode), - ), - mode: InsertMode.replace, - ); - - AppLogger.log.i("✅ Migrated preferences"); -} - -Future migrateSkipSegment() async { - AppLogger.log.i("🔵 Migrating skip segments.."); - Hive.registerAdapter(SkipSegmentAdapter()); - - final box = await Hive.openLazyBox( - SkipSegment.boxName, - path: await getHiveCacheDir(), - ); - - final skipSegments = await Future.wait( - box.keys.map( - (key) async => ( - id: key as String, - data: await box.get(key), - ), - ), - ); - - await _database.batch((batch) { - batch.insertAll( - _database.skipSegmentTable, - skipSegments - .where((element) => element.data != null) - .expand((element) => (element.data as List).map( - (segment) => SkipSegmentTableCompanion.insert( - trackId: element.id, - start: segment["start"], - end: segment["end"], - ), - )) - .toList(), - ); - }); - - AppLogger.log.i("✅ Migrated skip segments"); -} - -Future migrateSourceMatches() async { - AppLogger.log.i("🔵 Migrating source matches.."); - - Hive.registerAdapter(SourceMatchAdapter()); - Hive.registerAdapter(SourceTypeAdapter()); - - final box = await Hive.openBox( - SourceMatch.boxName, - path: await getHiveCacheDir(), - ); - - final sourceMatches = - box.keys.map((key) => (data: box.get(key), trackId: key)); - - await _database.batch((batch) { - batch.insertAll( - _database.sourceMatchTable, - sourceMatches - .where((element) => element.data != null) - .map( - (sourceMatch) => SourceMatchTableCompanion.insert( - sourceId: sourceMatch.data!.sourceId, - trackId: sourceMatch.trackId, - sourceType: Value( - switch (sourceMatch.data!.sourceType) { - SourceType.jiosaavn => db.SourceType.jiosaavn, - SourceType.youtube => db.SourceType.youtube, - SourceType.youtubeMusic => db.SourceType.youtubeMusic, - }, - ), - ), - ) - .toList(), - ); - }); - - AppLogger.log.i("✅ Migrated source matches"); -} - -Future migrateBlacklist() async { - AppLogger.log.i("🔵 Migrating blacklist.."); - - final box = PersistenceCacheBox>( - "blacklist", - fromJson: (json) => (json["blacklist"] as List) - .map((e) => BlacklistedElement.fromJson(e)) - .toSet(), - ); - - final data = await box.getData(); - - if (data == null) return; - - await _database.batch((batch) { - batch.insertAll( - _database.blacklistTable, - data.map( - (element) => BlacklistTableCompanion.insert( - name: element.name, - elementId: element.id, - elementType: switch (element.type) { - BlacklistedType.artist => db.BlacklistedType.artist, - BlacklistedType.track => db.BlacklistedType.track, - }, - ), - ), - ); - }); - - AppLogger.log.i("✅ Migrated blacklist"); -} - -Future migrateLastFmCredentials() async { - AppLogger.log.i("🔵 Migrating Last.fm credentials.."); - - final box = PersistenceCacheBox( - "scrobbler", - fromJson: (json) => ScrobblerState.fromJson(json), - encrypted: true, - ); - - final data = await box.getData(); - - if (data == null) return; - - await _database.into(_database.scrobblerTable).insert( - ScrobblerTableCompanion.insert( - id: const Value(0), - passwordHash: DecryptedText(data.passwordHash), - username: data.username, - ), - mode: InsertMode.replace, - ); - - AppLogger.log.i("✅ Migrated Last.fm credentials"); -} - -Future migratePlaybackHistory() async { - AppLogger.log.i("🔵 Migrating playback history.."); - - final box = PersistenceCacheBox( - "playback_history", - fromJson: (json) => PlaybackHistoryState.fromJson(json), - ); - - final data = await box.getData(); - - if (data == null) return; - - await _database.batch((batch) { - batch.insertAll( - _database.historyTable, - data.items.map( - (item) => switch (item) { - PlaybackHistoryAlbum() => HistoryTableCompanion.insert( - createdAt: Value(item.date), - itemId: item.album.id!, - data: item.album.toJson(), - type: db.HistoryEntryType.album, - ), - PlaybackHistoryPlaylist() => HistoryTableCompanion.insert( - createdAt: Value(item.date), - itemId: item.playlist.id!, - data: item.playlist.toJson(), - type: db.HistoryEntryType.playlist, - ), - PlaybackHistoryTrack() => HistoryTableCompanion.insert( - createdAt: Value(item.date), - itemId: item.track.id!, - data: item.track.toJson(), - type: db.HistoryEntryType.track, - ), - _ => throw Exception("Unknown history item type"), - }, - ), - ); - }); - - AppLogger.log.i("✅ Migrated playback history"); -} - -Future migrateFromHiveToDrift(AppDatabase database) async { - if (KVStoreService.hasMigratedToDrift) return; - - await PersistenceCacheBox.initializeBoxes( - path: await getHiveCacheDir(), - ); - - _database = database; - - await migrateAuthenticationInfo(); - await migratePreferences(); - - await migrateSkipSegment(); - await migrateSourceMatches(); - - await migrateBlacklist(); - await migratePlaybackHistory(); - - await migrateLastFmCredentials(); - - await KVStoreService.setHasMigratedToDrift(true); - - AppLogger.log.i("🚀 Migrated all data to Drift"); -} diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index 06c33e05..476ff787 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -6,6 +6,7 @@ #include "generated_plugin_registrant.h" +#include #include #include #include @@ -21,6 +22,9 @@ #include void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) audioplayers_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "AudioplayersLinuxPlugin"); + audioplayers_linux_plugin_register_with_registrar(audioplayers_linux_registrar); g_autoptr(FlPluginRegistrar) desktop_webview_window_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "DesktopWebviewWindowPlugin"); desktop_webview_window_plugin_register_with_registrar(desktop_webview_window_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index e98b18eb..a875e8f5 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + audioplayers_linux desktop_webview_window file_selector_linux flutter_secure_storage_linux diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 608a854e..12972107 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -8,6 +8,7 @@ import Foundation import app_links import audio_service import audio_session +import audioplayers_darwin import bonsoir_darwin import desktop_webview_window import device_info_plus @@ -32,6 +33,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { AppLinksMacosPlugin.register(with: registry.registrar(forPlugin: "AppLinksMacosPlugin")) AudioServicePlugin.register(with: registry.registrar(forPlugin: "AudioServicePlugin")) AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin")) + AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin")) SwiftBonsoirPlugin.register(with: registry.registrar(forPlugin: "SwiftBonsoirPlugin")) DesktopWebviewWindowPlugin.register(with: registry.registrar(forPlugin: "DesktopWebviewWindowPlugin")) DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) diff --git a/macos/Podfile.lock b/macos/Podfile.lock index fee42515..db8ed79c 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -5,6 +5,8 @@ PODS: - FlutterMacOS - audio_session (0.0.1): - FlutterMacOS + - audioplayers_darwin (0.0.1): + - FlutterMacOS - bonsoir_darwin (0.0.1): - Flutter - FlutterMacOS @@ -46,20 +48,21 @@ PODS: - sqflite_darwin (0.0.4): - Flutter - FlutterMacOS - - sqlite3 (3.47.0): - - sqlite3/common (= 3.47.0) - - sqlite3/common (3.47.0) - - sqlite3/dbstatvtab (3.47.0): + - sqlite3 (3.47.2): + - sqlite3/common (= 3.47.2) + - sqlite3/common (3.47.2) + - sqlite3/dbstatvtab (3.47.2): - sqlite3/common - - sqlite3/fts5 (3.47.0): + - sqlite3/fts5 (3.47.2): - sqlite3/common - - sqlite3/perf-threadsafe (3.47.0): + - sqlite3/perf-threadsafe (3.47.2): - sqlite3/common - - sqlite3/rtree (3.47.0): + - sqlite3/rtree (3.47.2): - sqlite3/common - sqlite3_flutter_libs (0.0.1): + - Flutter - FlutterMacOS - - sqlite3 (~> 3.47.0) + - sqlite3 (~> 3.47.1) - sqlite3/dbstatvtab - sqlite3/fts5 - sqlite3/perf-threadsafe @@ -77,6 +80,7 @@ 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`) - bonsoir_darwin (from `Flutter/ephemeral/.symlinks/plugins/bonsoir_darwin/darwin`) - desktop_webview_window (from `Flutter/ephemeral/.symlinks/plugins/desktop_webview_window/macos`) - device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`) @@ -95,7 +99,7 @@ DEPENDENCIES: - screen_retriever_macos (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos`) - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) - sqflite_darwin (from `Flutter/ephemeral/.symlinks/plugins/sqflite_darwin/darwin`) - - sqlite3_flutter_libs (from `Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/macos`) + - sqlite3_flutter_libs (from `Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/darwin`) - system_theme (from `Flutter/ephemeral/.symlinks/plugins/system_theme/macos`) - tray_manager (from `Flutter/ephemeral/.symlinks/plugins/tray_manager/macos`) - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) @@ -113,6 +117,8 @@ EXTERNAL SOURCES: :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 bonsoir_darwin: :path: Flutter/ephemeral/.symlinks/plugins/bonsoir_darwin/darwin desktop_webview_window: @@ -150,7 +156,7 @@ EXTERNAL SOURCES: sqflite_darwin: :path: Flutter/ephemeral/.symlinks/plugins/sqflite_darwin/darwin sqlite3_flutter_libs: - :path: Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/macos + :path: Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/darwin system_theme: :path: Flutter/ephemeral/.symlinks/plugins/system_theme/macos tray_manager: @@ -164,6 +170,7 @@ SPEC CHECKSUMS: app_links: 10e0a0ab602ffaf34d142cd4862f29d34b303b2a audio_service: b88ff778e0e3915efd4cd1a5ad6f0beef0c950a9 audio_session: dea1f41890dbf1718f04a56f1d6150fd50039b72 + audioplayers_darwin: dcad41de4fbd0099cb3749f7ab3b0cb8f70b810c bonsoir_darwin: e3b8526c42ca46a885142df84229131dfabea842 desktop_webview_window: 89bb3d691f4c80314a10be312f4cd35db93a9d5a device_info_plus: 1b14eed9bf95428983aed283a8d51cce3d8c4215 @@ -183,8 +190,8 @@ SPEC CHECKSUMS: screen_retriever_macos: 776e0fa5d42c6163d2bf772d22478df4b302b161 shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d - sqlite3: 0aa20658a9b238a3b1ff7175eb7bdd863b0ab4fd - sqlite3_flutter_libs: f0b7a85544d8bac7b8bac12eac7d05bcfdd786d0 + sqlite3: 7559e33dae4c78538df563795af3a86fc887ee71 + sqlite3_flutter_libs: 1b4e98da20ebd4e9b1240269b78cdcf492dbe9f3 system_theme: c7b9f6659a5caa26c9bc2284da096781e9a6fcbc tray_manager: 9064e219c56d75c476e46b9a21182087930baf90 url_launcher_macos: c82c93949963e55b228a30115bd219499a6fe404 diff --git a/pubspec.lock b/pubspec.lock index 5aa4f9b4..b58c16b8 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -142,6 +142,62 @@ packages: url: "https://pub.dev" source: hosted version: "0.1.21" + audioplayers: + dependency: transitive + description: + name: audioplayers + sha256: c346ba5a39dc208f1bab55fc239855f573d69b0e832402114bf0b793622adc4d + url: "https://pub.dev" + source: hosted + version: "6.1.0" + audioplayers_android: + dependency: transitive + description: + name: audioplayers_android + sha256: de576b890befe27175c2f511ba8b742bec83765fa97c3ce4282bba46212f58e4 + url: "https://pub.dev" + source: hosted + version: "5.0.0" + audioplayers_darwin: + dependency: transitive + description: + name: audioplayers_darwin + sha256: e507887f3ff18d8e5a10a668d7bedc28206b12e10b98347797257c6ae1019c3b + url: "https://pub.dev" + source: hosted + version: "6.0.0" + audioplayers_linux: + dependency: transitive + description: + name: audioplayers_linux + sha256: "3d3d244c90436115417f170426ce768856d8fe4dfc5ed66a049d2890acfa82f9" + url: "https://pub.dev" + source: hosted + version: "4.0.0" + audioplayers_platform_interface: + dependency: transitive + description: + name: audioplayers_platform_interface + sha256: "6834dd48dfb7bc6c2404998ebdd161f79cd3774a7e6779e1348d54a3bfdcfaa5" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + audioplayers_web: + dependency: transitive + description: + name: audioplayers_web + sha256: "3609bdf0e05e66a3d9750ee40b1e37f2a622c4edb796cc600b53a90a30a2ace4" + url: "https://pub.dev" + source: hosted + version: "5.0.1" + audioplayers_windows: + dependency: transitive + description: + name: audioplayers_windows + sha256: "8605762dddba992138d476f6a0c3afd9df30ac5b96039929063eceed416795c2" + url: "https://pub.dev" + source: hosted + version: "4.0.0" auto_size_text: dependency: "direct main" description: @@ -390,6 +446,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.2" + country_flags: + dependency: transitive + description: + name: country_flags + sha256: dad797491167a5b8dee465b969cb756795d842fdfc3fc1ff93f22e9c1884b73d + url: "https://pub.dev" + source: hosted + version: "3.1.0" coverage: dependency: transitive description: @@ -462,6 +526,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" + data_widget: + dependency: transitive + description: + name: data_widget + sha256: "95388df890189014f702b7e93f9de6bcf7d45143a99f6288f31899f10be441ba" + url: "https://pub.dev" + source: hosted + version: "0.0.2" dbus: dependency: transitive description: @@ -552,6 +624,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.15" + email_validator: + dependency: transitive + description: + name: email_validator + sha256: b19aa5d92fdd76fbc65112060c94d45ba855105a28bb6e462de7ff03b12fa1fb + url: "https://pub.dev" + source: hosted + version: "3.0.0" encrypt: dependency: "direct main" description: @@ -1276,6 +1356,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.1.0" + jovial_misc: + dependency: transitive + description: + name: jovial_misc + sha256: "4b10a4cac4f492d9692e97699bff775efa84abdba29909124cbccf3126e31cea" + url: "https://pub.dev" + source: hosted + version: "0.9.0" + jovial_svg: + dependency: transitive + description: + name: jovial_svg + sha256: ca14d42956b9949c36333065c9141f100e930c918f57f4bd8dd59d35581bd3fc + url: "https://pub.dev" + source: hosted + version: "1.1.24" js: dependency: transitive description: @@ -1740,6 +1836,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.0.2" + phonecodes: + dependency: transitive + description: + name: phonecodes + sha256: "094a76b0ba3d8f9c1c83044ae8783d46e6906703c86eb08facd876844c264bf5" + url: "https://pub.dev" + source: hosted + version: "0.0.3" piped_client: dependency: "direct main" description: @@ -1748,6 +1852,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.1.1" + pixel_snap: + dependency: transitive + description: + name: pixel_snap + sha256: "677410ea37b07cd37ecb6d5e6c0d8d7615a7cf3bd92ba406fd1ac57e937d1fb0" + url: "https://pub.dev" + source: hosted + version: "0.1.5" platform: dependency: transitive description: @@ -1925,6 +2037,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.1" + shadcn_flutter: + dependency: "direct main" + description: + name: shadcn_flutter + sha256: eaf10ec804beddf2059dd55b802188b64277a5e4fc577defbc7c012253caef1a + url: "https://pub.dev" + source: hosted + version: "0.0.23" shared_preferences: dependency: "direct main" description: @@ -2258,6 +2378,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.3.0+3" + syntax_highlight: + dependency: transitive + description: + name: syntax_highlight + sha256: ee33b6aa82cc722bb9b40152a792181dee222353b486c0255fde666a3e3a4997 + url: "https://pub.dev" + source: hosted + version: "0.4.0" system_theme: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 3866e410..c9a6f341 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -102,6 +102,7 @@ dependencies: ref: dart-3-support url: https://github.com/KRTirtho/scrobblenaut.git scroll_to_index: ^3.0.1 + shadcn_flutter: ^0.0.23 shared_preferences: ^2.2.3 shelf: ^1.4.1 shelf_router: ^1.1.4 @@ -165,6 +166,53 @@ flutter: - assets/logos/ - assets/backgrounds/ - LICENSE + fonts: + - family: GeistSans + fonts: + - asset: packages/shadcn_flutter/fonts/Geist-Black.otf + weight: 800 + - asset: packages/shadcn_flutter/fonts/Geist-Bold.otf + weight: 700 + - asset: packages/shadcn_flutter/fonts/Geist-Light.otf + weight: 300 + - asset: packages/shadcn_flutter/fonts/Geist-Medium.otf + weight: 500 + - asset: packages/shadcn_flutter/fonts/Geist-SemiBold.otf + weight: 600 + - asset: packages/shadcn_flutter/fonts/Geist-Thin.otf + weight: 100 + - asset: packages/shadcn_flutter/fonts/Geist-UltraBlack.otf + weight: 900 + - asset: packages/shadcn_flutter/fonts/Geist-UltraLight.otf + weight: 200 + - asset: packages/shadcn_flutter/fonts/Geist-Regular.otf + weight: 400 + - family: GeistMono + fonts: + - asset: packages/shadcn_flutter/fonts/GeistMono-Black.otf + weight: 800 + - asset: packages/shadcn_flutter/fonts/GeistMono-Bold.otf + weight: 700 + - asset: packages/shadcn_flutter/fonts/GeistMono-Light.otf + weight: 300 + - asset: packages/shadcn_flutter/fonts/GeistMono-Medium.otf + weight: 500 + - asset: packages/shadcn_flutter/fonts/GeistMono-Regular.otf + weight: 400 + - asset: packages/shadcn_flutter/fonts/GeistMono-SemiBold.otf + weight: 600 + - asset: packages/shadcn_flutter/fonts/GeistMono-Thin.otf + weight: 100 + - asset: packages/shadcn_flutter/fonts/GeistMono-UltraBlack.otf + weight: 900 + - asset: packages/shadcn_flutter/fonts/GeistMono-UltraLight.otf + weight: 200 + - family: RadixIcons + fonts: + - asset: packages/shadcn_flutter/icons/RadixIcons.otf + - family: BootstrapIcons + fonts: + - asset: packages/shadcn_flutter/icons/BootstrapIcons.otf flutter_gen: output: lib/collections diff --git a/web/flutter_bootstrap.js b/web/flutter_bootstrap.js new file mode 100644 index 00000000..a9f703d6 --- /dev/null +++ b/web/flutter_bootstrap.js @@ -0,0 +1,238 @@ +const words = [ + 'Something is happening. Please wait.', + 'Please be patient. This may take a while.', + 'While you wait, please consider that this is a good time to take a break.', + 'Please wait. This is a good time to go grab a cup of coffee.', + 'Sometimes the things that are worth waiting for take time.', + 'Please wait. This is a good time to stretch your legs.', + 'Posture check! Please wait while we load the application.', +]; + +const loaderWidget = ` +

` + +const shadcn_flutter_config = { + loaderWidget: loaderWidget, + backgroundColor: null, + foregroundColor: null, + loaderColor: null, + fontFamily: 'Geist Sans', + fontSize: '24px', + fontWeight: '400', + mainAxisAlignment: 'end', + crossAxisAlignment: 'end', + externalScripts: [ + { + src: 'https://cdn.jsdelivr.net/npm/@fontsource/geist-sans@5.0.3/400.min.css', + type: 'stylesheet', + }, + { + src: 'https://cdn.jsdelivr.net/npm/@fontsource/geist-sans@5.0.3/300.min.css', + type: 'stylesheet', + }, + ] +}; + +{{flutter_js}} +{{flutter_build_config}} + +class ShadcnAppConfig { + background; + foreground; + fontFamily; + fontSize; + fontWeight; + mainAxisAlignment; + crossAxisAlignment; + loaderWidget; + loaderColor; + externalScripts; + + constructor({ background, foreground, fontFamily, fontSize, fontWeight, mainAxisAlignment, crossAxisAlignment, loaderWidget, loaderColor, externalScripts }) { + this.background = background; + this.foreground = foreground; + this.fontFamily = fontFamily; + this.fontSize = fontSize; + this.fontWeight = fontWeight; + this.mainAxisAlignment = mainAxisAlignment; + this.crossAxisAlignment = crossAxisAlignment; + this.loaderWidget = loaderWidget; + this.loaderColor = loaderColor; + this.externalScripts = externalScripts; + + if (this.background == null) { + this.background = localStorage.getItem('shadcn_flutter.background') || '#09090b'; + } + if (this.foreground == null) { + this.foreground = localStorage.getItem('shadcn_flutter.foreground') || '#ffffff'; + } + if (this.loaderColor == null) { + this.loaderColor = localStorage.getItem('shadcn_flutter.primary') || '#3c83f6'; + } + } +} + +class ShadcnAppThemeChangedEvent extends CustomEvent { + constructor(theme) { + super('shadcn_flutter_theme_changed', { detail: theme }); + } +} + +class ShadcnAppTheme { + background; + foreground; + primary; + + constructor(background, foreground, primary) { + this.background = background; + this.foreground = foreground; + this.primary = primary; + } +} + +class ShadcnApp { + config; + + constructor(config) { + this.config = config; + } + + loadApp() { + window.addEventListener('shadcn_flutter_app_ready', this.onAppReady); + window.addEventListener('shadcn_flutter_theme_changed', this.onThemeChanged); + this.#initializeDocument(); + let externalScriptIndex = 0; + this.#loadExternalScripts(externalScriptIndex, () => { + _flutter.loader.load({ + onEntrypointLoaded: async function(engineInitializer) { + const appRunner = await engineInitializer.initializeEngine(); + await appRunner.runApp(); + } + }); + }); + } + + #loadExternalScripts(index, onDone) { + if (index >= this.config.externalScripts.length) { + onDone(); + return; + } + this.#loadScriptDynamically(this.config.externalScripts[index], () => { + this.#loadExternalScripts(index + 1, onDone); + }); + } + + #createStyleSheet(css) { + const style = document.createElement('style'); + style.type = 'text/css'; + style.appendChild(document.createTextNode(css)); + document.head.appendChild(style); + } + + #loadScriptDynamically(src, callback) { + if (typeof src === 'string') { + src = { src: src, type: 'script' }; + } + if (src.type === 'script') { + const script = document.createElement('script'); + script.src = src.src; + script.onload = callback; + document.body.appendChild(script); + } else if (src.type === 'module') { + const script = document.createElement('script'); + script.type = 'module'; + script.src = src.src; + script.onload = callback; + document.body.appendChild(script); + } else if (src.type === 'stylesheet') { + const link = document.createElement('link'); + link.rel = 'stylesheet'; + link.href = src.src; + link.onload = callback; + document.head.appendChild(link); + } else { + throw new Error('Unknown type of file to load: ' + src); + } + } + + #initializeDocument() { + const loaderStyle = ` + display: flex; + justify-content: ${this.config.mainAxisAlignment}; + align-items: ${this.config.crossAxisAlignment}; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: ${this.config.background}; + color: ${this.config.foreground}; + z-index: 9998; + font-family: ${this.config.fontFamily}; + font-size: ${this.config.fontSize}; + font-weight: ${this.config.fontWeight}; + text-align: center; + transition: opacity 0.5s; + opacity: 1; + pointer-events: initial; + `; + + const loaderBarCss = ` + .loader { + height: 7px; + background: repeating-linear-gradient(-45deg,${this.config.loaderColor} 0 15px,#000 0 20px) left/200% 100%; + animation: l3 20s infinite linear; + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 9999; + } + @keyframes l3 { + 100% {background-position:right} + }`; + + const loaderDiv = document.createElement('div'); + loaderDiv.style.cssText = loaderStyle; + loaderDiv.innerHTML = this.config.loaderWidget; + + document.body.appendChild(loaderDiv); + + document.body.style.backgroundColor = this.config.background; + + const loaderBarDiv = document.createElement('div'); + loaderBarDiv.className = 'loader'; + loaderDiv.appendChild(loaderBarDiv); + + this.#createStyleSheet(loaderBarCss); + } + + onAppReady() { + const loaderDiv = document.querySelector('div'); + loaderDiv.style.opacity = 0; + loaderDiv.style.pointerEvents = 'none'; + } + + onThemeChanged(event) { + let theme = event.detail; + let background = theme['background']; + let foreground = theme['foreground']; + let primary = theme['primary']; + localStorage.setItem('shadcn_flutter.background', background); + localStorage.setItem('shadcn_flutter.foreground', foreground); + localStorage.setItem('shadcn_flutter.primary', primary); + } +} + +globalThis.ShadcnApp = ShadcnApp; +globalThis.ShadcnAppConfig = ShadcnAppConfig; +globalThis.ShadcnAppThemeChangedEvent = ShadcnAppThemeChangedEvent; +globalThis.ShadcnAppTheme = ShadcnAppTheme; + +const shadcn_flutter = new ShadcnApp(new ShadcnAppConfig(shadcn_flutter_config)); +shadcn_flutter.loadApp(); \ No newline at end of file diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 42fa2129..7c490ef1 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -7,6 +7,7 @@ #include "generated_plugin_registrant.h" #include +#include #include #include #include @@ -25,6 +26,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { AppLinksPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("AppLinksPluginCApi")); + AudioplayersWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("AudioplayersWindowsPlugin")); BonsoirWindowsPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("BonsoirWindowsPluginCApi")); DesktopWebviewWindowPluginRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index cf14ec52..dfcc70cf 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -4,6 +4,7 @@ list(APPEND FLUTTER_PLUGIN_LIST app_links + audioplayers_windows bonsoir_windows desktop_webview_window file_selector_windows From e73d2d06d8a6cbedcede47c12c4bed38b3ff8c99 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 21 Dec 2024 09:28:55 +0600 Subject: [PATCH 010/112] refactor: use shadcn NavigationBar for mobile navigation bar --- lib/modules/root/spotube_navigation_bar.dart | 63 ++++++-------------- 1 file changed, 17 insertions(+), 46 deletions(-) diff --git a/lib/modules/root/spotube_navigation_bar.dart b/lib/modules/root/spotube_navigation_bar.dart index 978891b8..c2cf4b5a 100644 --- a/lib/modules/root/spotube_navigation_bar.dart +++ b/lib/modules/root/spotube_navigation_bar.dart @@ -1,10 +1,8 @@ -import 'dart:ui'; - -import 'package:curved_navigation_bar/curved_navigation_bar.dart'; -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart' show Badge; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/side_bar_tiles.dart'; import 'package:spotube/extensions/constrains.dart'; @@ -25,7 +23,6 @@ class SpotubeNavigationBar extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final theme = Theme.of(context); final routerState = GoRouterState.of(context); final downloadCount = ref.watch(downloadManagerProvider).$downloadCount; @@ -33,11 +30,6 @@ class SpotubeNavigationBar extends HookConsumerWidget { final layoutMode = ref.watch(userPreferencesProvider.select((s) => s.layoutMode)); - final buttonColor = useBrightnessValue( - theme.colorScheme.inversePrimary, - theme.colorScheme.primary.withOpacity(0.2), - ); - final navbarTileList = useMemoized( () => getNavbarTileList(context.l10n), [context.l10n], @@ -61,42 +53,21 @@ class SpotubeNavigationBar extends HookConsumerWidget { return AnimatedContainer( duration: const Duration(milliseconds: 100), - height: panelHeight, - child: ClipRect( - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 15, sigmaY: 15), - child: CurvedNavigationBar( - backgroundColor: - theme.colorScheme.secondaryContainer.withOpacity(0.72), - buttonBackgroundColor: buttonColor, - color: theme.colorScheme.surface, - height: panelHeight, - animationDuration: const Duration(milliseconds: 350), - items: navbarTileList.map( - (e) { - /// Using this [Builder] as an workaround for the first item's - /// icon color not updating unless navigating to another page - return Builder(builder: (context) { - return MouseRegion( - cursor: SystemMouseCursors.click, - child: Badge( - isLabelVisible: e.id == "library" && downloadCount > 0, - label: Text(downloadCount.toString()), - child: Icon( - e.icon, - color: Theme.of(context).colorScheme.primary, - ), - ), - ); - }); - }, - ).toList(), - index: selectedIndex, - onTap: (i) { - ServiceUtils.navigateNamed(context, navbarTileList[i].name); - }, - ), - ), + child: NavigationBar( + index: selectedIndex, + onSelected: (i) { + ServiceUtils.navigateNamed(context, navbarTileList[i].name); + }, + children: [ + for (final tile in navbarTileList) + NavigationButton( + child: Badge( + isLabelVisible: tile.id == "library" && downloadCount > 0, + label: Text(downloadCount.toString()), + child: Icon(tile.icon), + ), + ) + ], ), ); } From fe2f0a373f9c0e01c95fc64c744120bd359d646b Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 21 Dec 2024 09:34:56 +0600 Subject: [PATCH 011/112] refactor: use NavigationSidebar and NavigationRail for desktop sidebar --- lib/modules/root/sidebar.dart | 107 +++++++++++++++++++--------------- 1 file changed, 59 insertions(+), 48 deletions(-) diff --git a/lib/modules/root/sidebar.dart b/lib/modules/root/sidebar.dart index 4f3c4442..79e8d6d4 100644 --- a/lib/modules/root/sidebar.dart +++ b/lib/modules/root/sidebar.dart @@ -66,56 +66,67 @@ class Sidebar extends HookConsumerWidget { return Scaffold(child: child); } - return LayoutBuilder(builder: (context, constrains) { - return Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SafeArea( - child: Column( - children: [ - Expanded( - child: NavigationSidebar( - index: selectedIndex, - onSelected: (index) { - final tile = sidebarTileList[index]; - ServiceUtils.pushNamed(context, tile.name); - }, - children: [ - const NavigationLabel(child: Text("Spotube")), - for (final tile in sidebarTileList) - NavigationButton( - label: Text(tile.title), - child: Badge( - backgroundColor: context.theme.colorScheme.primary, - isLabelVisible: - tile.title == "Library" && downloadCount > 0, - label: Text( - downloadCount.toString(), - style: const TextStyle( - color: Colors.white, - fontSize: 10, - ), - ), - child: Icon(tile.icon), - ), - onChanged: (value) { - if (value) { - context.goNamed(tile.name); - } - }, - ), - ], - ), - ), - const SidebarFooter(), - ], + final navigationButtons = [ + NavigationLabel( + child: mediaQuery.lgAndUp ? const Text("Spotube") : const Text(""), + ), + for (final tile in sidebarTileList) + NavigationButton( + label: mediaQuery.lgAndUp ? Text(tile.title) : null, + child: Badge( + backgroundColor: context.theme.colorScheme.primary, + isLabelVisible: tile.title == "Library" && downloadCount > 0, + label: Text( + downloadCount.toString(), + style: const TextStyle( + color: Colors.white, + fontSize: 10, + ), ), + child: Icon(tile.icon), ), - const VerticalDivider(), - Expanded(child: child), - ], - ); - }); + onChanged: (value) { + if (value) { + context.goNamed(tile.name); + } + }, + ), + ]; + + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SafeArea( + child: Column( + children: [ + Expanded( + child: mediaQuery.lgAndUp + ? NavigationSidebar( + index: selectedIndex, + onSelected: (index) { + final tile = sidebarTileList[index]; + ServiceUtils.pushNamed(context, tile.name); + }, + children: navigationButtons, + ) + : NavigationRail( + alignment: NavigationRailAlignment.start, + index: selectedIndex, + onSelected: (index) { + final tile = sidebarTileList[index]; + ServiceUtils.pushNamed(context, tile.name); + }, + children: navigationButtons, + ), + ), + const SidebarFooter(), + ], + ), + ), + const VerticalDivider(), + Expanded(child: child), + ], + ); } } From 04190f2ddaa644c511edce7e55c0d4e749b6de70 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 21 Dec 2024 12:42:51 +0600 Subject: [PATCH 012/112] refactor: use DropdownMenu for adaptive pop sheet list, shadcn widgets for bottom player and player controls and actions --- .../adaptive/adaptive_pop_sheet_list.dart | 284 +++++++----------- lib/components/sort_tracks_dropdown.dart | 32 +- lib/components/track_tile/track_options.dart | 85 +++--- .../sections/body/track_view_options.dart | 16 +- lib/main.dart | 6 +- lib/modules/player/player_actions.dart | 132 ++++---- lib/modules/player/player_controls.dart | 240 +++++++-------- lib/modules/player/volume_slider.dart | 20 +- lib/modules/root/bottom_player.dart | 103 +++---- 9 files changed, 438 insertions(+), 480 deletions(-) diff --git a/lib/components/adaptive/adaptive_pop_sheet_list.dart b/lib/components/adaptive/adaptive_pop_sheet_list.dart index 97dc6132..5345199e 100644 --- a/lib/components/adaptive/adaptive_pop_sheet_list.dart +++ b/lib/components/adaptive/adaptive_pop_sheet_list.dart @@ -1,56 +1,34 @@ -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart' show ListTile, showModalBottomSheet; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/extensions/constrains.dart'; -_emptyCB() {} - -class PopSheetEntry extends ListTile { +class AdaptiveMenuButton extends MenuButton { final T? value; - const PopSheetEntry({ - this.value, + const AdaptiveMenuButton({ super.key, - super.leading, - super.title, - super.subtitle, + this.value, + required super.child, + super.subMenu, + super.onPressed, super.trailing, - super.isThreeLine = false, - super.dense, - super.visualDensity, - super.shape, - super.style, - super.selectedColor, - super.iconColor, - super.textColor, - super.titleTextStyle, - super.subtitleTextStyle, - super.leadingAndTrailingTextStyle, - super.contentPadding, + super.leading, super.enabled = true, - super.onTap = _emptyCB, - super.onLongPress, - super.onFocusChange, - super.mouseCursor, - super.selected = false, - super.focusColor, - super.hoverColor, - super.splashColor, super.focusNode, - super.autofocus = false, - super.tileColor, - super.selectedTileColor, - super.enableFeedback, - super.horizontalTitleGap, - super.minVerticalPadding, - super.minLeadingWidth, - super.titleAlignment, - }); + super.autoClose = true, + super.popoverController, + }) : assert( + value != null || onPressed != null, + 'Either value or onPressed must be provided', + ); } /// An adaptive widget that shows a [PopupMenuButton] when screen size is above /// or equal to 640px /// In smaller screen, a [IconButton] with a [showModalBottomSheet] is shown class AdaptivePopSheetList extends StatelessWidget { - final List> children; + final List> children; final Widget? icon; final Widget? child; final bool useRootNavigator; @@ -59,7 +37,6 @@ class AdaptivePopSheetList extends StatelessWidget { final String? tooltip; final ValueChanged? onSelected; - final BorderRadius borderRadius; final Offset offset; const AdaptivePopSheetList({ @@ -70,7 +47,6 @@ class AdaptivePopSheetList extends StatelessWidget { this.useRootNavigator = true, this.headings, this.onSelected, - this.borderRadius = const BorderRadius.all(Radius.circular(999)), this.tooltip, this.offset = Offset.zero, }) : assert( @@ -78,158 +54,128 @@ class AdaptivePopSheetList extends StatelessWidget { 'Either icon or child must be provided', ); - Future showPopupMenu(BuildContext context, RelativeRect position) { + Future showDropdownMenu(BuildContext context, Offset position) async { final mediaQuery = MediaQuery.of(context); + final childrenModified = children.map((s) { + if (s.onPressed == null) { + return MenuButton( + key: s.key, + autoClose: s.autoClose, + enabled: s.enabled, + leading: s.leading, + focusNode: s.focusNode, + onPressed: (context) { + if (s.value != null) { + onSelected?.call(s.value as T); + } + }, + popoverController: s.popoverController, + subMenu: s.subMenu, + trailing: s.trailing, + child: s.child, + ); + } + return s; + }).toList(); - return showMenu( + if (mediaQuery.mdAndUp) { + await showDropdown( + context: context, + rootOverlay: useRootNavigator, + // heightConstraint: PopoverConstraint.anchorFixedSize, + // constraints: BoxConstraints( + // maxHeight: mediaQuery.size.height * 0.6, + // ), + position: position, + builder: (context) { + return DropdownMenu( + children: childrenModified, + ); + }, + ).future; + return; + } + + showModalBottomSheet( context: context, - useRootNavigator: useRootNavigator, - constraints: BoxConstraints( - maxHeight: mediaQuery.size.height * 0.6, + enableDrag: true, + showDragHandle: true, + useRootNavigator: true, + shape: RoundedRectangleBorder( + borderRadius: context.theme.borderRadiusMd, ), - position: position, - items: children - .map( - (item) => PopupMenuItem( - padding: EdgeInsets.zero, - enabled: false, - child: _AdaptivePopSheetListItem( - item: item, - onSelected: onSelected, - ), - ), - ) - .toList(), + backgroundColor: context.theme.colorScheme.card, + builder: (context) { + return ListView.builder( + physics: const NeverScrollableScrollPhysics(), + itemCount: childrenModified.length, + shrinkWrap: true, + itemBuilder: (context, index) { + final data = childrenModified[index]; + + return ListTile( + dense: true, + leading: data.leading, + title: data.child, + enabled: data.enabled, + trailing: data.trailing, + focusNode: data.focusNode, + onTap: () { + data.onPressed?.call(context); + if (data.autoClose) { + Navigator.of(context).pop(); + } + }, + ); + }, + ); + }, ); } @override Widget build(BuildContext context) { final mediaQuery = MediaQuery.of(context); - final theme = Theme.of(context); if (mediaQuery.mdAndUp) { - return PopupMenuButton( - icon: icon, - tooltip: tooltip, - offset: offset, - child: child == null ? null : IgnorePointer(child: child), - itemBuilder: (context) => children - .map( - (item) => PopupMenuItem( - padding: EdgeInsets.zero, - enabled: false, - child: _AdaptivePopSheetListItem( - item: item, - onSelected: onSelected, - ), + return Tooltip( + tooltip: Text(tooltip ?? ''), + child: IconButton.ghost( + icon: icon ?? const Icon(SpotubeIcons.moreVertical), + onPressed: () { + final renderBox = context.findRenderObject() as RenderBox; + final position = RelativeRect.fromRect( + Rect.fromPoints( + renderBox.localToGlobal(Offset.zero, + ancestor: context.findRenderObject()), + renderBox.localToGlobal(renderBox.size.bottomRight(Offset.zero), + ancestor: context.findRenderObject()), ), - ) - .toList(), - ); - } - - void showSheet() { - showModalBottomSheet( - context: context, - useRootNavigator: useRootNavigator, - isScrollControlled: true, - showDragHandle: true, - constraints: BoxConstraints( - maxHeight: mediaQuery.size.height * 0.6, + Offset.zero & mediaQuery.size, + ); + final offset = Offset(position.left, position.top); + showDropdownMenu(context, offset); + }, ), - builder: (context) { - return Padding( - padding: const EdgeInsets.all(8.0).copyWith(top: 0), - child: DefaultTextStyle( - style: theme.textTheme.titleMedium!, - child: SingleChildScrollView( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - if (headings != null) ...[ - ...headings!, - const SizedBox(height: 8), - Divider( - color: theme.colorScheme.primary, - thickness: 0.3, - endIndent: 16, - indent: 16, - ), - ], - ...children.map( - (item) => _AdaptivePopSheetListItem( - item: item, - onSelected: onSelected, - ), - ) - ], - ), - ), - ), - ); - }, ); } if (child != null) { return Tooltip( - message: tooltip ?? '', - child: InkWell( - onTap: showSheet, - borderRadius: borderRadius, + tooltip: Text(tooltip ?? ''), + child: Button( + onPressed: () => showDropdownMenu(context, Offset.zero), + style: const ButtonStyle.ghost(), child: IgnorePointer(child: child), ), ); } - return IconButton( - icon: icon ?? const Icon(SpotubeIcons.moreVertical), - tooltip: tooltip, - style: theme.iconButtonTheme.style?.copyWith( - shape: WidgetStatePropertyAll( - RoundedRectangleBorder( - borderRadius: borderRadius, - ), - ), - ), - onPressed: showSheet, - ); - } -} - -class _AdaptivePopSheetListItem extends StatelessWidget { - final PopSheetEntry item; - final ValueChanged? onSelected; - const _AdaptivePopSheetListItem({ - super.key, - required this.item, - this.onSelected, - }); - - @override - Widget build(BuildContext context) { - final theme = Theme.of(context); - - return InkWell( - borderRadius: (theme.listTileTheme.shape as RoundedRectangleBorder?) - ?.borderRadius as BorderRadius? ?? - const BorderRadius.all(Radius.circular(10)), - onTap: !item.enabled - ? null - : () { - item.onTap?.call(); - if (item.value != null) { - Navigator.pop(context); - onSelected?.call(item.value as T); - } - }, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 8), - child: IconTheme.merge( - data: const IconThemeData(opacity: 1), - child: IgnorePointer(child: item), - ), + return Tooltip( + tooltip: Text(tooltip ?? ''), + child: IconButton.ghost( + icon: icon ?? const Icon(SpotubeIcons.moreVertical), + onPressed: () => showDropdownMenu(context, Offset.zero), ), ); } diff --git a/lib/components/sort_tracks_dropdown.dart b/lib/components/sort_tracks_dropdown.dart index 16727013..4f65e738 100644 --- a/lib/components/sort_tracks_dropdown.dart +++ b/lib/components/sort_tracks_dropdown.dart @@ -23,45 +23,45 @@ class SortTracksDropdown extends StatelessWidget { ), child: AdaptivePopSheetList( children: [ - PopSheetEntry( + AdaptiveMenuButton( value: SortBy.none, enabled: value != SortBy.none, - title: Text(context.l10n.none), + child: Text(context.l10n.none), ), - PopSheetEntry( + AdaptiveMenuButton( value: SortBy.ascending, enabled: value != SortBy.ascending, - title: Text(context.l10n.sort_a_z), + child: Text(context.l10n.sort_a_z), ), - PopSheetEntry( + AdaptiveMenuButton( value: SortBy.descending, enabled: value != SortBy.descending, - title: Text(context.l10n.sort_z_a), + child: Text(context.l10n.sort_z_a), ), - PopSheetEntry( + AdaptiveMenuButton( value: SortBy.newest, enabled: value != SortBy.newest, - title: Text(context.l10n.sort_newest), + child: Text(context.l10n.sort_newest), ), - PopSheetEntry( + AdaptiveMenuButton( value: SortBy.oldest, enabled: value != SortBy.oldest, - title: Text(context.l10n.sort_oldest), + child: Text(context.l10n.sort_oldest), ), - PopSheetEntry( + AdaptiveMenuButton( value: SortBy.duration, enabled: value != SortBy.duration, - title: Text(context.l10n.sort_duration), + child: Text(context.l10n.sort_duration), ), - PopSheetEntry( + AdaptiveMenuButton( value: SortBy.artist, enabled: value != SortBy.artist, - title: Text(context.l10n.sort_artist), + child: Text(context.l10n.sort_artist), ), - PopSheetEntry( + AdaptiveMenuButton( value: SortBy.album, enabled: value != SortBy.album, - title: Text(context.l10n.sort_album), + child: Text(context.l10n.sort_album), ), ], headings: [ diff --git a/lib/components/track_tile/track_options.dart b/lib/components/track_tile/track_options.dart index d2cb92cf..28a85fd1 100644 --- a/lib/components/track_tile/track_options.dart +++ b/lib/components/track_tile/track_options.dart @@ -5,7 +5,8 @@ import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:spotify/spotify.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.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/adaptive/adaptive_pop_sheet_list.dart'; @@ -332,38 +333,46 @@ class TrackOptions extends HookConsumerWidget { ], children: [ if (isLocalTrack) - PopSheetEntry( + AdaptiveMenuButton( value: TrackOptionValue.delete, leading: const Icon(SpotubeIcons.trash), - title: Text(context.l10n.delete), + child: Text(context.l10n.delete), ), if (mediaQuery.smAndDown && !isLocalTrack) - PopSheetEntry( + AdaptiveMenuButton( value: TrackOptionValue.album, leading: const Icon(SpotubeIcons.album), - title: Text(context.l10n.go_to_album), - subtitle: Text(track.album!.name!), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text(context.l10n.go_to_album), + Text( + track.album!.name!, + style: context.theme.typography.xSmall, + ), + ], + ), ), if (!playlist.containsTrack(track)) ...[ - PopSheetEntry( + AdaptiveMenuButton( value: TrackOptionValue.addToQueue, leading: const Icon(SpotubeIcons.queueAdd), - title: Text(context.l10n.add_to_queue), + child: Text(context.l10n.add_to_queue), ), - PopSheetEntry( + AdaptiveMenuButton( value: TrackOptionValue.playNext, leading: const Icon(SpotubeIcons.lightning), - title: Text(context.l10n.play_next), + child: Text(context.l10n.play_next), ), ] else - PopSheetEntry( + AdaptiveMenuButton( value: TrackOptionValue.removeFromQueue, enabled: playlist.activeTrack?.id != track.id, leading: const Icon(SpotubeIcons.queueRemove), - title: Text(context.l10n.remove_from_queue), + child: Text(context.l10n.remove_from_queue), ), if (me.asData?.value != null && !isLocalTrack) - PopSheetEntry( + AdaptiveMenuButton( value: TrackOptionValue.favorite, leading: favorites.isLiked ? const Icon( @@ -371,32 +380,32 @@ class TrackOptions extends HookConsumerWidget { color: Colors.pink, ) : const Icon(SpotubeIcons.heart), - title: Text( + child: Text( favorites.isLiked ? context.l10n.remove_from_favorites : context.l10n.save_as_favorite, ), ), if (auth.asData?.value != null && !isLocalTrack) ...[ - PopSheetEntry( + AdaptiveMenuButton( value: TrackOptionValue.startRadio, leading: const Icon(SpotubeIcons.radio), - title: Text(context.l10n.start_a_radio), + child: Text(context.l10n.start_a_radio), ), - PopSheetEntry( + AdaptiveMenuButton( value: TrackOptionValue.addToPlaylist, leading: const Icon(SpotubeIcons.playlistAdd), - title: Text(context.l10n.add_to_playlist), + child: Text(context.l10n.add_to_playlist), ), ], if (userPlaylist && auth.asData?.value != null && !isLocalTrack) - PopSheetEntry( + AdaptiveMenuButton( value: TrackOptionValue.removeFromPlaylist, leading: const Icon(SpotubeIcons.removeFilled), - title: Text(context.l10n.remove_from_playlist), + child: Text(context.l10n.remove_from_playlist), ), if (!isLocalTrack) - PopSheetEntry( + AdaptiveMenuButton( value: TrackOptionValue.download, enabled: !isInQueue, leading: isInQueue @@ -407,48 +416,56 @@ class TrackOptions extends HookConsumerWidget { ); }) : const Icon(SpotubeIcons.download), - title: Text(context.l10n.download_track), + child: Text(context.l10n.download_track), ), if (!isLocalTrack) - PopSheetEntry( + AdaptiveMenuButton( value: TrackOptionValue.blacklist, - leading: const Icon(SpotubeIcons.playlistRemove), - iconColor: isBlackListed != true ? Colors.red[400] : null, - textColor: isBlackListed != true ? Colors.red[400] : null, - title: Text( + leading: Icon( + SpotubeIcons.playlistRemove, + color: isBlackListed != true ? Colors.red[400] : null, + ), + child: Text( isBlackListed == true ? context.l10n.remove_from_blacklist : context.l10n.add_to_blacklist, + style: TextStyle( + color: isBlackListed != true ? Colors.red[400] : null, + ), ), ), if (!isLocalTrack) - PopSheetEntry( + AdaptiveMenuButton( value: TrackOptionValue.share, leading: const Icon(SpotubeIcons.share), - title: Text(context.l10n.share), + child: Text(context.l10n.share), ), if (!isLocalTrack) - PopSheetEntry( + AdaptiveMenuButton( value: TrackOptionValue.songlink, leading: Assets.logos.songlinkTransparent.image( width: 22, height: 22, color: colorScheme.onSurface.withOpacity(0.5), ), - title: Text(context.l10n.song_link), + child: Text(context.l10n.song_link), ), if (!isLocalTrack) - PopSheetEntry( + AdaptiveMenuButton( value: TrackOptionValue.details, leading: const Icon(SpotubeIcons.info), - title: Text(context.l10n.details), + child: Text(context.l10n.details), ), ], ); //! This is the most ANTI pattern I've ever done, but it works showMenuCbRef?.value = (relativeRect) { - adaptivePopSheetList.showPopupMenu(context, relativeRect); + final offsetFromRect = Offset( + relativeRect.left, + relativeRect.top, + ); + adaptivePopSheetList.showDropdownMenu(context, offsetFromRect); }; return ListTileTheme( diff --git a/lib/components/tracks_view/sections/body/track_view_options.dart b/lib/components/tracks_view/sections/body/track_view_options.dart index 23198aec..7114d713 100644 --- a/lib/components/tracks_view/sections/body/track_view_options.dart +++ b/lib/components/tracks_view/sections/body/track_view_options.dart @@ -102,35 +102,35 @@ class TrackViewBodyOptions extends HookConsumerWidget { }, icon: const Icon(SpotubeIcons.moreVertical), children: [ - PopSheetEntry( + AdaptiveMenuButton( value: "download", leading: const Icon(SpotubeIcons.download), enabled: selectedTracks.isNotEmpty, - title: Text( + child: Text( context.l10n.download_count(selectedTracks.length), ), ), - PopSheetEntry( + AdaptiveMenuButton( value: "add-to-playlist", leading: const Icon(SpotubeIcons.playlistAdd), enabled: selectedTracks.isNotEmpty, - title: Text( + child: Text( context.l10n.add_count_to_playlist(selectedTracks.length), ), ), - PopSheetEntry( + AdaptiveMenuButton( enabled: selectedTracks.isNotEmpty, value: "add-to-queue", leading: const Icon(SpotubeIcons.queueAdd), - title: Text( + child: Text( context.l10n.add_count_to_queue(selectedTracks.length), ), ), - PopSheetEntry( + AdaptiveMenuButton( enabled: selectedTracks.isNotEmpty, value: "play-next", leading: const Icon(SpotubeIcons.lightning), - title: Text( + child: Text( context.l10n.play_count_next(selectedTracks.length), ), ), diff --git a/lib/main.dart b/lib/main.dart index 3ed4314b..cd9acec2 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -219,12 +219,16 @@ class Spotube extends HookConsumerWidget { theme: ThemeData( radius: .5, iconTheme: const IconThemeProperties(), - colorScheme: ColorSchemes.lightNeutral(), + colorScheme: ColorSchemes.lightBlue(), + surfaceOpacity: .9, + surfaceBlur: 10, ), darkTheme: ThemeData( radius: .5, iconTheme: const IconThemeProperties(), colorScheme: ColorSchemes.darkNeutral(), + surfaceOpacity: .9, + surfaceBlur: 10, ), themeMode: themeMode, shortcuts: { diff --git a/lib/modules/player/player_actions.dart b/lib/modules/player/player_actions.dart index a47c992d..7db65c23 100644 --- a/lib/modules/player/player_actions.dart +++ b/lib/modules/player/player_actions.dart @@ -1,7 +1,7 @@ import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/modules/player/sibling_tracks_sheet.dart'; @@ -76,38 +76,37 @@ class PlayerActions extends HookConsumerWidget { mainAxisAlignment: mainAxisAlignment, children: [ if (showQueue) - IconButton( - icon: const Icon(SpotubeIcons.queue), - tooltip: context.l10n.queue, - onPressed: playlist.activeTrack != null - ? () { - Scaffold.of(context).openEndDrawer(); - } - : null, + Tooltip( + tooltip: Text(context.l10n.queue), + child: IconButton.ghost( + icon: const Icon(SpotubeIcons.queue), + enabled: playlist.activeTrack != null, + onPressed: () { + // Scaffold.of(context).openEndDrawer(); + }, + ), ), if (!isLocalTrack) - IconButton( - icon: const Icon(SpotubeIcons.alternativeRoute), - tooltip: context.l10n.alternative_track_sources, - onPressed: playlist.activeTrack != null - ? () { - showModalBottomSheet( - context: context, - isDismissible: true, - enableDrag: true, - isScrollControlled: true, - backgroundColor: Colors.black12, - barrierColor: Colors.black12, - elevation: 0, - shape: RoundedRectangleBorder( + Tooltip( + tooltip: Text(context.l10n.alternative_track_sources), + child: IconButton.ghost( + icon: const Icon(SpotubeIcons.alternativeRoute), + onPressed: playlist.activeTrack != null + ? () { + openDrawer( + context: context, + position: OverlayPosition.bottom, + barrierDismissible: true, + draggable: true, + barrierColor: Colors.black.withValues(alpha: .2), borderRadius: BorderRadius.circular(10), - ), - builder: (context) { - return SiblingTracksSheet(floating: floatingQueue); - }, - ); - } - : null, + builder: (context) { + return SiblingTracksSheet(floating: floatingQueue); + }, + ); + } + : null, + ), ), if (!kIsWeb && !isLocalTrack) if (isInQueue) @@ -115,24 +114,26 @@ class PlayerActions extends HookConsumerWidget { height: 20, width: 20, child: CircularProgressIndicator( - strokeWidth: 2, + size: 2, ), ) else - IconButton( - tooltip: context.l10n.download_track, - icon: Icon( - isDownloaded ? SpotubeIcons.done : SpotubeIcons.download, + Tooltip( + tooltip: Text(context.l10n.download_track), + child: IconButton.ghost( + icon: Icon( + isDownloaded ? SpotubeIcons.done : SpotubeIcons.download, + ), + onPressed: playlist.activeTrack != null + ? () => downloader.addToQueue(playlist.activeTrack!) + : null, ), - onPressed: playlist.activeTrack != null - ? () => downloader.addToQueue(playlist.activeTrack!) - : null, ), if (playlist.activeTrack != null && !isLocalTrack && auth.asData?.value != null) TrackHeartButton(track: playlist.activeTrack!), - AdaptivePopSheetList( + AdaptivePopSheetList( offset: Offset(0, -50 * (sleepTimerEntries.values.length + 2)), headings: [ Text(context.l10n.sleep_timer), @@ -150,24 +151,40 @@ class PlayerActions extends HookConsumerWidget { }, children: [ for (final entry in sleepTimerEntries.entries) - PopSheetEntry( + AdaptiveMenuButton( value: entry.value, enabled: sleepTimer != entry.value, - title: Text(entry.key), + child: Text(entry.key), ), - PopSheetEntry( - title: Text( - customHoursEnabled - ? context.l10n.custom_hours - : sleepTimer.format(abbreviated: true), - ), - // only enabled when there's no preset timers selected + AdaptiveMenuButton( enabled: customHoursEnabled, - onTap: () async { + onPressed: (context) async { final currentTime = TimeOfDay.now(); - final time = await showTimePicker( + final time = await showDialog( context: context, - initialTime: currentTime, + builder: (context) => HookBuilder(builder: (context) { + final timeRef = useRef(null); + return AlertDialog( + title: Text( + ShadcnLocalizations.of(context).placeholderTimePicker, + ), + content: TimePickerDialog( + use24HourFormat: false, + initialValue: TimeOfDay.fromDateTime( + DateTime.now().add(sleepTimer ?? Duration.zero), + ), + onChanged: (value) => timeRef.value = value, + ), + actions: [ + Button.primary( + onPressed: () { + Navigator.of(context).pop(timeRef.value); + }, + child: Text(context.l10n.save), + ), + ], + ); + }), ); if (time != null) { @@ -179,12 +196,19 @@ class PlayerActions extends HookConsumerWidget { ); } }, + child: Text( + customHoursEnabled + ? context.l10n.custom_hours + : sleepTimer.format(abbreviated: true), + ), ), - PopSheetEntry( + AdaptiveMenuButton( value: Duration.zero, enabled: sleepTimer != Duration.zero && sleepTimer != null, - textColor: Colors.green, - title: Text(context.l10n.cancel), + child: Text( + context.l10n.cancel, + style: const TextStyle(color: Colors.green), + ), ), ], ), diff --git a/lib/modules/player/player_controls.dart b/lib/modules/player/player_controls.dart index 12288a3d..0b3f5c2b 100644 --- a/lib/modules/player/player_controls.dart +++ b/lib/modules/player/player_controls.dart @@ -1,9 +1,9 @@ -import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:media_kit/media_kit.dart'; import 'package:palette_generator/palette_generator.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart' hide ThemeData; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/collections/intents.dart'; @@ -47,44 +47,6 @@ class PlayerControls extends HookConsumerWidget { useStream(audioPlayer.playingStream).data ?? audioPlayer.isPlaying; final theme = Theme.of(context); - final isDominantColorDark = ThemeData.estimateBrightnessForColor( - palette?.dominantColor?.color ?? theme.colorScheme.primary, - ) == - Brightness.dark; - - final dominantColor = isDominantColorDark - ? palette?.mutedColor ?? palette?.dominantColor - : palette?.dominantColor; - - final sliderColor = - palette?.dominantColor?.titleTextColor ?? theme.colorScheme.primary; - - final buttonStyle = IconButton.styleFrom( - backgroundColor: dominantColor?.color.withOpacity(0.2) ?? - theme.colorScheme.surface.withOpacity(0.4), - minimumSize: const Size(28, 28), - ); - - final activeButtonStyle = IconButton.styleFrom( - backgroundColor: - dominantColor?.titleTextColor ?? theme.colorScheme.primaryContainer, - foregroundColor: - dominantColor?.color ?? theme.colorScheme.onPrimaryContainer, - minimumSize: const Size(28, 28), - ); - - final accentColor = palette?.lightVibrantColor ?? - palette?.darkVibrantColor ?? - dominantColor; - - final resumePauseStyle = IconButton.styleFrom( - backgroundColor: accentColor?.color ?? theme.colorScheme.primary, - foregroundColor: - accentColor?.titleTextColor ?? theme.colorScheme.onPrimary, - padding: EdgeInsets.all(compact ? 10 : 12), - iconSize: compact ? 18 : 24, - ); - return GestureDetector( behavior: HitTestBehavior.translucent, onTap: () { @@ -122,45 +84,41 @@ class PlayerControls extends HookConsumerWidget { return Column( children: [ Tooltip( - message: context.l10n.slide_to_seek, + tooltip: Text(context.l10n.slide_to_seek), child: Slider( - // cannot divide by zero - // there's an edge case for value being bigger - // than total duration. Keeping it resolved - value: progress.value.toDouble(), - secondaryTrackValue: bufferProgress, + value: + SliderValue.single(progress.value.toDouble()), onChanged: isFetchingActiveTrack ? null : (v) { - progress.value = v; + progress.value = v.value; }, onChangeEnd: (value) async { await audioPlayer.seek( Duration( - seconds: (value * duration.inSeconds).toInt(), + seconds: (value.value * duration.inSeconds) + .toInt(), ), ); }, - activeColor: sliderColor, - secondaryActiveColor: sliderColor.withOpacity(0.2), - inactiveColor: sliderColor.withOpacity(0.15), ), ), Padding( padding: const EdgeInsets.symmetric( horizontal: 8.0, ), - child: DefaultTextStyle( - style: theme.textTheme.bodySmall!.copyWith( - color: palette?.dominantColor?.bodyTextColor, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text(position.toHumanReadableString()), - Text(duration.toHumanReadableString()), - ], - ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + position.toHumanReadableString(), + style: theme.typography.xSmall, + ), + Text( + duration.toHumanReadableString(), + style: theme.typography.xSmall, + ), + ], ), ), ], @@ -173,92 +131,104 @@ class PlayerControls extends HookConsumerWidget { Consumer(builder: (context, ref, _) { final shuffled = ref .watch(audioPlayerProvider.select((s) => s.shuffled)); - return IconButton( - tooltip: shuffled - ? context.l10n.unshuffle_playlist - : context.l10n.shuffle_playlist, - icon: const Icon(SpotubeIcons.shuffle), - style: shuffled ? activeButtonStyle : buttonStyle, - onPressed: isFetchingActiveTrack - ? null - : () { - if (shuffled) { - audioPlayer.setShuffle(false); - } else { - audioPlayer.setShuffle(true); - } - }, + return Tooltip( + tooltip: Text( + shuffled + ? context.l10n.unshuffle_playlist + : context.l10n.shuffle_playlist, + ), + child: IconButton( + icon: const Icon(SpotubeIcons.shuffle), + variance: shuffled + ? ButtonVariance.secondary + : ButtonVariance.ghost, + onPressed: isFetchingActiveTrack + ? null + : () { + if (shuffled) { + audioPlayer.setShuffle(false); + } else { + audioPlayer.setShuffle(true); + } + }, + ), ); }), - IconButton( - tooltip: context.l10n.previous_track, - icon: const Icon(SpotubeIcons.skipBack), - style: buttonStyle, - onPressed: isFetchingActiveTrack - ? null - : audioPlayer.skipToPrevious, + Tooltip( + tooltip: Text(context.l10n.previous_track), + child: IconButton.ghost( + enabled: !isFetchingActiveTrack, + icon: const Icon(SpotubeIcons.skipBack), + onPressed: audioPlayer.skipToPrevious, + ), ), - IconButton( - tooltip: playing - ? context.l10n.pause_playback - : context.l10n.resume_playback, - icon: isFetchingActiveTrack - ? SizedBox( - height: 20, - width: 20, - child: CircularProgressIndicator( - color: accentColor?.titleTextColor ?? - theme.colorScheme.onPrimary, + Tooltip( + tooltip: Text( + playing + ? context.l10n.pause_playback + : context.l10n.resume_playback, + ), + child: IconButton.primary( + shape: ButtonShape.circle, + icon: isFetchingActiveTrack + ? const SizedBox( + height: 20, + width: 20, + child: CircularProgressIndicator(), + ) + : Icon( + playing ? SpotubeIcons.pause : SpotubeIcons.play, ), - ) - : Icon( - playing ? SpotubeIcons.pause : SpotubeIcons.play, - ), - style: resumePauseStyle, - onPressed: isFetchingActiveTrack - ? null - : Actions.handler( - context, - PlayPauseIntent(ref), - ), + onPressed: isFetchingActiveTrack + ? null + : Actions.handler( + context, + PlayPauseIntent(ref), + ), + ), ), - IconButton( - tooltip: context.l10n.next_track, - icon: const Icon(SpotubeIcons.skipForward), - style: buttonStyle, - onPressed: - isFetchingActiveTrack ? null : audioPlayer.skipToNext, + Tooltip( + tooltip: Text(context.l10n.next_track), + child: IconButton.ghost( + icon: const Icon(SpotubeIcons.skipForward), + onPressed: + isFetchingActiveTrack ? null : audioPlayer.skipToNext, + ), ), Consumer(builder: (context, ref, _) { final loopMode = ref .watch(audioPlayerProvider.select((s) => s.loopMode)); - return IconButton( - tooltip: loopMode == PlaylistMode.single - ? context.l10n.loop_track - : loopMode == PlaylistMode.loop - ? context.l10n.repeat_playlist - : null, - icon: Icon( + return Tooltip( + tooltip: Text( loopMode == PlaylistMode.single - ? SpotubeIcons.repeatOne - : SpotubeIcons.repeat, + ? context.l10n.loop_track + : loopMode == PlaylistMode.loop + ? context.l10n.repeat_playlist + : "", + ), + child: IconButton( + icon: Icon( + loopMode == PlaylistMode.single + ? SpotubeIcons.repeatOne + : SpotubeIcons.repeat, + ), + variance: loopMode == PlaylistMode.single || + loopMode == PlaylistMode.loop + ? ButtonVariance.secondary + : ButtonVariance.ghost, + onPressed: isFetchingActiveTrack + ? null + : () async { + await audioPlayer.setLoopMode( + switch (loopMode) { + PlaylistMode.loop => PlaylistMode.single, + PlaylistMode.single => PlaylistMode.none, + PlaylistMode.none => PlaylistMode.loop, + }, + ); + }, ), - style: loopMode == PlaylistMode.single || - loopMode == PlaylistMode.loop - ? activeButtonStyle - : buttonStyle, - onPressed: isFetchingActiveTrack - ? null - : () async { - await audioPlayer.setLoopMode( - switch (loopMode) { - PlaylistMode.loop => PlaylistMode.single, - PlaylistMode.single => PlaylistMode.none, - PlaylistMode.none => PlaylistMode.loop, - }, - ); - }, ); }), ], diff --git a/lib/modules/player/volume_slider.dart b/lib/modules/player/volume_slider.dart index 8483143b..515f1fbc 100644 --- a/lib/modules/player/volume_slider.dart +++ b/lib/modules/player/volume_slider.dart @@ -1,6 +1,7 @@ import 'package:flutter/gestures.dart'; -import 'package:flutter/material.dart'; + import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/spotube_icons.dart'; class VolumeSlider extends HookConsumerWidget { @@ -30,17 +31,11 @@ class VolumeSlider extends HookConsumerWidget { } } }, - child: SliderTheme( - data: const SliderThemeData( - showValueIndicator: ShowValueIndicator.always, - ), - child: Slider( - min: 0, - max: 1, - label: (value * 100).toStringAsFixed(0), - value: value, - onChanged: onChanged, - ), + child: Slider( + min: 0, + max: 1, + value: SliderValue.single(value), + onChanged: (v) => onChanged(v.value), ), ); return Row( @@ -48,6 +43,7 @@ class VolumeSlider extends HookConsumerWidget { !fullWidth ? MainAxisAlignment.center : MainAxisAlignment.start, children: [ IconButton( + variance: ButtonVariance.ghost, icon: Icon( value == 0 ? SpotubeIcons.volumeMute diff --git a/lib/modules/root/bottom_player.dart b/lib/modules/root/bottom_player.dart index a2f45449..f435eefb 100644 --- a/lib/modules/root/bottom_player.dart +++ b/lib/modules/root/bottom_player.dart @@ -3,6 +3,7 @@ import 'dart:ui'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/assets.gen.dart'; import 'package:spotube/collections/spotube_icons.dart'; @@ -16,7 +17,6 @@ import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/hooks/utils/use_brightness_value.dart'; -import 'package:flutter/material.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; @@ -46,7 +46,7 @@ class BottomPlayer extends HookConsumerWidget { ); final theme = Theme.of(context); - final bg = theme.colorScheme.surfaceContainerHighest; + final bg = theme.colorScheme.background; final bgColor = useBrightnessValue( Color.lerp(bg, Colors.white, 0.7), @@ -64,31 +64,30 @@ class BottomPlayer extends HookConsumerWidget { child: BackdropFilter( filter: ImageFilter.blur(sigmaX: 15, sigmaY: 15), child: DecoratedBox( - decoration: BoxDecoration(color: bgColor?.withOpacity(0.8)), - child: Material( - type: MaterialType.transparency, - textStyle: theme.textTheme.bodyMedium!, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: PlayerTrackDetails(track: playlist.activeTrack), + decoration: BoxDecoration(color: bgColor?.withValues(alpha: .8)), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: PlayerTrackDetails(track: playlist.activeTrack), + ), + // controls + const Flexible( + flex: 3, + child: Padding( + padding: EdgeInsets.only(top: 5), + child: PlayerControls(), ), - // controls - const Flexible( - flex: 3, - child: Padding( - padding: EdgeInsets.only(top: 5), - child: PlayerControls(), - ), - ), - // add to saved tracks - Column( - children: [ - PlayerActions( - extraActions: [ - IconButton( - tooltip: context.l10n.mini_player, + ), + // add to saved tracks + Column( + children: [ + PlayerActions( + extraActions: [ + Tooltip( + tooltip: Text(context.l10n.mini_player), + child: IconButton( + variance: ButtonVariance.ghost, icon: const Icon(SpotubeIcons.miniPlayer), onPressed: () async { if (!kIsDesktop) return; @@ -107,35 +106,37 @@ class BottomPlayer extends HookConsumerWidget { await Future.delayed( const Duration(milliseconds: 100), () async { - GoRouter.of(context).go( - '/mini-player', - extra: prevSize, - ); + if (context.mounted) { + context.go( + '/mini-player', + extra: prevSize, + ); + } }, ); }, ), - ], - ), - Container( - height: 40, - constraints: const BoxConstraints(maxWidth: 250), - padding: const EdgeInsets.only(right: 10), - child: Consumer(builder: (context, ref, _) { - final volume = ref.watch(volumeProvider); - return VolumeSlider( - fullWidth: true, - value: volume, - onChanged: (value) { - ref.read(volumeProvider.notifier).setVolume(value); - }, - ); - }), - ) - ], - ), - ], - ), + ), + ], + ), + Container( + height: 40, + constraints: const BoxConstraints(maxWidth: 250), + padding: const EdgeInsets.only(right: 10), + child: Consumer(builder: (context, ref, _) { + final volume = ref.watch(volumeProvider); + return VolumeSlider( + fullWidth: true, + value: volume, + onChanged: (value) { + ref.read(volumeProvider.notifier).setVolume(value); + }, + ); + }), + ) + ], + ), + ], ), ), ), From 2488da2279b9fa5d65c101989e5a45e96b06188a Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 21 Dec 2024 14:38:54 +0600 Subject: [PATCH 013/112] refactor: bottom player border, player queue using shadcn drawer --- .vscode/settings.json | 1 + lib/collections/spotube_icons.dart | 1 + lib/main.dart | 4 +- lib/modules/player/player.dart | 95 +++---- lib/modules/player/player_actions.dart | 30 ++- lib/modules/player/player_queue.dart | 350 +++++++++++-------------- lib/modules/player/volume_slider.dart | 15 +- lib/modules/root/bottom_player.dart | 148 +++++------ lib/modules/root/sidebar.dart | 51 ++-- lib/pages/root/root_app.dart | 159 +++++------ 10 files changed, 397 insertions(+), 457 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 1f47bada..57413df4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -13,6 +13,7 @@ "RGBO", "riverpod", "Scrobblenaut", + "shadcn", "skeletonizer", "songlink", "speechiness", diff --git a/lib/collections/spotube_icons.dart b/lib/collections/spotube_icons.dart index 5c4df85f..a1c6d69f 100644 --- a/lib/collections/spotube_icons.dart +++ b/lib/collections/spotube_icons.dart @@ -127,4 +127,5 @@ abstract class SpotubeIcons { static const cache = FeatherIcons.hardDrive; static const export = Icons.file_open_outlined; static const delete = FeatherIcons.trash2; + static const open = FeatherIcons.externalLink; } diff --git a/lib/main.dart b/lib/main.dart index cd9acec2..d1275577 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -220,14 +220,14 @@ class Spotube extends HookConsumerWidget { radius: .5, iconTheme: const IconThemeProperties(), colorScheme: ColorSchemes.lightBlue(), - surfaceOpacity: .9, + surfaceOpacity: .8, surfaceBlur: 10, ), darkTheme: ThemeData( radius: .5, iconTheme: const IconThemeProperties(), colorScheme: ColorSchemes.darkNeutral(), - surfaceOpacity: .9, + surfaceOpacity: .8, surfaceBlur: 10, ), themeMode: themeMode, diff --git a/lib/modules/player/player.dart b/lib/modules/player/player.dart index 925afadc..a79934d9 100644 --- a/lib/modules/player/player.dart +++ b/lib/modules/player/player.dart @@ -3,6 +3,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart' + show openDrawer, OverlayPosition; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/collections/assets.gen.dart'; import 'package:spotube/collections/spotube_icons.dart'; @@ -289,53 +292,53 @@ class PlayerView extends HookConsumerWidget { const SizedBox(width: 10), Expanded( child: OutlinedButton.icon( - icon: const Icon(SpotubeIcons.queue), - label: Text(context.l10n.queue), - style: OutlinedButton.styleFrom( - foregroundColor: bodyTextColor, - side: BorderSide( - color: bodyTextColor ?? Colors.white, - ), + icon: const Icon(SpotubeIcons.queue), + label: Text(context.l10n.queue), + style: OutlinedButton.styleFrom( + foregroundColor: bodyTextColor, + side: BorderSide( + color: bodyTextColor ?? Colors.white, ), - onPressed: currentTrack != null - ? () { - showModalBottomSheet( - context: context, - isDismissible: true, - enableDrag: true, - isScrollControlled: true, - backgroundColor: Colors.black12, - barrierColor: Colors.black12, - shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.circular(10), - ), - constraints: BoxConstraints( - maxHeight: - MediaQuery.of(context) - .size - .height * - .7, - ), - builder: (context) => Consumer( - builder: (context, ref, _) { - final playlist = ref.watch( - audioPlayerProvider, - ); - final playlistNotifier = ref - .read(audioPlayerProvider - .notifier); - return PlayerQueue - .fromAudioPlayerNotifier( - floating: false, - playlist: playlist, - notifier: playlistNotifier, - ); - }, - ), - ); - } - : null), + ), + // enabled: currentTrack != null, + onPressed: () { + openDrawer( + context: context, + barrierDismissible: true, + draggable: true, + barrierColor: Colors.black12, + borderRadius: BorderRadius.circular(10), + transformBackdrop: false, + position: OverlayPosition.bottom, + surfaceBlur: context.theme.surfaceBlur, + surfaceOpacity: 0.7, + expands: true, + builder: (context) => Consumer( + builder: (context, ref, _) { + final playlist = ref.watch( + audioPlayerProvider, + ); + final playlistNotifier = ref.read( + audioPlayerProvider.notifier); + return ConstrainedBox( + constraints: BoxConstraints( + maxHeight: MediaQuery.of(context) + .size + .height * + 0.8, + ), + child: PlayerQueue + .fromAudioPlayerNotifier( + floating: false, + playlist: playlist, + notifier: playlistNotifier, + ), + ); + }, + ), + ); + }, + ), ), if (auth.asData?.value != null) const SizedBox(width: 10), diff --git a/lib/modules/player/player_actions.dart b/lib/modules/player/player_actions.dart index 7db65c23..dbdfa11b 100644 --- a/lib/modules/player/player_actions.dart +++ b/lib/modules/player/player_actions.dart @@ -2,8 +2,10 @@ import 'package:flutter/foundation.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/modules/player/player_queue.dart'; import 'package:spotube/modules/player/sibling_tracks_sheet.dart'; import 'package:spotube/components/adaptive/adaptive_pop_sheet_list.dart'; import 'package:spotube/components/heart_button/heart_button.dart'; @@ -82,7 +84,32 @@ class PlayerActions extends HookConsumerWidget { icon: const Icon(SpotubeIcons.queue), enabled: playlist.activeTrack != null, onPressed: () { - // Scaffold.of(context).openEndDrawer(); + openDrawer( + context: context, + position: OverlayPosition.right, + transformBackdrop: false, + draggable: false, + surfaceBlur: context.theme.surfaceBlur, + surfaceOpacity: 0.7, + builder: (context) { + return Container( + constraints: const BoxConstraints(maxWidth: 800), + child: Consumer( + builder: (context, ref, _) { + final playlist = ref.watch(audioPlayerProvider); + final playlistNotifier = + ref.read(audioPlayerProvider.notifier); + + return PlayerQueue.fromAudioPlayerNotifier( + floating: true, + playlist: playlist, + notifier: playlistNotifier, + ); + }, + ), + ); + }, + ); }, ), ), @@ -100,6 +127,7 @@ class PlayerActions extends HookConsumerWidget { draggable: true, barrierColor: Colors.black.withValues(alpha: .2), borderRadius: BorderRadius.circular(10), + transformBackdrop: false, builder: (context) { return SiblingTracksSheet(floating: floatingQueue); }, diff --git a/lib/modules/player/player_queue.dart b/lib/modules/player/player_queue.dart index 369b95d2..49279d5c 100644 --- a/lib/modules/player/player_queue.dart +++ b/lib/modules/player/player_queue.dart @@ -1,14 +1,12 @@ -import 'dart:ui'; - +import 'package:auto_size_text/auto_size_text.dart'; import 'package:collection/collection.dart'; -import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:fuzzywuzzy/fuzzywuzzy.dart'; -import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:scroll_to_index/scroll_to_index.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/fallbacks/not_found.dart'; @@ -60,16 +58,6 @@ class PlayerQueue extends HookConsumerWidget { final isSearching = useState(false); final tracks = playlist.tracks; - final borderRadius = floating - ? const BorderRadius.only( - topLeft: Radius.circular(10), - ) - : const BorderRadius.only( - topLeft: Radius.circular(10), - topRight: Radius.circular(10), - ); - final theme = Theme.of(context); - final headlineColor = theme.textTheme.headlineSmall?.color; final filteredTracks = useMemoized( () { @@ -92,217 +80,173 @@ class PlayerQueue extends HookConsumerWidget { [tracks, searchText.value], ); - useEffect(() { - if (playlist.activeTrack == null) return null; - - controller.scrollToIndex( - playlist.playlist.index, - preferPosition: AutoScrollPosition.middle, - ); - return null; - }, []); - if (tracks.isEmpty) { return const NotFound(vertical: true); } - return LayoutBuilder( - builder: (context, constrains) { - return ClipRRect( - borderRadius: borderRadius, - clipBehavior: Clip.hardEdge, - child: BackdropFilter( - filter: ImageFilter.blur( - sigmaX: 15, - sigmaY: 15, - ), - child: Container( - padding: const EdgeInsets.only( - top: 5.0, + return Stack( + children: [ + LayoutBuilder( + builder: (context, constrains) { + final searchBar = ConstrainedBox( + constraints: BoxConstraints( + maxHeight: 40, + maxWidth: + mediaQuery.smAndDown ? mediaQuery.size.width - 40 : 300, ), - decoration: BoxDecoration( - color: - theme.colorScheme.surfaceContainerHighest.withOpacity(0.5), - borderRadius: borderRadius, - ), - child: CallbackShortcuts( - bindings: { - LogicalKeySet(LogicalKeyboardKey.escape): () { - if (!isSearching.value) { - Navigator.of(context).pop(); - } - isSearching.value = false; - searchText.value = ''; - } + child: TextField( + onChanged: (value) { + searchText.value = value; }, - child: InterScrollbar( - controller: controller, - child: CustomScrollView( - controller: controller, - slivers: [ - if (!floating) - SliverToBoxAdapter( - child: Center( - child: Container( - height: 5, - width: 100, - margin: const EdgeInsets.only(bottom: 5, top: 2), - decoration: BoxDecoration( - color: headlineColor, - borderRadius: BorderRadius.circular(20), - ), + placeholder: Text(context.l10n.search), + ), + ); + return CallbackShortcuts( + bindings: { + LogicalKeySet(LogicalKeyboardKey.escape): () { + if (!isSearching.value) { + Navigator.of(context).pop(); + } + isSearching.value = false; + searchText.value = ''; + } + }, + child: Column( + children: [ + if (isSearching.value && mediaQuery.smAndDown) + AppBar( + backgroundColor: Colors.transparent, + leading: [ + if (mediaQuery.smAndDown) + IconButton.ghost( + icon: const Icon( + Icons.arrow_back_ios_new_outlined, ), - ), - ), - SliverAppBar( - floating: true, - pinned: false, - snap: false, - backgroundColor: Colors.transparent, - elevation: 0, - automaticallyImplyLeading: false, - title: BackdropFilter( - filter: ImageFilter.blur( - sigmaX: 10, - sigmaY: 10, - ), - child: SizedBox( - height: kToolbarHeight, - child: mediaQuery.mdAndUp || !isSearching.value - ? Align( - alignment: Alignment.centerLeft, - child: Text( - context.l10n - .tracks_in_queue(tracks.length), - style: TextStyle( - color: headlineColor, - fontWeight: FontWeight.bold, - fontSize: 18, - ), - ), - ) - : null, - ), - ), - actions: [ - if (mediaQuery.mdAndUp || isSearching.value) - TextField( - onChanged: (value) { - searchText.value = value; - }, - decoration: InputDecoration( - hintText: context.l10n.search, - isDense: true, - prefixIcon: mediaQuery.smAndDown - ? IconButton( - icon: const Icon( - Icons.arrow_back_ios_new_outlined, - ), - onPressed: () { - isSearching.value = false; - searchText.value = ''; - }, - style: IconButton.styleFrom( - padding: EdgeInsets.zero, - minimumSize: const Size.square(20), - ), - ) - : const Icon(SpotubeIcons.filter), - constraints: BoxConstraints( - maxHeight: 40, - maxWidth: mediaQuery.smAndDown - ? mediaQuery.size.width - 40 - : 300, - ), + onPressed: () { + isSearching.value = false; + searchText.value = ''; + }, + ) + ], + surfaceBlur: 0, + surfaceOpacity: 0, + child: searchBar, + ) + else + AppBar( + trailingGap: 0, + backgroundColor: Colors.transparent, + surfaceBlur: 0, + surfaceOpacity: 0, + title: mediaQuery.mdAndUp || !isSearching.value + ? SizedBox( + height: 30, + child: AutoSizeText( + context.l10n.tracks_in_queue(tracks.length), + maxLines: 1, ), ) - else - IconButton.filledTonal( - icon: const Icon(SpotubeIcons.filter), - onPressed: () { - isSearching.value = !isSearching.value; - }, - ), - if (mediaQuery.mdAndUp || !isSearching.value) ...[ - const SizedBox(width: 10), - FilledButton( - style: FilledButton.styleFrom( - backgroundColor: theme.scaffoldBackgroundColor - .withOpacity(0.5), - foregroundColor: - theme.textTheme.headlineSmall?.color, - ), - child: Row( - children: [ - const Icon(SpotubeIcons.playlistRemove), - const SizedBox(width: 5), - Text(context.l10n.clear_all), - ], - ), + : null, + trailing: [ + if (mediaQuery.mdAndUp) + searchBar + else + IconButton.ghost( + icon: const Icon(SpotubeIcons.filter), + onPressed: () { + isSearching.value = !isSearching.value; + }, + ), + if (mediaQuery.mdAndUp || !isSearching.value) ...[ + const SizedBox(width: 10), + Tooltip( + tooltip: Text(context.l10n.clear_all), + child: IconButton.outline( + icon: const Icon(SpotubeIcons.playlistRemove), onPressed: () { onStop(); Navigator.of(context).pop(); }, ), - const SizedBox(width: 10), - ], + ), ], - ), - const SliverGap(10), - SliverReorderableList( - onReorder: onReorder, - itemCount: filteredTracks.length, - onReorderStart: (index) { - HapticFeedback.selectionClick(); - }, - onReorderEnd: (index) { - HapticFeedback.selectionClick(); - }, - itemBuilder: (context, i) { - final track = filteredTracks.elementAt(i); - return AutoScrollTag( - key: ValueKey(i), - controller: controller, - index: i, - child: Material( - color: Colors.transparent, - child: TrackTile( - playlist: playlist, + ], + ), + const Divider(), + Expanded( + child: InterScrollbar( + controller: controller, + child: CustomScrollView( + controller: controller, + slivers: [ + const SliverGap(10), + SliverReorderableList( + onReorder: onReorder, + itemCount: filteredTracks.length, + onReorderStart: (index) { + HapticFeedback.selectionClick(); + }, + onReorderEnd: (index) { + HapticFeedback.selectionClick(); + }, + itemBuilder: (context, i) { + final track = filteredTracks.elementAt(i); + return AutoScrollTag( + key: ValueKey(i), + controller: controller, index: i, - track: track, - onTap: () async { - if (playlist.activeTrack?.id == track.id) { - return; - } - await onJump(track); - }, - leadingActions: [ - if (!isSearching.value && - searchText.value.isEmpty) - Padding( - padding: const EdgeInsets.only(left: 8.0), - child: ReorderableDragStartListener( - index: i, - child: const Icon( - SpotubeIcons.dragHandle, + child: TrackTile( + playlist: playlist, + index: i, + track: track, + onTap: () async { + if (playlist.activeTrack?.id == track.id) { + return; + } + await onJump(track); + }, + leadingActions: [ + if (!isSearching.value && + searchText.value.isEmpty) + Padding( + padding: + const EdgeInsets.only(left: 8.0), + child: ReorderableDragStartListener( + index: i, + child: const Icon( + SpotubeIcons.dragHandle, + ), ), ), - ), - ], - ), - ), - ); - }, + ], + ), + ); + }, + ), + const SliverGap(100), + ], ), - const SliverGap(100), - ], + ), ), - ), + ], ), - ), + ); + }, + ), + Positioned( + right: 20, + bottom: 20, + child: IconButton.secondary( + icon: const Icon(SpotubeIcons.open), + onPressed: () { + controller.scrollToIndex( + playlist.playlist.index, + preferPosition: AutoScrollPosition.middle, + ); + }, ), - ); - }, + ) + ], ); } } diff --git a/lib/modules/player/volume_slider.dart b/lib/modules/player/volume_slider.dart index 515f1fbc..ee4ac9c5 100644 --- a/lib/modules/player/volume_slider.dart +++ b/lib/modules/player/volume_slider.dart @@ -31,13 +31,18 @@ class VolumeSlider extends HookConsumerWidget { } } }, - child: Slider( - min: 0, - max: 1, - value: SliderValue.single(value), - onChanged: (v) => onChanged(v.value), + child: SizedBox( + height: 20, + width: 100, + child: Slider( + min: 0, + max: 1, + value: SliderValue.single(value), + onChanged: (v) => onChanged(v.value), + ), ), ); + return Row( mainAxisAlignment: !fullWidth ? MainAxisAlignment.center : MainAxisAlignment.start, diff --git a/lib/modules/root/bottom_player.dart b/lib/modules/root/bottom_player.dart index f435eefb..8a22cc7a 100644 --- a/lib/modules/root/bottom_player.dart +++ b/lib/modules/root/bottom_player.dart @@ -1,9 +1,8 @@ -import 'dart:ui'; - import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/collections/assets.gen.dart'; import 'package:spotube/collections/spotube_icons.dart'; @@ -16,7 +15,6 @@ import 'package:spotube/modules/player/volume_slider.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; -import 'package:spotube/hooks/utils/use_brightness_value.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; @@ -45,14 +43,6 @@ class BottomPlayer extends HookConsumerWidget { [playlist.activeTrack?.album?.images], ); - final theme = Theme.of(context); - final bg = theme.colorScheme.background; - - final bgColor = useBrightnessValue( - Color.lerp(bg, Colors.white, 0.7), - Color.lerp(bg, Colors.black, 0.45)!, - ); - // returning an empty non spacious Container as the overlay will take // place in the global overlay stack aka [_entries] if (layoutMode == LayoutMode.compact || @@ -60,85 +50,81 @@ class BottomPlayer extends HookConsumerWidget { return PlayerOverlay(albumArt: albumArt); } - return ClipRect( - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 15, sigmaY: 15), - child: DecoratedBox( - decoration: BoxDecoration(color: bgColor?.withValues(alpha: .8)), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + return SurfaceCard( + borderRadius: BorderRadius.zero, + surfaceBlur: context.theme.surfaceBlur, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: PlayerTrackDetails(track: playlist.activeTrack), + ), + // controls + const Flexible( + flex: 3, + child: Padding( + padding: EdgeInsets.only(top: 5), + child: PlayerControls(), + ), + ), + // add to saved tracks + Column( + mainAxisSize: MainAxisSize.min, children: [ - Expanded( - child: PlayerTrackDetails(track: playlist.activeTrack), - ), - // controls - const Flexible( - flex: 3, - child: Padding( - padding: EdgeInsets.only(top: 5), - child: PlayerControls(), - ), - ), - // add to saved tracks - Column( - children: [ - PlayerActions( - extraActions: [ - Tooltip( - tooltip: Text(context.l10n.mini_player), - child: IconButton( - variance: ButtonVariance.ghost, - icon: const Icon(SpotubeIcons.miniPlayer), - onPressed: () async { - if (!kIsDesktop) return; + PlayerActions( + extraActions: [ + Tooltip( + tooltip: Text(context.l10n.mini_player), + child: IconButton( + variance: ButtonVariance.ghost, + icon: const Icon(SpotubeIcons.miniPlayer), + onPressed: () async { + if (!kIsDesktop) return; - final prevSize = await windowManager.getSize(); - await windowManager.setMinimumSize( - const Size(300, 300), - ); - await windowManager.setAlwaysOnTop(true); - if (!kIsLinux) { - await windowManager.setHasShadow(false); + final prevSize = await windowManager.getSize(); + await windowManager.setMinimumSize( + const Size(300, 300), + ); + await windowManager.setAlwaysOnTop(true); + if (!kIsLinux) { + await windowManager.setHasShadow(false); + } + await windowManager.setAlignment(Alignment.topRight); + await windowManager.setSize(const Size(400, 500)); + await Future.delayed( + const Duration(milliseconds: 100), + () async { + if (context.mounted) { + context.go( + '/mini-player', + extra: prevSize, + ); } - await windowManager - .setAlignment(Alignment.topRight); - await windowManager.setSize(const Size(400, 500)); - await Future.delayed( - const Duration(milliseconds: 100), - () async { - if (context.mounted) { - context.go( - '/mini-player', - extra: prevSize, - ); - } - }, - ); }, - ), - ), - ], + ); + }, + ), ), - Container( - height: 40, - constraints: const BoxConstraints(maxWidth: 250), - padding: const EdgeInsets.only(right: 10), - child: Consumer(builder: (context, ref, _) { - final volume = ref.watch(volumeProvider); - return VolumeSlider( - fullWidth: true, - value: volume, - onChanged: (value) { - ref.read(volumeProvider.notifier).setVolume(value); - }, - ); - }), - ) ], ), + Container( + height: 40, + constraints: const BoxConstraints(maxWidth: 250), + padding: const EdgeInsets.only(right: 10), + child: Consumer(builder: (context, ref, _) { + final volume = ref.watch(volumeProvider); + return VolumeSlider( + fullWidth: true, + value: volume, + onChanged: (value) { + ref.read(volumeProvider.notifier).setVolume(value); + }, + ); + }), + ) ], ), - ), + ], ), ); } diff --git a/lib/modules/root/sidebar.dart b/lib/modules/root/sidebar.dart index 79e8d6d4..f045c23d 100644 --- a/lib/modules/root/sidebar.dart +++ b/lib/modules/root/sidebar.dart @@ -96,32 +96,31 @@ class Sidebar extends HookConsumerWidget { return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - SafeArea( - child: Column( - children: [ - Expanded( - child: mediaQuery.lgAndUp - ? NavigationSidebar( - index: selectedIndex, - onSelected: (index) { - final tile = sidebarTileList[index]; - ServiceUtils.pushNamed(context, tile.name); - }, - children: navigationButtons, - ) - : NavigationRail( - alignment: NavigationRailAlignment.start, - index: selectedIndex, - onSelected: (index) { - final tile = sidebarTileList[index]; - ServiceUtils.pushNamed(context, tile.name); - }, - children: navigationButtons, - ), - ), - const SidebarFooter(), - ], - ), + Column( + children: [ + Expanded( + child: mediaQuery.lgAndUp + ? NavigationSidebar( + index: selectedIndex, + onSelected: (index) { + final tile = sidebarTileList[index]; + ServiceUtils.pushNamed(context, tile.name); + }, + children: navigationButtons, + ) + : NavigationRail( + alignment: NavigationRailAlignment.start, + index: selectedIndex, + onSelected: (index) { + final tile = sidebarTileList[index]; + ServiceUtils.pushNamed(context, tile.name); + }, + children: navigationButtons, + ), + ), + const SidebarFooter(), + const Gap(130) + ], ), const VerticalDivider(), Expanded(child: child), diff --git a/lib/pages/root/root_app.dart b/lib/pages/root/root_app.dart index 2a6c36f0..84c40a2f 100644 --- a/lib/pages/root/root_app.dart +++ b/lib/pages/root/root_app.dart @@ -1,14 +1,13 @@ import 'dart:async'; -import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/side_bar_tiles.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/framework/app_pop_scope.dart'; -import 'package:spotube/modules/player/player_queue.dart'; import 'package:spotube/components/dialogs/replace_downloaded_dialog.dart'; import 'package:spotube/modules/root/bottom_player.dart'; import 'package:spotube/modules/root/sidebar.dart'; @@ -17,7 +16,6 @@ import 'package:spotube/extensions/context.dart'; import 'package:spotube/hooks/configurators/use_endless_playback.dart'; import 'package:spotube/pages/home/home.dart'; import 'package:spotube/provider/download_manager_provider.dart'; -import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/provider/glance/glance.dart'; import 'package:spotube/provider/server/routes/connect.dart'; import 'package:spotube/services/connectivity_adapter.dart'; @@ -37,7 +35,7 @@ class RootApp extends HookConsumerWidget { final showingDialogCompleter = useRef(Completer()..complete()); final downloader = ref.watch(downloadManagerProvider); - final scaffoldMessenger = ScaffoldMessenger.of(context); + final connectRoutes = ref.watch(serverConnectRoutesProvider); ref.listen(glanceProvider, (_, __) {}); @@ -50,64 +48,70 @@ class RootApp extends HookConsumerWidget { final subscriptions = [ ConnectionCheckerService.instance.onConnectivityChanged .listen((status) { + if (!context.mounted) return; if (status) { - scaffoldMessenger.showSnackBar( - SnackBar( - content: Row( - children: [ - Icon( - SpotubeIcons.wifi, - color: theme.colorScheme.onPrimary, - ), - const SizedBox(width: 10), - Text(context.l10n.connection_restored), - ], - ), - backgroundColor: theme.colorScheme.primary, - showCloseIcon: true, - width: 350, - ), + showToast( + context: context, + builder: (context, overlay) { + return SurfaceCard( + fillColor: theme.colorScheme.primary, + child: Row( + children: [ + Icon( + SpotubeIcons.wifi, + color: theme.colorScheme.primaryForeground, + ), + const SizedBox(width: 10), + Text(context.l10n.connection_restored), + ], + ), + ); + }, ); } else { - scaffoldMessenger.showSnackBar( - SnackBar( - content: Row( - children: [ - Icon( - SpotubeIcons.noWifi, - color: theme.colorScheme.onError, - ), - const SizedBox(width: 10), - Text(context.l10n.you_are_offline), - ], - ), - backgroundColor: theme.colorScheme.error, - showCloseIcon: true, - width: 300, - ), + showToast( + context: context, + builder: (context, overlay) { + return SurfaceCard( + fillColor: theme.colorScheme.destructive, + child: Row( + children: [ + Icon( + SpotubeIcons.noWifi, + color: theme.colorScheme.destructiveForeground, + ), + const SizedBox(width: 10), + Text(context.l10n.you_are_offline), + ], + ), + ); + }, ); } }), connectRoutes.connectClientStream.listen((clientOrigin) { - scaffoldMessenger.showSnackBar( - SnackBar( - backgroundColor: Colors.yellow[600], - behavior: SnackBarBehavior.floating, - content: Row( - mainAxisSize: MainAxisSize.min, - children: [ - const Icon( - SpotubeIcons.error, - color: Colors.black, - ), - const SizedBox(width: 10), - Text( - context.l10n.connect_client_alert(clientOrigin), - style: const TextStyle(color: Colors.black), - ), - ], - ), - ), + if (!context.mounted) return; + showToast( + context: context, + builder: (context, overlay) { + return SurfaceCard( + fillColor: Colors.yellow[600], + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon( + SpotubeIcons.error, + color: Colors.black, + ), + const SizedBox(width: 10), + Text( + context.l10n.connect_client_alert(clientOrigin), + style: const TextStyle(color: Colors.black), + ), + ], + ), + ); + }, ); }) ]; @@ -156,7 +160,7 @@ class RootApp extends HookConsumerWidget { useEndlessPlayback(ref); - final backgroundColor = Theme.of(context).scaffoldBackgroundColor; + final backgroundColor = Theme.of(context).colorScheme.background; useEffect(() { SystemChrome.setSystemUIOverlayStyle( @@ -175,43 +179,12 @@ class RootApp extends HookConsumerWidget { }, []); final scaffold = Scaffold( - body: Sidebar(child: child), - extendBody: true, - drawerScrimColor: Colors.transparent, - endDrawer: kIsDesktop - ? Container( - constraints: const BoxConstraints(maxWidth: 800), - decoration: BoxDecoration( - boxShadow: theme.brightness == Brightness.light - ? null - : kElevationToShadow[8], - ), - margin: const EdgeInsets.only( - top: 40, - bottom: 100, - ), - child: Consumer( - builder: (context, ref, _) { - final playlist = ref.watch(audioPlayerProvider); - final playlistNotifier = - ref.read(audioPlayerProvider.notifier); - - return PlayerQueue.fromAudioPlayerNotifier( - floating: true, - playlist: playlist, - notifier: playlistNotifier, - ); - }, - ), - ) - : null, - bottomNavigationBar: const Column( - mainAxisSize: MainAxisSize.min, - children: [ - BottomPlayer(), - SpotubeNavigationBar(), - ], - ), + footers: const [ + BottomPlayer(), + SpotubeNavigationBar(), + ], + floatingFooter: true, + child: Sidebar(child: child), ); if (!kIsAndroid) { From 1089e905116714accaf9db97c36134a7108da7af Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 21 Dec 2024 15:21:13 +0600 Subject: [PATCH 014/112] refactor: use shadcn CardImage for playbutton card --- .../horizontal_playbutton_card_view.dart | 2 + lib/components/playbutton_card.dart | 237 +++++------------- 2 files changed, 65 insertions(+), 174 deletions(-) diff --git a/lib/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart b/lib/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart index 16204952..1093fff0 100644 --- a/lib/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart +++ b/lib/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart @@ -2,6 +2,7 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:gap/gap.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/collections/fake.dart'; @@ -90,6 +91,7 @@ class HorizontalPlaybuttonCardView extends HookWidget { ), isLoading: isLoadingNextPage, hasReachedMax: !hasNextPage, + separatorBuilder: (context, index) => const Gap(8.0), itemBuilder: (context, index) { final item = items[index]; diff --git a/lib/components/playbutton_card.dart b/lib/components/playbutton_card.dart index ae9050d8..0b942564 100644 --- a/lib/components/playbutton_card.dart +++ b/lib/components/playbutton_card.dart @@ -1,16 +1,9 @@ -import 'package:auto_size_text/auto_size_text.dart'; -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:gap/gap.dart'; -import 'package:skeletonizer/skeletonizer.dart'; + +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/spotube_icons.dart'; -import 'package:spotube/components/hover_builder.dart'; import 'package:spotube/components/image/universal_image.dart'; -import 'package:spotube/extensions/constrains.dart'; -import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/string.dart'; -import 'package:spotube/hooks/utils/use_breakpoint_value.dart'; -import 'package:spotube/hooks/utils/use_brightness_value.dart'; class PlaybuttonCard extends HookWidget { final void Function()? onTap; @@ -40,180 +33,76 @@ class PlaybuttonCard extends HookWidget { @override Widget build(BuildContext context) { - final textsKey = useMemoized(() => GlobalKey(), []); - final theme = Theme.of(context); - final mediaQuery = MediaQuery.of(context); - final radius = BorderRadius.circular(15); - - final double size = useBreakpointValue( - xs: 130, - sm: 130, - md: 150, - others: 170, - ); - - final end = useBreakpointValue( - xs: 7, - sm: 7, - others: 15, - ); - final unescapeHtml = description?.unescapeHtml().cleanHtml(); + return Container( - constraints: BoxConstraints(maxWidth: size), - margin: margin, - child: Material( - color: Color.lerp( - theme.colorScheme.surfaceContainerHighest, - theme.colorScheme.surface, - useBrightnessValue(.9, .7), - ), - borderRadius: radius, - shadowColor: theme.colorScheme.surface, - elevation: 3, - child: InkWell( - mouseCursor: SystemMouseCursors.click, - onTap: onTap, - borderRadius: radius, - splashFactory: theme.splashFactory, - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Stack( - clipBehavior: Clip.none, - children: [ - Container( - margin: const EdgeInsets.fromLTRB(8, 8, 8, 0), - padding: const EdgeInsets.only( - left: 8, - right: 8, - top: 8, - ), - height: mediaQuery.smAndDown - ? 120 - : mediaQuery.mdAndDown - ? 130 - : 150, - decoration: BoxDecoration( - borderRadius: radius, - image: DecorationImage( - image: UniversalImage.imageProvider(imageUrl), - fit: BoxFit.cover, + width: 150, + child: CardImage( + image: Stack( + children: [ + UniversalImage( + path: imageUrl, + fit: BoxFit.cover, + ), + StatedWidget.builder( + builder: (context, states) { + return Positioned( + right: 8, + bottom: 8, + child: Column( + children: [ + AnimatedScale( + curve: Curves.easeOutBack, + duration: const Duration(milliseconds: 300), + scale: states.contains(WidgetState.hovered) ? 1 : 0.7, + child: AnimatedOpacity( + duration: const Duration(milliseconds: 300), + opacity: states.contains(WidgetState.hovered) ? 1 : 0, + child: IconButton.secondary( + icon: const Icon(SpotubeIcons.queueAdd), + onPressed: onAddToQueuePressed, + size: ButtonSize.small, + ), + ), ), - ), - ), - if (isOwner) - Positioned( - top: 15, - left: 15, - child: AnimatedSize( + const Gap(5), + AnimatedScale( + curve: Curves.easeOutBack, duration: const Duration(milliseconds: 150), - alignment: Alignment.centerLeft, - curve: Curves.easeInExpo, - child: HoverBuilder(builder: (context, isHovered) { - return Container( - padding: const EdgeInsets.all(4), - decoration: BoxDecoration( - color: Colors.blueAccent, - borderRadius: BorderRadius.circular(20), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - const Icon( - SpotubeIcons.user, - color: Colors.white, - size: 16, - ), - if (isHovered) - Text( - context.l10n.owned_by_you, - style: theme.textTheme.bodySmall?.copyWith( - color: Colors.white, - ), - ), - ], - ), - ); - }), - ), - ), - Positioned( - right: end, - bottom: -15, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - if (!isPlaying) - Skeleton.keep( - child: IconButton( - style: IconButton.styleFrom( - backgroundColor: theme.colorScheme.surface, - foregroundColor: theme.colorScheme.primary, - minimumSize: const Size.square(10), - ), - icon: const Icon(SpotubeIcons.queueAdd), - onPressed: isLoading ? null : onAddToQueuePressed, - ), + scale: states.contains(WidgetState.hovered) ? 1 : 0.7, + child: AnimatedOpacity( + duration: const Duration(milliseconds: 150), + opacity: states.contains(WidgetState.hovered) ? 1 : 0, + child: IconButton.secondary( + icon: const Icon(SpotubeIcons.play), + onPressed: onPlaybuttonPressed, + size: ButtonSize.small, ), - const Gap(5), - IconButton( - style: IconButton.styleFrom( - backgroundColor: theme.colorScheme.primaryContainer, - foregroundColor: theme.colorScheme.primary, - minimumSize: const Size.square(10), - ), - icon: Skeleton.keep( - child: isLoading - ? SizedBox.fromSize( - size: const Size.square(15), - child: const CircularProgressIndicator( - strokeWidth: 2), - ) - : isPlaying - ? const Icon(SpotubeIcons.pause) - : const Icon(SpotubeIcons.play), - ), - onPressed: isLoading ? null : onPlaybuttonPressed, ), - ], - ), - ), - ], - ), - Column( - key: textsKey, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox(height: 15), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 12.0), - child: AutoSizeText( - title, - maxLines: 1, - minFontSize: theme.textTheme.bodyMedium!.fontSize!, - overflow: TextOverflow.ellipsis, - ), - ), - if (description != null) - Padding( - padding: const EdgeInsets.symmetric(horizontal: 12.0), - child: AutoSizeText( - unescapeHtml!, - maxLines: 2, - style: theme.textTheme.bodySmall?.copyWith( - color: theme.colorScheme.onSurface.withOpacity(.5), - ), - overflow: TextOverflow.ellipsis, ), - ), - const SizedBox(height: 10), - ], - ), - ], + ], + ), + ); + }, + ) + ], + ), + title: Tooltip( + tooltip: Text(title), + child: Text( + title, + maxLines: 1, + overflow: TextOverflow.ellipsis, ), ), + subtitle: unescapeHtml == null + ? null + : Text( + unescapeHtml, + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + onPressed: onTap, ), ); } From fcefce4b1bfa28221ee7d0a6a5bb815cb088d277 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 21 Dec 2024 16:05:35 +0600 Subject: [PATCH 015/112] refactor: titlebar to use shadcn appbar and library tabs to use shadcn TabList --- lib/components/playbutton_card.dart | 15 +++--- lib/components/titlebar/titlebar.dart | 30 +++++------ lib/pages/library/library.dart | 78 ++++++++++++++++----------- 3 files changed, 67 insertions(+), 56 deletions(-) diff --git a/lib/components/playbutton_card.dart b/lib/components/playbutton_card.dart index 0b942564..f781066e 100644 --- a/lib/components/playbutton_card.dart +++ b/lib/components/playbutton_card.dart @@ -33,7 +33,7 @@ class PlaybuttonCard extends HookWidget { @override Widget build(BuildContext context) { - final unescapeHtml = description?.unescapeHtml().cleanHtml(); + final unescapeHtml = description?.unescapeHtml().cleanHtml() ?? ""; return Container( width: 150, @@ -42,6 +42,7 @@ class PlaybuttonCard extends HookWidget { children: [ UniversalImage( path: imageUrl, + height: 150, fit: BoxFit.cover, ), StatedWidget.builder( @@ -95,13 +96,11 @@ class PlaybuttonCard extends HookWidget { overflow: TextOverflow.ellipsis, ), ), - subtitle: unescapeHtml == null - ? null - : Text( - unescapeHtml, - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), + subtitle: Text( + unescapeHtml.isEmpty ? "\n" : unescapeHtml, + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), onPressed: onTap, ), ); diff --git a/lib/components/titlebar/titlebar.dart b/lib/components/titlebar/titlebar.dart index 76a5ec8a..a3d0978c 100644 --- a/lib/components/titlebar/titlebar.dart +++ b/lib/components/titlebar/titlebar.dart @@ -1,5 +1,6 @@ -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart' hide AppBar; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart' show AppBar; import 'package:spotube/components/titlebar/titlebar_buttons.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/utils/platform.dart'; @@ -148,29 +149,26 @@ class _PageWindowTitleBarState extends ConsumerState { left: kIsMacOS && hasFullscreen && hasLeadingOrCanPop ? 65 : 0, ), child: AppBar( - leading: widget.leading, - automaticallyImplyLeading: widget.automaticallyImplyLeading, - actions: [ + leading: [ + if (widget.leading != null) widget.leading!, + if (widget.leading == null && + widget.automaticallyImplyLeading && + Navigator.canPop(context)) + const BackButton(), + ], + trailing: [ ...?widget.actions, WindowTitleBarButtons(foregroundColor: widget.foregroundColor), ], backgroundColor: widget.backgroundColor, - foregroundColor: widget.foregroundColor, - actionsIconTheme: widget.actionsIconTheme, - centerTitle: widget.centerTitle, - titleSpacing: widget.titleSpacing, - toolbarOpacity: widget.toolbarOpacity, - leadingWidth: widget.leadingWidth, - toolbarTextStyle: widget.toolbarTextStyle, - titleTextStyle: widget.titleTextStyle, title: SizedBox( width: double.infinity, // workaround to force dragging child: widget.title ?? const Text(""), ), - scrolledUnderElevation: 0, - shadowColor: Colors.transparent, - forceMaterialTransparency: true, - elevation: 0, + alignment: widget.centerTitle == true + ? Alignment.center + : Alignment.centerLeft, + leadingGap: widget.leadingWidth, ), ), ); diff --git a/lib/pages/library/library.dart b/lib/pages/library/library.dart index a0bc1bb7..02152f3d 100644 --- a/lib/pages/library/library.dart +++ b/lib/pages/library/library.dart @@ -1,5 +1,7 @@ -import 'package:flutter/material.dart' hide Image; +import 'package:flutter/material.dart' show Badge; +import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/modules/library/user_local_tracks.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; @@ -7,7 +9,6 @@ import 'package:spotube/modules/library/user_albums.dart'; import 'package:spotube/modules/library/user_artists.dart'; import 'package:spotube/modules/library/user_downloads.dart'; import 'package:spotube/modules/library/user_playlists.dart'; -import 'package:spotube/components/themed_button_tab_bar.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/download_manager_provider.dart'; @@ -18,40 +19,53 @@ class LibraryPage extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { final downloadingCount = ref.watch(downloadManagerProvider).$downloadCount; + final index = useState(0); - return DefaultTabController( - length: 5, - child: SafeArea( - bottom: false, - child: Scaffold( - appBar: PageWindowTitleBar( - centerTitle: true, - leading: ThemedButtonsTabBar( - tabs: [ - Tab(text: " ${context.l10n.playlists} "), - Tab(text: " ${context.l10n.local_tab} "), - Tab( - child: Badge( - isLabelVisible: downloadingCount > 0, - label: Text(downloadingCount.toString()), - child: Text(" ${context.l10n.downloads} "), + final children = [ + Text(context.l10n.playlists), + Text(context.l10n.local_tab), + Badge( + isLabelVisible: downloadingCount > 0, + label: Text(downloadingCount.toString()), + child: Text(context.l10n.downloads), + ), + Text(context.l10n.artists), + Text(context.l10n.albums), + ]; + + return SafeArea( + bottom: false, + child: Scaffold( + headers: [ + PageWindowTitleBar( + leading: TabList( + index: index.value, + children: [ + for (final child in children) + TabButton( + child: child, + onPressed: () { + index.value = children.indexOf(child); + }, ), - ), - Tab(text: " ${context.l10n.artists} "), - Tab(text: " ${context.l10n.albums} "), ], ), - leadingWidth: double.infinity, - ), - body: const TabBarView( - children: [ - UserPlaylists(), - UserLocalTracks(), - UserDownloads(), - UserArtists(), - UserAlbums(), - ], - ), + ) + ], + child: IndexedStack( + index: index.value, + children: const [ + UserPlaylists(), + UserLocalTracks(), + UserDownloads(), + UserArtists(), + UserAlbums(), + // Text("UserPlaylists()"), + // Text("UserLocalTracks()"), + // Text("UserDownloads()"), + // Text("UserArtists()"), + // Text("UserAlbums()"), + ], ), ), ); From f80ea32de46c717020cba30acbab48ee4b9435e5 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 21 Dec 2024 17:02:13 +0600 Subject: [PATCH 016/112] refactor: use Appbar titlebar throughout the app --- lib/components/titlebar/titlebar.dart | 222 ++++++------------ lib/components/track_tile/track_options.dart | 2 + lib/components/tracks_view/track_view.dart | 14 +- lib/modules/player/player.dart | 16 +- lib/pages/artist/artist.dart | 4 +- lib/pages/connect/connect.dart | 3 +- lib/pages/connect/control/control.dart | 2 +- .../getting_started/getting_started.dart | 4 +- lib/pages/home/feed/feed_section.dart | 4 +- lib/pages/home/genres/genre_playlists.dart | 4 +- lib/pages/home/genres/genres.dart | 3 +- lib/pages/home/home.dart | 2 +- lib/pages/lastfm_login/lastfm_login.dart | 2 +- lib/pages/library/library.dart | 33 ++- lib/pages/library/local_folder.dart | 7 +- .../playlist_generate/playlist_generate.dart | 5 +- .../playlist_generate_result.dart | 2 +- lib/pages/lyrics/lyrics.dart | 2 +- lib/pages/mobile_login/mobile_login.dart | 4 +- lib/pages/profile/profile.dart | 4 +- lib/pages/search/search.dart | 2 +- lib/pages/settings/about.dart | 4 +- lib/pages/settings/blacklist.dart | 5 +- lib/pages/settings/logs.dart | 6 +- lib/pages/settings/settings.dart | 3 +- lib/pages/stats/albums/albums.dart | 3 +- lib/pages/stats/artists/artists.dart | 3 +- lib/pages/stats/fees/fees.dart | 3 +- lib/pages/stats/minutes/minutes.dart | 3 +- lib/pages/stats/playlists/playlists.dart | 3 +- lib/pages/stats/stats.dart | 2 +- lib/pages/stats/streams/streams.dart | 3 +- lib/pages/track/track.dart | 2 +- 33 files changed, 149 insertions(+), 232 deletions(-) diff --git a/lib/components/titlebar/titlebar.dart b/lib/components/titlebar/titlebar.dart index a3d0978c..282a734d 100644 --- a/lib/components/titlebar/titlebar.dart +++ b/lib/components/titlebar/titlebar.dart @@ -1,89 +1,56 @@ import 'package:flutter/material.dart' hide AppBar; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:shadcn_flutter/shadcn_flutter.dart' show AppBar; +import 'package:shadcn_flutter/shadcn_flutter.dart' + show AppBar, WidgetExtension; import 'package:spotube/components/titlebar/titlebar_buttons.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/utils/platform.dart'; - import 'package:window_manager/window_manager.dart'; -class PageWindowTitleBar extends StatefulHookConsumerWidget - implements PreferredSizeWidget { - final Widget? leading; +class TitleBar extends HookConsumerWidget implements PreferredSizeWidget { final bool automaticallyImplyLeading; - final List? actions; + final List trailing; + final List leading; + final Widget? child; + final Widget? title; + final Widget? header; // small widget placed on top of title + final Widget? subtitle; // small widget placed below title + final bool + trailingExpanded; // expand the trailing instead of the main content + final AlignmentGeometry alignment; final Color? backgroundColor; final Color? foregroundColor; - final IconThemeData? actionsIconTheme; - final bool? centerTitle; - final double? titleSpacing; - final double toolbarOpacity; - final double? leadingWidth; - final TextStyle? toolbarTextStyle; - final TextStyle? titleTextStyle; - final double? titleWidth; - final Widget? title; + final double? leadingGap; + final double? trailingGap; + final EdgeInsetsGeometry? padding; + final double? height; + final bool useSafeArea; + final double? surfaceBlur; + final double? surfaceOpacity; - final bool _sliver; - - const PageWindowTitleBar({ + const TitleBar({ super.key, - this.actions, + this.automaticallyImplyLeading = true, + this.trailing = const [], + this.leading = const [], this.title, - this.toolbarOpacity = 1, + this.header, + this.subtitle, + this.child, + this.trailingExpanded = false, + this.alignment = Alignment.center, + this.padding, this.backgroundColor, - this.actionsIconTheme, - this.automaticallyImplyLeading = false, - this.centerTitle, this.foregroundColor, - this.leading, - this.leadingWidth, - this.titleSpacing, - this.titleTextStyle, - this.titleWidth, - this.toolbarTextStyle, - }) : _sliver = false, - pinned = false, - floating = false, - snap = false, - stretch = false; + this.leadingGap, + this.trailingGap, + this.height, + this.surfaceBlur, + this.surfaceOpacity, + this.useSafeArea = true, + }); - final bool pinned; - final bool floating; - final bool snap; - final bool stretch; - - const PageWindowTitleBar.sliver({ - super.key, - this.actions, - this.title, - this.backgroundColor, - this.actionsIconTheme, - this.automaticallyImplyLeading = false, - this.centerTitle, - this.foregroundColor, - this.leading, - this.leadingWidth, - this.titleSpacing, - this.titleTextStyle, - this.titleWidth, - this.toolbarTextStyle, - this.pinned = false, - this.floating = false, - this.snap = false, - this.stretch = false, - }) : _sliver = true, - toolbarOpacity = 1; - - @override - Size get preferredSize => const Size.fromHeight(kToolbarHeight); - - @override - ConsumerState createState() => _PageWindowTitleBarState(); -} - -class _PageWindowTitleBarState extends ConsumerState { - void onDrag(details) { + void onDrag(WidgetRef ref) { final systemTitleBar = ref.read(userPreferencesProvider.select((s) => s.systemTitleBar)); if (kIsDesktop && !systemTitleBar) { @@ -92,86 +59,53 @@ class _PageWindowTitleBarState extends ConsumerState { } @override - Widget build(BuildContext context) { - final mediaQuery = MediaQuery.of(context); + Widget build(BuildContext context, ref) { + final hasLeadingOrCanPop = leading.isNotEmpty || Navigator.canPop(context); - if (widget._sliver) { - return SliverLayoutBuilder( + return SizedBox( + height: height ?? 56, + child: LayoutBuilder( builder: (context, constraints) { final hasFullscreen = - mediaQuery.size.width == constraints.crossAxisExtent; - final hasLeadingOrCanPop = - widget.leading != null || Navigator.canPop(context); + MediaQuery.sizeOf(context).width == constraints.maxWidth; - return SliverPadding( - padding: EdgeInsets.only( - left: kIsMacOS && hasFullscreen && hasLeadingOrCanPop ? 65 : 0, - ), - sliver: SliverAppBar( - leading: widget.leading, - automaticallyImplyLeading: widget.automaticallyImplyLeading, - actions: [ - ...?widget.actions, - WindowTitleBarButtons(foregroundColor: widget.foregroundColor), + return GestureDetector( + onHorizontalDragStart: (_) => onDrag(ref), + onVerticalDragStart: (_) => onDrag(ref), + child: AppBar( + leading: leading.isEmpty && + automaticallyImplyLeading && + Navigator.canPop(context) + ? [ + const BackButton(), + ] + : leading, + trailing: [ + ...trailing, + WindowTitleBarButtons(foregroundColor: foregroundColor), ], - backgroundColor: widget.backgroundColor, - foregroundColor: widget.foregroundColor, - actionsIconTheme: widget.actionsIconTheme, - centerTitle: widget.centerTitle, - titleSpacing: widget.titleSpacing, - leadingWidth: widget.leadingWidth, - toolbarTextStyle: widget.toolbarTextStyle, - titleTextStyle: widget.titleTextStyle, - title: SizedBox( - width: double.infinity, // workaround to force dragging - child: widget.title ?? const Text(""), - ), - pinned: widget.pinned, - floating: widget.floating, - snap: widget.snap, - stretch: widget.stretch, - ), + title: title, + header: header, + subtitle: subtitle, + trailingExpanded: trailingExpanded, + alignment: alignment, + padding: padding, + backgroundColor: backgroundColor, + leadingGap: leadingGap, + trailingGap: trailingGap, + height: height, + surfaceBlur: surfaceBlur, + surfaceOpacity: surfaceOpacity, + useSafeArea: useSafeArea, + child: child, + ).withPadding( + left: kIsMacOS && hasFullscreen && hasLeadingOrCanPop ? 65 : 0), ); }, - ); - } - - return LayoutBuilder(builder: (context, constrains) { - final hasFullscreen = mediaQuery.size.width == constrains.maxWidth; - final hasLeadingOrCanPop = - widget.leading != null || Navigator.canPop(context); - - return GestureDetector( - onHorizontalDragStart: onDrag, - onVerticalDragStart: onDrag, - child: Padding( - padding: EdgeInsets.only( - left: kIsMacOS && hasFullscreen && hasLeadingOrCanPop ? 65 : 0, - ), - child: AppBar( - leading: [ - if (widget.leading != null) widget.leading!, - if (widget.leading == null && - widget.automaticallyImplyLeading && - Navigator.canPop(context)) - const BackButton(), - ], - trailing: [ - ...?widget.actions, - WindowTitleBarButtons(foregroundColor: widget.foregroundColor), - ], - backgroundColor: widget.backgroundColor, - title: SizedBox( - width: double.infinity, // workaround to force dragging - child: widget.title ?? const Text(""), - ), - alignment: widget.centerTitle == true - ? Alignment.center - : Alignment.centerLeft, - leadingGap: widget.leadingWidth, - ), - ), - ); - }); + ), + ); } + + @override + Size get preferredSize => Size.fromHeight(height ?? 56.0); } diff --git a/lib/components/track_tile/track_options.dart b/lib/components/track_tile/track_options.dart index 28a85fd1..c40ddd2a 100644 --- a/lib/components/track_tile/track_options.dart +++ b/lib/components/track_tile/track_options.dart @@ -5,6 +5,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; + import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotify/spotify.dart' hide Offset; import 'package:spotube/collections/assets.gen.dart'; @@ -344,6 +345,7 @@ class TrackOptions extends HookConsumerWidget { leading: const Icon(SpotubeIcons.album), child: Column( mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(context.l10n.go_to_album), Text( diff --git a/lib/components/tracks_view/track_view.dart b/lib/components/tracks_view/track_view.dart index 2a3f5237..fa6011e0 100644 --- a/lib/components/tracks_view/track_view.dart +++ b/lib/components/tracks_view/track_view.dart @@ -20,14 +20,14 @@ class TrackView extends HookConsumerWidget { return Scaffold( appBar: kIsDesktop - ? const PageWindowTitleBar( + ? const TitleBar( backgroundColor: Colors.transparent, - foregroundColor: Colors.white, - leadingWidth: 400, - leading: Align( - alignment: Alignment.centerLeft, - child: BackButton(color: Colors.white), - ), + leading: [ + Align( + alignment: Alignment.centerLeft, + child: BackButton(color: Colors.white), + ) + ], ) : null, extendBodyBehindAppBar: true, diff --git a/lib/modules/player/player.dart b/lib/modules/player/player.dart index a79934d9..3f19fbf0 100644 --- a/lib/modules/player/player.dart +++ b/lib/modules/player/player.dart @@ -138,15 +138,15 @@ class PlayerView extends HookConsumerWidget { child: ForceDraggableWidget( child: Padding( padding: EdgeInsets.only(top: topPadding), - child: PageWindowTitleBar( + child: TitleBar( backgroundColor: Colors.transparent, - foregroundColor: titleTextColor, - toolbarOpacity: 1, - leading: IconButton( - icon: const Icon(SpotubeIcons.angleDown, size: 18), - onPressed: panelController.close, - ), - actions: [ + leading: [ + IconButton( + icon: const Icon(SpotubeIcons.angleDown, size: 18), + onPressed: panelController.close, + ) + ], + trailing: [ if (currentTrack is YoutubeSourcedTrack) TextButton.icon( icon: Assets.logos.songlinkTransparent.image( diff --git a/lib/pages/artist/artist.dart b/lib/pages/artist/artist.dart index 70ad72de..9e8b5be4 100644 --- a/lib/pages/artist/artist.dart +++ b/lib/pages/artist/artist.dart @@ -30,8 +30,8 @@ class ArtistPage extends HookConsumerWidget { return SafeArea( bottom: false, child: Scaffold( - appBar: const PageWindowTitleBar( - leading: BackButton(), + appBar: const TitleBar( + leading: [BackButton()], backgroundColor: Colors.transparent, ), extendBodyBehindAppBar: true, diff --git a/lib/pages/connect/connect.dart b/lib/pages/connect/connect.dart index d3b0d0cb..1a5dfb31 100644 --- a/lib/pages/connect/connect.dart +++ b/lib/pages/connect/connect.dart @@ -23,10 +23,9 @@ class ConnectPage extends HookConsumerWidget { final discoveredDevices = connectClients.asData?.value.services; return Scaffold( - appBar: PageWindowTitleBar( + appBar: TitleBar( automaticallyImplyLeading: true, title: Text(context.l10n.devices), - titleSpacing: 0, ), body: ListTileTheme( shape: RoundedRectangleBorder( diff --git a/lib/pages/connect/control/control.dart b/lib/pages/connect/control/control.dart index cae0bd1b..03406546 100644 --- a/lib/pages/connect/control/control.dart +++ b/lib/pages/connect/control/control.dart @@ -88,7 +88,7 @@ class ConnectControlPage extends HookConsumerWidget { return SafeArea( child: Scaffold( - appBar: PageWindowTitleBar( + appBar: TitleBar( title: Text(resolvedService!.name), automaticallyImplyLeading: true, ), diff --git a/lib/pages/getting_started/getting_started.dart b/lib/pages/getting_started/getting_started.dart index 0159a77f..6a8141d0 100644 --- a/lib/pages/getting_started/getting_started.dart +++ b/lib/pages/getting_started/getting_started.dart @@ -43,9 +43,9 @@ class GettingStarting extends HookConsumerWidget { return Theme( data: themeData, child: Scaffold( - appBar: PageWindowTitleBar( + appBar: TitleBar( backgroundColor: Colors.transparent, - actions: [ + trailing: [ ListenableBuilder( listenable: pageController, builder: (context, _) { diff --git a/lib/pages/home/feed/feed_section.dart b/lib/pages/home/feed/feed_section.dart index bcfc0b81..0249d865 100644 --- a/lib/pages/home/feed/feed_section.dart +++ b/lib/pages/home/feed/feed_section.dart @@ -23,11 +23,9 @@ class HomeFeedSectionPage extends HookConsumerWidget { return Skeletonizer( enabled: homeFeedSection.isLoading, child: Scaffold( - appBar: PageWindowTitleBar( + appBar: TitleBar( title: Text(section.title ?? ""), - centerTitle: false, automaticallyImplyLeading: true, - titleSpacing: 0, ), body: CustomScrollView( slivers: [ diff --git a/lib/pages/home/genres/genre_playlists.dart b/lib/pages/home/genres/genre_playlists.dart index 04658965..ec478617 100644 --- a/lib/pages/home/genres/genre_playlists.dart +++ b/lib/pages/home/genres/genre_playlists.dart @@ -40,8 +40,8 @@ class GenrePlaylistsPage extends HookConsumerWidget { return Scaffold( appBar: kIsDesktop - ? const PageWindowTitleBar( - leading: BackButton(color: Colors.white), + ? const TitleBar( + leading: [BackButton(color: Colors.white)], backgroundColor: Colors.transparent, foregroundColor: Colors.white, ) diff --git a/lib/pages/home/genres/genres.dart b/lib/pages/home/genres/genres.dart index 4846d633..ed9d9351 100644 --- a/lib/pages/home/genres/genres.dart +++ b/lib/pages/home/genres/genres.dart @@ -25,10 +25,9 @@ class GenrePage extends HookConsumerWidget { final mediaQuery = MediaQuery.of(context); return Scaffold( - appBar: PageWindowTitleBar( + appBar: TitleBar( title: Text(context.l10n.explore_genres), automaticallyImplyLeading: true, - titleSpacing: 0, ), body: SafeArea( top: false, diff --git a/lib/pages/home/home.dart b/lib/pages/home/home.dart index efdca4f7..eede8dfd 100644 --- a/lib/pages/home/home.dart +++ b/lib/pages/home/home.dart @@ -34,7 +34,7 @@ class HomePage extends HookConsumerWidget { return SafeArea( bottom: false, child: Scaffold( - appBar: kIsMobile || kIsMacOS ? null : const PageWindowTitleBar(), + appBar: kIsMobile || kIsMacOS ? null : const TitleBar(), body: CustomScrollView( controller: controller, slivers: [ diff --git a/lib/pages/lastfm_login/lastfm_login.dart b/lib/pages/lastfm_login/lastfm_login.dart index 8107e627..2611d771 100644 --- a/lib/pages/lastfm_login/lastfm_login.dart +++ b/lib/pages/lastfm_login/lastfm_login.dart @@ -27,7 +27,7 @@ class LastFMLoginPage extends HookConsumerWidget { final isLoading = useState(false); return Scaffold( - appBar: const PageWindowTitleBar(leading: BackButton()), + appBar: const TitleBar(leading: [BackButton()]), body: Center( child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 400), diff --git a/lib/pages/library/library.dart b/lib/pages/library/library.dart index 02152f3d..dbab9a87 100644 --- a/lib/pages/library/library.dart +++ b/lib/pages/library/library.dart @@ -37,19 +37,21 @@ class LibraryPage extends HookConsumerWidget { bottom: false, child: Scaffold( headers: [ - PageWindowTitleBar( - leading: TabList( - index: index.value, - children: [ - for (final child in children) - TabButton( - child: child, - onPressed: () { - index.value = children.indexOf(child); - }, - ), - ], - ), + TitleBar( + leading: [ + TabList( + index: index.value, + children: [ + for (final child in children) + TabButton( + child: child, + onPressed: () { + index.value = children.indexOf(child); + }, + ), + ], + ) + ], ) ], child: IndexedStack( @@ -60,11 +62,6 @@ class LibraryPage extends HookConsumerWidget { UserDownloads(), UserArtists(), UserAlbums(), - // Text("UserPlaylists()"), - // Text("UserLocalTracks()"), - // Text("UserDownloads()"), - // Text("UserArtists()"), - // Text("UserAlbums()"), ], ), ), diff --git a/lib/pages/library/local_folder.dart b/lib/pages/library/local_folder.dart index c2848b24..478eac5e 100644 --- a/lib/pages/library/local_folder.dart +++ b/lib/pages/library/local_folder.dart @@ -93,9 +93,8 @@ class LocalLibraryPage extends HookConsumerWidget { return SafeArea( bottom: false, child: Scaffold( - appBar: PageWindowTitleBar( - leading: const BackButton(), - centerTitle: true, + appBar: TitleBar( + leading: const [BackButton()], title: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, @@ -120,7 +119,7 @@ class LocalLibraryPage extends HookConsumerWidget { ], ), backgroundColor: Colors.transparent, - actions: [ + trailing: [ if (isCache) ...[ IconButton( iconSize: 16, diff --git a/lib/pages/library/playlist_generate/playlist_generate.dart b/lib/pages/library/playlist_generate/playlist_generate.dart index b62013c5..63565362 100644 --- a/lib/pages/library/playlist_generate/playlist_generate.dart +++ b/lib/pages/library/playlist_generate/playlist_generate.dart @@ -231,10 +231,9 @@ class PlaylistGeneratorPage extends HookConsumerWidget { final controller = useScrollController(); return Scaffold( - appBar: PageWindowTitleBar( - leading: const BackButton(), + appBar: TitleBar( + leading: const [BackButton()], title: Text(context.l10n.generate_playlist), - centerTitle: true, ), body: Scrollbar( controller: controller, diff --git a/lib/pages/library/playlist_generate/playlist_generate_result.dart b/lib/pages/library/playlist_generate/playlist_generate_result.dart index 3bdc3b52..f44cbee7 100644 --- a/lib/pages/library/playlist_generate/playlist_generate_result.dart +++ b/lib/pages/library/playlist_generate/playlist_generate_result.dart @@ -48,7 +48,7 @@ class PlaylistGenerateResultPage extends HookConsumerWidget { (generatedPlaylist.asData?.value.length ?? 0); return Scaffold( - appBar: const PageWindowTitleBar(leading: BackButton()), + appBar: const TitleBar(leading: [BackButton()]), body: generatedPlaylist.isLoading ? Center( child: Column( diff --git a/lib/pages/lyrics/lyrics.dart b/lib/pages/lyrics/lyrics.dart index 0f4f9473..48005f6e 100644 --- a/lib/pages/lyrics/lyrics.dart +++ b/lib/pages/lyrics/lyrics.dart @@ -146,7 +146,7 @@ class LyricsPage extends HookConsumerWidget { child: Scaffold( extendBodyBehindAppBar: true, appBar: !kIsMacOS - ? PageWindowTitleBar( + ? TitleBar( backgroundColor: Colors.transparent, title: tabbar, ) diff --git a/lib/pages/mobile_login/mobile_login.dart b/lib/pages/mobile_login/mobile_login.dart index c45c2184..fa818dc8 100644 --- a/lib/pages/mobile_login/mobile_login.dart +++ b/lib/pages/mobile_login/mobile_login.dart @@ -24,8 +24,8 @@ class WebViewLogin extends HookConsumerWidget { } return Scaffold( - appBar: const PageWindowTitleBar( - leading: BackButton(color: Colors.white), + appBar: const TitleBar( + leading: [BackButton(color: Colors.white)], backgroundColor: Colors.transparent, ), extendBodyBehindAppBar: true, diff --git a/lib/pages/profile/profile.dart b/lib/pages/profile/profile.dart index 9e51793d..b4d72b53 100644 --- a/lib/pages/profile/profile.dart +++ b/lib/pages/profile/profile.dart @@ -42,11 +42,9 @@ class ProfilePage extends HookConsumerWidget { return SafeArea( child: Scaffold( - appBar: PageWindowTitleBar( + appBar: TitleBar( title: Text(context.l10n.profile), - titleSpacing: 0, automaticallyImplyLeading: true, - centerTitle: false, ), body: Skeletonizer( enabled: me.isLoading, diff --git a/lib/pages/search/search.dart b/lib/pages/search/search.dart index d5de12f0..c413df68 100644 --- a/lib/pages/search/search.dart +++ b/lib/pages/search/search.dart @@ -88,7 +88,7 @@ class SearchPage extends HookConsumerWidget { bottom: false, child: Scaffold( appBar: kIsDesktop && !kIsMacOS - ? const PageWindowTitleBar(automaticallyImplyLeading: true) + ? const TitleBar(automaticallyImplyLeading: true) : null, body: auth.asData?.value == null ? const AnonymousFallback() diff --git a/lib/pages/settings/about.dart b/lib/pages/settings/about.dart index 1357c52f..491cdcf6 100644 --- a/lib/pages/settings/about.dart +++ b/lib/pages/settings/about.dart @@ -29,8 +29,8 @@ class AboutSpotube extends HookConsumerWidget { const colon = Text(":"); return Scaffold( - appBar: PageWindowTitleBar( - leading: const BackButton(), + appBar: TitleBar( + leading: const [BackButton()], title: Text(context.l10n.about_spotube), ), body: SingleChildScrollView( diff --git a/lib/pages/settings/blacklist.dart b/lib/pages/settings/blacklist.dart index 1f018dab..57a8b6fe 100644 --- a/lib/pages/settings/blacklist.dart +++ b/lib/pages/settings/blacklist.dart @@ -44,10 +44,9 @@ class BlackListPage extends HookConsumerWidget { ); return Scaffold( - appBar: PageWindowTitleBar( + appBar: TitleBar( title: Text(context.l10n.blacklist), - centerTitle: true, - leading: const BackButton(), + leading: const [BackButton()], ), body: Column( mainAxisSize: MainAxisSize.min, diff --git a/lib/pages/settings/logs.dart b/lib/pages/settings/logs.dart index 6ccbe32f..0f1260aa 100644 --- a/lib/pages/settings/logs.dart +++ b/lib/pages/settings/logs.dart @@ -21,10 +21,10 @@ class LogsPage extends HookConsumerWidget { final logsQuery = ref.watch(logsProvider); return Scaffold( - appBar: PageWindowTitleBar( + appBar: TitleBar( title: Text(context.l10n.logs), - leading: const BackButton(), - actions: [ + leading: const [BackButton()], + trailing: [ IconButton( icon: const Icon(SpotubeIcons.clipboard), iconSize: 16, diff --git a/lib/pages/settings/settings.dart b/lib/pages/settings/settings.dart index 8bce4bcf..a7355812 100644 --- a/lib/pages/settings/settings.dart +++ b/lib/pages/settings/settings.dart @@ -28,9 +28,8 @@ class SettingsPage extends HookConsumerWidget { return SafeArea( bottom: false, child: Scaffold( - appBar: PageWindowTitleBar( + appBar: TitleBar( title: Text(context.l10n.settings), - centerTitle: true, automaticallyImplyLeading: true, ), body: Scrollbar( diff --git a/lib/pages/stats/albums/albums.dart b/lib/pages/stats/albums/albums.dart index e14a2f32..b424cd70 100644 --- a/lib/pages/stats/albums/albums.dart +++ b/lib/pages/stats/albums/albums.dart @@ -25,9 +25,8 @@ class StatsAlbumsPage extends HookConsumerWidget { final albumsData = topAlbums.asData?.value.items ?? []; return Scaffold( - appBar: PageWindowTitleBar( + appBar: TitleBar( automaticallyImplyLeading: true, - centerTitle: false, title: Text(context.l10n.albums), ), body: Skeletonizer( diff --git a/lib/pages/stats/artists/artists.dart b/lib/pages/stats/artists/artists.dart index 436bbb57..468ddabb 100644 --- a/lib/pages/stats/artists/artists.dart +++ b/lib/pages/stats/artists/artists.dart @@ -28,9 +28,8 @@ class StatsArtistsPage extends HookConsumerWidget { () => topTracks.asData?.value.artists ?? [], [topTracks.asData?.value]); return Scaffold( - appBar: PageWindowTitleBar( + appBar: TitleBar( automaticallyImplyLeading: true, - centerTitle: false, title: Text(context.l10n.artists), ), body: Skeletonizer( diff --git a/lib/pages/stats/fees/fees.dart b/lib/pages/stats/fees/fees.dart index da62fb30..1bbcb103 100644 --- a/lib/pages/stats/fees/fees.dart +++ b/lib/pages/stats/fees/fees.dart @@ -41,9 +41,8 @@ class StatsStreamFeesPage extends HookConsumerWidget { ); return Scaffold( - appBar: PageWindowTitleBar( + appBar: TitleBar( automaticallyImplyLeading: true, - centerTitle: false, title: Text(context.l10n.streaming_fees_hypothetical), ), body: CustomScrollView( diff --git a/lib/pages/stats/minutes/minutes.dart b/lib/pages/stats/minutes/minutes.dart index 3ad0984b..f6cfafca 100644 --- a/lib/pages/stats/minutes/minutes.dart +++ b/lib/pages/stats/minutes/minutes.dart @@ -28,9 +28,8 @@ class StatsMinutesPage extends HookConsumerWidget { final tracksData = topTracks.asData?.value.items ?? []; return Scaffold( - appBar: PageWindowTitleBar( + appBar: TitleBar( title: Text(context.l10n.minutes_listened), - centerTitle: false, automaticallyImplyLeading: true, ), body: Skeletonizer( diff --git a/lib/pages/stats/playlists/playlists.dart b/lib/pages/stats/playlists/playlists.dart index 4e83b0a2..53885570 100644 --- a/lib/pages/stats/playlists/playlists.dart +++ b/lib/pages/stats/playlists/playlists.dart @@ -26,9 +26,8 @@ class StatsPlaylistsPage extends HookConsumerWidget { final playlistsData = topPlaylists.asData?.value.items ?? []; return Scaffold( - appBar: PageWindowTitleBar( + appBar: TitleBar( automaticallyImplyLeading: true, - centerTitle: false, title: Text(context.l10n.playlists), ), body: Skeletonizer( diff --git a/lib/pages/stats/stats.dart b/lib/pages/stats/stats.dart index b2dc03c2..9c35df63 100644 --- a/lib/pages/stats/stats.dart +++ b/lib/pages/stats/stats.dart @@ -16,7 +16,7 @@ class StatsPage extends HookConsumerWidget { return SafeArea( bottom: false, child: Scaffold( - appBar: kIsMacOS || kIsMobile ? null : const PageWindowTitleBar(), + appBar: kIsMacOS || kIsMobile ? null : const TitleBar(), body: CustomScrollView( slivers: [ if (kIsMacOS) const SliverGap(20), diff --git a/lib/pages/stats/streams/streams.dart b/lib/pages/stats/streams/streams.dart index 059366e0..b835b3a6 100644 --- a/lib/pages/stats/streams/streams.dart +++ b/lib/pages/stats/streams/streams.dart @@ -28,9 +28,8 @@ class StatsStreamsPage extends HookConsumerWidget { final tracksData = topTracks.asData?.value.items ?? []; return Scaffold( - appBar: PageWindowTitleBar( + appBar: TitleBar( title: Text(context.l10n.streamed_songs), - centerTitle: false, automaticallyImplyLeading: true, ), body: Skeletonizer( diff --git a/lib/pages/track/track.dart b/lib/pages/track/track.dart index 84c53b74..30f2e998 100644 --- a/lib/pages/track/track.dart +++ b/lib/pages/track/track.dart @@ -53,7 +53,7 @@ class TrackPage extends HookConsumerWidget { } return Scaffold( - appBar: const PageWindowTitleBar( + appBar: const TitleBar( automaticallyImplyLeading: true, backgroundColor: Colors.transparent, ), From 2925dd6748302152d3819224a7d0164f78c94165 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 21 Dec 2024 18:23:45 +0600 Subject: [PATCH 017/112] refactor: library page filter fields and update home sections --- lib/components/button/back_button.dart | 14 ++ .../horizontal_playbutton_card_view.dart | 7 +- lib/components/themed_button_tab_bar.dart | 50 ----- lib/modules/home/sections/featured.dart | 2 +- lib/modules/home/sections/feed.dart | 8 +- lib/modules/home/sections/friends.dart | 5 +- .../home/sections/friends/friend_item.dart | 27 +-- lib/modules/home/sections/genres.dart | 88 ++++---- lib/modules/home/sections/made_for_user.dart | 2 +- lib/modules/home/sections/new_releases.dart | 2 +- lib/modules/home/sections/recent.dart | 2 +- lib/modules/library/user_albums.dart | 18 +- lib/modules/library/user_artists.dart | 18 +- lib/modules/library/user_playlists.dart | 25 ++- lib/modules/root/sidebar.dart | 6 +- lib/modules/stats/top/top.dart | 3 +- lib/pages/home/home.dart | 15 +- lib/pages/lyrics/lyrics.dart | 211 +++++++++--------- lib/pages/search/search.dart | 187 +++++++--------- 19 files changed, 313 insertions(+), 377 deletions(-) create mode 100644 lib/components/button/back_button.dart delete mode 100644 lib/components/themed_button_tab_bar.dart diff --git a/lib/components/button/back_button.dart b/lib/components/button/back_button.dart new file mode 100644 index 00000000..784f8e6b --- /dev/null +++ b/lib/components/button/back_button.dart @@ -0,0 +1,14 @@ +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:spotube/collections/spotube_icons.dart'; + +class BackButton extends StatelessWidget { + const BackButton({super.key}); + + @override + Widget build(BuildContext context) { + return IconButton.ghost( + icon: const Icon(SpotubeIcons.angleLeft), + onPressed: () => Navigator.of(context).pop(), + ); + } +} diff --git a/lib/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart b/lib/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart index 1093fff0..f41e0709 100644 --- a/lib/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart +++ b/lib/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart @@ -1,8 +1,8 @@ import 'dart:ui'; -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:gap/gap.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/collections/fake.dart'; @@ -37,7 +37,6 @@ class HorizontalPlaybuttonCardView extends HookWidget { @override Widget build(BuildContext context) { - final ThemeData(:textTheme) = Theme.of(context); final scrollController = useScrollController(); final height = useBreakpointValue( xs: 226, @@ -56,7 +55,7 @@ class HorizontalPlaybuttonCardView extends HookWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ DefaultTextStyle( - style: textTheme.titleMedium!, + style: context.theme.typography.h4, child: title, ), if (titleTrailing != null) titleTrailing!, diff --git a/lib/components/themed_button_tab_bar.dart b/lib/components/themed_button_tab_bar.dart deleted file mode 100644 index c245e5f4..00000000 --- a/lib/components/themed_button_tab_bar.dart +++ /dev/null @@ -1,50 +0,0 @@ -import 'package:buttons_tabbar/buttons_tabbar.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:spotube/hooks/utils/use_brightness_value.dart'; - -class ThemedButtonsTabBar extends HookWidget implements PreferredSizeWidget { - final List tabs; - final TabController? controller; - const ThemedButtonsTabBar({super.key, required this.tabs, this.controller}); - - @override - Widget build(BuildContext context) { - final theme = Theme.of(context); - final bgColor = useBrightnessValue( - theme.colorScheme.primaryContainer, - Color.lerp(theme.colorScheme.primary, Colors.black, 0.7)!, - ); - - return Padding( - padding: const EdgeInsets.only( - top: 8, - bottom: 8, - ), - child: ButtonsTabBar( - controller: controller, - radius: 100, - decoration: BoxDecoration( - color: bgColor, - borderRadius: BorderRadius.circular(15), - ), - labelStyle: theme.textTheme.labelLarge?.copyWith( - color: theme.colorScheme.primary, - fontWeight: FontWeight.bold, - ), - borderWidth: 0, - unselectedDecoration: BoxDecoration( - color: theme.colorScheme.surface, - borderRadius: BorderRadius.circular(15), - ), - unselectedLabelStyle: theme.textTheme.labelLarge?.copyWith( - color: theme.colorScheme.primary, - ), - tabs: tabs, - ), - ); - } - - @override - Size get preferredSize => const Size.fromHeight(50); -} diff --git a/lib/modules/home/sections/featured.dart b/lib/modules/home/sections/featured.dart index 4f30c342..9ccc8908 100644 --- a/lib/modules/home/sections/featured.dart +++ b/lib/modules/home/sections/featured.dart @@ -1,5 +1,5 @@ -import 'package:flutter/material.dart' hide Page; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart'; diff --git a/lib/modules/home/sections/feed.dart b/lib/modules/home/sections/feed.dart index 8685fe19..bce2ea5b 100644 --- a/lib/modules/home/sections/feed.dart +++ b/lib/modules/home/sections/feed.dart @@ -1,5 +1,5 @@ -import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart'; import 'package:spotube/extensions/context.dart'; @@ -40,9 +40,9 @@ class HomePageFeedSection extends HookConsumerWidget { onFetchMore: () {}, titleTrailing: Directionality( textDirection: TextDirection.rtl, - child: TextButton.icon( - label: Text(context.l10n.browse_more), - icon: const Icon(SpotubeIcons.angleRight), + child: Button.link( + leading: const Icon(SpotubeIcons.angleRight), + child: Text(context.l10n.browse_more), onPressed: () => ServiceUtils.pushNamed( context, HomeFeedSectionPage.name, diff --git a/lib/modules/home/sections/friends.dart b/lib/modules/home/sections/friends.dart index 6f59c209..00f4a86a 100644 --- a/lib/modules/home/sections/friends.dart +++ b/lib/modules/home/sections/friends.dart @@ -1,8 +1,9 @@ import 'dart:ui'; -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotube/collections/fake.dart'; import 'package:spotube/modules/home/sections/friends/friend_item.dart'; @@ -75,7 +76,7 @@ class HomePageFriendsSection extends HookConsumerWidget { padding: const EdgeInsets.all(8.0), child: Text( context.l10n.friends, - style: Theme.of(context).textTheme.titleMedium, + style: context.theme.typography.h4, ), ), ), diff --git a/lib/modules/home/sections/friends/friend_item.dart b/lib/modules/home/sections/friends/friend_item.dart index 773a4a8c..42ec2909 100644 --- a/lib/modules/home/sections/friends/friend_item.dart +++ b/lib/modules/home/sections/friends/friend_item.dart @@ -1,8 +1,8 @@ import 'package:flutter/gestures.dart'; -import 'package:flutter/material.dart'; -import 'package:gap/gap.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/models/spotify_friends.dart'; @@ -20,27 +20,15 @@ class FriendItem extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final ThemeData( - textTheme: textTheme, - colorScheme: colorScheme, - ) = Theme.of(context); - final spotify = ref.watch(spotifyProvider); - return Container( + return Card( padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: colorScheme.surfaceContainerHighest.withOpacity(0.3), - borderRadius: BorderRadius.circular(15), - ), - constraints: const BoxConstraints( - minWidth: 300, - ), - height: 80, child: Row( children: [ - CircleAvatar( - backgroundImage: UniversalImage.imageProvider( + Avatar( + initials: Avatar.getInitials(friend.user.name), + provider: UniversalImage.imageProvider( friend.user.imageUrl, ), ), @@ -50,11 +38,10 @@ class FriendItem extends HookConsumerWidget { children: [ Text( friend.user.name, - style: textTheme.bodyLarge, + style: context.theme.typography.bold, ), RichText( text: TextSpan( - style: textTheme.bodySmall, children: [ TextSpan( text: friend.track.name, diff --git a/lib/modules/home/sections/genres.dart b/lib/modules/home/sections/genres.dart index 5f2dfa5e..574f3294 100644 --- a/lib/modules/home/sections/genres.dart +++ b/lib/modules/home/sections/genres.dart @@ -1,10 +1,10 @@ import 'dart:math'; -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:gap/gap.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/collections/fake.dart'; @@ -22,7 +22,6 @@ class HomeGenresSection extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final ThemeData(:textTheme, :colorScheme) = Theme.of(context); final mediaQuery = MediaQuery.of(context); final categoriesQuery = ref.watch(categoriesProvider); @@ -46,21 +45,18 @@ class HomeGenresSection extends HookConsumerWidget { children: [ Text( context.l10n.genres, - style: textTheme.headlineSmall, + style: context.theme.typography.h4, ), Directionality( textDirection: TextDirection.rtl, - child: TextButton.icon( + child: Button.link( onPressed: () { context.pushNamed(GenrePage.name); }, - icon: const Icon(SpotubeIcons.angleRight), - label: Text( + leading: const Icon(SpotubeIcons.angleRight), + child: Text( context.l10n.browse_all, - style: textTheme.bodyMedium?.copyWith( - color: colorScheme.secondary, - ), - ), + ).muted(), ), ), ], @@ -96,12 +92,12 @@ class HomeGenresSection extends HookConsumerWidget { final text = gradient.colors .take(2) .any((c) => c.computeLuminance() > 0.5) - ? Colors.grey[900] + ? Colors.gray[900] : Colors.white; return ( gradient: LinearGradient( colors: gradient.colors - .map((c) => c.withOpacity(0.8)) + .map((c) => c.withAlpha((0.8 * 255).ceil())) .toList(), ), textColor: text @@ -110,40 +106,42 @@ class HomeGenresSection extends HookConsumerWidget { [], ); - return InkWell( - onTap: () { - context.pushNamed( - GenrePlaylistsPage.name, - pathParameters: { - "categoryId": category.id!, - }, - extra: category, - ); - }, - borderRadius: BorderRadius.circular(8), - child: Ink( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - image: DecorationImage( - image: UniversalImage.imageProvider( - category.icons!.first.url!, - ), - fit: BoxFit.cover, - ), - ), - child: Ink( + return MouseRegion( + cursor: SystemMouseCursors.click, + child: GestureDetector( + onTap: () { + context.pushNamed( + GenrePlaylistsPage.name, + pathParameters: { + "categoryId": category.id!, + }, + extra: category, + ); + }, + child: Container( decoration: BoxDecoration( - borderRadius: BorderRadius.circular(5), - color: colorScheme.surfaceContainerHighest, - gradient: categoriesQuery.isLoading ? null : gradient, + borderRadius: BorderRadius.circular(8), + image: DecorationImage( + image: UniversalImage.imageProvider( + category.icons!.first.url!, + ), + fit: BoxFit.cover, + ), ), - padding: const EdgeInsets.symmetric(horizontal: 16), - child: Align( - alignment: Alignment.centerLeft, - child: Text( - category.name!, - style: textTheme.titleMedium - ?.copyWith(color: textColor), + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(5), + color: context.theme.colorScheme.muted, + gradient: + categoriesQuery.isLoading ? null : gradient, + ), + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Align( + alignment: Alignment.centerLeft, + child: Text( + category.name!, + style: context.theme.typography.large, + ), ), ), ), diff --git a/lib/modules/home/sections/made_for_user.dart b/lib/modules/home/sections/made_for_user.dart index 1b9854d3..4fd025d5 100644 --- a/lib/modules/home/sections/made_for_user.dart +++ b/lib/modules/home/sections/made_for_user.dart @@ -1,5 +1,5 @@ -import 'package:flutter/widgets.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart'; import 'package:spotube/provider/spotify/spotify.dart'; diff --git a/lib/modules/home/sections/new_releases.dart b/lib/modules/home/sections/new_releases.dart index e2b32741..2ebbbee0 100644 --- a/lib/modules/home/sections/new_releases.dart +++ b/lib/modules/home/sections/new_releases.dart @@ -1,5 +1,5 @@ -import 'package:flutter/material.dart' hide Page; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart'; import 'package:spotube/extensions/context.dart'; diff --git a/lib/modules/home/sections/recent.dart b/lib/modules/home/sections/recent.dart index 43c0459d..5420ad55 100644 --- a/lib/modules/home/sections/recent.dart +++ b/lib/modules/home/sections/recent.dart @@ -1,5 +1,5 @@ -import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotube/collections/fake.dart'; import 'package:spotube/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart'; diff --git a/lib/modules/library/user_albums.dart b/lib/modules/library/user_albums.dart index 37fca7c0..4a22bbea 100644 --- a/lib/modules/library/user_albums.dart +++ b/lib/modules/library/user_albums.dart @@ -1,8 +1,8 @@ -import 'package:flutter/material.dart' hide Image; +import 'package:shadcn_flutter/shadcn_flutter.dart' hide Image; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:collection/collection.dart'; import 'package:fuzzywuzzy/fuzzywuzzy.dart'; -import 'package:gap/gap.dart'; + import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotube/collections/fake.dart'; @@ -52,7 +52,7 @@ class UserAlbums extends HookConsumerWidget { return SafeArea( child: Scaffold( - body: RefreshIndicator( + child: RefreshTrigger( onRefresh: () async { ref.invalidate(favoriteAlbumsProvider); }, @@ -62,13 +62,17 @@ class UserAlbums extends HookConsumerWidget { controller: controller, slivers: [ SliverAppBar( + backgroundColor: Theme.of(context).colorScheme.background, floating: true, flexibleSpace: Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: SearchBar( - onChanged: (value) => searchText.value = value, - leading: const Icon(SpotubeIcons.filter), - hintText: context.l10n.filter_albums, + child: SizedBox( + height: 48, + child: TextField( + onChanged: (value) => searchText.value = value, + leading: const Icon(SpotubeIcons.filter), + placeholder: Text(context.l10n.filter_artist), + ), ), ), ), diff --git a/lib/modules/library/user_artists.dart b/lib/modules/library/user_artists.dart index 7968d91c..83a321fc 100644 --- a/lib/modules/library/user_artists.dart +++ b/lib/modules/library/user_artists.dart @@ -1,9 +1,9 @@ -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:collection/collection.dart'; import 'package:fuzzywuzzy/fuzzywuzzy.dart'; -import 'package:gap/gap.dart'; + import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotube/collections/fake.dart'; @@ -54,7 +54,7 @@ class UserArtists extends HookConsumerWidget { return SafeArea( child: Scaffold( - body: RefreshIndicator( + child: RefreshTrigger( onRefresh: () async { ref.invalidate(followedArtistsProvider); }, @@ -66,11 +66,15 @@ class UserArtists extends HookConsumerWidget { controller: controller, slivers: [ SliverAppBar( + backgroundColor: Theme.of(context).colorScheme.background, floating: true, - flexibleSpace: SearchBar( - onChanged: (value) => searchText.value = value, - leading: const Icon(SpotubeIcons.filter), - hintText: context.l10n.filter_artist, + flexibleSpace: SizedBox( + height: 48, + child: TextField( + onChanged: (value) => searchText.value = value, + leading: const Icon(SpotubeIcons.filter), + placeholder: Text(context.l10n.filter_artist), + ), ), ), const SliverGap(10), diff --git a/lib/modules/library/user_playlists.dart b/lib/modules/library/user_playlists.dart index 577f9655..50595298 100644 --- a/lib/modules/library/user_playlists.dart +++ b/lib/modules/library/user_playlists.dart @@ -1,9 +1,10 @@ -import 'package:flutter/material.dart' hide Image; +import 'package:flutter/material.dart' show kToolbarHeight; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:fuzzywuzzy/fuzzywuzzy.dart'; import 'package:collection/collection.dart'; -import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart' hide Image; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotify/spotify.dart'; @@ -79,7 +80,7 @@ class UserPlaylists extends HookConsumerWidget { return const AnonymousFallback(); } - return RefreshIndicator( + return RefreshTrigger( onRefresh: () async { ref.invalidate(favoritePlaylistsProvider); }, @@ -91,11 +92,13 @@ class UserPlaylists extends HookConsumerWidget { slivers: [ SliverAppBar( floating: true, - flexibleSpace: Padding( + backgroundColor: context.theme.colorScheme.background, + flexibleSpace: Container( padding: const EdgeInsets.symmetric(horizontal: 8), - child: SearchBar( + height: 48, + child: TextField( onChanged: (value) => searchText.value = value, - hintText: context.l10n.filter_playlists, + placeholder: Text(context.l10n.filter_playlists), leading: const Icon(SpotubeIcons.filter), ), ), @@ -107,12 +110,14 @@ class UserPlaylists extends HookConsumerWidget { const Gap(10), const PlaylistCreateDialogButton(), const Gap(10), - ElevatedButton.icon( - icon: const Icon(SpotubeIcons.magic), - label: Text(context.l10n.generate_playlist), + Button.primary( + leading: const Icon(SpotubeIcons.magic), + child: Text(context.l10n.generate_playlist), onPressed: () { ServiceUtils.pushNamed( - context, PlaylistGeneratorPage.name); + context, + PlaylistGeneratorPage.name, + ); }, ), const Gap(10), diff --git a/lib/modules/root/sidebar.dart b/lib/modules/root/sidebar.dart index f045c23d..1afa85c5 100644 --- a/lib/modules/root/sidebar.dart +++ b/lib/modules/root/sidebar.dart @@ -104,7 +104,7 @@ class Sidebar extends HookConsumerWidget { index: selectedIndex, onSelected: (index) { final tile = sidebarTileList[index]; - ServiceUtils.pushNamed(context, tile.name); + context.goNamed(tile.name); }, children: navigationButtons, ) @@ -113,13 +113,13 @@ class Sidebar extends HookConsumerWidget { index: selectedIndex, onSelected: (index) { final tile = sidebarTileList[index]; - ServiceUtils.pushNamed(context, tile.name); + context.goNamed(tile.name); }, children: navigationButtons, ), ), const SidebarFooter(), - const Gap(130) + if (mediaQuery.lgAndUp) const Gap(130) else const Gap(65), ], ), const VerticalDivider(), diff --git a/lib/modules/stats/top/top.dart b/lib/modules/stats/top/top.dart index 643064aa..5c2cfbf9 100644 --- a/lib/modules/stats/top/top.dart +++ b/lib/modules/stats/top/top.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:spotube/components/themed_button_tab_bar.dart'; import 'package:spotube/modules/stats/top/albums.dart'; import 'package:spotube/modules/stats/top/artists.dart'; import 'package:spotube/modules/stats/top/tracks.dart'; @@ -23,7 +22,7 @@ class StatsPageTopSection extends HookConsumerWidget { slivers: [ SliverAppBar( floating: true, - flexibleSpace: ThemedButtonsTabBar( + flexibleSpace: TabBar( controller: tabController, tabs: [ Tab( diff --git a/lib/pages/home/home.dart b/lib/pages/home/home.dart index eede8dfd..2dfbc0f3 100644 --- a/lib/pages/home/home.dart +++ b/lib/pages/home/home.dart @@ -1,7 +1,8 @@ -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:gap/gap.dart'; + import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/collections/assets.gen.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/models/database/database.dart'; @@ -34,18 +35,22 @@ class HomePage extends HookConsumerWidget { return SafeArea( bottom: false, child: Scaffold( - appBar: kIsMobile || kIsMacOS ? null : const TitleBar(), - body: CustomScrollView( + headers: [ + if (kIsWindows || kIsLinux) const TitleBar(), + ], + child: CustomScrollView( controller: controller, slivers: [ if (mediaQuery.smAndDown || layoutMode == LayoutMode.compact) SliverAppBar( floating: true, title: Assets.spotubeLogoPng.image(height: 45), + backgroundColor: context.theme.colorScheme.background, + foregroundColor: context.theme.colorScheme.foreground, actions: [ const ConnectDeviceButton(), const Gap(10), - IconButton( + IconButton.ghost( icon: const Icon(SpotubeIcons.settings, size: 20), onPressed: () { ServiceUtils.pushNamed(context, SettingsPage.name); diff --git a/lib/pages/lyrics/lyrics.dart b/lib/pages/lyrics/lyrics.dart index 48005f6e..17e552e6 100644 --- a/lib/pages/lyrics/lyrics.dart +++ b/lib/pages/lyrics/lyrics.dart @@ -1,14 +1,12 @@ import 'dart:ui'; -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/components/image/universal_image.dart'; -import 'package:spotube/components/themed_button_tab_bar.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; @@ -39,6 +37,7 @@ class LyricsPage extends HookConsumerWidget { final palette = usePaletteColor(albumArt, ref); final mediaQuery = MediaQuery.of(context); final route = ModalRoute.of(context); + final selectedIndex = useState(0); final resetStatusBar = useCustomStatusBarColor( palette.color, @@ -46,134 +45,134 @@ class LyricsPage extends HookConsumerWidget { noSetBGColor: true, ); - PreferredSizeWidget tabbar = ThemedButtonsTabBar( - tabs: [ - Tab(text: " ${context.l10n.synced} "), - Tab(text: " ${context.l10n.plain} "), - ], + Widget tabbar = Padding( + padding: const EdgeInsets.all(10), + child: Opacity( + opacity: 0.8, + child: Tabs( + index: selectedIndex.value, + onChanged: (index) => selectedIndex.value = index, + tabs: [ + Text(context.l10n.synced), + Text(context.l10n.plain), + ], + ), + ), ); - tabbar = PreferredSize( - preferredSize: tabbar.preferredSize, - child: Row( - children: [ - tabbar, - const Spacer(), - Consumer( - builder: (context, ref, child) { - final playback = ref.watch(audioPlayerProvider); - final lyric = - ref.watch(syncedLyricsProvider(playback.activeTrack)); - final providerName = lyric.asData?.value.provider; + tabbar = Row( + children: [ + tabbar, + const Spacer(), + Consumer( + builder: (context, ref, child) { + final playback = ref.watch(audioPlayerProvider); + final lyric = ref.watch(syncedLyricsProvider(playback.activeTrack)); + final providerName = lyric.asData?.value.provider; - if (providerName == null) { - return const SizedBox.shrink(); - } + if (providerName == null) { + return const SizedBox.shrink(); + } - return Align( - alignment: Alignment.bottomRight, - child: Text(context.l10n.powered_by_provider(providerName)), - ); - }, - ), - const Gap(5), - ], - ), + return Align( + alignment: Alignment.bottomRight, + child: Text(context.l10n.powered_by_provider(providerName)), + ); + }, + ), + const Gap(5), + ], ); if (isModal) { return PopScope( canPop: true, onPopInvokedWithResult: (_, __) => resetStatusBar(), - child: DefaultTabController( - length: 2, - child: SafeArea( - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 15, sigmaY: 15), - child: Container( - clipBehavior: Clip.hardEdge, - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surface.withOpacity(.4), - borderRadius: const BorderRadius.only( - topLeft: Radius.circular(10), - topRight: Radius.circular(10), - ), + child: SafeArea( + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 15, sigmaY: 15), + child: Container( + clipBehavior: Clip.hardEdge, + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.background.withOpacity(.4), + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(10), + topRight: Radius.circular(10), ), - child: Column( - children: [ - const SizedBox(height: 5), - Container( - height: 7, - width: 150, - decoration: BoxDecoration( - color: palette.titleTextColor, - borderRadius: BorderRadius.circular(10), - ), + ), + child: Column( + children: [ + const SizedBox(height: 5), + Container( + height: 7, + width: 150, + decoration: BoxDecoration( + color: palette.titleTextColor, + borderRadius: BorderRadius.circular(10), ), - AppBar( - leadingWidth: double.infinity, - leading: tabbar, - backgroundColor: Colors.transparent, - automaticallyImplyLeading: false, - actions: [ - IconButton( - icon: const Icon(SpotubeIcons.minimize), - onPressed: () => Navigator.of(context).pop(), - ), - const SizedBox(width: 5), + ), + AppBar( + leading: [tabbar], + backgroundColor: Colors.transparent, + trailing: [ + IconButton.ghost( + icon: const Icon(SpotubeIcons.minimize), + onPressed: () => Navigator.of(context).pop(), + ), + const SizedBox(width: 5), + ], + ), + Expanded( + child: IndexedStack( + index: selectedIndex.value, + children: [ + SyncedLyrics(palette: palette, isModal: isModal), + PlainLyrics(palette: palette, isModal: isModal), ], ), - Expanded( - child: TabBarView( - children: [ - SyncedLyrics(palette: palette, isModal: isModal), - PlainLyrics(palette: palette, isModal: isModal), - ], - ), - ), - ], - ), + ), + ], ), ), ), ), ); } - return DefaultTabController( - length: 2, - child: SafeArea( - bottom: mediaQuery.mdAndUp, - child: Scaffold( - extendBodyBehindAppBar: true, - appBar: !kIsMacOS + return SafeArea( + bottom: mediaQuery.mdAndUp, + child: Scaffold( + floatingHeader: true, + headers: [ + !kIsMacOS ? TitleBar( backgroundColor: Colors.transparent, title: tabbar, ) - : tabbar, - body: Container( - clipBehavior: Clip.hardEdge, - decoration: BoxDecoration( - image: DecorationImage( - image: UniversalImage.imageProvider(albumArt), - fit: BoxFit.cover, - ), - borderRadius: const BorderRadius.only( - bottomLeft: Radius.circular(10), - ), + : tabbar + ], + child: Container( + clipBehavior: Clip.hardEdge, + decoration: BoxDecoration( + image: DecorationImage( + image: UniversalImage.imageProvider(albumArt), + fit: BoxFit.cover, ), - margin: const EdgeInsets.only(bottom: 10), - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5), - child: ColoredBox( - color: palette.color.withOpacity(.7), - child: SafeArea( - child: TabBarView( - children: [ - SyncedLyrics(palette: palette, isModal: isModal), - PlainLyrics(palette: palette, isModal: isModal), - ], - ), + borderRadius: const BorderRadius.only( + bottomLeft: Radius.circular(10), + ), + ), + margin: const EdgeInsets.only(bottom: 10), + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5), + child: ColoredBox( + color: palette.color.withOpacity(.7), + child: SafeArea( + child: IndexedStack( + index: selectedIndex.value, + children: [ + SyncedLyrics(palette: palette, isModal: isModal), + PlainLyrics(palette: palette, isModal: isModal), + ], ), ), ), diff --git a/lib/pages/search/search.dart b/lib/pages/search/search.dart index c413df68..ba5cce83 100644 --- a/lib/pages/search/search.dart +++ b/lib/pages/search/search.dart @@ -1,21 +1,17 @@ -import 'dart:async'; - -import 'package:collection/collection.dart'; -import 'package:flutter/material.dart' hide Page; -import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:fuzzywuzzy/fuzzywuzzy.dart'; -import 'package:gap/gap.dart'; -import 'package:go_router/go_router.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:flutter/services.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:fuzzywuzzy/fuzzywuzzy.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/inter_scrollbar/inter_scrollbar.dart'; import 'package:spotube/components/fallbacks/anonymous_fallback.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/hooks/utils/use_force_update.dart'; import 'package:spotube/pages/search/sections/albums.dart'; import 'package:spotube/pages/search/sections/artists.dart'; import 'package:spotube/pages/search/sections/playlists.dart'; @@ -23,7 +19,6 @@ import 'package:spotube/pages/search/sections/tracks.dart'; import 'package:spotube/provider/authentication/authentication.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:spotube/services/kv_store/kv_store.dart'; - import 'package:spotube/utils/platform.dart'; class SearchPage extends HookConsumerWidget { @@ -36,6 +31,7 @@ class SearchPage extends HookConsumerWidget { final theme = Theme.of(context); final searchTerm = ref.watch(searchTermStateProvider); final controller = useSearchController(); + final focusNode = useFocusNode(); final auth = ref.watch(authenticationProvider); final mediaQuery = MediaQuery.of(context); @@ -84,117 +80,92 @@ class SearchPage extends HookConsumerWidget { }, ); + void onSubmitted(String value) { + ref.read(searchTermStateProvider.notifier).state = value; + if (value.trim().isEmpty) { + return; + } + KVStoreService.setRecentSearches( + { + value, + ...KVStoreService.recentSearches, + }.toList(), + ); + } + return SafeArea( bottom: false, child: Scaffold( - appBar: kIsDesktop && !kIsMacOS - ? const TitleBar(automaticallyImplyLeading: true) - : null, - body: auth.asData?.value == null + headers: [ + if (kIsWindows || kIsLinux) + const TitleBar(automaticallyImplyLeading: true) + ], + child: auth.asData?.value == null ? const AnonymousFallback() : Column( children: [ Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ - if ((kIsMobile || kIsMacOS) && context.canPop()) - const BackButton() - else - const Gap(20), Expanded( child: Padding( - padding: const EdgeInsets.only( - right: 20, - top: 20, - bottom: 20, - ), - child: SearchAnchor( - searchController: controller, - viewBuilder: (_) => HookBuilder(builder: (context) { - final searchController = - useListenable(controller); - final update = useForceUpdate(); - final suggestions = searchController.text.isEmpty - ? KVStoreService.recentSearches - : KVStoreService.recentSearches - .where( - (s) => - weightedRatio( - s.toLowerCase(), - searchController.text - .toLowerCase(), - ) > - 50, - ) - .toList(); + padding: const EdgeInsets.all(20), + child: ListenableBuilder( + listenable: controller, + builder: (context, _) { + final suggestions = controller.text.isEmpty + ? KVStoreService.recentSearches + : KVStoreService.recentSearches + .where( + (s) => + weightedRatio( + s.toLowerCase(), + controller.text.toLowerCase(), + ) > + 50, + ) + .toList(); - return ListView.builder( - itemCount: suggestions.length, - itemBuilder: (context, index) { - final suggestion = suggestions[index]; + return KeyboardListener( + focusNode: focusNode, + autofocus: true, + onKeyEvent: (value) { + final isEnter = value.logicalKey == + LogicalKeyboardKey.enter; - return ListTile( - leading: const Icon(SpotubeIcons.history), - title: Text(suggestion), - trailing: IconButton( - icon: const Icon(SpotubeIcons.trash), + if (isEnter) { + onSubmitted(controller.text); + focusNode.unfocus(); + } + }, + child: AutoComplete( + autofocus: true, + controller: controller, + suggestions: suggestions, + leading: const Icon(SpotubeIcons.search), + textInputAction: TextInputAction.search, + placeholder: Text(context.l10n.search), + trailing: IconButton.ghost( + size: ButtonSize.small, + icon: const Icon(SpotubeIcons.close), onPressed: () { - KVStoreService.setRecentSearches( - KVStoreService.recentSearches - .where((s) => s != suggestion) - .toList(), - ); - update(); + controller.clear(); }, ), - onTap: () { - controller.closeView(suggestion); + onAcceptSuggestion: (index) { + controller.text = + KVStoreService.recentSearches[index]; ref - .read( - searchTermStateProvider.notifier) - .state = suggestion; + .read(searchTermStateProvider + .notifier) + .state = + KVStoreService.recentSearches[index]; }, - ); - }, - ); - }), - suggestionsBuilder: (context, controller) { - return []; - }, - viewOnSubmitted: (value) async { - controller.closeView(value); - Timer( - const Duration(milliseconds: 50), - () { - ref - .read(searchTermStateProvider.notifier) - .state = value; - if (value.trim().isEmpty) { - return; - } - KVStoreService.setRecentSearches( - { - value, - ...KVStoreService.recentSearches, - }.toList(), - ); - }, - ); - }, - builder: (context, controller) { - return SearchBar( - autoFocus: queries.none((s) => - s.asData?.value != null && - !s.hasError) && - !kIsMobile, - controller: controller, - leading: const Icon(SpotubeIcons.search), - hintText: "${context.l10n.search}...", - onTap: controller.openView, - onChanged: (_) => controller.openView(), - ); - }, - ), + onChanged: (value) {}, + onSubmitted: onSubmitted, + ), + ); + }), ), ), ], @@ -211,15 +182,15 @@ class SearchPage extends HookConsumerWidget { Icon( SpotubeIcons.web, size: 120, - color: theme.colorScheme.onSurface + color: theme.colorScheme.foreground .withOpacity(0.7), ), const SizedBox(height: 20), Text( context.l10n.search_to_get_results, - style: theme.textTheme.titleLarge?.copyWith( + style: theme.typography.h3.copyWith( fontWeight: FontWeight.w900, - color: theme.colorScheme.onSurface + color: theme.colorScheme.foreground .withOpacity(0.5), ), ), @@ -245,7 +216,7 @@ class SearchPage extends HookConsumerWidget { style: TextStyle( fontSize: 20, fontWeight: FontWeight.w900, - color: theme.colorScheme.onSurface + color: theme.colorScheme.foreground .withOpacity(0.7), ), ), From 418a0d29bda84b4a1479f47f2a87b7c8d3cde2e4 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 21 Dec 2024 21:12:49 +0600 Subject: [PATCH 018/112] refactor: artist card to use shadcn card --- lib/modules/artist/artist_card.dart | 137 +++++++++------------------- 1 file changed, 44 insertions(+), 93 deletions(-) diff --git a/lib/modules/artist/artist_card.dart b/lib/modules/artist/artist_card.dart index add2608d..57c955c7 100644 --- a/lib/modules/artist/artist_card.dart +++ b/lib/modules/artist/artist_card.dart @@ -1,14 +1,13 @@ import 'package:auto_size_text/auto_size_text.dart'; -import 'package:flutter/material.dart'; + import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:skeletonizer/skeletonizer.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; -import 'package:spotube/hooks/utils/use_breakpoint_value.dart'; -import 'package:spotube/hooks/utils/use_brightness_value.dart'; + import 'package:spotube/pages/artist/artist.dart'; import 'package:spotube/provider/blacklist_provider.dart'; import 'package:spotube/utils/service_utils.dart'; @@ -33,98 +32,50 @@ class ArtistCard extends HookConsumerWidget { ), ); - final radius = BorderRadius.circular(15); - - final double size = useBreakpointValue( - xs: 130, - sm: 130, - md: 150, - others: 170, - ); - - return Container( - width: size, - margin: const EdgeInsets.symmetric(vertical: 5), - child: Material( - shadowColor: theme.colorScheme.surface, - color: Color.lerp( - theme.colorScheme.surfaceContainerHighest, - theme.colorScheme.surface, - useBrightnessValue(.9, .7), - ), - elevation: 3, - shape: RoundedRectangleBorder( - borderRadius: radius, - side: isBlackListed == true - ? const BorderSide( - color: Colors.red, - width: 2, - ) - : BorderSide.none, - ), - child: InkWell( - onTap: () { - ServiceUtils.pushNamed( - context, - ArtistPage.name, - pathParameters: { - "id": artist.id!, - }, - ); + return SizedBox( + width: 180, + child: Button.card( + onPressed: () { + ServiceUtils.pushNamed( + context, + ArtistPage.name, + pathParameters: { + "id": artist.id!, }, - borderRadius: radius, - child: Padding( - padding: const EdgeInsets.all(12), - child: Column( - children: [ - Stack( - children: [ - ConstrainedBox( - constraints: BoxConstraints( - maxHeight: size, - ), - child: CircleAvatar( - backgroundImage: backgroundImage, - radius: size / 2, - ), - ), - Positioned( - right: 0, - child: Container( - padding: const EdgeInsets.symmetric( - horizontal: 10, - vertical: 5, - ), - decoration: BoxDecoration( - color: Colors.blue, - borderRadius: BorderRadius.circular(50)), - child: Skeleton.ignore( - child: Text( - context.l10n.artist, - style: const TextStyle( - color: Colors.white, - fontSize: 12, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - ), - ], - ), - const SizedBox(height: 10), - AutoSizeText( - artist.name!, - maxLines: 1, - textAlign: TextAlign.center, - overflow: TextOverflow.ellipsis, - style: theme.textTheme.bodyMedium?.copyWith( - fontWeight: FontWeight.bold, - ), + ); + }, + child: Column( + children: [ + Avatar( + initials: artist.name!.trim()[0].toUpperCase(), + provider: backgroundImage, + size: 130, + ), + const Gap(10), + AutoSizeText( + artist.name!, + maxLines: 2, + textAlign: TextAlign.center, + overflow: TextOverflow.ellipsis, + style: theme.typography.bold, + ), + const Spacer(), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + if (isBlackListed == true) ...[ + DestructiveBadge( + child: Text(context.l10n.blacklisted.toUpperCase()), ), + const Gap(5), ], - ), - )), + SecondaryBadge( + child: Text(context.l10n.artist.toUpperCase()), + ) + ], + ) + ], + ), ), ); } From 7ee071f2e312beaa3ee007119881bbd50e2f70ef Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 21 Dec 2024 21:40:34 +0600 Subject: [PATCH 019/112] refactor: connected device button --- lib/modules/connect/connect_device.dart | 126 ++++++------------- lib/modules/root/spotube_navigation_bar.dart | 4 +- lib/pages/library/library.dart | 34 ++--- 3 files changed, 56 insertions(+), 108 deletions(-) diff --git a/lib/modules/connect/connect_device.dart b/lib/modules/connect/connect_device.dart index f4888534..be9826a3 100644 --- a/lib/modules/connect/connect_device.dart +++ b/lib/modules/connect/connect_device.dart @@ -1,6 +1,5 @@ -import 'package:flutter/material.dart'; -import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/pages/connect/connect.dart'; @@ -14,110 +13,55 @@ class ConnectDeviceButton extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final ThemeData(:colorScheme) = Theme.of(context); - final pixelRatio = MediaQuery.of(context).devicePixelRatio; final connectClients = ref.watch(connectClientsProvider); + final hasServices = + connectClients.asData?.value.services.isNotEmpty == true; + if (_sidebar) { return SizedBox( width: double.infinity, - child: TextButton( + child: Button.primary( onPressed: () { ServiceUtils.pushNamed(context, ConnectPage.name); }, - style: FilledButton.styleFrom( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - padding: const EdgeInsets.all(5), - ), - child: Row( - children: [ - Text(context.l10n.devices), - if (connectClients.asData?.value.services.isNotEmpty == true) - Text( - " (${connectClients.asData?.value.services.length})", - ), - const Spacer(), - const Icon(SpotubeIcons.speaker), - const Gap(5), - ], + trailing: const Icon(SpotubeIcons.speaker), + child: Text( + "${context.l10n.devices}" + "${hasServices ? " (${connectClients.asData?.value.services.length})" : ""}", ), ), ); } - return SizedBox( - height: 40 * pixelRatio, - child: Stack( - alignment: Alignment.centerRight, - fit: StackFit.loose, - children: [ - Material( - type: MaterialType.transparency, - child: Center( - child: ClipRect( - clipBehavior: Clip.hardEdge, - child: InkWell( - onTap: () { - ServiceUtils.pushNamed(context, ConnectPage.name); - }, - borderRadius: BorderRadius.circular(50), - child: Ink( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(50), - color: colorScheme.primaryContainer, - ), - padding: - const EdgeInsets.symmetric(horizontal: 10, vertical: 5), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - if (connectClients.asData?.value.resolvedService != - null) ...[ - Container( - width: 7, - height: 7, - decoration: BoxDecoration( - color: Colors.greenAccent, - borderRadius: BorderRadius.circular(50), - ), - ), - const Gap(5), - ], - Text(context.l10n.devices), - if (connectClients.asData?.value.services.isNotEmpty == - true) - Text( - " (${connectClients.asData?.value.services.length})", - style: TextStyle( - color: colorScheme.onPrimaryContainer - .withOpacity(0.5), - ), - ), - const Gap(35), - ], - ), + return Row( + children: [ + SecondaryBadge( + onPressed: () { + ServiceUtils.pushNamed(context, ConnectPage.name); + }, + style: const ButtonStyle.secondary(size: ButtonSize(.8)), + leading: connectClients.asData?.value.resolvedService != null + ? const Center( + child: DotItem( + size: 6, + borderRadius: 10, + color: Colors.green, ), - ), - ), - ), + ) + : null, + child: Text( + "${context.l10n.devices}" + "${hasServices ? " (${connectClients.asData?.value.services.length})" : ""}", ), - Positioned( - right: -3, - child: IconButton.filled( - icon: const Icon(SpotubeIcons.speaker), - style: IconButton.styleFrom( - visualDensity: VisualDensity.standard, - foregroundColor: colorScheme.onPrimary, - ), - onPressed: () { - ServiceUtils.pushNamed(context, ConnectPage.name); - }, - ), - ), - ], - ), + ), + IconButton.primary( + icon: const Icon(SpotubeIcons.speaker), + onPressed: () { + ServiceUtils.pushNamed(context, ConnectPage.name); + }, + ) + ], ); } } diff --git a/lib/modules/root/spotube_navigation_bar.dart b/lib/modules/root/spotube_navigation_bar.dart index c2cf4b5a..fa585054 100644 --- a/lib/modules/root/spotube_navigation_bar.dart +++ b/lib/modules/root/spotube_navigation_bar.dart @@ -7,7 +7,6 @@ import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/side_bar_tiles.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/hooks/utils/use_brightness_value.dart'; import 'package:spotube/models/database/database.dart'; import 'package:spotube/provider/download_manager_provider.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; @@ -61,6 +60,9 @@ class SpotubeNavigationBar extends HookConsumerWidget { children: [ for (final tile in navbarTileList) NavigationButton( + style: const ButtonStyle.muted(density: ButtonDensity.icon), + selectedStyle: + const ButtonStyle.fixed(density: ButtonDensity.icon), child: Badge( isLabelVisible: tile.id == "library" && downloadCount > 0, label: Text(downloadCount.toString()), diff --git a/lib/pages/library/library.dart b/lib/pages/library/library.dart index dbab9a87..e107f413 100644 --- a/lib/pages/library/library.dart +++ b/lib/pages/library/library.dart @@ -11,6 +11,7 @@ import 'package:spotube/modules/library/user_downloads.dart'; import 'package:spotube/modules/library/user_playlists.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/download_manager_provider.dart'; +import 'package:spotube/utils/platform.dart'; class LibraryPage extends HookConsumerWidget { static const name = "library"; @@ -37,22 +38,23 @@ class LibraryPage extends HookConsumerWidget { bottom: false, child: Scaffold( headers: [ - TitleBar( - leading: [ - TabList( - index: index.value, - children: [ - for (final child in children) - TabButton( - child: child, - onPressed: () { - index.value = children.indexOf(child); - }, - ), - ], - ) - ], - ) + if (kIsWindows || kIsLinux) const TitleBar(), + SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: TabList( + index: index.value, + children: [ + for (final child in children) + TabButton( + child: child, + onPressed: () { + index.value = children.indexOf(child); + }, + ), + ], + ), + ), + const Gap(10), ], child: IndexedStack( index: index.value, From 2fefd65f5171735c8abab8b7181c8423472ab124 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 22 Dec 2024 11:25:01 +0600 Subject: [PATCH 020/112] refactor: settings using shadcn components --- lib/collections/spotube_icons.dart | 2 + .../adaptive/adaptive_select_tile.dart | 103 ++--- lib/components/button/back_button.dart | 1 + lib/components/playbutton_card.dart | 19 +- lib/components/titlebar/titlebar.dart | 5 +- lib/modules/player/player_queue.dart | 2 +- .../settings/section_card_with_heading.dart | 54 ++- lib/pages/search/search.dart | 21 +- lib/pages/settings/sections/about.dart | 23 +- lib/pages/settings/sections/accounts.dart | 38 +- lib/pages/settings/sections/appearance.dart | 47 +-- lib/pages/settings/sections/desktop.dart | 38 +- lib/pages/settings/sections/developers.dart | 3 +- lib/pages/settings/sections/downloads.dart | 7 +- .../settings/sections/language_region.dart | 10 +- lib/pages/settings/sections/playback.dart | 380 +++++++++--------- lib/pages/settings/settings.dart | 54 +-- macos/Runner/AppDelegate.swift | 4 + pubspec.lock | 4 +- pubspec.yaml | 2 +- 20 files changed, 421 insertions(+), 396 deletions(-) diff --git a/lib/collections/spotube_icons.dart b/lib/collections/spotube_icons.dart index a1c6d69f..ff7092e3 100644 --- a/lib/collections/spotube_icons.dart +++ b/lib/collections/spotube_icons.dart @@ -128,4 +128,6 @@ abstract class SpotubeIcons { static const export = Icons.file_open_outlined; static const delete = FeatherIcons.trash2; static const open = FeatherIcons.externalLink; + static const radioChecked = Icons.radio_button_on_rounded; + static const radioUnchecked = Icons.radio_button_off_rounded; } diff --git a/lib/components/adaptive/adaptive_select_tile.dart b/lib/components/adaptive/adaptive_select_tile.dart index 3f6d2700..40308711 100644 --- a/lib/components/adaptive/adaptive_select_tile.dart +++ b/lib/components/adaptive/adaptive_select_tile.dart @@ -1,5 +1,6 @@ -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart' show ListTile, ListTileControlAffinity; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/extensions/constrains.dart'; @@ -11,7 +12,7 @@ class AdaptiveSelectTile extends HookWidget { final T value; final ValueChanged? onChanged; - final List> options; + final List> options; /// Show the smaller value when the breakpoint is reached /// @@ -39,55 +40,25 @@ class AdaptiveSelectTile extends HookWidget { Widget build(BuildContext context) { final theme = Theme.of(context); final mediaQuery = MediaQuery.of(context); - final rawControl = DecoratedBox( - decoration: BoxDecoration( - color: theme.colorScheme.secondaryContainer, - borderRadius: BorderRadius.circular(10), - ), - child: DropdownButton( - items: options, - value: value, - onChanged: onChanged, - menuMaxHeight: mediaQuery.size.height * 0.6, - underline: const SizedBox.shrink(), - padding: const EdgeInsets.symmetric(horizontal: 10), - borderRadius: BorderRadius.circular(10), - icon: const Icon(SpotubeIcons.angleDown), - dropdownColor: theme.colorScheme.secondaryContainer, - ), - ); - final controlPlaceholder = useMemoized( - () => options - .firstWhere( - (element) => element.value == value, - orElse: () => DropdownMenuItem( - value: null, - child: Container(), - ), - ) - .child, - [value, options]); - final control = breakLayout ?? mediaQuery.mdAndUp - ? rawControl - : showValueWhenUnfolded - ? Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - border: Border.all( - color: theme.colorScheme.primary, - width: 2, - ), - borderRadius: BorderRadius.circular(10), - ), - child: DefaultTextStyle( - style: TextStyle( - color: theme.colorScheme.primary, - ), - child: controlPlaceholder, - ), - ) - : const SizedBox.shrink(); + Widget? control = Select( + itemBuilder: (context, item) { + return options.firstWhere((element) => element.value == item).child; + }, + value: value, + onChanged: onChanged, + children: options, + ); + + if (mediaQuery.smAndDown) { + if (showValueWhenUnfolded) { + control = OutlineBadge( + child: options.firstWhere((element) => element.value == value).child, + ); + } else { + control = null; + } + } return ListTile( title: title, @@ -104,20 +75,26 @@ class AdaptiveSelectTile extends HookWidget { showDialog( context: context, builder: (context) { - return SimpleDialog( - title: title, - children: [ - for (final option in options) - RadioListTile( - title: option.child, - value: option.value as T, - groupValue: value, - onChanged: (v) { - Navigator.pop(context); - onChanged?.call(v); + return AlertDialog( + content: ListView.builder( + shrinkWrap: true, + itemCount: options.length, + itemBuilder: (context, index) { + final item = options[index]; + + return ListTile( + iconColor: theme.colorScheme.primary, + leading: item.value == value + ? const Icon(SpotubeIcons.radioChecked) + : const Icon(SpotubeIcons.radioUnchecked), + title: item.child, + onTap: () { + onChanged?.call(item.value); + Navigator.of(context).pop(); }, - ), - ], + ); + }, + ), ); }, ); diff --git a/lib/components/button/back_button.dart b/lib/components/button/back_button.dart index 784f8e6b..41b7d527 100644 --- a/lib/components/button/back_button.dart +++ b/lib/components/button/back_button.dart @@ -7,6 +7,7 @@ class BackButton extends StatelessWidget { @override Widget build(BuildContext context) { return IconButton.ghost( + size: const ButtonSize(.9), icon: const Icon(SpotubeIcons.angleLeft), onPressed: () => Navigator.of(context).pop(), ); diff --git a/lib/components/playbutton_card.dart b/lib/components/playbutton_card.dart index f781066e..31143ae8 100644 --- a/lib/components/playbutton_card.dart +++ b/lib/components/playbutton_card.dart @@ -4,6 +4,7 @@ import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/extensions/string.dart'; +import 'package:spotube/utils/platform.dart'; class PlaybuttonCard extends HookWidget { final void Function()? onTap; @@ -55,10 +56,15 @@ class PlaybuttonCard extends HookWidget { AnimatedScale( curve: Curves.easeOutBack, duration: const Duration(milliseconds: 300), - scale: states.contains(WidgetState.hovered) ? 1 : 0.7, + scale: states.contains(WidgetState.hovered) || kIsMobile + ? 1 + : 0.7, child: AnimatedOpacity( duration: const Duration(milliseconds: 300), - opacity: states.contains(WidgetState.hovered) ? 1 : 0, + opacity: + states.contains(WidgetState.hovered) || kIsMobile + ? 1 + : 0, child: IconButton.secondary( icon: const Icon(SpotubeIcons.queueAdd), onPressed: onAddToQueuePressed, @@ -70,10 +76,15 @@ class PlaybuttonCard extends HookWidget { AnimatedScale( curve: Curves.easeOutBack, duration: const Duration(milliseconds: 150), - scale: states.contains(WidgetState.hovered) ? 1 : 0.7, + scale: states.contains(WidgetState.hovered) || kIsMobile + ? 1 + : 0.7, child: AnimatedOpacity( duration: const Duration(milliseconds: 150), - opacity: states.contains(WidgetState.hovered) ? 1 : 0, + opacity: + states.contains(WidgetState.hovered) || kIsMobile + ? 1 + : 0, child: IconButton.secondary( icon: const Icon(SpotubeIcons.play), onPressed: onPlaybuttonPressed, diff --git a/lib/components/titlebar/titlebar.dart b/lib/components/titlebar/titlebar.dart index 282a734d..5c3f7940 100644 --- a/lib/components/titlebar/titlebar.dart +++ b/lib/components/titlebar/titlebar.dart @@ -1,7 +1,6 @@ -import 'package:flutter/material.dart' hide AppBar; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:shadcn_flutter/shadcn_flutter.dart' - show AppBar, WidgetExtension; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:spotube/components/button/back_button.dart'; import 'package:spotube/components/titlebar/titlebar_buttons.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/utils/platform.dart'; diff --git a/lib/modules/player/player_queue.dart b/lib/modules/player/player_queue.dart index 49279d5c..0186d974 100644 --- a/lib/modules/player/player_queue.dart +++ b/lib/modules/player/player_queue.dart @@ -237,7 +237,7 @@ class PlayerQueue extends HookConsumerWidget { right: 20, bottom: 20, child: IconButton.secondary( - icon: const Icon(SpotubeIcons.open), + icon: const Icon(SpotubeIcons.angleDown), onPressed: () { controller.scrollToIndex( playlist.playlist.index, diff --git a/lib/modules/settings/section_card_with_heading.dart b/lib/modules/settings/section_card_with_heading.dart index 87060579..cd9428f0 100644 --- a/lib/modules/settings/section_card_with_heading.dart +++ b/lib/modules/settings/section_card_with_heading.dart @@ -1,4 +1,6 @@ -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart' show ListTileTheme, ListTileThemeData; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; class SectionCardWithHeading extends StatelessWidget { final String heading; @@ -11,27 +13,41 @@ class SectionCardWithHeading extends StatelessWidget { @override Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: Text( - heading, - style: Theme.of(context).textTheme.titleLarge?.copyWith( - fontWeight: FontWeight.w600, - ), + return ListTileTheme( + data: ListTileThemeData( + shape: RoundedRectangleBorder( + borderRadius: context.theme.borderRadiusLg, + side: BorderSide( + color: context.theme.colorScheme.border, + width: .5, ), ), - Padding( - padding: const EdgeInsets.all(8.0), - child: Card( - clipBehavior: Clip.antiAliasWithSaveLayer, - child: Column(mainAxisSize: MainAxisSize.min, children: children), + textColor: context.theme.colorScheme.foreground, + iconColor: context.theme.colorScheme.foreground, + selectedColor: context.theme.colorScheme.accent, + subtitleTextStyle: context.theme.typography.xSmall, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Text( + heading, + style: context.theme.typography.large, + ), ), - ), - ], + Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: children, + ).gap(8.0), + ), + ], + ), ); } } diff --git a/lib/pages/search/search.dart b/lib/pages/search/search.dart index ba5cce83..5c096a32 100644 --- a/lib/pages/search/search.dart +++ b/lib/pages/search/search.dart @@ -145,12 +145,21 @@ class SearchPage extends HookConsumerWidget { leading: const Icon(SpotubeIcons.search), textInputAction: TextInputAction.search, placeholder: Text(context.l10n.search), - trailing: IconButton.ghost( - size: ButtonSize.small, - icon: const Icon(SpotubeIcons.close), - onPressed: () { - controller.clear(); - }, + trailing: AnimatedCrossFade( + duration: + const Duration(milliseconds: 300), + crossFadeState: controller.text.isNotEmpty + ? CrossFadeState.showFirst + : CrossFadeState.showSecond, + firstChild: IconButton.ghost( + size: ButtonSize.small, + icon: const Icon(SpotubeIcons.close), + onPressed: () { + controller.clear(); + }, + ), + secondChild: + const SizedBox.square(dimension: 28), ), onAcceptSuggestion: (index) { controller.text = diff --git a/lib/pages/settings/sections/about.dart b/lib/pages/settings/sections/about.dart index a0a5bf30..5910fc1b 100644 --- a/lib/pages/settings/sections/about.dart +++ b/lib/pages/settings/sections/about.dart @@ -1,7 +1,9 @@ import 'package:auto_size_text/auto_size_text.dart'; -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart' show FilledButton, ButtonStyle, ListTile; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart' hide ButtonStyle; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/collections/env.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/modules/settings/section_card_with_heading.dart'; @@ -45,9 +47,13 @@ class SettingsAboutSection extends HookConsumerWidget { trailing: (context, update) => FilledButton( style: ButtonStyle( backgroundColor: WidgetStatePropertyAll(Colors.red[100]), - foregroundColor: - const WidgetStatePropertyAll(Colors.pinkAccent), + foregroundColor: const WidgetStatePropertyAll(Colors.pink), padding: const WidgetStatePropertyAll(EdgeInsets.all(15)), + shape: WidgetStatePropertyAll( + RoundedRectangleBorder( + borderRadius: context.theme.borderRadiusLg, + ), + ), ), onPressed: () { launchUrlString( @@ -66,11 +72,14 @@ class SettingsAboutSection extends HookConsumerWidget { ), ), if (Env.enableUpdateChecker) - SwitchListTile( - secondary: const Icon(SpotubeIcons.update), + ListTile( + leading: const Icon(SpotubeIcons.update), title: Text(context.l10n.check_for_updates), - value: preferences.checkUpdate, - onChanged: (checked) => preferencesNotifier.setCheckUpdate(checked), + trailing: Switch( + value: preferences.checkUpdate, + onChanged: (checked) => + preferencesNotifier.setCheckUpdate(checked), + ), ), ListTile( leading: const Icon(SpotubeIcons.info), diff --git a/lib/pages/settings/sections/accounts.dart b/lib/pages/settings/sections/accounts.dart index b9a26147..6132776c 100644 --- a/lib/pages/settings/sections/accounts.dart +++ b/lib/pages/settings/sections/accounts.dart @@ -1,7 +1,8 @@ import 'package:auto_size_text/auto_size_text.dart'; -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart' show ListTile; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/modules/settings/section_card_with_heading.dart'; import 'package:spotube/components/image/universal_image.dart'; @@ -28,11 +29,6 @@ class SettingsAccountSection extends HookConsumerWidget { final me = ref.watch(meProvider); final meData = me.asData?.value; - final logoutBtnStyle = FilledButton.styleFrom( - backgroundColor: Colors.red, - foregroundColor: Colors.white, - ); - final onLogin = useLoginCallback(ref); return SectionCardWithHeading( @@ -44,8 +40,9 @@ class SettingsAccountSection extends HookConsumerWidget { title: Text(context.l10n.user_profile), trailing: Padding( padding: const EdgeInsets.all(8.0), - child: CircleAvatar( - backgroundImage: UniversalImage.imageProvider( + child: Avatar( + initials: Avatar.getInitials(meData?.displayName ?? "User"), + provider: UniversalImage.imageProvider( (meData?.images).asUrlString( placeholder: ImagePlaceholder.artist, ), @@ -76,15 +73,8 @@ class SettingsAccountSection extends HookConsumerWidget { onTap: constrains.mdAndUp ? null : onLogin, trailing: constrains.smAndDown ? null - : FilledButton( + : Button.primary( onPressed: onLogin, - style: ButtonStyle( - shape: WidgetStateProperty.all( - RoundedRectangleBorder( - borderRadius: BorderRadius.circular(25.0), - ), - ), - ), child: Text( context.l10n.connect_with_spotify.toUpperCase(), ), @@ -106,8 +96,7 @@ class SettingsAccountSection extends HookConsumerWidget { ), ), ), - trailing: FilledButton( - style: logoutBtnStyle, + trailing: Button.destructive( onPressed: () async { ref.read(authenticationProvider.notifier).logout(); GoRouter.of(context).pop(); @@ -121,27 +110,22 @@ class SettingsAccountSection extends HookConsumerWidget { leading: const Icon(SpotubeIcons.lastFm), title: Text(context.l10n.login_with_lastfm), subtitle: Text(context.l10n.scrobble_to_lastfm), - trailing: FilledButton.icon( - icon: const Icon(SpotubeIcons.lastFm), - label: Text(context.l10n.connect), + trailing: Button.secondary( + leading: const Icon(SpotubeIcons.lastFm), onPressed: () { router.push("/lastfm-login"); }, - style: FilledButton.styleFrom( - backgroundColor: const Color.fromARGB(255, 186, 0, 0), - foregroundColor: Colors.white, - ), + child: Text(context.l10n.connect), ), ) else ListTile( leading: const Icon(SpotubeIcons.lastFm), title: Text(context.l10n.disconnect_lastfm), - trailing: FilledButton( + trailing: Button.destructive( onPressed: () { ref.read(scrobblerProvider.notifier).logout(); }, - style: logoutBtnStyle, child: Text(context.l10n.disconnect), ), ), diff --git a/lib/pages/settings/sections/appearance.dart b/lib/pages/settings/sections/appearance.dart index 9a95e60b..aaa2ce8a 100644 --- a/lib/pages/settings/sections/appearance.dart +++ b/lib/pages/settings/sections/appearance.dart @@ -1,7 +1,6 @@ -import 'package:flutter/material.dart' hide ThemeMode; -import 'package:shadcn_flutter/shadcn_flutter.dart' show ThemeMode; +import 'package:flutter/material.dart' show ListTile; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/models/database/database.dart'; @@ -42,15 +41,15 @@ class SettingsAppearanceSection extends HookConsumerWidget { } }, options: [ - DropdownMenuItem( + SelectItemButton( value: LayoutMode.adaptive, child: Text(context.l10n.adaptive), ), - DropdownMenuItem( + SelectItemButton( value: LayoutMode.compact, child: Text(context.l10n.compact), ), - DropdownMenuItem( + SelectItemButton( value: LayoutMode.extended, child: Text(context.l10n.extended), ), @@ -61,15 +60,15 @@ class SettingsAppearanceSection extends HookConsumerWidget { title: Text(context.l10n.theme), value: preferences.themeMode, options: [ - DropdownMenuItem( + SelectItemButton( value: ThemeMode.dark, child: Text(context.l10n.dark), ), - DropdownMenuItem( + SelectItemButton( value: ThemeMode.light, child: Text(context.l10n.light), ), - DropdownMenuItem( + SelectItemButton( value: ThemeMode.system, child: Text(context.l10n.system), ), @@ -80,13 +79,14 @@ class SettingsAppearanceSection extends HookConsumerWidget { } }, ), - SwitchListTile( - secondary: const Icon(SpotubeIcons.amoled), - title: Text(context.l10n.use_amoled_mode), - subtitle: Text(context.l10n.pitch_dark_theme), - value: preferences.amoledDarkTheme, - onChanged: preferencesNotifier.setAmoledDarkTheme, - ), + ListTile( + leading: const Icon(SpotubeIcons.amoled), + title: Text(context.l10n.use_amoled_mode), + subtitle: Text(context.l10n.pitch_dark_theme), + trailing: Switch( + value: preferences.amoledDarkTheme, + onChanged: preferencesNotifier.setAmoledDarkTheme, + )), ListTile( leading: const Icon(SpotubeIcons.palette), title: Text(context.l10n.accent_color), @@ -101,13 +101,14 @@ class SettingsAppearanceSection extends HookConsumerWidget { ), onTap: pickColorScheme(), ), - SwitchListTile( - secondary: const Icon(SpotubeIcons.colorSync), - title: Text(context.l10n.sync_album_color), - subtitle: Text(context.l10n.sync_album_color_description), - value: preferences.albumColorSync, - onChanged: preferencesNotifier.setAlbumColorSync, - ), + ListTile( + leading: const Icon(SpotubeIcons.colorSync), + title: Text(context.l10n.sync_album_color), + subtitle: Text(context.l10n.sync_album_color_description), + trailing: Switch( + value: preferences.albumColorSync, + onChanged: preferencesNotifier.setAlbumColorSync, + )), ]; if (isGettingStarted) { diff --git a/lib/pages/settings/sections/desktop.dart b/lib/pages/settings/sections/desktop.dart index c61f0150..ad45c689 100644 --- a/lib/pages/settings/sections/desktop.dart +++ b/lib/pages/settings/sections/desktop.dart @@ -1,6 +1,6 @@ -import 'package:flutter/material.dart'; -import 'package:gap/gap.dart'; +import 'package:flutter/material.dart' show ListTile; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/models/database/database.dart'; import 'package:spotube/modules/settings/section_card_with_heading.dart'; @@ -25,11 +25,11 @@ class SettingsDesktopSection extends HookConsumerWidget { title: Text(context.l10n.close_behavior), value: preferences.closeBehavior, options: [ - DropdownMenuItem( + SelectItemButton( value: CloseBehavior.close, child: Text(context.l10n.close), ), - DropdownMenuItem( + SelectItemButton( value: CloseBehavior.minimizeToTray, child: Text(context.l10n.minimize_to_tray), ), @@ -40,23 +40,29 @@ class SettingsDesktopSection extends HookConsumerWidget { } }, ), - SwitchListTile( - secondary: const Icon(SpotubeIcons.tray), + ListTile( + leading: const Icon(SpotubeIcons.tray), title: Text(context.l10n.show_tray_icon), - value: preferences.showSystemTrayIcon, - onChanged: preferencesNotifier.setShowSystemTrayIcon, + trailing: Switch( + value: preferences.showSystemTrayIcon, + onChanged: preferencesNotifier.setShowSystemTrayIcon, + ), ), - SwitchListTile( - secondary: const Icon(SpotubeIcons.window), + ListTile( + leading: const Icon(SpotubeIcons.window), title: Text(context.l10n.use_system_title_bar), - value: preferences.systemTitleBar, - onChanged: preferencesNotifier.setSystemTitleBar, + trailing: Switch( + value: preferences.systemTitleBar, + onChanged: preferencesNotifier.setSystemTitleBar, + ), ), - SwitchListTile( - secondary: const Icon(SpotubeIcons.discord), + ListTile( + leading: const Icon(SpotubeIcons.discord), title: Text(context.l10n.discord_rich_presence), - value: preferences.discordPresence, - onChanged: preferencesNotifier.setDiscordPresence, + trailing: Switch( + value: preferences.discordPresence, + onChanged: preferencesNotifier.setDiscordPresence, + ), ), ], ); diff --git a/lib/pages/settings/sections/developers.dart b/lib/pages/settings/sections/developers.dart index f33fe843..4d8b8ba1 100644 --- a/lib/pages/settings/sections/developers.dart +++ b/lib/pages/settings/sections/developers.dart @@ -1,6 +1,7 @@ -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart' show ListTile; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:go_router/go_router.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/modules/settings/section_card_with_heading.dart'; import 'package:spotube/extensions/context.dart'; diff --git a/lib/pages/settings/sections/downloads.dart b/lib/pages/settings/sections/downloads.dart index 8e679a7d..516d2aca 100644 --- a/lib/pages/settings/sections/downloads.dart +++ b/lib/pages/settings/sections/downloads.dart @@ -1,8 +1,9 @@ import 'package:file_picker/file_picker.dart'; import 'package:file_selector/file_selector.dart'; -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart' show ListTile; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/modules/settings/section_card_with_heading.dart'; import 'package:spotube/extensions/context.dart'; @@ -40,9 +41,9 @@ class SettingsDownloadsSection extends HookConsumerWidget { leading: const Icon(SpotubeIcons.download), title: Text(context.l10n.download_location), subtitle: Text(preferences.downloadLocation), - trailing: FilledButton( + trailing: IconButton.secondary( onPressed: pickDownloadLocation, - child: const Icon(SpotubeIcons.folder), + icon: const Icon(SpotubeIcons.folder), ), onTap: pickDownloadLocation, ), diff --git a/lib/pages/settings/sections/language_region.dart b/lib/pages/settings/sections/language_region.dart index 18c2d088..26f820de 100644 --- a/lib/pages/settings/sections/language_region.dart +++ b/lib/pages/settings/sections/language_region.dart @@ -1,6 +1,5 @@ -import 'package:flutter/material.dart'; -import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/collections/language_codes.dart'; import 'package:spotube/collections/spotify_markets.dart'; @@ -24,7 +23,6 @@ class SettingsLanguageRegionSection extends HookConsumerWidget { return SectionCardWithHeading( heading: context.l10n.language_region, children: [ - const Gap(10), AdaptiveSelectTile( value: preferences.locale, onChanged: (locale) { @@ -34,12 +32,12 @@ class SettingsLanguageRegionSection extends HookConsumerWidget { title: Text(context.l10n.language), secondary: const Icon(SpotubeIcons.language), options: [ - DropdownMenuItem( + SelectItemButton( value: const Locale("system", "system"), child: Text(context.l10n.system_default), ), for (final locale in L10n.all) - DropdownMenuItem( + SelectItemButton( value: locale, child: Builder(builder: (context) { final isoCodeName = LanguageLocals.getDisplayLanguage( @@ -64,7 +62,7 @@ class SettingsLanguageRegionSection extends HookConsumerWidget { }, options: spotifyMarkets .map( - (country) => DropdownMenuItem( + (country) => SelectItemButton( value: country.$1, child: Text(country.$2), ), diff --git a/lib/pages/settings/sections/playback.dart b/lib/pages/settings/sections/playback.dart index f8868789..6888e3a9 100644 --- a/lib/pages/settings/sections/playback.dart +++ b/lib/pages/settings/sections/playback.dart @@ -1,11 +1,12 @@ import 'package:collection/collection.dart'; import 'package:flutter/gestures.dart'; -import 'package:flutter/material.dart'; -import 'package:gap/gap.dart'; +import 'package:flutter/material.dart' show ListTile; + import 'package:go_router/go_router.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:piped_client/piped_client.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/models/database/database.dart'; import 'package:spotube/modules/settings/section_card_with_heading.dart'; @@ -30,21 +31,20 @@ class SettingsPlaybackSection extends HookConsumerWidget { return SectionCardWithHeading( heading: context.l10n.playback, children: [ - const Gap(10), AdaptiveSelectTile( secondary: const Icon(SpotubeIcons.audioQuality), title: Text(context.l10n.audio_quality), value: preferences.audioQuality, options: [ - DropdownMenuItem( + SelectItemButton( value: SourceQualities.high, child: Text(context.l10n.high), ), - DropdownMenuItem( + SelectItemButton( value: SourceQualities.medium, child: Text(context.l10n.medium), ), - DropdownMenuItem( + SelectItemButton( value: SourceQualities.low, child: Text(context.l10n.low), ), @@ -55,13 +55,12 @@ class SettingsPlaybackSection extends HookConsumerWidget { } }, ), - const Gap(5), AdaptiveSelectTile( secondary: const Icon(SpotubeIcons.api), title: Text(context.l10n.audio_source), value: preferences.audioSource, options: AudioSource.values - .map((e) => DropdownMenuItem( + .map((e) => SelectItemButton( value: e, child: Text(e.label), )) @@ -71,177 +70,173 @@ class SettingsPlaybackSection extends HookConsumerWidget { preferencesNotifier.setAudioSource(value); }, ), - AnimatedSwitcher( + AnimatedCrossFade( duration: const Duration(milliseconds: 300), - child: preferences.audioSource != AudioSource.piped - ? const SizedBox.shrink() - : Consumer(builder: (context, ref, child) { - final instanceList = ref.watch(pipedInstancesFutureProvider); + crossFadeState: preferences.audioSource != AudioSource.piped + ? CrossFadeState.showFirst + : CrossFadeState.showSecond, + firstChild: const SizedBox.shrink(), + secondChild: Consumer( + builder: (context, ref, child) { + final instanceList = ref.watch(pipedInstancesFutureProvider); - return instanceList.when( - data: (data) { - return AdaptiveSelectTile( - secondary: const Icon(SpotubeIcons.piped), - title: Text(context.l10n.piped_instance), - subtitle: RichText( - text: TextSpan( - children: [ - TextSpan( - text: context.l10n.piped_description, - style: theme.textTheme.bodyMedium, - ), - const TextSpan(text: "\n"), - TextSpan( - text: context.l10n.piped_warning, - style: theme.textTheme.labelMedium, - ) - ], - ), - ), - value: preferences.pipedInstance, - showValueWhenUnfolded: false, - options: data - .sortedBy((e) => e.name) - .map( - (e) => DropdownMenuItem( - value: e.apiUrl, - child: RichText( - text: TextSpan( - children: [ - TextSpan( - text: "${e.name.trim()}\n", - style: theme.textTheme.labelLarge, - ), - TextSpan( - text: e.locations - .map(countryCodeToEmoji) - .join(""), - style: GoogleFonts.notoColorEmoji(), - ), - ], - ), - ), - ), - ) - .toList(), - onChanged: (value) { - if (value != null) { - preferencesNotifier.setPipedInstance(value); - } - }, - ); - }, - loading: () => const Center( - child: CircularProgressIndicator(), + return instanceList.when( + data: (data) { + return AdaptiveSelectTile( + secondary: const Icon(SpotubeIcons.piped), + title: Text(context.l10n.piped_instance), + subtitle: Text( + "${context.l10n.piped_description}\n" + "${context.l10n.piped_warning}", ), - error: (error, stackTrace) => Text(error.toString()), - ); - }), - ), - AnimatedSwitcher( - duration: const Duration(milliseconds: 300), - child: preferences.audioSource != AudioSource.invidious - ? const SizedBox.shrink() - : Consumer(builder: (context, ref, child) { - final instanceList = ref.watch(invidiousInstancesProvider); - - return instanceList.when( - data: (data) { - return AdaptiveSelectTile( - secondary: const Icon(SpotubeIcons.piped), - title: Text(context.l10n.invidious_instance), - subtitle: RichText( - text: TextSpan( - children: [ - TextSpan( - text: context.l10n.invidious_description, - style: theme.textTheme.bodyMedium, - ), - const TextSpan(text: "\n"), - TextSpan( - text: context.l10n.invidious_warning, - style: theme.textTheme.labelMedium, - ) - ], - ), - ), - value: preferences.invidiousInstance, - showValueWhenUnfolded: false, - options: data - .sortedBy((e) => e.name) - .map( - (e) => DropdownMenuItem( - value: e.details.uri, - child: RichText( - text: TextSpan( - children: [ - TextSpan( - text: "${e.name.trim()}\n", - style: theme.textTheme.labelLarge, - ), - TextSpan( - text: countryCodeToEmoji( - e.details.region, - ), - style: GoogleFonts.notoColorEmoji(), - ), - ], - ), + value: preferences.pipedInstance, + showValueWhenUnfolded: false, + options: data + .sortedBy((e) => e.name) + .map( + (e) => SelectItemButton( + value: e.apiUrl, + child: RichText( + text: TextSpan( + style: theme.typography.normal.copyWith( + color: theme.colorScheme.foreground, ), + children: [ + TextSpan( + text: "${e.name.trim()}\n", + ), + TextSpan( + text: e.locations + .map(countryCodeToEmoji) + .join(""), + style: GoogleFonts.notoColorEmoji(), + ), + ], ), - ) - .toList(), - onChanged: (value) { - if (value != null) { - preferencesNotifier.setInvidiousInstance(value); - } - }, - ); + ), + ), + ) + .toList(), + onChanged: (value) { + if (value != null) { + preferencesNotifier.setPipedInstance(value); + } }, - loading: () => const Center( - child: CircularProgressIndicator(), - ), - error: (error, stackTrace) => Text(error.toString()), ); - }), - ), - AnimatedSwitcher( - duration: const Duration(milliseconds: 300), - child: preferences.audioSource != AudioSource.piped - ? const SizedBox.shrink() - : AdaptiveSelectTile( - secondary: const Icon(SpotubeIcons.search), - title: Text(context.l10n.search_mode), - value: preferences.searchMode, - options: SearchMode.values - .map((e) => DropdownMenuItem( - value: e, - child: Text(e.label), - )) - .toList(), - onChanged: (value) { - if (value == null) return; - preferencesNotifier.setSearchMode(value); - }, + }, + loading: () => const Center( + child: CircularProgressIndicator(), ), + error: (error, stackTrace) => Text(error.toString()), + ); + }, + ), ), - AnimatedSwitcher( + AnimatedCrossFade( duration: const Duration(milliseconds: 300), - child: preferences.searchMode == SearchMode.youtube && + crossFadeState: preferences.audioSource != AudioSource.invidious + ? CrossFadeState.showFirst + : CrossFadeState.showSecond, + firstChild: const SizedBox.shrink(), + secondChild: Consumer( + builder: (context, ref, child) { + final instanceList = ref.watch(invidiousInstancesProvider); + + return instanceList.when( + data: (data) { + return AdaptiveSelectTile( + secondary: const Icon(SpotubeIcons.piped), + title: Text(context.l10n.invidious_instance), + subtitle: Text( + "${context.l10n.invidious_description}\n" + "${context.l10n.invidious_warning}", + ), + value: preferences.invidiousInstance, + showValueWhenUnfolded: false, + options: data + .sortedBy((e) => e.name) + .map( + (e) => SelectItemButton( + value: e.details.uri, + child: RichText( + text: TextSpan( + style: theme.typography.normal.copyWith( + color: theme.colorScheme.foreground, + ), + children: [ + TextSpan( + text: "${e.name.trim()}\n", + ), + TextSpan( + text: countryCodeToEmoji( + e.details.region, + ), + style: GoogleFonts.notoColorEmoji(), + ), + ], + ), + ), + ), + ) + .toList(), + onChanged: (value) { + if (value != null) { + preferencesNotifier.setInvidiousInstance(value); + } + }, + ); + }, + loading: () => const Center( + child: CircularProgressIndicator(), + ), + error: (error, stackTrace) => Text(error.toString()), + ); + }, + ), + ), + AnimatedCrossFade( + duration: const Duration(milliseconds: 300), + crossFadeState: preferences.audioSource != AudioSource.youtube + ? CrossFadeState.showFirst + : CrossFadeState.showSecond, + firstChild: const SizedBox.shrink(), + secondChild: AdaptiveSelectTile( + secondary: const Icon(SpotubeIcons.search), + title: Text(context.l10n.search_mode), + value: preferences.searchMode, + options: SearchMode.values + .map((e) => SelectItemButton( + value: e, + child: Text(e.label), + )) + .toList(), + onChanged: (value) { + if (value == null) return; + preferencesNotifier.setSearchMode(value); + }, + ), + ), + AnimatedCrossFade( + duration: const Duration(milliseconds: 300), + crossFadeState: preferences.searchMode == SearchMode.youtube && (preferences.audioSource == AudioSource.piped || preferences.audioSource == AudioSource.youtube || preferences.audioSource == AudioSource.invidious) - ? SwitchListTile( - secondary: const Icon(SpotubeIcons.skip), - title: Text(context.l10n.skip_non_music), - value: preferences.skipNonMusic, - onChanged: (state) { - preferencesNotifier.setSkipNonMusic(state); - }, - ) - : const SizedBox.shrink(), + ? CrossFadeState.showFirst + : CrossFadeState.showSecond, + firstChild: ListTile( + leading: const Icon(SpotubeIcons.skip), + title: Text(context.l10n.skip_non_music), + trailing: Switch( + value: preferences.skipNonMusic, + onChanged: (state) { + preferencesNotifier.setSkipNonMusic(state); + }, + ), + ), + secondChild: const SizedBox.shrink(), ), - SwitchListTile( + ListTile( title: Text(context.l10n.cache_music), subtitle: kIsMobile ? null @@ -253,7 +248,7 @@ class SettingsPlaybackSection extends HookConsumerWidget { text: context.l10n.cache_folder.toLowerCase(), recognizer: TapGestureRecognizer() ..onTap = preferencesNotifier.openCacheFolder, - style: theme.textTheme.bodyMedium?.copyWith( + style: theme.typography.normal.copyWith( color: theme.colorScheme.primary, decoration: TextDecoration.underline, ), @@ -261,9 +256,11 @@ class SettingsPlaybackSection extends HookConsumerWidget { ], ), ), - secondary: const Icon(SpotubeIcons.cache), - value: preferences.cacheMusic, - onChanged: preferencesNotifier.setCacheMusic, + leading: const Icon(SpotubeIcons.cache), + trailing: Switch( + value: preferences.cacheMusic, + onChanged: preferencesNotifier.setCacheMusic, + ), ), ListTile( leading: const Icon(SpotubeIcons.playlistRemove), @@ -274,25 +271,26 @@ class SettingsPlaybackSection extends HookConsumerWidget { }, trailing: const Icon(SpotubeIcons.angleRight), ), - SwitchListTile( - secondary: const Icon(SpotubeIcons.normalize), + ListTile( + leading: const Icon(SpotubeIcons.normalize), title: Text(context.l10n.normalize_audio), - value: preferences.normalizeAudio, - onChanged: preferencesNotifier.setNormalizeAudio, + trailing: Switch( + value: preferences.normalizeAudio, + onChanged: preferencesNotifier.setNormalizeAudio, + ), ), if (preferences.audioSource != AudioSource.jiosaavn) ...[ - const Gap(5), AdaptiveSelectTile( secondary: const Icon(SpotubeIcons.stream), title: Text(context.l10n.streaming_music_codec), value: preferences.streamMusicCodec, showValueWhenUnfolded: false, options: SourceCodecs.values - .map((e) => DropdownMenuItem( + .map((e) => SelectItemButton( value: e, child: Text( e.label, - style: theme.textTheme.labelMedium, + style: theme.typography.small, ), )) .toList(), @@ -301,18 +299,17 @@ class SettingsPlaybackSection extends HookConsumerWidget { preferencesNotifier.setStreamMusicCodec(value); }, ), - const Gap(5), AdaptiveSelectTile( secondary: const Icon(SpotubeIcons.file), title: Text(context.l10n.download_music_codec), value: preferences.downloadMusicCodec, showValueWhenUnfolded: false, options: SourceCodecs.values - .map((e) => DropdownMenuItem( + .map((e) => SelectItemButton( value: e, child: Text( e.label, - style: theme.textTheme.labelMedium, + style: theme.typography.small, ), )) .toList(), @@ -320,20 +317,23 @@ class SettingsPlaybackSection extends HookConsumerWidget { if (value == null) return; preferencesNotifier.setDownloadMusicCodec(value); }, - ) + ), ], - SwitchListTile( - secondary: const Icon(SpotubeIcons.repeat), - title: Text(context.l10n.endless_playback), - value: preferences.endlessPlayback, - onChanged: preferencesNotifier.setEndlessPlayback, - ), - SwitchListTile( + ListTile( + leading: const Icon(SpotubeIcons.repeat), + title: Text(context.l10n.endless_playback), + trailing: Switch( + value: preferences.endlessPlayback, + onChanged: preferencesNotifier.setEndlessPlayback, + )), + ListTile( title: Text(context.l10n.enable_connect), subtitle: Text(context.l10n.enable_connect_description), - secondary: const Icon(SpotubeIcons.connect), - value: preferences.enableConnect, - onChanged: preferencesNotifier.setEnableConnect, + leading: const Icon(SpotubeIcons.connect), + trailing: Switch( + value: preferences.enableConnect, + onChanged: preferencesNotifier.setEnableConnect, + ), ), ], ); diff --git a/lib/pages/settings/settings.dart b/lib/pages/settings/settings.dart index a7355812..54c377eb 100644 --- a/lib/pages/settings/settings.dart +++ b/lib/pages/settings/settings.dart @@ -1,7 +1,8 @@ import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart' show Material, MaterialType; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/pages/settings/sections/about.dart'; @@ -28,36 +29,41 @@ class SettingsPage extends HookConsumerWidget { return SafeArea( bottom: false, child: Scaffold( - appBar: TitleBar( - title: Text(context.l10n.settings), - automaticallyImplyLeading: true, - ), - body: Scrollbar( + headers: [ + TitleBar( + title: Text(context.l10n.settings), + automaticallyImplyLeading: true, + ) + ], + child: Scrollbar( controller: controller, child: Center( child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 1366), child: ScrollConfiguration( behavior: const ScrollBehavior().copyWith(scrollbars: false), - child: ListView( - controller: controller, - children: [ - const SettingsAccountSection(), - const SettingsLanguageRegionSection(), - const SettingsAppearanceSection(), - const SettingsPlaybackSection(), - const SettingsDownloadsSection(), - if (kIsDesktop) const SettingsDesktopSection(), - if (!kIsWeb) const SettingsDevelopersSection(), - const SettingsAboutSection(), - Center( - child: FilledButton( - onPressed: preferencesNotifier.reset, - child: Text(context.l10n.restore_defaults), + child: Material( + type: MaterialType.transparency, + child: ListView( + controller: controller, + children: [ + const SettingsAccountSection(), + const SettingsLanguageRegionSection(), + const SettingsAppearanceSection(), + const SettingsPlaybackSection(), + const SettingsDownloadsSection(), + if (kIsDesktop) const SettingsDesktopSection(), + if (!kIsWeb) const SettingsDevelopersSection(), + const SettingsAboutSection(), + Center( + child: Button.destructive( + onPressed: preferencesNotifier.reset, + child: Text(context.l10n.restore_defaults), + ), ), - ), - const SizedBox(height: 10), - ], + const SizedBox(height: 200), + ], + ), ), ), ), diff --git a/macos/Runner/AppDelegate.swift b/macos/Runner/AppDelegate.swift index a6f73a80..db44369c 100644 --- a/macos/Runner/AppDelegate.swift +++ b/macos/Runner/AppDelegate.swift @@ -6,4 +6,8 @@ class AppDelegate: FlutterAppDelegate { override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { return false } + + override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { + return true + } } diff --git a/pubspec.lock b/pubspec.lock index b58c16b8..46ed96d6 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1336,10 +1336,10 @@ packages: dependency: "direct main" description: name: invidious - sha256: "7cb879c0b4b99aa06ec720af84f6988ff0080bb0434d041f6fb0c4add680ee36" + sha256: "27ef3a001df875665de15535dbc9099f44d12a59480018fb1e17377d4af0308d" url: "https://pub.dev" source: hosted - version: "0.1.0" + version: "0.1.1" io: dependency: "direct dev" description: diff --git a/pubspec.yaml b/pubspec.yaml index c9a6f341..e1b1ada3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -78,7 +78,7 @@ dependencies: http: ^1.2.1 image_picker: ^1.1.0 intl: any - invidious: ^0.1.0 + invidious: ^0.1.1 jiosaavn: ^0.1.0 json_annotation: ^4.8.1 local_notifier: ^0.1.6 From 05d544fe5a66e63ea2fdaf0bb239a476263e8b66 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 22 Dec 2024 11:58:06 +0600 Subject: [PATCH 021/112] refactor: update FriendItem and HorizontalPlaybuttonCardView styles, remove unused imports, and clean up dependencies --- lib/collections/assets.gen.dart | 15 + lib/collections/fonts.gen.dart | 24 + .../adaptive/adaptive_popup_menu_button.dart | 106 -- lib/components/bordered_text.dart | 88 - lib/components/compact_search.dart | 52 - lib/components/dialogs/piped_down_dialog.dart | 46 - .../horizontal_playbutton_card_view.dart | 4 +- lib/extensions/page.dart | 61 - .../controllers/use_sidebarx_controller.dart | 59 - lib/main.dart | 10 +- lib/models/database/database.steps.dart | 2 +- lib/models/spotify_spotube_credentials.dart | 30 - .../home/sections/friends/friend_item.dart | 3 + lib/modules/library/user_albums.dart | 17 +- lib/modules/library/user_playlists.dart | 16 +- lib/provider/spotify/spotify.dart | 3 - lib/provider/spotify/utils/persistence.dart | 40 - lib/utils/migrations/adapters.dart | 320 ---- lib/utils/migrations/adapters.freezed.dart | 1421 ----------------- lib/utils/migrations/adapters.g.dart | 600 ------- lib/utils/migrations/cache_box.dart | 100 -- pubspec.lock | 34 +- pubspec.yaml | 5 - 23 files changed, 67 insertions(+), 2989 deletions(-) create mode 100644 lib/collections/fonts.gen.dart delete mode 100644 lib/components/adaptive/adaptive_popup_menu_button.dart delete mode 100644 lib/components/bordered_text.dart delete mode 100644 lib/components/compact_search.dart delete mode 100644 lib/components/dialogs/piped_down_dialog.dart delete mode 100644 lib/extensions/page.dart delete mode 100644 lib/hooks/controllers/use_sidebarx_controller.dart delete mode 100644 lib/models/spotify_spotube_credentials.dart delete mode 100644 lib/provider/spotify/utils/persistence.dart delete mode 100644 lib/utils/migrations/adapters.dart delete mode 100644 lib/utils/migrations/adapters.freezed.dart delete mode 100644 lib/utils/migrations/adapters.g.dart delete mode 100644 lib/utils/migrations/cache_box.dart diff --git a/lib/collections/assets.gen.dart b/lib/collections/assets.gen.dart index 6825fbd5..e098ff9a 100644 --- a/lib/collections/assets.gen.dart +++ b/lib/collections/assets.gen.dart @@ -9,6 +9,17 @@ import 'package:flutter/widgets.dart'; +class $AssetsBackgroundsGen { + const $AssetsBackgroundsGen(); + + /// File path: assets/backgrounds/xmas-effect.png + AssetGenImage get xmasEffect => + const AssetGenImage('assets/backgrounds/xmas-effect.png'); + + /// List of all assets + List get values => [xmasEffect]; +} + class $AssetsLogosGen { const $AssetsLogosGen(); @@ -46,6 +57,7 @@ class Assets { static const String license = 'LICENSE'; static const AssetGenImage albumPlaceholder = AssetGenImage('assets/album-placeholder.png'); + static const $AssetsBackgroundsGen backgrounds = $AssetsBackgroundsGen(); static const AssetGenImage bengaliPatternsBg = AssetGenImage('assets/bengali-patterns-bg.jpg'); static const AssetGenImage branding = AssetGenImage('assets/branding.png'); @@ -61,6 +73,8 @@ class Assets { AssetGenImage('assets/spotube-hero-banner.png'); static const AssetGenImage spotubeLogoForeground = AssetGenImage('assets/spotube-logo-foreground.jpg'); + static const AssetGenImage spotubeLogoMacos = + AssetGenImage('assets/spotube-logo-macos.png'); static const AssetGenImage spotubeLogoBmp = AssetGenImage('assets/spotube-logo.bmp'); static const String spotubeLogoIco = 'assets/spotube-logo.ico'; @@ -104,6 +118,7 @@ class Assets { placeholder, spotubeHeroBanner, spotubeLogoForeground, + spotubeLogoMacos, spotubeLogoBmp, spotubeLogoIco, spotubeLogoPng, diff --git a/lib/collections/fonts.gen.dart b/lib/collections/fonts.gen.dart new file mode 100644 index 00000000..811e1d36 --- /dev/null +++ b/lib/collections/fonts.gen.dart @@ -0,0 +1,24 @@ +/// GENERATED CODE - DO NOT MODIFY BY HAND +/// ***************************************************** +/// FlutterGen +/// ***************************************************** + +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: directives_ordering,unnecessary_import,implicit_dynamic_list_literal,deprecated_member_use + +class FontFamily { + FontFamily._(); + + /// Font family: BootstrapIcons + static const String bootstrapIcons = 'BootstrapIcons'; + + /// Font family: GeistMono + static const String geistMono = 'GeistMono'; + + /// Font family: GeistSans + static const String geistSans = 'GeistSans'; + + /// Font family: RadixIcons + static const String radixIcons = 'RadixIcons'; +} diff --git a/lib/components/adaptive/adaptive_popup_menu_button.dart b/lib/components/adaptive/adaptive_popup_menu_button.dart deleted file mode 100644 index 02fced52..00000000 --- a/lib/components/adaptive/adaptive_popup_menu_button.dart +++ /dev/null @@ -1,106 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; - -import 'package:popover/popover.dart'; -import 'package:spotube/collections/spotube_icons.dart'; -import 'package:spotube/extensions/constrains.dart'; - -class Action extends StatelessWidget { - final Widget text; - final Widget icon; - final void Function() onPressed; - final bool isExpanded; - final Color? backgroundColor; - const Action({ - super.key, - required this.icon, - required this.text, - required this.onPressed, - this.isExpanded = true, - this.backgroundColor, - }); - - @override - Widget build(BuildContext context) { - if (isExpanded != true) { - return IconButton( - icon: icon, - onPressed: onPressed, - style: IconButton.styleFrom( - backgroundColor: backgroundColor, - ), - tooltip: text is Text - ? (text as Text).data - : text.toStringShallow().split(",").last.replaceAll( - "\"", - "", - ), - ); - } - - return ListTile( - tileColor: backgroundColor, - onTap: onPressed, - leading: icon, - title: text, - ); - } -} - -class AdaptiveActions extends HookWidget { - final List actions; - final bool? breakOn; - const AdaptiveActions({ - required this.actions, - this.breakOn, - super.key, - }); - - @override - Widget build(BuildContext context) { - final mediaQuery = MediaQuery.of(context); - - if (breakOn ?? mediaQuery.lgAndUp) { - return IconButton( - icon: const Icon(SpotubeIcons.moreHorizontal), - onPressed: () { - showPopover( - context: context, - direction: PopoverDirection.left, - bodyBuilder: (context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: actions - .map( - (action) => SizedBox( - width: 200, - child: Row( - children: [ - Expanded(child: action), - ], - ), - ), - ) - .toList(), - ); - }, - backgroundColor: Theme.of(context).cardColor, - ); - }, - ); - } - - return Row( - children: actions.map((action) { - return Action( - icon: action.icon, - onPressed: action.onPressed, - text: action.text, - backgroundColor: action.backgroundColor, - isExpanded: false, - ); - }).toList(), - ); - } -} diff --git a/lib/components/bordered_text.dart b/lib/components/bordered_text.dart deleted file mode 100644 index f25f2208..00000000 --- a/lib/components/bordered_text.dart +++ /dev/null @@ -1,88 +0,0 @@ -library bordered_text; - -import 'package:flutter/widgets.dart'; - -/// Adds stroke to text widget -/// We can apply a very thin and subtle stroke to a [Text] -/// ```dart -/// BorderedText( -/// strokeWidth: 1.0, -/// text: Text( -/// 'Bordered Text', -/// style: TextStyle( -/// decoration: TextDecoration.none, -/// decorationStyle: TextDecorationStyle.wavy, -/// decorationColor: Colors.red, -/// ), -/// ), -/// ) -/// ``` -class BorderedText extends StatelessWidget { - const BorderedText({ - super.key, - required this.child, - this.strokeCap = StrokeCap.round, - this.strokeJoin = StrokeJoin.round, - this.strokeWidth = 6.0, - this.strokeColor = const Color.fromRGBO(53, 0, 71, 1), - }); - - /// the stroke cap style - final StrokeCap strokeCap; - - /// the stroke joint style - final StrokeJoin strokeJoin; - - /// the stroke width - final double strokeWidth; - - /// the stroke color - final Color strokeColor; - - /// the [Text] widget to apply stroke on - final Text child; - - @override - Widget build(BuildContext context) { - TextStyle style; - if (child.style != null) { - style = child.style!.copyWith( - foreground: Paint() - ..style = PaintingStyle.stroke - ..strokeCap = strokeCap - ..strokeJoin = strokeJoin - ..strokeWidth = strokeWidth - ..color = strokeColor, - color: null, - ); - } else { - style = TextStyle( - foreground: Paint() - ..style = PaintingStyle.stroke - ..strokeCap = strokeCap - ..strokeJoin = strokeJoin - ..strokeWidth = strokeWidth - ..color = strokeColor, - ); - } - return Stack( - alignment: Alignment.center, - textDirection: child.textDirection, - children: [ - Text( - child.data!, - style: style, - maxLines: child.maxLines, - overflow: child.overflow, - semanticsLabel: child.semanticsLabel, - softWrap: child.softWrap, - strutStyle: child.strutStyle, - textAlign: child.textAlign, - textDirection: child.textDirection, - textScaler: child.textScaler, - ), - child, - ], - ); - } -} diff --git a/lib/components/compact_search.dart b/lib/components/compact_search.dart deleted file mode 100644 index d37cb673..00000000 --- a/lib/components/compact_search.dart +++ /dev/null @@ -1,52 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; - -import 'package:popover/popover.dart'; -import 'package:spotube/collections/spotube_icons.dart'; - -class CompactSearch extends HookWidget { - final ValueChanged? onChanged; - final String placeholder; - final IconData icon; - final Color? iconColor; - - const CompactSearch({ - super.key, - this.onChanged, - this.placeholder = "Search...", - this.icon = SpotubeIcons.search, - this.iconColor, - }); - - @override - Widget build(BuildContext context) { - return IconButton( - onPressed: () { - showPopover( - context: context, - backgroundColor: Theme.of(context).cardColor, - transitionDuration: const Duration(milliseconds: 100), - barrierColor: Colors.transparent, - arrowDxOffset: -6, - bodyBuilder: (context) { - return Container( - padding: const EdgeInsets.all(8.0), - width: 300, - child: TextField( - autofocus: true, - onChanged: onChanged, - decoration: InputDecoration( - hintText: placeholder, - prefixIcon: Icon(icon), - ), - ), - ); - }, - height: 60, - ); - }, - tooltip: placeholder, - icon: Icon(icon, color: iconColor), - ); - } -} diff --git a/lib/components/dialogs/piped_down_dialog.dart b/lib/components/dialogs/piped_down_dialog.dart deleted file mode 100644 index b1717a2a..00000000 --- a/lib/components/dialogs/piped_down_dialog.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:spotube/collections/spotube_icons.dart'; -import 'package:spotube/extensions/context.dart'; -import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; - -class PipedDownDialog extends HookConsumerWidget { - const PipedDownDialog({super.key}); - - @override - Widget build(BuildContext context, ref) { - final pipedInstance = - ref.watch(userPreferencesProvider.select((s) => s.pipedInstance)); - final ThemeData(:colorScheme) = Theme.of(context); - - return AlertDialog( - insetPadding: const EdgeInsets.all(6), - contentPadding: const EdgeInsets.all(6), - icon: Icon( - SpotubeIcons.error, - color: colorScheme.error, - ), - title: Text( - context.l10n.piped_api_down, - style: TextStyle(color: colorScheme.error), - ), - content: Card( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: - Text(context.l10n.piped_down_error_instructions(pipedInstance)), - ), - ), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: Text(context.l10n.ok), - ), - FilledButton( - onPressed: () => Navigator.pop(context), - child: Text(context.l10n.settings), - ), - ], - ); - } -} diff --git a/lib/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart b/lib/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart index f41e0709..31c6a37c 100644 --- a/lib/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart +++ b/lib/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart @@ -55,7 +55,9 @@ class HorizontalPlaybuttonCardView extends HookWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ DefaultTextStyle( - style: context.theme.typography.h4, + style: context.theme.typography.h4.copyWith( + color: context.theme.colorScheme.foreground, + ), child: title, ), if (titleTrailing != null) titleTrailing!, diff --git a/lib/extensions/page.dart b/lib/extensions/page.dart deleted file mode 100644 index 34343fb5..00000000 --- a/lib/extensions/page.dart +++ /dev/null @@ -1,61 +0,0 @@ -import 'package:spotify/spotify.dart'; - -extension CursorPageJson on CursorPage { - static CursorPage fromJson( - Map json, - T Function(dynamic json) itemFromJson, - ) { - final metadata = Paging.fromJson(json["metadata"]); - final paging = CursorPaging(); - paging.cursors = Cursor.fromJson(json["metadata"])..after = json["after"]; - paging.href = metadata.href; - paging.itemsNative = paging.itemsNative; - paging.limit = metadata.limit; - paging.next = metadata.next; - return CursorPage( - paging, - itemFromJson, - ); - } - - Map toJson() { - return { - "after": after, - "metadata": metadata.toJson(), - }; - } -} - -extension PagingToJson on Paging { - Map toJson() { - return { - "items": itemsNative, - "total": total, - "next": next, - "previous": previous, - "limit": limit, - "offset": offset, - "href": href, - }; - } -} - -extension PageJson on Page { - static Page fromJson( - Map json, - T Function(dynamic json) itemFromJson, - ) { - return Page( - Paging.fromJson( - Map.castFrom(json["metadata"]), - ), - itemFromJson, - ); - } - - Map toJson() { - return { - "metadata": metadata.toJson(), - }; - } -} diff --git a/lib/hooks/controllers/use_sidebarx_controller.dart b/lib/hooks/controllers/use_sidebarx_controller.dart deleted file mode 100644 index a14c3305..00000000 --- a/lib/hooks/controllers/use_sidebarx_controller.dart +++ /dev/null @@ -1,59 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:sidebarx/sidebarx.dart'; - -/// Creates [SidebarXController] that will be disposed automatically. -/// -/// See also: -/// - [SidebarXController] -SidebarXController useSidebarXController({ - required int selectedIndex, - bool? extended, - List? keys, -}) { - return use( - _SidebarXControllerHook( - selectedIndex: selectedIndex, - extended: extended, - keys: keys, - ), - ); -} - -class _SidebarXControllerHook extends Hook { - const _SidebarXControllerHook({ - required this.selectedIndex, - this.extended, - super.keys, - }); - - final int selectedIndex; - final bool? extended; - - @override - HookState> createState() => - _SidebarXControllerHookState(); -} - -class _SidebarXControllerHookState - extends HookState { - late final SidebarXController controller; - - @override - void initHook() { - super.initHook(); - controller = SidebarXController( - selectedIndex: hook.selectedIndex, - extended: hook.extended, - ); - } - - @override - SidebarXController build(BuildContext context) => controller; - - @override - void dispose() => controller.dispose(); - - @override - String get debugLabel => 'useSidebarXController'; -} diff --git a/lib/main.dart b/lib/main.dart index d1275577..cae1e9fe 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -7,7 +7,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_discord_rpc/flutter_discord_rpc.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; -import 'package:hive/hive.dart'; + import 'package:home_widget/home_widget.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:local_notifier/local_notifier.dart'; @@ -43,7 +43,6 @@ import 'package:spotube/services/wm_tools/wm_tools.dart'; import 'package:spotube/utils/migrations/sandbox.dart'; import 'package:spotube/utils/platform.dart'; import 'package:system_theme/system_theme.dart'; -import 'package:path_provider/path_provider.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_native_splash/flutter_native_splash.dart'; import 'package:flutter_displaymode/flutter_displaymode.dart'; @@ -100,11 +99,6 @@ Future main(List rawArgs) async { await KVStoreService.initialize(); await EncryptedKvStoreService.initialize(); - final hiveCacheDir = - kIsWeb ? null : (await getApplicationSupportDirectory()).path; - - Hive.init(hiveCacheDir); - final database = AppDatabase(); if (kIsDesktop) { @@ -222,6 +216,7 @@ class Spotube extends HookConsumerWidget { colorScheme: ColorSchemes.lightBlue(), surfaceOpacity: .8, surfaceBlur: 10, + typography: const Typography.geist(), ), darkTheme: ThemeData( radius: .5, @@ -229,6 +224,7 @@ class Spotube extends HookConsumerWidget { colorScheme: ColorSchemes.darkNeutral(), surfaceOpacity: .8, surfaceBlur: 10, + typography: const Typography.geist(), ), themeMode: themeMode, shortcuts: { diff --git a/lib/models/database/database.steps.dart b/lib/models/database/database.steps.dart index 40546bdb..11a564c6 100644 --- a/lib/models/database/database.steps.dart +++ b/lib/models/database/database.steps.dart @@ -4,8 +4,8 @@ import 'package:drift/drift.dart' as i1; import 'package:drift/drift.dart'; // ignore_for_file: type=lint,unused_import import 'package:flutter/material.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/models/database/database.dart'; import 'package:spotube/services/sourced_track/enums.dart'; -import 'package:spotube/utils/migrations/adapters.dart'; // GENERATED BY drift_dev, DO NOT MODIFY. final class Schema2 extends i0.VersionedSchema { diff --git a/lib/models/spotify_spotube_credentials.dart b/lib/models/spotify_spotube_credentials.dart deleted file mode 100644 index 982ca64a..00000000 --- a/lib/models/spotify_spotube_credentials.dart +++ /dev/null @@ -1,30 +0,0 @@ -class SpotifySpotubeCredentials { - String clientId; - String accessToken; - DateTime expiration; - bool isAnonymous; - - SpotifySpotubeCredentials({ - required this.clientId, - required this.accessToken, - required this.expiration, - required this.isAnonymous, - }); - - SpotifySpotubeCredentials.fromJson(Map json) - : clientId = json['clientId'], - accessToken = json['accessToken'], - expiration = DateTime.fromMillisecondsSinceEpoch( - json['accessTokenExpirationTimestampMs'], - ), - isAnonymous = json['isAnonymous']; - - Map toJson() { - return { - 'clientId': clientId, - 'accessToken': accessToken, - 'accessTokenExpirationTimestampMs': expiration.millisecondsSinceEpoch, - 'isAnonymous': isAnonymous, - }; - } -} diff --git a/lib/modules/home/sections/friends/friend_item.dart b/lib/modules/home/sections/friends/friend_item.dart index 42ec2909..94feb5cd 100644 --- a/lib/modules/home/sections/friends/friend_item.dart +++ b/lib/modules/home/sections/friends/friend_item.dart @@ -42,6 +42,9 @@ class FriendItem extends HookConsumerWidget { ), RichText( text: TextSpan( + style: context.theme.typography.normal.copyWith( + color: context.theme.colorScheme.foreground, + ), children: [ TextSpan( text: friend.track.name, diff --git a/lib/modules/library/user_albums.dart b/lib/modules/library/user_albums.dart index 4a22bbea..535381fc 100644 --- a/lib/modules/library/user_albums.dart +++ b/lib/modules/library/user_albums.dart @@ -12,7 +12,6 @@ import 'package:spotube/modules/album/album_card.dart'; import 'package:spotube/components/inter_scrollbar/inter_scrollbar.dart'; import 'package:spotube/components/fallbacks/anonymous_fallback.dart'; import 'package:spotube/components/waypoint.dart'; -import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/authentication/authentication.dart'; import 'package:spotube/provider/spotify/spotify.dart'; @@ -77,12 +76,14 @@ class UserAlbums extends HookConsumerWidget { ), ), const SliverGap(10), - SliverLayoutBuilder(builder: (context, constrains) { - return SliverGrid.builder( + SliverPadding( + padding: const EdgeInsets.symmetric(horizontal: 8), + sliver: SliverGrid.builder( itemCount: albums.isEmpty ? 6 : albums.length + 1, - gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( - maxCrossAxisExtent: 200, - mainAxisExtent: constrains.smAndDown ? 225 : 250, + gridDelegate: + const SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: 150, + mainAxisExtent: 225, crossAxisSpacing: 8, mainAxisSpacing: 8, ), @@ -110,8 +111,8 @@ class UserAlbums extends HookConsumerWidget { ), ); }, - ); - }), + ), + ), ], ), ), diff --git a/lib/modules/library/user_playlists.dart b/lib/modules/library/user_playlists.dart index 50595298..0f307894 100644 --- a/lib/modules/library/user_playlists.dart +++ b/lib/modules/library/user_playlists.dart @@ -15,7 +15,6 @@ import 'package:spotube/components/inter_scrollbar/inter_scrollbar.dart'; import 'package:spotube/components/fallbacks/anonymous_fallback.dart'; import 'package:spotube/modules/playlist/playlist_card.dart'; import 'package:spotube/components/waypoint.dart'; -import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/pages/library/playlist_generate/playlist_generate.dart'; import 'package:spotube/provider/authentication/authentication.dart'; @@ -126,12 +125,13 @@ class UserPlaylists extends HookConsumerWidget { ), ), const SliverGap(10), - SliverLayoutBuilder(builder: (context, constrains) { - return SliverGrid.builder( + SliverPadding( + padding: const EdgeInsets.symmetric(horizontal: 8), + sliver: SliverGrid.builder( itemCount: playlists.isEmpty ? 6 : playlists.length + 1, - gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( - maxCrossAxisExtent: 200, - mainAxisExtent: constrains.smAndDown ? 225 : 250, + gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: 150, + mainAxisExtent: 225, crossAxisSpacing: 8, mainAxisSpacing: 8, ), @@ -157,8 +157,8 @@ class UserPlaylists extends HookConsumerWidget { FakeData.playlistSimple, ); }, - ); - }) + ), + ), ], ), ), diff --git a/lib/provider/spotify/spotify.dart b/lib/provider/spotify/spotify.dart index 8cf60120..dbf3802b 100644 --- a/lib/provider/spotify/spotify.dart +++ b/lib/provider/spotify/spotify.dart @@ -6,12 +6,10 @@ import 'package:drift/drift.dart'; import 'package:spotube/models/database/database.dart'; import 'package:spotube/provider/authentication/authentication.dart'; import 'package:spotube/provider/database/database.dart'; -import 'package:spotube/provider/spotify/utils/json_cast.dart'; import 'package:spotube/services/logger/logger.dart'; import 'package:collection/collection.dart'; import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; -import 'package:hive_flutter/hive_flutter.dart'; import 'package:intl/intl.dart'; import 'package:lrc/lrc.dart'; import 'package:package_info_plus/package_info_plus.dart'; @@ -70,7 +68,6 @@ part 'views/view.dart'; part 'utils/mixin.dart'; part 'utils/state.dart'; part 'utils/provider.dart'; -part 'utils/persistence.dart'; part 'utils/async.dart'; part 'utils/provider/paginated.dart'; diff --git a/lib/provider/spotify/utils/persistence.dart b/lib/provider/spotify/utils/persistence.dart deleted file mode 100644 index 57f41dec..00000000 --- a/lib/provider/spotify/utils/persistence.dart +++ /dev/null @@ -1,40 +0,0 @@ -part of '../spotify.dart'; - -// ignore: invalid_use_of_internal_member -mixin Persistence on BuildlessAsyncNotifier { - LazyBox get store => Hive.lazyBox("spotube_cache"); - - FutureOr fromJson(Map json); - Map toJson(T data); - - FutureOr onInit() {} - - Future load() async { - final json = await store.get(runtimeType.toString()); - if (json != null || - (json is Map && json.entries.isNotEmpty) || - (json is List && json.isNotEmpty)) { - state = AsyncData( - await fromJson( - castNestedJson(json), - ), - ); - } - - await onInit(); - } - - Future save() async { - await store.put( - runtimeType.toString(), - state.value == null ? null : toJson(state.value as T), - ); - } - - @override - set state(AsyncValue value) { - if (state == value) return; - super.state = value; - save(); - } -} diff --git a/lib/utils/migrations/adapters.dart b/lib/utils/migrations/adapters.dart deleted file mode 100644 index f7f6350b..00000000 --- a/lib/utils/migrations/adapters.dart +++ /dev/null @@ -1,320 +0,0 @@ -import 'package:hive/hive.dart'; -import 'dart:convert'; - -import 'package:flutter/material.dart'; -import 'package:freezed_annotation/freezed_annotation.dart'; -import 'package:spotify/spotify.dart'; -import 'package:spotube/modules/settings/color_scheme_picker_dialog.dart'; -import 'package:spotube/services/sourced_track/enums.dart'; - -part 'adapters.g.dart'; -part 'adapters.freezed.dart'; - -@HiveType(typeId: 2) -class SkipSegment { - @HiveField(0) - final int start; - @HiveField(1) - final int end; - SkipSegment(this.start, this.end); - - static String version = 'v1'; - static final boxName = "oss.krtirtho.spotube.skip_segments.$version"; - static LazyBox get box => Hive.lazyBox(boxName); - - SkipSegment.fromJson(Map json) - : start = json['start'], - end = json['end']; - - Map toJson() => { - 'start': start, - 'end': end, - }; -} - -@JsonEnum() -@HiveType(typeId: 5) -enum SourceType { - @HiveField(0) - youtube._("YouTube"), - - @HiveField(1) - youtubeMusic._("YouTube Music"), - - @HiveField(2) - jiosaavn._("JioSaavn"); - - final String label; - - const SourceType._(this.label); -} - -@JsonSerializable() -@HiveType(typeId: 6) -class SourceMatch { - @HiveField(0) - String id; - - @HiveField(1) - String sourceId; - - @HiveField(2) - SourceType sourceType; - - @HiveField(3) - DateTime createdAt; - - SourceMatch({ - required this.id, - required this.sourceId, - required this.sourceType, - required this.createdAt, - }); - - factory SourceMatch.fromJson(Map json) => - _$SourceMatchFromJson(json); - - Map toJson() => _$SourceMatchToJson(this); - - static String version = 'v1'; - static final boxName = "oss.krtirtho.spotube.source_matches.$version"; - - static LazyBox get box => Hive.lazyBox(boxName); -} - -@JsonSerializable() -class AuthenticationCredentials { - String cookie; - String accessToken; - DateTime expiration; - - AuthenticationCredentials({ - required this.cookie, - required this.accessToken, - required this.expiration, - }); - - factory AuthenticationCredentials.fromJson(Map json) { - return AuthenticationCredentials( - cookie: json['cookie'] as String, - accessToken: json['accessToken'] as String, - expiration: DateTime.parse(json['expiration'] as String), - ); - } - - Map toJson() { - return { - 'cookie': cookie, - 'accessToken': accessToken, - 'expiration': expiration.toIso8601String(), - }; - } -} - -@JsonEnum() -enum LayoutMode { - compact, - extended, - adaptive, -} - -@JsonEnum() -enum CloseBehavior { - minimizeToTray, - close, -} - -@JsonEnum() -enum AudioSource { - youtube, - piped, - jiosaavn; - - String get label => name[0].toUpperCase() + name.substring(1); -} - -@JsonEnum() -enum MusicCodec { - m4a._("M4a (Best for downloaded music)"), - weba._("WebA (Best for streamed music)\nDoesn't support audio metadata"); - - final String label; - const MusicCodec._(this.label); -} - -@JsonEnum() -enum SearchMode { - youtube._("YouTube"), - youtubeMusic._("YouTube Music"); - - final String label; - - const SearchMode._(this.label); - - factory SearchMode.fromString(String key) { - return SearchMode.values.firstWhere((e) => e.name == key); - } -} - -@freezed -class UserPreferences with _$UserPreferences { - const factory UserPreferences({ - @Default(SourceQualities.high) SourceQualities audioQuality, - @Default(true) bool albumColorSync, - @Default(false) bool amoledDarkTheme, - @Default(true) bool checkUpdate, - @Default(false) bool normalizeAudio, - @Default(false) bool showSystemTrayIcon, - @Default(false) bool skipNonMusic, - @Default(false) bool systemTitleBar, - @Default(CloseBehavior.close) CloseBehavior closeBehavior, - @Default(SpotubeColor(0xFF2196F3, name: "Blue")) - @JsonKey( - fromJson: UserPreferences._accentColorSchemeFromJson, - toJson: UserPreferences._accentColorSchemeToJson, - readValue: UserPreferences._accentColorSchemeReadValue, - ) - SpotubeColor accentColorScheme, - @Default(LayoutMode.adaptive) LayoutMode layoutMode, - @Default(Locale("system", "system")) - @JsonKey( - fromJson: UserPreferences._localeFromJson, - toJson: UserPreferences._localeToJson, - readValue: UserPreferences._localeReadValue, - ) - Locale locale, - @Default(Market.US) Market recommendationMarket, - @Default(SearchMode.youtube) SearchMode searchMode, - @Default("") String downloadLocation, - @Default([]) List localLibraryLocation, - @Default("https://pipedapi.kavin.rocks") String pipedInstance, - @Default(ThemeMode.system) ThemeMode themeMode, - @Default(AudioSource.youtube) AudioSource audioSource, - @Default(SourceCodecs.weba) SourceCodecs streamMusicCodec, - @Default(SourceCodecs.m4a) SourceCodecs downloadMusicCodec, - @Default(true) bool discordPresence, - @Default(true) bool endlessPlayback, - @Default(false) bool enableConnect, - }) = _UserPreferences; - factory UserPreferences.fromJson(Map json) => - _$UserPreferencesFromJson(json); - - factory UserPreferences.withDefaults() => UserPreferences.fromJson({}); - - static SpotubeColor _accentColorSchemeFromJson(Map json) { - return SpotubeColor.fromString(json["color"]); - } - - static Map? _accentColorSchemeReadValue( - Map json, String key) { - if (json[key] is String) { - return {"color": json[key]}; - } - - return json[key] as Map?; - } - - static Map _accentColorSchemeToJson(SpotubeColor color) { - return {"color": color.toString()}; - } - - static Locale _localeFromJson(Map json) { - return Locale(json["languageCode"], json["countryCode"]); - } - - static Map _localeToJson(Locale locale) { - return { - "languageCode": locale.languageCode, - "countryCode": locale.countryCode, - }; - } - - static Map? _localeReadValue( - Map json, String key) { - if (json[key] is String) { - final map = jsonDecode(json[key]); - return { - "languageCode": map["lc"], - "countryCode": map["cc"], - }; - } - - return json[key] as Map?; - } -} - -enum BlacklistedType { - artist, - track; - - static BlacklistedType fromName(String name) => - BlacklistedType.values.firstWhere((e) => e.name == name); -} - -class BlacklistedElement { - final String id; - final String name; - final BlacklistedType type; - - BlacklistedElement.fromJson(Map json) - : id = json['id'], - name = json['name'], - type = BlacklistedType.fromName(json['type']); - - Map toJson() => {'id': id, 'type': type.name, 'name': name}; -} - -@freezed -class PlaybackHistoryItem with _$PlaybackHistoryItem { - factory PlaybackHistoryItem.playlist({ - required DateTime date, - required PlaylistSimple playlist, - }) = PlaybackHistoryPlaylist; - - factory PlaybackHistoryItem.album({ - required DateTime date, - required AlbumSimple album, - }) = PlaybackHistoryAlbum; - - factory PlaybackHistoryItem.track({ - required DateTime date, - required Track track, - }) = PlaybackHistoryTrack; - - factory PlaybackHistoryItem.fromJson(Map json) => - _$PlaybackHistoryItemFromJson(json); -} - -class PlaybackHistoryState { - final List items; - const PlaybackHistoryState({this.items = const []}); - - factory PlaybackHistoryState.fromJson(Map json) { - return PlaybackHistoryState( - items: json["items"] - ?.map( - (json) => PlaybackHistoryItem.fromJson(json), - ) - .toList() - .cast() ?? - [], - ); - } -} - -class ScrobblerState { - final String username; - final String passwordHash; - - ScrobblerState({ - required this.username, - required this.passwordHash, - }); - - factory ScrobblerState.fromJson(Map json) { - return ScrobblerState( - username: json["username"], - passwordHash: json["passwordHash"], - ); - } -} diff --git a/lib/utils/migrations/adapters.freezed.dart b/lib/utils/migrations/adapters.freezed.dart deleted file mode 100644 index 40dfd662..00000000 --- a/lib/utils/migrations/adapters.freezed.dart +++ /dev/null @@ -1,1421 +0,0 @@ -// coverage:ignore-file -// GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: type=lint -// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark - -part of 'adapters.dart'; - -// ************************************************************************** -// FreezedGenerator -// ************************************************************************** - -T _$identity(T value) => value; - -final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); - -UserPreferences _$UserPreferencesFromJson(Map json) { - return _UserPreferences.fromJson(json); -} - -/// @nodoc -mixin _$UserPreferences { - SourceQualities get audioQuality => throw _privateConstructorUsedError; - bool get albumColorSync => throw _privateConstructorUsedError; - bool get amoledDarkTheme => throw _privateConstructorUsedError; - bool get checkUpdate => throw _privateConstructorUsedError; - bool get normalizeAudio => throw _privateConstructorUsedError; - bool get showSystemTrayIcon => throw _privateConstructorUsedError; - bool get skipNonMusic => throw _privateConstructorUsedError; - bool get systemTitleBar => throw _privateConstructorUsedError; - CloseBehavior get closeBehavior => throw _privateConstructorUsedError; - @JsonKey( - fromJson: UserPreferences._accentColorSchemeFromJson, - toJson: UserPreferences._accentColorSchemeToJson, - readValue: UserPreferences._accentColorSchemeReadValue) - SpotubeColor get accentColorScheme => throw _privateConstructorUsedError; - LayoutMode get layoutMode => throw _privateConstructorUsedError; - @JsonKey( - fromJson: UserPreferences._localeFromJson, - toJson: UserPreferences._localeToJson, - readValue: UserPreferences._localeReadValue) - Locale get locale => throw _privateConstructorUsedError; - Market get recommendationMarket => throw _privateConstructorUsedError; - SearchMode get searchMode => throw _privateConstructorUsedError; - String get downloadLocation => throw _privateConstructorUsedError; - List get localLibraryLocation => throw _privateConstructorUsedError; - String get pipedInstance => throw _privateConstructorUsedError; - ThemeMode get themeMode => throw _privateConstructorUsedError; - AudioSource get audioSource => throw _privateConstructorUsedError; - SourceCodecs get streamMusicCodec => throw _privateConstructorUsedError; - SourceCodecs get downloadMusicCodec => throw _privateConstructorUsedError; - bool get discordPresence => throw _privateConstructorUsedError; - bool get endlessPlayback => throw _privateConstructorUsedError; - bool get enableConnect => throw _privateConstructorUsedError; - - /// Serializes this UserPreferences to a JSON map. - Map toJson() => throw _privateConstructorUsedError; - - /// Create a copy of UserPreferences - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - $UserPreferencesCopyWith get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $UserPreferencesCopyWith<$Res> { - factory $UserPreferencesCopyWith( - UserPreferences value, $Res Function(UserPreferences) then) = - _$UserPreferencesCopyWithImpl<$Res, UserPreferences>; - @useResult - $Res call( - {SourceQualities audioQuality, - bool albumColorSync, - bool amoledDarkTheme, - bool checkUpdate, - bool normalizeAudio, - bool showSystemTrayIcon, - bool skipNonMusic, - bool systemTitleBar, - CloseBehavior closeBehavior, - @JsonKey( - fromJson: UserPreferences._accentColorSchemeFromJson, - toJson: UserPreferences._accentColorSchemeToJson, - readValue: UserPreferences._accentColorSchemeReadValue) - SpotubeColor accentColorScheme, - LayoutMode layoutMode, - @JsonKey( - fromJson: UserPreferences._localeFromJson, - toJson: UserPreferences._localeToJson, - readValue: UserPreferences._localeReadValue) - Locale locale, - Market recommendationMarket, - SearchMode searchMode, - String downloadLocation, - List localLibraryLocation, - String pipedInstance, - ThemeMode themeMode, - AudioSource audioSource, - SourceCodecs streamMusicCodec, - SourceCodecs downloadMusicCodec, - bool discordPresence, - bool endlessPlayback, - bool enableConnect}); -} - -/// @nodoc -class _$UserPreferencesCopyWithImpl<$Res, $Val extends UserPreferences> - implements $UserPreferencesCopyWith<$Res> { - _$UserPreferencesCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - /// Create a copy of UserPreferences - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? audioQuality = null, - Object? albumColorSync = null, - Object? amoledDarkTheme = null, - Object? checkUpdate = null, - Object? normalizeAudio = null, - Object? showSystemTrayIcon = null, - Object? skipNonMusic = null, - Object? systemTitleBar = null, - Object? closeBehavior = null, - Object? accentColorScheme = null, - Object? layoutMode = null, - Object? locale = null, - Object? recommendationMarket = null, - Object? searchMode = null, - Object? downloadLocation = null, - Object? localLibraryLocation = null, - Object? pipedInstance = null, - Object? themeMode = null, - Object? audioSource = null, - Object? streamMusicCodec = null, - Object? downloadMusicCodec = null, - Object? discordPresence = null, - Object? endlessPlayback = null, - Object? enableConnect = null, - }) { - return _then(_value.copyWith( - audioQuality: null == audioQuality - ? _value.audioQuality - : audioQuality // ignore: cast_nullable_to_non_nullable - as SourceQualities, - albumColorSync: null == albumColorSync - ? _value.albumColorSync - : albumColorSync // ignore: cast_nullable_to_non_nullable - as bool, - amoledDarkTheme: null == amoledDarkTheme - ? _value.amoledDarkTheme - : amoledDarkTheme // ignore: cast_nullable_to_non_nullable - as bool, - checkUpdate: null == checkUpdate - ? _value.checkUpdate - : checkUpdate // ignore: cast_nullable_to_non_nullable - as bool, - normalizeAudio: null == normalizeAudio - ? _value.normalizeAudio - : normalizeAudio // ignore: cast_nullable_to_non_nullable - as bool, - showSystemTrayIcon: null == showSystemTrayIcon - ? _value.showSystemTrayIcon - : showSystemTrayIcon // ignore: cast_nullable_to_non_nullable - as bool, - skipNonMusic: null == skipNonMusic - ? _value.skipNonMusic - : skipNonMusic // ignore: cast_nullable_to_non_nullable - as bool, - systemTitleBar: null == systemTitleBar - ? _value.systemTitleBar - : systemTitleBar // ignore: cast_nullable_to_non_nullable - as bool, - closeBehavior: null == closeBehavior - ? _value.closeBehavior - : closeBehavior // ignore: cast_nullable_to_non_nullable - as CloseBehavior, - accentColorScheme: null == accentColorScheme - ? _value.accentColorScheme - : accentColorScheme // ignore: cast_nullable_to_non_nullable - as SpotubeColor, - layoutMode: null == layoutMode - ? _value.layoutMode - : layoutMode // ignore: cast_nullable_to_non_nullable - as LayoutMode, - locale: null == locale - ? _value.locale - : locale // ignore: cast_nullable_to_non_nullable - as Locale, - recommendationMarket: null == recommendationMarket - ? _value.recommendationMarket - : recommendationMarket // ignore: cast_nullable_to_non_nullable - as Market, - searchMode: null == searchMode - ? _value.searchMode - : searchMode // ignore: cast_nullable_to_non_nullable - as SearchMode, - downloadLocation: null == downloadLocation - ? _value.downloadLocation - : downloadLocation // ignore: cast_nullable_to_non_nullable - as String, - localLibraryLocation: null == localLibraryLocation - ? _value.localLibraryLocation - : localLibraryLocation // ignore: cast_nullable_to_non_nullable - as List, - pipedInstance: null == pipedInstance - ? _value.pipedInstance - : pipedInstance // ignore: cast_nullable_to_non_nullable - as String, - themeMode: null == themeMode - ? _value.themeMode - : themeMode // ignore: cast_nullable_to_non_nullable - as ThemeMode, - audioSource: null == audioSource - ? _value.audioSource - : audioSource // ignore: cast_nullable_to_non_nullable - as AudioSource, - streamMusicCodec: null == streamMusicCodec - ? _value.streamMusicCodec - : streamMusicCodec // ignore: cast_nullable_to_non_nullable - as SourceCodecs, - downloadMusicCodec: null == downloadMusicCodec - ? _value.downloadMusicCodec - : downloadMusicCodec // ignore: cast_nullable_to_non_nullable - as SourceCodecs, - discordPresence: null == discordPresence - ? _value.discordPresence - : discordPresence // ignore: cast_nullable_to_non_nullable - as bool, - endlessPlayback: null == endlessPlayback - ? _value.endlessPlayback - : endlessPlayback // ignore: cast_nullable_to_non_nullable - as bool, - enableConnect: null == enableConnect - ? _value.enableConnect - : enableConnect // ignore: cast_nullable_to_non_nullable - as bool, - ) as $Val); - } -} - -/// @nodoc -abstract class _$$UserPreferencesImplCopyWith<$Res> - implements $UserPreferencesCopyWith<$Res> { - factory _$$UserPreferencesImplCopyWith(_$UserPreferencesImpl value, - $Res Function(_$UserPreferencesImpl) then) = - __$$UserPreferencesImplCopyWithImpl<$Res>; - @override - @useResult - $Res call( - {SourceQualities audioQuality, - bool albumColorSync, - bool amoledDarkTheme, - bool checkUpdate, - bool normalizeAudio, - bool showSystemTrayIcon, - bool skipNonMusic, - bool systemTitleBar, - CloseBehavior closeBehavior, - @JsonKey( - fromJson: UserPreferences._accentColorSchemeFromJson, - toJson: UserPreferences._accentColorSchemeToJson, - readValue: UserPreferences._accentColorSchemeReadValue) - SpotubeColor accentColorScheme, - LayoutMode layoutMode, - @JsonKey( - fromJson: UserPreferences._localeFromJson, - toJson: UserPreferences._localeToJson, - readValue: UserPreferences._localeReadValue) - Locale locale, - Market recommendationMarket, - SearchMode searchMode, - String downloadLocation, - List localLibraryLocation, - String pipedInstance, - ThemeMode themeMode, - AudioSource audioSource, - SourceCodecs streamMusicCodec, - SourceCodecs downloadMusicCodec, - bool discordPresence, - bool endlessPlayback, - bool enableConnect}); -} - -/// @nodoc -class __$$UserPreferencesImplCopyWithImpl<$Res> - extends _$UserPreferencesCopyWithImpl<$Res, _$UserPreferencesImpl> - implements _$$UserPreferencesImplCopyWith<$Res> { - __$$UserPreferencesImplCopyWithImpl( - _$UserPreferencesImpl _value, $Res Function(_$UserPreferencesImpl) _then) - : super(_value, _then); - - /// Create a copy of UserPreferences - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? audioQuality = null, - Object? albumColorSync = null, - Object? amoledDarkTheme = null, - Object? checkUpdate = null, - Object? normalizeAudio = null, - Object? showSystemTrayIcon = null, - Object? skipNonMusic = null, - Object? systemTitleBar = null, - Object? closeBehavior = null, - Object? accentColorScheme = null, - Object? layoutMode = null, - Object? locale = null, - Object? recommendationMarket = null, - Object? searchMode = null, - Object? downloadLocation = null, - Object? localLibraryLocation = null, - Object? pipedInstance = null, - Object? themeMode = null, - Object? audioSource = null, - Object? streamMusicCodec = null, - Object? downloadMusicCodec = null, - Object? discordPresence = null, - Object? endlessPlayback = null, - Object? enableConnect = null, - }) { - return _then(_$UserPreferencesImpl( - audioQuality: null == audioQuality - ? _value.audioQuality - : audioQuality // ignore: cast_nullable_to_non_nullable - as SourceQualities, - albumColorSync: null == albumColorSync - ? _value.albumColorSync - : albumColorSync // ignore: cast_nullable_to_non_nullable - as bool, - amoledDarkTheme: null == amoledDarkTheme - ? _value.amoledDarkTheme - : amoledDarkTheme // ignore: cast_nullable_to_non_nullable - as bool, - checkUpdate: null == checkUpdate - ? _value.checkUpdate - : checkUpdate // ignore: cast_nullable_to_non_nullable - as bool, - normalizeAudio: null == normalizeAudio - ? _value.normalizeAudio - : normalizeAudio // ignore: cast_nullable_to_non_nullable - as bool, - showSystemTrayIcon: null == showSystemTrayIcon - ? _value.showSystemTrayIcon - : showSystemTrayIcon // ignore: cast_nullable_to_non_nullable - as bool, - skipNonMusic: null == skipNonMusic - ? _value.skipNonMusic - : skipNonMusic // ignore: cast_nullable_to_non_nullable - as bool, - systemTitleBar: null == systemTitleBar - ? _value.systemTitleBar - : systemTitleBar // ignore: cast_nullable_to_non_nullable - as bool, - closeBehavior: null == closeBehavior - ? _value.closeBehavior - : closeBehavior // ignore: cast_nullable_to_non_nullable - as CloseBehavior, - accentColorScheme: null == accentColorScheme - ? _value.accentColorScheme - : accentColorScheme // ignore: cast_nullable_to_non_nullable - as SpotubeColor, - layoutMode: null == layoutMode - ? _value.layoutMode - : layoutMode // ignore: cast_nullable_to_non_nullable - as LayoutMode, - locale: null == locale - ? _value.locale - : locale // ignore: cast_nullable_to_non_nullable - as Locale, - recommendationMarket: null == recommendationMarket - ? _value.recommendationMarket - : recommendationMarket // ignore: cast_nullable_to_non_nullable - as Market, - searchMode: null == searchMode - ? _value.searchMode - : searchMode // ignore: cast_nullable_to_non_nullable - as SearchMode, - downloadLocation: null == downloadLocation - ? _value.downloadLocation - : downloadLocation // ignore: cast_nullable_to_non_nullable - as String, - localLibraryLocation: null == localLibraryLocation - ? _value._localLibraryLocation - : localLibraryLocation // ignore: cast_nullable_to_non_nullable - as List, - pipedInstance: null == pipedInstance - ? _value.pipedInstance - : pipedInstance // ignore: cast_nullable_to_non_nullable - as String, - themeMode: null == themeMode - ? _value.themeMode - : themeMode // ignore: cast_nullable_to_non_nullable - as ThemeMode, - audioSource: null == audioSource - ? _value.audioSource - : audioSource // ignore: cast_nullable_to_non_nullable - as AudioSource, - streamMusicCodec: null == streamMusicCodec - ? _value.streamMusicCodec - : streamMusicCodec // ignore: cast_nullable_to_non_nullable - as SourceCodecs, - downloadMusicCodec: null == downloadMusicCodec - ? _value.downloadMusicCodec - : downloadMusicCodec // ignore: cast_nullable_to_non_nullable - as SourceCodecs, - discordPresence: null == discordPresence - ? _value.discordPresence - : discordPresence // ignore: cast_nullable_to_non_nullable - as bool, - endlessPlayback: null == endlessPlayback - ? _value.endlessPlayback - : endlessPlayback // ignore: cast_nullable_to_non_nullable - as bool, - enableConnect: null == enableConnect - ? _value.enableConnect - : enableConnect // ignore: cast_nullable_to_non_nullable - as bool, - )); - } -} - -/// @nodoc -@JsonSerializable() -class _$UserPreferencesImpl implements _UserPreferences { - const _$UserPreferencesImpl( - {this.audioQuality = SourceQualities.high, - this.albumColorSync = true, - this.amoledDarkTheme = false, - this.checkUpdate = true, - this.normalizeAudio = false, - this.showSystemTrayIcon = false, - this.skipNonMusic = false, - this.systemTitleBar = false, - this.closeBehavior = CloseBehavior.close, - @JsonKey( - fromJson: UserPreferences._accentColorSchemeFromJson, - toJson: UserPreferences._accentColorSchemeToJson, - readValue: UserPreferences._accentColorSchemeReadValue) - this.accentColorScheme = const SpotubeColor(0xFF2196F3, name: "Blue"), - this.layoutMode = LayoutMode.adaptive, - @JsonKey( - fromJson: UserPreferences._localeFromJson, - toJson: UserPreferences._localeToJson, - readValue: UserPreferences._localeReadValue) - this.locale = const Locale("system", "system"), - this.recommendationMarket = Market.US, - this.searchMode = SearchMode.youtube, - this.downloadLocation = "", - final List localLibraryLocation = const [], - this.pipedInstance = "https://pipedapi.kavin.rocks", - this.themeMode = ThemeMode.system, - this.audioSource = AudioSource.youtube, - this.streamMusicCodec = SourceCodecs.weba, - this.downloadMusicCodec = SourceCodecs.m4a, - this.discordPresence = true, - this.endlessPlayback = true, - this.enableConnect = false}) - : _localLibraryLocation = localLibraryLocation; - - factory _$UserPreferencesImpl.fromJson(Map json) => - _$$UserPreferencesImplFromJson(json); - - @override - @JsonKey() - final SourceQualities audioQuality; - @override - @JsonKey() - final bool albumColorSync; - @override - @JsonKey() - final bool amoledDarkTheme; - @override - @JsonKey() - final bool checkUpdate; - @override - @JsonKey() - final bool normalizeAudio; - @override - @JsonKey() - final bool showSystemTrayIcon; - @override - @JsonKey() - final bool skipNonMusic; - @override - @JsonKey() - final bool systemTitleBar; - @override - @JsonKey() - final CloseBehavior closeBehavior; - @override - @JsonKey( - fromJson: UserPreferences._accentColorSchemeFromJson, - toJson: UserPreferences._accentColorSchemeToJson, - readValue: UserPreferences._accentColorSchemeReadValue) - final SpotubeColor accentColorScheme; - @override - @JsonKey() - final LayoutMode layoutMode; - @override - @JsonKey( - fromJson: UserPreferences._localeFromJson, - toJson: UserPreferences._localeToJson, - readValue: UserPreferences._localeReadValue) - final Locale locale; - @override - @JsonKey() - final Market recommendationMarket; - @override - @JsonKey() - final SearchMode searchMode; - @override - @JsonKey() - final String downloadLocation; - final List _localLibraryLocation; - @override - @JsonKey() - List get localLibraryLocation { - if (_localLibraryLocation is EqualUnmodifiableListView) - return _localLibraryLocation; - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_localLibraryLocation); - } - - @override - @JsonKey() - final String pipedInstance; - @override - @JsonKey() - final ThemeMode themeMode; - @override - @JsonKey() - final AudioSource audioSource; - @override - @JsonKey() - final SourceCodecs streamMusicCodec; - @override - @JsonKey() - final SourceCodecs downloadMusicCodec; - @override - @JsonKey() - final bool discordPresence; - @override - @JsonKey() - final bool endlessPlayback; - @override - @JsonKey() - final bool enableConnect; - - @override - String toString() { - return 'UserPreferences(audioQuality: $audioQuality, albumColorSync: $albumColorSync, amoledDarkTheme: $amoledDarkTheme, checkUpdate: $checkUpdate, normalizeAudio: $normalizeAudio, showSystemTrayIcon: $showSystemTrayIcon, skipNonMusic: $skipNonMusic, systemTitleBar: $systemTitleBar, closeBehavior: $closeBehavior, accentColorScheme: $accentColorScheme, layoutMode: $layoutMode, locale: $locale, recommendationMarket: $recommendationMarket, searchMode: $searchMode, downloadLocation: $downloadLocation, localLibraryLocation: $localLibraryLocation, pipedInstance: $pipedInstance, themeMode: $themeMode, audioSource: $audioSource, streamMusicCodec: $streamMusicCodec, downloadMusicCodec: $downloadMusicCodec, discordPresence: $discordPresence, endlessPlayback: $endlessPlayback, enableConnect: $enableConnect)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$UserPreferencesImpl && - (identical(other.audioQuality, audioQuality) || - other.audioQuality == audioQuality) && - (identical(other.albumColorSync, albumColorSync) || - other.albumColorSync == albumColorSync) && - (identical(other.amoledDarkTheme, amoledDarkTheme) || - other.amoledDarkTheme == amoledDarkTheme) && - (identical(other.checkUpdate, checkUpdate) || - other.checkUpdate == checkUpdate) && - (identical(other.normalizeAudio, normalizeAudio) || - other.normalizeAudio == normalizeAudio) && - (identical(other.showSystemTrayIcon, showSystemTrayIcon) || - other.showSystemTrayIcon == showSystemTrayIcon) && - (identical(other.skipNonMusic, skipNonMusic) || - other.skipNonMusic == skipNonMusic) && - (identical(other.systemTitleBar, systemTitleBar) || - other.systemTitleBar == systemTitleBar) && - (identical(other.closeBehavior, closeBehavior) || - other.closeBehavior == closeBehavior) && - (identical(other.accentColorScheme, accentColorScheme) || - other.accentColorScheme == accentColorScheme) && - (identical(other.layoutMode, layoutMode) || - other.layoutMode == layoutMode) && - (identical(other.locale, locale) || other.locale == locale) && - (identical(other.recommendationMarket, recommendationMarket) || - other.recommendationMarket == recommendationMarket) && - (identical(other.searchMode, searchMode) || - other.searchMode == searchMode) && - (identical(other.downloadLocation, downloadLocation) || - other.downloadLocation == downloadLocation) && - const DeepCollectionEquality() - .equals(other._localLibraryLocation, _localLibraryLocation) && - (identical(other.pipedInstance, pipedInstance) || - other.pipedInstance == pipedInstance) && - (identical(other.themeMode, themeMode) || - other.themeMode == themeMode) && - (identical(other.audioSource, audioSource) || - other.audioSource == audioSource) && - (identical(other.streamMusicCodec, streamMusicCodec) || - other.streamMusicCodec == streamMusicCodec) && - (identical(other.downloadMusicCodec, downloadMusicCodec) || - other.downloadMusicCodec == downloadMusicCodec) && - (identical(other.discordPresence, discordPresence) || - other.discordPresence == discordPresence) && - (identical(other.endlessPlayback, endlessPlayback) || - other.endlessPlayback == endlessPlayback) && - (identical(other.enableConnect, enableConnect) || - other.enableConnect == enableConnect)); - } - - @JsonKey(includeFromJson: false, includeToJson: false) - @override - int get hashCode => Object.hashAll([ - runtimeType, - audioQuality, - albumColorSync, - amoledDarkTheme, - checkUpdate, - normalizeAudio, - showSystemTrayIcon, - skipNonMusic, - systemTitleBar, - closeBehavior, - accentColorScheme, - layoutMode, - locale, - recommendationMarket, - searchMode, - downloadLocation, - const DeepCollectionEquality().hash(_localLibraryLocation), - pipedInstance, - themeMode, - audioSource, - streamMusicCodec, - downloadMusicCodec, - discordPresence, - endlessPlayback, - enableConnect - ]); - - /// Create a copy of UserPreferences - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - @override - @pragma('vm:prefer-inline') - _$$UserPreferencesImplCopyWith<_$UserPreferencesImpl> get copyWith => - __$$UserPreferencesImplCopyWithImpl<_$UserPreferencesImpl>( - this, _$identity); - - @override - Map toJson() { - return _$$UserPreferencesImplToJson( - this, - ); - } -} - -abstract class _UserPreferences implements UserPreferences { - const factory _UserPreferences( - {final SourceQualities audioQuality, - final bool albumColorSync, - final bool amoledDarkTheme, - final bool checkUpdate, - final bool normalizeAudio, - final bool showSystemTrayIcon, - final bool skipNonMusic, - final bool systemTitleBar, - final CloseBehavior closeBehavior, - @JsonKey( - fromJson: UserPreferences._accentColorSchemeFromJson, - toJson: UserPreferences._accentColorSchemeToJson, - readValue: UserPreferences._accentColorSchemeReadValue) - final SpotubeColor accentColorScheme, - final LayoutMode layoutMode, - @JsonKey( - fromJson: UserPreferences._localeFromJson, - toJson: UserPreferences._localeToJson, - readValue: UserPreferences._localeReadValue) - final Locale locale, - final Market recommendationMarket, - final SearchMode searchMode, - final String downloadLocation, - final List localLibraryLocation, - final String pipedInstance, - final ThemeMode themeMode, - final AudioSource audioSource, - final SourceCodecs streamMusicCodec, - final SourceCodecs downloadMusicCodec, - final bool discordPresence, - final bool endlessPlayback, - final bool enableConnect}) = _$UserPreferencesImpl; - - factory _UserPreferences.fromJson(Map json) = - _$UserPreferencesImpl.fromJson; - - @override - SourceQualities get audioQuality; - @override - bool get albumColorSync; - @override - bool get amoledDarkTheme; - @override - bool get checkUpdate; - @override - bool get normalizeAudio; - @override - bool get showSystemTrayIcon; - @override - bool get skipNonMusic; - @override - bool get systemTitleBar; - @override - CloseBehavior get closeBehavior; - @override - @JsonKey( - fromJson: UserPreferences._accentColorSchemeFromJson, - toJson: UserPreferences._accentColorSchemeToJson, - readValue: UserPreferences._accentColorSchemeReadValue) - SpotubeColor get accentColorScheme; - @override - LayoutMode get layoutMode; - @override - @JsonKey( - fromJson: UserPreferences._localeFromJson, - toJson: UserPreferences._localeToJson, - readValue: UserPreferences._localeReadValue) - Locale get locale; - @override - Market get recommendationMarket; - @override - SearchMode get searchMode; - @override - String get downloadLocation; - @override - List get localLibraryLocation; - @override - String get pipedInstance; - @override - ThemeMode get themeMode; - @override - AudioSource get audioSource; - @override - SourceCodecs get streamMusicCodec; - @override - SourceCodecs get downloadMusicCodec; - @override - bool get discordPresence; - @override - bool get endlessPlayback; - @override - bool get enableConnect; - - /// Create a copy of UserPreferences - /// with the given fields replaced by the non-null parameter values. - @override - @JsonKey(includeFromJson: false, includeToJson: false) - _$$UserPreferencesImplCopyWith<_$UserPreferencesImpl> get copyWith => - throw _privateConstructorUsedError; -} - -PlaybackHistoryItem _$PlaybackHistoryItemFromJson(Map json) { - switch (json['runtimeType']) { - case 'playlist': - return PlaybackHistoryPlaylist.fromJson(json); - case 'album': - return PlaybackHistoryAlbum.fromJson(json); - case 'track': - return PlaybackHistoryTrack.fromJson(json); - - default: - throw CheckedFromJsonException(json, 'runtimeType', 'PlaybackHistoryItem', - 'Invalid union type "${json['runtimeType']}"!'); - } -} - -/// @nodoc -mixin _$PlaybackHistoryItem { - DateTime get date => throw _privateConstructorUsedError; - @optionalTypeArgs - TResult when({ - required TResult Function(DateTime date, PlaylistSimple playlist) playlist, - required TResult Function(DateTime date, AlbumSimple album) album, - required TResult Function(DateTime date, Track track) track, - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult? whenOrNull({ - TResult? Function(DateTime date, PlaylistSimple playlist)? playlist, - TResult? Function(DateTime date, AlbumSimple album)? album, - TResult? Function(DateTime date, Track track)? track, - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult maybeWhen({ - TResult Function(DateTime date, PlaylistSimple playlist)? playlist, - TResult Function(DateTime date, AlbumSimple album)? album, - TResult Function(DateTime date, Track track)? track, - required TResult orElse(), - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult map({ - required TResult Function(PlaybackHistoryPlaylist value) playlist, - required TResult Function(PlaybackHistoryAlbum value) album, - required TResult Function(PlaybackHistoryTrack value) track, - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult? mapOrNull({ - TResult? Function(PlaybackHistoryPlaylist value)? playlist, - TResult? Function(PlaybackHistoryAlbum value)? album, - TResult? Function(PlaybackHistoryTrack value)? track, - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult maybeMap({ - TResult Function(PlaybackHistoryPlaylist value)? playlist, - TResult Function(PlaybackHistoryAlbum value)? album, - TResult Function(PlaybackHistoryTrack value)? track, - required TResult orElse(), - }) => - throw _privateConstructorUsedError; - - /// Serializes this PlaybackHistoryItem to a JSON map. - Map toJson() => throw _privateConstructorUsedError; - - /// Create a copy of PlaybackHistoryItem - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - $PlaybackHistoryItemCopyWith get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $PlaybackHistoryItemCopyWith<$Res> { - factory $PlaybackHistoryItemCopyWith( - PlaybackHistoryItem value, $Res Function(PlaybackHistoryItem) then) = - _$PlaybackHistoryItemCopyWithImpl<$Res, PlaybackHistoryItem>; - @useResult - $Res call({DateTime date}); -} - -/// @nodoc -class _$PlaybackHistoryItemCopyWithImpl<$Res, $Val extends PlaybackHistoryItem> - implements $PlaybackHistoryItemCopyWith<$Res> { - _$PlaybackHistoryItemCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - /// Create a copy of PlaybackHistoryItem - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? date = null, - }) { - return _then(_value.copyWith( - date: null == date - ? _value.date - : date // ignore: cast_nullable_to_non_nullable - as DateTime, - ) as $Val); - } -} - -/// @nodoc -abstract class _$$PlaybackHistoryPlaylistImplCopyWith<$Res> - implements $PlaybackHistoryItemCopyWith<$Res> { - factory _$$PlaybackHistoryPlaylistImplCopyWith( - _$PlaybackHistoryPlaylistImpl value, - $Res Function(_$PlaybackHistoryPlaylistImpl) then) = - __$$PlaybackHistoryPlaylistImplCopyWithImpl<$Res>; - @override - @useResult - $Res call({DateTime date, PlaylistSimple playlist}); -} - -/// @nodoc -class __$$PlaybackHistoryPlaylistImplCopyWithImpl<$Res> - extends _$PlaybackHistoryItemCopyWithImpl<$Res, - _$PlaybackHistoryPlaylistImpl> - implements _$$PlaybackHistoryPlaylistImplCopyWith<$Res> { - __$$PlaybackHistoryPlaylistImplCopyWithImpl( - _$PlaybackHistoryPlaylistImpl _value, - $Res Function(_$PlaybackHistoryPlaylistImpl) _then) - : super(_value, _then); - - /// Create a copy of PlaybackHistoryItem - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? date = null, - Object? playlist = null, - }) { - return _then(_$PlaybackHistoryPlaylistImpl( - date: null == date - ? _value.date - : date // ignore: cast_nullable_to_non_nullable - as DateTime, - playlist: null == playlist - ? _value.playlist - : playlist // ignore: cast_nullable_to_non_nullable - as PlaylistSimple, - )); - } -} - -/// @nodoc -@JsonSerializable() -class _$PlaybackHistoryPlaylistImpl implements PlaybackHistoryPlaylist { - _$PlaybackHistoryPlaylistImpl( - {required this.date, required this.playlist, final String? $type}) - : $type = $type ?? 'playlist'; - - factory _$PlaybackHistoryPlaylistImpl.fromJson(Map json) => - _$$PlaybackHistoryPlaylistImplFromJson(json); - - @override - final DateTime date; - @override - final PlaylistSimple playlist; - - @JsonKey(name: 'runtimeType') - final String $type; - - @override - String toString() { - return 'PlaybackHistoryItem.playlist(date: $date, playlist: $playlist)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$PlaybackHistoryPlaylistImpl && - (identical(other.date, date) || other.date == date) && - (identical(other.playlist, playlist) || - other.playlist == playlist)); - } - - @JsonKey(includeFromJson: false, includeToJson: false) - @override - int get hashCode => Object.hash(runtimeType, date, playlist); - - /// Create a copy of PlaybackHistoryItem - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - @override - @pragma('vm:prefer-inline') - _$$PlaybackHistoryPlaylistImplCopyWith<_$PlaybackHistoryPlaylistImpl> - get copyWith => __$$PlaybackHistoryPlaylistImplCopyWithImpl< - _$PlaybackHistoryPlaylistImpl>(this, _$identity); - - @override - @optionalTypeArgs - TResult when({ - required TResult Function(DateTime date, PlaylistSimple playlist) playlist, - required TResult Function(DateTime date, AlbumSimple album) album, - required TResult Function(DateTime date, Track track) track, - }) { - return playlist(date, this.playlist); - } - - @override - @optionalTypeArgs - TResult? whenOrNull({ - TResult? Function(DateTime date, PlaylistSimple playlist)? playlist, - TResult? Function(DateTime date, AlbumSimple album)? album, - TResult? Function(DateTime date, Track track)? track, - }) { - return playlist?.call(date, this.playlist); - } - - @override - @optionalTypeArgs - TResult maybeWhen({ - TResult Function(DateTime date, PlaylistSimple playlist)? playlist, - TResult Function(DateTime date, AlbumSimple album)? album, - TResult Function(DateTime date, Track track)? track, - required TResult orElse(), - }) { - if (playlist != null) { - return playlist(date, this.playlist); - } - return orElse(); - } - - @override - @optionalTypeArgs - TResult map({ - required TResult Function(PlaybackHistoryPlaylist value) playlist, - required TResult Function(PlaybackHistoryAlbum value) album, - required TResult Function(PlaybackHistoryTrack value) track, - }) { - return playlist(this); - } - - @override - @optionalTypeArgs - TResult? mapOrNull({ - TResult? Function(PlaybackHistoryPlaylist value)? playlist, - TResult? Function(PlaybackHistoryAlbum value)? album, - TResult? Function(PlaybackHistoryTrack value)? track, - }) { - return playlist?.call(this); - } - - @override - @optionalTypeArgs - TResult maybeMap({ - TResult Function(PlaybackHistoryPlaylist value)? playlist, - TResult Function(PlaybackHistoryAlbum value)? album, - TResult Function(PlaybackHistoryTrack value)? track, - required TResult orElse(), - }) { - if (playlist != null) { - return playlist(this); - } - return orElse(); - } - - @override - Map toJson() { - return _$$PlaybackHistoryPlaylistImplToJson( - this, - ); - } -} - -abstract class PlaybackHistoryPlaylist implements PlaybackHistoryItem { - factory PlaybackHistoryPlaylist( - {required final DateTime date, - required final PlaylistSimple playlist}) = _$PlaybackHistoryPlaylistImpl; - - factory PlaybackHistoryPlaylist.fromJson(Map json) = - _$PlaybackHistoryPlaylistImpl.fromJson; - - @override - DateTime get date; - PlaylistSimple get playlist; - - /// Create a copy of PlaybackHistoryItem - /// with the given fields replaced by the non-null parameter values. - @override - @JsonKey(includeFromJson: false, includeToJson: false) - _$$PlaybackHistoryPlaylistImplCopyWith<_$PlaybackHistoryPlaylistImpl> - get copyWith => throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class _$$PlaybackHistoryAlbumImplCopyWith<$Res> - implements $PlaybackHistoryItemCopyWith<$Res> { - factory _$$PlaybackHistoryAlbumImplCopyWith(_$PlaybackHistoryAlbumImpl value, - $Res Function(_$PlaybackHistoryAlbumImpl) then) = - __$$PlaybackHistoryAlbumImplCopyWithImpl<$Res>; - @override - @useResult - $Res call({DateTime date, AlbumSimple album}); -} - -/// @nodoc -class __$$PlaybackHistoryAlbumImplCopyWithImpl<$Res> - extends _$PlaybackHistoryItemCopyWithImpl<$Res, _$PlaybackHistoryAlbumImpl> - implements _$$PlaybackHistoryAlbumImplCopyWith<$Res> { - __$$PlaybackHistoryAlbumImplCopyWithImpl(_$PlaybackHistoryAlbumImpl _value, - $Res Function(_$PlaybackHistoryAlbumImpl) _then) - : super(_value, _then); - - /// Create a copy of PlaybackHistoryItem - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? date = null, - Object? album = null, - }) { - return _then(_$PlaybackHistoryAlbumImpl( - date: null == date - ? _value.date - : date // ignore: cast_nullable_to_non_nullable - as DateTime, - album: null == album - ? _value.album - : album // ignore: cast_nullable_to_non_nullable - as AlbumSimple, - )); - } -} - -/// @nodoc -@JsonSerializable() -class _$PlaybackHistoryAlbumImpl implements PlaybackHistoryAlbum { - _$PlaybackHistoryAlbumImpl( - {required this.date, required this.album, final String? $type}) - : $type = $type ?? 'album'; - - factory _$PlaybackHistoryAlbumImpl.fromJson(Map json) => - _$$PlaybackHistoryAlbumImplFromJson(json); - - @override - final DateTime date; - @override - final AlbumSimple album; - - @JsonKey(name: 'runtimeType') - final String $type; - - @override - String toString() { - return 'PlaybackHistoryItem.album(date: $date, album: $album)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$PlaybackHistoryAlbumImpl && - (identical(other.date, date) || other.date == date) && - (identical(other.album, album) || other.album == album)); - } - - @JsonKey(includeFromJson: false, includeToJson: false) - @override - int get hashCode => Object.hash(runtimeType, date, album); - - /// Create a copy of PlaybackHistoryItem - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - @override - @pragma('vm:prefer-inline') - _$$PlaybackHistoryAlbumImplCopyWith<_$PlaybackHistoryAlbumImpl> - get copyWith => - __$$PlaybackHistoryAlbumImplCopyWithImpl<_$PlaybackHistoryAlbumImpl>( - this, _$identity); - - @override - @optionalTypeArgs - TResult when({ - required TResult Function(DateTime date, PlaylistSimple playlist) playlist, - required TResult Function(DateTime date, AlbumSimple album) album, - required TResult Function(DateTime date, Track track) track, - }) { - return album(date, this.album); - } - - @override - @optionalTypeArgs - TResult? whenOrNull({ - TResult? Function(DateTime date, PlaylistSimple playlist)? playlist, - TResult? Function(DateTime date, AlbumSimple album)? album, - TResult? Function(DateTime date, Track track)? track, - }) { - return album?.call(date, this.album); - } - - @override - @optionalTypeArgs - TResult maybeWhen({ - TResult Function(DateTime date, PlaylistSimple playlist)? playlist, - TResult Function(DateTime date, AlbumSimple album)? album, - TResult Function(DateTime date, Track track)? track, - required TResult orElse(), - }) { - if (album != null) { - return album(date, this.album); - } - return orElse(); - } - - @override - @optionalTypeArgs - TResult map({ - required TResult Function(PlaybackHistoryPlaylist value) playlist, - required TResult Function(PlaybackHistoryAlbum value) album, - required TResult Function(PlaybackHistoryTrack value) track, - }) { - return album(this); - } - - @override - @optionalTypeArgs - TResult? mapOrNull({ - TResult? Function(PlaybackHistoryPlaylist value)? playlist, - TResult? Function(PlaybackHistoryAlbum value)? album, - TResult? Function(PlaybackHistoryTrack value)? track, - }) { - return album?.call(this); - } - - @override - @optionalTypeArgs - TResult maybeMap({ - TResult Function(PlaybackHistoryPlaylist value)? playlist, - TResult Function(PlaybackHistoryAlbum value)? album, - TResult Function(PlaybackHistoryTrack value)? track, - required TResult orElse(), - }) { - if (album != null) { - return album(this); - } - return orElse(); - } - - @override - Map toJson() { - return _$$PlaybackHistoryAlbumImplToJson( - this, - ); - } -} - -abstract class PlaybackHistoryAlbum implements PlaybackHistoryItem { - factory PlaybackHistoryAlbum( - {required final DateTime date, - required final AlbumSimple album}) = _$PlaybackHistoryAlbumImpl; - - factory PlaybackHistoryAlbum.fromJson(Map json) = - _$PlaybackHistoryAlbumImpl.fromJson; - - @override - DateTime get date; - AlbumSimple get album; - - /// Create a copy of PlaybackHistoryItem - /// with the given fields replaced by the non-null parameter values. - @override - @JsonKey(includeFromJson: false, includeToJson: false) - _$$PlaybackHistoryAlbumImplCopyWith<_$PlaybackHistoryAlbumImpl> - get copyWith => throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class _$$PlaybackHistoryTrackImplCopyWith<$Res> - implements $PlaybackHistoryItemCopyWith<$Res> { - factory _$$PlaybackHistoryTrackImplCopyWith(_$PlaybackHistoryTrackImpl value, - $Res Function(_$PlaybackHistoryTrackImpl) then) = - __$$PlaybackHistoryTrackImplCopyWithImpl<$Res>; - @override - @useResult - $Res call({DateTime date, Track track}); -} - -/// @nodoc -class __$$PlaybackHistoryTrackImplCopyWithImpl<$Res> - extends _$PlaybackHistoryItemCopyWithImpl<$Res, _$PlaybackHistoryTrackImpl> - implements _$$PlaybackHistoryTrackImplCopyWith<$Res> { - __$$PlaybackHistoryTrackImplCopyWithImpl(_$PlaybackHistoryTrackImpl _value, - $Res Function(_$PlaybackHistoryTrackImpl) _then) - : super(_value, _then); - - /// Create a copy of PlaybackHistoryItem - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? date = null, - Object? track = null, - }) { - return _then(_$PlaybackHistoryTrackImpl( - date: null == date - ? _value.date - : date // ignore: cast_nullable_to_non_nullable - as DateTime, - track: null == track - ? _value.track - : track // ignore: cast_nullable_to_non_nullable - as Track, - )); - } -} - -/// @nodoc -@JsonSerializable() -class _$PlaybackHistoryTrackImpl implements PlaybackHistoryTrack { - _$PlaybackHistoryTrackImpl( - {required this.date, required this.track, final String? $type}) - : $type = $type ?? 'track'; - - factory _$PlaybackHistoryTrackImpl.fromJson(Map json) => - _$$PlaybackHistoryTrackImplFromJson(json); - - @override - final DateTime date; - @override - final Track track; - - @JsonKey(name: 'runtimeType') - final String $type; - - @override - String toString() { - return 'PlaybackHistoryItem.track(date: $date, track: $track)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$PlaybackHistoryTrackImpl && - (identical(other.date, date) || other.date == date) && - (identical(other.track, track) || other.track == track)); - } - - @JsonKey(includeFromJson: false, includeToJson: false) - @override - int get hashCode => Object.hash(runtimeType, date, track); - - /// Create a copy of PlaybackHistoryItem - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - @override - @pragma('vm:prefer-inline') - _$$PlaybackHistoryTrackImplCopyWith<_$PlaybackHistoryTrackImpl> - get copyWith => - __$$PlaybackHistoryTrackImplCopyWithImpl<_$PlaybackHistoryTrackImpl>( - this, _$identity); - - @override - @optionalTypeArgs - TResult when({ - required TResult Function(DateTime date, PlaylistSimple playlist) playlist, - required TResult Function(DateTime date, AlbumSimple album) album, - required TResult Function(DateTime date, Track track) track, - }) { - return track(date, this.track); - } - - @override - @optionalTypeArgs - TResult? whenOrNull({ - TResult? Function(DateTime date, PlaylistSimple playlist)? playlist, - TResult? Function(DateTime date, AlbumSimple album)? album, - TResult? Function(DateTime date, Track track)? track, - }) { - return track?.call(date, this.track); - } - - @override - @optionalTypeArgs - TResult maybeWhen({ - TResult Function(DateTime date, PlaylistSimple playlist)? playlist, - TResult Function(DateTime date, AlbumSimple album)? album, - TResult Function(DateTime date, Track track)? track, - required TResult orElse(), - }) { - if (track != null) { - return track(date, this.track); - } - return orElse(); - } - - @override - @optionalTypeArgs - TResult map({ - required TResult Function(PlaybackHistoryPlaylist value) playlist, - required TResult Function(PlaybackHistoryAlbum value) album, - required TResult Function(PlaybackHistoryTrack value) track, - }) { - return track(this); - } - - @override - @optionalTypeArgs - TResult? mapOrNull({ - TResult? Function(PlaybackHistoryPlaylist value)? playlist, - TResult? Function(PlaybackHistoryAlbum value)? album, - TResult? Function(PlaybackHistoryTrack value)? track, - }) { - return track?.call(this); - } - - @override - @optionalTypeArgs - TResult maybeMap({ - TResult Function(PlaybackHistoryPlaylist value)? playlist, - TResult Function(PlaybackHistoryAlbum value)? album, - TResult Function(PlaybackHistoryTrack value)? track, - required TResult orElse(), - }) { - if (track != null) { - return track(this); - } - return orElse(); - } - - @override - Map toJson() { - return _$$PlaybackHistoryTrackImplToJson( - this, - ); - } -} - -abstract class PlaybackHistoryTrack implements PlaybackHistoryItem { - factory PlaybackHistoryTrack( - {required final DateTime date, - required final Track track}) = _$PlaybackHistoryTrackImpl; - - factory PlaybackHistoryTrack.fromJson(Map json) = - _$PlaybackHistoryTrackImpl.fromJson; - - @override - DateTime get date; - Track get track; - - /// Create a copy of PlaybackHistoryItem - /// with the given fields replaced by the non-null parameter values. - @override - @JsonKey(includeFromJson: false, includeToJson: false) - _$$PlaybackHistoryTrackImplCopyWith<_$PlaybackHistoryTrackImpl> - get copyWith => throw _privateConstructorUsedError; -} diff --git a/lib/utils/migrations/adapters.g.dart b/lib/utils/migrations/adapters.g.dart deleted file mode 100644 index ca95a840..00000000 --- a/lib/utils/migrations/adapters.g.dart +++ /dev/null @@ -1,600 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'adapters.dart'; - -// ************************************************************************** -// TypeAdapterGenerator -// ************************************************************************** - -class SkipSegmentAdapter extends TypeAdapter { - @override - final int typeId = 2; - - @override - SkipSegment read(BinaryReader reader) { - final numOfFields = reader.readByte(); - final fields = { - for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), - }; - return SkipSegment( - fields[0] as int, - fields[1] as int, - ); - } - - @override - void write(BinaryWriter writer, SkipSegment obj) { - writer - ..writeByte(2) - ..writeByte(0) - ..write(obj.start) - ..writeByte(1) - ..write(obj.end); - } - - @override - int get hashCode => typeId.hashCode; - - @override - bool operator ==(Object other) => - identical(this, other) || - other is SkipSegmentAdapter && - runtimeType == other.runtimeType && - typeId == other.typeId; -} - -class SourceMatchAdapter extends TypeAdapter { - @override - final int typeId = 6; - - @override - SourceMatch read(BinaryReader reader) { - final numOfFields = reader.readByte(); - final fields = { - for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), - }; - return SourceMatch( - id: fields[0] as String, - sourceId: fields[1] as String, - sourceType: fields[2] as SourceType, - createdAt: fields[3] as DateTime, - ); - } - - @override - void write(BinaryWriter writer, SourceMatch obj) { - writer - ..writeByte(4) - ..writeByte(0) - ..write(obj.id) - ..writeByte(1) - ..write(obj.sourceId) - ..writeByte(2) - ..write(obj.sourceType) - ..writeByte(3) - ..write(obj.createdAt); - } - - @override - int get hashCode => typeId.hashCode; - - @override - bool operator ==(Object other) => - identical(this, other) || - other is SourceMatchAdapter && - runtimeType == other.runtimeType && - typeId == other.typeId; -} - -class SourceTypeAdapter extends TypeAdapter { - @override - final int typeId = 5; - - @override - SourceType read(BinaryReader reader) { - switch (reader.readByte()) { - case 0: - return SourceType.youtube; - case 1: - return SourceType.youtubeMusic; - case 2: - return SourceType.jiosaavn; - default: - return SourceType.youtube; - } - } - - @override - void write(BinaryWriter writer, SourceType obj) { - switch (obj) { - case SourceType.youtube: - writer.writeByte(0); - break; - case SourceType.youtubeMusic: - writer.writeByte(1); - break; - case SourceType.jiosaavn: - writer.writeByte(2); - break; - } - } - - @override - int get hashCode => typeId.hashCode; - - @override - bool operator ==(Object other) => - identical(this, other) || - other is SourceTypeAdapter && - runtimeType == other.runtimeType && - typeId == other.typeId; -} - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -SourceMatch _$SourceMatchFromJson(Map json) => SourceMatch( - id: json['id'] as String, - sourceId: json['sourceId'] as String, - sourceType: $enumDecode(_$SourceTypeEnumMap, json['sourceType']), - createdAt: DateTime.parse(json['createdAt'] as String), - ); - -Map _$SourceMatchToJson(SourceMatch instance) => - { - 'id': instance.id, - 'sourceId': instance.sourceId, - 'sourceType': _$SourceTypeEnumMap[instance.sourceType]!, - 'createdAt': instance.createdAt.toIso8601String(), - }; - -const _$SourceTypeEnumMap = { - SourceType.youtube: 'youtube', - SourceType.youtubeMusic: 'youtubeMusic', - SourceType.jiosaavn: 'jiosaavn', -}; - -AuthenticationCredentials _$AuthenticationCredentialsFromJson(Map json) => - AuthenticationCredentials( - cookie: json['cookie'] as String, - accessToken: json['accessToken'] as String, - expiration: DateTime.parse(json['expiration'] as String), - ); - -Map _$AuthenticationCredentialsToJson( - AuthenticationCredentials instance) => - { - 'cookie': instance.cookie, - 'accessToken': instance.accessToken, - 'expiration': instance.expiration.toIso8601String(), - }; - -_$UserPreferencesImpl _$$UserPreferencesImplFromJson(Map json) => - _$UserPreferencesImpl( - audioQuality: - $enumDecodeNullable(_$SourceQualitiesEnumMap, json['audioQuality']) ?? - SourceQualities.high, - albumColorSync: json['albumColorSync'] as bool? ?? true, - amoledDarkTheme: json['amoledDarkTheme'] as bool? ?? false, - checkUpdate: json['checkUpdate'] as bool? ?? true, - normalizeAudio: json['normalizeAudio'] as bool? ?? false, - showSystemTrayIcon: json['showSystemTrayIcon'] as bool? ?? false, - skipNonMusic: json['skipNonMusic'] as bool? ?? false, - systemTitleBar: json['systemTitleBar'] as bool? ?? false, - closeBehavior: - $enumDecodeNullable(_$CloseBehaviorEnumMap, json['closeBehavior']) ?? - CloseBehavior.close, - accentColorScheme: UserPreferences._accentColorSchemeReadValue( - json, 'accentColorScheme') == - null - ? const SpotubeColor(0xFF2196F3, name: "Blue") - : UserPreferences._accentColorSchemeFromJson( - UserPreferences._accentColorSchemeReadValue( - json, 'accentColorScheme') as Map), - layoutMode: - $enumDecodeNullable(_$LayoutModeEnumMap, json['layoutMode']) ?? - LayoutMode.adaptive, - locale: UserPreferences._localeReadValue(json, 'locale') == null - ? const Locale("system", "system") - : UserPreferences._localeFromJson( - UserPreferences._localeReadValue(json, 'locale') - as Map), - recommendationMarket: - $enumDecodeNullable(_$MarketEnumMap, json['recommendationMarket']) ?? - Market.US, - searchMode: - $enumDecodeNullable(_$SearchModeEnumMap, json['searchMode']) ?? - SearchMode.youtube, - downloadLocation: json['downloadLocation'] as String? ?? "", - localLibraryLocation: (json['localLibraryLocation'] as List?) - ?.map((e) => e as String) - .toList() ?? - const [], - pipedInstance: - json['pipedInstance'] as String? ?? "https://pipedapi.kavin.rocks", - themeMode: $enumDecodeNullable(_$ThemeModeEnumMap, json['themeMode']) ?? - ThemeMode.system, - audioSource: - $enumDecodeNullable(_$AudioSourceEnumMap, json['audioSource']) ?? - AudioSource.youtube, - streamMusicCodec: $enumDecodeNullable( - _$SourceCodecsEnumMap, json['streamMusicCodec']) ?? - SourceCodecs.weba, - downloadMusicCodec: $enumDecodeNullable( - _$SourceCodecsEnumMap, json['downloadMusicCodec']) ?? - SourceCodecs.m4a, - discordPresence: json['discordPresence'] as bool? ?? true, - endlessPlayback: json['endlessPlayback'] as bool? ?? true, - enableConnect: json['enableConnect'] as bool? ?? false, - ); - -Map _$$UserPreferencesImplToJson( - _$UserPreferencesImpl instance) => - { - 'audioQuality': _$SourceQualitiesEnumMap[instance.audioQuality]!, - 'albumColorSync': instance.albumColorSync, - 'amoledDarkTheme': instance.amoledDarkTheme, - 'checkUpdate': instance.checkUpdate, - 'normalizeAudio': instance.normalizeAudio, - 'showSystemTrayIcon': instance.showSystemTrayIcon, - 'skipNonMusic': instance.skipNonMusic, - 'systemTitleBar': instance.systemTitleBar, - 'closeBehavior': _$CloseBehaviorEnumMap[instance.closeBehavior]!, - 'accentColorScheme': - UserPreferences._accentColorSchemeToJson(instance.accentColorScheme), - 'layoutMode': _$LayoutModeEnumMap[instance.layoutMode]!, - 'locale': UserPreferences._localeToJson(instance.locale), - 'recommendationMarket': _$MarketEnumMap[instance.recommendationMarket]!, - 'searchMode': _$SearchModeEnumMap[instance.searchMode]!, - 'downloadLocation': instance.downloadLocation, - 'localLibraryLocation': instance.localLibraryLocation, - 'pipedInstance': instance.pipedInstance, - 'themeMode': _$ThemeModeEnumMap[instance.themeMode]!, - 'audioSource': _$AudioSourceEnumMap[instance.audioSource]!, - 'streamMusicCodec': _$SourceCodecsEnumMap[instance.streamMusicCodec]!, - 'downloadMusicCodec': _$SourceCodecsEnumMap[instance.downloadMusicCodec]!, - 'discordPresence': instance.discordPresence, - 'endlessPlayback': instance.endlessPlayback, - 'enableConnect': instance.enableConnect, - }; - -const _$SourceQualitiesEnumMap = { - SourceQualities.high: 'high', - SourceQualities.medium: 'medium', - SourceQualities.low: 'low', -}; - -const _$CloseBehaviorEnumMap = { - CloseBehavior.minimizeToTray: 'minimizeToTray', - CloseBehavior.close: 'close', -}; - -const _$LayoutModeEnumMap = { - LayoutMode.compact: 'compact', - LayoutMode.extended: 'extended', - LayoutMode.adaptive: 'adaptive', -}; - -const _$MarketEnumMap = { - Market.AD: 'AD', - Market.AE: 'AE', - Market.AF: 'AF', - Market.AG: 'AG', - Market.AI: 'AI', - Market.AL: 'AL', - Market.AM: 'AM', - Market.AO: 'AO', - Market.AQ: 'AQ', - Market.AR: 'AR', - Market.AS: 'AS', - Market.AT: 'AT', - Market.AU: 'AU', - Market.AW: 'AW', - Market.AX: 'AX', - Market.AZ: 'AZ', - Market.BA: 'BA', - Market.BB: 'BB', - Market.BD: 'BD', - Market.BE: 'BE', - Market.BF: 'BF', - Market.BG: 'BG', - Market.BH: 'BH', - Market.BI: 'BI', - Market.BJ: 'BJ', - Market.BL: 'BL', - Market.BM: 'BM', - Market.BN: 'BN', - Market.BO: 'BO', - Market.BQ: 'BQ', - Market.BR: 'BR', - Market.BS: 'BS', - Market.BT: 'BT', - Market.BV: 'BV', - Market.BW: 'BW', - Market.BY: 'BY', - Market.BZ: 'BZ', - Market.CA: 'CA', - Market.CC: 'CC', - Market.CD: 'CD', - Market.CF: 'CF', - Market.CG: 'CG', - Market.CH: 'CH', - Market.CI: 'CI', - Market.CK: 'CK', - Market.CL: 'CL', - Market.CM: 'CM', - Market.CN: 'CN', - Market.CO: 'CO', - Market.CR: 'CR', - Market.CU: 'CU', - Market.CV: 'CV', - Market.CW: 'CW', - Market.CX: 'CX', - Market.CY: 'CY', - Market.CZ: 'CZ', - Market.DE: 'DE', - Market.DJ: 'DJ', - Market.DK: 'DK', - Market.DM: 'DM', - Market.DO: 'DO', - Market.DZ: 'DZ', - Market.EC: 'EC', - Market.EE: 'EE', - Market.EG: 'EG', - Market.EH: 'EH', - Market.ER: 'ER', - Market.ES: 'ES', - Market.ET: 'ET', - Market.FI: 'FI', - Market.FJ: 'FJ', - Market.FK: 'FK', - Market.FM: 'FM', - Market.FO: 'FO', - Market.FR: 'FR', - Market.GA: 'GA', - Market.GB: 'GB', - Market.GD: 'GD', - Market.GE: 'GE', - Market.GF: 'GF', - Market.GG: 'GG', - Market.GH: 'GH', - Market.GI: 'GI', - Market.GL: 'GL', - Market.GM: 'GM', - Market.GN: 'GN', - Market.GP: 'GP', - Market.GQ: 'GQ', - Market.GR: 'GR', - Market.GS: 'GS', - Market.GT: 'GT', - Market.GU: 'GU', - Market.GW: 'GW', - Market.GY: 'GY', - Market.HK: 'HK', - Market.HM: 'HM', - Market.HN: 'HN', - Market.HR: 'HR', - Market.HT: 'HT', - Market.HU: 'HU', - Market.ID: 'ID', - Market.IE: 'IE', - Market.IL: 'IL', - Market.IM: 'IM', - Market.IN: 'IN', - Market.IO: 'IO', - Market.IQ: 'IQ', - Market.IR: 'IR', - Market.IS: 'IS', - Market.IT: 'IT', - Market.JE: 'JE', - Market.JM: 'JM', - Market.JO: 'JO', - Market.JP: 'JP', - Market.KE: 'KE', - Market.KG: 'KG', - Market.KH: 'KH', - Market.KI: 'KI', - Market.KM: 'KM', - Market.KN: 'KN', - Market.KP: 'KP', - Market.KR: 'KR', - Market.KW: 'KW', - Market.KY: 'KY', - Market.KZ: 'KZ', - Market.LA: 'LA', - Market.LB: 'LB', - Market.LC: 'LC', - Market.LI: 'LI', - Market.LK: 'LK', - Market.LR: 'LR', - Market.LS: 'LS', - Market.LT: 'LT', - Market.LU: 'LU', - Market.LV: 'LV', - Market.LY: 'LY', - Market.MA: 'MA', - Market.MC: 'MC', - Market.MD: 'MD', - Market.ME: 'ME', - Market.MF: 'MF', - Market.MG: 'MG', - Market.MH: 'MH', - Market.MK: 'MK', - Market.ML: 'ML', - Market.MM: 'MM', - Market.MN: 'MN', - Market.MO: 'MO', - Market.MP: 'MP', - Market.MQ: 'MQ', - Market.MR: 'MR', - Market.MS: 'MS', - Market.MT: 'MT', - Market.MU: 'MU', - Market.MV: 'MV', - Market.MW: 'MW', - Market.MX: 'MX', - Market.MY: 'MY', - Market.MZ: 'MZ', - Market.NA: 'NA', - Market.NC: 'NC', - Market.NE: 'NE', - Market.NF: 'NF', - Market.NG: 'NG', - Market.NI: 'NI', - Market.NL: 'NL', - Market.NO: 'NO', - Market.NP: 'NP', - Market.NR: 'NR', - Market.NU: 'NU', - Market.NZ: 'NZ', - Market.OM: 'OM', - Market.PA: 'PA', - Market.PE: 'PE', - Market.PF: 'PF', - Market.PG: 'PG', - Market.PH: 'PH', - Market.PK: 'PK', - Market.PL: 'PL', - Market.PM: 'PM', - Market.PN: 'PN', - Market.PR: 'PR', - Market.PS: 'PS', - Market.PT: 'PT', - Market.PW: 'PW', - Market.PY: 'PY', - Market.QA: 'QA', - Market.RE: 'RE', - Market.RO: 'RO', - Market.RS: 'RS', - Market.RU: 'RU', - Market.RW: 'RW', - Market.SA: 'SA', - Market.SB: 'SB', - Market.SC: 'SC', - Market.SD: 'SD', - Market.SE: 'SE', - Market.SG: 'SG', - Market.SH: 'SH', - Market.SI: 'SI', - Market.SJ: 'SJ', - Market.SK: 'SK', - Market.SL: 'SL', - Market.SM: 'SM', - Market.SN: 'SN', - Market.SO: 'SO', - Market.SR: 'SR', - Market.SS: 'SS', - Market.ST: 'ST', - Market.SV: 'SV', - Market.SX: 'SX', - Market.SY: 'SY', - Market.SZ: 'SZ', - Market.TC: 'TC', - Market.TD: 'TD', - Market.TF: 'TF', - Market.TG: 'TG', - Market.TH: 'TH', - Market.TJ: 'TJ', - Market.TK: 'TK', - Market.TL: 'TL', - Market.TM: 'TM', - Market.TN: 'TN', - Market.TO: 'TO', - Market.TR: 'TR', - Market.TT: 'TT', - Market.TV: 'TV', - Market.TW: 'TW', - Market.TZ: 'TZ', - Market.UA: 'UA', - Market.UG: 'UG', - Market.UM: 'UM', - Market.US: 'US', - Market.UY: 'UY', - Market.UZ: 'UZ', - Market.VA: 'VA', - Market.VC: 'VC', - Market.VE: 'VE', - Market.VG: 'VG', - Market.VI: 'VI', - Market.VN: 'VN', - Market.VU: 'VU', - Market.WF: 'WF', - Market.WS: 'WS', - Market.XK: 'XK', - Market.YE: 'YE', - Market.YT: 'YT', - Market.ZA: 'ZA', - Market.ZM: 'ZM', - Market.ZW: 'ZW', -}; - -const _$SearchModeEnumMap = { - SearchMode.youtube: 'youtube', - SearchMode.youtubeMusic: 'youtubeMusic', -}; - -const _$ThemeModeEnumMap = { - ThemeMode.system: 'system', - ThemeMode.light: 'light', - ThemeMode.dark: 'dark', -}; - -const _$AudioSourceEnumMap = { - AudioSource.youtube: 'youtube', - AudioSource.piped: 'piped', - AudioSource.jiosaavn: 'jiosaavn', -}; - -const _$SourceCodecsEnumMap = { - SourceCodecs.m4a: 'm4a', - SourceCodecs.weba: 'weba', -}; - -_$PlaybackHistoryPlaylistImpl _$$PlaybackHistoryPlaylistImplFromJson( - Map json) => - _$PlaybackHistoryPlaylistImpl( - date: DateTime.parse(json['date'] as String), - playlist: PlaylistSimple.fromJson( - Map.from(json['playlist'] as Map)), - $type: json['runtimeType'] as String?, - ); - -Map _$$PlaybackHistoryPlaylistImplToJson( - _$PlaybackHistoryPlaylistImpl instance) => - { - 'date': instance.date.toIso8601String(), - 'playlist': instance.playlist.toJson(), - 'runtimeType': instance.$type, - }; - -_$PlaybackHistoryAlbumImpl _$$PlaybackHistoryAlbumImplFromJson(Map json) => - _$PlaybackHistoryAlbumImpl( - date: DateTime.parse(json['date'] as String), - album: - AlbumSimple.fromJson(Map.from(json['album'] as Map)), - $type: json['runtimeType'] as String?, - ); - -Map _$$PlaybackHistoryAlbumImplToJson( - _$PlaybackHistoryAlbumImpl instance) => - { - 'date': instance.date.toIso8601String(), - 'album': instance.album.toJson(), - 'runtimeType': instance.$type, - }; - -_$PlaybackHistoryTrackImpl _$$PlaybackHistoryTrackImplFromJson(Map json) => - _$PlaybackHistoryTrackImpl( - date: DateTime.parse(json['date'] as String), - track: Track.fromJson(Map.from(json['track'] as Map)), - $type: json['runtimeType'] as String?, - ); - -Map _$$PlaybackHistoryTrackImplToJson( - _$PlaybackHistoryTrackImpl instance) => - { - 'date': instance.date.toIso8601String(), - 'track': instance.track.toJson(), - 'runtimeType': instance.$type, - }; diff --git a/lib/utils/migrations/cache_box.dart b/lib/utils/migrations/cache_box.dart deleted file mode 100644 index dfe1947b..00000000 --- a/lib/utils/migrations/cache_box.dart +++ /dev/null @@ -1,100 +0,0 @@ -import 'dart:convert'; - -import 'package:hive/hive.dart'; -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:spotube/provider/spotify/utils/json_cast.dart'; -import 'package:spotube/services/kv_store/encrypted_kv_store.dart'; -import 'package:spotube/utils/platform.dart'; -import 'package:spotube/utils/primitive_utils.dart'; - -const kKeyBoxName = "spotube_box_name"; -const kNoEncryptionWarningShownKey = "showedNoEncryptionWarning"; -const kIsUsingEncryption = "isUsingEncryption"; -String getBoxKey(String boxName) => "spotube_box_$boxName"; - -class PersistenceCacheBox { - static late LazyBox _box; - static late LazyBox _encryptedBox; - - final String cacheKey; - final bool encrypted; - - final T Function(Map) fromJson; - - PersistenceCacheBox( - this.cacheKey, { - required this.fromJson, - this.encrypted = false, - }); - - static Future read(String key) async { - final localStorage = await SharedPreferences.getInstance(); - if (kIsMacOS || kIsIOS || (kIsLinux && !kIsFlatpak)) { - return localStorage.getString(key); - } - - try { - await localStorage.setBool(kIsUsingEncryption, true); - return await EncryptedKvStoreService.storage.read(key: key); - } catch (e) { - await localStorage.setBool(kIsUsingEncryption, false); - return localStorage.getString(key); - } - } - - static Future write(String key, String value) async { - final localStorage = await SharedPreferences.getInstance(); - if (kIsMacOS || kIsIOS || (kIsLinux && !kIsFlatpak)) { - await localStorage.setString(key, value); - return; - } - - try { - await localStorage.setBool(kIsUsingEncryption, true); - await EncryptedKvStoreService.storage.write(key: key, value: value); - } catch (e) { - await localStorage.setBool(kIsUsingEncryption, false); - await localStorage.setString(key, value); - } - } - - static Future initializeBoxes({required String? path}) async { - String? boxName = await read(kKeyBoxName); - - if (boxName == null) { - boxName = "spotube-${PrimitiveUtils.uuid.v4()}"; - await write(kKeyBoxName, boxName); - } - - String? encryptionKey = await read(getBoxKey(boxName)); - - if (encryptionKey == null) { - encryptionKey = base64Url.encode(Hive.generateSecureKey()); - await write(getBoxKey(boxName), encryptionKey); - } - - _encryptedBox = await Hive.openLazyBox( - boxName, - encryptionCipher: HiveAesCipher(base64Url.decode(encryptionKey)), - ); - - _box = await Hive.openLazyBox( - "spotube_cache", - path: path, - ); - } - - LazyBox get box => encrypted ? _encryptedBox : _box; - - Future getData() async { - final json = await box.get(cacheKey); - - if (json != null || - (json is Map && json.entries.isNotEmpty) || - (json is List && json.isNotEmpty)) { - return fromJson(castNestedJson(json)); - } - - return null; - } -} diff --git a/pubspec.lock b/pubspec.lock index 46ed96d6..91ca8765 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -334,14 +334,6 @@ packages: url: "https://pub.dev" source: hosted version: "8.9.2" - buttons_tabbar: - dependency: "direct main" - description: - name: buttons_tabbar - sha256: "6e541377ab96d4223d8f072bc4f35c9d32dafe042005cad93530e0cd9d02801f" - url: "https://pub.dev" - source: hosted - version: "1.3.14" cached_network_image: dependency: "direct main" description: @@ -486,14 +478,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.2" - curved_navigation_bar: - dependency: "direct main" - description: - name: curved_navigation_bar - sha256: bb4ab128fcb6f4a9f0f1f72d227db531818b20218984789777f049fcbf919279 - url: "https://pub.dev" - source: hosted - version: "1.0.6" dart_des: dependency: transitive description: @@ -1025,7 +1009,7 @@ packages: source: hosted version: "1.1.1" flutter_svg: - dependency: "direct main" + dependency: transitive description: name: flutter_svg sha256: "6ff9fa12892ae074092de2fa6a9938fb21dbabfdaa2ff57dc697ff912fc8d4b2" @@ -1892,14 +1876,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.1" - popover: - dependency: "direct main" - description: - name: popover - sha256: "0606f3e10f92fc0459f5c52fd917738c29e7552323b28694d50c2d3312d0e1a2" - url: "https://pub.dev" - source: hosted - version: "0.3.1" posix: dependency: transitive description: @@ -2149,14 +2125,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.1.2" - sidebarx: - dependency: "direct main" - description: - name: sidebarx - sha256: abe39d6db237fb8e25c600e8039ffab80fa7fe71acab03e9c378c31f912d2766 - url: "https://pub.dev" - source: hosted - version: "0.17.1" simple_icons: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index e1b1ada3..25ccd41c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -21,10 +21,8 @@ dependencies: audio_session: ^0.1.19 auto_size_text: ^3.0.0 bonsoir: ^5.1.10 - buttons_tabbar: ^1.3.8 cached_network_image: ^3.3.1 collection: ^1.18.0 - curved_navigation_bar: ^1.0.3 desktop_webview_window: git: path: packages/desktop_webview_window @@ -62,7 +60,6 @@ dependencies: flutter_riverpod: ^2.5.1 flutter_secure_storage: ^9.0.0 flutter_sharing_intent: ^1.1.0 - flutter_svg: ^1.1.6 form_validator: ^2.1.1 freezed_annotation: ^2.4.1 fuzzywuzzy: ^1.1.6 @@ -95,7 +92,6 @@ dependencies: path_provider: ^2.1.3 permission_handler: ^11.3.1 piped_client: ^0.1.1 - popover: ^0.3.0 riverpod: ^2.5.1 scrobblenaut: git: @@ -107,7 +103,6 @@ dependencies: shelf: ^1.4.1 shelf_router: ^1.1.4 shelf_web_socket: ^2.0.0 - sidebarx: ^0.17.1 simple_icons: ^10.1.3 skeletonizer: ^1.1.1 sliver_tools: ^0.2.12 From a6720d53925bfde2c1925fe040fcebf1256ace63 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 22 Dec 2024 14:48:48 +0600 Subject: [PATCH 022/112] feat: grid/list customizable playbutton view --- lib/collections/spotube_icons.dart | 2 + .../adaptive/adaptive_pop_sheet_list.dart | 8 +- lib/components/button/back_button.dart | 10 +- .../horizontal_playbutton_card_view.dart | 20 +- .../playbutton_card.dart | 60 +++-- .../playbutton_view/playbutton_tile.dart | 92 ++++++++ .../playbutton_view/playbutton_view.dart | 157 +++++++++++++ lib/l10n/app_en.arb | 3 +- lib/modules/album/album_card.dart | 193 +++++++++------- lib/modules/library/user_albums.dart | 46 +--- lib/modules/library/user_playlists.dart | 44 +--- lib/modules/player/player_actions.dart | 8 +- lib/modules/player/player_controls.dart | 43 ++-- lib/modules/player/player_queue.dart | 3 +- lib/modules/playlist/playlist_card.dart | 209 +++++++++++------- lib/modules/root/bottom_player.dart | 3 +- lib/pages/home/feed/feed_section.dart | 78 ++++--- lib/pages/home/genres/genre_playlists.dart | 193 +++++++--------- untranslated_messages.json | 106 ++++++++- 19 files changed, 849 insertions(+), 429 deletions(-) rename lib/components/{ => playbutton_view}/playbutton_card.dart (64%) create mode 100644 lib/components/playbutton_view/playbutton_tile.dart create mode 100644 lib/components/playbutton_view/playbutton_view.dart diff --git a/lib/collections/spotube_icons.dart b/lib/collections/spotube_icons.dart index ff7092e3..9239875e 100644 --- a/lib/collections/spotube_icons.dart +++ b/lib/collections/spotube_icons.dart @@ -130,4 +130,6 @@ abstract class SpotubeIcons { static const open = FeatherIcons.externalLink; static const radioChecked = Icons.radio_button_on_rounded; static const radioUnchecked = Icons.radio_button_off_rounded; + static const grid = FeatherIcons.grid; + static const list = FeatherIcons.list; } diff --git a/lib/components/adaptive/adaptive_pop_sheet_list.dart b/lib/components/adaptive/adaptive_pop_sheet_list.dart index 5345199e..fa72031e 100644 --- a/lib/components/adaptive/adaptive_pop_sheet_list.dart +++ b/lib/components/adaptive/adaptive_pop_sheet_list.dart @@ -139,7 +139,9 @@ class AdaptivePopSheetList extends StatelessWidget { if (mediaQuery.mdAndUp) { return Tooltip( - tooltip: Text(tooltip ?? ''), + tooltip: TooltipContainer( + child: Text(tooltip ?? ''), + ), child: IconButton.ghost( icon: icon ?? const Icon(SpotubeIcons.moreVertical), onPressed: () { @@ -162,7 +164,7 @@ class AdaptivePopSheetList extends StatelessWidget { if (child != null) { return Tooltip( - tooltip: Text(tooltip ?? ''), + tooltip: TooltipContainer(child: Text(tooltip ?? '')), child: Button( onPressed: () => showDropdownMenu(context, Offset.zero), style: const ButtonStyle.ghost(), @@ -172,7 +174,7 @@ class AdaptivePopSheetList extends StatelessWidget { } return Tooltip( - tooltip: Text(tooltip ?? ''), + tooltip: TooltipContainer(child: Text(tooltip ?? '')), child: IconButton.ghost( icon: icon ?? const Icon(SpotubeIcons.moreVertical), onPressed: () => showDropdownMenu(context, Offset.zero), diff --git a/lib/components/button/back_button.dart b/lib/components/button/back_button.dart index 41b7d527..17b93cea 100644 --- a/lib/components/button/back_button.dart +++ b/lib/components/button/back_button.dart @@ -2,13 +2,19 @@ import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/spotube_icons.dart'; class BackButton extends StatelessWidget { - const BackButton({super.key}); + final Color? color; + const BackButton({ + super.key, + this.color, + }); @override Widget build(BuildContext context) { return IconButton.ghost( size: const ButtonSize(.9), - icon: const Icon(SpotubeIcons.angleLeft), + icon: color != null + ? Icon(SpotubeIcons.angleLeft, color: color) + : const Icon(SpotubeIcons.angleLeft), onPressed: () => Navigator.of(context).pop(), ); } diff --git a/lib/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart b/lib/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart index 31c6a37c..0ebebea7 100644 --- a/lib/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart +++ b/lib/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart @@ -9,7 +9,6 @@ import 'package:spotube/collections/fake.dart'; import 'package:spotube/modules/album/album_card.dart'; import 'package:spotube/modules/artist/artist_card.dart'; import 'package:spotube/modules/playlist/playlist_card.dart'; -import 'package:spotube/hooks/utils/use_breakpoint_value.dart'; import 'package:very_good_infinite_list/very_good_infinite_list.dart'; class HorizontalPlaybuttonCardView extends HookWidget { @@ -38,12 +37,7 @@ class HorizontalPlaybuttonCardView extends HookWidget { @override Widget build(BuildContext context) { final scrollController = useScrollController(); - final height = useBreakpointValue( - xs: 226, - sm: 226, - md: 236, - others: 266, - ); + final isArtist = items.every((s) => s is Artist); return Padding( padding: const EdgeInsets.all(8.0), @@ -64,7 +58,7 @@ class HorizontalPlaybuttonCardView extends HookWidget { ], ), SizedBox( - height: height, + height: isArtist ? 250 : 225, child: NotificationListener( // disable multiple scrollbar to use this onNotification: (notification) => true, @@ -88,7 +82,9 @@ class HorizontalPlaybuttonCardView extends HookWidget { onFetchData: onFetchMore, loadingBuilder: (context) => Skeletonizer( enabled: true, - child: AlbumCard(FakeData.albumSimple), + child: isArtist + ? ArtistCard(FakeData.artist) + : AlbumCard(FakeData.albumSimple), ), isLoading: isLoadingNextPage, hasReachedMax: !hasNextPage, @@ -100,11 +96,7 @@ class HorizontalPlaybuttonCardView extends HookWidget { PlaylistSimple() => PlaylistCard(item as PlaylistSimple), AlbumSimple() => AlbumCard(item as AlbumSimple), - Artist() => Padding( - padding: const EdgeInsets.symmetric( - horizontal: 12.0), - child: ArtistCard(item as Artist), - ), + Artist() => ArtistCard(item as Artist), _ => const SizedBox.shrink(), }; }), diff --git a/lib/components/playbutton_card.dart b/lib/components/playbutton_view/playbutton_card.dart similarity index 64% rename from lib/components/playbutton_card.dart rename to lib/components/playbutton_view/playbutton_card.dart index 31143ae8..849bab2a 100644 --- a/lib/components/playbutton_card.dart +++ b/lib/components/playbutton_view/playbutton_card.dart @@ -1,17 +1,15 @@ -import 'package:flutter_hooks/flutter_hooks.dart'; - import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/extensions/string.dart'; import 'package:spotube/utils/platform.dart'; -class PlaybuttonCard extends HookWidget { +class PlaybuttonCard extends StatelessWidget { final void Function()? onTap; final void Function()? onPlaybuttonPressed; final void Function()? onAddToQueuePressed; final String? description; - final EdgeInsetsGeometry? margin; + final String imageUrl; final bool isPlaying; final bool isLoading; @@ -23,7 +21,6 @@ class PlaybuttonCard extends HookWidget { required this.isPlaying, required this.isLoading, required this.title, - this.margin, this.description, this.onPlaybuttonPressed, this.onAddToQueuePressed, @@ -56,15 +53,18 @@ class PlaybuttonCard extends HookWidget { AnimatedScale( curve: Curves.easeOutBack, duration: const Duration(milliseconds: 300), - scale: states.contains(WidgetState.hovered) || kIsMobile + scale: (states.contains(WidgetState.hovered) || + kIsMobile) && + !isLoading ? 1 : 0.7, child: AnimatedOpacity( duration: const Duration(milliseconds: 300), - opacity: - states.contains(WidgetState.hovered) || kIsMobile - ? 1 - : 0, + opacity: (states.contains(WidgetState.hovered) || + kIsMobile) && + !isLoading + ? 1 + : 0, child: IconButton.secondary( icon: const Icon(SpotubeIcons.queueAdd), onPressed: onAddToQueuePressed, @@ -76,17 +76,29 @@ class PlaybuttonCard extends HookWidget { AnimatedScale( curve: Curves.easeOutBack, duration: const Duration(milliseconds: 150), - scale: states.contains(WidgetState.hovered) || kIsMobile + scale: states.contains(WidgetState.hovered) || + kIsMobile || + isPlaying || + isLoading ? 1 : 0.7, child: AnimatedOpacity( duration: const Duration(milliseconds: 150), - opacity: - states.contains(WidgetState.hovered) || kIsMobile - ? 1 - : 0, + opacity: states.contains(WidgetState.hovered) || + kIsMobile || + isPlaying || + isLoading + ? 1 + : 0, child: IconButton.secondary( - icon: const Icon(SpotubeIcons.play), + icon: switch ((isLoading, isPlaying)) { + (true, _) => const CircularProgressIndicator( + size: 15, + ), + (false, false) => const Icon(SpotubeIcons.play), + (false, true) => const Icon(SpotubeIcons.pause) + }, + enabled: !isLoading, onPressed: onPlaybuttonPressed, size: ButtonSize.small, ), @@ -96,11 +108,23 @@ class PlaybuttonCard extends HookWidget { ), ); }, - ) + ), + if (isOwner) + const Positioned( + right: 5, + top: 5, + child: SecondaryBadge( + style: ButtonStyle.secondaryIcon( + shape: ButtonShape.circle, + size: ButtonSize.small, + ), + child: Icon(SpotubeIcons.user), + ), + ), ], ), title: Tooltip( - tooltip: Text(title), + tooltip: TooltipContainer(child: Text(title)), child: Text( title, maxLines: 1, diff --git a/lib/components/playbutton_view/playbutton_tile.dart b/lib/components/playbutton_view/playbutton_tile.dart new file mode 100644 index 00000000..3f9d89fe --- /dev/null +++ b/lib/components/playbutton_view/playbutton_tile.dart @@ -0,0 +1,92 @@ +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; +import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/image/universal_image.dart'; +import 'package:spotube/extensions/context.dart'; +import 'package:spotube/extensions/string.dart'; + +class PlaybuttonTile extends StatelessWidget { + final void Function()? onTap; + final void Function()? onPlaybuttonPressed; + final void Function()? onAddToQueuePressed; + final String? description; + + final String imageUrl; + final bool isPlaying; + final bool isLoading; + final String title; + final bool isOwner; + + const PlaybuttonTile({ + required this.imageUrl, + required this.isPlaying, + required this.isLoading, + required this.title, + this.description, + this.onPlaybuttonPressed, + this.onAddToQueuePressed, + this.onTap, + this.isOwner = false, + super.key, + }); + + @override + Widget build(BuildContext context) { + final cleanDescription = description?.unescapeHtml().cleanHtml() ?? ""; + + return Button.ghost( + leading: ClipRRect( + borderRadius: context.theme.borderRadiusMd, + child: UniversalImage( + path: imageUrl, + width: 40, + height: 40, + fit: BoxFit.cover, + ), + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Tooltip( + tooltip: TooltipContainer(child: Text(context.l10n.add_to_queue)), + child: IconButton.outline( + icon: const Icon(SpotubeIcons.queueAdd), + onPressed: onAddToQueuePressed, + enabled: !isLoading, + ), + ), + const Gap(8), + Tooltip( + tooltip: TooltipContainer(child: Text(context.l10n.play)), + child: IconButton.secondary( + icon: switch ((isLoading, isPlaying)) { + (true, _) => const CircularProgressIndicator( + size: 22, + ), + (false, false) => const Icon(SpotubeIcons.play), + (false, true) => const Icon(SpotubeIcons.pause) + }, + onPressed: onPlaybuttonPressed, + enabled: !isLoading, + ), + ), + ], + ), + enabled: !isLoading, + onPressed: onTap, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(title), + if (cleanDescription.isNotEmpty) + Text( + description!, + maxLines: 2, + overflow: TextOverflow.ellipsis, + ).xSmall().muted(), + ], + ), + ); + } +} diff --git a/lib/components/playbutton_view/playbutton_view.dart b/lib/components/playbutton_view/playbutton_view.dart new file mode 100644 index 00000000..52cfb592 --- /dev/null +++ b/lib/components/playbutton_view/playbutton_view.dart @@ -0,0 +1,157 @@ +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:skeletonizer/skeletonizer.dart'; +import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/playbutton_view/playbutton_card.dart'; +import 'package:spotube/components/playbutton_view/playbutton_tile.dart'; +import 'package:spotube/components/waypoint.dart'; +import 'package:spotube/extensions/constrains.dart'; +import 'package:very_good_infinite_list/very_good_infinite_list.dart'; + +const _dummyPlaybuttonCard = PlaybuttonCard( + imageUrl: 'https://placehold.co/150x150.png', + isLoading: false, + isPlaying: false, + title: "Playbutton", + description: "A really cool playbutton", + isOwner: false, +); + +const _dummyPlaybuttonTile = PlaybuttonTile( + imageUrl: 'https://placehold.co/150x150.png', + isLoading: false, + isPlaying: false, + title: "Playbutton", + description: "A really cool playbutton", + isOwner: false, +); + +/// A [PlaybuttonCard] grid/list view (selectable) sliver widget +/// with support for infinite scrolling +class PlaybuttonView extends StatelessWidget { + final int itemCount; + final Widget Function(BuildContext context, int index) gridItemBuilder; + final Widget Function(BuildContext context, int index) listItemBuilder; + final bool hasMore; + final bool isLoading; + final VoidCallback onRequestMore; + final ScrollController controller; + + const PlaybuttonView({ + super.key, + required this.itemCount, + required this.gridItemBuilder, + required this.listItemBuilder, + required this.hasMore, + required this.isLoading, + required this.onRequestMore, + required this.controller, + }); + + @override + Widget build(BuildContext context) { + return SliverLayoutBuilder( + builder: (context, constrains) => HookBuilder(builder: (context) { + final isGrid = useState(constrains.mdAndUp); + final hasUserInteracted = useRef(false); + + useEffect(() { + if (hasUserInteracted.value) return null; + if (isGrid.value != constrains.mdAndUp) { + isGrid.value = constrains.mdAndUp; + } + return null; + }, [constrains]); + + return SliverMainAxisGroup( + slivers: [ + SliverToBoxAdapter( + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Toggle( + value: isGrid.value, + style: + const ButtonStyle.outline(density: ButtonDensity.icon), + onChanged: (value) { + isGrid.value = value; + hasUserInteracted.value = true; + }, + child: const Icon(SpotubeIcons.grid), + ), + const SizedBox(width: 8), + Toggle( + value: !isGrid.value, + style: + const ButtonStyle.outline(density: ButtonDensity.icon), + onChanged: (value) { + isGrid.value = !value; + hasUserInteracted.value = true; + }, + child: const Icon(SpotubeIcons.list), + ), + ], + ), + ), + const SliverGap(10), + // Toggle between grid and list view + switch ((isGrid.value, isLoading)) { + (true, _) => SliverGrid.builder( + itemCount: isLoading ? 6 : itemCount + 1, + gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: 150, + mainAxisExtent: 225, + crossAxisSpacing: 8, + mainAxisSpacing: 8, + ), + itemBuilder: (context, index) { + if (isLoading) { + return const Skeletonizer( + enabled: true, + child: _dummyPlaybuttonCard, + ); + } + + if (index == itemCount) { + if (!hasMore) return const SizedBox.shrink(); + return Waypoint( + controller: controller, + isGrid: true, + onTouchEdge: onRequestMore, + child: const Skeletonizer( + enabled: true, + child: _dummyPlaybuttonCard, + ), + ); + } + + return gridItemBuilder(context, index); + }, + ), + (false, true) => Skeletonizer.sliver( + enabled: true, + child: SliverList( + delegate: SliverChildBuilderDelegate( + (context, index) => _dummyPlaybuttonTile, + childCount: 6, + ), + ), + ), + (false, false) => SliverInfiniteList( + itemCount: itemCount, + loadingBuilder: (context) => const Skeletonizer( + enabled: true, + child: _dummyPlaybuttonTile, + ), + itemBuilder: listItemBuilder, + onFetchData: onRequestMore, + hasReachedMax: !hasMore, + isLoading: isLoading, + ), + } + ], + ); + }), + ); + } +} diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index f949480e..5b9e5183 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -401,5 +401,6 @@ "export_cache_files": "Export Cached Files", "found_n_files": "Found {count} files", "export_cache_confirmation": "Do you want to export these files to", - "exported_n_out_of_m_files": "Exported {filesExported} out of {files} files" + "exported_n_out_of_m_files": "Exported {filesExported} out of {files} files", + "undo": "Undo" } \ No newline at end of file diff --git a/lib/modules/album/album_card.dart b/lib/modules/album/album_card.dart index dd914fad..86935698 100644 --- a/lib/modules/album/album_card.dart +++ b/lib/modules/album/album_card.dart @@ -1,9 +1,10 @@ -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/dialogs/select_device_dialog.dart'; -import 'package:spotube/components/playbutton_card.dart'; +import 'package:spotube/components/playbutton_view/playbutton_card.dart'; +import 'package:spotube/components/playbutton_view/playbutton_tile.dart'; import 'package:spotube/extensions/artist_simple.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; @@ -24,10 +25,16 @@ extension FormattedAlbumType on AlbumType { class AlbumCard extends HookConsumerWidget { final AlbumSimple album; + final bool _isTile; const AlbumCard( this.album, { super.key, - }); + }) : _isTile = false; + + const AlbumCard.tile( + this.album, { + super.key, + }) : _isTile = true; @override Widget build(BuildContext context, ref) { @@ -45,8 +52,6 @@ class AlbumCard extends HookConsumerWidget { final updating = useState(false); - final scaffoldMessenger = ScaffoldMessenger.maybeOf(context); - Future> fetchAllTrack() async { if (album.tracks != null && album.tracks!.isNotEmpty) { return album.tracks!.map((track) => track.asTrack(album)).toList(); @@ -55,88 +60,116 @@ class AlbumCard extends HookConsumerWidget { return ref.read(albumTracksProvider(album).notifier).fetchAll(); } - return PlaybuttonCard( - imageUrl: album.images.asUrlString( - placeholder: ImagePlaceholder.collection, - ), - margin: const EdgeInsets.symmetric(horizontal: 10), - isPlaying: isPlaylistPlaying, - isLoading: - (isPlaylistPlaying && isFetchingActiveTrack) || updating.value, - title: album.name!, - description: - "${album.albumType?.formatted} • ${album.artists?.asString() ?? ""}", - onTap: () { - ServiceUtils.pushNamed( - context, - AlbumPage.name, - pathParameters: { - "id": album.id!, - }, - extra: album, + var imageUrl = album.images.asUrlString( + placeholder: ImagePlaceholder.collection, + ); + var isLoading = + (isPlaylistPlaying && isFetchingActiveTrack) || updating.value; + var description = + "${album.albumType?.formatted} • ${album.artists?.asString() ?? ""}"; + + void onTap() { + ServiceUtils.pushNamed( + context, + AlbumPage.name, + pathParameters: { + "id": album.id!, + }, + extra: album, + ); + } + + void onPlaybuttonPressed() async { + updating.value = true; + try { + if (isPlaylistPlaying) { + return playing ? audioPlayer.pause() : audioPlayer.resume(); + } + + final fetchedTracks = await fetchAllTrack(); + + if (fetchedTracks.isEmpty || !context.mounted) return; + + final isRemoteDevice = await showSelectDeviceDialog(context, ref); + if (isRemoteDevice) { + final remotePlayback = ref.read(connectProvider.notifier); + await remotePlayback.load( + WebSocketLoadEventData.album( + tracks: fetchedTracks, + collection: album, + ), ); - }, - onPlaybuttonPressed: () async { - updating.value = true; - try { - if (isPlaylistPlaying) { - return playing ? audioPlayer.pause() : audioPlayer.resume(); - } + } else { + await playlistNotifier.load(fetchedTracks, autoPlay: true); + playlistNotifier.addCollection(album.id!); + historyNotifier.addAlbums([album]); + } + } finally { + updating.value = false; + } + } - final fetchedTracks = await fetchAllTrack(); + void onAddToQueuePressed() async { + if (isPlaylistPlaying) { + return; + } - if (fetchedTracks.isEmpty || !context.mounted) return; + updating.value = true; + try { + final fetchedTracks = await fetchAllTrack(); - final isRemoteDevice = await showSelectDeviceDialog(context, ref); - if (isRemoteDevice) { - final remotePlayback = ref.read(connectProvider.notifier); - await remotePlayback.load( - WebSocketLoadEventData.album( - tracks: fetchedTracks, - collection: album, + if (fetchedTracks.isEmpty) return; + playlistNotifier.addTracks(fetchedTracks); + playlistNotifier.addCollection(album.id!); + historyNotifier.addAlbums([album]); + if (context.mounted) { + showToast( + context: context, + builder: (context, overlay) { + return SurfaceCard( + child: Basic( + content: Text( + context.l10n.added_to_queue(fetchedTracks.length), + ), + trailing: Button.outline( + child: Text(context.l10n.undo), + onPressed: () { + playlistNotifier + .removeTracks(fetchedTracks.map((e) => e.id!)); + }, + ), ), ); - } else { - await playlistNotifier.load(fetchedTracks, autoPlay: true); - playlistNotifier.addCollection(album.id!); - historyNotifier.addAlbums([album]); - } - } finally { - updating.value = false; - } - }, - onAddToQueuePressed: () async { - if (isPlaylistPlaying) { - return; - } + }, + ); + } + } finally { + updating.value = false; + } + } - updating.value = true; - try { - final fetchedTracks = await fetchAllTrack(); + if (_isTile) { + return PlaybuttonTile( + imageUrl: imageUrl, + isPlaying: isPlaylistPlaying, + isLoading: isLoading, + title: album.name!, + description: description, + onTap: onTap, + onPlaybuttonPressed: onPlaybuttonPressed, + onAddToQueuePressed: onAddToQueuePressed, + ); + } - if (fetchedTracks.isEmpty) return; - playlistNotifier.addTracks(fetchedTracks); - playlistNotifier.addCollection(album.id!); - historyNotifier.addAlbums([album]); - if (context.mounted) { - final snackbar = SnackBar( - content: Text( - context.l10n.added_to_queue(fetchedTracks.length), - ), - action: SnackBarAction( - label: "Undo", - onPressed: () { - playlistNotifier - .removeTracks(fetchedTracks.map((e) => e.id!)); - }, - ), - ); - - scaffoldMessenger?.showSnackBar(snackbar); - } - } finally { - updating.value = false; - } - }); + return PlaybuttonCard( + imageUrl: imageUrl, + isPlaying: isPlaylistPlaying, + isLoading: isLoading, + title: album.name!, + description: description, + onTap: onTap, + onPlaybuttonPressed: onPlaybuttonPressed, + onAddToQueuePressed: onAddToQueuePressed, + ); } } diff --git a/lib/modules/library/user_albums.dart b/lib/modules/library/user_albums.dart index 535381fc..a388c0ad 100644 --- a/lib/modules/library/user_albums.dart +++ b/lib/modules/library/user_albums.dart @@ -4,14 +4,12 @@ import 'package:collection/collection.dart'; import 'package:fuzzywuzzy/fuzzywuzzy.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:skeletonizer/skeletonizer.dart'; -import 'package:spotube/collections/fake.dart'; import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/playbutton_view/playbutton_view.dart'; import 'package:spotube/modules/album/album_card.dart'; import 'package:spotube/components/inter_scrollbar/inter_scrollbar.dart'; import 'package:spotube/components/fallbacks/anonymous_fallback.dart'; -import 'package:spotube/components/waypoint.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/authentication/authentication.dart'; import 'package:spotube/provider/spotify/spotify.dart'; @@ -78,39 +76,17 @@ class UserAlbums extends HookConsumerWidget { const SliverGap(10), SliverPadding( padding: const EdgeInsets.symmetric(horizontal: 8), - sliver: SliverGrid.builder( - itemCount: albums.isEmpty ? 6 : albums.length + 1, - gridDelegate: - const SliverGridDelegateWithMaxCrossAxisExtent( - maxCrossAxisExtent: 150, - mainAxisExtent: 225, - crossAxisSpacing: 8, - mainAxisSpacing: 8, + sliver: PlaybuttonView( + controller: controller, + itemCount: albums.length, + hasMore: albumsQuery.asData?.value.hasMore == true, + isLoading: albumsQuery.isLoading, + onRequestMore: albumsQueryNotifier.fetchMore, + gridItemBuilder: (context, index) => AlbumCard( + albums[index], ), - itemBuilder: (context, index) { - if (albums.isNotEmpty && index == albums.length) { - if (albumsQuery.asData?.value.hasMore != true) { - return const SizedBox.shrink(); - } - - return Waypoint( - controller: controller, - isGrid: true, - onTouchEdge: albumsQueryNotifier.fetchMore, - child: Skeletonizer( - enabled: true, - child: AlbumCard(FakeData.albumSimple), - ), - ); - } - - return Skeletonizer( - enabled: albumsQuery.isLoading, - child: AlbumCard( - albums.elementAtOrNull(index) ?? FakeData.albumSimple, - ), - ); - }, + listItemBuilder: (context, index) => + AlbumCard.tile(albums[index]), ), ), ], diff --git a/lib/modules/library/user_playlists.dart b/lib/modules/library/user_playlists.dart index 0f307894..2a2d65e0 100644 --- a/lib/modules/library/user_playlists.dart +++ b/lib/modules/library/user_playlists.dart @@ -5,16 +5,14 @@ import 'package:collection/collection.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart' hide Image; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; -import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotify/spotify.dart'; -import 'package:spotube/collections/fake.dart'; import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/playbutton_view/playbutton_view.dart'; import 'package:spotube/modules/playlist/playlist_create_dialog.dart'; import 'package:spotube/components/inter_scrollbar/inter_scrollbar.dart'; import 'package:spotube/components/fallbacks/anonymous_fallback.dart'; import 'package:spotube/modules/playlist/playlist_card.dart'; -import 'package:spotube/components/waypoint.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/pages/library/playlist_generate/playlist_generate.dart'; import 'package:spotube/provider/authentication/authentication.dart'; @@ -127,35 +125,17 @@ class UserPlaylists extends HookConsumerWidget { const SliverGap(10), SliverPadding( padding: const EdgeInsets.symmetric(horizontal: 8), - sliver: SliverGrid.builder( - itemCount: playlists.isEmpty ? 6 : playlists.length + 1, - gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( - maxCrossAxisExtent: 150, - mainAxisExtent: 225, - crossAxisSpacing: 8, - mainAxisSpacing: 8, - ), - itemBuilder: (context, index) { - if (playlists.isNotEmpty && index == playlists.length) { - if (playlistsQuery.asData?.value.hasMore != true) { - return const SizedBox.shrink(); - } - - return Waypoint( - controller: controller, - isGrid: true, - onTouchEdge: playlistsQueryNotifier.fetchMore, - child: Skeletonizer( - enabled: true, - child: PlaylistCard(FakeData.playlistSimple), - ), - ); - } - - return PlaylistCard( - playlists.elementAtOrNull(index) ?? - FakeData.playlistSimple, - ); + sliver: PlaybuttonView( + controller: controller, + hasMore: playlistsQuery.asData?.value.hasMore == true, + isLoading: playlistsQuery.isLoading, + onRequestMore: playlistsQueryNotifier.fetchMore, + itemCount: playlists.length, + gridItemBuilder: (context, index) { + return PlaylistCard(playlists[index]); + }, + listItemBuilder: (context, index) { + return PlaylistCard.tile(playlists[index]); }, ), ), diff --git a/lib/modules/player/player_actions.dart b/lib/modules/player/player_actions.dart index dbdfa11b..5b469510 100644 --- a/lib/modules/player/player_actions.dart +++ b/lib/modules/player/player_actions.dart @@ -79,7 +79,7 @@ class PlayerActions extends HookConsumerWidget { children: [ if (showQueue) Tooltip( - tooltip: Text(context.l10n.queue), + tooltip: TooltipContainer(child: Text(context.l10n.queue)), child: IconButton.ghost( icon: const Icon(SpotubeIcons.queue), enabled: playlist.activeTrack != null, @@ -115,7 +115,8 @@ class PlayerActions extends HookConsumerWidget { ), if (!isLocalTrack) Tooltip( - tooltip: Text(context.l10n.alternative_track_sources), + tooltip: TooltipContainer( + child: Text(context.l10n.alternative_track_sources)), child: IconButton.ghost( icon: const Icon(SpotubeIcons.alternativeRoute), onPressed: playlist.activeTrack != null @@ -147,7 +148,8 @@ class PlayerActions extends HookConsumerWidget { ) else Tooltip( - tooltip: Text(context.l10n.download_track), + tooltip: + TooltipContainer(child: Text(context.l10n.download_track)), child: IconButton.ghost( icon: Icon( isDownloaded ? SpotubeIcons.done : SpotubeIcons.download, diff --git a/lib/modules/player/player_controls.dart b/lib/modules/player/player_controls.dart index 0b3f5c2b..52c40b35 100644 --- a/lib/modules/player/player_controls.dart +++ b/lib/modules/player/player_controls.dart @@ -84,7 +84,8 @@ class PlayerControls extends HookConsumerWidget { return Column( children: [ Tooltip( - tooltip: Text(context.l10n.slide_to_seek), + tooltip: TooltipContainer( + child: Text(context.l10n.slide_to_seek)), child: Slider( value: SliderValue.single(progress.value.toDouble()), @@ -132,10 +133,12 @@ class PlayerControls extends HookConsumerWidget { final shuffled = ref .watch(audioPlayerProvider.select((s) => s.shuffled)); return Tooltip( - tooltip: Text( - shuffled - ? context.l10n.unshuffle_playlist - : context.l10n.shuffle_playlist, + tooltip: TooltipContainer( + child: Text( + shuffled + ? context.l10n.unshuffle_playlist + : context.l10n.shuffle_playlist, + ), ), child: IconButton( icon: const Icon(SpotubeIcons.shuffle), @@ -155,7 +158,8 @@ class PlayerControls extends HookConsumerWidget { ); }), Tooltip( - tooltip: Text(context.l10n.previous_track), + tooltip: TooltipContainer( + child: Text(context.l10n.previous_track)), child: IconButton.ghost( enabled: !isFetchingActiveTrack, icon: const Icon(SpotubeIcons.skipBack), @@ -163,10 +167,12 @@ class PlayerControls extends HookConsumerWidget { ), ), Tooltip( - tooltip: Text( - playing - ? context.l10n.pause_playback - : context.l10n.resume_playback, + tooltip: TooltipContainer( + child: Text( + playing + ? context.l10n.pause_playback + : context.l10n.resume_playback, + ), ), child: IconButton.primary( shape: ButtonShape.circle, @@ -188,7 +194,8 @@ class PlayerControls extends HookConsumerWidget { ), ), Tooltip( - tooltip: Text(context.l10n.next_track), + tooltip: + TooltipContainer(child: Text(context.l10n.next_track)), child: IconButton.ghost( icon: const Icon(SpotubeIcons.skipForward), onPressed: @@ -200,12 +207,14 @@ class PlayerControls extends HookConsumerWidget { .watch(audioPlayerProvider.select((s) => s.loopMode)); return Tooltip( - tooltip: Text( - loopMode == PlaylistMode.single - ? context.l10n.loop_track - : loopMode == PlaylistMode.loop - ? context.l10n.repeat_playlist - : "", + tooltip: TooltipContainer( + child: Text( + loopMode == PlaylistMode.single + ? context.l10n.loop_track + : loopMode == PlaylistMode.loop + ? context.l10n.repeat_playlist + : "", + ), ), child: IconButton( icon: Icon( diff --git a/lib/modules/player/player_queue.dart b/lib/modules/player/player_queue.dart index 0186d974..58442666 100644 --- a/lib/modules/player/player_queue.dart +++ b/lib/modules/player/player_queue.dart @@ -160,7 +160,8 @@ class PlayerQueue extends HookConsumerWidget { if (mediaQuery.mdAndUp || !isSearching.value) ...[ const SizedBox(width: 10), Tooltip( - tooltip: Text(context.l10n.clear_all), + tooltip: TooltipContainer( + child: Text(context.l10n.clear_all)), child: IconButton.outline( icon: const Icon(SpotubeIcons.playlistRemove), onPressed: () { diff --git a/lib/modules/playlist/playlist_card.dart b/lib/modules/playlist/playlist_card.dart index df683a80..945f3571 100644 --- a/lib/modules/playlist/playlist_card.dart +++ b/lib/modules/playlist/playlist_card.dart @@ -1,9 +1,10 @@ -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/dialogs/select_device_dialog.dart'; -import 'package:spotube/components/playbutton_card.dart'; +import 'package:spotube/components/playbutton_view/playbutton_card.dart'; +import 'package:spotube/components/playbutton_view/playbutton_tile.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/models/connect/connect.dart'; @@ -18,10 +19,18 @@ import 'package:spotube/utils/service_utils.dart'; class PlaylistCard extends HookConsumerWidget { final PlaylistSimple playlist; + final bool _isTile; + const PlaylistCard( this.playlist, { super.key, - }); + }) : _isTile = false; + + const PlaylistCard.tile( + this.playlist, { + super.key, + }) : _isTile = true; + @override Widget build(BuildContext context, ref) { final playlistQueue = ref.watch(audioPlayerProvider); @@ -60,96 +69,128 @@ class PlaylistCard extends HookConsumerWidget { return ref.read(playlistTracksProvider(playlist.id!).notifier).fetchAll(); } - return PlaybuttonCard( - margin: const EdgeInsets.symmetric(horizontal: 10), - title: playlist.name!, - description: playlist.description, - imageUrl: playlist.images.asUrlString( - placeholder: ImagePlaceholder.collection, - ), - isPlaying: isPlaylistPlaying, - isLoading: (isPlaylistPlaying && isFetchingActiveTrack) || updating.value, - isOwner: playlist.owner?.id == me.asData?.value.id && - me.asData?.value.id != null, - onTap: () { - ServiceUtils.pushNamed( - context, - PlaylistPage.name, - pathParameters: { - "id": playlist.id!, - }, - extra: playlist, - ); - }, - onPlaybuttonPressed: () async { - try { - updating.value = true; - if (isPlaylistPlaying && playing) { - return audioPlayer.pause(); - } else if (isPlaylistPlaying && !playing) { - return audioPlayer.resume(); - } + void onTap() { + ServiceUtils.pushNamed( + context, + PlaylistPage.name, + pathParameters: { + "id": playlist.id!, + }, + extra: playlist, + ); + } - final fetchedInitialTracks = await fetchInitialTracks(); - - if (fetchedInitialTracks.isEmpty || !context.mounted) return; - - final isRemoteDevice = await showSelectDeviceDialog(context, ref); - if (isRemoteDevice) { - final remotePlayback = ref.read(connectProvider.notifier); - final allTracks = await fetchAllTracks(); - await remotePlayback.load( - WebSocketLoadEventData.playlist( - tracks: allTracks, - collection: playlist, - ), - ); - } else { - await playlistNotifier.load(fetchedInitialTracks, autoPlay: true); - playlistNotifier.addCollection(playlist.id!); - historyNotifier.addPlaylists([playlist]); - - final allTracks = await fetchAllTracks(); - - await playlistNotifier - .addTracks(allTracks.sublist(fetchedInitialTracks.length)); - } - } finally { - if (context.mounted) { - updating.value = false; - } - } - }, - onAddToQueuePressed: () async { + void onPlaybuttonPressed() async { + try { updating.value = true; - try { - if (isPlaylistPlaying) return; + if (isPlaylistPlaying && playing) { + return audioPlayer.pause(); + } else if (isPlaylistPlaying && !playing) { + return audioPlayer.resume(); + } - final fetchedInitialTracks = await fetchAllTracks(); + final fetchedInitialTracks = await fetchInitialTracks(); - if (fetchedInitialTracks.isEmpty) return; + if (fetchedInitialTracks.isEmpty || !context.mounted) return; - playlistNotifier.addTracks(fetchedInitialTracks); + final isRemoteDevice = await showSelectDeviceDialog(context, ref); + if (isRemoteDevice) { + final remotePlayback = ref.read(connectProvider.notifier); + final allTracks = await fetchAllTracks(); + await remotePlayback.load( + WebSocketLoadEventData.playlist( + tracks: allTracks, + collection: playlist, + ), + ); + } else { + await playlistNotifier.load(fetchedInitialTracks, autoPlay: true); playlistNotifier.addCollection(playlist.id!); historyNotifier.addPlaylists([playlist]); - if (context.mounted) { - final snackbar = SnackBar( - content: Text(context.l10n - .added_num_tracks_to_queue(fetchedInitialTracks.length)), - action: SnackBarAction( - label: "Undo", - onPressed: () { - playlistNotifier - .removeTracks(fetchedInitialTracks.map((e) => e.id!)); - }, - ), - ); - ScaffoldMessenger.maybeOf(context)?.showSnackBar(snackbar); - } - } finally { + + final allTracks = await fetchAllTracks(); + + await playlistNotifier + .addTracks(allTracks.sublist(fetchedInitialTracks.length)); + } + } finally { + if (context.mounted) { updating.value = false; } - }, + } + } + + void onAddToQueuePressed() async { + updating.value = true; + try { + if (isPlaylistPlaying) return; + + final fetchedInitialTracks = await fetchAllTracks(); + + if (fetchedInitialTracks.isEmpty) return; + + playlistNotifier.addTracks(fetchedInitialTracks); + playlistNotifier.addCollection(playlist.id!); + historyNotifier.addPlaylists([playlist]); + if (context.mounted) { + showToast( + context: context, + builder: (context, overlay) { + return SurfaceCard( + child: Basic( + content: Text( + context.l10n + .added_num_tracks_to_queue(fetchedInitialTracks.length), + ), + trailing: Button.outline( + child: Text(context.l10n.undo), + onPressed: () { + playlistNotifier + .removeTracks(fetchedInitialTracks.map((e) => e.id!)); + }, + ), + ), + ); + }, + ); + } + } finally { + updating.value = false; + } + } + + final imageUrl = playlist.images.asUrlString( + placeholder: ImagePlaceholder.collection, + ); + final isLoading = + (isPlaylistPlaying && isFetchingActiveTrack) || updating.value; + final isOwner = playlist.owner?.id == me.asData?.value.id && + me.asData?.value.id != null; + + if (_isTile) { + return PlaybuttonTile( + title: playlist.name!, + description: playlist.description, + imageUrl: imageUrl, + isPlaying: isPlaylistPlaying, + isLoading: isLoading, + isOwner: isOwner, + onTap: onTap, + onPlaybuttonPressed: onPlaybuttonPressed, + onAddToQueuePressed: onAddToQueuePressed, + ); + } + + return PlaybuttonCard( + title: playlist.name!, + description: playlist.description, + imageUrl: imageUrl, + isPlaying: isPlaylistPlaying, + isLoading: isLoading, + isOwner: isOwner, + onTap: onTap, + onPlaybuttonPressed: onPlaybuttonPressed, + onAddToQueuePressed: onAddToQueuePressed, ); } } diff --git a/lib/modules/root/bottom_player.dart b/lib/modules/root/bottom_player.dart index 8a22cc7a..fc581377 100644 --- a/lib/modules/root/bottom_player.dart +++ b/lib/modules/root/bottom_player.dart @@ -74,7 +74,8 @@ class BottomPlayer extends HookConsumerWidget { PlayerActions( extraActions: [ Tooltip( - tooltip: Text(context.l10n.mini_player), + tooltip: + TooltipContainer(child: Text(context.l10n.mini_player)), child: IconButton( variance: ButtonVariance.ghost, icon: const Icon(SpotubeIcons.miniPlayer), diff --git a/lib/pages/home/feed/feed_section.dart b/lib/pages/home/feed/feed_section.dart index 0249d865..38d0887c 100644 --- a/lib/pages/home/feed/feed_section.dart +++ b/lib/pages/home/feed/feed_section.dart @@ -1,12 +1,13 @@ -import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotube/collections/fake.dart'; +import 'package:spotube/components/playbutton_view/playbutton_view.dart'; import 'package:spotube/modules/album/album_card.dart'; import 'package:spotube/modules/artist/artist_card.dart'; import 'package:spotube/modules/playlist/playlist_card.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; -import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/provider/spotify/views/home_section.dart'; class HomeFeedSectionPage extends HookConsumerWidget { @@ -19,47 +20,72 @@ class HomeFeedSectionPage extends HookConsumerWidget { Widget build(BuildContext context, ref) { final homeFeedSection = ref.watch(homeSectionViewProvider(sectionUri)); final section = homeFeedSection.asData?.value ?? FakeData.feedSection; + final controller = useScrollController(); + final isArtist = section.items.every((item) => item.artist != null); return Skeletonizer( enabled: homeFeedSection.isLoading, child: Scaffold( - appBar: TitleBar( - title: Text(section.title ?? ""), - automaticallyImplyLeading: true, - ), - body: CustomScrollView( - slivers: [ - SliverLayoutBuilder( - builder: (context, constrains) { - return SliverGrid.builder( - gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( + headers: [ + TitleBar( + title: Text(section.title ?? ""), + automaticallyImplyLeading: true, + ) + ], + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: CustomScrollView( + controller: controller, + slivers: [ + if (isArtist) + SliverGrid.builder( + gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: 200, - mainAxisExtent: constrains.smAndDown ? 225 : 250, + mainAxisExtent: 250, crossAxisSpacing: 8, mainAxisSpacing: 8, ), itemCount: section.items.length, itemBuilder: (context, index) { final item = section.items[index]; - + return ArtistCard(item.artist!.asArtist); + }, + ) + else + PlaybuttonView( + controller: controller, + itemCount: section.items.length, + hasMore: false, + isLoading: false, + onRequestMore: () => {}, + listItemBuilder: (context, index) { + final item = section.items[index]; + if (item.album != null) { + return AlbumCard.tile(item.album!.asAlbum); + } + if (item.playlist != null) { + return PlaylistCard.tile(item.playlist!.asPlaylist); + } + return const SizedBox.shrink(); + }, + gridItemBuilder: (context, index) { + final item = section.items[index]; if (item.album != null) { return AlbumCard(item.album!.asAlbum); - } else if (item.artist != null) { - return ArtistCard(item.artist!.asArtist); - } else if (item.playlist != null) { + } + if (item.playlist != null) { return PlaylistCard(item.playlist!.asPlaylist); } - return const SizedBox(); + return const SizedBox.shrink(); }, - ); - }, - ), - const SliverToBoxAdapter( - child: SafeArea( - child: SizedBox(), + ), + const SliverToBoxAdapter( + child: SafeArea( + child: SizedBox(), + ), ), - ), - ], + ], + ), ), ), ); diff --git a/lib/pages/home/genres/genre_playlists.dart b/lib/pages/home/genres/genre_playlists.dart index ec478617..ebfc4450 100644 --- a/lib/pages/home/genres/genre_playlists.dart +++ b/lib/pages/home/genres/genre_playlists.dart @@ -1,19 +1,20 @@ -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart' show CollapseMode, FlexibleSpaceBar; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:gap/gap.dart'; + import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:skeletonizer/skeletonizer.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; + import 'package:spotify/spotify.dart' hide Offset; -import 'package:spotube/collections/fake.dart'; +import 'package:spotube/components/button/back_button.dart'; +import 'package:spotube/components/playbutton_view/playbutton_view.dart'; import 'package:spotube/hooks/utils/use_custom_status_bar_color.dart'; import 'package:spotube/modules/playlist/playlist_card.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; -import 'package:spotube/components/waypoint.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/provider/spotify/spotify.dart'; -import 'package:collection/collection.dart'; import 'package:spotube/utils/platform.dart'; class GenrePlaylistsPage extends HookConsumerWidget { @@ -39,123 +40,93 @@ class GenrePlaylistsPage extends HookConsumerWidget { ); return Scaffold( - appBar: kIsDesktop - ? const TitleBar( - leading: [BackButton(color: Colors.white)], - backgroundColor: Colors.transparent, - foregroundColor: Colors.white, - ) - : null, - extendBodyBehindAppBar: true, - body: DecoratedBox( + headers: [ + if (kIsDesktop) + const TitleBar( + leading: [ + BackButton(), + ], + backgroundColor: Colors.transparent, + surfaceOpacity: 0, + surfaceBlur: 0, + ) + ], + floatingHeader: true, + child: DecoratedBox( decoration: BoxDecoration( image: DecorationImage( image: UniversalImage.imageProvider(category.icons!.first.url!), alignment: Alignment.topCenter, fit: BoxFit.cover, - colorFilter: ColorFilter.mode( - Colors.black.withOpacity(0.5), - BlendMode.darken, - ), repeat: ImageRepeat.noRepeat, matchTextDirection: true, ), ), - child: CustomScrollView( - controller: scrollController, - slivers: [ - SliverAppBar( - automaticallyImplyLeading: kIsMobile, - expandedHeight: mediaQuery.mdAndDown ? 200 : 150, - title: const Text(""), - backgroundColor: Colors.transparent, - flexibleSpace: FlexibleSpaceBar( - centerTitle: kIsDesktop, - title: Text( - category.name!, - style: Theme.of(context).textTheme.headlineMedium?.copyWith( - color: Colors.white, - letterSpacing: 3, - shadows: [ - const Shadow( - offset: Offset(-1.5, -1.5), - color: Colors.black54, - ), - const Shadow( - offset: Offset(1.5, -1.5), - color: Colors.black54, - ), - const Shadow( - offset: Offset(1.5, 1.5), - color: Colors.black54, - ), - const Shadow( - offset: Offset(-1.5, 1.5), - color: Colors.black54, - ), - ], + child: SurfaceCard( + borderRadius: BorderRadius.zero, + padding: EdgeInsets.zero, + child: CustomScrollView( + controller: scrollController, + slivers: [ + SliverAppBar( + automaticallyImplyLeading: false, + leading: kIsMobile ? const BackButton() : null, + expandedHeight: mediaQuery.mdAndDown ? 200 : 150, + title: const Text(""), + backgroundColor: Colors.transparent, + flexibleSpace: FlexibleSpaceBar( + centerTitle: kIsDesktop, + title: Text( + category.name!, + style: context.theme.typography.h3.copyWith( + color: Colors.white, + letterSpacing: 3, + shadows: [ + Shadow( + offset: const Offset(-1.5, -1.5), + color: Colors.black.withAlpha(138), + ), + Shadow( + offset: const Offset(1.5, -1.5), + color: Colors.black.withAlpha(138), + ), + Shadow( + offset: const Offset(1.5, 1.5), + color: Colors.black.withAlpha(138), + ), + Shadow( + offset: const Offset(-1.5, 1.5), + color: Colors.black.withAlpha(138), + ), + ], + ), + ), + collapseMode: CollapseMode.parallax, + ), + ), + const SliverGap(20), + SliverSafeArea( + top: false, + sliver: SliverPadding( + padding: EdgeInsets.symmetric( + horizontal: mediaQuery.mdAndDown ? 12 : 24, + ), + sliver: PlaybuttonView( + controller: scrollController, + itemCount: playlists.asData?.value.items.length ?? 0, + isLoading: playlists.isLoading, + hasMore: playlists.asData?.value.hasMore == true, + onRequestMore: playlistsNotifier.fetchMore, + listItemBuilder: (context, index) => + PlaylistCard.tile(playlists.asData!.value.items[index]), + gridItemBuilder: (context, index) => + PlaylistCard(playlists.asData!.value.items[index]), ), ), - collapseMode: CollapseMode.parallax, ), - ), - const SliverGap(20), - SliverSafeArea( - top: false, - sliver: SliverPadding( - padding: EdgeInsets.symmetric( - horizontal: mediaQuery.mdAndDown ? 12 : 24, - ), - sliver: playlists.asData?.value.items.isNotEmpty != true - ? Skeletonizer.sliver( - child: SliverToBoxAdapter( - child: Wrap( - spacing: 12, - runSpacing: 12, - children: List.generate( - 6, - (index) => PlaylistCard(FakeData.playlist), - ), - ), - ), - ) - : SliverGrid.builder( - gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( - maxCrossAxisExtent: 190, - mainAxisExtent: mediaQuery.mdAndDown ? 225 : 250, - crossAxisSpacing: 12, - mainAxisSpacing: 12, - ), - itemCount: - (playlists.asData?.value.items.length ?? 0) + 1, - itemBuilder: (context, index) { - final playlist = playlists.asData?.value.items - .elementAtOrNull(index); - - if (playlist == null) { - if (playlists.asData?.value.hasMore == false) { - return const SizedBox.shrink(); - } - return Skeletonizer( - enabled: true, - child: Waypoint( - controller: scrollController, - isGrid: true, - onTouchEdge: playlistsNotifier.fetchMore, - child: PlaylistCard(FakeData.playlist), - ), - ); - } - - return Skeleton.keep( - child: PlaylistCard(playlist), - ); - }, - ), - ), - ), - const SliverGap(20), - ], + const SliverGap(20), + ], + ), ), ), ); diff --git a/untranslated_messages.json b/untranslated_messages.json index 9e26dfee..67bb4673 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -1 +1,105 @@ -{} \ No newline at end of file +{ + "ar": [ + "undo" + ], + + "bn": [ + "undo" + ], + + "ca": [ + "undo" + ], + + "cs": [ + "undo" + ], + + "de": [ + "undo" + ], + + "es": [ + "undo" + ], + + "eu": [ + "undo" + ], + + "fa": [ + "undo" + ], + + "fi": [ + "undo" + ], + + "fr": [ + "undo" + ], + + "hi": [ + "undo" + ], + + "id": [ + "undo" + ], + + "it": [ + "undo" + ], + + "ja": [ + "undo" + ], + + "ka": [ + "undo" + ], + + "ko": [ + "undo" + ], + + "ne": [ + "undo" + ], + + "nl": [ + "undo" + ], + + "pl": [ + "undo" + ], + + "pt": [ + "undo" + ], + + "ru": [ + "undo" + ], + + "th": [ + "undo" + ], + + "tr": [ + "undo" + ], + + "uk": [ + "undo" + ], + + "vi": [ + "undo" + ], + + "zh": [ + "undo" + ] +} From b09263d128062efb6ad6b66c19da4f5b31377e64 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 22 Dec 2024 15:03:49 +0600 Subject: [PATCH 023/112] chore: fix queue close causing exceptions --- lib/components/adaptive/adaptive_pop_sheet_list.dart | 10 +++++----- lib/components/track_tile/track_options.dart | 1 + lib/modules/player/player_actions.dart | 10 +++++++++- lib/modules/player/player_queue.dart | 2 +- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/lib/components/adaptive/adaptive_pop_sheet_list.dart b/lib/components/adaptive/adaptive_pop_sheet_list.dart index fa72031e..63499e8a 100644 --- a/lib/components/adaptive/adaptive_pop_sheet_list.dart +++ b/lib/components/adaptive/adaptive_pop_sheet_list.dart @@ -34,7 +34,7 @@ class AdaptivePopSheetList extends StatelessWidget { final bool useRootNavigator; final List? headings; - final String? tooltip; + final String tooltip; final ValueChanged? onSelected; final Offset offset; @@ -47,7 +47,7 @@ class AdaptivePopSheetList extends StatelessWidget { this.useRootNavigator = true, this.headings, this.onSelected, - this.tooltip, + required this.tooltip, this.offset = Offset.zero, }) : assert( !(icon != null && child != null), @@ -140,7 +140,7 @@ class AdaptivePopSheetList extends StatelessWidget { if (mediaQuery.mdAndUp) { return Tooltip( tooltip: TooltipContainer( - child: Text(tooltip ?? ''), + child: Text(tooltip), ), child: IconButton.ghost( icon: icon ?? const Icon(SpotubeIcons.moreVertical), @@ -164,7 +164,7 @@ class AdaptivePopSheetList extends StatelessWidget { if (child != null) { return Tooltip( - tooltip: TooltipContainer(child: Text(tooltip ?? '')), + tooltip: TooltipContainer(child: Text(tooltip)), child: Button( onPressed: () => showDropdownMenu(context, Offset.zero), style: const ButtonStyle.ghost(), @@ -174,7 +174,7 @@ class AdaptivePopSheetList extends StatelessWidget { } return Tooltip( - tooltip: TooltipContainer(child: Text(tooltip ?? '')), + tooltip: TooltipContainer(child: Text(tooltip)), child: IconButton.ghost( icon: icon ?? const Icon(SpotubeIcons.moreVertical), onPressed: () => showDropdownMenu(context, Offset.zero), diff --git a/lib/components/track_tile/track_options.dart b/lib/components/track_tile/track_options.dart index c40ddd2a..ec2fd2f0 100644 --- a/lib/components/track_tile/track_options.dart +++ b/lib/components/track_tile/track_options.dart @@ -204,6 +204,7 @@ class TrackOptions extends HookConsumerWidget { final isLocalTrack = track is LocalTrack; final adaptivePopSheetList = AdaptivePopSheetList( + tooltip: context.l10n.more_actions, onSelected: (value) async { switch (value) { case TrackOptionValue.album: diff --git a/lib/modules/player/player_actions.dart b/lib/modules/player/player_actions.dart index 5b469510..12965da4 100644 --- a/lib/modules/player/player_actions.dart +++ b/lib/modules/player/player_actions.dart @@ -164,6 +164,7 @@ class PlayerActions extends HookConsumerWidget { auth.asData?.value != null) TrackHeartButton(track: playlist.activeTrack!), AdaptivePopSheetList( + tooltip: context.l10n.sleep_timer, offset: Offset(0, -50 * (sleepTimerEntries.values.length + 2)), headings: [ Text(context.l10n.sleep_timer), @@ -190,11 +191,18 @@ class PlayerActions extends HookConsumerWidget { enabled: customHoursEnabled, onPressed: (context) async { final currentTime = TimeOfDay.now(); - final time = await showDialog( + final time = await showDialog( context: context, builder: (context) => HookBuilder(builder: (context) { final timeRef = useRef(null); return AlertDialog( + trailing: IconButton.ghost( + size: ButtonSize.xSmall, + icon: const Icon(SpotubeIcons.close), + onPressed: () { + Navigator.of(context).pop(); + }, + ), title: Text( ShadcnLocalizations.of(context).placeholderTimePicker, ), diff --git a/lib/modules/player/player_queue.dart b/lib/modules/player/player_queue.dart index 58442666..cdda39da 100644 --- a/lib/modules/player/player_queue.dart +++ b/lib/modules/player/player_queue.dart @@ -166,7 +166,7 @@ class PlayerQueue extends HookConsumerWidget { icon: const Icon(SpotubeIcons.playlistRemove), onPressed: () { onStop(); - Navigator.of(context).pop(); + closeDrawer(context); }, ), ), From b40c0b77729f06ecb1a1676f8f1a90cb9c91a845 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 22 Dec 2024 22:55:40 +0600 Subject: [PATCH 024/112] chore: use latest shadcn --- linux/flutter/generated_plugin_registrant.cc | 4 -- linux/flutter/generated_plugins.cmake | 1 - macos/Flutter/GeneratedPluginRegistrant.swift | 2 - macos/Podfile.lock | 6 -- pubspec.lock | 70 +------------------ pubspec.yaml | 2 +- .../flutter/generated_plugin_registrant.cc | 3 - windows/flutter/generated_plugins.cmake | 1 - 8 files changed, 4 insertions(+), 85 deletions(-) diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index 476ff787..06c33e05 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -6,7 +6,6 @@ #include "generated_plugin_registrant.h" -#include #include #include #include @@ -22,9 +21,6 @@ #include void fl_register_plugins(FlPluginRegistry* registry) { - g_autoptr(FlPluginRegistrar) audioplayers_linux_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "AudioplayersLinuxPlugin"); - audioplayers_linux_plugin_register_with_registrar(audioplayers_linux_registrar); g_autoptr(FlPluginRegistrar) desktop_webview_window_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "DesktopWebviewWindowPlugin"); desktop_webview_window_plugin_register_with_registrar(desktop_webview_window_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index a875e8f5..e98b18eb 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -3,7 +3,6 @@ # list(APPEND FLUTTER_PLUGIN_LIST - audioplayers_linux desktop_webview_window file_selector_linux flutter_secure_storage_linux diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 12972107..608a854e 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -8,7 +8,6 @@ import Foundation import app_links import audio_service import audio_session -import audioplayers_darwin import bonsoir_darwin import desktop_webview_window import device_info_plus @@ -33,7 +32,6 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { AppLinksMacosPlugin.register(with: registry.registrar(forPlugin: "AppLinksMacosPlugin")) AudioServicePlugin.register(with: registry.registrar(forPlugin: "AudioServicePlugin")) AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin")) - AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin")) SwiftBonsoirPlugin.register(with: registry.registrar(forPlugin: "SwiftBonsoirPlugin")) DesktopWebviewWindowPlugin.register(with: registry.registrar(forPlugin: "DesktopWebviewWindowPlugin")) DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) diff --git a/macos/Podfile.lock b/macos/Podfile.lock index db8ed79c..bdf530f1 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -5,8 +5,6 @@ PODS: - FlutterMacOS - audio_session (0.0.1): - FlutterMacOS - - audioplayers_darwin (0.0.1): - - FlutterMacOS - bonsoir_darwin (0.0.1): - Flutter - FlutterMacOS @@ -80,7 +78,6 @@ 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`) - bonsoir_darwin (from `Flutter/ephemeral/.symlinks/plugins/bonsoir_darwin/darwin`) - desktop_webview_window (from `Flutter/ephemeral/.symlinks/plugins/desktop_webview_window/macos`) - device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`) @@ -117,8 +114,6 @@ EXTERNAL SOURCES: :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 bonsoir_darwin: :path: Flutter/ephemeral/.symlinks/plugins/bonsoir_darwin/darwin desktop_webview_window: @@ -170,7 +165,6 @@ SPEC CHECKSUMS: app_links: 10e0a0ab602ffaf34d142cd4862f29d34b303b2a audio_service: b88ff778e0e3915efd4cd1a5ad6f0beef0c950a9 audio_session: dea1f41890dbf1718f04a56f1d6150fd50039b72 - audioplayers_darwin: dcad41de4fbd0099cb3749f7ab3b0cb8f70b810c bonsoir_darwin: e3b8526c42ca46a885142df84229131dfabea842 desktop_webview_window: 89bb3d691f4c80314a10be312f4cd35db93a9d5a device_info_plus: 1b14eed9bf95428983aed283a8d51cce3d8c4215 diff --git a/pubspec.lock b/pubspec.lock index 91ca8765..aaf82934 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -142,62 +142,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.1.21" - audioplayers: - dependency: transitive - description: - name: audioplayers - sha256: c346ba5a39dc208f1bab55fc239855f573d69b0e832402114bf0b793622adc4d - url: "https://pub.dev" - source: hosted - version: "6.1.0" - audioplayers_android: - dependency: transitive - description: - name: audioplayers_android - sha256: de576b890befe27175c2f511ba8b742bec83765fa97c3ce4282bba46212f58e4 - url: "https://pub.dev" - source: hosted - version: "5.0.0" - audioplayers_darwin: - dependency: transitive - description: - name: audioplayers_darwin - sha256: e507887f3ff18d8e5a10a668d7bedc28206b12e10b98347797257c6ae1019c3b - url: "https://pub.dev" - source: hosted - version: "6.0.0" - audioplayers_linux: - dependency: transitive - description: - name: audioplayers_linux - sha256: "3d3d244c90436115417f170426ce768856d8fe4dfc5ed66a049d2890acfa82f9" - url: "https://pub.dev" - source: hosted - version: "4.0.0" - audioplayers_platform_interface: - dependency: transitive - description: - name: audioplayers_platform_interface - sha256: "6834dd48dfb7bc6c2404998ebdd161f79cd3774a7e6779e1348d54a3bfdcfaa5" - url: "https://pub.dev" - source: hosted - version: "7.0.0" - audioplayers_web: - dependency: transitive - description: - name: audioplayers_web - sha256: "3609bdf0e05e66a3d9750ee40b1e37f2a622c4edb796cc600b53a90a30a2ace4" - url: "https://pub.dev" - source: hosted - version: "5.0.1" - audioplayers_windows: - dependency: transitive - description: - name: audioplayers_windows - sha256: "8605762dddba992138d476f6a0c3afd9df30ac5b96039929063eceed416795c2" - url: "https://pub.dev" - source: hosted - version: "4.0.0" auto_size_text: dependency: "direct main" description: @@ -1836,14 +1780,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.1.1" - pixel_snap: - dependency: transitive - description: - name: pixel_snap - sha256: "677410ea37b07cd37ecb6d5e6c0d8d7615a7cf3bd92ba406fd1ac57e937d1fb0" - url: "https://pub.dev" - source: hosted - version: "0.1.5" platform: dependency: transitive description: @@ -2017,10 +1953,10 @@ packages: dependency: "direct main" description: name: shadcn_flutter - sha256: eaf10ec804beddf2059dd55b802188b64277a5e4fc577defbc7c012253caef1a + sha256: "2b58f6ee6d15defd8d07aa1e82077c85455ddc68047368994c562006c2338ec2" url: "https://pub.dev" source: hosted - version: "0.0.23" + version: "0.0.24" shared_preferences: dependency: "direct main" description: @@ -2732,4 +2668,4 @@ packages: version: "2.3.6" sdks: dart: ">=3.5.3 <4.0.0" - flutter: ">=3.24.0" + flutter: ">=3.27.0" diff --git a/pubspec.yaml b/pubspec.yaml index 25ccd41c..3a90b3d1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -98,7 +98,7 @@ dependencies: ref: dart-3-support url: https://github.com/KRTirtho/scrobblenaut.git scroll_to_index: ^3.0.1 - shadcn_flutter: ^0.0.23 + shadcn_flutter: ^0.0.24 shared_preferences: ^2.2.3 shelf: ^1.4.1 shelf_router: ^1.1.4 diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 7c490ef1..42fa2129 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -7,7 +7,6 @@ #include "generated_plugin_registrant.h" #include -#include #include #include #include @@ -26,8 +25,6 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { AppLinksPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("AppLinksPluginCApi")); - AudioplayersWindowsPluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("AudioplayersWindowsPlugin")); BonsoirWindowsPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("BonsoirWindowsPluginCApi")); DesktopWebviewWindowPluginRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index dfcc70cf..cf14ec52 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -4,7 +4,6 @@ list(APPEND FLUTTER_PLUGIN_LIST app_links - audioplayers_windows bonsoir_windows desktop_webview_window file_selector_windows From db3aaa4b83e4b4af46071900de987550dc2d0e45 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 23 Dec 2024 19:23:10 +0600 Subject: [PATCH 025/112] chore: upgrade to flutter 3.27.1 --- .fvm/fvm_config.json | 2 +- .fvmrc | 2 +- .vscode/settings.json | 2 +- .../main/kotlin/oss/krtirtho/spotube/glance/HomePlayerWidget.kt | 1 + 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.fvm/fvm_config.json b/.fvm/fvm_config.json index e20d18ad..41b45a53 100644 --- a/.fvm/fvm_config.json +++ b/.fvm/fvm_config.json @@ -1,3 +1,3 @@ { - "flutterSdkVersion": "3.27.0" + "flutterSdkVersion": "3.27.1" } \ No newline at end of file diff --git a/.fvmrc b/.fvmrc index 34136bbd..d1af5d57 100644 --- a/.fvmrc +++ b/.fvmrc @@ -1,4 +1,4 @@ { - "flutter": "3.27.0", + "flutter": "3.27.1", "flavors": {} } \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 57413df4..4d76417f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -28,5 +28,5 @@ "README.md": "LICENSE,CODE_OF_CONDUCT.md,CONTRIBUTING.md,SECURITY.md,CONTRIBUTION.md,CHANGELOG.md,PRIVACY_POLICY.md", "*.dart": "${capture}.g.dart,${capture}.freezed.dart" }, - "dart.flutterSdkPath": ".fvm/versions/3.27.0" + "dart.flutterSdkPath": ".fvm/versions/3.27.1" } \ No newline at end of file diff --git a/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/HomePlayerWidget.kt b/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/HomePlayerWidget.kt index a04a0508..013723c0 100644 --- a/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/HomePlayerWidget.kt +++ b/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/HomePlayerWidget.kt @@ -2,6 +2,7 @@ package oss.krtirtho.spotube.glance import HomeWidgetGlanceState import HomeWidgetGlanceStateDefinition +import android.R import android.content.Context import android.graphics.drawable.Icon import android.net.Uri From e2143a0625790b9a7ec847db5e84bca90450722b Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Tue, 24 Dec 2024 20:19:10 +0600 Subject: [PATCH 026/112] chore: fix android build and player controls slider layout builder exception --- lib/extensions/constrains.dart | 19 ++++++++++++ lib/modules/player/player_controls.dart | 41 +++++++++++++++---------- pubspec.lock | 29 +++++++++-------- pubspec.yaml | 13 ++++++-- 4 files changed, 70 insertions(+), 32 deletions(-) diff --git a/lib/extensions/constrains.dart b/lib/extensions/constrains.dart index dc1027e2..b7353c4f 100644 --- a/lib/extensions/constrains.dart +++ b/lib/extensions/constrains.dart @@ -106,3 +106,22 @@ extension ScreenBreakpoints on MediaQueryData { bool get lgAndDown => isXs || isSm || isMd || isLg; bool get xlAndDown => isXs || isSm || isMd || isLg || isXl; } + +extension SizeBreakpoints on Size { + bool get isXs => width <= Breakpoints.xs; + bool get isSm => width > Breakpoints.xs && width <= Breakpoints.sm; + bool get isMd => width > Breakpoints.sm && width <= Breakpoints.md; + bool get isLg => width > Breakpoints.md && width <= Breakpoints.lg; + bool get isXl => width > Breakpoints.lg && width <= Breakpoints.xl; + bool get is2Xl => width > Breakpoints.xl; + + bool get smAndUp => isSm || isMd || isLg || isXl || is2Xl; + bool get mdAndUp => isMd || isLg || isXl || is2Xl; + bool get lgAndUp => isLg || isXl || is2Xl; + bool get xlAndUp => isXl || is2Xl; + + bool get smAndDown => isXs || isSm; + bool get mdAndDown => isXs || isSm || isMd; + bool get lgAndDown => isXs || isSm || isMd || isLg; + bool get xlAndDown => isXs || isSm || isMd || isLg || isXl; +} diff --git a/lib/modules/player/player_controls.dart b/lib/modules/player/player_controls.dart index 52c40b35..3c1cd503 100644 --- a/lib/modules/player/player_controls.dart +++ b/lib/modules/player/player_controls.dart @@ -7,6 +7,7 @@ import 'package:shadcn_flutter/shadcn_flutter.dart' hide ThemeData; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/collections/intents.dart'; +import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/duration.dart'; import 'package:spotube/modules/player/use_progress.dart'; @@ -65,6 +66,8 @@ class PlayerControls extends HookConsumerWidget { if (!compact) HookBuilder( builder: (context) { + final mediaQuery = MediaQuery.sizeOf(context); + final ( :bufferProgress, :duration, @@ -85,23 +88,27 @@ class PlayerControls extends HookConsumerWidget { children: [ Tooltip( tooltip: TooltipContainer( - child: Text(context.l10n.slide_to_seek)), - child: Slider( - value: - SliderValue.single(progress.value.toDouble()), - onChanged: isFetchingActiveTrack - ? null - : (v) { - progress.value = v.value; - }, - onChangeEnd: (value) async { - await audioPlayer.seek( - Duration( - seconds: (value.value * duration.inSeconds) - .toInt(), - ), - ); - }, + child: Text(context.l10n.slide_to_seek), + ), + child: SizedBox( + width: mediaQuery.xlAndUp ? 600 : 500, + child: Slider( + value: + SliderValue.single(progress.value.toDouble()), + onChanged: isFetchingActiveTrack + ? null + : (v) { + progress.value = v.value; + }, + onChangeEnd: (value) async { + await audioPlayer.seek( + Duration( + seconds: (value.value * duration.inSeconds) + .toInt(), + ), + ); + }, + ), ), ), Padding( diff --git a/pubspec.lock b/pubspec.lock index aaf82934..ff445cad 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -159,12 +159,13 @@ packages: source: hosted version: "5.1.10" bonsoir_android: - dependency: transitive + dependency: "direct overridden" description: - name: bonsoir_android - sha256: a72d83a78780c1f238e3178d0585e5604fbd9f2503206293737cdfab899ce8d0 - url: "https://pub.dev" - source: hosted + path: "packages/bonsoir_android" + ref: HEAD + resolved-ref: aa5604628ba41e3a7153769f4465a3d375488f2e + url: "https://github.com/KRTirtho/Bonsoir.git" + source: git version: "5.1.5" bonsoir_darwin: dependency: transitive @@ -514,10 +515,11 @@ packages: disable_battery_optimization: dependency: "direct main" description: - name: disable_battery_optimization - sha256: "6b2ba802f984af141faf1b6b5fb956d5ef01f9cd555597c35b9cc335a03185ba" - url: "https://pub.dev" - source: hosted + path: "." + ref: HEAD + resolved-ref: aa77a61946849fff495091fc13dcc390948cc60b + url: "https://github.com/KRTirtho/Disable-Battery-Optimizations.git" + source: git version: "1.1.1" draggable_scrollbar: dependency: "direct main" @@ -1952,10 +1954,11 @@ packages: shadcn_flutter: dependency: "direct main" description: - name: shadcn_flutter - sha256: "2b58f6ee6d15defd8d07aa1e82077c85455ddc68047368994c562006c2338ec2" - url: "https://pub.dev" - source: hosted + path: "." + ref: "5359958464a57235f0f34c43a4623356a32459a0" + resolved-ref: "5359958464a57235f0f34c43a4623356a32459a0" + url: "https://github.com/KRTirtho/shadcn_flutter.git" + source: git version: "0.0.24" shared_preferences: dependency: "direct main" diff --git a/pubspec.yaml b/pubspec.yaml index 3a90b3d1..198bc949 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -30,7 +30,9 @@ dependencies: url: https://github.com/KRTirtho/flutter-plugins.git device_info_plus: ^11.1.1 dio: ^5.4.3+1 - disable_battery_optimization: ^1.1.1 + disable_battery_optimization: + git: + url: https://github.com/KRTirtho/Disable-Battery-Optimizations.git draggable_scrollbar: git: ref: cfd570035bf393de541d32e9b28808b5d7e602df @@ -98,7 +100,10 @@ dependencies: ref: dart-3-support url: https://github.com/KRTirtho/scrobblenaut.git scroll_to_index: ^3.0.1 - shadcn_flutter: ^0.0.24 + shadcn_flutter: + git: + url: https://github.com/KRTirtho/shadcn_flutter.git + ref: 5359958464a57235f0f34c43a4623356a32459a0 shared_preferences: ^2.2.3 shelf: ^1.4.1 shelf_router: ^1.1.4 @@ -149,6 +154,10 @@ dev_dependencies: drift_dev: ^2.21.0 dependency_overrides: + bonsoir_android: + git: + url: https://github.com/KRTirtho/Bonsoir.git + path: packages/bonsoir_android web: ^1.1.0 meta: 1.16.0 From ced85d3f0c68a6e89ab7451f40091452e489528c Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Tue, 24 Dec 2024 21:33:24 +0600 Subject: [PATCH 027/112] chore: fix scaling issue in android and status bar being black --- .../horizontal_playbutton_card_view.dart | 12 ++- .../playbutton_view/playbutton_card.dart | 20 ++-- .../playbutton_view/playbutton_tile.dart | 17 ++-- .../playbutton_view/playbutton_view.dart | 7 +- lib/main.dart | 3 +- lib/modules/player/player_controls.dart | 2 +- lib/pages/home/genres/genres.dart | 91 ++++++++++--------- lib/pages/root/root_app.dart | 9 +- 8 files changed, 93 insertions(+), 68 deletions(-) diff --git a/lib/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart b/lib/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart index 0ebebea7..d37bc8a0 100644 --- a/lib/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart +++ b/lib/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart @@ -48,11 +48,15 @@ class HorizontalPlaybuttonCardView extends HookWidget { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - DefaultTextStyle( - style: context.theme.typography.h4.copyWith( - color: context.theme.colorScheme.foreground, + Flexible( + child: DefaultTextStyle( + style: context.theme.typography.h4.copyWith( + color: context.theme.colorScheme.foreground, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + child: title, ), - child: title, ), if (titleTrailing != null) titleTrailing!, ], diff --git a/lib/components/playbutton_view/playbutton_card.dart b/lib/components/playbutton_view/playbutton_card.dart index 849bab2a..21016d57 100644 --- a/lib/components/playbutton_view/playbutton_card.dart +++ b/lib/components/playbutton_view/playbutton_card.dart @@ -1,4 +1,5 @@ import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/extensions/string.dart'; @@ -32,16 +33,23 @@ class PlaybuttonCard extends StatelessWidget { @override Widget build(BuildContext context) { final unescapeHtml = description?.unescapeHtml().cleanHtml() ?? ""; + final scale = context.theme.scaling; - return Container( - width: 150, + return SizedBox( + width: 150 * scale, child: CardImage( image: Stack( children: [ - UniversalImage( - path: imageUrl, - height: 150, - fit: BoxFit.cover, + Container( + width: 150 * scale, + height: 150 * scale, + decoration: BoxDecoration( + borderRadius: context.theme.borderRadiusMd, + image: DecorationImage( + image: UniversalImage.imageProvider(imageUrl), + fit: BoxFit.cover, + ), + ), ), StatedWidget.builder( builder: (context, states) { diff --git a/lib/components/playbutton_view/playbutton_tile.dart b/lib/components/playbutton_view/playbutton_tile.dart index 3f9d89fe..e06f3689 100644 --- a/lib/components/playbutton_view/playbutton_tile.dart +++ b/lib/components/playbutton_view/playbutton_tile.dart @@ -33,15 +33,18 @@ class PlaybuttonTile extends StatelessWidget { @override Widget build(BuildContext context) { final cleanDescription = description?.unescapeHtml().cleanHtml() ?? ""; + final scale = context.theme.scaling; return Button.ghost( - leading: ClipRRect( - borderRadius: context.theme.borderRadiusMd, - child: UniversalImage( - path: imageUrl, - width: 40, - height: 40, - fit: BoxFit.cover, + leading: Container( + width: 50 * scale, + height: 50 * scale, + decoration: BoxDecoration( + borderRadius: context.theme.borderRadiusMd, + image: DecorationImage( + image: UniversalImage.imageProvider(imageUrl), + fit: BoxFit.cover, + ), ), ), trailing: Row( diff --git a/lib/components/playbutton_view/playbutton_view.dart b/lib/components/playbutton_view/playbutton_view.dart index 52cfb592..7520f313 100644 --- a/lib/components/playbutton_view/playbutton_view.dart +++ b/lib/components/playbutton_view/playbutton_view.dart @@ -1,5 +1,6 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/playbutton_view/playbutton_card.dart'; @@ -98,9 +99,9 @@ class PlaybuttonView extends StatelessWidget { switch ((isGrid.value, isLoading)) { (true, _) => SliverGrid.builder( itemCount: isLoading ? 6 : itemCount + 1, - gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( - maxCrossAxisExtent: 150, - mainAxisExtent: 225, + gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: 150 * context.theme.scaling, + mainAxisExtent: 225 * context.theme.scaling, crossAxisSpacing: 8, mainAxisSpacing: 8, ), diff --git a/lib/main.dart b/lib/main.dart index cae1e9fe..0b84d38d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -210,13 +210,13 @@ class Spotube extends HookConsumerWidget { return child; }, + scaling: const AdaptiveScaling(1), theme: ThemeData( radius: .5, iconTheme: const IconThemeProperties(), colorScheme: ColorSchemes.lightBlue(), surfaceOpacity: .8, surfaceBlur: 10, - typography: const Typography.geist(), ), darkTheme: ThemeData( radius: .5, @@ -224,7 +224,6 @@ class Spotube extends HookConsumerWidget { colorScheme: ColorSchemes.darkNeutral(), surfaceOpacity: .8, surfaceBlur: 10, - typography: const Typography.geist(), ), themeMode: themeMode, shortcuts: { diff --git a/lib/modules/player/player_controls.dart b/lib/modules/player/player_controls.dart index 3c1cd503..acc3064e 100644 --- a/lib/modules/player/player_controls.dart +++ b/lib/modules/player/player_controls.dart @@ -3,7 +3,7 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:media_kit/media_kit.dart'; import 'package:palette_generator/palette_generator.dart'; -import 'package:shadcn_flutter/shadcn_flutter.dart' hide ThemeData; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/collections/intents.dart'; diff --git a/lib/pages/home/genres/genres.dart b/lib/pages/home/genres/genres.dart index ed9d9351..062852e8 100644 --- a/lib/pages/home/genres/genres.dart +++ b/lib/pages/home/genres/genres.dart @@ -1,10 +1,12 @@ import 'dart:math'; import 'package:auto_size_text/auto_size_text.dart'; -import 'package:flutter/material.dart'; + import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/collections/gradients.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/extensions/constrains.dart'; @@ -18,19 +20,19 @@ class GenrePage extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final ThemeData(:textTheme) = Theme.of(context); final scrollController = useScrollController(); final categories = ref.watch(categoriesProvider); final mediaQuery = MediaQuery.of(context); - return Scaffold( - appBar: TitleBar( - title: Text(context.l10n.explore_genres), - automaticallyImplyLeading: true, - ), - body: SafeArea( - top: false, + return SafeArea( + child: Scaffold( + headers: [ + TitleBar( + title: Text(context.l10n.explore_genres), + automaticallyImplyLeading: true, + ) + ], child: GridView.builder( padding: const EdgeInsets.all(12), controller: scrollController, @@ -45,9 +47,8 @@ class GenrePage extends HookConsumerWidget { itemBuilder: (context, index) { final category = categories.asData!.value[index]; final gradient = gradients[Random().nextInt(gradients.length)]; - return InkWell( - borderRadius: BorderRadius.circular(8), - onTap: () { + return CardImage( + onPressed: () { context.pushNamed( GenrePlaylistsPage.name, pathParameters: { @@ -56,37 +57,45 @@ class GenrePage extends HookConsumerWidget { extra: category, ); }, - child: Ink( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - image: DecorationImage( - image: NetworkImage(category.icons!.first.url!), - fit: BoxFit.cover, - ), - gradient: gradient, - ), - child: Align( - alignment: Alignment.bottomCenter, - child: AutoSizeText( - category.name!, - style: textTheme.titleLarge?.copyWith( - color: Colors.white, - shadows: [ - // stroke shadow - const Shadow( - color: Colors.black, - offset: Offset(1, 1), - blurRadius: 2, - ), - ], + image: Stack( + children: [ + Container( + height: 300, + width: 250, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + image: DecorationImage( + image: NetworkImage(category.icons!.first.url!), + fit: BoxFit.cover, + ), + gradient: gradient, ), - maxLines: 1, - textAlign: TextAlign.center, - maxFontSize: textTheme.titleLarge!.fontSize!, - minFontSize: textTheme.titleMedium!.fontSize!, ), - ), + Positioned.fill( + bottom: 10, + child: Align( + alignment: Alignment.bottomCenter, + child: AutoSizeText( + category.name!, + style: context.theme.typography.h3.copyWith( + color: Colors.white, + shadows: [ + // stroke shadow + const Shadow( + color: Colors.black, + offset: Offset(1, 1), + blurRadius: 2, + ), + ], + ), + maxLines: 1, + textAlign: TextAlign.center, + maxFontSize: context.theme.typography.h3.fontSize!, + minFontSize: context.theme.typography.large.fontSize!, + ), + ), + ), + ], ), ); }, diff --git a/lib/pages/root/root_app.dart b/lib/pages/root/root_app.dart index 84c40a2f..606bba34 100644 --- a/lib/pages/root/root_app.dart +++ b/lib/pages/root/root_app.dart @@ -161,18 +161,19 @@ class RootApp extends HookConsumerWidget { useEndlessPlayback(ref); final backgroundColor = Theme.of(context).colorScheme.background; + final brightness = Theme.of(context).brightness; useEffect(() { SystemChrome.setSystemUIOverlayStyle( SystemUiOverlayStyle( statusBarColor: backgroundColor, // status bar color - statusBarIconBrightness: backgroundColor.computeLuminance() > 0.179 - ? Brightness.dark - : Brightness.light, + statusBarIconBrightness: brightness == Brightness.dark + ? Brightness.light + : Brightness.dark, ), ); return null; - }, [backgroundColor]); + }, [backgroundColor, brightness]); final navTileNames = useMemoized(() { return getSidebarTileList(context.l10n).map((s) => s.name).toList(); From d53782da23fb4ce44c1337b141d1c575fb739e30 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 28 Dec 2024 14:30:25 +0600 Subject: [PATCH 028/112] refactor: playlist and album pages --- .fvm/fvm_config.json | 2 +- .fvmrc | 2 +- .vscode/settings.json | 2 +- .../adaptive/adaptive_pop_sheet_list.dart | 31 +- lib/components/heart_button/heart_button.dart | 50 +-- lib/components/sort_tracks_dropdown.dart | 88 ----- .../presentation_actions.dart | 220 +++++++++++ .../track_presentation/presentation_list.dart | 84 +++++ .../presentation_modifiers.dart | 117 ++++++ .../presentation_props.dart} | 67 ++-- .../presentation_state.dart | 157 ++++++++ .../track_presentation/presentation_top.dart | 262 +++++++++++++ .../sort_tracks_dropdown.dart | 70 ++++ .../track_presentation.dart | 72 ++++ .../use_action_callbacks.dart | 135 +++++++ .../use_is_user_playlist.dart | 0 .../use_track_tile_play_callback.dart | 84 +++++ lib/components/track_tile/track_tile.dart | 354 ++++++++++-------- .../sections/body/track_view_body.dart | 192 ---------- .../body/track_view_body_headers.dart | 105 ------ .../sections/body/track_view_options.dart | 140 ------- .../sections/header/flexible_header.dart | 167 --------- .../sections/header/header_actions.dart | 111 ------ .../sections/header/header_buttons.dart | 206 ---------- lib/components/tracks_view/track_view.dart | 52 --- .../tracks_view/track_view_provider.dart | 64 ---- lib/l10n/app_en.arb | 7 +- lib/main.dart | 4 + lib/modules/root/sidebar.dart | 4 +- .../settings/section_card_with_heading.dart | 6 +- lib/pages/album/album.dart | 80 ++-- lib/pages/library/local_folder.dart | 2 +- lib/pages/playlist/liked_playlist.dart | 48 +-- lib/pages/playlist/playlist.dart | 93 ++--- .../xcshareddata/xcschemes/Runner.xcscheme | 1 + pubspec.lock | 48 +-- untranslated_messages.json | 182 +++++++-- 37 files changed, 1793 insertions(+), 1516 deletions(-) delete mode 100644 lib/components/sort_tracks_dropdown.dart create mode 100644 lib/components/track_presentation/presentation_actions.dart create mode 100644 lib/components/track_presentation/presentation_list.dart create mode 100644 lib/components/track_presentation/presentation_modifiers.dart rename lib/components/{tracks_view/track_view_props.dart => track_presentation/presentation_props.dart} (60%) create mode 100644 lib/components/track_presentation/presentation_state.dart create mode 100644 lib/components/track_presentation/presentation_top.dart create mode 100644 lib/components/track_presentation/sort_tracks_dropdown.dart create mode 100644 lib/components/track_presentation/track_presentation.dart create mode 100644 lib/components/track_presentation/use_action_callbacks.dart rename lib/components/{tracks_view/sections/body => track_presentation}/use_is_user_playlist.dart (100%) create mode 100644 lib/components/track_presentation/use_track_tile_play_callback.dart delete mode 100644 lib/components/tracks_view/sections/body/track_view_body.dart delete mode 100644 lib/components/tracks_view/sections/body/track_view_body_headers.dart delete mode 100644 lib/components/tracks_view/sections/body/track_view_options.dart delete mode 100644 lib/components/tracks_view/sections/header/flexible_header.dart delete mode 100644 lib/components/tracks_view/sections/header/header_actions.dart delete mode 100644 lib/components/tracks_view/sections/header/header_buttons.dart delete mode 100644 lib/components/tracks_view/track_view.dart delete mode 100644 lib/components/tracks_view/track_view_provider.dart diff --git a/.fvm/fvm_config.json b/.fvm/fvm_config.json index 41b45a53..7572d05e 100644 --- a/.fvm/fvm_config.json +++ b/.fvm/fvm_config.json @@ -1,3 +1,3 @@ { - "flutterSdkVersion": "3.27.1" + "flutterSdkVersion": "3.28.0-0.1.pre" } \ No newline at end of file diff --git a/.fvmrc b/.fvmrc index d1af5d57..089fa312 100644 --- a/.fvmrc +++ b/.fvmrc @@ -1,4 +1,4 @@ { - "flutter": "3.27.1", + "flutter": "3.28.0-0.1.pre", "flavors": {} } \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 4d76417f..a5548411 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -28,5 +28,5 @@ "README.md": "LICENSE,CODE_OF_CONDUCT.md,CONTRIBUTING.md,SECURITY.md,CONTRIBUTION.md,CHANGELOG.md,PRIVACY_POLICY.md", "*.dart": "${capture}.g.dart,${capture}.freezed.dart" }, - "dart.flutterSdkPath": ".fvm/versions/3.27.1" + "dart.flutterSdkPath": ".fvm/versions/3.28.0-0.1.pre" } \ No newline at end of file diff --git a/lib/components/adaptive/adaptive_pop_sheet_list.dart b/lib/components/adaptive/adaptive_pop_sheet_list.dart index 63499e8a..d81ca977 100644 --- a/lib/components/adaptive/adaptive_pop_sheet_list.dart +++ b/lib/components/adaptive/adaptive_pop_sheet_list.dart @@ -1,4 +1,4 @@ -import 'package:flutter/material.dart' show ListTile, showModalBottomSheet; +import 'package:flutter/material.dart' show showModalBottomSheet; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/collections/spotube_icons.dart'; @@ -39,6 +39,8 @@ class AdaptivePopSheetList extends StatelessWidget { final Offset offset; + final ButtonVariance variance; + const AdaptivePopSheetList({ super.key, required this.children, @@ -49,6 +51,7 @@ class AdaptivePopSheetList extends StatelessWidget { this.onSelected, required this.tooltip, this.offset = Offset.zero, + this.variance = ButtonVariance.ghost, }) : assert( !(icon != null && child != null), 'Either icon or child must be provided', @@ -79,7 +82,7 @@ class AdaptivePopSheetList extends StatelessWidget { }).toList(); if (mediaQuery.mdAndUp) { - await showDropdown( + await showDropdown( context: context, rootOverlay: useRootNavigator, // heightConstraint: PopoverConstraint.anchorFixedSize, @@ -113,19 +116,21 @@ class AdaptivePopSheetList extends StatelessWidget { itemBuilder: (context, index) { final data = childrenModified[index]; - return ListTile( - dense: true, - leading: data.leading, - title: data.child, + return Button( enabled: data.enabled, - trailing: data.trailing, - focusNode: data.focusNode, - onTap: () { + style: ButtonVariance.ghost.copyWith( + padding: (context, state, value) => const EdgeInsets.all(16), + ), + onPressed: () { data.onPressed?.call(context); if (data.autoClose) { Navigator.of(context).pop(); } }, + leading: data.leading, + trailing: data.trailing, + alignment: Alignment.centerLeft, + child: data.child, ); }, ); @@ -142,7 +147,8 @@ class AdaptivePopSheetList extends StatelessWidget { tooltip: TooltipContainer( child: Text(tooltip), ), - child: IconButton.ghost( + child: IconButton( + variance: variance, icon: icon ?? const Icon(SpotubeIcons.moreVertical), onPressed: () { final renderBox = context.findRenderObject() as RenderBox; @@ -167,7 +173,7 @@ class AdaptivePopSheetList extends StatelessWidget { tooltip: TooltipContainer(child: Text(tooltip)), child: Button( onPressed: () => showDropdownMenu(context, Offset.zero), - style: const ButtonStyle.ghost(), + style: variance, child: IgnorePointer(child: child), ), ); @@ -175,7 +181,8 @@ class AdaptivePopSheetList extends StatelessWidget { return Tooltip( tooltip: TooltipContainer(child: Text(tooltip)), - child: IconButton.ghost( + child: IconButton( + variance: variance, icon: icon ?? const Icon(SpotubeIcons.moreVertical), onPressed: () => showDropdownMenu(context, Offset.zero), ), diff --git a/lib/components/heart_button/heart_button.dart b/lib/components/heart_button/heart_button.dart index fa4318cc..56cb22ab 100644 --- a/lib/components/heart_button/heart_button.dart +++ b/lib/components/heart_button/heart_button.dart @@ -1,5 +1,5 @@ -import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/heart_button/use_track_toggle_like.dart'; @@ -13,12 +13,16 @@ class HeartButton extends HookConsumerWidget { final IconData? icon; final Color? color; final String? tooltip; + final ButtonVariance variance; + final ButtonSize size; const HeartButton({ required this.isLiked, required this.onPressed, this.color, this.tooltip, this.icon, + this.variance = ButtonVariance.ghost, + this.size = ButtonSize.normal, super.key, }); @@ -28,28 +32,32 @@ class HeartButton extends HookConsumerWidget { if (auth.asData?.value == null) return const SizedBox.shrink(); - return IconButton( - tooltip: tooltip, - icon: AnimatedSwitcher( - switchInCurve: Curves.fastOutSlowIn, - switchOutCurve: Curves.fastOutSlowIn, - duration: const Duration(milliseconds: 300), - transitionBuilder: (child, animation) { - return ScaleTransition( - scale: animation, - child: child, - ); - }, - child: Icon( - icon ?? - (isLiked - ? Icons.favorite_rounded - : Icons.favorite_outline_rounded), - key: ValueKey(isLiked), - color: color ?? (isLiked ? color ?? Colors.red : null), + return Tooltip( + tooltip: TooltipContainer(child: Text(tooltip ?? "")), + child: IconButton( + variance: variance, + size: size, + icon: AnimatedSwitcher( + switchInCurve: Curves.fastOutSlowIn, + switchOutCurve: Curves.fastOutSlowIn, + duration: const Duration(milliseconds: 300), + transitionBuilder: (child, animation) { + return ScaleTransition( + scale: animation, + child: child, + ); + }, + child: Icon( + icon ?? + (isLiked + ? Icons.favorite_rounded + : Icons.favorite_outline_rounded), + key: ValueKey(isLiked), + color: color ?? (isLiked ? color ?? Colors.red : null), + ), ), + onPressed: onPressed, ), - onPressed: onPressed, ); } } diff --git a/lib/components/sort_tracks_dropdown.dart b/lib/components/sort_tracks_dropdown.dart deleted file mode 100644 index 4f65e738..00000000 --- a/lib/components/sort_tracks_dropdown.dart +++ /dev/null @@ -1,88 +0,0 @@ -import 'package:flutter/material.dart'; - -import 'package:spotube/collections/spotube_icons.dart'; -import 'package:spotube/modules/library/user_local_tracks.dart'; -import 'package:spotube/components/adaptive/adaptive_pop_sheet_list.dart'; -import 'package:spotube/extensions/context.dart'; - -class SortTracksDropdown extends StatelessWidget { - final SortBy? value; - final void Function(SortBy)? onChanged; - const SortTracksDropdown({ - this.onChanged, - this.value, - super.key, - }); - - @override - Widget build(BuildContext context) { - var theme = Theme.of(context); - return ListTileTheme( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - child: AdaptivePopSheetList( - children: [ - AdaptiveMenuButton( - value: SortBy.none, - enabled: value != SortBy.none, - child: Text(context.l10n.none), - ), - AdaptiveMenuButton( - value: SortBy.ascending, - enabled: value != SortBy.ascending, - child: Text(context.l10n.sort_a_z), - ), - AdaptiveMenuButton( - value: SortBy.descending, - enabled: value != SortBy.descending, - child: Text(context.l10n.sort_z_a), - ), - AdaptiveMenuButton( - value: SortBy.newest, - enabled: value != SortBy.newest, - child: Text(context.l10n.sort_newest), - ), - AdaptiveMenuButton( - value: SortBy.oldest, - enabled: value != SortBy.oldest, - child: Text(context.l10n.sort_oldest), - ), - AdaptiveMenuButton( - value: SortBy.duration, - enabled: value != SortBy.duration, - child: Text(context.l10n.sort_duration), - ), - AdaptiveMenuButton( - value: SortBy.artist, - enabled: value != SortBy.artist, - child: Text(context.l10n.sort_artist), - ), - AdaptiveMenuButton( - value: SortBy.album, - enabled: value != SortBy.album, - child: Text(context.l10n.sort_album), - ), - ], - headings: [ - Text(context.l10n.sort_tracks), - ], - onSelected: onChanged, - tooltip: context.l10n.sort_tracks, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0), - child: DefaultTextStyle( - style: theme.textTheme.titleSmall!, - child: Row( - children: [ - const Icon(SpotubeIcons.sort), - const SizedBox(width: 8), - Text(context.l10n.sort_tracks), - ], - ), - ), - ), - ), - ); - } -} diff --git a/lib/components/track_presentation/presentation_actions.dart b/lib/components/track_presentation/presentation_actions.dart new file mode 100644 index 00000000..41f518d0 --- /dev/null +++ b/lib/components/track_presentation/presentation_actions.dart @@ -0,0 +1,220 @@ +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; +import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/adaptive/adaptive_pop_sheet_list.dart'; +import 'package:spotube/components/dialogs/confirm_download_dialog.dart'; +import 'package:spotube/components/dialogs/playlist_add_track_dialog.dart'; +import 'package:spotube/components/track_presentation/presentation_props.dart'; +import 'package:spotube/components/track_presentation/presentation_state.dart'; +import 'package:spotube/extensions/context.dart'; +import 'package:spotube/models/database/database.dart'; +import 'package:spotube/provider/download_manager_provider.dart'; +import 'package:spotube/provider/history/history.dart'; +import 'package:spotube/provider/audio_player/audio_player.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; + +class TrackPresentationActionsSection extends HookConsumerWidget { + const TrackPresentationActionsSection({super.key}); + + showToastForAction(BuildContext context, String action, int count) { + final message = switch (action) { + "download" => (context.l10n.download_count(count), SpotubeIcons.download), + "add-to-playlist" => ( + context.l10n.add_count_to_playlist(count), + SpotubeIcons.playlistAdd + ), + "add-to-queue" => ( + context.l10n.add_count_to_queue(count), + SpotubeIcons.queueAdd + ), + "play-next" => ( + context.l10n.play_count_next(count), + SpotubeIcons.lightning + ), + _ => ("", SpotubeIcons.error), + }; + + showToast( + context: context, + location: ToastLocation.topRight, + builder: (context, overlay) { + return SurfaceCard( + child: Basic( + leading: Icon(message.$2), + title: Text(message.$1), + leadingAlignment: Alignment.center, + trailing: IconButton.ghost( + size: ButtonSize.small, + icon: const Icon(SpotubeIcons.close), + onPressed: () { + overlay.close(); + }, + ), + ), + ); + }, + ); + } + + @override + Widget build(BuildContext context, ref) { + final options = TrackPresentationOptions.of(context); + + ref.watch(downloadManagerProvider); + final downloader = ref.watch(downloadManagerProvider.notifier); + final playlistNotifier = ref.watch(audioPlayerProvider.notifier); + final historyNotifier = ref.watch(playbackHistoryActionsProvider); + final audioSource = + ref.watch(userPreferencesProvider.select((s) => s.audioSource)); + + final state = ref.watch(presentationStateProvider(options.collection)); + final notifier = + ref.watch(presentationStateProvider(options.collection).notifier); + final selectedTracks = state.selectedTracks; + + return AdaptivePopSheetList( + tooltip: context.l10n.more_actions, + headings: [ + Text( + context.l10n.more_actions, + style: context.theme.typography.large, + ), + ], + onSelected: (action) async { + var tracks = selectedTracks; + + if (selectedTracks.isEmpty) { + tracks = await options.pagination.onFetchAll(); + + notifier.selectAllTracks(); + } + + if (!context.mounted) return; + + switch (action) { + case "download": + { + final confirmed = audioSource == AudioSource.piped || + await showDialog( + context: context, + builder: (context) { + return const ConfirmDownloadDialog(); + }, + ); + if (confirmed != true) return; + downloader.batchAddToQueue(tracks); + notifier.deselectAllTracks(); + if (!context.mounted) return; + showToastForAction(context, action, tracks.length); + break; + } + case "add-to-playlist": + { + if (context.mounted) { + final worked = await showDialog( + context: context, + builder: (context) { + return PlaylistAddTrackDialog( + openFromPlaylist: options.collectionId, + tracks: tracks.toList(), + ); + }, + ); + + if (!context.mounted || worked != true) return; + showToastForAction(context, action, tracks.length); + } + break; + } + case "play-next": + { + playlistNotifier.addTracksAtFirst(tracks); + playlistNotifier.addCollection(options.collectionId); + if (options.collection is AlbumSimple) { + historyNotifier.addAlbums([options.collection as AlbumSimple]); + } else { + historyNotifier + .addPlaylists([options.collection as PlaylistSimple]); + } + notifier.deselectAllTracks(); + if (!context.mounted) return; + showToastForAction(context, action, tracks.length); + break; + } + case "add-to-queue": + { + playlistNotifier.addTracks(tracks); + playlistNotifier.addCollection(options.collectionId); + if (options.collection is AlbumSimple) { + historyNotifier.addAlbums([options.collection as AlbumSimple]); + } else { + historyNotifier + .addPlaylists([options.collection as PlaylistSimple]); + } + notifier.deselectAllTracks(); + if (!context.mounted) return; + showToastForAction(context, action, tracks.length); + break; + } + default: + } + + if (!context.mounted) return; + }, + icon: const Icon(SpotubeIcons.moreVertical), + variance: ButtonVariance.outline, + children: [ + AdaptiveMenuButton( + value: "download", + leading: const Icon(SpotubeIcons.download), + child: selectedTracks.isEmpty || + selectedTracks.length == options.tracks.length + ? Text( + context.l10n.download_all, + ) + : Text( + context.l10n.download_count(selectedTracks.length), + ), + ), + AdaptiveMenuButton( + value: "add-to-playlist", + leading: const Icon(SpotubeIcons.playlistAdd), + child: selectedTracks.isEmpty || + selectedTracks.length == options.tracks.length + ? Text( + context.l10n.add_all_to_playlist, + ) + : Text( + context.l10n.add_count_to_playlist(selectedTracks.length), + ), + ), + AdaptiveMenuButton( + value: "add-to-queue", + leading: const Icon(SpotubeIcons.queueAdd), + child: selectedTracks.isEmpty || + selectedTracks.length == options.tracks.length + ? Text( + context.l10n.add_all_to_queue, + ) + : Text( + context.l10n.add_count_to_queue(selectedTracks.length), + ), + ), + AdaptiveMenuButton( + value: "play-next", + leading: const Icon(SpotubeIcons.lightning), + child: selectedTracks.isEmpty || + selectedTracks.length == options.tracks.length + ? Text( + context.l10n.play_all_next, + ) + : Text( + context.l10n.play_count_next(selectedTracks.length), + ), + ), + ], + ); + } +} diff --git a/lib/components/track_presentation/presentation_list.dart b/lib/components/track_presentation/presentation_list.dart new file mode 100644 index 00000000..55b4c46d --- /dev/null +++ b/lib/components/track_presentation/presentation_list.dart @@ -0,0 +1,84 @@ +import 'package:flutter/services.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:skeletonizer/skeletonizer.dart'; +import 'package:spotube/collections/fake.dart'; +import 'package:spotube/components/track_presentation/presentation_props.dart'; +import 'package:spotube/components/track_presentation/presentation_state.dart'; +import 'package:spotube/components/track_presentation/use_track_tile_play_callback.dart'; +import 'package:spotube/components/track_tile/track_tile.dart'; +import 'package:spotube/components/track_presentation/use_is_user_playlist.dart'; +import 'package:spotube/provider/audio_player/audio_player.dart'; +import 'package:very_good_infinite_list/very_good_infinite_list.dart'; + +class PresentationListSection extends HookConsumerWidget { + const PresentationListSection({super.key}); + + @override + Widget build(BuildContext context, ref) { + final options = TrackPresentationOptions.of(context); + final playlist = ref.watch(audioPlayerProvider); + final state = ref.watch(presentationStateProvider(options.collection)); + final notifier = + ref.read(presentationStateProvider(options.collection).notifier); + final isUserPlaylist = useIsUserPlaylist(ref, options.collectionId); + + final onTileTap = useTrackTilePlayCallback(ref); + + return SliverInfiniteList( + isLoading: options.pagination.isLoading, + onFetchData: options.pagination.onFetchMore, + itemCount: state.presentationTracks.length, + hasReachedMax: !options.pagination.hasNextPage, + loadingBuilder: (context) { + return Skeletonizer( + enabled: true, + child: TrackTile( + index: 0, + playlist: playlist, + track: FakeData.track, + ), + ); + }, + emptyBuilder: (context) => Skeletonizer( + enabled: true, + child: Column( + children: List.generate( + 10, + (index) => TrackTile( + track: FakeData.track, + index: index, + playlist: playlist, + ), + ), + ), + ), + itemBuilder: (context, index) { + final track = state.presentationTracks[index]; + final isSelected = state.selectedTracks.any((e) => e.id == track.id); + return TrackTile( + userPlaylist: isUserPlaylist, + playlistId: options.collectionId, + index: index, + playlist: playlist, + track: track, + selected: isSelected, + onTap: () => onTileTap(track, index), + onChanged: state.selectedTracks.isEmpty + ? null + : (isSelected) { + if (isSelected == true) { + notifier.selectTrack(track); + } else { + notifier.deselectTrack(track); + } + }, + onLongPress: () { + notifier.selectTrack(track); + HapticFeedback.selectionClick(); + }, + ); + }, + ); + } +} diff --git a/lib/components/track_presentation/presentation_modifiers.dart b/lib/components/track_presentation/presentation_modifiers.dart new file mode 100644 index 00000000..d1678e17 --- /dev/null +++ b/lib/components/track_presentation/presentation_modifiers.dart @@ -0,0 +1,117 @@ +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; +import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/track_presentation/sort_tracks_dropdown.dart'; +import 'package:spotube/components/track_presentation/presentation_actions.dart'; +import 'package:spotube/components/track_presentation/presentation_props.dart'; +import 'package:spotube/components/track_presentation/presentation_state.dart'; +import 'package:spotube/extensions/constrains.dart'; +import 'package:spotube/extensions/context.dart'; + +class TrackPresentationModifiersSection extends HookConsumerWidget { + const TrackPresentationModifiersSection({super.key}); + + @override + Widget build(BuildContext context, ref) { + final options = TrackPresentationOptions.of(context); + final state = ref.watch(presentationStateProvider(options.collection)); + final notifier = ref.watch( + presentationStateProvider(options.collection).notifier, + ); + + final controller = useTextEditingController(); + + return LayoutBuilder(builder: (context, constrains) { + return Padding( + padding: EdgeInsets.symmetric( + horizontal: constrains.mdAndUp ? 16 : 8, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Checkbox( + state: state.selectedTracks.length == options.tracks.length + ? CheckboxState.checked + : CheckboxState.unchecked, + onChanged: (value) { + if (value == CheckboxState.checked) { + notifier.selectAllTracks(); + } else { + notifier.deselectAllTracks(); + } + }, + ), + ], + ), + Flexible( + child: Row( + mainAxisSize: MainAxisSize.min, + spacing: 8, + children: [ + Flexible( + child: ConstrainedBox( + constraints: const BoxConstraints( + maxWidth: 320, + ), + child: TextField( + controller: controller, + leading: Icon( + SpotubeIcons.search, + color: context.theme.colorScheme.mutedForeground, + ), + placeholder: Text(context.l10n.search_tracks), + onChanged: (value) { + if (value.isEmpty) { + notifier.clearFilter(); + } else { + notifier.filterTracks(value); + } + }, + trailing: ListenableBuilder( + listenable: controller, + builder: (context, _) { + return AnimatedCrossFade( + duration: const Duration(milliseconds: 300), + crossFadeState: controller.text.isEmpty + ? CrossFadeState.showFirst + : CrossFadeState.showSecond, + firstChild: + const SizedBox.square(dimension: 20), + secondChild: AnimatedScale( + duration: const Duration(milliseconds: 300), + scale: controller.text.isEmpty ? 0 : 1, + child: IconButton.ghost( + size: const ButtonSize(.6), + icon: const Icon(SpotubeIcons.close), + onPressed: () { + controller.clear(); + notifier.clearFilter(); + }, + ), + ), + ); + }), + ), + ), + ), + SortTracksDropdown( + value: state.sortBy, + onChanged: (value) { + notifier.sortTracks(value); + }, + ), + const TrackPresentationActionsSection(), + ], + ), + ), + ], + ), + ); + }); + } +} diff --git a/lib/components/tracks_view/track_view_props.dart b/lib/components/track_presentation/presentation_props.dart similarity index 60% rename from lib/components/tracks_view/track_view_props.dart rename to lib/components/track_presentation/presentation_props.dart index b0a00ae2..144cf0e8 100644 --- a/lib/components/tracks_view/track_view_props.dart +++ b/lib/components/track_presentation/presentation_props.dart @@ -1,6 +1,6 @@ import 'dart:async'; -import 'package:flutter/material.dart' hide Page; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; class PaginationProps { @@ -38,31 +38,33 @@ class PaginationProps { onRefresh.hashCode; } -class InheritedTrackView extends InheritedWidget { +class TrackPresentationOptions { final Object collection; final String title; final String? description; + final String? owner; + final String? ownerImage; final String image; final String routePath; final List tracks; final PaginationProps pagination; final bool isLiked; - final String shareUrl; + final String? shareUrl; // events final FutureOr Function()? onHeart; // if null heart button will hidden - const InheritedTrackView({ - super.key, - required super.child, + const TrackPresentationOptions({ required this.collection, required this.title, this.description, + this.owner, + this.ownerImage, required this.image, required this.tracks, required this.pagination, required this.routePath, - required this.shareUrl, + this.shareUrl, this.isLiked = false, this.onHeart, }) : assert(collection is AlbumSimple || collection is PlaylistSimple); @@ -71,29 +73,36 @@ class InheritedTrackView extends InheritedWidget { ? (collection as AlbumSimple).id! : (collection as PlaylistSimple).id!; - @override - bool updateShouldNotify(InheritedTrackView oldWidget) { - return oldWidget.title != title || - oldWidget.description != description || - oldWidget.image != image || - oldWidget.tracks != tracks || - oldWidget.pagination != pagination || - oldWidget.isLiked != isLiked || - oldWidget.onHeart != onHeart || - oldWidget.shareUrl != shareUrl || - oldWidget.routePath != routePath || - oldWidget.collection != collection || - oldWidget.child != child; + static TrackPresentationOptions of(BuildContext context) { + return Data.of(context); } - static InheritedTrackView of(BuildContext context) { - final widget = - context.dependOnInheritedWidgetOfExactType(); - if (widget == null) { - throw Exception( - 'InheritedTrackView not found. Make sure to wrap [TrackView] with [InheritedTrackView]', - ); - } - return widget; + @override + operator ==(Object other) { + return other is TrackPresentationOptions && + other.collection == collection && + other.title == title && + other.description == description && + other.image == image && + other.routePath == routePath && + other.tracks == tracks && + other.pagination == pagination && + other.isLiked == isLiked && + other.shareUrl == shareUrl && + other.onHeart == onHeart; } + + @override + int get hashCode => + super.hashCode ^ + collection.hashCode ^ + title.hashCode ^ + description.hashCode ^ + image.hashCode ^ + routePath.hashCode ^ + tracks.hashCode ^ + pagination.hashCode ^ + isLiked.hashCode ^ + shareUrl.hashCode ^ + onHeart.hashCode; } diff --git a/lib/components/track_presentation/presentation_state.dart b/lib/components/track_presentation/presentation_state.dart new file mode 100644 index 00000000..11ca9809 --- /dev/null +++ b/lib/components/track_presentation/presentation_state.dart @@ -0,0 +1,157 @@ +import 'package:collection/collection.dart'; +import 'package:fuzzywuzzy/fuzzywuzzy.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotify/spotify.dart'; +import 'package:spotube/modules/library/user_local_tracks.dart'; +import 'package:spotube/provider/spotify/spotify.dart'; +import 'package:spotube/utils/service_utils.dart'; + +class PresentationState { + final List selectedTracks; + final List presentationTracks; + final SortBy sortBy; + + const PresentationState({ + required this.selectedTracks, + required this.presentationTracks, + required this.sortBy, + }); + + PresentationState copyWith({ + List? selectedTracks, + List? presentationTracks, + SortBy? sortBy, + }) { + return PresentationState( + selectedTracks: selectedTracks ?? this.selectedTracks, + presentationTracks: presentationTracks ?? this.presentationTracks, + sortBy: sortBy ?? this.sortBy, + ); + } +} + +class PresentationStateNotifier + extends AutoDisposeFamilyNotifier { + @override + PresentationState build(collection) { + final isPlaylist = arg is PlaylistSimple; + + if ((isPlaylist && (arg as PlaylistSimple).id != "user-liked-tracks") || + arg is AlbumSimple) { + ref.listen( + isPlaylist + ? playlistTracksProvider((arg as PlaylistSimple).id!) + : albumTracksProvider((arg as AlbumSimple)), + (previous, next) { + next.whenData((value) { + state = state.copyWith( + presentationTracks: ServiceUtils.sortTracks( + value.items, + state.sortBy, + ), + ); + }); + }, + ); + } + + return PresentationState( + selectedTracks: [], + presentationTracks: tracks, + sortBy: SortBy.none, + ); + } + + List get tracks { + assert( + arg is PlaylistSimple || arg is AlbumSimple, + "arg must be PlaylistSimple or AlbumSimple", + ); + + final isPlaylist = arg is PlaylistSimple; + final isSavedTrackPlaylist = + isPlaylist && (arg as PlaylistSimple).id == "user-liked-tracks"; + final tracks = switch ((isPlaylist, isSavedTrackPlaylist)) { + (true, true) => ref.read(likedTracksProvider).asData?.value, + (true, false) => ref + .read(playlistTracksProvider((arg as PlaylistSimple).id!)) + .asData + ?.value + .items, + _ => ref + .read(albumTracksProvider((arg as AlbumSimple))) + .asData + ?.value + .items, + } ?? + []; + + return tracks; + } + + void selectTrack(Track track) { + if (state.selectedTracks.any((e) => e.id == track.id)) { + return; + } + + state = state.copyWith( + selectedTracks: [...state.selectedTracks, track], + ); + } + + void selectAllTracks() { + state = state.copyWith( + selectedTracks: tracks, + ); + } + + void deselectTrack(Track track) { + state = state.copyWith( + selectedTracks: state.selectedTracks.where((e) => e != track).toList(), + ); + } + + void deselectAllTracks() { + state = state.copyWith( + selectedTracks: [], + ); + } + + void filterTracks(String query) { + if (query.isEmpty) { + return; + } + + state = state.copyWith( + presentationTracks: ServiceUtils.sortTracks( + tracks + .map((e) => (weightedRatio(e.name!, query), e)) + .sorted((a, b) => b.$1.compareTo(a.$1)) + .where((e) => e.$1 > 50) + .map((e) => e.$2) + .toList(), + state.sortBy, + ), + ); + } + + void clearFilter() { + state = state.copyWith( + presentationTracks: ServiceUtils.sortTracks(tracks, state.sortBy), + ); + } + + void sortTracks(SortBy sortBy) { + state = state.copyWith( + presentationTracks: sortBy == SortBy.none + ? tracks + : ServiceUtils.sortTracks(state.presentationTracks, sortBy), + sortBy: sortBy, + ); + } +} + +final presentationStateProvider = AutoDisposeNotifierProviderFamily< + PresentationStateNotifier, PresentationState, Object>( + () => PresentationStateNotifier(), +); diff --git a/lib/components/track_presentation/presentation_top.dart b/lib/components/track_presentation/presentation_top.dart new file mode 100644 index 00000000..59854aaf --- /dev/null +++ b/lib/components/track_presentation/presentation_top.dart @@ -0,0 +1,262 @@ +import 'package:auto_size_text/auto_size_text.dart'; +import 'package:flutter/services.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; +import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/heart_button/heart_button.dart'; +import 'package:spotube/components/image/universal_image.dart'; +import 'package:spotube/components/track_presentation/presentation_props.dart'; +import 'package:spotube/components/track_presentation/use_action_callbacks.dart'; +import 'package:spotube/components/track_presentation/use_is_user_playlist.dart'; +import 'package:spotube/extensions/constrains.dart'; +import 'package:spotube/extensions/context.dart'; +import 'package:spotube/modules/playlist/playlist_create_dialog.dart'; + +class TrackPresentationTopSection extends HookConsumerWidget { + const TrackPresentationTopSection({super.key}); + + @override + Widget build(BuildContext context, ref) { + final mediaQuery = MediaQuery.sizeOf(context); + final options = TrackPresentationOptions.of(context); + final scale = context.theme.scaling; + final isUserPlaylist = useIsUserPlaylist(ref, options.collectionId); + + final imageDimension = mediaQuery.mdAndUp ? 200 : 120; + + final (:isLoading, :isActive, :onPlay, :onShuffle) = + useActionCallbacks(ref); + + final playbackActions = Row( + spacing: 8 * scale, + children: [ + Tooltip( + tooltip: TooltipContainer( + child: Text(context.l10n.shuffle_playlist), + ), + child: IconButton.secondary( + icon: isLoading + ? const Center( + child: + CircularProgressIndicator(onSurface: false, size: 20), + ) + : const Icon(SpotubeIcons.shuffle), + enabled: !isLoading && !isActive, + onPressed: onShuffle, + ), + ), + if (mediaQuery.width <= 320) + Tooltip( + tooltip: TooltipContainer( + child: Text(context.l10n.add_to_queue), + ), + child: IconButton.secondary( + icon: const Icon(SpotubeIcons.queueAdd), + enabled: !isLoading && !isActive, + onPressed: () {}, + ), + ) + else + Button.secondary( + leading: const Icon(SpotubeIcons.add), + enabled: !isLoading && !isActive, + child: Text(context.l10n.queue), + onPressed: () {}, + ), + Button.primary( + alignment: Alignment.center, + leading: switch ((isActive, isLoading)) { + (true, false) => const Icon(SpotubeIcons.pause), + (false, true) => const Center( + child: CircularProgressIndicator(onSurface: true, size: 18), + ), + _ => const Icon(SpotubeIcons.play), + }, + onPressed: onPlay, + enabled: !isLoading && !isActive, + child: isActive ? Text(context.l10n.pause) : Text(context.l10n.play), + ), + ], + ); + + final additionalActions = Row( + spacing: 8 * scale, + children: [ + if (isUserPlaylist) + IconButton.outline( + size: ButtonSize.small, + icon: const Icon(SpotubeIcons.edit), + onPressed: () { + showDialog( + context: context, + builder: (context) { + return PlaylistCreateDialog( + playlistId: options.collectionId, + trackIds: options.tracks.map((e) => e.id!).toList(), + ); + }, + ); + }, + ), + if (options.shareUrl != null) + Tooltip( + tooltip: TooltipContainer( + child: Text(context.l10n.share), + ), + child: IconButton.outline( + icon: const Icon(SpotubeIcons.share), + size: ButtonSize.small, + onPressed: () async { + await Clipboard.setData( + ClipboardData(text: options.shareUrl!), + ); + + if (!context.mounted) return; + + showToast( + context: context, + location: ToastLocation.topRight, + builder: (context, overlay) { + return SurfaceCard( + child: Text( + context.l10n + .copied_shareurl_to_clipboard(options.shareUrl!), + ).small(), + ); + }, + ); + }, + ), + ), + if (options.onHeart != null) + HeartButton( + isLiked: options.isLiked, + tooltip: options.isLiked + ? context.l10n.remove_from_favorites + : context.l10n.save_as_favorite, + variance: ButtonVariance.outline, + size: ButtonSize.small, + onPressed: options.onHeart, + ), + ], + ); + + return SliverMainAxisGroup( + slivers: [ + if (mediaQuery.mdAndUp) SliverGap(16 * scale), + SliverPadding( + padding: EdgeInsets.symmetric( + horizontal: (mediaQuery.mdAndUp ? 16 : 8.0) * scale, + ), + sliver: SliverList.list( + children: [ + DecoratedBox( + decoration: BoxDecoration( + image: DecorationImage( + image: UniversalImage.imageProvider(options.image), + fit: BoxFit.cover, + ), + borderRadius: BorderRadius.circular(45), + ), + child: OutlinedContainer( + surfaceOpacity: context.theme.surfaceOpacity, + surfaceBlur: context.theme.surfaceBlur, + padding: EdgeInsets.all(24 * scale), + borderRadius: BorderRadius.circular(22 * scale), + borderWidth: 2, + child: Column( + mainAxisSize: MainAxisSize.min, + spacing: 16 * scale, + children: [ + Row( + spacing: 16 * scale, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Container( + height: imageDimension * scale, + width: imageDimension * scale, + decoration: BoxDecoration( + borderRadius: context.theme.borderRadiusXl, + image: DecorationImage( + image: + UniversalImage.imageProvider(options.image), + fit: BoxFit.cover, + ), + ), + ), + Flexible( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AutoSizeText( + options.title, + maxLines: 2, + minFontSize: 16, + style: context.theme.typography.h3, + ), + if (options.description != null) + AutoSizeText( + options.description!, + maxLines: 2, + minFontSize: 14, + maxFontSize: 18, + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: context + .theme.colorScheme.mutedForeground, + fontSize: 18, + ), + ), + const Gap(16), + Flex( + crossAxisAlignment: CrossAxisAlignment.start, + direction: mediaQuery.smAndUp + ? Axis.horizontal + : Axis.vertical, + spacing: 8 * scale, + children: [ + if (options.owner != null) + OutlineBadge( + leading: options.ownerImage != null + ? Avatar( + initials: + options.owner?[0] ?? "U", + provider: UniversalImage + .imageProvider( + options.ownerImage!, + ), + ) + : null, + child: Text( + options.owner!, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ).small(), + ), + additionalActions, + ], + ), + if (mediaQuery.mdAndUp) ...[ + const Gap(16), + playbackActions + ], + ], + ), + ), + ], + ), + if (mediaQuery.smAndDown) playbackActions, + ], + ), + ), + ), + ], + ), + ) + ], + ); + } +} diff --git a/lib/components/track_presentation/sort_tracks_dropdown.dart b/lib/components/track_presentation/sort_tracks_dropdown.dart new file mode 100644 index 00000000..543bacb3 --- /dev/null +++ b/lib/components/track_presentation/sort_tracks_dropdown.dart @@ -0,0 +1,70 @@ +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/modules/library/user_local_tracks.dart'; +import 'package:spotube/components/adaptive/adaptive_pop_sheet_list.dart'; +import 'package:spotube/extensions/context.dart'; + +class SortTracksDropdown extends StatelessWidget { + final SortBy? value; + final void Function(SortBy)? onChanged; + const SortTracksDropdown({ + this.onChanged, + this.value, + super.key, + }); + + @override + Widget build(BuildContext context) { + return AdaptivePopSheetList( + variance: ButtonVariance.outline, + headings: [ + Text(context.l10n.sort_tracks), + ], + onSelected: onChanged, + tooltip: context.l10n.sort_tracks, + icon: const Icon(SpotubeIcons.sort), + children: [ + AdaptiveMenuButton( + value: SortBy.none, + enabled: value != SortBy.none, + child: Text(context.l10n.none), + ), + AdaptiveMenuButton( + value: SortBy.ascending, + enabled: value != SortBy.ascending, + child: Text(context.l10n.sort_a_z), + ), + AdaptiveMenuButton( + value: SortBy.descending, + enabled: value != SortBy.descending, + child: Text(context.l10n.sort_z_a), + ), + AdaptiveMenuButton( + value: SortBy.newest, + enabled: value != SortBy.newest, + child: Text(context.l10n.sort_newest), + ), + AdaptiveMenuButton( + value: SortBy.oldest, + enabled: value != SortBy.oldest, + child: Text(context.l10n.sort_oldest), + ), + AdaptiveMenuButton( + value: SortBy.duration, + enabled: value != SortBy.duration, + child: Text(context.l10n.sort_duration), + ), + AdaptiveMenuButton( + value: SortBy.artist, + enabled: value != SortBy.artist, + child: Text(context.l10n.sort_artist), + ), + AdaptiveMenuButton( + value: SortBy.album, + enabled: value != SortBy.album, + child: Text(context.l10n.sort_album), + ), + ], + ); + } +} diff --git a/lib/components/track_presentation/track_presentation.dart b/lib/components/track_presentation/track_presentation.dart new file mode 100644 index 00000000..8bc1c6df --- /dev/null +++ b/lib/components/track_presentation/track_presentation.dart @@ -0,0 +1,72 @@ +import 'package:flutter/material.dart' show ListTile; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; +import 'package:spotube/components/titlebar/titlebar.dart'; +import 'package:spotube/components/track_presentation/presentation_list.dart'; +import 'package:spotube/components/track_presentation/presentation_props.dart'; +import 'package:spotube/components/track_presentation/presentation_top.dart'; +import 'package:spotube/components/track_presentation/presentation_modifiers.dart'; +import 'package:spotube/extensions/constrains.dart'; +import 'package:spotube/extensions/context.dart'; + +class TrackPresentation extends HookConsumerWidget { + final TrackPresentationOptions options; + const TrackPresentation({ + super.key, + required this.options, + }); + + @override + Widget build(BuildContext context, ref) { + final headerTextStyle = context.theme.typography.small.copyWith( + color: context.theme.colorScheme.mutedForeground, + ); + + return Data.inherit( + data: options, + child: SafeArea( + child: Scaffold( + headers: const [TitleBar()], + child: CustomScrollView( + slivers: [ + const TrackPresentationTopSection(), + const SliverGap(16), + SliverLayoutBuilder( + builder: (context, constrains) { + return SliverList.list( + children: [ + const TrackPresentationModifiersSection(), + ListTile( + titleTextStyle: headerTextStyle, + subtitleTextStyle: headerTextStyle, + leadingAndTrailingTextStyle: headerTextStyle, + leading: constrains.mdAndUp ? const Text(" #") : null, + title: Row( + children: [ + Expanded( + flex: constrains.lgAndUp ? 5 : 6, + child: Text(context.l10n.title), + ), + if (constrains.mdAndUp) + Expanded( + flex: 3, + child: Text(context.l10n.album), + ), + Text(context.l10n.duration), + ], + ), + ), + ], + ); + }, + ), + const PresentationListSection(), + const SliverGap(200), + ], + ), + ), + ), + ); + } +} diff --git a/lib/components/track_presentation/use_action_callbacks.dart b/lib/components/track_presentation/use_action_callbacks.dart new file mode 100644 index 00000000..e9b9c98e --- /dev/null +++ b/lib/components/track_presentation/use_action_callbacks.dart @@ -0,0 +1,135 @@ +import 'dart:math'; + +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotify/spotify.dart'; +import 'package:spotube/components/dialogs/select_device_dialog.dart'; +import 'package:spotube/components/track_presentation/presentation_props.dart'; + +import 'package:spotube/models/connect/connect.dart'; +import 'package:spotube/provider/audio_player/audio_player.dart'; +import 'package:spotube/provider/connect/connect.dart'; +import 'package:spotube/provider/history/history.dart'; +import 'package:spotube/services/audio_player/audio_player.dart'; + +typedef UseActionCallbacks = ({ + bool isActive, + bool isLoading, + Future Function() onShuffle, + Future Function() onPlay, +}); + +UseActionCallbacks useActionCallbacks(WidgetRef ref) { + final isLoading = useState(false); + final context = useContext(); + final options = TrackPresentationOptions.of(context); + final playlist = ref.watch(audioPlayerProvider); + final playlistNotifier = ref.watch(audioPlayerProvider.notifier); + final historyNotifier = ref.watch(playbackHistoryActionsProvider); + + final isActive = useMemoized( + () => playlist.collections.contains(options.collectionId), + [playlist.collections, options.collectionId], + ); + + final onShuffle = useCallback(() async { + try { + isLoading.value = true; + + final initialTracks = options.tracks; + if (!context.mounted) return; + + final isRemoteDevice = await showSelectDeviceDialog(context, ref); + if (isRemoteDevice) { + final allTracks = await options.pagination.onFetchAll(); + final remotePlayback = ref.read(connectProvider.notifier); + await remotePlayback.load( + options.collection is AlbumSimple + ? WebSocketLoadEventData.album( + tracks: allTracks, + collection: options.collection as AlbumSimple, + initialIndex: Random().nextInt(allTracks.length)) + : WebSocketLoadEventData.playlist( + tracks: allTracks, + collection: options.collection as PlaylistSimple, + initialIndex: Random().nextInt(allTracks.length), + ), + ); + await remotePlayback.setShuffle(true); + } else { + await playlistNotifier.load( + initialTracks, + autoPlay: true, + initialIndex: Random().nextInt(initialTracks.length), + ); + await audioPlayer.setShuffle(true); + playlistNotifier.addCollection(options.collectionId); + if (options.collection is AlbumSimple) { + historyNotifier.addAlbums([options.collection as AlbumSimple]); + } else { + historyNotifier.addPlaylists([options.collection as PlaylistSimple]); + } + + final allTracks = await options.pagination.onFetchAll(); + + await playlistNotifier.addTracks( + allTracks.sublist(initialTracks.length), + ); + } + } finally { + isLoading.value = false; + } + }, [options, playlistNotifier, historyNotifier]); + + final onPlay = useCallback(() async { + try { + isLoading.value = true; + + final initialTracks = options.tracks; + + if (!context.mounted) return; + + final isRemoteDevice = await showSelectDeviceDialog(context, ref); + if (isRemoteDevice) { + final allTracks = await options.pagination.onFetchAll(); + final remotePlayback = ref.read(connectProvider.notifier); + await remotePlayback.load( + options.collection is AlbumSimple + ? WebSocketLoadEventData.album( + tracks: allTracks, + collection: options.collection as AlbumSimple, + ) + : WebSocketLoadEventData.playlist( + tracks: allTracks, + collection: options.collection as PlaylistSimple, + ), + ); + } else { + await playlistNotifier.load(initialTracks, autoPlay: true); + playlistNotifier.addCollection(options.collectionId); + if (options.collection is AlbumSimple) { + historyNotifier.addAlbums([options.collection as AlbumSimple]); + } else { + historyNotifier.addPlaylists([options.collection as PlaylistSimple]); + } + + final allTracks = await options.pagination.onFetchAll(); + + await playlistNotifier.addTracks( + allTracks.sublist(initialTracks.length), + ); + } + } finally { + if (context.mounted) { + isLoading.value = false; + } + } + }, [options, playlistNotifier, historyNotifier]); + + return ( + isActive: isActive, + isLoading: isLoading.value, + onShuffle: onShuffle, + onPlay: onPlay, + ); +} diff --git a/lib/components/tracks_view/sections/body/use_is_user_playlist.dart b/lib/components/track_presentation/use_is_user_playlist.dart similarity index 100% rename from lib/components/tracks_view/sections/body/use_is_user_playlist.dart rename to lib/components/track_presentation/use_is_user_playlist.dart diff --git a/lib/components/track_presentation/use_track_tile_play_callback.dart b/lib/components/track_presentation/use_track_tile_play_callback.dart new file mode 100644 index 00000000..261d01d8 --- /dev/null +++ b/lib/components/track_presentation/use_track_tile_play_callback.dart @@ -0,0 +1,84 @@ +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:spotify/spotify.dart'; +import 'package:spotube/components/dialogs/select_device_dialog.dart'; +import 'package:spotube/components/track_presentation/presentation_props.dart'; +import 'package:spotube/components/track_presentation/presentation_state.dart'; +import 'package:spotube/extensions/list.dart'; + +import 'package:spotube/models/connect/connect.dart'; +import 'package:spotube/provider/audio_player/audio_player.dart'; +import 'package:spotube/provider/connect/connect.dart'; +import 'package:spotube/provider/history/history.dart'; + +Future Function(Track track, int index) useTrackTilePlayCallback( + WidgetRef ref, +) { + final context = useContext(); + final options = TrackPresentationOptions.of(context); + final playlist = ref.watch(audioPlayerProvider); + final playlistNotifier = ref.watch(audioPlayerProvider.notifier); + final historyNotifier = ref.watch(playbackHistoryActionsProvider); + + final isActive = useMemoized( + () => playlist.collections.contains(options.collectionId), + [playlist.collections, options.collectionId], + ); + + final onTapTrackTile = useCallback((Track track, int index) async { + final state = ref.read(presentationStateProvider(options.collection)); + final notifier = + ref.read(presentationStateProvider(options.collection).notifier); + + if (state.selectedTracks.isNotEmpty) { + notifier.selectTrack(track); + return; + } + + final isRemoteDevice = await showSelectDeviceDialog(context, ref); + + if (isRemoteDevice) { + final remotePlayback = ref.read(connectProvider.notifier); + final remoteQueue = ref.read(queueProvider); + if (remoteQueue.collections.contains(options.collectionId) || + remoteQueue.tracks.any((s) => s.id == track.id)) { + await playlistNotifier.jumpToTrack(track); + } else { + final tracks = await options.pagination.onFetchAll(); + await remotePlayback.load( + options.collection is AlbumSimple + ? WebSocketLoadEventData.album( + tracks: tracks, + collection: options.collection as AlbumSimple, + initialIndex: index, + ) + : WebSocketLoadEventData.playlist( + tracks: tracks, + collection: options.collection as PlaylistSimple, + initialIndex: index, + ), + ); + } + } else { + if (isActive || playlist.tracks.containsBy(track, (a) => a.id)) { + await playlistNotifier.jumpToTrack(track); + } else { + final tracks = await options.pagination.onFetchAll(); + await playlistNotifier.load( + tracks, + initialIndex: index, + autoPlay: true, + ); + playlistNotifier.addCollection(options.collectionId); + if (options.collection is AlbumSimple) { + historyNotifier.addAlbums([options.collection as AlbumSimple]); + } else { + historyNotifier.addPlaylists([options.collection as PlaylistSimple]); + } + } + } + }, [isActive, playlist, options, playlistNotifier, historyNotifier]); + + return onTapTrackTile; +} diff --git a/lib/components/track_tile/track_tile.dart b/lib/components/track_tile/track_tile.dart index 8ab889f8..560d2255 100644 --- a/lib/components/track_tile/track_tile.dart +++ b/lib/components/track_tile/track_tile.dart @@ -1,10 +1,11 @@ import 'dart:async'; import 'package:flutter/gestures.dart'; -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart' show ListTile, Material, MaterialType; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:gap/gap.dart'; + import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/collections/spotube_icons.dart'; @@ -88,78 +89,98 @@ class TrackTile extends HookConsumerWidget { }, child: HoverBuilder( permanentState: isSelected || constrains.smAndDown ? true : null, - builder: (context, isHovering) => ListTile( - selected: isSelected, - onTap: () async { - try { - isLoading.value = true; - await onTap?.call(); - } finally { - if (context.mounted) { - isLoading.value = false; + builder: (context, isHovering) => Material( + type: MaterialType.transparency, + child: ListTile( + selectedColor: theme.colorScheme.primary, + selectedTileColor: theme.colorScheme.primary.withOpacity(0.1), + selected: isSelected, + onTap: () async { + try { + isLoading.value = true; + await onTap?.call(); + } finally { + if (context.mounted) { + isLoading.value = false; + } } - } - }, - onLongPress: onLongPress, - enabled: !isBlackListed, - contentPadding: EdgeInsets.zero, - tileColor: isBlackListed ? theme.colorScheme.errorContainer : null, - horizontalTitleGap: 12, - leadingAndTrailingTextStyle: theme.textTheme.bodyMedium, - leading: Row( - mainAxisSize: MainAxisSize.min, - children: [ - ...?leadingActions, - if (index != null && onChanged == null && constrains.mdAndUp) - SizedBox( - width: 50, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 6), - child: Text( - '${(index ?? 0) + 1}', - maxLines: 1, - style: theme.textTheme.bodySmall, - textAlign: TextAlign.center, - ), + }, + onLongPress: onLongPress, + enabled: !isBlackListed, + contentPadding: EdgeInsets.zero, + tileColor: isBlackListed ? theme.colorScheme.destructive : null, + horizontalTitleGap: 12, + leadingAndTrailingTextStyle: theme.typography.normal.copyWith( + color: theme.colorScheme.foreground, + ), + titleTextStyle: theme.typography.normal.copyWith( + color: theme.colorScheme.foreground, + ), + subtitleTextStyle: theme.typography.xSmall.copyWith( + color: theme.colorScheme.mutedForeground, + ), + leading: Row( + mainAxisSize: MainAxisSize.min, + children: [ + ...?leadingActions, + AnimatedCrossFade( + duration: const Duration(milliseconds: 300), + crossFadeState: index != null && onChanged == null + ? CrossFadeState.showSecond + : CrossFadeState.showFirst, + firstChild: Checkbox( + state: selected + ? CheckboxState.checked + : CheckboxState.unchecked, + onChanged: (state) => + onChanged?.call(state == CheckboxState.checked), ), - ) - else if (constrains.smAndDown) - const SizedBox(width: 16), - if (onChanged != null) - Checkbox( - value: selected, - onChanged: onChanged, - ), - Stack( - children: [ - ClipRRect( - borderRadius: BorderRadius.circular(4), - child: AspectRatio( - aspectRatio: 1, - child: UniversalImage( - path: (track.album?.images).asUrlString( - placeholder: ImagePlaceholder.albumArt, + secondChild: constrains.smAndDown + ? const SizedBox(width: 16) + : SizedBox( + width: 50, + child: Padding( + padding: + const EdgeInsets.symmetric(horizontal: 6), + child: Text( + '${(index ?? 0) + 1}', + maxLines: 1, + style: theme.typography.small, + textAlign: TextAlign.center, + ), + ), ), - fit: BoxFit.cover, - ), - ), - ), - Positioned.fill( - child: AnimatedContainer( - duration: const Duration(milliseconds: 300), + ), + Stack( + children: [ + Container( + height: 40, + width: 40, decoration: BoxDecoration( - borderRadius: BorderRadius.circular(4), - color: isHovering - ? Colors.black.withOpacity(0.4) - : Colors.transparent, + borderRadius: theme.borderRadiusMd, + image: DecorationImage( + fit: BoxFit.cover, + image: UniversalImage.imageProvider( + (track.album?.images).asUrlString( + placeholder: ImagePlaceholder.albumArt, + ), + ), + ), ), ), - ), - Positioned.fill( - child: Center( - child: IconTheme( - data: theme.iconTheme - .copyWith(size: 26, color: Colors.white), + Positioned.fill( + child: AnimatedContainer( + duration: const Duration(milliseconds: 300), + decoration: BoxDecoration( + borderRadius: theme.borderRadiusMd, + color: isHovering + ? Colors.black.withOpacity(0.4) + : Colors.transparent, + ), + ), + ), + Positioned.fill( + child: Center( child: Skeleton.ignore( child: Consumer( builder: (context, ref, _) { @@ -167,119 +188,126 @@ class TrackTile extends HookConsumerWidget { ref.watch(queryingTrackInfoProvider); return AnimatedSwitcher( duration: const Duration(milliseconds: 300), - child: (isPlaying && isFetchingActiveTrack) || - isLoading.value - ? const SizedBox( - width: 26, - height: 26, - child: CircularProgressIndicator( - strokeWidth: 1.5, - color: Colors.white, - ), - ) - : isPlaying - ? Icon( - SpotubeIcons.pause, - color: theme.colorScheme.primary, - ) - : !isHovering - ? const SizedBox.shrink() - : const Icon(SpotubeIcons.play), + child: switch (( + isPlaying, + isFetchingActiveTrack, + isPlaying, + isHovering, + isLoading.value + )) { + (true, true, _, _, _) || + (_, _, _, _, true) => + const SizedBox( + width: 26, + height: 26, + child: CircularProgressIndicator( + size: 1.5), + ), + (_, _, true, _, _) => Icon( + SpotubeIcons.pause, + color: theme.colorScheme.primary, + ), + (_, _, _, true, _) => const Icon( + SpotubeIcons.play, + color: Colors.white, + ), + _ => const SizedBox.shrink(), + }, ); }, ), ), ), ), - ), - ], - ), - ], - ), - title: Row( - children: [ - Expanded( - flex: 6, - child: switch (track) { - LocalTrack() => Text( - track.name!, - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - _ => LinkText( - track.name!, - "/track/${track.id}", - push: true, - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - }, - ), - if (constrains.mdAndUp) ...[ - const SizedBox(width: 8), + ], + ), + ], + ), + title: Row( + children: [ Expanded( - flex: 4, + flex: 6, child: switch (track) { LocalTrack() => Text( - track.album!.name!, + track.name!, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + _ => LinkText( + track.name!, + "/track/${track.id}", + push: true, maxLines: 1, overflow: TextOverflow.ellipsis, ), - _ => Align( - alignment: Alignment.centerLeft, - child: LinkText( - track.album!.name!, - "/album/${track.album?.id}", - extra: track.album, - push: true, - overflow: TextOverflow.ellipsis, - ), - ) }, ), + if (constrains.mdAndUp) ...[ + const SizedBox(width: 8), + Expanded( + flex: 4, + child: switch (track) { + LocalTrack() => Text( + track.album!.name!, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + _ => Align( + alignment: Alignment.centerLeft, + child: LinkText( + track.album!.name!, + "/album/${track.album?.id}", + extra: track.album, + push: true, + overflow: TextOverflow.ellipsis, + ), + ) + }, + ), + ], ], - ], - ), - subtitle: Align( - alignment: Alignment.centerLeft, - child: track is LocalTrack - ? Text( - track.artists?.asString() ?? '', - ) - : ClipRect( - child: ConstrainedBox( - constraints: const BoxConstraints(maxHeight: 40), - child: ArtistLink( - artists: track.artists ?? [], - onOverflowArtistClick: () => ServiceUtils.pushNamed( - context, - TrackPage.name, - pathParameters: { - "id": track.id!, - }, + ), + subtitle: Align( + alignment: Alignment.centerLeft, + child: track is LocalTrack + ? Text( + track.artists?.asString() ?? '', + ) + : ClipRect( + child: ConstrainedBox( + constraints: const BoxConstraints(maxHeight: 40), + child: ArtistLink( + artists: track.artists ?? [], + onOverflowArtistClick: () => ServiceUtils.pushNamed( + context, + TrackPage.name, + pathParameters: { + "id": track.id!, + }, + ), ), ), ), - ), - ), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - const SizedBox(width: 8), - Text( - Duration(milliseconds: track.durationMs ?? 0) - .toHumanReadableString(padZero: false), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - TrackOptions( - track: track, - playlistId: playlistId, - userPlaylist: userPlaylist, - showMenuCbRef: showOptionCbRef, - ), - if (kIsDesktop) const Gap(10), - ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const SizedBox(width: 8), + Text( + Duration(milliseconds: track.durationMs ?? 0) + .toHumanReadableString(padZero: false), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + TrackOptions( + track: track, + playlistId: playlistId, + userPlaylist: userPlaylist, + showMenuCbRef: showOptionCbRef, + ), + if (kIsDesktop) const Gap(10), + ], + ), ), ), ), diff --git a/lib/components/tracks_view/sections/body/track_view_body.dart b/lib/components/tracks_view/sections/body/track_view_body.dart deleted file mode 100644 index 0f161b0c..00000000 --- a/lib/components/tracks_view/sections/body/track_view_body.dart +++ /dev/null @@ -1,192 +0,0 @@ -import 'package:collection/collection.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:fuzzywuzzy/fuzzywuzzy.dart'; -import 'package:gap/gap.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:skeletonizer/skeletonizer.dart'; -import 'package:spotify/spotify.dart'; -import 'package:spotube/collections/fake.dart'; -import 'package:spotube/components/dialogs/select_device_dialog.dart'; -import 'package:spotube/components/expandable_search/expandable_search.dart'; -import 'package:spotube/components/track_tile/track_tile.dart'; -import 'package:spotube/components/tracks_view/sections/body/track_view_body_headers.dart'; -import 'package:spotube/components/tracks_view/sections/body/use_is_user_playlist.dart'; -import 'package:spotube/components/tracks_view/track_view_props.dart'; -import 'package:spotube/components/tracks_view/track_view_provider.dart'; -import 'package:spotube/extensions/list.dart'; -import 'package:spotube/models/connect/connect.dart'; -import 'package:spotube/provider/connect/connect.dart'; -import 'package:spotube/provider/history/history.dart'; -import 'package:spotube/provider/audio_player/audio_player.dart'; -import 'package:spotube/utils/service_utils.dart'; -import 'package:very_good_infinite_list/very_good_infinite_list.dart'; - -class TrackViewBodySection extends HookConsumerWidget { - const TrackViewBodySection({super.key}); - - @override - Widget build(BuildContext context, ref) { - final playlist = ref.watch(audioPlayerProvider); - final playlistNotifier = ref.watch(audioPlayerProvider.notifier); - final historyNotifier = ref.watch(playbackHistoryActionsProvider); - final props = InheritedTrackView.of(context); - final trackViewState = ref.watch(trackViewProvider(props.tracks)); - - final searchController = useTextEditingController(); - final searchFocus = useFocusNode(); - - useValueListenable(searchController); - final searchQuery = searchController.text; - - final isFiltering = useState(false); - - final uniqTracks = useMemoized(() { - final trackIds = props.tracks.map((e) => e.id).toSet(); - return props.tracks.where((e) => trackIds.remove(e.id)).toList(); - }, [props.tracks]); - - final tracks = useMemoized(() { - List filteredTracks; - if (searchQuery.isEmpty) { - filteredTracks = uniqTracks; - } else { - filteredTracks = uniqTracks - .map((e) => (weightedRatio(e.name!, searchQuery), e)) - .sorted((a, b) => b.$1.compareTo(a.$1)) - .where((e) => e.$1 > 50) - .map((e) => e.$2) - .toList(); - } - return ServiceUtils.sortTracks(filteredTracks, trackViewState.sortBy); - }, [trackViewState.sortBy, searchQuery, uniqTracks]); - - final isUserPlaylist = useIsUserPlaylist(ref, props.collectionId); - - final isActive = playlist.collections.contains(props.collectionId); - - final onTapTrackTile = useCallback((Track track, int index) async { - if (trackViewState.isSelecting) { - trackViewState.toggleTrackSelection(track.id!); - return; - } - - final isRemoteDevice = await showSelectDeviceDialog(context, ref); - - if (isRemoteDevice) { - final remotePlayback = ref.read(connectProvider.notifier); - final remoteQueue = ref.read(queueProvider); - if (remoteQueue.collections.contains(props.collectionId) || - remoteQueue.tracks.any((s) => s.id == track.id)) { - await playlistNotifier.jumpToTrack(track); - } else { - final tracks = await props.pagination.onFetchAll(); - await remotePlayback.load( - props.collection is AlbumSimple - ? WebSocketLoadEventData.album( - tracks: tracks, - collection: props.collection as AlbumSimple, - initialIndex: index, - ) - : WebSocketLoadEventData.playlist( - tracks: tracks, - collection: props.collection as PlaylistSimple, - initialIndex: index, - ), - ); - } - } else { - if (isActive || playlist.tracks.containsBy(track, (a) => a.id)) { - await playlistNotifier.jumpToTrack(track); - } else { - final tracks = await props.pagination.onFetchAll(); - await playlistNotifier.load( - tracks, - initialIndex: index, - autoPlay: true, - ); - playlistNotifier.addCollection(props.collectionId); - if (props.collection is AlbumSimple) { - historyNotifier.addAlbums([props.collection as AlbumSimple]); - } else { - historyNotifier.addPlaylists([props.collection as PlaylistSimple]); - } - } - } - }, [isActive, playlist, props, playlistNotifier, historyNotifier]); - - return SliverMainAxisGroup( - slivers: [ - SliverToBoxAdapter( - child: TrackViewBodyHeaders( - isFiltering: isFiltering, - searchFocus: searchFocus, - ), - ), - const SliverGap(8), - SliverToBoxAdapter( - child: ExpandableSearchField( - isFiltering: isFiltering.value, - onChangeFiltering: (value) { - isFiltering.value = value; - }, - searchController: searchController, - searchFocus: searchFocus, - ), - ), - SliverSafeArea( - top: false, - sliver: SliverInfiniteList( - itemCount: tracks.length, - onFetchData: props.pagination.onFetchMore, - isLoading: props.pagination.isLoading, - hasReachedMax: !props.pagination.hasNextPage, - loadingBuilder: (context) => Skeletonizer( - enabled: true, - child: TrackTile( - playlist: playlist, - track: FakeData.track, - index: 0, - ), - ), - emptyBuilder: (context) => Skeletonizer( - enabled: true, - child: Column( - children: List.generate( - 10, - (index) => TrackTile( - track: FakeData.track, - index: index, - playlist: playlist, - ), - ), - ), - ), - itemBuilder: (context, index) { - final track = tracks[index]; - return TrackTile( - playlist: playlist, - track: track, - index: index, - selected: trackViewState.selectedTrackIds.contains(track.id!), - playlistId: props.collectionId, - userPlaylist: isUserPlaylist, - onChanged: !trackViewState.isSelecting - ? null - : (value) { - trackViewState.toggleTrackSelection(track.id!); - }, - onLongPress: () { - trackViewState.selectTrack(track.id!); - HapticFeedback.selectionClick(); - }, - onTap: () => onTapTrackTile(track, index), - ); - }, - ), - ), - ], - ); - } -} diff --git a/lib/components/tracks_view/sections/body/track_view_body_headers.dart b/lib/components/tracks_view/sections/body/track_view_body_headers.dart deleted file mode 100644 index 82cc7706..00000000 --- a/lib/components/tracks_view/sections/body/track_view_body_headers.dart +++ /dev/null @@ -1,105 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:gap/gap.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:spotube/components/expandable_search/expandable_search.dart'; -import 'package:spotube/components/sort_tracks_dropdown.dart'; -import 'package:spotube/components/tracks_view/sections/body/track_view_options.dart'; -import 'package:spotube/components/tracks_view/track_view_props.dart'; -import 'package:spotube/components/tracks_view/track_view_provider.dart'; -import 'package:spotube/extensions/constrains.dart'; -import 'package:spotube/extensions/context.dart'; -import 'package:spotube/utils/platform.dart'; - -class TrackViewBodyHeaders extends HookConsumerWidget { - final ValueNotifier isFiltering; - final FocusNode searchFocus; - - const TrackViewBodyHeaders({ - super.key, - required this.isFiltering, - required this.searchFocus, - }); - - @override - Widget build(BuildContext context, ref) { - final ThemeData(:textTheme) = Theme.of(context); - final props = InheritedTrackView.of(context); - final trackViewState = ref.watch(trackViewProvider(props.tracks)); - return LayoutBuilder( - builder: (context, constrains) { - return Row( - children: [ - AnimatedSwitcher( - duration: const Duration(milliseconds: 200), - transitionBuilder: (child, animation) { - return FadeTransition( - opacity: animation, - child: ScaleTransition( - scale: animation, - child: child, - ), - ); - }, - child: Checkbox( - value: trackViewState.hasSelectedAll, - onChanged: (checked) { - if (checked == true) { - trackViewState.selectAll(); - } else { - trackViewState.deselectAll(); - } - }, - ), - ), - Expanded( - flex: 7, - child: Row( - children: [ - Text( - context.l10n.title, - style: textTheme.bodyLarge, - overflow: TextOverflow.ellipsis, - ), - ], - ), - ), - // used alignment of this table-head - if (constrains.mdAndUp) - Expanded( - flex: 3, - child: Row( - children: [ - Text( - context.l10n.album, - overflow: TextOverflow.ellipsis, - style: textTheme.bodyLarge, - ), - ], - ), - ), - SortTracksDropdown( - value: trackViewState.sortBy, - onChanged: (value) { - trackViewState.sort(value); - }, - ), - ExpandableSearchButton( - isFiltering: isFiltering.value, - searchFocus: searchFocus, - onPressed: (value) { - isFiltering.value = value; - if (value) { - searchFocus.requestFocus(); - } else { - searchFocus.unfocus(); - } - }, - ), - const TrackViewBodyOptions(), - if (kIsDesktop) const Gap(10), - ], - ); - }, - ); - } -} diff --git a/lib/components/tracks_view/sections/body/track_view_options.dart b/lib/components/tracks_view/sections/body/track_view_options.dart deleted file mode 100644 index 7114d713..00000000 --- a/lib/components/tracks_view/sections/body/track_view_options.dart +++ /dev/null @@ -1,140 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:spotify/spotify.dart'; -import 'package:spotube/collections/spotube_icons.dart'; -import 'package:spotube/components/adaptive/adaptive_pop_sheet_list.dart'; -import 'package:spotube/components/dialogs/confirm_download_dialog.dart'; -import 'package:spotube/components/dialogs/playlist_add_track_dialog.dart'; -import 'package:spotube/components/tracks_view/track_view_props.dart'; -import 'package:spotube/components/tracks_view/track_view_provider.dart'; -import 'package:spotube/extensions/context.dart'; -import 'package:spotube/models/database/database.dart'; -import 'package:spotube/provider/download_manager_provider.dart'; -import 'package:spotube/provider/history/history.dart'; -import 'package:spotube/provider/audio_player/audio_player.dart'; -import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; - -class TrackViewBodyOptions extends HookConsumerWidget { - const TrackViewBodyOptions({super.key}); - - @override - Widget build(BuildContext context, ref) { - final props = InheritedTrackView.of(context); - final ThemeData(:textTheme) = Theme.of(context); - - ref.watch(downloadManagerProvider); - final downloader = ref.watch(downloadManagerProvider.notifier); - final playlistNotifier = ref.watch(audioPlayerProvider.notifier); - final historyNotifier = ref.watch(playbackHistoryActionsProvider); - final audioSource = - ref.watch(userPreferencesProvider.select((s) => s.audioSource)); - - final trackViewState = ref.watch(trackViewProvider(props.tracks)); - final selectedTracks = trackViewState.selectedTracks; - - return AdaptivePopSheetList( - tooltip: context.l10n.more_actions, - headings: [ - Text( - context.l10n.more_actions, - style: textTheme.bodyLarge, - ), - ], - onSelected: (action) async { - switch (action) { - case "download": - { - final confirmed = audioSource == AudioSource.piped || - await showDialog( - context: context, - builder: (context) { - return const ConfirmDownloadDialog(); - }, - ); - if (confirmed != true) return; - await downloader.batchAddToQueue(selectedTracks); - trackViewState.deselectAll(); - break; - } - case "add-to-playlist": - { - if (context.mounted) { - await showDialog( - context: context, - builder: (context) { - return PlaylistAddTrackDialog( - openFromPlaylist: props.collectionId, - tracks: selectedTracks.toList(), - ); - }, - ); - } - break; - } - case "play-next": - { - playlistNotifier.addTracksAtFirst(selectedTracks); - playlistNotifier.addCollection(props.collectionId); - if (props.collection is AlbumSimple) { - historyNotifier.addAlbums([props.collection as AlbumSimple]); - } else { - historyNotifier - .addPlaylists([props.collection as PlaylistSimple]); - } - trackViewState.deselectAll(); - break; - } - case "add-to-queue": - { - playlistNotifier.addTracks(selectedTracks); - playlistNotifier.addCollection(props.collectionId); - if (props.collection is AlbumSimple) { - historyNotifier.addAlbums([props.collection as AlbumSimple]); - } else { - historyNotifier - .addPlaylists([props.collection as PlaylistSimple]); - } - trackViewState.deselectAll(); - break; - } - default: - } - }, - icon: const Icon(SpotubeIcons.moreVertical), - children: [ - AdaptiveMenuButton( - value: "download", - leading: const Icon(SpotubeIcons.download), - enabled: selectedTracks.isNotEmpty, - child: Text( - context.l10n.download_count(selectedTracks.length), - ), - ), - AdaptiveMenuButton( - value: "add-to-playlist", - leading: const Icon(SpotubeIcons.playlistAdd), - enabled: selectedTracks.isNotEmpty, - child: Text( - context.l10n.add_count_to_playlist(selectedTracks.length), - ), - ), - AdaptiveMenuButton( - enabled: selectedTracks.isNotEmpty, - value: "add-to-queue", - leading: const Icon(SpotubeIcons.queueAdd), - child: Text( - context.l10n.add_count_to_queue(selectedTracks.length), - ), - ), - AdaptiveMenuButton( - enabled: selectedTracks.isNotEmpty, - value: "play-next", - leading: const Icon(SpotubeIcons.lightning), - child: Text( - context.l10n.play_count_next(selectedTracks.length), - ), - ), - ], - ); - } -} diff --git a/lib/components/tracks_view/sections/header/flexible_header.dart b/lib/components/tracks_view/sections/header/flexible_header.dart deleted file mode 100644 index 508d289c..00000000 --- a/lib/components/tracks_view/sections/header/flexible_header.dart +++ /dev/null @@ -1,167 +0,0 @@ -import 'dart:ui'; - -import 'package:flutter/material.dart'; - -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:spotube/collections/assets.gen.dart'; -import 'package:spotube/components/image/universal_image.dart'; -import 'package:spotube/components/tracks_view/sections/header/header_actions.dart'; -import 'package:spotube/components/tracks_view/sections/header/header_buttons.dart'; -import 'package:spotube/components/tracks_view/track_view_props.dart'; -import 'package:gap/gap.dart'; -import 'package:spotube/extensions/constrains.dart'; -import 'package:spotube/extensions/string.dart'; -import 'package:spotube/hooks/utils/use_palette_color.dart'; -import 'package:spotube/utils/platform.dart'; - -class TrackViewFlexHeader extends HookConsumerWidget { - const TrackViewFlexHeader({super.key}); - - @override - Widget build(BuildContext context, ref) { - final props = InheritedTrackView.of(context); - final ThemeData(:colorScheme, :textTheme, :iconTheme) = Theme.of(context); - final defaultTextStyle = DefaultTextStyle.of(context); - final mediaQuery = MediaQuery.of(context); - - final palette = usePaletteColor(props.image, ref); - - return IconTheme( - data: iconTheme.copyWith(color: palette.bodyTextColor), - child: SliverLayoutBuilder( - builder: (context, constrains) { - final isExpanded = constrains.scrollOffset < 350; - - final headingStyle = (mediaQuery.mdAndDown - ? textTheme.headlineSmall - : textTheme.headlineMedium) - ?.copyWith( - color: palette.bodyTextColor, - ); - return SliverAppBar( - iconTheme: iconTheme.copyWith( - color: palette.bodyTextColor, - size: 16, - ), - actions: isExpanded - ? [] - : [ - const TrackViewHeaderActions(), - TrackViewHeaderButtons(compact: true, color: palette), - ], - floating: false, - pinned: true, - expandedHeight: 450, - automaticallyImplyLeading: kIsMobile, - backgroundColor: palette.color, - title: isExpanded ? null : Text(props.title, style: headingStyle), - flexibleSpace: FlexibleSpaceBar( - background: Container( - clipBehavior: Clip.hardEdge, - decoration: BoxDecoration( - image: DecorationImage( - image: UniversalImage.imageProvider(props.image), - fit: BoxFit.cover, - ), - ), - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10), - child: DecoratedBox( - decoration: BoxDecoration( - gradient: LinearGradient( - colors: [ - Colors.black45, - colorScheme.surface, - ], - begin: const FractionalOffset(0, 0), - end: const FractionalOffset(0, 1), - tileMode: TileMode.clamp, - ), - ), - child: SafeArea( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - ConstrainedBox( - constraints: BoxConstraints( - maxWidth: mediaQuery.mdAndDown - ? mediaQuery.size.width - : 800, - ), - child: Flex( - direction: mediaQuery.mdAndDown - ? Axis.vertical - : Axis.horizontal, - mainAxisSize: MainAxisSize.min, - children: [ - ClipRRect( - borderRadius: BorderRadius.circular(10), - child: UniversalImage( - path: props.image, - width: 200, - height: 200, - placeholder: Assets.albumPlaceholder.path, - ), - ), - const Gap(20), - Flexible( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: mediaQuery.mdAndDown - ? CrossAxisAlignment.center - : CrossAxisAlignment.start, - children: [ - Text( - props.title, - style: headingStyle, - textAlign: mediaQuery.mdAndDown - ? TextAlign.center - : TextAlign.start, - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - const SizedBox(height: 10), - if (props.description != null && - props.description!.isNotEmpty) - Text( - props.description! - .unescapeHtml() - .cleanHtml(), - style: - defaultTextStyle.style.copyWith( - color: palette.bodyTextColor, - ), - textAlign: mediaQuery.mdAndDown - ? TextAlign.center - : TextAlign.start, - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - const Gap(10), - const TrackViewHeaderActions(), - const Gap(10), - TrackViewHeaderButtons(color: palette), - ], - ), - ), - ], - ), - ), - ], - ), - ), - ), - ), - ), - ), - ), - ); - }, - ), - ); - } -} diff --git a/lib/components/tracks_view/sections/header/header_actions.dart b/lib/components/tracks_view/sections/header/header_actions.dart deleted file mode 100644 index 8e378f97..00000000 --- a/lib/components/tracks_view/sections/header/header_actions.dart +++ /dev/null @@ -1,111 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:go_router/go_router.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:spotify/spotify.dart'; -import 'package:spotube/collections/spotube_icons.dart'; -import 'package:spotube/modules/playlist/playlist_create_dialog.dart'; -import 'package:spotube/components/heart_button/heart_button.dart'; -import 'package:spotube/components/tracks_view/sections/body/use_is_user_playlist.dart'; -import 'package:spotube/components/tracks_view/track_view_props.dart'; -import 'package:spotube/extensions/context.dart'; -import 'package:spotube/provider/authentication/authentication.dart'; -import 'package:spotube/provider/history/history.dart'; -import 'package:spotube/provider/audio_player/audio_player.dart'; - -class TrackViewHeaderActions extends HookConsumerWidget { - const TrackViewHeaderActions({super.key}); - - @override - Widget build(BuildContext context, ref) { - final props = InheritedTrackView.of(context); - - final playlist = ref.watch(audioPlayerProvider); - final playlistNotifier = ref.watch(audioPlayerProvider.notifier); - final historyNotifier = ref.watch(playbackHistoryActionsProvider); - - final isActive = playlist.collections.contains(props.collectionId); - - final isUserPlaylist = useIsUserPlaylist(ref, props.collectionId); - - final scaffoldMessenger = ScaffoldMessenger.of(context); - - final auth = ref.watch(authenticationProvider); - - final copiedText = - context.l10n.copied_shareurl_to_clipboard(props.shareUrl); - - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - IconButton( - tooltip: context.l10n.share, - icon: const Icon(SpotubeIcons.share), - onPressed: () async { - await Clipboard.setData( - ClipboardData(text: props.shareUrl), - ); - - scaffoldMessenger.showSnackBar( - SnackBar( - width: 300, - behavior: SnackBarBehavior.floating, - content: Text( - copiedText, - textAlign: TextAlign.center, - ), - ), - ); - }, - ), - IconButton( - icon: const Icon(SpotubeIcons.queueAdd), - tooltip: context.l10n.add_to_queue, - onPressed: isActive || props.tracks.isEmpty - ? null - : () async { - final tracks = await props.pagination.onFetchAll(); - await playlistNotifier.addTracks(tracks); - playlistNotifier.addCollection(props.collectionId); - if (props.collection is AlbumSimple) { - historyNotifier - .addAlbums([props.collection as AlbumSimple]); - } else { - historyNotifier - .addPlaylists([props.collection as PlaylistSimple]); - } - }, - ), - if (props.onHeart != null && auth.asData?.value != null) - HeartButton( - isLiked: props.isLiked, - icon: isUserPlaylist ? SpotubeIcons.trash : null, - tooltip: props.isLiked - ? context.l10n.remove_from_favorites - : context.l10n.save_as_favorite, - onPressed: () async { - final shouldPop = await props.onHeart?.call(); - if (isUserPlaylist && shouldPop == true && context.mounted) { - context.pop(); - } - }, - ), - if (isUserPlaylist) - IconButton( - icon: const Icon(SpotubeIcons.edit), - onPressed: () { - showDialog( - context: context, - builder: (context) { - return PlaylistCreateDialog( - playlistId: props.collectionId, - trackIds: props.tracks.map((e) => e.id!).toList(), - ); - }, - ); - }, - ), - ], - ); - } -} diff --git a/lib/components/tracks_view/sections/header/header_buttons.dart b/lib/components/tracks_view/sections/header/header_buttons.dart deleted file mode 100644 index 54e0f0cf..00000000 --- a/lib/components/tracks_view/sections/header/header_buttons.dart +++ /dev/null @@ -1,206 +0,0 @@ -import 'dart:math'; - -import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:gap/gap.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:palette_generator/palette_generator.dart'; -import 'package:spotify/spotify.dart'; -import 'package:spotube/collections/spotube_icons.dart'; -import 'package:spotube/components/dialogs/select_device_dialog.dart'; -import 'package:spotube/components/tracks_view/track_view_props.dart'; -import 'package:spotube/extensions/context.dart'; -import 'package:spotube/models/connect/connect.dart'; -import 'package:spotube/provider/connect/connect.dart'; -import 'package:spotube/provider/history/history.dart'; -import 'package:spotube/provider/audio_player/audio_player.dart'; -import 'package:spotube/services/audio_player/audio_player.dart'; - -class TrackViewHeaderButtons extends HookConsumerWidget { - final PaletteColor color; - final bool compact; - const TrackViewHeaderButtons({ - super.key, - required this.color, - this.compact = false, - }); - - @override - Widget build(BuildContext context, ref) { - final props = InheritedTrackView.of(context); - final playlist = ref.watch(audioPlayerProvider); - final playlistNotifier = ref.watch(audioPlayerProvider.notifier); - final historyNotifier = ref.watch(playbackHistoryActionsProvider); - - final isActive = playlist.collections.contains(props.collectionId); - - final isLoading = useState(false); - - const progressIndicator = Center( - child: SizedBox.square( - dimension: 20, - child: CircularProgressIndicator(strokeWidth: .8), - ), - ); - - void onShuffle() async { - try { - isLoading.value = true; - - final initialTracks = props.tracks; - if (!context.mounted) return; - - final isRemoteDevice = await showSelectDeviceDialog(context, ref); - if (isRemoteDevice) { - final allTracks = await props.pagination.onFetchAll(); - final remotePlayback = ref.read(connectProvider.notifier); - await remotePlayback.load( - props.collection is AlbumSimple - ? WebSocketLoadEventData.album( - tracks: allTracks, - collection: props.collection as AlbumSimple, - initialIndex: Random().nextInt(allTracks.length)) - : WebSocketLoadEventData.playlist( - tracks: allTracks, - collection: props.collection as PlaylistSimple, - initialIndex: Random().nextInt(allTracks.length), - ), - ); - await remotePlayback.setShuffle(true); - } else { - await playlistNotifier.load( - initialTracks, - autoPlay: true, - initialIndex: Random().nextInt(initialTracks.length), - ); - await audioPlayer.setShuffle(true); - playlistNotifier.addCollection(props.collectionId); - if (props.collection is AlbumSimple) { - historyNotifier.addAlbums([props.collection as AlbumSimple]); - } else { - historyNotifier.addPlaylists([props.collection as PlaylistSimple]); - } - - final allTracks = await props.pagination.onFetchAll(); - - await playlistNotifier.addTracks( - allTracks.sublist(initialTracks.length), - ); - } - } finally { - isLoading.value = false; - } - } - - void onPlay() async { - try { - isLoading.value = true; - - final initialTracks = props.tracks; - - if (!context.mounted) return; - - final isRemoteDevice = await showSelectDeviceDialog(context, ref); - if (isRemoteDevice) { - final allTracks = await props.pagination.onFetchAll(); - final remotePlayback = ref.read(connectProvider.notifier); - await remotePlayback.load( - props.collection is AlbumSimple - ? WebSocketLoadEventData.album( - tracks: allTracks, - collection: props.collection as AlbumSimple, - ) - : WebSocketLoadEventData.playlist( - tracks: allTracks, - collection: props.collection as PlaylistSimple, - ), - ); - } else { - await playlistNotifier.load(initialTracks, autoPlay: true); - playlistNotifier.addCollection(props.collectionId); - if (props.collection is AlbumSimple) { - historyNotifier.addAlbums([props.collection as AlbumSimple]); - } else { - historyNotifier.addPlaylists([props.collection as PlaylistSimple]); - } - - final allTracks = await props.pagination.onFetchAll(); - - await playlistNotifier.addTracks( - allTracks.sublist(initialTracks.length), - ); - } - } finally { - if (context.mounted) { - isLoading.value = false; - } - } - } - - if (compact) { - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - if (!isActive && !isLoading.value) - IconButton( - icon: const Icon(SpotubeIcons.shuffle), - onPressed: props.tracks.isEmpty ? null : onShuffle, - ), - const Gap(10), - IconButton.filledTonal( - icon: isActive - ? const Icon(SpotubeIcons.pause) - : isLoading.value - ? progressIndicator - : const Icon(SpotubeIcons.play), - onPressed: isActive || props.tracks.isEmpty || isLoading.value - ? null - : onPlay, - ), - const Gap(10), - ], - ); - } - - return Row( - mainAxisSize: MainAxisSize.min, - children: [ - AnimatedOpacity( - duration: const Duration(milliseconds: 300), - opacity: isActive || isLoading.value ? 0 : 1, - child: AnimatedSize( - duration: const Duration(milliseconds: 300), - child: SizedBox.square( - dimension: isActive || isLoading.value ? 0 : null, - child: FilledButton.icon( - style: ElevatedButton.styleFrom( - backgroundColor: Colors.white, - foregroundColor: Colors.black, - minimumSize: const Size(150, 40)), - label: Text(context.l10n.shuffle), - icon: const Icon(SpotubeIcons.shuffle), - onPressed: props.tracks.isEmpty ? null : onShuffle, - ), - ), - ), - ), - const Gap(10), - FilledButton.icon( - style: ElevatedButton.styleFrom( - backgroundColor: color.color, - foregroundColor: color.bodyTextColor, - minimumSize: const Size(150, 40)), - onPressed: isActive || props.tracks.isEmpty || isLoading.value - ? null - : onPlay, - icon: isActive - ? const Icon(SpotubeIcons.pause) - : isLoading.value - ? progressIndicator - : const Icon(SpotubeIcons.play), - label: Text(context.l10n.play), - ), - ], - ); - } -} diff --git a/lib/components/tracks_view/track_view.dart b/lib/components/tracks_view/track_view.dart deleted file mode 100644 index fa6011e0..00000000 --- a/lib/components/tracks_view/track_view.dart +++ /dev/null @@ -1,52 +0,0 @@ -import 'package:flutter/material.dart'; - -import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:sliver_tools/sliver_tools.dart'; -import 'package:spotube/components/inter_scrollbar/inter_scrollbar.dart'; -import 'package:spotube/components/titlebar/titlebar.dart'; -import 'package:spotube/components/tracks_view/sections/header/flexible_header.dart'; -import 'package:spotube/components/tracks_view/sections/body/track_view_body.dart'; -import 'package:spotube/components/tracks_view/track_view_props.dart'; -import 'package:spotube/utils/platform.dart'; - -class TrackView extends HookConsumerWidget { - const TrackView({super.key}); - - @override - Widget build(BuildContext context, ref) { - final props = InheritedTrackView.of(context); - final controller = useScrollController(); - - return Scaffold( - appBar: kIsDesktop - ? const TitleBar( - backgroundColor: Colors.transparent, - leading: [ - Align( - alignment: Alignment.centerLeft, - child: BackButton(color: Colors.white), - ) - ], - ) - : null, - extendBodyBehindAppBar: true, - body: RefreshIndicator( - onRefresh: props.pagination.onRefresh, - child: InterScrollbar( - controller: controller, - child: CustomScrollView( - controller: controller, - slivers: const [ - TrackViewFlexHeader(), - SliverAnimatedSwitcher( - duration: Duration(milliseconds: 500), - child: TrackViewBodySection(), - ), - ], - ), - ), - ), - ); - } -} diff --git a/lib/components/tracks_view/track_view_provider.dart b/lib/components/tracks_view/track_view_provider.dart deleted file mode 100644 index 16aa6d9c..00000000 --- a/lib/components/tracks_view/track_view_provider.dart +++ /dev/null @@ -1,64 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:spotify/spotify.dart'; -import 'package:spotube/modules/library/user_local_tracks.dart'; - -class TrackViewNotifier extends ChangeNotifier { - List tracks; - List selectedTrackIds; - SortBy sortBy; - String? searchQuery; - - TrackViewNotifier( - this.tracks, { - this.selectedTrackIds = const [], - this.sortBy = SortBy.none, - this.searchQuery, - }); - - bool get isSelecting => selectedTrackIds.isNotEmpty; - - bool get hasSelectedAll => - selectedTrackIds.length == tracks.length && tracks.isNotEmpty; - - List get selectedTracks => - tracks.where((e) => selectedTrackIds.contains(e.id)).toList(); - - void selectTrack(String trackId) { - selectedTrackIds = [...selectedTrackIds, trackId]; - notifyListeners(); - } - - void unselectTrack(String trackId) { - selectedTrackIds = selectedTrackIds.where((e) => e != trackId).toList(); - notifyListeners(); - } - - void toggleTrackSelection(String trackId) { - if (selectedTrackIds.contains(trackId)) { - unselectTrack(trackId); - } else { - selectTrack(trackId); - } - } - - void selectAll() { - selectedTrackIds = tracks.map((e) => e.id!).toList(); - notifyListeners(); - } - - void deselectAll() { - selectedTrackIds = []; - notifyListeners(); - } - - void sort(SortBy sortBy) { - this.sortBy = sortBy; - notifyListeners(); - } -} - -final trackViewProvider = ChangeNotifierProvider.autoDispose - .family>((ref, tracks) { - return TrackViewNotifier(tracks); -}); diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 5b9e5183..4109edb7 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -402,5 +402,10 @@ "found_n_files": "Found {count} files", "export_cache_confirmation": "Do you want to export these files to", "exported_n_out_of_m_files": "Exported {filesExported} out of {files} files", - "undo": "Undo" + "undo": "Undo", + "download_all": "Download all", + "add_all_to_playlist": "Add all to playlist", + "add_all_to_queue": "Add all to queue", + "play_all_next": "Play all next", + "pause": "Pause" } \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 0b84d38d..ecf2cc37 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,6 +3,7 @@ import 'dart:ui'; import 'package:desktop_webview_window/desktop_webview_window.dart'; import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart' as material; import 'package:flutter/services.dart'; import 'package:flutter_discord_rpc/flutter_discord_rpc.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; @@ -225,6 +226,9 @@ class Spotube extends HookConsumerWidget { surfaceOpacity: .8, surfaceBlur: 10, ), + materialTheme: material.ThemeData( + splashFactory: material.NoSplash.splashFactory, + ), themeMode: themeMode, shortcuts: { ...WidgetsApp.defaultShortcuts.map((key, value) { diff --git a/lib/modules/root/sidebar.dart b/lib/modules/root/sidebar.dart index 1afa85c5..9a92a1cb 100644 --- a/lib/modules/root/sidebar.dart +++ b/lib/modules/root/sidebar.dart @@ -78,8 +78,8 @@ class Sidebar extends HookConsumerWidget { isLabelVisible: tile.title == "Library" && downloadCount > 0, label: Text( downloadCount.toString(), - style: const TextStyle( - color: Colors.white, + style: TextStyle( + color: context.theme.colorScheme.primaryForeground, fontSize: 10, ), ), diff --git a/lib/modules/settings/section_card_with_heading.dart b/lib/modules/settings/section_card_with_heading.dart index cd9428f0..c7bc1f26 100644 --- a/lib/modules/settings/section_card_with_heading.dart +++ b/lib/modules/settings/section_card_with_heading.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart' show ListTileTheme, ListTileThemeData; -import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart' hide Theme, ThemeData; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; class SectionCardWithHeading extends StatelessWidget { @@ -35,7 +35,9 @@ class SectionCardWithHeading extends StatelessWidget { padding: const EdgeInsets.symmetric(horizontal: 8.0), child: Text( heading, - style: context.theme.typography.large, + style: context.theme.typography.large.copyWith( + color: context.theme.colorScheme.foreground, + ), ), ), Padding( diff --git a/lib/pages/album/album.dart b/lib/pages/album/album.dart index 0c6cfd69..4a10268b 100644 --- a/lib/pages/album/album.dart +++ b/lib/pages/album/album.dart @@ -1,8 +1,8 @@ -import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; -import 'package:spotube/components/tracks_view/track_view.dart'; -import 'package:spotube/components/tracks_view/track_view_props.dart'; +import 'package:spotube/components/track_presentation/presentation_props.dart'; +import 'package:spotube/components/track_presentation/track_presentation.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/provider/spotify/spotify.dart'; @@ -23,43 +23,45 @@ class AlbumPage extends HookConsumerWidget { final favoriteAlbumsNotifier = ref.watch(favoriteAlbumsProvider.notifier); final isSavedAlbum = ref.watch(albumsIsSavedProvider(album.id!)); - return InheritedTrackView( - collection: album, - image: album.images.asUrlString( - placeholder: ImagePlaceholder.albumArt, + return TrackPresentation( + options: TrackPresentationOptions( + collection: album, + image: album.images.asUrlString( + placeholder: ImagePlaceholder.albumArt, + ), + title: album.name!, + description: + "${context.l10n.released} • ${album.releaseDate} • ${album.artists!.first.name}", + tracks: tracks.asData?.value.items ?? [], + pagination: PaginationProps( + hasNextPage: tracks.asData?.value.hasMore ?? false, + isLoading: tracks.isLoadingNextPage, + onFetchMore: () async { + await tracksNotifier.fetchMore(); + }, + onFetchAll: () async { + return tracksNotifier.fetchAll(); + }, + onRefresh: () async { + ref.invalidate(albumTracksProvider(album)); + }, + ), + routePath: "/album/${album.id}", + shareUrl: album.externalUrls?.spotify ?? + "https://open.spotify.com/album/${album.id}", + isLiked: isSavedAlbum.asData?.value ?? false, + owner: album.artists!.first.name, + onHeart: isSavedAlbum.asData?.value == null + ? null + : () async { + if (isSavedAlbum.asData!.value) { + await favoriteAlbumsNotifier.removeFavorites([album.id!]); + } else { + await favoriteAlbumsNotifier.addFavorites([album.id!]); + } + return null; + }, ), - title: album.name!, - description: - "${context.l10n.released} • ${album.releaseDate} • ${album.artists!.first.name}", - tracks: tracks.asData?.value.items ?? [], - pagination: PaginationProps( - hasNextPage: tracks.asData?.value.hasMore ?? false, - isLoading: tracks.isLoadingNextPage, - onFetchMore: () async { - await tracksNotifier.fetchMore(); - }, - onFetchAll: () async { - return tracksNotifier.fetchAll(); - }, - onRefresh: () async { - ref.invalidate(albumTracksProvider(album)); - }, - ), - routePath: "/album/${album.id}", - shareUrl: album.externalUrls?.spotify ?? - "https://open.spotify.com/album/${album.id}", - isLiked: isSavedAlbum.asData?.value ?? false, - onHeart: isSavedAlbum.asData?.value == null - ? null - : () async { - if (isSavedAlbum.asData!.value) { - await favoriteAlbumsNotifier.removeFavorites([album.id!]); - } else { - await favoriteAlbumsNotifier.addFavorites([album.id!]); - } - return null; - }, - child: const TrackView(), ); } } diff --git a/lib/pages/library/local_folder.dart b/lib/pages/library/local_folder.dart index 478eac5e..8cfec3a8 100644 --- a/lib/pages/library/local_folder.dart +++ b/lib/pages/library/local_folder.dart @@ -17,7 +17,7 @@ import 'package:spotube/components/expandable_search/expandable_search.dart'; import 'package:spotube/components/fallbacks/not_found.dart'; import 'package:spotube/components/inter_scrollbar/inter_scrollbar.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; -import 'package:spotube/components/sort_tracks_dropdown.dart'; +import 'package:spotube/components/track_presentation/sort_tracks_dropdown.dart'; import 'package:spotube/components/track_tile/track_tile.dart'; import 'package:spotube/extensions/artist_simple.dart'; import 'package:spotube/extensions/context.dart'; diff --git a/lib/pages/playlist/liked_playlist.dart b/lib/pages/playlist/liked_playlist.dart index 942f46d5..3b4455d5 100644 --- a/lib/pages/playlist/liked_playlist.dart +++ b/lib/pages/playlist/liked_playlist.dart @@ -1,8 +1,8 @@ import 'package:flutter/widgets.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; -import 'package:spotube/components/tracks_view/track_view.dart'; -import 'package:spotube/components/tracks_view/track_view_props.dart'; +import 'package:spotube/components/track_presentation/presentation_props.dart'; +import 'package:spotube/components/track_presentation/track_presentation.dart'; import 'package:spotube/pages/playlist/playlist.dart'; import 'package:spotube/provider/spotify/spotify.dart'; @@ -20,28 +20,30 @@ class LikedPlaylistPage extends HookConsumerWidget { final likedTracks = ref.watch(likedTracksProvider); final tracks = likedTracks.asData?.value ?? []; - return InheritedTrackView( - collection: playlist, - image: "assets/liked-tracks.jpg", - pagination: PaginationProps( - hasNextPage: false, - isLoading: false, - onFetchMore: () {}, - onFetchAll: () async { - return tracks.toList(); - }, - onRefresh: () async { - ref.invalidate(likedTracksProvider); - }, + return TrackPresentation( + options: TrackPresentationOptions( + collection: playlist, + image: "assets/liked-tracks.jpg", + pagination: PaginationProps( + hasNextPage: false, + isLoading: false, + onFetchMore: () {}, + onFetchAll: () async { + return tracks.toList(); + }, + onRefresh: () async { + ref.invalidate(likedTracksProvider); + }, + ), + title: playlist.name!, + description: playlist.description, + tracks: tracks, + routePath: '/playlist/${playlist.id}', + isLiked: false, + shareUrl: null, + onHeart: null, + owner: playlist.owner?.displayName, ), - title: playlist.name!, - description: playlist.description, - tracks: tracks, - routePath: '/playlist/${playlist.id}', - isLiked: false, - shareUrl: "", - onHeart: null, - child: const TrackView(), ); } } diff --git a/lib/pages/playlist/playlist.dart b/lib/pages/playlist/playlist.dart index e1b33e98..da28c83c 100644 --- a/lib/pages/playlist/playlist.dart +++ b/lib/pages/playlist/playlist.dart @@ -3,9 +3,9 @@ import 'package:flutter/material.dart' hide Page; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/dialogs/prompt_dialog.dart'; -import 'package:spotube/components/tracks_view/sections/body/use_is_user_playlist.dart'; -import 'package:spotube/components/tracks_view/track_view.dart'; -import 'package:spotube/components/tracks_view/track_view_props.dart'; +import 'package:spotube/components/track_presentation/presentation_props.dart'; +import 'package:spotube/components/track_presentation/track_presentation.dart'; +import 'package:spotube/components/track_presentation/use_is_user_playlist.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/provider/spotify/spotify.dart'; @@ -45,49 +45,52 @@ class PlaylistPage extends HookConsumerWidget { final isUserPlaylist = useIsUserPlaylist(ref, playlist.id!); - return InheritedTrackView( - collection: playlist, - image: playlist.images.asUrlString( - placeholder: ImagePlaceholder.collection, - ), - pagination: PaginationProps( - hasNextPage: tracks.asData?.value.hasMore ?? false, - isLoading: tracks.isLoadingNextPage, - onFetchMore: tracksNotifier.fetchMore, - onRefresh: () async { - ref.invalidate(playlistTracksProvider(playlist.id!)); - }, - onFetchAll: () async { - return await tracksNotifier.fetchAll(); - }, - ), - title: playlist.name!, - description: playlist.description, - tracks: tracks.asData?.value.items ?? [], - routePath: '/playlist/${playlist.id}', - isLiked: isFavoritePlaylist.asData?.value ?? false, - shareUrl: playlist.externalUrls?.spotify ?? - "https://open.spotify.com/playlist/${playlist.id}", - onHeart: isFavoritePlaylist.asData?.value == null - ? null - : () async { - final confirmed = isUserPlaylist - ? await showPromptDialog( - context: context, - title: context.l10n.delete_playlist, - message: context.l10n.delete_playlist_confirmation, - ) - : true; - if (!confirmed) return null; + return TrackPresentation( + options: TrackPresentationOptions( + collection: playlist, + image: playlist.images.asUrlString( + placeholder: ImagePlaceholder.collection, + ), + pagination: PaginationProps( + hasNextPage: tracks.asData?.value.hasMore ?? false, + isLoading: tracks.isLoadingNextPage, + onFetchMore: tracksNotifier.fetchMore, + onRefresh: () async { + ref.invalidate(playlistTracksProvider(playlist.id!)); + }, + onFetchAll: () async { + return await tracksNotifier.fetchAll(); + }, + ), + title: playlist.name!, + description: playlist.description, + owner: playlist.owner?.displayName, + ownerImage: playlist.owner?.images?.lastOrNull?.url, + tracks: tracks.asData?.value.items ?? [], + routePath: '/playlist/${playlist.id}', + isLiked: isFavoritePlaylist.asData?.value ?? false, + shareUrl: playlist.externalUrls?.spotify ?? + "https://open.spotify.com/playlist/${playlist.id}", + onHeart: isFavoritePlaylist.asData?.value == null + ? null + : () async { + final confirmed = isUserPlaylist + ? await showPromptDialog( + context: context, + title: context.l10n.delete_playlist, + message: context.l10n.delete_playlist_confirmation, + ) + : true; + if (!confirmed) return null; - if (isFavoritePlaylist.asData!.value) { - await favoritePlaylistsNotifier.removeFavorite(playlist); - } else { - await favoritePlaylistsNotifier.addFavorite(playlist); - } - return isUserPlaylist; - }, - child: const TrackView(), + if (isFavoritePlaylist.asData!.value) { + await favoritePlaylistsNotifier.removeFavorite(playlist); + } else { + await favoritePlaylistsNotifier.addFavorite(playlist); + } + return isUserPlaylist; + }, + ), ); } } diff --git a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 1407feb3..de152fbe 100644 --- a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -48,6 +48,7 @@ ignoresPersistentStateOnLaunch = "NO" debugDocumentVersioning = "YES" debugServiceExtension = "internal" + enableGPUValidationMode = "1" allowLocationSimulation = "YES"> diff --git a/pubspec.lock b/pubspec.lock index ff445cad..34306fef 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -98,10 +98,10 @@ packages: dependency: "direct main" description: name: async - sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 url: "https://pub.dev" source: hosted - version: "2.11.0" + version: "2.12.0" audio_service: dependency: "direct main" description: @@ -203,10 +203,10 @@ packages: dependency: transitive description: name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" build: dependency: transitive description: @@ -347,10 +347,10 @@ packages: dependency: transitive description: name: clock - sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" code_builder: dependency: transitive description: @@ -598,10 +598,10 @@ packages: dependency: transitive description: name: fake_async - sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.3.2" ffi: dependency: transitive description: @@ -614,10 +614,10 @@ packages: dependency: transitive description: name: file - sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "7.0.1" file_picker: dependency: "direct main" description: @@ -1330,18 +1330,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" + sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec url: "https://pub.dev" source: hosted - version: "10.0.7" + version: "10.0.8" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" + sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 url: "https://pub.dev" source: hosted - version: "3.0.8" + version: "3.0.9" leak_tracker_testing: dependency: transitive description: @@ -1642,10 +1642,10 @@ packages: dependency: "direct main" description: name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.9.1" path_drawing: dependency: transitive description: @@ -1786,10 +1786,10 @@ packages: dependency: transitive description: name: platform - sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" url: "https://pub.dev" source: hosted - version: "3.1.5" + version: "3.1.6" plugin_platform_interface: dependency: transitive description: @@ -1826,10 +1826,10 @@ packages: dependency: transitive description: name: process - sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32" + sha256: "107d8be718f120bbba9dcd1e95e3bd325b1b4a4f07db64154635ba03f2567a0d" url: "https://pub.dev" source: hosted - version: "5.0.2" + version: "5.0.3" process_run: dependency: "direct dev" description: @@ -2257,10 +2257,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" + sha256: "0bd04f5bb74fcd6ff0606a888a30e917af9bd52820b178eaa464beb11dca84b6" url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" stroke_text: dependency: "direct main" description: @@ -2553,10 +2553,10 @@ packages: dependency: transitive description: name: vm_service - sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b + sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" url: "https://pub.dev" source: hosted - version: "14.3.0" + version: "14.3.1" watcher: dependency: transitive description: diff --git a/untranslated_messages.json b/untranslated_messages.json index 67bb4673..05b5aca3 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -1,105 +1,235 @@ { "ar": [ - "undo" + "undo", + "download_all", + "add_all_to_playlist", + "add_all_to_queue", + "play_all_next", + "pause" ], "bn": [ - "undo" + "undo", + "download_all", + "add_all_to_playlist", + "add_all_to_queue", + "play_all_next", + "pause" ], "ca": [ - "undo" + "undo", + "download_all", + "add_all_to_playlist", + "add_all_to_queue", + "play_all_next", + "pause" ], "cs": [ - "undo" + "undo", + "download_all", + "add_all_to_playlist", + "add_all_to_queue", + "play_all_next", + "pause" ], "de": [ - "undo" + "undo", + "download_all", + "add_all_to_playlist", + "add_all_to_queue", + "play_all_next", + "pause" ], "es": [ - "undo" + "undo", + "download_all", + "add_all_to_playlist", + "add_all_to_queue", + "play_all_next", + "pause" ], "eu": [ - "undo" + "undo", + "download_all", + "add_all_to_playlist", + "add_all_to_queue", + "play_all_next", + "pause" ], "fa": [ - "undo" + "undo", + "download_all", + "add_all_to_playlist", + "add_all_to_queue", + "play_all_next", + "pause" ], "fi": [ - "undo" + "undo", + "download_all", + "add_all_to_playlist", + "add_all_to_queue", + "play_all_next", + "pause" ], "fr": [ - "undo" + "undo", + "download_all", + "add_all_to_playlist", + "add_all_to_queue", + "play_all_next", + "pause" ], "hi": [ - "undo" + "undo", + "download_all", + "add_all_to_playlist", + "add_all_to_queue", + "play_all_next", + "pause" ], "id": [ - "undo" + "undo", + "download_all", + "add_all_to_playlist", + "add_all_to_queue", + "play_all_next", + "pause" ], "it": [ - "undo" + "undo", + "download_all", + "add_all_to_playlist", + "add_all_to_queue", + "play_all_next", + "pause" ], "ja": [ - "undo" + "undo", + "download_all", + "add_all_to_playlist", + "add_all_to_queue", + "play_all_next", + "pause" ], "ka": [ - "undo" + "undo", + "download_all", + "add_all_to_playlist", + "add_all_to_queue", + "play_all_next", + "pause" ], "ko": [ - "undo" + "undo", + "download_all", + "add_all_to_playlist", + "add_all_to_queue", + "play_all_next", + "pause" ], "ne": [ - "undo" + "undo", + "download_all", + "add_all_to_playlist", + "add_all_to_queue", + "play_all_next", + "pause" ], "nl": [ - "undo" + "undo", + "download_all", + "add_all_to_playlist", + "add_all_to_queue", + "play_all_next", + "pause" ], "pl": [ - "undo" + "undo", + "download_all", + "add_all_to_playlist", + "add_all_to_queue", + "play_all_next", + "pause" ], "pt": [ - "undo" + "undo", + "download_all", + "add_all_to_playlist", + "add_all_to_queue", + "play_all_next", + "pause" ], "ru": [ - "undo" + "undo", + "download_all", + "add_all_to_playlist", + "add_all_to_queue", + "play_all_next", + "pause" ], "th": [ - "undo" + "undo", + "download_all", + "add_all_to_playlist", + "add_all_to_queue", + "play_all_next", + "pause" ], "tr": [ - "undo" + "undo", + "download_all", + "add_all_to_playlist", + "add_all_to_queue", + "play_all_next", + "pause" ], "uk": [ - "undo" + "undo", + "download_all", + "add_all_to_playlist", + "add_all_to_queue", + "play_all_next", + "pause" ], "vi": [ - "undo" + "undo", + "download_all", + "add_all_to_playlist", + "add_all_to_queue", + "play_all_next", + "pause" ], "zh": [ - "undo" + "undo", + "download_all", + "add_all_to_playlist", + "add_all_to_queue", + "play_all_next", + "pause" ] } From 2ee0ca44c79de6038f639f768cc2cf39d06534b4 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 28 Dec 2024 19:51:04 +0600 Subject: [PATCH 029/112] refactor: profile page to use shadcn design --- lib/pages/profile/profile.dart | 40 +++++++++++------------- lib/pages/search/sections/albums.dart | 2 +- lib/pages/search/sections/artists.dart | 2 +- lib/pages/search/sections/playlists.dart | 2 +- lib/pages/search/sections/tracks.dart | 5 +-- 5 files changed, 24 insertions(+), 27 deletions(-) diff --git a/lib/pages/profile/profile.dart b/lib/pages/profile/profile.dart index b4d72b53..004fbd1a 100644 --- a/lib/pages/profile/profile.dart +++ b/lib/pages/profile/profile.dart @@ -1,7 +1,6 @@ -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:sliver_tools/sliver_tools.dart'; import 'package:spotube/collections/fake.dart'; @@ -21,8 +20,6 @@ class ProfilePage extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final ThemeData(:textTheme) = Theme.of(context); - final me = ref.watch(meProvider); final meData = me.asData?.value ?? FakeData.user; @@ -42,11 +39,13 @@ class ProfilePage extends HookConsumerWidget { return SafeArea( child: Scaffold( - appBar: TitleBar( - title: Text(context.l10n.profile), - automaticallyImplyLeading: true, - ), - body: Skeletonizer( + headers: [ + TitleBar( + title: Text(context.l10n.profile), + automaticallyImplyLeading: true, + ) + ], + child: Skeletonizer( enabled: me.isLoading, child: CustomScrollView( slivers: [ @@ -73,9 +72,8 @@ class ProfilePage extends HookConsumerWidget { SliverToBoxAdapter( child: Text( meData.displayName ?? context.l10n.no_name, - style: textTheme.titleLarge, textAlign: TextAlign.center, - ), + ).h4(), ), const SliverGap(20), SliverCrossAxisConstrained( @@ -84,15 +82,15 @@ class ProfilePage extends HookConsumerWidget { child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ - TextButton.icon( - label: Text(context.l10n.edit), - icon: const Icon(SpotubeIcons.edit), + Button.text( + leading: const Icon(SpotubeIcons.edit), onPressed: () { launchUrlString( "https://www.spotify.com/account/profile/", mode: LaunchMode.externalApplication, ); }, + child: Text(context.l10n.edit), ), ], ), @@ -102,25 +100,22 @@ class ProfilePage extends HookConsumerWidget { maxCrossAxisExtent: 500, child: SliverToBoxAdapter( child: Card( - margin: const EdgeInsets.all(10), child: Padding( padding: const EdgeInsets.all(8.0), child: Table( columnWidths: const { - 0: FixedColumnWidth(110), + 0: FixedTableSize(120), }, - children: [ + defaultRowHeight: const FixedTableSize(40), + rows: [ for (final MapEntry(:key, :value) in userProperties.entries) TableRow( - children: [ + cells: [ TableCell( child: Padding( padding: const EdgeInsets.all(6), - child: Text( - key, - style: textTheme.titleSmall, - ), + child: Text(key).large(), ), ), TableCell( @@ -137,6 +132,7 @@ class ProfilePage extends HookConsumerWidget { ), ), ), + const SliverGap(200), ], ), ), diff --git a/lib/pages/search/sections/albums.dart b/lib/pages/search/sections/albums.dart index 857eb59c..105c23d5 100644 --- a/lib/pages/search/sections/albums.dart +++ b/lib/pages/search/sections/albums.dart @@ -1,6 +1,6 @@ -import 'package:flutter/material.dart' hide Page; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart'; diff --git a/lib/pages/search/sections/artists.dart b/lib/pages/search/sections/artists.dart index 16295580..9a94b3c1 100644 --- a/lib/pages/search/sections/artists.dart +++ b/lib/pages/search/sections/artists.dart @@ -1,5 +1,5 @@ -import 'package:flutter/material.dart' hide Page; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart'; diff --git a/lib/pages/search/sections/playlists.dart b/lib/pages/search/sections/playlists.dart index 3799f9fa..17bf4849 100644 --- a/lib/pages/search/sections/playlists.dart +++ b/lib/pages/search/sections/playlists.dart @@ -1,5 +1,5 @@ -import 'package:flutter/material.dart' hide Page; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart'; import 'package:spotube/extensions/context.dart'; diff --git a/lib/pages/search/sections/tracks.dart b/lib/pages/search/sections/tracks.dart index 6ec8f685..c0daa853 100644 --- a/lib/pages/search/sections/tracks.dart +++ b/lib/pages/search/sections/tracks.dart @@ -1,6 +1,7 @@ import 'package:collection/collection.dart'; -import 'package:flutter/material.dart' hide Page; + import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/dialogs/prompt_dialog.dart'; import 'package:spotube/components/dialogs/select_device_dialog.dart'; @@ -37,7 +38,7 @@ class SearchTracksSection extends HookConsumerWidget { padding: const EdgeInsets.symmetric(horizontal: 8), child: Text( context.l10n.songs, - style: theme.textTheme.titleLarge!, + style: theme.typography.h4, ), ), if (searchTrack.isLoading) From d845180e6039a60bc5ef174fad8285328171cc20 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 28 Dec 2024 21:18:35 +0600 Subject: [PATCH 030/112] fix: mobile keyboard overflow --- ios/Runner.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/xcschemes/Runner.xcscheme | 1 + .../horizontal_playbutton_card_view.dart | 3 +- .../playbutton_view/playbutton_tile.dart | 8 +- .../presentation_modifiers.dart | 15 +- .../track_presentation.dart | 30 +++- lib/main.dart | 6 + lib/modules/library/user_albums.dart | 6 +- lib/modules/library/user_artists.dart | 6 +- lib/modules/library/user_playlists.dart | 6 +- lib/pages/lastfm_login/lastfm_login.dart | 140 +++++++++--------- lib/pages/root/root_app.dart | 18 ++- lib/pages/search/search.dart | 136 ++++++++--------- 13 files changed, 213 insertions(+), 164 deletions(-) diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 63871a3d..bbfc1404 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 70; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 5e31d3d3..c53e2b31 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -48,6 +48,7 @@ ignoresPersistentStateOnLaunch = "NO" debugDocumentVersioning = "YES" debugServiceExtension = "internal" + enableGPUValidationMode = "1" allowLocationSimulation = "YES"> diff --git a/lib/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart b/lib/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart index d37bc8a0..47fb0f33 100644 --- a/lib/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart +++ b/lib/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart @@ -38,6 +38,7 @@ class HorizontalPlaybuttonCardView extends HookWidget { Widget build(BuildContext context) { final scrollController = useScrollController(); final isArtist = items.every((s) => s is Artist); + final scale = context.theme.scaling; return Padding( padding: const EdgeInsets.all(8.0), @@ -92,7 +93,7 @@ class HorizontalPlaybuttonCardView extends HookWidget { ), isLoading: isLoadingNextPage, hasReachedMax: !hasNextPage, - separatorBuilder: (context, index) => const Gap(8.0), + separatorBuilder: (context, index) => Gap(12 * scale), itemBuilder: (context, index) { final item = items[index]; diff --git a/lib/components/playbutton_view/playbutton_tile.dart b/lib/components/playbutton_view/playbutton_tile.dart index e06f3689..3daaf75c 100644 --- a/lib/components/playbutton_view/playbutton_tile.dart +++ b/lib/components/playbutton_view/playbutton_tile.dart @@ -35,7 +35,7 @@ class PlaybuttonTile extends StatelessWidget { final cleanDescription = description?.unescapeHtml().cleanHtml() ?? ""; final scale = context.theme.scaling; - return Button.ghost( + return Button( leading: Container( width: 50 * scale, height: 50 * scale, @@ -47,6 +47,12 @@ class PlaybuttonTile extends StatelessWidget { ), ), ), + style: ButtonVariance.ghost.copyWith( + padding: (context, states, value) { + return (ButtonVariance.ghost.padding(context, states) as EdgeInsets) + .copyWith(right: 0, left: 0); + }, + ), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ diff --git a/lib/components/track_presentation/presentation_modifiers.dart b/lib/components/track_presentation/presentation_modifiers.dart index d1678e17..4d781d24 100644 --- a/lib/components/track_presentation/presentation_modifiers.dart +++ b/lib/components/track_presentation/presentation_modifiers.dart @@ -11,7 +11,11 @@ import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; class TrackPresentationModifiersSection extends HookConsumerWidget { - const TrackPresentationModifiersSection({super.key}); + final FocusNode? focusNode; + const TrackPresentationModifiersSection({ + super.key, + this.focusNode, + }); @override Widget build(BuildContext context, ref) { @@ -22,11 +26,12 @@ class TrackPresentationModifiersSection extends HookConsumerWidget { ); final controller = useTextEditingController(); + final scale = context.theme.scaling; return LayoutBuilder(builder: (context, constrains) { return Padding( padding: EdgeInsets.symmetric( - horizontal: constrains.mdAndUp ? 16 : 8, + horizontal: (constrains.mdAndUp ? 16 : 8) * scale, ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -55,11 +60,13 @@ class TrackPresentationModifiersSection extends HookConsumerWidget { children: [ Flexible( child: ConstrainedBox( - constraints: const BoxConstraints( - maxWidth: 320, + constraints: BoxConstraints( + maxWidth: 320 * scale, + maxHeight: 38 * scale, ), child: TextField( controller: controller, + focusNode: focusNode, leading: Icon( SpotubeIcons.search, color: context.theme.colorScheme.mutedForeground, diff --git a/lib/components/track_presentation/track_presentation.dart b/lib/components/track_presentation/track_presentation.dart index 8bc1c6df..e81a2e1e 100644 --- a/lib/components/track_presentation/track_presentation.dart +++ b/lib/components/track_presentation/track_presentation.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart' show ListTile; +import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; @@ -9,6 +10,7 @@ import 'package:spotube/components/track_presentation/presentation_top.dart'; import 'package:spotube/components/track_presentation/presentation_modifiers.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; +import 'package:spotube/utils/platform.dart'; class TrackPresentation extends HookConsumerWidget { final TrackPresentationOptions options; @@ -22,6 +24,29 @@ class TrackPresentation extends HookConsumerWidget { final headerTextStyle = context.theme.typography.small.copyWith( color: context.theme.colorScheme.mutedForeground, ); + final scrollController = useScrollController(); + final focusNode = useFocusNode(); + final scale = context.theme.scaling; + + useEffect(() { + if (!kIsMobile) return null; + void listener() { + if (!scrollController.hasClients) return; + + if (focusNode.hasFocus) { + scrollController.animateTo( + 300 * scale, + duration: const Duration(milliseconds: 300), + curve: Curves.easeInOut, + ); + } + } + + focusNode.addListener(listener); + return () { + focusNode.removeListener(listener); + }; + }, [focusNode, scrollController, scale]); return Data.inherit( data: options, @@ -29,6 +54,7 @@ class TrackPresentation extends HookConsumerWidget { child: Scaffold( headers: const [TitleBar()], child: CustomScrollView( + controller: scrollController, slivers: [ const TrackPresentationTopSection(), const SliverGap(16), @@ -36,7 +62,9 @@ class TrackPresentation extends HookConsumerWidget { builder: (context, constrains) { return SliverList.list( children: [ - const TrackPresentationModifiersSection(), + TrackPresentationModifiersSection( + focusNode: focusNode, + ), ListTile( titleTextStyle: headerTextStyle, subtitleTextStyle: headerTextStyle, diff --git a/lib/main.dart b/lib/main.dart index ecf2cc37..2f93ea87 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -228,6 +228,12 @@ class Spotube extends HookConsumerWidget { ), materialTheme: material.ThemeData( splashFactory: material.NoSplash.splashFactory, + appBarTheme: const material.AppBarTheme( + surfaceTintColor: Colors.transparent, + scrolledUnderElevation: 0, + shadowColor: Colors.transparent, + elevation: 0, + ), ), themeMode: themeMode, shortcuts: { diff --git a/lib/modules/library/user_albums.dart b/lib/modules/library/user_albums.dart index a388c0ad..b460f22e 100644 --- a/lib/modules/library/user_albums.dart +++ b/lib/modules/library/user_albums.dart @@ -50,9 +50,9 @@ class UserAlbums extends HookConsumerWidget { return SafeArea( child: Scaffold( child: RefreshTrigger( - onRefresh: () async { - ref.invalidate(favoriteAlbumsProvider); - }, + // onRefresh: () async { + // ref.invalidate(favoriteAlbumsProvider); + // }, child: InterScrollbar( controller: controller, child: CustomScrollView( diff --git a/lib/modules/library/user_artists.dart b/lib/modules/library/user_artists.dart index 83a321fc..eaf5afb3 100644 --- a/lib/modules/library/user_artists.dart +++ b/lib/modules/library/user_artists.dart @@ -55,9 +55,9 @@ class UserArtists extends HookConsumerWidget { return SafeArea( child: Scaffold( child: RefreshTrigger( - onRefresh: () async { - ref.invalidate(followedArtistsProvider); - }, + // onRefresh: () async { + // ref.invalidate(followedArtistsProvider); + // }, child: InterScrollbar( controller: controller, child: Padding( diff --git a/lib/modules/library/user_playlists.dart b/lib/modules/library/user_playlists.dart index 2a2d65e0..1b1bf110 100644 --- a/lib/modules/library/user_playlists.dart +++ b/lib/modules/library/user_playlists.dart @@ -78,9 +78,9 @@ class UserPlaylists extends HookConsumerWidget { } return RefreshTrigger( - onRefresh: () async { - ref.invalidate(favoritePlaylistsProvider); - }, + // onRefresh: () async { + // ref.invalidate(favoritePlaylistsProvider); + // }, child: SafeArea( child: InterScrollbar( controller: controller, diff --git a/lib/pages/lastfm_login/lastfm_login.dart b/lib/pages/lastfm_login/lastfm_login.dart index 2611d771..d5466544 100644 --- a/lib/pages/lastfm_login/lastfm_login.dart +++ b/lib/pages/lastfm_login/lastfm_login.dart @@ -1,9 +1,10 @@ -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:form_validator/form_validator.dart'; + import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/button/back_button.dart'; import 'package:spotube/components/dialogs/prompt_dialog.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/extensions/context.dart'; @@ -15,31 +16,59 @@ class LastFMLoginPage extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final theme = Theme.of(context); final router = GoRouter.of(context); final scrobblerNotifier = ref.read(scrobblerProvider.notifier); - final formKey = useMemoized(() => GlobalKey(), []); - final username = useTextEditingController(); - final password = useTextEditingController(); + final usernameKey = + useMemoized(() => const FormKey("username"), []); + final passwordKey = + useMemoized(() => const FormKey("password"), []); + final passwordVisible = useState(false); final isLoading = useState(false); return Scaffold( - appBar: const TitleBar(leading: [BackButton()]), - body: Center( - child: ConstrainedBox( + headers: const [ + SafeArea( + child: TitleBar( + leading: [BackButton()], + ), + ), + ], + child: SingleChildScrollView( + child: Container( constraints: const BoxConstraints(maxWidth: 400), + alignment: Alignment.center, + padding: const EdgeInsets.all(16), child: Card( - margin: const EdgeInsets.all(8.0), child: Padding( padding: const EdgeInsets.all(16.0).copyWith(top: 8), child: Form( - key: formKey, - autovalidateMode: AutovalidateMode.onUserInteraction, + onSubmit: (context, values) async { + try { + isLoading.value = true; + await scrobblerNotifier.login( + values[usernameKey].trim(), + values[passwordKey], + ); + router.pop(); + } catch (e) { + if (context.mounted) { + showPromptDialog( + context: context, + title: context.l10n.error("Authentication failed"), + message: e.toString(), + cancelText: null, + ); + } + } finally { + isLoading.value = false; + } + }, child: Column( mainAxisSize: MainAxisSize.min, + spacing: 10, children: [ Container( decoration: BoxDecoration( @@ -53,38 +82,35 @@ class LastFMLoginPage extends HookConsumerWidget { size: 60, ), ), - Text( - "last.fm", - style: theme.textTheme.titleLarge, - ), - const SizedBox(height: 10), + const Text("last.fm").h3(), Text(context.l10n.login_with_your_lastfm), - const SizedBox(height: 10), AutofillGroup( child: Column( + spacing: 10, children: [ - TextFormField( - autofillHints: const [ - AutofillHints.username, - AutofillHints.email, - ], - controller: username, - validator: ValidationBuilder().required().build(), - decoration: InputDecoration( - labelText: context.l10n.username, + FormField( + label: Text(context.l10n.username), + key: usernameKey, + validator: const NotEmptyValidator(), + child: TextField( + autofillHints: const [ + AutofillHints.username, + AutofillHints.email, + ], + placeholder: Text(context.l10n.username), ), ), - const SizedBox(height: 10), - TextFormField( - autofillHints: const [ - AutofillHints.password, - ], - controller: password, - validator: ValidationBuilder().required().build(), - obscureText: !passwordVisible.value, - decoration: InputDecoration( - labelText: context.l10n.password, - suffixIcon: IconButton( + FormField( + key: passwordKey, + validator: const NotEmptyValidator(), + label: Text(context.l10n.password), + child: TextField( + autofillHints: const [ + AutofillHints.password, + ], + obscureText: !passwordVisible.value, + placeholder: Text(context.l10n.password), + trailing: IconButton.ghost( icon: Icon( passwordVisible.value ? SpotubeIcons.eye @@ -98,37 +124,13 @@ class LastFMLoginPage extends HookConsumerWidget { ], ), ), - const SizedBox(height: 10), - FilledButton( - onPressed: isLoading.value - ? null - : () async { - try { - isLoading.value = true; - if (formKey.currentState?.validate() != true) { - return; - } - await scrobblerNotifier.login( - username.text.trim(), - password.text, - ); - router.pop(); - } catch (e) { - if (context.mounted) { - showPromptDialog( - context: context, - title: context.l10n - .error("Authentication failed"), - message: e.toString(), - cancelText: null, - ); - } - } finally { - isLoading.value = false; - } - }, - child: Text(context.l10n.login), - ), + FormErrorBuilder(builder: (context, errors, child) { + return Button.primary( + onPressed: () => context.submitForm(), + enabled: errors.isEmpty && !isLoading.value, + child: Text(context.l10n.login), + ); + }), ], ), ), diff --git a/lib/pages/root/root_app.dart b/lib/pages/root/root_app.dart index 606bba34..cdb56910 100644 --- a/lib/pages/root/root_app.dart +++ b/lib/pages/root/root_app.dart @@ -179,13 +179,17 @@ class RootApp extends HookConsumerWidget { return getSidebarTileList(context.l10n).map((s) => s.name).toList(); }, []); - final scaffold = Scaffold( - footers: const [ - BottomPlayer(), - SpotubeNavigationBar(), - ], - floatingFooter: true, - child: Sidebar(child: child), + final scaffold = MediaQuery.removeViewInsets( + context: context, + removeBottom: true, + child: Scaffold( + footers: const [ + BottomPlayer(), + SpotubeNavigationBar(), + ], + floatingFooter: true, + child: Sidebar(child: child), + ), ); if (!kIsAndroid) { diff --git a/lib/pages/search/search.dart b/lib/pages/search/search.dart index 5c096a32..9e2bf20c 100644 --- a/lib/pages/search/search.dart +++ b/lib/pages/search/search.dart @@ -29,13 +29,15 @@ class SearchPage extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { final theme = Theme.of(context); - final searchTerm = ref.watch(searchTermStateProvider); + final mediaQuery = MediaQuery.sizeOf(context); + + final scrollController = useScrollController(); final controller = useSearchController(); final focusNode = useFocusNode(); final auth = ref.watch(authenticationProvider); - final mediaQuery = MediaQuery.of(context); + final searchTerm = ref.watch(searchTermStateProvider); final searchTrack = ref.watch(searchProvider(SearchType.track)); final searchAlbum = ref.watch(searchProvider(SearchType.album)); final searchPlaylist = ref.watch(searchProvider(SearchType.playlist)); @@ -51,35 +53,6 @@ class SearchPage extends HookConsumerWidget { return null; }, []); - final resultWidget = HookBuilder( - builder: (context) { - final controller = useScrollController(); - - return InterScrollbar( - controller: controller, - child: SingleChildScrollView( - controller: controller, - child: const Padding( - padding: EdgeInsets.symmetric(vertical: 8), - child: SafeArea( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SearchTracksSection(), - SearchPlaylistsSection(), - Gap(20), - SearchArtistsSection(), - Gap(20), - SearchAlbumsSection(), - ], - ), - ), - ), - ), - ); - }, - ); - void onSubmitted(String value) { ref.read(searchTermStateProvider.notifier).state = value; if (value.trim().isEmpty) { @@ -182,59 +155,80 @@ class SearchPage extends HookConsumerWidget { Expanded( child: AnimatedSwitcher( duration: const Duration(milliseconds: 300), - child: searchTerm.isEmpty - ? Column( - children: [ - SizedBox( - height: mediaQuery.size.height * 0.2, - ), - Icon( - SpotubeIcons.web, - size: 120, + child: switch ((searchTerm.isEmpty, isFetching)) { + (true, false) => Column( + children: [ + SizedBox( + height: mediaQuery.height * 0.2, + ), + Icon( + SpotubeIcons.web, + size: 120, + color: theme.colorScheme.foreground + .withOpacity(0.7), + ), + const SizedBox(height: 20), + Text( + context.l10n.search_to_get_results, + style: theme.typography.h3.copyWith( + fontWeight: FontWeight.w900, color: theme.colorScheme.foreground - .withOpacity(0.7), + .withOpacity(0.5), ), - const SizedBox(height: 20), + ), + ], + ), + (false, true) => Container( + constraints: BoxConstraints( + maxWidth: mediaQuery.lgAndUp + ? mediaQuery.width * 0.5 + : mediaQuery.width, + ), + padding: const EdgeInsets.symmetric( + horizontal: 20, + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ Text( - context.l10n.search_to_get_results, - style: theme.typography.h3.copyWith( + context.l10n.crunching_results, + style: TextStyle( + fontSize: 20, fontWeight: FontWeight.w900, color: theme.colorScheme.foreground - .withOpacity(0.5), + .withOpacity(0.7), ), ), + const SizedBox(height: 20), + const LinearProgressIndicator(), ], - ) - : isFetching - ? Container( - constraints: BoxConstraints( - maxWidth: mediaQuery.lgAndUp - ? mediaQuery.size.width * 0.5 - : mediaQuery.size.width, - ), - padding: const EdgeInsets.symmetric( - horizontal: 20, - ), + ), + ), + _ => InterScrollbar( + controller: scrollController, + child: SingleChildScrollView( + controller: scrollController, + child: const Padding( + padding: EdgeInsets.symmetric(vertical: 8), + child: SafeArea( child: Column( - mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: - CrossAxisAlignment.center, + CrossAxisAlignment.start, children: [ - Text( - context.l10n.crunching_results, - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.w900, - color: theme.colorScheme.foreground - .withOpacity(0.7), - ), - ), - const SizedBox(height: 20), - const LinearProgressIndicator(), + SearchTracksSection(), + SearchPlaylistsSection(), + Gap(20), + SearchArtistsSection(), + Gap(20), + SearchAlbumsSection(), ], ), - ) - : resultWidget, + ), + ), + ), + ), + }, ), ), ], From b558cc17f174705b5963193298db758bb7cbd4ec Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 28 Dec 2024 21:55:36 +0600 Subject: [PATCH 031/112] fix: SafeArea for global bottom items not working --- lib/pages/root/root_app.dart | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/lib/pages/root/root_app.dart b/lib/pages/root/root_app.dart index cdb56910..b8d4d166 100644 --- a/lib/pages/root/root_app.dart +++ b/lib/pages/root/root_app.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:collection/collection.dart'; import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:go_router/go_router.dart'; @@ -179,16 +180,37 @@ class RootApp extends HookConsumerWidget { return getSidebarTileList(context.l10n).map((s) => s.name).toList(); }, []); + final bottomPlayerKey = useMemoized(() => GlobalKey(), []); + final navigationBarKey = useMemoized(() => GlobalKey(), []); + + final bottomPadding = useMemoized(() { + return [bottomPlayerKey, navigationBarKey] + .map((k) => + (k.currentContext?.findRenderObject() as RenderBox?) + ?.size + .height ?? + 0) + .sum; + }, [bottomPlayerKey, navigationBarKey]); + final scaffold = MediaQuery.removeViewInsets( context: context, removeBottom: true, child: Scaffold( - footers: const [ - BottomPlayer(), - SpotubeNavigationBar(), + footers: [ + BottomPlayer(key: bottomPlayerKey), + SpotubeNavigationBar(key: navigationBarKey), ], floatingFooter: true, - child: Sidebar(child: child), + // Fix for safe are not working for bottom bar + child: MediaQuery( + data: MediaQuery.of(context).copyWith( + padding: MediaQuery.of(context).padding.copyWith( + bottom: bottomPadding, + ), + ), + child: Sidebar(child: child), + ), ), ); From 047eccfa82f96c1a967d67e4e6f80156ccc2eb0b Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 29 Dec 2024 13:36:44 +0600 Subject: [PATCH 032/112] fix: SafeArea not working for bottom floating widgets --- .../playbutton_view/playbutton_view.dart | 10 +- lib/modules/library/user_albums.dart | 2 + lib/modules/library/user_artists.dart | 2 + lib/modules/library/user_playlists.dart | 2 + lib/modules/lyrics/zoom_controls.dart | 40 +++--- lib/modules/player/player.dart | 6 - lib/pages/lyrics/lyrics.dart | 129 +++++++++--------- lib/pages/lyrics/plain_lyrics.dart | 18 +-- lib/pages/lyrics/synced_lyrics.dart | 77 +++++------ lib/pages/root/root_app.dart | 30 +--- pubspec.lock | 4 +- pubspec.yaml | 2 +- 12 files changed, 153 insertions(+), 169 deletions(-) diff --git a/lib/components/playbutton_view/playbutton_view.dart b/lib/components/playbutton_view/playbutton_view.dart index 7520f313..dd8dc371 100644 --- a/lib/components/playbutton_view/playbutton_view.dart +++ b/lib/components/playbutton_view/playbutton_view.dart @@ -51,6 +51,8 @@ class PlaybuttonView extends StatelessWidget { @override Widget build(BuildContext context) { + final scale = context.theme.scaling; + return SliverLayoutBuilder( builder: (context, constrains) => HookBuilder(builder: (context) { final isGrid = useState(constrains.mdAndUp); @@ -100,10 +102,10 @@ class PlaybuttonView extends StatelessWidget { (true, _) => SliverGrid.builder( itemCount: isLoading ? 6 : itemCount + 1, gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( - maxCrossAxisExtent: 150 * context.theme.scaling, - mainAxisExtent: 225 * context.theme.scaling, - crossAxisSpacing: 8, - mainAxisSpacing: 8, + maxCrossAxisExtent: 150 * scale, + mainAxisExtent: 225 * scale, + crossAxisSpacing: 12 * scale, + mainAxisSpacing: 12 * scale, ), itemBuilder: (context, index) { if (isLoading) { diff --git a/lib/modules/library/user_albums.dart b/lib/modules/library/user_albums.dart index b460f22e..a3f14fba 100644 --- a/lib/modules/library/user_albums.dart +++ b/lib/modules/library/user_albums.dart @@ -48,6 +48,7 @@ class UserAlbums extends HookConsumerWidget { } return SafeArea( + bottom: false, child: Scaffold( child: RefreshTrigger( // onRefresh: () async { @@ -89,6 +90,7 @@ class UserAlbums extends HookConsumerWidget { AlbumCard.tile(albums[index]), ), ), + const SliverSafeArea(sliver: SliverGap(10)), ], ), ), diff --git a/lib/modules/library/user_artists.dart b/lib/modules/library/user_artists.dart index eaf5afb3..576298ce 100644 --- a/lib/modules/library/user_artists.dart +++ b/lib/modules/library/user_artists.dart @@ -53,6 +53,7 @@ class UserArtists extends HookConsumerWidget { } return SafeArea( + bottom: false, child: Scaffold( child: RefreshTrigger( // onRefresh: () async { @@ -117,6 +118,7 @@ class UserArtists extends HookConsumerWidget { }, ); }), + const SliverSafeArea(sliver: SliverGap(10)), ], ), ), diff --git a/lib/modules/library/user_playlists.dart b/lib/modules/library/user_playlists.dart index 1b1bf110..58462bf9 100644 --- a/lib/modules/library/user_playlists.dart +++ b/lib/modules/library/user_playlists.dart @@ -82,6 +82,7 @@ class UserPlaylists extends HookConsumerWidget { // ref.invalidate(favoritePlaylistsProvider); // }, child: SafeArea( + bottom: false, child: InterScrollbar( controller: controller, child: CustomScrollView( @@ -139,6 +140,7 @@ class UserPlaylists extends HookConsumerWidget { }, ), ), + const SliverSafeArea(sliver: SliverGap(10)), ], ), ), diff --git a/lib/modules/lyrics/zoom_controls.dart b/lib/modules/lyrics/zoom_controls.dart index 73beb4ae..b4eeb9d6 100644 --- a/lib/modules/lyrics/zoom_controls.dart +++ b/lib/modules/lyrics/zoom_controls.dart @@ -1,5 +1,6 @@ -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/collections/spotube_icons.dart'; @@ -32,7 +33,7 @@ class ZoomControls extends HookWidget { @override Widget build(BuildContext context) { final actions = [ - IconButton( + IconButton.ghost( icon: decreaseIcon, onPressed: () { if (value == min) return; @@ -40,7 +41,7 @@ class ZoomControls extends HookWidget { }, ), Text("$value$unit"), - IconButton( + IconButton.ghost( icon: increaseIcon, onPressed: () { if (value == max) return; @@ -50,27 +51,28 @@ class ZoomControls extends HookWidget { ]; return Container( - decoration: BoxDecoration( - color: Theme.of(context).cardColor.withOpacity(0.7), - borderRadius: BorderRadius.circular(10), - ), constraints: BoxConstraints( maxHeight: direction == Axis.horizontal ? 50 : 200, maxWidth: direction == Axis.vertical ? 50 : double.infinity, ), margin: const EdgeInsets.all(8), - child: direction == Axis.horizontal - ? Row( - mainAxisAlignment: MainAxisAlignment.end, - mainAxisSize: MainAxisSize.min, - children: actions, - ) - : Column( - mainAxisAlignment: MainAxisAlignment.end, - mainAxisSize: MainAxisSize.min, - verticalDirection: VerticalDirection.up, - children: actions, - ), + child: SurfaceCard( + surfaceBlur: context.theme.surfaceBlur, + surfaceOpacity: context.theme.surfaceOpacity, + padding: EdgeInsets.zero, + child: direction == Axis.horizontal + ? Row( + mainAxisAlignment: MainAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: actions, + ) + : Column( + mainAxisAlignment: MainAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + verticalDirection: VerticalDirection.up, + children: actions, + ), + ), ); } } diff --git a/lib/modules/player/player.dart b/lib/modules/player/player.dart index 3f19fbf0..014e6aef 100644 --- a/lib/modules/player/player.dart +++ b/lib/modules/player/player.dart @@ -367,12 +367,6 @@ class PlayerView extends HookConsumerWidget { topRight: Radius.circular(20), ), ), - constraints: BoxConstraints( - maxHeight: MediaQuery.of(context) - .size - .height * - 0.8, - ), builder: (context) => const LyricsPage(isModal: true), ); diff --git a/lib/pages/lyrics/lyrics.dart b/lib/pages/lyrics/lyrics.dart index 17e552e6..679ef78e 100644 --- a/lib/pages/lyrics/lyrics.dart +++ b/lib/pages/lyrics/lyrics.dart @@ -1,13 +1,11 @@ -import 'dart:ui'; - import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/components/image/universal_image.dart'; -import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/hooks/utils/use_custom_status_bar_color.dart'; @@ -35,7 +33,6 @@ class LyricsPage extends HookConsumerWidget { [playlist.activeTrack?.album?.images], ); final palette = usePaletteColor(albumArt, ref); - final mediaQuery = MediaQuery.of(context); final route = ModalRoute.of(context); final selectedIndex = useState(0); @@ -47,17 +44,28 @@ class LyricsPage extends HookConsumerWidget { Widget tabbar = Padding( padding: const EdgeInsets.all(10), - child: Opacity( - opacity: 0.8, - child: Tabs( - index: selectedIndex.value, - onChanged: (index) => selectedIndex.value = index, - tabs: [ - Text(context.l10n.synced), - Text(context.l10n.plain), - ], - ), - ), + child: isModal + ? TabList( + index: selectedIndex.value, + children: [ + TabButton( + onPressed: () => selectedIndex.value = 0, + child: Text(context.l10n.synced), + ), + TabButton( + onPressed: () => selectedIndex.value = 1, + child: Text(context.l10n.plain), + ), + ], + ) + : Tabs( + index: selectedIndex.value, + onChanged: (index) => selectedIndex.value = index, + tabs: [ + Text(context.l10n.synced), + Text(context.l10n.plain), + ], + ), ); tabbar = Row( @@ -89,57 +97,53 @@ class LyricsPage extends HookConsumerWidget { canPop: true, onPopInvokedWithResult: (_, __) => resetStatusBar(), child: SafeArea( - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 15, sigmaY: 15), - child: Container( - clipBehavior: Clip.hardEdge, - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.background.withOpacity(.4), - borderRadius: const BorderRadius.only( - topLeft: Radius.circular(10), - topRight: Radius.circular(10), - ), - ), - child: Column( - children: [ - const SizedBox(height: 5), - Container( - height: 7, - width: 150, - decoration: BoxDecoration( - color: palette.titleTextColor, - borderRadius: BorderRadius.circular(10), - ), + bottom: false, + child: SurfaceCard( + surfaceBlur: context.theme.surfaceBlur, + surfaceOpacity: context.theme.surfaceOpacity, + padding: EdgeInsets.zero, + borderRadius: BorderRadius.zero, + borderWidth: 0, + child: Column( + children: [ + const SizedBox(height: 5), + Container( + height: 7, + width: 150, + decoration: BoxDecoration( + color: palette.titleTextColor, + borderRadius: BorderRadius.circular(10), ), - AppBar( - leading: [tabbar], - backgroundColor: Colors.transparent, - trailing: [ - IconButton.ghost( - icon: const Icon(SpotubeIcons.minimize), - onPressed: () => Navigator.of(context).pop(), - ), - const SizedBox(width: 5), + ), + Row( + children: [ + Expanded( + child: tabbar, + ), + IconButton.ghost( + icon: const Icon(SpotubeIcons.minimize), + onPressed: () => Navigator.of(context).pop(), + ), + const SizedBox(width: 5), + ], + ), + Expanded( + child: IndexedStack( + index: selectedIndex.value, + children: [ + SyncedLyrics(palette: palette, isModal: isModal), + PlainLyrics(palette: palette, isModal: isModal), ], ), - Expanded( - child: IndexedStack( - index: selectedIndex.value, - children: [ - SyncedLyrics(palette: palette, isModal: isModal), - PlainLyrics(palette: palette, isModal: isModal), - ], - ), - ), - ], - ), + ), + ], ), ), ), ); } return SafeArea( - bottom: mediaQuery.mdAndUp, + bottom: false, child: Scaffold( floatingHeader: true, headers: [ @@ -157,13 +161,14 @@ class LyricsPage extends HookConsumerWidget { image: UniversalImage.imageProvider(albumArt), fit: BoxFit.cover, ), - borderRadius: const BorderRadius.only( - bottomLeft: Radius.circular(10), - ), ), margin: const EdgeInsets.only(bottom: 10), - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5), + child: SurfaceCard( + surfaceBlur: context.theme.surfaceBlur, + surfaceOpacity: context.theme.surfaceOpacity, + padding: EdgeInsets.zero, + borderRadius: BorderRadius.zero, + borderWidth: 0, child: ColoredBox( color: palette.color.withOpacity(.7), child: SafeArea( diff --git a/lib/pages/lyrics/plain_lyrics.dart b/lib/pages/lyrics/plain_lyrics.dart index 7c571d5f..6246fd79 100644 --- a/lib/pages/lyrics/plain_lyrics.dart +++ b/lib/pages/lyrics/plain_lyrics.dart @@ -1,9 +1,8 @@ import 'package:collection/collection.dart'; -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:palette_generator/palette_generator.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/modules/lyrics/zoom_controls.dart'; import 'package:spotube/components/shimmers/shimmer_lyrics.dart'; @@ -30,7 +29,7 @@ class PlainLyrics extends HookConsumerWidget { final playlist = ref.watch(audioPlayerProvider); final lyricsQuery = ref.watch(syncedLyricsProvider(playlist.activeTrack)); final mediaQuery = MediaQuery.of(context); - final textTheme = Theme.of(context).textTheme; + final typography = Theme.of(context).typography; final textZoomLevel = useState(defaultTextZoom); @@ -44,9 +43,8 @@ class PlainLyrics extends HookConsumerWidget { child: Text( playlist.activeTrack?.name ?? "", style: mediaQuery.mdAndUp - ? textTheme.displaySmall - : textTheme.headlineMedium?.copyWith( - fontSize: 25, + ? typography.h3 + : typography.h4.copyWith( color: palette.titleTextColor, ), ), @@ -54,10 +52,8 @@ class PlainLyrics extends HookConsumerWidget { Center( child: Text( playlist.activeTrack?.artists?.asString() ?? "", - style: (mediaQuery.mdAndUp - ? textTheme.headlineSmall - : textTheme.titleLarge) - ?.copyWith(color: palette.bodyTextColor), + style: (mediaQuery.mdAndUp ? typography.h4 : typography.large) + .copyWith(color: palette.bodyTextColor), ), ) ], @@ -79,7 +75,7 @@ class PlainLyrics extends HookConsumerWidget { children: [ Text( context.l10n.no_lyrics_available, - style: textTheme.bodyLarge?.copyWith( + style: typography.large.copyWith( color: palette.bodyTextColor, ), textAlign: TextAlign.center, diff --git a/lib/pages/lyrics/synced_lyrics.dart b/lib/pages/lyrics/synced_lyrics.dart index 59bd863a..1367fa5a 100644 --- a/lib/pages/lyrics/synced_lyrics.dart +++ b/lib/pages/lyrics/synced_lyrics.dart @@ -1,10 +1,9 @@ import 'dart:async'; -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:palette_generator/palette_generator.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/modules/lyrics/zoom_controls.dart'; import 'package:spotube/components/shimmers/shimmer_lyrics.dart'; @@ -37,7 +36,7 @@ class SyncedLyrics extends HookConsumerWidget { Widget build(BuildContext context, ref) { final playlist = ref.watch(audioPlayerProvider); - final mediaQuery = MediaQuery.of(context); + final mediaQuery = MediaQuery.sizeOf(context); final controller = useAutoScrollController(); final delay = ref.watch(syncedLyricsDelayProvider); @@ -54,7 +53,7 @@ class SyncedLyrics extends HookConsumerWidget { useSyncedLyrics(ref, lyricsState.asData?.value.lyricsMap ?? {}, delay); final textZoomLevel = useState(defaultTextZoom); - final textTheme = Theme.of(context).textTheme; + final typography = Theme.of(context).typography; ref.listen( audioPlayerProvider.select((s) => s.activeTrack), @@ -69,11 +68,11 @@ class SyncedLyrics extends HookConsumerWidget { ); final headlineTextStyle = (mediaQuery.mdAndUp - ? textTheme.displaySmall - : textTheme.headlineMedium?.copyWith(fontSize: 25)) - ?.copyWith(color: palette.titleTextColor); + ? typography.h3 + : typography.h4.copyWith(fontSize: 25)) + .copyWith(color: palette.titleTextColor); - final bodyTextTheme = textTheme.bodyLarge?.copyWith( + final bodyTextTheme = typography.large.copyWith( color: palette.bodyTextColor, ); @@ -115,9 +114,8 @@ class SyncedLyrics extends HookConsumerWidget { preferredSize: const Size.fromHeight(40), child: Text( playlist.activeTrack?.artists?.asString() ?? "", - style: mediaQuery.mdAndUp - ? textTheme.headlineSmall - : textTheme.titleLarge, + style: + mediaQuery.mdAndUp ? typography.h4 : typography.x2Large, ), ), ), @@ -144,7 +142,7 @@ class SyncedLyrics extends HookConsumerWidget { ? Container( padding: index == lyricValue.lyrics.length - 1 ? EdgeInsets.only( - bottom: mediaQuery.size.height / 2, + bottom: mediaQuery.height / 2, ) : null, ) @@ -165,31 +163,34 @@ class SyncedLyrics extends HookConsumerWidget { (textZoomLevel.value / 100), ), textAlign: TextAlign.center, - child: InkWell( - onTap: () async { - final time = Duration( - seconds: - lyricSlice.time.inSeconds - delay, - ); - if (time > audioPlayer.duration || - time.isNegative) { - return; - } - audioPlayer.seek(time); - }, - child: Builder(builder: (context) { - return StrokeText( - text: lyricSlice.text, - textStyle: - DefaultTextStyle.of(context).style, - textColor: isActive - ? Colors.white - : palette.bodyTextColor, - strokeColor: isActive - ? Colors.black - : Colors.transparent, - ); - }), + child: MouseRegion( + cursor: SystemMouseCursors.click, + child: GestureDetector( + onTap: () async { + final time = Duration( + seconds: + lyricSlice.time.inSeconds - delay, + ); + if (time > audioPlayer.duration || + time.isNegative) { + return; + } + audioPlayer.seek(time); + }, + child: Builder(builder: (context) { + return StrokeText( + text: lyricSlice.text, + textStyle: + DefaultTextStyle.of(context).style, + textColor: isActive + ? Colors.white + : palette.bodyTextColor, + strokeColor: isActive + ? Colors.black + : Colors.transparent, + ); + }), + ), ), ), ), @@ -231,7 +232,7 @@ class SyncedLyrics extends HookConsumerWidget { ), TextSpan( text: " Plain Lyrics ", - style: textTheme.bodyLarge?.copyWith( + style: typography.large.copyWith( color: palette.bodyTextColor, fontWeight: FontWeight.bold, ), diff --git a/lib/pages/root/root_app.dart b/lib/pages/root/root_app.dart index b8d4d166..cdb56910 100644 --- a/lib/pages/root/root_app.dart +++ b/lib/pages/root/root_app.dart @@ -1,6 +1,5 @@ import 'dart:async'; -import 'package:collection/collection.dart'; import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:go_router/go_router.dart'; @@ -180,37 +179,16 @@ class RootApp extends HookConsumerWidget { return getSidebarTileList(context.l10n).map((s) => s.name).toList(); }, []); - final bottomPlayerKey = useMemoized(() => GlobalKey(), []); - final navigationBarKey = useMemoized(() => GlobalKey(), []); - - final bottomPadding = useMemoized(() { - return [bottomPlayerKey, navigationBarKey] - .map((k) => - (k.currentContext?.findRenderObject() as RenderBox?) - ?.size - .height ?? - 0) - .sum; - }, [bottomPlayerKey, navigationBarKey]); - final scaffold = MediaQuery.removeViewInsets( context: context, removeBottom: true, child: Scaffold( - footers: [ - BottomPlayer(key: bottomPlayerKey), - SpotubeNavigationBar(key: navigationBarKey), + footers: const [ + BottomPlayer(), + SpotubeNavigationBar(), ], floatingFooter: true, - // Fix for safe are not working for bottom bar - child: MediaQuery( - data: MediaQuery.of(context).copyWith( - padding: MediaQuery.of(context).padding.copyWith( - bottom: bottomPadding, - ), - ), - child: Sidebar(child: child), - ), + child: Sidebar(child: child), ), ); diff --git a/pubspec.lock b/pubspec.lock index 34306fef..d441371d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1955,8 +1955,8 @@ packages: dependency: "direct main" description: path: "." - ref: "5359958464a57235f0f34c43a4623356a32459a0" - resolved-ref: "5359958464a57235f0f34c43a4623356a32459a0" + ref: fix-scaffold-footer-safearea + resolved-ref: "8ede34e1e3270ec3839192a7a6453e19cd00f9ab" url: "https://github.com/KRTirtho/shadcn_flutter.git" source: git version: "0.0.24" diff --git a/pubspec.yaml b/pubspec.yaml index 198bc949..f00c298f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -103,7 +103,7 @@ dependencies: shadcn_flutter: git: url: https://github.com/KRTirtho/shadcn_flutter.git - ref: 5359958464a57235f0f34c43a4623356a32459a0 + ref: fix-scaffold-footer-safearea shared_preferences: ^2.2.3 shelf: ^1.4.1 shelf_router: ^1.1.4 From 684e595d1687ec422695d6cd29737ab726ab8f03 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 29 Dec 2024 15:07:48 +0600 Subject: [PATCH 033/112] refactor: use shadcn widgets for create playlist and add tracks to playlist dialog --- .../dialogs/playlist_add_track_dialog.dart | 134 +++--- lib/components/form/checkbox_form_field.dart | 45 ++ lib/components/form/text_form_field.dart | 187 ++++++++ .../track_presentation.dart | 2 +- .../playlist/playlist_create_dialog.dart | 442 +++++++++--------- pubspec.lock | 18 +- pubspec.yaml | 2 + 7 files changed, 542 insertions(+), 288 deletions(-) create mode 100644 lib/components/form/checkbox_form_field.dart create mode 100644 lib/components/form/text_form_field.dart diff --git a/lib/components/dialogs/playlist_add_track_dialog.dart b/lib/components/dialogs/playlist_add_track_dialog.dart index 5af9c9e4..5098bf9d 100644 --- a/lib/components/dialogs/playlist_add_track_dialog.dart +++ b/lib/components/dialogs/playlist_add_track_dialog.dart @@ -1,7 +1,6 @@ -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/modules/playlist/playlist_create_dialog.dart'; @@ -22,7 +21,7 @@ class PlaylistAddTrackDialog extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final ThemeData(:textTheme) = Theme.of(context); + final typography = Theme.of(context).typography; final userPlaylists = ref.watch(favoritePlaylistsProvider); final favoritePlaylistsNotifier = ref.watch(favoritePlaylistsProvider.notifier); @@ -64,67 +63,86 @@ class PlaylistAddTrackDialog extends HookConsumerWidget { tracks.map((e) => e.id!).toList(), ), ), - ).then((_) => Navigator.pop(context, true)); + ).then((_) => context.mounted ? Navigator.pop(context, true) : null); } - return AlertDialog( - insetPadding: EdgeInsets.zero, - title: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - context.l10n.add_to_playlist, - style: textTheme.titleMedium, + return ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 400), + child: AlertDialog( + title: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + context.l10n.add_to_playlist, + style: typography.large, + ), + const Spacer(), + const PlaylistCreateDialogButton(), + ], + ), + actions: [ + OutlineButton( + child: Text(context.l10n.cancel), + onPressed: () { + Navigator.pop(context, false); + }, + ), + PrimaryButton( + onPressed: onAdd, + child: Text(context.l10n.add), ), - const Gap(20), - const PlaylistCreateDialogButton(), ], - ), - actions: [ - OutlinedButton( - child: Text(context.l10n.cancel), - onPressed: () { - Navigator.pop(context, false); - }, - ), - FilledButton( - onPressed: onAdd, - child: Text(context.l10n.add), - ), - ], - content: SizedBox( - height: 300, - width: 300, - child: userPlaylists.isLoading - ? const Center(child: CircularProgressIndicator()) - : ListView.builder( - shrinkWrap: true, - itemCount: filteredPlaylists.length, - itemBuilder: (context, index) { - final playlist = filteredPlaylists.elementAt(index); - return CheckboxListTile( - secondary: CircleAvatar( - backgroundImage: UniversalImage.imageProvider( - playlist.images.asUrlString( - placeholder: ImagePlaceholder.collection, + content: SizedBox( + height: 300, + child: userPlaylists.isLoading + ? const Center(child: CircularProgressIndicator()) + : ListView.builder( + shrinkWrap: true, + itemCount: filteredPlaylists.length, + itemBuilder: (context, index) { + final playlist = filteredPlaylists.elementAt(index); + return Button.ghost( + style: ButtonVariance.ghost.copyWith( + padding: (context, _, __) { + return const EdgeInsets.symmetric(vertical: 8); + }, + ), + leading: Avatar( + initials: + Avatar.getInitials(playlist.name ?? "Playlist"), + provider: UniversalImage.imageProvider( + playlist.images.asUrlString( + placeholder: ImagePlaceholder.collection, + ), ), ), - ), - contentPadding: EdgeInsets.zero, - title: Padding( - padding: const EdgeInsets.only(left: 8.0), - child: Text(playlist.name!), - ), - value: playlistsCheck.value[playlist.id] ?? false, - onChanged: (val) { - playlistsCheck.value = { - ...playlistsCheck.value, - playlist.id!: val == true - }; - }, - ); - }, - ), + trailing: Checkbox( + state: (playlistsCheck.value[playlist.id] ?? false) + ? CheckboxState.checked + : CheckboxState.unchecked, + onChanged: (val) { + playlistsCheck.value = { + ...playlistsCheck.value, + playlist.id!: val == CheckboxState.checked, + }; + }, + ), + onPressed: () { + playlistsCheck.value = { + ...playlistsCheck.value, + playlist.id!: + !(playlistsCheck.value[playlist.id] ?? false), + }; + }, + child: Padding( + padding: const EdgeInsets.only(left: 8.0), + child: Text(playlist.name!), + ), + ); + }, + ), + ), ), ); } diff --git a/lib/components/form/checkbox_form_field.dart b/lib/components/form/checkbox_form_field.dart new file mode 100644 index 00000000..0e794833 --- /dev/null +++ b/lib/components/form/checkbox_form_field.dart @@ -0,0 +1,45 @@ +import 'package:flutter_form_builder/flutter_form_builder.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; + +class CheckboxFormBuilderField extends StatelessWidget { + final String name; + final FormFieldValidator? validator; + + final ValueChanged? onChanged; + final Widget? leading; + final Widget? trailing; + final bool tristate; + const CheckboxFormBuilderField({ + super.key, + required this.name, + this.validator, + this.onChanged, + this.leading, + this.trailing, + this.tristate = false, + }); + + @override + Widget build(BuildContext context) { + return FormBuilderField( + name: name, + validator: validator, + builder: (field) { + return Checkbox( + state: tristate && field.value == null + ? CheckboxState.indeterminate + : field.value == true + ? CheckboxState.checked + : CheckboxState.unchecked, + onChanged: (state) { + field.didChange(state == CheckboxState.checked); + onChanged?.call(state); + }, + leading: leading, + trailing: trailing, + tristate: tristate, + ); + }, + ); + } +} diff --git a/lib/components/form/text_form_field.dart b/lib/components/form/text_form_field.dart new file mode 100644 index 00000000..ef3514c5 --- /dev/null +++ b/lib/components/form/text_form_field.dart @@ -0,0 +1,187 @@ +import 'package:flutter/services.dart'; +import 'package:flutter_form_builder/flutter_form_builder.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; + +class TextFormBuilderField extends StatelessWidget { + final String name; + final FormFieldValidator? validator; + final Widget? label; + + final TextEditingController? controller; + final bool filled; + final Widget? placeholder; + final AlignmentGeometry? placeholderAlignment; + final AlignmentGeometry? leadingAlignment; + final AlignmentGeometry? trailingAlignment; + final bool border; + final Widget? leading; + final Widget? trailing; + final EdgeInsetsGeometry? padding; + final ValueChanged? onSubmitted; + final VoidCallback? onEditingComplete; + final FocusNode? focusNode; + final VoidCallback? onTap; + final bool enabled; + final bool readOnly; + final bool obscureText; + final String obscuringCharacter; + final String? initialValue; + final int? maxLength; + final MaxLengthEnforcement? maxLengthEnforcement; + final int? maxLines; + final int? minLines; + final BorderRadiusGeometry? borderRadius; + final TextAlign textAlign; + final bool expands; + final TextAlignVertical? textAlignVertical; + final UndoHistoryController? undoController; + final ValueChanged? onChanged; + final Iterable? autofillHints; + final void Function(PointerDownEvent event)? onTapOutside; + final List? inputFormatters; + final TextStyle? style; + final EditableTextContextMenuBuilder? contextMenuBuilder; + final bool useNativeContextMenu; + final bool? isCollapsed; + final TextInputType? keyboardType; + final TextInputAction? textInputAction; + final Clip clipBehavior; + final bool autofocus; + final WidgetStatesController? statesController; + + const TextFormBuilderField({ + super.key, + required this.name, + this.label, + this.validator, + this.controller, + this.maxLength, + this.maxLengthEnforcement, + this.maxLines = 1, + this.minLines, + this.filled = false, + this.placeholder, + this.border = true, + this.leading, + this.trailing, + this.padding, + this.onSubmitted, + this.onEditingComplete, + this.focusNode, + this.onTap, + this.enabled = true, + this.readOnly = false, + this.obscureText = false, + this.obscuringCharacter = '•', + this.initialValue, + this.borderRadius, + this.keyboardType, + this.textAlign = TextAlign.start, + this.expands = false, + this.textAlignVertical = TextAlignVertical.center, + this.autofillHints, + this.undoController, + this.onChanged, + this.onTapOutside, + this.inputFormatters, + this.style, + this.contextMenuBuilder = TextField.defaultContextMenuBuilder, + this.useNativeContextMenu = false, + this.isCollapsed, + this.textInputAction, + this.clipBehavior = Clip.hardEdge, + this.autofocus = false, + this.placeholderAlignment, + this.leadingAlignment, + this.trailingAlignment, + this.statesController, + }); + + @override + Widget build(BuildContext context) { + return FormBuilderField( + name: name, + validator: validator, + onChanged: (value) { + if (value == null) return; + onChanged?.call(value); + }, + builder: (field) => Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + spacing: 5, + children: [ + if (label != null) + DefaultTextStyle( + style: context.theme.typography.semiBold.copyWith( + color: field.hasError + ? context.theme.colorScheme.destructive + : context.theme.colorScheme.foreground, + ), + child: label!, + ), + TextField( + controller: controller, + maxLength: maxLength, + maxLengthEnforcement: maxLengthEnforcement, + maxLines: maxLines, + minLines: minLines, + filled: filled, + placeholder: placeholder, + border: border, + leading: leading, + trailing: trailing, + padding: padding, + onSubmitted: (value) { + field.validate(); + field.save(); + onSubmitted?.call(value); + }, + onEditingComplete: () { + field.save(); + onEditingComplete?.call(); + }, + focusNode: focusNode, + onTap: onTap, + enabled: enabled, + readOnly: readOnly, + obscureText: obscureText, + obscuringCharacter: obscuringCharacter, + initialValue: field.value, + borderRadius: borderRadius, + textAlign: textAlign, + expands: expands, + textAlignVertical: textAlignVertical, + autofillHints: autofillHints, + undoController: undoController, + onChanged: (value) { + field.didChange(value); + }, + onTapOutside: onTapOutside, + inputFormatters: inputFormatters, + style: style, + contextMenuBuilder: contextMenuBuilder, + useNativeContextMenu: useNativeContextMenu, + isCollapsed: isCollapsed, + keyboardType: keyboardType, + textInputAction: textInputAction, + clipBehavior: clipBehavior, + autofocus: autofocus, + placeholderAlignment: placeholderAlignment, + leadingAlignment: leadingAlignment, + trailingAlignment: trailingAlignment, + statesController: statesController, + ), + if (field.hasError) + Text( + field.errorText ?? "", + style: TextStyle( + color: context.theme.colorScheme.destructive, + ), + ), + ], + ), + ); + } +} diff --git a/lib/components/track_presentation/track_presentation.dart b/lib/components/track_presentation/track_presentation.dart index e81a2e1e..96f5f964 100644 --- a/lib/components/track_presentation/track_presentation.dart +++ b/lib/components/track_presentation/track_presentation.dart @@ -90,7 +90,7 @@ class TrackPresentation extends HookConsumerWidget { }, ), const PresentationListSection(), - const SliverGap(200), + const SliverSafeArea(sliver: SliverGap(10)), ], ), ), diff --git a/lib/modules/playlist/playlist_create_dialog.dart b/lib/modules/playlist/playlist_create_dialog.dart index 78680a1c..8b231b84 100644 --- a/lib/modules/playlist/playlist_create_dialog.dart +++ b/lib/modules/playlist/playlist_create_dialog.dart @@ -2,20 +2,23 @@ import 'dart:convert'; import 'dart:io'; import 'package:collection/collection.dart'; -import 'package:flutter/material.dart'; +import 'package:flutter_form_builder/flutter_form_builder.dart'; +import 'package:form_builder_validators/form_builder_validators.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:form_validator/form_validator.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:image_picker/image_picker.dart'; +import 'package:path/path.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/form/checkbox_form_field.dart'; +import 'package:spotube/components/form/text_form_field.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; -import 'package:spotube/extensions/string.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:spotube/provider/spotify_provider.dart'; @@ -23,241 +26,227 @@ class PlaylistCreateDialog extends HookConsumerWidget { /// Track ids to add to the playlist final List trackIds; final String? playlistId; - PlaylistCreateDialog({ + const PlaylistCreateDialog({ super.key, this.trackIds = const [], this.playlistId, }); - final formKey = GlobalKey(); - @override Widget build(BuildContext context, ref) { - return ScaffoldMessenger( - child: Scaffold( - backgroundColor: Colors.transparent, - body: HookBuilder(builder: (context) { - final userPlaylists = ref.watch(favoritePlaylistsProvider); - final playlist = ref.watch(playlistProvider(playlistId ?? "")); - final playlistNotifier = - ref.watch(playlistProvider(playlistId ?? "").notifier); + final userPlaylists = ref.watch(favoritePlaylistsProvider); + final playlist = ref.watch(playlistProvider(playlistId ?? "")); + final playlistNotifier = + ref.watch(playlistProvider(playlistId ?? "").notifier); - final updatingPlaylist = useMemoized( - () => userPlaylists.asData?.value.items - .firstWhereOrNull((playlist) => playlist.id == playlistId), - [ - userPlaylists.asData?.value.items, - playlistId, - ], - ); + final isSubmitting = useState(false); - final playlistName = useTextEditingController( - text: updatingPlaylist?.name, - ); - final description = useTextEditingController( - text: updatingPlaylist?.description?.unescapeHtml(), - ); - final public = useState( - updatingPlaylist?.public ?? false, - ); - final collaborative = useState( - updatingPlaylist?.collaborative ?? false, - ); - final image = useState(null); + final formKey = useMemoized(() => GlobalKey(), []); - final isUpdatingPlaylist = playlistId != null; + final updatingPlaylist = useMemoized( + () => userPlaylists.asData?.value.items + .firstWhereOrNull((playlist) => playlist.id == playlistId), + [ + userPlaylists.asData?.value.items, + playlistId, + ], + ); - final l10n = context.l10n; - final theme = Theme.of(context); - final scaffold = ScaffoldMessenger.of(context); + final isUpdatingPlaylist = playlistId != null; - final onError = useCallback((error) { - if (error is SpotifyError || error is SpotifyException) { - scaffold.showSnackBar( - SnackBar( - content: Text( - l10n.error(error.message ?? context.l10n.epic_failure), - style: theme.textTheme.bodyMedium!.copyWith( - color: theme.colorScheme.onError, - ), + final l10n = context.l10n; + final theme = Theme.of(context); + + final onError = useCallback((error) { + if (error is SpotifyError || error is SpotifyException) { + showToast( + context: context, + location: ToastLocation.topRight, + builder: (context, overlay) { + return SurfaceCard( + child: Basic( + title: Text( + l10n.error(error.message ?? l10n.epic_failure), + style: theme.typography.normal.copyWith( + color: theme.colorScheme.destructive, ), - backgroundColor: theme.colorScheme.error, ), - ); - } - }, [scaffold, l10n, theme]); - - Future onCreate() async { - if (!formKey.currentState!.validate()) return; - - final PlaylistInput payload = ( - playlistName: playlistName.text, - collaborative: collaborative.value, - public: public.value, - description: description.text, - base64Image: image.value?.path != null - ? await image.value! - .readAsBytes() - .then((bytes) => base64Encode(bytes)) - : null, + ), ); + }, + ); + } + }, [l10n, theme]); - if (isUpdatingPlaylist) { - await playlistNotifier.modify(payload, onError); - } else { - await playlistNotifier.create(payload, onError); - } + Future onCreate() async { + if (!formKey.currentState!.saveAndValidate()) return; - if (context.mounted && - !ref.read(playlistProvider(playlistId ?? "")).hasError) { - context.pop(); - } - } + try { + isSubmitting.value = true; + final values = formKey.currentState!.value; - return AlertDialog( - title: Text( - isUpdatingPlaylist - ? context.l10n.update_playlist - : context.l10n.create_a_playlist, - ), - actions: [ - OutlinedButton( - child: Text(context.l10n.cancel), - onPressed: () { - Navigator.pop(context); + final PlaylistInput payload = ( + playlistName: values['playlistName'], + collaborative: values['collaborative'], + public: values['public'], + description: values['description'], + base64Image: (values['image'] as XFile?)?.path != null + ? await (values['image'] as XFile) + .readAsBytes() + .then((bytes) => base64Encode(bytes)) + : null, + ); + + if (isUpdatingPlaylist) { + await playlistNotifier.modify(payload, onError); + } else { + await playlistNotifier.create(payload, onError); + } + } finally { + isSubmitting.value = false; + if (context.mounted && + !ref.read(playlistProvider(playlistId ?? "")).hasError) { + context.pop(); + } + } + } + + return AlertDialog( + title: Text( + isUpdatingPlaylist + ? context.l10n.update_playlist + : context.l10n.create_a_playlist, + ), + actions: [ + Button.outline( + child: Text(context.l10n.cancel), + onPressed: () { + Navigator.pop(context); + }, + ), + Button.primary( + onPressed: onCreate, + enabled: !playlist.isLoading & !isSubmitting.value, + child: Text( + isUpdatingPlaylist ? context.l10n.update : context.l10n.create, + ), + ), + ], + content: Container( + width: MediaQuery.of(context).size.width, + constraints: const BoxConstraints(maxWidth: 500), + child: FormBuilder( + key: formKey, + initialValue: { + 'playlistName': updatingPlaylist?.name, + 'description': updatingPlaylist?.description, + 'public': updatingPlaylist?.public ?? false, + 'collaborative': updatingPlaylist?.collaborative ?? false, + }, + child: ListView( + shrinkWrap: true, + children: [ + FormBuilderField( + name: 'image', + validator: (value) { + if (value == null) return null; + final file = File(value.path); + + if (file.lengthSync() > 256000) { + return "Image size should be less than 256kb"; + } + + if (extension(file.path) != ".png") { + return "Image should be in PNG format"; + } + return null; + }, + builder: (field) { + return Column( + spacing: 10, + children: [ + UniversalImage( + path: field.value?.path ?? + (updatingPlaylist?.images).asUrlString( + placeholder: ImagePlaceholder.collection, + ), + height: 200, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Button.secondary( + leading: const Icon(SpotubeIcons.edit), + child: Text( + field.value?.path != null || + updatingPlaylist?.images != null + ? context.l10n.change_cover + : context.l10n.add_cover, + ), + onPressed: () async { + final imageFile = await ImagePicker().pickImage( + source: ImageSource.gallery, + ); + + if (imageFile != null) { + field.didChange(imageFile); + field.validate(); + field.save(); + } + }, + ), + const SizedBox(width: 10), + IconButton.destructive( + icon: const Icon(SpotubeIcons.trash), + enabled: field.value != null, + onPressed: () { + field.didChange(null); + field.validate(); + field.save(); + }, + ), + ], + ), + if (field.hasError) + Text( + field.errorText ?? "", + style: theme.typography.normal.copyWith( + color: theme.colorScheme.destructive, + ), + ) + ], + ); }, ), - FilledButton( - onPressed: playlist.isLoading ? null : onCreate, - child: Text( - isUpdatingPlaylist - ? context.l10n.update - : context.l10n.create, - ), + const Gap(20), + TextFormBuilderField( + name: 'playlistName', + label: Text(context.l10n.playlist_name), + placeholder: Text(context.l10n.name_of_playlist), + validator: FormBuilderValidators.required(), + ), + const Gap(20), + TextFormBuilderField( + name: 'description', + label: Text(context.l10n.description), + validator: FormBuilderValidators.required(), + placeholder: Text(context.l10n.description), + keyboardType: TextInputType.multiline, + maxLines: 5, + ), + const Gap(20), + CheckboxFormBuilderField( + name: 'public', + trailing: Text(context.l10n.public), + ), + const Gap(10), + CheckboxFormBuilderField( + name: 'collaborative', + trailing: Text(context.l10n.collaborative), ), ], - insetPadding: const EdgeInsets.all(8), - content: Container( - width: MediaQuery.of(context).size.width, - constraints: const BoxConstraints(maxWidth: 500), - child: Form( - key: formKey, - child: ListView( - shrinkWrap: true, - children: [ - FormField( - initialValue: image.value, - onSaved: (newValue) { - image.value = newValue; - }, - validator: (value) { - if (value == null) return null; - final file = File(value.path); - - if (file.lengthSync() > 256000) { - return "Image size should be less than 256kb"; - } - return null; - }, - builder: (field) { - return Column( - children: [ - UniversalImage( - path: field.value?.path ?? - (updatingPlaylist?.images).asUrlString( - placeholder: ImagePlaceholder.collection, - ), - height: 200, - ), - const SizedBox(height: 10), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - FilledButton.icon( - icon: const Icon(SpotubeIcons.edit), - label: Text( - field.value?.path != null || - updatingPlaylist?.images != null - ? context.l10n.change_cover - : context.l10n.add_cover, - ), - onPressed: () async { - final imageFile = await ImagePicker() - .pickImage( - source: ImageSource.gallery); - - if (imageFile != null) { - field.didChange(imageFile); - field.validate(); - field.save(); - } - }, - ), - const SizedBox(width: 10), - IconButton.filled( - icon: const Icon(SpotubeIcons.trash), - style: IconButton.styleFrom( - backgroundColor: - theme.colorScheme.errorContainer, - foregroundColor: theme.colorScheme.error, - ), - onPressed: field.value == null - ? null - : () { - field.didChange(null); - field.validate(); - field.save(); - }, - ), - ], - ), - if (field.hasError) - Text( - field.errorText ?? "", - style: theme.textTheme.bodyMedium!.copyWith( - color: theme.colorScheme.error, - ), - ) - ], - ); - }), - const SizedBox(height: 10), - TextFormField( - controller: playlistName, - decoration: InputDecoration( - hintText: context.l10n.name_of_playlist, - labelText: context.l10n.name_of_playlist, - ), - validator: ValidationBuilder().required().build(), - ), - const SizedBox(height: 10), - TextFormField( - controller: description, - decoration: InputDecoration( - hintText: context.l10n.description, - ), - keyboardType: TextInputType.multiline, - validator: ValidationBuilder().required().build(), - maxLines: 5, - ), - const SizedBox(height: 10), - CheckboxListTile( - title: Text(context.l10n.public), - value: public.value, - onChanged: (val) => public.value = val ?? false, - ), - const SizedBox(height: 10), - CheckboxListTile( - title: Text(context.l10n.collaborative), - value: collaborative.value, - onChanged: (val) => collaborative.value = val ?? false, - ), - ], - ), - ), - ), - ); - }), + ), + ), ), ); } @@ -269,7 +258,10 @@ class PlaylistCreateDialogButton extends HookConsumerWidget { showPlaylistDialog(BuildContext context, SpotifyApi spotify) { showDialog( context: context, - builder: (context) => PlaylistCreateDialog(), + alignment: Alignment.center, + builder: (context) => const ToastLayer( + child: PlaylistCreateDialog(), + ), ); } @@ -279,21 +271,15 @@ class PlaylistCreateDialogButton extends HookConsumerWidget { final spotify = ref.watch(spotifyProvider); if (mediaQuery.smAndDown) { - return ElevatedButton( - style: FilledButton.styleFrom( - foregroundColor: Theme.of(context).colorScheme.primary, - ), - child: const Icon(SpotubeIcons.addFilled), + return IconButton.secondary( + icon: const Icon(SpotubeIcons.addFilled), onPressed: () => showPlaylistDialog(context, spotify), ); } - return FilledButton.tonalIcon( - style: FilledButton.styleFrom( - foregroundColor: Theme.of(context).colorScheme.primary, - ), - icon: const Icon(SpotubeIcons.addFilled), - label: Text(context.l10n.create_playlist), + return Button.secondary( + leading: const Icon(SpotubeIcons.addFilled), + child: Text(context.l10n.create_playlist), onPressed: () => showPlaylistDialog(context, spotify), ); } diff --git a/pubspec.lock b/pubspec.lock index d441371d..8c8c30be 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -757,6 +757,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.0+1" + flutter_form_builder: + dependency: "direct main" + description: + name: flutter_form_builder + sha256: "39aee5a2548df0b3979a83eea38468116a888341fbca8a92c4be18a486a7bb57" + url: "https://pub.dev" + source: hosted + version: "9.6.0" flutter_gen_core: dependency: transitive description: @@ -972,6 +980,14 @@ packages: description: flutter source: sdk version: "0.0.0" + form_builder_validators: + dependency: "direct main" + description: + name: form_builder_validators + sha256: "517fb884183fff7a0ef3db7d375981011da26ee452f20fb3d2e788ad527ad01d" + url: "https://pub.dev" + source: hosted + version: "11.1.1" form_validator: dependency: "direct main" description: @@ -2670,5 +2686,5 @@ packages: source: hosted version: "2.3.6" sdks: - dart: ">=3.5.3 <4.0.0" + dart: ">=3.6.0 <4.0.0" flutter: ">=3.27.0" diff --git a/pubspec.yaml b/pubspec.yaml index f00c298f..e06cf96c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -54,6 +54,7 @@ dependencies: flutter_discord_rpc: ^1.0.0 flutter_displaymode: ^0.6.0 flutter_feather_icons: ^2.0.0+1 + flutter_form_builder: ^9.6.0 flutter_hooks: ^0.20.5 flutter_inappwebview: ^6.1.3 flutter_localizations: @@ -62,6 +63,7 @@ dependencies: flutter_riverpod: ^2.5.1 flutter_secure_storage: ^9.0.0 flutter_sharing_intent: ^1.1.0 + form_builder_validators: ^11.1.1 form_validator: ^2.1.1 freezed_annotation: ^2.4.1 fuzzywuzzy: ^1.1.6 From f96b5eae974432be782c0f6be3b5fa87f69a1416 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 3 Jan 2025 21:11:36 +0600 Subject: [PATCH 034/112] refactor: floating player to use shadcn --- .../dialogs/track_details_dialog.dart | 83 +-- lib/components/panels/controller.dart | 146 ---- lib/components/panels/helpers.dart | 95 --- lib/components/panels/sliding_up_panel.dart | 685 ------------------ .../track_presentation.dart | 1 + lib/main.dart | 2 +- lib/modules/player/player.dart | 546 ++++++-------- lib/modules/player/player_overlay.dart | 187 +---- .../player/player_overlay_collapsed.dart | 118 +++ lib/modules/root/spotube_navigation_bar.dart | 42 +- lib/pages/lyrics/plain_lyrics.dart | 9 +- lib/pages/lyrics/synced_lyrics.dart | 20 +- pubspec.lock | 8 + pubspec.yaml | 1 + 14 files changed, 457 insertions(+), 1486 deletions(-) delete mode 100644 lib/components/panels/controller.dart delete mode 100644 lib/components/panels/helpers.dart delete mode 100644 lib/components/panels/sliding_up_panel.dart create mode 100644 lib/modules/player/player_overlay_collapsed.dart diff --git a/lib/components/dialogs/track_details_dialog.dart b/lib/components/dialogs/track_details_dialog.dart index 61bca7b1..1296ae0e 100644 --- a/lib/components/dialogs/track_details_dialog.dart +++ b/lib/components/dialogs/track_details_dialog.dart @@ -1,5 +1,5 @@ -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/links/artist_link.dart'; @@ -73,17 +73,15 @@ class TrackDetailsDialog extends HookWidget { }; return AlertDialog( - contentPadding: const EdgeInsets.all(16), - insetPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 100), - scrollable: true, + surfaceBlur: 0, + surfaceOpacity: 1, title: Row( - mainAxisAlignment: MainAxisAlignment.center, + spacing: 8, children: [ const Icon(SpotubeIcons.info), - const SizedBox(width: 8), Text( context.l10n.details, - style: theme.textTheme.titleMedium, + style: theme.typography.h4, ), ], ), @@ -91,65 +89,64 @@ class TrackDetailsDialog extends HookWidget { width: mediaQuery.mdAndUp ? double.infinity : 700, child: Table( columnWidths: const { - 0: FixedColumnWidth(95), - 1: FixedColumnWidth(10), - 2: FlexColumnWidth(1), + 0: FixedTableSize(95), + 1: FixedTableSize(10), + 2: FlexTableSize(), }, - defaultVerticalAlignment: TableCellVerticalAlignment.middle, - children: [ + theme: const TableTheme( + backgroundColor: Colors.transparent, + cellTheme: TableCellTheme( + backgroundColor: WidgetStatePropertyAll(Colors.transparent), + ), + ), + rowHeights: const {0: FixedTableSize(40)}, + rows: [ for (final entry in detailsMap.entries) TableRow( - children: [ + cells: [ TableCell( - verticalAlignment: TableCellVerticalAlignment.top, child: Text( entry.key, - style: theme.textTheme.titleMedium, + style: theme.typography.bold, ), ), const TableCell( - verticalAlignment: TableCellVerticalAlignment.top, child: Text(":"), ), - if (entry.value is Widget) - entry.value as Widget - else if (entry.value is String) - Text( - entry.value as String, - style: theme.textTheme.bodyMedium, - ), + TableCell( + child: entry.value is Widget + ? entry.value as Widget + : (entry.value is String) + ? Text( + entry.value as String, + style: theme.typography.normal, + ) + : const Text(""), + ), ], ), - const TableRow( - children: [ - SizedBox(height: 16), - SizedBox(height: 16), - SizedBox(height: 16), - ], - ), for (final entry in ytTracksDetailsMap.entries) TableRow( - children: [ + cells: [ TableCell( - verticalAlignment: TableCellVerticalAlignment.top, child: Text( entry.key, - style: theme.textTheme.titleMedium, + style: theme.typography.bold, ), ), const TableCell( - verticalAlignment: TableCellVerticalAlignment.top, child: Text(":"), ), - if (entry.value is Widget) - entry.value as Widget - else - Text( - entry.value, - maxLines: 2, - overflow: TextOverflow.ellipsis, - style: theme.textTheme.bodyMedium, - ), + TableCell( + child: entry.value is Widget + ? entry.value as Widget + : Text( + entry.value, + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: theme.typography.normal, + ), + ), ], ), ], diff --git a/lib/components/panels/controller.dart b/lib/components/panels/controller.dart deleted file mode 100644 index 4e367701..00000000 --- a/lib/components/panels/controller.dart +++ /dev/null @@ -1,146 +0,0 @@ -part of 'sliding_up_panel.dart'; - -class PanelController extends ChangeNotifier { - SlidingUpPanelState? _panelState; - - void _addState(SlidingUpPanelState panelState) { - _panelState = panelState; - notifyListeners(); - } - - bool _forceScrollChange = false; - - /// use this function when scroll change in func - /// Example: - /// panelController.forseScrollChange(scrollController.animateTo(100, duration: Duration(milliseconds: 400), curve: Curves.ease)) - Future forceScrollChange(Future func) async { - _forceScrollChange = true; - _panelState!._scrollingEnabled = true; - await func; - // if (_panelState!._sc.offset == 0) { - // _panelState!._scrollingEnabled = true; - // } - if (panelPosition < 1) { - _panelState!._scMinOffset = _panelState!._scrollController.offset; - } - _forceScrollChange = false; - } - - bool __nowTargetForceDraggable = false; - - bool get _nowTargetForceDraggable => __nowTargetForceDraggable; - - set _nowTargetForceDraggable(bool value) { - __nowTargetForceDraggable = value; - notifyListeners(); - } - - /// Determine if the panelController is attached to an instance - /// of the SlidingUpPanel (this property must return true before any other - /// functions can be used) - bool get isAttached => _panelState != null; - - /// Closes the sliding panel to its collapsed state (i.e. to the minHeight) - Future close() async { - assert(isAttached, "PanelController must be attached to a SlidingUpPanel"); - await _panelState!._close(); - notifyListeners(); - } - - /// Opens the sliding panel fully - /// (i.e. to the maxHeight) - Future open() async { - assert(isAttached, "PanelController must be attached to a SlidingUpPanel"); - await _panelState!._open(); - notifyListeners(); - } - - /// Hides the sliding panel (i.e. is invisible) - Future hide() async { - assert(isAttached, "PanelController must be attached to a SlidingUpPanel"); - await _panelState!._hide(); - notifyListeners(); - } - - /// Shows the sliding panel in its collapsed state - /// (i.e. "un-hide" the sliding panel) - Future show() async { - assert(isAttached, "PanelController must be attached to a SlidingUpPanel"); - await _panelState!._show(); - notifyListeners(); - } - - /// Animates the panel position to the value. - /// The value must between 0.0 and 1.0 - /// where 0.0 is fully collapsed and 1.0 is completely open. - /// (optional) duration specifies the time for the animation to complete - /// (optional) curve specifies the easing behavior of the animation. - Future animatePanelToPosition(double value, - {Duration? duration, Curve curve = Curves.linear}) { - assert(isAttached, "PanelController must be attached to a SlidingUpPanel"); - assert(0.0 <= value && value <= 1.0); - return _panelState! - ._animatePanelToPosition(value, duration: duration, curve: curve); - } - - /// Animates the panel position to the snap point - /// Requires that the SlidingUpPanel snapPoint property is not null - /// (optional) duration specifies the time for the animation to complete - /// (optional) curve specifies the easing behavior of the animation. - Future animatePanelToSnapPoint( - {Duration? duration, Curve curve = Curves.linear}) { - assert(isAttached, "PanelController must be attached to a SlidingUpPanel"); - assert(_panelState!.widget.snapPoint != null, - "SlidingUpPanel snapPoint property must not be null"); - return _panelState! - ._animatePanelToSnapPoint(duration: duration, curve: curve); - } - - /// Sets the panel position (without animation). - /// The value must between 0.0 and 1.0 - /// where 0.0 is fully collapsed and 1.0 is completely open. - set panelPosition(double value) { - assert(isAttached, "PanelController must be attached to a SlidingUpPanel"); - assert(0.0 <= value && value <= 1.0); - _panelState!._panelPosition = value; - } - - /// Gets the current panel position. - /// Returns the % offset from collapsed state - /// to the open state - /// as a decimal between 0.0 and 1.0 - /// where 0.0 is fully collapsed and - /// 1.0 is full open. - double get panelPosition { - assert(isAttached, "PanelController must be attached to a SlidingUpPanel"); - return _panelState!._panelPosition; - } - - /// Returns whether or not the panel is - /// currently animating. - bool get isPanelAnimating { - assert(isAttached, "PanelController must be attached to a SlidingUpPanel"); - return _panelState!._isPanelAnimating; - } - - /// Returns whether or not the - /// panel is open. - bool get isPanelOpen { - assert(isAttached, "PanelController must be attached to a SlidingUpPanel"); - return _panelState!._isPanelOpen; - } - - /// Returns whether or not the - /// panel is closed. - bool get isPanelClosed { - assert(isAttached, "PanelController must be attached to a SlidingUpPanel"); - return _panelState!._isPanelClosed; - } - - /// Returns whether or not the - /// panel is shown/hidden. - bool get isPanelShown { - assert(isAttached, "PanelController must be attached to a SlidingUpPanel"); - return _panelState!._isPanelShown; - } -} diff --git a/lib/components/panels/helpers.dart b/lib/components/panels/helpers.dart deleted file mode 100644 index d79fa97c..00000000 --- a/lib/components/panels/helpers.dart +++ /dev/null @@ -1,95 +0,0 @@ -part of "sliding_up_panel.dart"; - -/// if you want to prevent the panel from being dragged using the widget, -/// wrap the widget with this -class IgnoreDraggableWidget extends SingleChildRenderObjectWidget { - const IgnoreDraggableWidget({ - super.key, - required super.child, - }); - - @override - IgnoreDraggableWidgetWidgetRenderBox createRenderObject( - BuildContext context, - ) { - return IgnoreDraggableWidgetWidgetRenderBox(); - } -} - -class IgnoreDraggableWidgetWidgetRenderBox extends RenderPointerListener { - @override - HitTestBehavior get behavior => HitTestBehavior.opaque; -} - -/// if you want to force the panel to be dragged using the widget, -/// wrap the widget with this -/// For example, use [Scrollable] inside to allow the panel to be dragged -/// even if the scroll is not at position 0. -class ForceDraggableWidget extends SingleChildRenderObjectWidget { - const ForceDraggableWidget({ - super.key, - required super.child, - }); - - @override - ForceDraggableWidgetRenderBox createRenderObject( - BuildContext context, - ) { - return ForceDraggableWidgetRenderBox(); - } -} - -class ForceDraggableWidgetRenderBox extends RenderPointerListener { - @override - HitTestBehavior get behavior => HitTestBehavior.opaque; -} - -/// To make [ForceDraggableWidget] work in [Scrollable] widgets -class PanelScrollPhysics extends ScrollPhysics { - final PanelController controller; - const PanelScrollPhysics({required this.controller, super.parent}); - @override - PanelScrollPhysics applyTo(ScrollPhysics? ancestor) { - return PanelScrollPhysics( - controller: controller, parent: buildParent(ancestor)); - } - - @override - double applyPhysicsToUserOffset(ScrollMetrics position, double offset) { - if (controller._nowTargetForceDraggable) return 0.0; - return super.applyPhysicsToUserOffset(position, offset); - } - - @override - Simulation? createBallisticSimulation( - ScrollMetrics position, double velocity) { - if (controller._nowTargetForceDraggable) { - return super.createBallisticSimulation(position, 0); - } - return super.createBallisticSimulation(position, velocity); - } - - @override - bool get allowImplicitScrolling => false; -} - -/// if you want to prevent unwanted panel dragging when scrolling widgets [Scrollable] with horizontal axis -/// wrap the widget with this -class HorizontalScrollableWidget extends SingleChildRenderObjectWidget { - const HorizontalScrollableWidget({ - super.key, - required super.child, - }); - - @override - HorizontalScrollableWidgetRenderBox createRenderObject( - BuildContext context, - ) { - return HorizontalScrollableWidgetRenderBox(); - } -} - -class HorizontalScrollableWidgetRenderBox extends RenderPointerListener { - @override - HitTestBehavior get behavior => HitTestBehavior.opaque; -} diff --git a/lib/components/panels/sliding_up_panel.dart b/lib/components/panels/sliding_up_panel.dart deleted file mode 100644 index e99fe261..00000000 --- a/lib/components/panels/sliding_up_panel.dart +++ /dev/null @@ -1,685 +0,0 @@ -/* -Name: Zotov Vladimir -Date: 18/06/22 -Purpose: Defines the package: sliding_up_panel2 -Copyright: © 2022, Zotov Vladimir. All rights reserved. -Licensing: More information can be found here: https://github.com/Zotov-VD/sliding_up_panel/blob/master/LICENSE - -This product includes software developed by Akshath Jain (https://akshathjain.com) -*/ - -library panels; - -import 'dart:math'; - -import 'package:flutter/gestures.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/physics.dart'; -import 'package:flutter/rendering.dart'; - -part 'controller.dart'; -part 'helpers.dart'; - -enum SlideDirection { up, down } - -enum PanelState { open, closed } - -class SlidingUpPanel extends StatefulWidget { - /// Returns the Widget that slides into view. When the - /// panel is collapsed and if [collapsed] is null, - /// then top portion of this Widget will be displayed; - /// otherwise, [collapsed] will be displayed overtop - /// of this Widget. - final Widget? Function(double position)? panelBuilder; - - /// The Widget displayed overtop the [panel] when collapsed. - /// This fades out as the panel is opened. - final Widget? collapsed; - - /// The Widget that lies underneath the sliding panel. - /// This Widget automatically sizes itself - /// to fill the screen. - final Widget? body; - - /// Optional persistent widget that floats above the [panel] and attaches - /// to the top of the [panel]. Content at the top of the panel will be covered - /// by this widget. Add padding to the bottom of the `panel` to - /// avoid coverage. - final Widget? header; - - /// Optional persistent widget that floats above the [panel] and - /// attaches to the bottom of the [panel]. Content at the bottom of the panel - /// will be covered by this widget. Add padding to the bottom of the `panel` - /// to avoid coverage. - final Widget? footer; - - /// The height of the sliding panel when fully collapsed. - final double minHeight; - - /// The height of the sliding panel when fully open. - final double maxHeight; - - /// A point between [minHeight] and [maxHeight] that the panel snaps to - /// while animating. A fast swipe on the panel will disregard this point - /// and go directly to the open/close position. This value is represented as a - /// percentage of the total animation distance ([maxHeight] - [minHeight]), - /// so it must be between 0.0 and 1.0, exclusive. - final double? snapPoint; - - /// The amount to inset the children of the sliding panel sheet. - final EdgeInsetsGeometry? padding; - - /// Empty space surrounding the sliding panel sheet. - final EdgeInsetsGeometry? margin; - - /// Set to false to disable the panel from snapping open or closed. - final bool panelSnapping; - - /// Disable panel draggable on scrolling. Defaults to false. - final bool disableDraggableOnScrolling; - - /// If non-null, this can be used to control the state of the panel. - final PanelController? controller; - - /// If non-null, shows a darkening shadow over the [body] as the panel slides open. - final bool backdropEnabled; - - /// Shows a darkening shadow of this [Color] over the [body] as the panel slides open. - final Color backdropColor; - - /// The opacity of the backdrop when the panel is fully open. - /// This value can range from 0.0 to 1.0 where 0.0 is completely transparent - /// and 1.0 is completely opaque. - final double backdropOpacity; - - /// Flag that indicates whether or not tapping the - /// backdrop closes the panel. Defaults to true. - final bool backdropTapClosesPanel; - - /// If non-null, this callback - /// is called as the panel slides around with the - /// current position of the panel. The position is a double - /// between 0.0 and 1.0 where 0.0 is fully collapsed and 1.0 is fully open. - final void Function(double position)? onPanelSlide; - - /// If non-null, this callback is called when the - /// panel is fully opened - final VoidCallback? onPanelOpened; - - /// If non-null, this callback is called when the panel - /// is fully collapsed. - final VoidCallback? onPanelClosed; - - /// If non-null and true, the SlidingUpPanel exhibits a - /// parallax effect as the panel slides up. Essentially, - /// the body slides up as the panel slides up. - final bool parallaxEnabled; - - /// Allows for specifying the extent of the parallax effect in terms - /// of the percentage the panel has slid up/down. Recommended values are - /// within 0.0 and 1.0 where 0.0 is no parallax and 1.0 mimics a - /// one-to-one scrolling effect. Defaults to a 10% parallax. - final double parallaxOffset; - - /// Allows toggling of the draggability of the SlidingUpPanel. - /// Set this to false to prevent the user from being able to drag - /// the panel up and down. Defaults to true. - final bool isDraggable; - - /// Either SlideDirection.UP or SlideDirection.DOWN. Indicates which way - /// the panel should slide. Defaults to UP. If set to DOWN, the panel attaches - /// itself to the top of the screen and is fully opened when the user swipes - /// down on the panel. - final SlideDirection slideDirection; - - /// The default state of the panel; either PanelState.OPEN or PanelState.CLOSED. - /// This value defaults to PanelState.CLOSED which indicates that the panel is - /// in the closed position and must be opened. PanelState.OPEN indicates that - /// by default the Panel is open and must be swiped closed by the user. - final PanelState defaultPanelState; - - /// To attach to a [Scrollable] on a panel that - /// links the panel's position to the scroll position. Useful for implementing - /// infinite scroll behavior - final ScrollController? scrollController; - - final BoxDecoration? panelDecoration; - - const SlidingUpPanel( - {super.key, - this.body, - this.collapsed, - this.minHeight = 100.0, - this.maxHeight = 500.0, - this.snapPoint, - this.padding, - this.margin, - this.panelDecoration, - this.panelSnapping = true, - this.disableDraggableOnScrolling = false, - this.controller, - this.backdropEnabled = false, - this.backdropColor = Colors.black, - this.backdropOpacity = 0.5, - this.backdropTapClosesPanel = true, - this.onPanelSlide, - this.onPanelOpened, - this.onPanelClosed, - this.parallaxEnabled = false, - this.parallaxOffset = 0.1, - this.isDraggable = true, - this.slideDirection = SlideDirection.up, - this.defaultPanelState = PanelState.closed, - this.header, - this.footer, - this.scrollController, - this.panelBuilder}) - : assert(panelBuilder != null), - assert(0 <= backdropOpacity && backdropOpacity <= 1.0), - assert(snapPoint == null || 0 < snapPoint && snapPoint < 1.0); - - @override - SlidingUpPanelState createState() => SlidingUpPanelState(); -} - -class SlidingUpPanelState extends State - with SingleTickerProviderStateMixin { - late AnimationController _animationController; - late final ScrollController _scrollController; - - bool _scrollingEnabled = false; - final VelocityTracker _velocityTracker = - VelocityTracker.withKind(PointerDeviceKind.touch); - - bool _isPanelVisible = true; - - @override - void initState() { - super.initState(); - - _animationController = AnimationController( - vsync: this, - duration: const Duration(milliseconds: 300), - value: widget.defaultPanelState == PanelState.closed - ? 0.0 - : 1.0 //set the default panel state (i.e. set initial value of _ac) - ) - ..addListener(() { - if (widget.onPanelSlide != null) { - widget.onPanelSlide!(_animationController.value); - } - - if (widget.onPanelOpened != null && - (_animationController.value == 1.0 || - _animationController.value == 0.0)) { - widget.onPanelOpened!(); - } - }); - - // prevent the panel content from being scrolled only if the widget is - // draggable and panel scrolling is enabled - _scrollController = widget.scrollController ?? ScrollController(); - _scrollController.addListener(() { - if (widget.isDraggable && - !widget.disableDraggableOnScrolling && - (!_scrollingEnabled || _panelPosition < 1) && - widget.controller?._forceScrollChange != true) { - _scrollController.jumpTo(_scMinOffset); - } - }); - - widget.controller?._addState(this); - } - - @override - Widget build(BuildContext context) { - final mediaQuery = MediaQuery.of(context); - - return Stack( - alignment: widget.slideDirection == SlideDirection.up - ? Alignment.bottomCenter - : Alignment.topCenter, - children: [ - //make the back widget take up the entire back side - if (widget.body != null) - AnimatedBuilder( - animation: _animationController, - builder: (context, child) { - return Positioned( - top: widget.parallaxEnabled ? _getParallax() : 0.0, - child: child ?? const SizedBox(), - ); - }, - child: SizedBox( - height: mediaQuery.size.height, - width: mediaQuery.size.width, - child: widget.body, - ), - ), - - //the backdrop to overlay on the body - if (widget.backdropEnabled) - GestureDetector( - onVerticalDragEnd: widget.backdropTapClosesPanel - ? (DragEndDetails details) { - // only trigger a close if the drag is towards panel close position - if ((widget.slideDirection == SlideDirection.up ? 1 : -1) * - details.velocity.pixelsPerSecond.dy > - 0) _close(); - } - : null, - onTap: widget.backdropTapClosesPanel ? () => _close() : null, - child: AnimatedBuilder( - animation: _animationController, - builder: (context, _) { - return Container( - height: mediaQuery.size.height, - width: mediaQuery.size.width, - - //set color to null so that touch events pass through - //to the body when the panel is closed, otherwise, - //if a color exists, then touch events won't go through - color: _animationController.value == 0.0 - ? null - : widget.backdropColor.withOpacity( - widget.backdropOpacity * _animationController.value, - ), - ); - }), - ), - - //the actual sliding part - if (_isPanelVisible) - _gestureHandler( - child: AnimatedBuilder( - animation: _animationController, - builder: (context, child) { - return Container( - height: _animationController.value * - (widget.maxHeight - widget.minHeight) + - widget.minHeight, - margin: widget.margin, - padding: widget.padding, - decoration: widget.panelDecoration, - child: child, - ); - }, - child: Stack( - children: [ - //open panel - Positioned( - top: - widget.slideDirection == SlideDirection.up ? 0.0 : null, - bottom: widget.slideDirection == SlideDirection.down - ? 0.0 - : null, - width: mediaQuery.size.width - - (widget.margin != null - ? widget.margin!.horizontal - : 0) - - (widget.padding != null - ? widget.padding!.horizontal - : 0), - child: SizedBox( - height: widget.maxHeight, - child: widget.panelBuilder!( - _animationController.value, - ), - ), - ), - - // footer - if (widget.footer != null) - Positioned( - top: widget.slideDirection == SlideDirection.up - ? null - : 0.0, - bottom: widget.slideDirection == SlideDirection.down - ? null - : 0.0, - child: widget.footer ?? const SizedBox()), - - // header - if (widget.header != null) - Positioned( - top: widget.slideDirection == SlideDirection.up - ? 0.0 - : null, - bottom: widget.slideDirection == SlideDirection.down - ? 0.0 - : null, - child: widget.header ?? const SizedBox(), - ), - - // collapsed panel - Positioned( - top: - widget.slideDirection == SlideDirection.up ? 0.0 : null, - bottom: widget.slideDirection == SlideDirection.down - ? 0.0 - : null, - width: mediaQuery.size.width - - (widget.margin != null - ? widget.margin!.horizontal - : 0) - - (widget.padding != null - ? widget.padding!.horizontal - : 0), - child: AnimatedContainer( - duration: const Duration(milliseconds: 250), - height: widget.minHeight, - child: widget.collapsed == null - ? null - : FadeTransition( - opacity: Tween(begin: 1.0, end: 0.0) - .animate(_animationController), - - // if the panel is open ignore pointers (touch events) on the collapsed - // child so that way touch events go through to whatever is underneath - child: IgnorePointer( - ignoring: _animationController.value == 1.0, - child: widget.collapsed, - ), - ), - ), - ), - ], - ), - ), - ), - ], - ); - } - - @override - void dispose() { - _animationController.dispose(); - super.dispose(); - } - - double _getParallax() { - if (widget.slideDirection == SlideDirection.up) { - return -_animationController.value * - (widget.maxHeight - widget.minHeight) * - widget.parallaxOffset; - } else { - return _animationController.value * - (widget.maxHeight - widget.minHeight) * - widget.parallaxOffset; - } - } - - bool _ignoreScrollable = false; - bool _isHorizontalScrollableWidget = false; - Axis? _scrollableAxis; - - // returns a gesture detector if panel is used - // and a listener if panelBuilder is used. - // this is because the listener is designed only for use with linking the scrolling of - // panels and using it for panels that don't want to linked scrolling yields odd results - Widget _gestureHandler({required Widget child}) { - if (!widget.isDraggable) return child; - - return Listener( - onPointerDown: (PointerDownEvent e) { - var rb = context.findRenderObject() as RenderBox; - var result = BoxHitTestResult(); - rb.hitTest(result, position: e.position); - - if (_panelPosition == 1) { - _scMinOffset = 0.0; - } - // if there any widget in the path that must force graggable, - // stop it right here - if (result.path.any((entry) => - entry.target.runtimeType == ForceDraggableWidgetRenderBox)) { - widget.controller?._nowTargetForceDraggable = true; - _scMinOffset = _scrollController.offset; - _isHorizontalScrollableWidget = false; - } else if (result.path.any((entry) => - entry.target.runtimeType == HorizontalScrollableWidgetRenderBox)) { - _isHorizontalScrollableWidget = true; - widget.controller?._nowTargetForceDraggable = false; - } else if (result.path.any((entry) => - entry.target.runtimeType == IgnoreDraggableWidgetWidgetRenderBox)) { - _ignoreScrollable = true; - widget.controller?._nowTargetForceDraggable = false; - _isHorizontalScrollableWidget = false; - return; - } else { - widget.controller?._nowTargetForceDraggable = false; - _isHorizontalScrollableWidget = false; - } - _ignoreScrollable = false; - _velocityTracker.addPosition(e.timeStamp, e.position); - }, - onPointerMove: (PointerMoveEvent e) { - if (_scrollableAxis == null) { - if (e.delta.dx.abs() > e.delta.dy.abs()) { - _scrollableAxis = Axis.horizontal; - } else { - _scrollableAxis = Axis.vertical; - } - } - - if (_isHorizontalScrollableWidget && - _scrollableAxis == Axis.horizontal) { - return; - } - - if (_ignoreScrollable) return; - _velocityTracker.addPosition( - e.timeStamp, - e.position, - ); // add current position for velocity tracking - _onGestureSlide(e.delta.dy); - }, - onPointerUp: (PointerUpEvent e) { - if (_ignoreScrollable) return; - _scrollableAxis = null; - _onGestureEnd(_velocityTracker.getVelocity()); - }, - child: child, - ); - } - - double _scMinOffset = 0.0; - - // handles the sliding gesture - void _onGestureSlide(double dy) { - // only slide the panel if scrolling is not enabled - if (widget.controller?._nowTargetForceDraggable == false && - widget.disableDraggableOnScrolling) { - return; - } - if ((!_scrollingEnabled) || - _panelPosition < 1 || - widget.controller?._nowTargetForceDraggable == true) { - if (widget.slideDirection == SlideDirection.up) { - _animationController.value -= - dy / (widget.maxHeight - widget.minHeight); - } else { - _animationController.value += - dy / (widget.maxHeight - widget.minHeight); - } - } - - // if the panel is open and the user hasn't scrolled, we need to determine - // whether to enable scrolling if the user swipes up, or disable closing and - // begin to close the panel if the user swipes down - if (_isPanelOpen && - _scrollController.hasClients && - _scrollController.offset <= _scMinOffset) { - setState(() { - if (dy < 0) { - _scrollingEnabled = true; - } else { - _scrollingEnabled = false; - } - }); - } - } - - // handles when user stops sliding - void _onGestureEnd(Velocity v) { - if (widget.controller?._nowTargetForceDraggable == false && - widget.disableDraggableOnScrolling) { - return; - } - double minFlingVelocity = 365.0; - double kSnap = 8; - - //let the current animation finish before starting a new one - if (_animationController.isAnimating) return; - - // if scrolling is allowed and the panel is open, we don't want to close - // the panel if they swipe up on the scrollable - if (_isPanelOpen && _scrollingEnabled) return; - - //check if the velocity is sufficient to constitute fling to end - double visualVelocity = - -v.pixelsPerSecond.dy / (widget.maxHeight - widget.minHeight); - - // reverse visual velocity to account for slide direction - if (widget.slideDirection == SlideDirection.down) { - visualVelocity = -visualVelocity; - } - - // get minimum distances to figure out where the panel is at - double d2Close = _animationController.value; - double d2Open = 1 - _animationController.value; - double d2Snap = ((widget.snapPoint ?? 3) - _animationController.value) - .abs(); // large value if null results in not every being the min - double minDistance = min(d2Close, min(d2Snap, d2Open)); - - // check if velocity is sufficient for a fling - if (v.pixelsPerSecond.dy.abs() >= minFlingVelocity) { - // snapPoint exists - if (widget.panelSnapping && widget.snapPoint != null) { - if (v.pixelsPerSecond.dy.abs() >= kSnap * minFlingVelocity || - minDistance == d2Snap) { - _animationController.fling(velocity: visualVelocity); - } else { - _flingPanelToPosition(widget.snapPoint!, visualVelocity); - } - - // no snap point exists - } else if (widget.panelSnapping) { - _animationController.fling(velocity: visualVelocity); - - // panel snapping disabled - } else { - _animationController.animateTo( - _animationController.value + visualVelocity * 0.16, - duration: const Duration(milliseconds: 410), - curve: Curves.decelerate, - ); - } - - return; - } - - // check if the controller is already halfway there - if (widget.panelSnapping) { - if (minDistance == d2Close) { - _close(); - } else if (minDistance == d2Snap) { - _flingPanelToPosition(widget.snapPoint!, visualVelocity); - } else { - _open(); - } - } - } - - void _flingPanelToPosition(double targetPos, double velocity) { - final Simulation simulation = SpringSimulation( - SpringDescription.withDampingRatio( - mass: 1.0, - stiffness: 500.0, - ratio: 1.0, - ), - _animationController.value, - targetPos, - velocity); - - _animationController.animateWith(simulation); - } - - //--------------------------------- - //PanelController related functions - //--------------------------------- - - //close the panel - Future _close() { - return _animationController.fling(velocity: -1.0); - } - - //open the panel - Future _open() { - return _animationController.fling(velocity: 1.0); - } - - //hide the panel (completely offscreen) - Future _hide() { - return _animationController.fling(velocity: -1.0).then((x) { - setState(() { - _isPanelVisible = false; - }); - }); - } - - //show the panel (in collapsed mode) - Future _show() { - return _animationController.fling(velocity: -1.0).then((x) { - setState(() { - _isPanelVisible = true; - }); - }); - } - - //animate the panel position to value - must - //be between 0.0 and 1.0 - Future _animatePanelToPosition(double value, - {Duration? duration, Curve curve = Curves.linear}) { - assert(0.0 <= value && value <= 1.0); - return _animationController.animateTo(value, - duration: duration, curve: curve); - } - - //animate the panel position to the snap point - //REQUIRES that widget.snapPoint != null - Future _animatePanelToSnapPoint( - {Duration? duration, Curve curve = Curves.linear}) { - assert(widget.snapPoint != null); - return _animationController.animateTo(widget.snapPoint!, - duration: duration, curve: curve); - } - - //set the panel position to value - must - //be between 0.0 and 1.0 - set _panelPosition(double value) { - assert(0.0 <= value && value <= 1.0); - _animationController.value = value; - } - - //get the current panel position - //returns the % offset from collapsed state - //as a decimal between 0.0 and 1.0 - double get _panelPosition => _animationController.value; - - //returns whether or not - //the panel is still animating - bool get _isPanelAnimating => _animationController.isAnimating; - - //returns whether or not the - //panel is open - bool get _isPanelOpen => _animationController.value == 1.0; - - //returns whether or not the - //panel is closed - bool get _isPanelClosed => _animationController.value == 0.0; - - //returns whether or not the - //panel is shown/hidden - bool get _isPanelShown => _isPanelVisible; -} diff --git a/lib/components/track_presentation/track_presentation.dart b/lib/components/track_presentation/track_presentation.dart index 96f5f964..4f1db832 100644 --- a/lib/components/track_presentation/track_presentation.dart +++ b/lib/components/track_presentation/track_presentation.dart @@ -51,6 +51,7 @@ class TrackPresentation extends HookConsumerWidget { return Data.inherit( data: options, child: SafeArea( + bottom: false, child: Scaffold( headers: const [TitleBar()], child: CustomScrollView( diff --git a/lib/main.dart b/lib/main.dart index 2f93ea87..57cfbd88 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -222,7 +222,7 @@ class Spotube extends HookConsumerWidget { darkTheme: ThemeData( radius: .5, iconTheme: const IconThemeProperties(), - colorScheme: ColorSchemes.darkNeutral(), + colorScheme: ColorSchemes.darkOrange(), surfaceOpacity: .8, surfaceBlur: 10, ), diff --git a/lib/modules/player/player.dart b/lib/modules/player/player.dart index 014e6aef..0c915b08 100644 --- a/lib/modules/player/player.dart +++ b/lib/modules/player/player.dart @@ -1,11 +1,11 @@ import 'package:auto_size_text/auto_size_text.dart'; -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart' show showModalBottomSheet; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:shadcn_flutter/shadcn_flutter.dart' - show openDrawer, OverlayPosition; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; +import 'package:sliding_up_panel/sliding_up_panel.dart'; import 'package:spotube/collections/assets.gen.dart'; import 'package:spotube/collections/spotube_icons.dart'; @@ -14,19 +14,16 @@ import 'package:spotube/modules/player/player_actions.dart'; import 'package:spotube/modules/player/player_controls.dart'; import 'package:spotube/modules/player/player_queue.dart'; import 'package:spotube/modules/player/volume_slider.dart'; -import 'package:spotube/components/animated_gradient.dart'; import 'package:spotube/components/dialogs/track_details_dialog.dart'; import 'package:spotube/components/links/artist_link.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/components/image/universal_image.dart'; -import 'package:spotube/components/panels/sliding_up_panel.dart'; import 'package:spotube/extensions/artist_simple.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; -import 'package:spotube/hooks/utils/use_custom_status_bar_color.dart'; -import 'package:spotube/hooks/utils/use_palette_color.dart'; import 'package:spotube/models/local_track.dart'; +import 'package:spotube/modules/root/spotube_navigation_bar.dart'; import 'package:spotube/pages/lyrics/lyrics.dart'; import 'package:spotube/pages/track/track.dart'; import 'package:spotube/provider/authentication/authentication.dart'; @@ -58,6 +55,16 @@ class PlayerView extends HookConsumerWidget { final isLocalTrack = currentTrack is LocalTrack; final mediaQuery = MediaQuery.of(context); + final shouldHide = useState(true); + + ref.listen(navigationPanelHeight, (_, height) { + shouldHide.value = height.ceil() == 50; + }); + + if (shouldHide.value) { + return const SizedBox(); + } + useEffect(() { if (mediaQuery.lgAndUp) { WidgetsBinding.instance.addPostFrameCallback((_) { @@ -74,15 +81,6 @@ class PlayerView extends HookConsumerWidget { [currentTrack?.album?.images], ); - final palette = usePaletteGenerator(albumArt); - final titleTextColor = palette.dominantColor?.titleTextColor; - final bodyTextColor = palette.dominantColor?.bodyTextColor; - - final bgColor = palette.dominantColor?.color ?? theme.colorScheme.primary; - - final GlobalKey scaffoldKey = - useMemoized(() => GlobalKey(), []); - useEffect(() { for (final renderView in WidgetsBinding.instance.renderViews) { renderView.automaticSystemUiAdjustment = false; @@ -93,324 +91,230 @@ class PlayerView extends HookConsumerWidget { renderView.automaticSystemUiAdjustment = true; } }; - }, [panelController.isPanelOpen]); - - useCustomStatusBarColor( - bgColor, - panelController.isPanelOpen, - noSetBGColor: true, - automaticSystemUiAdjustment: false, - ); - - final topPadding = MediaQueryData.fromView(View.of(context)).padding.top; + }, [panelController.isAttached && panelController.isPanelOpen]); return AppPopScope( canPop: context.canPop(), onPopInvoked: (didPop) async { await panelController.close(); }, - child: IconTheme( - data: theme.iconTheme.copyWith(color: bodyTextColor), - child: AnimateGradient( - animateAlignments: true, - primaryBegin: Alignment.topLeft, - primaryEnd: Alignment.bottomLeft, - secondaryBegin: Alignment.bottomRight, - secondaryEnd: Alignment.topRight, - duration: const Duration(seconds: 15), - primaryColors: [ - palette.dominantColor?.color ?? theme.colorScheme.primary, - palette.mutedColor?.color ?? theme.colorScheme.secondary, - ], - secondaryColors: [ - (palette.darkVibrantColor ?? palette.lightVibrantColor)?.color ?? - theme.colorScheme.primaryContainer, - (palette.darkMutedColor ?? palette.lightMutedColor)?.color ?? - theme.colorScheme.secondaryContainer, - ], - child: Scaffold( - key: scaffoldKey, - backgroundColor: Colors.transparent, - appBar: PreferredSize( - preferredSize: Size.fromHeight( - kToolbarHeight + topPadding, - ), - child: ForceDraggableWidget( - child: Padding( - padding: EdgeInsets.only(top: topPadding), - child: TitleBar( - backgroundColor: Colors.transparent, - leading: [ - IconButton( - icon: const Icon(SpotubeIcons.angleDown, size: 18), - onPressed: panelController.close, - ) - ], - trailing: [ - if (currentTrack is YoutubeSourcedTrack) - TextButton.icon( - icon: Assets.logos.songlinkTransparent.image( - width: 20, - height: 20, - color: bodyTextColor, - ), - label: Text(context.l10n.song_link), - style: TextButton.styleFrom( - foregroundColor: bodyTextColor, - padding: const EdgeInsets.symmetric(horizontal: 10), - ), - onPressed: () { - final url = - "https://song.link/s/${currentTrack.id}"; + child: Scaffold( + headers: [ + SafeArea( + child: TitleBar( + surfaceOpacity: 0, + surfaceBlur: 0, + leading: [ + IconButton.ghost( + icon: const Icon(SpotubeIcons.angleDown, size: 18), + onPressed: panelController.close, + ) + ], + trailing: [ + if (currentTrack is YoutubeSourcedTrack) + TextButton( + leading: Assets.logos.songlinkTransparent.image( + width: 20, + height: 20, + color: theme.colorScheme.foreground, + ), + onPressed: () { + final url = "https://song.link/s/${currentTrack.id}"; - launchUrlString(url); + launchUrlString(url); + }, + child: Text(context.l10n.song_link), + ), + Tooltip( + tooltip: TooltipContainer( + child: Text(context.l10n.details), + ), + child: IconButton.ghost( + icon: const Icon(SpotubeIcons.info, size: 18), + onPressed: currentTrack == null + ? null + : () { + showDialog( + context: context, + builder: (context) { + return TrackDetailsDialog( + track: currentTrack, + ); + }); }, - ), - IconButton( - icon: const Icon(SpotubeIcons.info, size: 18), - tooltip: context.l10n.details, - style: IconButton.styleFrom( - foregroundColor: bodyTextColor, - ), - onPressed: currentTrack == null - ? null - : () { - showDialog( - context: context, - builder: (context) { - return TrackDetailsDialog( - track: currentTrack, - ); - }); - }, - ) + ), + ) + ], + ), + ), + ], + child: SingleChildScrollView( + controller: scrollController, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + children: [ + Container( + margin: const EdgeInsets.all(8), + constraints: + const BoxConstraints(maxHeight: 300, maxWidth: 300), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + boxShadow: [ + BoxShadow( + color: Colors.black.withAlpha(100), + spreadRadius: 2, + blurRadius: 10, + offset: Offset.zero, + ), ], ), - ), - ), - ), - extendBodyBehindAppBar: true, - body: SingleChildScrollView( - controller: scrollController, - child: Container( - alignment: Alignment.center, - width: double.infinity, - child: ConstrainedBox( - constraints: const BoxConstraints(maxWidth: 580), - child: SafeArea( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - children: [ - ForceDraggableWidget( - child: Container( - margin: const EdgeInsets.all(8), - constraints: const BoxConstraints( - maxHeight: 300, maxWidth: 300), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - boxShadow: const [ - BoxShadow( - color: Colors.black26, - spreadRadius: 2, - blurRadius: 10, - offset: Offset(0, 0), - ), - ], - ), - child: ClipRRect( - borderRadius: BorderRadius.circular(20), - child: UniversalImage( - path: albumArt, - placeholder: Assets.albumPlaceholder.path, - fit: BoxFit.cover, - ), - ), - ), - ), - const SizedBox(height: 60), - Container( - padding: const EdgeInsets.symmetric(horizontal: 16), - alignment: Alignment.centerLeft, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - AutoSizeText( - currentTrack?.name ?? - context.l10n.not_playing, - style: TextStyle( - color: titleTextColor, - fontSize: 22, - ), - maxFontSize: 22, - maxLines: 1, - textAlign: TextAlign.start, - ), - if (isLocalTrack) - Text( - currentTrack.artists?.asString() ?? "", - style: theme.textTheme.bodyMedium!.copyWith( - fontWeight: FontWeight.bold, - color: bodyTextColor, - ), - ) - else - ArtistLink( - artists: currentTrack?.artists ?? [], - textStyle: - theme.textTheme.bodyMedium!.copyWith( - fontWeight: FontWeight.bold, - color: bodyTextColor, - ), - onRouteChange: (route) { - panelController.close(); - GoRouter.of(context).push(route); - }, - onOverflowArtistClick: () => - ServiceUtils.pushNamed( - context, - TrackPage.name, - pathParameters: { - "id": currentTrack!.id!, - }, - ), - ), - ], - ), - ), - const SizedBox(height: 10), - PlayerControls(palette: palette), - const SizedBox(height: 25), - const PlayerActions( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - showQueue: false, - ), - const SizedBox(height: 10), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - const SizedBox(width: 10), - Expanded( - child: OutlinedButton.icon( - icon: const Icon(SpotubeIcons.queue), - label: Text(context.l10n.queue), - style: OutlinedButton.styleFrom( - foregroundColor: bodyTextColor, - side: BorderSide( - color: bodyTextColor ?? Colors.white, - ), - ), - // enabled: currentTrack != null, - onPressed: () { - openDrawer( - context: context, - barrierDismissible: true, - draggable: true, - barrierColor: Colors.black12, - borderRadius: BorderRadius.circular(10), - transformBackdrop: false, - position: OverlayPosition.bottom, - surfaceBlur: context.theme.surfaceBlur, - surfaceOpacity: 0.7, - expands: true, - builder: (context) => Consumer( - builder: (context, ref, _) { - final playlist = ref.watch( - audioPlayerProvider, - ); - final playlistNotifier = ref.read( - audioPlayerProvider.notifier); - return ConstrainedBox( - constraints: BoxConstraints( - maxHeight: MediaQuery.of(context) - .size - .height * - 0.8, - ), - child: PlayerQueue - .fromAudioPlayerNotifier( - floating: false, - playlist: playlist, - notifier: playlistNotifier, - ), - ); - }, - ), - ); - }, - ), - ), - if (auth.asData?.value != null) - const SizedBox(width: 10), - if (auth.asData?.value != null) - Expanded( - child: OutlinedButton.icon( - label: Text(context.l10n.lyrics), - icon: const Icon(SpotubeIcons.music), - style: OutlinedButton.styleFrom( - foregroundColor: bodyTextColor, - side: BorderSide( - color: bodyTextColor ?? Colors.white, - ), - ), - onPressed: () { - showModalBottomSheet( - context: context, - isDismissible: true, - enableDrag: true, - isScrollControlled: true, - backgroundColor: Colors.black38, - barrierColor: Colors.black12, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(20), - topRight: Radius.circular(20), - ), - ), - builder: (context) => - const LyricsPage(isModal: true), - ); - }, - ), - ), - const SizedBox(width: 10), - ], - ), - const SizedBox(height: 25), - SliderTheme( - data: theme.sliderTheme.copyWith( - activeTrackColor: titleTextColor, - inactiveTrackColor: bodyTextColor, - thumbColor: titleTextColor, - overlayColor: titleTextColor?.withOpacity(0.2), - trackHeight: 2, - thumbShape: const RoundSliderThumbShape( - enabledThumbRadius: 8, - ), - ), - child: Padding( - padding: - const EdgeInsets.symmetric(horizontal: 16), - child: Consumer(builder: (context, ref, _) { - final volume = ref.watch(volumeProvider); - return VolumeSlider( - fullWidth: true, - value: volume, - onChanged: (value) { - ref - .read(volumeProvider.notifier) - .setVolume(value); - }, - ); - }), - ), - ), - ], - ), + child: ClipRRect( + borderRadius: BorderRadius.circular(20), + child: UniversalImage( + path: albumArt, + placeholder: Assets.albumPlaceholder.path, + fit: BoxFit.cover, ), ), ), - ), + const SizedBox(height: 60), + Container( + padding: const EdgeInsets.symmetric(horizontal: 16), + alignment: Alignment.centerLeft, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AutoSizeText( + currentTrack?.name ?? context.l10n.not_playing, + style: const TextStyle(fontSize: 22), + maxFontSize: 22, + maxLines: 1, + textAlign: TextAlign.start, + ), + if (isLocalTrack) + Text( + currentTrack.artists?.asString() ?? "", + style: theme.typography.normal + .copyWith(fontWeight: FontWeight.bold), + ) + else + ArtistLink( + artists: currentTrack?.artists ?? [], + textStyle: theme.typography.normal + .copyWith(fontWeight: FontWeight.bold), + onRouteChange: (route) { + panelController.close(); + GoRouter.of(context).push(route); + }, + onOverflowArtistClick: () => ServiceUtils.pushNamed( + context, + TrackPage.name, + pathParameters: { + "id": currentTrack!.id!, + }, + ), + ), + ], + ), + ), + const SizedBox(height: 10), + const PlayerControls(), + const SizedBox(height: 25), + const PlayerActions( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + showQueue: false, + ), + const SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + const SizedBox(width: 10), + Expanded( + child: OutlineButton( + leading: const Icon(SpotubeIcons.queue), + child: Text(context.l10n.queue), + onPressed: () { + openDrawer( + context: context, + barrierDismissible: true, + draggable: true, + barrierColor: Colors.black.withAlpha(100), + borderRadius: BorderRadius.circular(10), + transformBackdrop: false, + position: OverlayPosition.bottom, + surfaceBlur: context.theme.surfaceBlur, + surfaceOpacity: 0.7, + expands: true, + builder: (context) => Consumer( + builder: (context, ref, _) { + final playlist = ref.watch( + audioPlayerProvider, + ); + final playlistNotifier = + ref.read(audioPlayerProvider.notifier); + return ConstrainedBox( + constraints: BoxConstraints( + maxHeight: + MediaQuery.of(context).size.height * + 0.8, + ), + child: PlayerQueue.fromAudioPlayerNotifier( + floating: false, + playlist: playlist, + notifier: playlistNotifier, + ), + ); + }, + ), + ); + }, + ), + ), + if (auth.asData?.value != null) const SizedBox(width: 10), + if (auth.asData?.value != null) + Expanded( + child: OutlineButton( + leading: const Icon(SpotubeIcons.music), + child: Text(context.l10n.lyrics), + onPressed: () { + showModalBottomSheet( + context: context, + isDismissible: true, + enableDrag: true, + isScrollControlled: true, + backgroundColor: Colors.black.withAlpha(100), + barrierColor: Colors.black.withAlpha(100), + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(20), + topRight: Radius.circular(20), + ), + ), + builder: (context) => + const LyricsPage(isModal: true), + ); + }, + ), + ), + const SizedBox(width: 10), + ], + ), + const SizedBox(height: 25), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Consumer(builder: (context, ref, _) { + final volume = ref.watch(volumeProvider); + return VolumeSlider( + fullWidth: true, + value: volume, + onChanged: (value) { + ref.read(volumeProvider.notifier).setVolume(value); + }, + ); + }), + ), + ], ), ), ), diff --git a/lib/modules/player/player_overlay.dart b/lib/modules/player/player_overlay.dart index 2322bcba..a37ac5bc 100644 --- a/lib/modules/player/player_overlay.dart +++ b/lib/modules/player/player_overlay.dart @@ -1,19 +1,12 @@ -import 'dart:ui'; - -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:sliding_up_panel/sliding_up_panel.dart'; +import 'package:spotube/modules/player/player_overlay_collapsed.dart'; -import 'package:spotube/modules/player/player_track_details.dart'; import 'package:spotube/modules/root/spotube_navigation_bar.dart'; -import 'package:spotube/components/panels/sliding_up_panel.dart'; -import 'package:spotube/collections/spotube_icons.dart'; -import 'package:spotube/collections/intents.dart'; -import 'package:spotube/modules/player/use_progress.dart'; import 'package:spotube/modules/player/player.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; -import 'package:spotube/provider/audio_player/querying_track_info.dart'; -import 'package:spotube/services/audio_player/audio_player.dart'; class PlayerOverlay extends HookConsumerWidget { final String albumArt; @@ -25,180 +18,34 @@ class PlayerOverlay extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final isFetchingActiveTrack = ref.watch(queryingTrackInfoProvider); final playlist = ref.watch(audioPlayerProvider); final canShow = playlist.activeTrack != null; - final playing = - useStream(audioPlayer.playingStream).data ?? audioPlayer.isPlaying; - - final theme = Theme.of(context); - final textColor = theme.colorScheme.primary; - - const radius = BorderRadius.only( - topLeft: Radius.circular(10), - topRight: Radius.circular(10), - ); - - final mediaQuery = MediaQuery.of(context); + final screenSize = MediaQuery.sizeOf(context); final panelController = useMemoized(() => PanelController(), []); - final scrollController = useScrollController(); - - useEffect(() { - return () { - panelController.dispose(); - }; - }, []); return SlidingUpPanel( - maxHeight: mediaQuery.size.height, + maxHeight: screenSize.height, backdropEnabled: false, - minHeight: canShow ? 53 : 0, + minHeight: canShow ? 63 : 0, onPanelSlide: (position) { final invertedPosition = 1 - position; ref.read(navigationPanelHeight.notifier).state = 50 * invertedPosition; }, controller: panelController, - collapsed: ClipRRect( - borderRadius: radius, - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 15, sigmaY: 15), - child: AnimatedContainer( - duration: const Duration(milliseconds: 250), - width: mediaQuery.size.width, - decoration: BoxDecoration( - color: theme.colorScheme.secondaryContainer.withOpacity(.8), - borderRadius: radius, - ), - child: AnimatedOpacity( - duration: const Duration(milliseconds: 250), - opacity: canShow ? 1 : 0, - child: Material( - type: MaterialType.transparency, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - HookBuilder( - builder: (context) { - final progress = useProgress(ref); - // animated - return TweenAnimationBuilder( - duration: const Duration(milliseconds: 250), - tween: Tween( - begin: 0, - end: progress.progressStatic, - ), - builder: (context, value, child) { - return LinearProgressIndicator( - value: value, - minHeight: 2, - backgroundColor: Colors.transparent, - valueColor: AlwaysStoppedAnimation( - theme.colorScheme.primary, - ), - ); - }, - ); - }, - ), - Expanded( - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: GestureDetector( - onTap: () { - panelController.open(); - }, - child: Container( - width: double.infinity, - color: Colors.transparent, - child: PlayerTrackDetails( - track: playlist.activeTrack, - color: textColor, - ), - ), - ), - ), - Row( - children: [ - IconButton( - icon: Icon( - SpotubeIcons.skipBack, - color: textColor, - ), - onPressed: isFetchingActiveTrack - ? null - : audioPlayer.skipToPrevious, - ), - Consumer( - builder: (context, ref, _) { - return IconButton( - icon: isFetchingActiveTrack - ? const SizedBox( - height: 20, - width: 20, - child: CircularProgressIndicator(), - ) - : Icon( - playing - ? SpotubeIcons.pause - : SpotubeIcons.play, - color: textColor, - ), - onPressed: Actions.handler( - context, - PlayPauseIntent(ref), - ), - ); - }, - ), - IconButton( - icon: Icon( - SpotubeIcons.skipForward, - color: textColor, - ), - onPressed: isFetchingActiveTrack - ? null - : audioPlayer.skipToNext, - ), - ], - ), - ], - ), - ), - ], - ), - ), - ), - ), - ), + color: Colors.transparent, + parallaxEnabled: true, + renderPanelSheet: false, + header: SizedBox( + height: 63, + width: screenSize.width, + child: PlayerOverlayCollapsedSection(panelController: panelController), + ), + panelBuilder: (scrollController) => PlayerView( + panelController: panelController, + scrollController: scrollController, ), - scrollController: scrollController, - panelBuilder: (position) { - // this is the reason we're getting an update - final navigationHeight = ref.watch(navigationPanelHeight); - - if (navigationHeight == 50) return const SizedBox(); - - return IgnorePointer( - ignoring: !panelController.isPanelOpen, - child: AnimatedContainer( - clipBehavior: Clip.antiAlias, - duration: const Duration(milliseconds: 250), - decoration: navigationHeight == 0 - ? const BoxDecoration(borderRadius: BorderRadius.zero) - : const BoxDecoration(borderRadius: radius), - child: IgnoreDraggableWidget( - child: PlayerView( - panelController: panelController, - scrollController: scrollController, - ), - ), - ), - ); - }, ); } } diff --git a/lib/modules/player/player_overlay_collapsed.dart b/lib/modules/player/player_overlay_collapsed.dart new file mode 100644 index 00000000..52847c40 --- /dev/null +++ b/lib/modules/player/player_overlay_collapsed.dart @@ -0,0 +1,118 @@ +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:sliding_up_panel/sliding_up_panel.dart'; +import 'package:spotube/collections/intents.dart'; +import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/modules/player/player_track_details.dart'; +import 'package:spotube/modules/root/spotube_navigation_bar.dart'; +import 'package:spotube/provider/audio_player/audio_player.dart'; +import 'package:spotube/provider/audio_player/querying_track_info.dart'; +import 'package:spotube/services/audio_player/audio_player.dart'; + +class PlayerOverlayCollapsedSection extends HookConsumerWidget { + final PanelController panelController; + const PlayerOverlayCollapsedSection({ + super.key, + required this.panelController, + }); + + @override + Widget build(BuildContext context, ref) { + final playlist = ref.watch(audioPlayerProvider); + final canShow = playlist.activeTrack != null; + + final isFetchingActiveTrack = ref.watch(queryingTrackInfoProvider); + final playing = + useStream(audioPlayer.playingStream).data ?? audioPlayer.isPlaying; + + final theme = Theme.of(context); + + final shouldShow = useState(true); + + ref.listen(navigationPanelHeight, (_, height) { + shouldShow.value = height.ceil() == 50; + }); + + return AnimatedSwitcher( + duration: const Duration(milliseconds: 250), + child: canShow && shouldShow.value + ? Padding( + padding: const EdgeInsets.all(5), + child: SurfaceCard( + borderWidth: 0, + surfaceBlur: theme.surfaceBlur, + surfaceOpacity: theme.surfaceOpacity, + padding: EdgeInsets.zero, + borderRadius: theme.borderRadiusLg, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Expanded( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: GestureDetector( + onTap: () { + panelController.open(); + }, + child: Container( + width: double.infinity, + color: Colors.transparent, + child: PlayerTrackDetails( + track: playlist.activeTrack, + color: theme.colorScheme.foreground, + ), + ), + ), + ), + Row( + children: [ + IconButton.ghost( + icon: const Icon(SpotubeIcons.skipBack), + onPressed: isFetchingActiveTrack + ? null + : audioPlayer.skipToPrevious, + ), + Consumer( + builder: (context, ref, _) { + return IconButton.ghost( + icon: isFetchingActiveTrack + ? const SizedBox( + height: 20, + width: 20, + child: CircularProgressIndicator(), + ) + : Icon( + playing + ? SpotubeIcons.pause + : SpotubeIcons.play, + ), + onPressed: Actions.handler( + context, + PlayPauseIntent(ref), + ), + ); + }, + ), + IconButton.ghost( + icon: const Icon(SpotubeIcons.skipForward), + onPressed: isFetchingActiveTrack + ? null + : audioPlayer.skipToNext, + ), + const Gap(5), + ], + ), + ], + ), + ), + ], + ), + ), + ) + : const SizedBox.shrink(), + ); + } +} diff --git a/lib/modules/root/spotube_navigation_bar.dart b/lib/modules/root/spotube_navigation_bar.dart index fa585054..8d3e71f4 100644 --- a/lib/modules/root/spotube_navigation_bar.dart +++ b/lib/modules/root/spotube_navigation_bar.dart @@ -3,6 +3,7 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/collections/side_bar_tiles.dart'; import 'package:spotube/extensions/constrains.dart'; @@ -52,24 +53,29 @@ class SpotubeNavigationBar extends HookConsumerWidget { return AnimatedContainer( duration: const Duration(milliseconds: 100), - child: NavigationBar( - index: selectedIndex, - onSelected: (i) { - ServiceUtils.navigateNamed(context, navbarTileList[i].name); - }, - children: [ - for (final tile in navbarTileList) - NavigationButton( - style: const ButtonStyle.muted(density: ButtonDensity.icon), - selectedStyle: - const ButtonStyle.fixed(density: ButtonDensity.icon), - child: Badge( - isLabelVisible: tile.id == "library" && downloadCount > 0, - label: Text(downloadCount.toString()), - child: Icon(tile.icon), - ), - ) - ], + height: panelHeight, + child: SingleChildScrollView( + child: NavigationBar( + index: selectedIndex, + surfaceBlur: context.theme.surfaceBlur, + surfaceOpacity: context.theme.surfaceOpacity, + onSelected: (i) { + ServiceUtils.navigateNamed(context, navbarTileList[i].name); + }, + children: [ + for (final tile in navbarTileList) + NavigationButton( + style: const ButtonStyle.muted(density: ButtonDensity.icon), + selectedStyle: + const ButtonStyle.fixed(density: ButtonDensity.icon), + child: Badge( + isLabelVisible: tile.id == "library" && downloadCount > 0, + label: Text(downloadCount.toString()), + child: Icon(tile.icon), + ), + ) + ], + ), ), ); } diff --git a/lib/pages/lyrics/plain_lyrics.dart b/lib/pages/lyrics/plain_lyrics.dart index 6246fd79..0b5354a0 100644 --- a/lib/pages/lyrics/plain_lyrics.dart +++ b/lib/pages/lyrics/plain_lyrics.dart @@ -3,6 +3,7 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:palette_generator/palette_generator.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/modules/lyrics/zoom_controls.dart'; import 'package:spotube/components/shimmers/shimmer_lyrics.dart'; @@ -53,7 +54,9 @@ class PlainLyrics extends HookConsumerWidget { child: Text( playlist.activeTrack?.artists?.asString() ?? "", style: (mediaQuery.mdAndUp ? typography.h4 : typography.large) - .copyWith(color: palette.bodyTextColor), + .copyWith( + color: palette.bodyTextColor, + ), ), ) ], @@ -103,7 +106,9 @@ class PlainLyrics extends HookConsumerWidget { return AnimatedDefaultTextStyle( duration: const Duration(milliseconds: 200), style: TextStyle( - color: palette.bodyTextColor, + color: isModal == true + ? context.theme.colorScheme.foreground + : palette.bodyTextColor, fontSize: 24 * textZoomLevel.value / 100, height: textZoomLevel.value < 70 ? 1.5 diff --git a/lib/pages/lyrics/synced_lyrics.dart b/lib/pages/lyrics/synced_lyrics.dart index 1367fa5a..b7423e14 100644 --- a/lib/pages/lyrics/synced_lyrics.dart +++ b/lib/pages/lyrics/synced_lyrics.dart @@ -34,9 +34,11 @@ class SyncedLyrics extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { + final mediaQuery = MediaQuery.sizeOf(context); + final theme = Theme.of(context); + final playlist = ref.watch(audioPlayerProvider); - final mediaQuery = MediaQuery.sizeOf(context); final controller = useAutoScrollController(); final delay = ref.watch(syncedLyricsDelayProvider); @@ -70,7 +72,9 @@ class SyncedLyrics extends HookConsumerWidget { final headlineTextStyle = (mediaQuery.mdAndUp ? typography.h3 : typography.h4.copyWith(fontSize: 25)) - .copyWith(color: palette.titleTextColor); + .copyWith( + color: palette.titleTextColor, + ); final bodyTextTheme = typography.large.copyWith( color: palette.bodyTextColor, @@ -182,9 +186,15 @@ class SyncedLyrics extends HookConsumerWidget { text: lyricSlice.text, textStyle: DefaultTextStyle.of(context).style, - textColor: isActive - ? Colors.white - : palette.bodyTextColor, + textColor: switch (( + isActive, + isModal == true + )) { + (true, _) => Colors.white, + (_, true) => + theme.colorScheme.mutedForeground, + (_, _) => palette.bodyTextColor, + }, strokeColor: isActive ? Colors.black : Colors.transparent, diff --git a/pubspec.lock b/pubspec.lock index 8c8c30be..a43f4f2c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -2101,6 +2101,14 @@ packages: description: flutter source: sdk version: "0.0.0" + sliding_up_panel: + dependency: "direct main" + description: + name: sliding_up_panel + sha256: "578e90956a6212d1e406373250b2436a0f3afece29aee3c24c8360094d6cf968" + url: "https://pub.dev" + source: hosted + version: "2.0.0+1" sliver_tools: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index e06cf96c..35738548 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -112,6 +112,7 @@ dependencies: shelf_web_socket: ^2.0.0 simple_icons: ^10.1.3 skeletonizer: ^1.1.1 + sliding_up_panel: ^2.0.0+1 sliver_tools: ^0.2.12 smtc_windows: ^1.0.0 spotify: ^0.13.7 From 30e03786bfb0071aa57969a88a979536804ba12a Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 3 Jan 2025 23:10:26 +0600 Subject: [PATCH 035/112] refactor: alternative track sheet to use shadcn --- lib/modules/player/player.dart | 402 ++++++++++--------- lib/modules/player/player_actions.dart | 62 ++- lib/modules/player/sibling_tracks_sheet.dart | 257 ++++++------ 3 files changed, 378 insertions(+), 343 deletions(-) diff --git a/lib/modules/player/player.dart b/lib/modules/player/player.dart index 0c915b08..16ee6c72 100644 --- a/lib/modules/player/player.dart +++ b/lib/modules/player/player.dart @@ -98,223 +98,229 @@ class PlayerView extends HookConsumerWidget { onPopInvoked: (didPop) async { await panelController.close(); }, - child: Scaffold( - headers: [ - SafeArea( - child: TitleBar( - surfaceOpacity: 0, - surfaceBlur: 0, - leading: [ - IconButton.ghost( - icon: const Icon(SpotubeIcons.angleDown, size: 18), - onPressed: panelController.close, - ) - ], - trailing: [ - if (currentTrack is YoutubeSourcedTrack) - TextButton( - leading: Assets.logos.songlinkTransparent.image( - width: 20, - height: 20, - color: theme.colorScheme.foreground, - ), - onPressed: () { - final url = "https://song.link/s/${currentTrack.id}"; + child: SurfaceCard( + borderWidth: 0, + surfaceOpacity: 0.9, + padding: EdgeInsets.zero, + child: Scaffold( + backgroundColor: Colors.transparent, + headers: [ + SafeArea( + child: TitleBar( + surfaceOpacity: 0, + surfaceBlur: 0, + leading: [ + IconButton.ghost( + icon: const Icon(SpotubeIcons.angleDown, size: 18), + onPressed: panelController.close, + ) + ], + trailing: [ + if (currentTrack is YoutubeSourcedTrack) + TextButton( + leading: Assets.logos.songlinkTransparent.image( + width: 20, + height: 20, + color: theme.colorScheme.foreground, + ), + onPressed: () { + final url = "https://song.link/s/${currentTrack.id}"; - launchUrlString(url); - }, - child: Text(context.l10n.song_link), - ), - Tooltip( - tooltip: TooltipContainer( - child: Text(context.l10n.details), - ), - child: IconButton.ghost( - icon: const Icon(SpotubeIcons.info, size: 18), - onPressed: currentTrack == null - ? null - : () { - showDialog( - context: context, - builder: (context) { - return TrackDetailsDialog( - track: currentTrack, - ); - }); - }, - ), - ) - ], + launchUrlString(url); + }, + child: Text(context.l10n.song_link), + ), + Tooltip( + tooltip: TooltipContainer( + child: Text(context.l10n.details), + ), + child: IconButton.ghost( + icon: const Icon(SpotubeIcons.info, size: 18), + onPressed: currentTrack == null + ? null + : () { + showDialog( + context: context, + builder: (context) { + return TrackDetailsDialog( + track: currentTrack, + ); + }); + }, + ), + ) + ], + ), ), - ), - ], - child: SingleChildScrollView( - controller: scrollController, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - children: [ - Container( - margin: const EdgeInsets.all(8), - constraints: - const BoxConstraints(maxHeight: 300, maxWidth: 300), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - boxShadow: [ - BoxShadow( - color: Colors.black.withAlpha(100), - spreadRadius: 2, - blurRadius: 10, - offset: Offset.zero, + ], + child: SingleChildScrollView( + controller: scrollController, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + children: [ + Container( + margin: const EdgeInsets.all(8), + constraints: + const BoxConstraints(maxHeight: 300, maxWidth: 300), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + boxShadow: [ + BoxShadow( + color: Colors.black.withAlpha(100), + spreadRadius: 2, + blurRadius: 10, + offset: Offset.zero, + ), + ], + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(20), + child: UniversalImage( + path: albumArt, + placeholder: Assets.albumPlaceholder.path, + fit: BoxFit.cover, ), - ], - ), - child: ClipRRect( - borderRadius: BorderRadius.circular(20), - child: UniversalImage( - path: albumArt, - placeholder: Assets.albumPlaceholder.path, - fit: BoxFit.cover, ), ), - ), - const SizedBox(height: 60), - Container( - padding: const EdgeInsets.symmetric(horizontal: 16), - alignment: Alignment.centerLeft, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - AutoSizeText( - currentTrack?.name ?? context.l10n.not_playing, - style: const TextStyle(fontSize: 22), - maxFontSize: 22, - maxLines: 1, - textAlign: TextAlign.start, - ), - if (isLocalTrack) - Text( - currentTrack.artists?.asString() ?? "", - style: theme.typography.normal - .copyWith(fontWeight: FontWeight.bold), - ) - else - ArtistLink( - artists: currentTrack?.artists ?? [], - textStyle: theme.typography.normal - .copyWith(fontWeight: FontWeight.bold), - onRouteChange: (route) { - panelController.close(); - GoRouter.of(context).push(route); - }, - onOverflowArtistClick: () => ServiceUtils.pushNamed( - context, - TrackPage.name, - pathParameters: { - "id": currentTrack!.id!, - }, - ), + const SizedBox(height: 60), + Container( + padding: const EdgeInsets.symmetric(horizontal: 16), + alignment: Alignment.centerLeft, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AutoSizeText( + currentTrack?.name ?? context.l10n.not_playing, + style: const TextStyle(fontSize: 22), + maxFontSize: 22, + maxLines: 1, + textAlign: TextAlign.start, ), - ], - ), - ), - const SizedBox(height: 10), - const PlayerControls(), - const SizedBox(height: 25), - const PlayerActions( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - showQueue: false, - ), - const SizedBox(height: 10), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - const SizedBox(width: 10), - Expanded( - child: OutlineButton( - leading: const Icon(SpotubeIcons.queue), - child: Text(context.l10n.queue), - onPressed: () { - openDrawer( - context: context, - barrierDismissible: true, - draggable: true, - barrierColor: Colors.black.withAlpha(100), - borderRadius: BorderRadius.circular(10), - transformBackdrop: false, - position: OverlayPosition.bottom, - surfaceBlur: context.theme.surfaceBlur, - surfaceOpacity: 0.7, - expands: true, - builder: (context) => Consumer( - builder: (context, ref, _) { - final playlist = ref.watch( - audioPlayerProvider, - ); - final playlistNotifier = - ref.read(audioPlayerProvider.notifier); - return ConstrainedBox( - constraints: BoxConstraints( - maxHeight: - MediaQuery.of(context).size.height * - 0.8, - ), - child: PlayerQueue.fromAudioPlayerNotifier( - floating: false, - playlist: playlist, - notifier: playlistNotifier, - ), - ); + if (isLocalTrack) + Text( + currentTrack.artists?.asString() ?? "", + style: theme.typography.normal + .copyWith(fontWeight: FontWeight.bold), + ) + else + ArtistLink( + artists: currentTrack?.artists ?? [], + textStyle: theme.typography.normal + .copyWith(fontWeight: FontWeight.bold), + onRouteChange: (route) { + panelController.close(); + GoRouter.of(context).push(route); + }, + onOverflowArtistClick: () => ServiceUtils.pushNamed( + context, + TrackPage.name, + pathParameters: { + "id": currentTrack!.id!, }, ), - ); - }, - ), + ), + ], ), - if (auth.asData?.value != null) const SizedBox(width: 10), - if (auth.asData?.value != null) + ), + const SizedBox(height: 10), + const PlayerControls(), + const SizedBox(height: 25), + const PlayerActions( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + showQueue: false, + ), + const SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + const SizedBox(width: 10), Expanded( child: OutlineButton( - leading: const Icon(SpotubeIcons.music), - child: Text(context.l10n.lyrics), + leading: const Icon(SpotubeIcons.queue), + child: Text(context.l10n.queue), onPressed: () { - showModalBottomSheet( + openDrawer( context: context, - isDismissible: true, - enableDrag: true, - isScrollControlled: true, - backgroundColor: Colors.black.withAlpha(100), + barrierDismissible: true, + draggable: true, barrierColor: Colors.black.withAlpha(100), - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(20), - topRight: Radius.circular(20), - ), + borderRadius: BorderRadius.circular(10), + transformBackdrop: false, + position: OverlayPosition.bottom, + surfaceBlur: context.theme.surfaceBlur, + surfaceOpacity: 0.7, + expands: true, + builder: (context) => Consumer( + builder: (context, ref, _) { + final playlist = ref.watch( + audioPlayerProvider, + ); + final playlistNotifier = + ref.read(audioPlayerProvider.notifier); + return ConstrainedBox( + constraints: BoxConstraints( + maxHeight: + MediaQuery.of(context).size.height * + 0.8, + ), + child: PlayerQueue.fromAudioPlayerNotifier( + floating: false, + playlist: playlist, + notifier: playlistNotifier, + ), + ); + }, ), - builder: (context) => - const LyricsPage(isModal: true), ); }, ), ), - const SizedBox(width: 10), - ], - ), - const SizedBox(height: 25), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: Consumer(builder: (context, ref, _) { - final volume = ref.watch(volumeProvider); - return VolumeSlider( - fullWidth: true, - value: volume, - onChanged: (value) { - ref.read(volumeProvider.notifier).setVolume(value); - }, - ); - }), - ), - ], + if (auth.asData?.value != null) const SizedBox(width: 10), + if (auth.asData?.value != null) + Expanded( + child: OutlineButton( + leading: const Icon(SpotubeIcons.music), + child: Text(context.l10n.lyrics), + onPressed: () { + showModalBottomSheet( + context: context, + isDismissible: true, + enableDrag: true, + isScrollControlled: true, + backgroundColor: Colors.black.withAlpha(100), + barrierColor: Colors.black.withAlpha(100), + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(20), + topRight: Radius.circular(20), + ), + ), + builder: (context) => + const LyricsPage(isModal: true), + ); + }, + ), + ), + const SizedBox(width: 10), + ], + ), + const SizedBox(height: 25), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Consumer(builder: (context, ref, _) { + final volume = ref.watch(volumeProvider); + return VolumeSlider( + fullWidth: true, + value: volume, + onChanged: (value) { + ref.read(volumeProvider.notifier).setVolume(value); + }, + ); + }), + ), + ], + ), ), ), ), diff --git a/lib/modules/player/player_actions.dart b/lib/modules/player/player_actions.dart index 12965da4..584af70d 100644 --- a/lib/modules/player/player_actions.dart +++ b/lib/modules/player/player_actions.dart @@ -5,6 +5,7 @@ import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/modules/player/player_queue.dart'; import 'package:spotube/modules/player/sibling_tracks_sheet.dart'; import 'package:spotube/components/adaptive/adaptive_pop_sheet_list.dart'; @@ -118,23 +119,54 @@ class PlayerActions extends HookConsumerWidget { tooltip: TooltipContainer( child: Text(context.l10n.alternative_track_sources)), child: IconButton.ghost( + enabled: playlist.activeTrack != null, icon: const Icon(SpotubeIcons.alternativeRoute), - onPressed: playlist.activeTrack != null - ? () { - openDrawer( - context: context, - position: OverlayPosition.bottom, - barrierDismissible: true, - draggable: true, - barrierColor: Colors.black.withValues(alpha: .2), - borderRadius: BorderRadius.circular(10), - transformBackdrop: false, - builder: (context) { - return SiblingTracksSheet(floating: floatingQueue); - }, + onPressed: () { + final screenSize = MediaQuery.sizeOf(context); + if (screenSize.mdAndUp) { + showPopover( + alignment: Alignment.bottomCenter, + context: context, + builder: (context) { + return SurfaceCard( + padding: EdgeInsets.zero, + child: ConstrainedBox( + constraints: const BoxConstraints( + maxHeight: 600, + maxWidth: 500, + ), + child: SiblingTracksSheet(floating: floatingQueue), + ), ); - } - : null, + }, + ); + } else { + openDrawer( + context: context, + position: OverlayPosition.bottom, + barrierDismissible: true, + draggable: true, + barrierColor: Colors.black.withValues(alpha: .2), + borderRadius: BorderRadius.circular(10), + transformBackdrop: false, + surfaceBlur: context.theme.surfaceBlur, + surfaceOpacity: context.theme.surfaceOpacity, + builder: (context) { + return Card( + borderWidth: 0, + borderColor: Colors.transparent, + padding: EdgeInsets.zero, + child: ConstrainedBox( + constraints: BoxConstraints( + maxHeight: screenSize.height * .8, + ), + child: SiblingTracksSheet(floating: floatingQueue), + ), + ); + }, + ); + } + }, ), ), if (!kIsWeb && !isLocalTrack) diff --git a/lib/modules/player/sibling_tracks_sheet.dart b/lib/modules/player/sibling_tracks_sheet.dart index 3a31d88e..9bd1ea22 100644 --- a/lib/modules/player/sibling_tracks_sheet.dart +++ b/lib/modules/player/sibling_tracks_sheet.dart @@ -1,16 +1,15 @@ -import 'dart:ui'; - import 'package:collection/collection.dart'; -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart' show ListTile, Material, MaterialType; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/collections/assets.gen.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/components/inter_scrollbar/inter_scrollbar.dart'; import 'package:spotube/extensions/artist_simple.dart'; -import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/duration.dart'; import 'package:spotube/hooks/utils/use_debounce.dart'; @@ -152,13 +151,6 @@ class SiblingTracksSheet extends HookConsumerWidget { [activeTrack, isFetchingActiveTrack], ); - final borderRadius = floating - ? BorderRadius.circular(10) - : const BorderRadius.only( - topLeft: Radius.circular(10), - topRight: Radius.circular(10), - ); - useEffect(() { if (activeTrack is SourcedTrack && activeTrack.siblings.isEmpty) { activeTrackNotifier.populateSibling(); @@ -170,9 +162,17 @@ class SiblingTracksSheet extends HookConsumerWidget { (SourceInfo sourceInfo) { final icon = sourceInfoToIconMap[sourceInfo.runtimeType]; return ListTile( + hoverColor: theme.colorScheme.primary.withOpacity(.1), + dense: true, + subtitleTextStyle: theme.typography.small.copyWith( + color: theme.colorScheme.mutedForeground, + ), + titleTextStyle: theme.typography.normal, + leadingAndTrailingTextStyle: theme.typography.normal, title: Text(sourceInfo.title), + horizontalTitleGap: 0, leading: Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.only(top: 8.0, right: 8.0), child: UniversalImage( path: sourceInfo.thumbnail, height: 60, @@ -192,12 +192,13 @@ class SiblingTracksSheet extends HookConsumerWidget { enabled: !isFetchingActiveTrack, selected: !isFetchingActiveTrack && sourceInfo.id == (activeTrack as SourcedTrack).sourceInfo.id, - selectedTileColor: theme.popupMenuTheme.color, + selectedTileColor: theme.colorScheme.primary.withOpacity(.1), + selectedColor: theme.colorScheme.primary, onTap: () { if (!isFetchingActiveTrack && sourceInfo.id != (activeTrack as SourcedTrack).sourceInfo.id) { activeTrackNotifier.swapSibling(sourceInfo); - Navigator.of(context).pop(); + closeDrawer(context); } }, ); @@ -205,131 +206,127 @@ class SiblingTracksSheet extends HookConsumerWidget { [activeTrack, siblings], ); - final mediaQuery = MediaQuery.of(context); - return SafeArea( - child: ClipRRect( - borderRadius: borderRadius, - clipBehavior: Clip.hardEdge, - child: BackdropFilter( - filter: ImageFilter.blur( - sigmaX: 12.0, - sigmaY: 12.0, - ), - child: AnimatedSize( - duration: const Duration(milliseconds: 300), - child: Container( - height: isSearching.value && mediaQuery.smAndDown - ? mediaQuery.size.height - 50 - : mediaQuery.size.height * .6, - decoration: BoxDecoration( - borderRadius: borderRadius, - color: - theme.colorScheme.surfaceContainerHighest.withOpacity(.5), - ), - child: Scaffold( - backgroundColor: Colors.transparent, - appBar: AppBar( - centerTitle: true, - title: AnimatedSwitcher( - duration: const Duration(milliseconds: 300), - child: !isSearching.value - ? Text( - context.l10n.alternative_track_sources, - style: theme.textTheme.headlineSmall, - ) - : TextField( - autofocus: true, - controller: searchController, - decoration: InputDecoration( - hintText: context.l10n.search, - hintStyle: theme.textTheme.headlineSmall, - border: InputBorder.none, - ), - style: theme.textTheme.headlineSmall, - ), - ), - automaticallyImplyLeading: false, - backgroundColor: Colors.transparent, - actions: [ - if (!isSearching.value) - IconButton( - icon: const Icon(SpotubeIcons.search, size: 18), - onPressed: () { - isSearching.value = true; - }, - ) - else ...[ - if (preferences.audioSource == AudioSource.piped) - PopupMenuButton( - icon: const Icon(SpotubeIcons.filter, size: 18), - onSelected: (SearchMode mode) { - searchMode.value = mode; - }, - initialValue: searchMode.value, - itemBuilder: (context) => SearchMode.values - .map( - (e) => PopupMenuItem( - value: e, - child: Text(e.label), - ), - ) - .toList(), - ), - IconButton( - icon: const Icon(SpotubeIcons.close, size: 18), - onPressed: () { - isSearching.value = false; - }, - ), - ] - ], - ), - body: Padding( - padding: const EdgeInsets.all(8.0), - child: AnimatedSwitcher( - duration: const Duration(milliseconds: 300), - transitionBuilder: (child, animation) => - FadeTransition(opacity: animation, child: child), - child: InterScrollbar( - controller: controller, - child: switch (isSearching.value) { - false => ListView.builder( - controller: controller, - itemCount: siblings.length, - itemBuilder: (context, index) => - itemBuilder(siblings[index]), - ), - true => FutureBuilder( - future: searchRequest, - builder: (context, snapshot) { - if (snapshot.hasError) { - return Center( - child: Text(snapshot.error.toString()), - ); - } else if (!snapshot.hasData) { - return const Center( - child: CircularProgressIndicator()); - } + final scale = context.theme.scaling; - return InterScrollbar( - controller: controller, - child: ListView.builder( - controller: controller, - itemCount: snapshot.data!.length, - itemBuilder: (context, index) => - itemBuilder(snapshot.data![index]), - ), - ); - }, + return SafeArea( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 16), + child: Row( + spacing: 5, + children: [ + AnimatedSwitcher( + duration: const Duration(milliseconds: 300), + child: !isSearching.value + ? Text( + context.l10n.alternative_track_sources, + style: theme.typography.bold, + ) + : Flexible( + child: ConstrainedBox( + constraints: BoxConstraints( + maxWidth: 320 * scale, + maxHeight: 38 * scale, + ), + child: TextField( + autofocus: true, + controller: searchController, + placeholder: Text(context.l10n.search), + style: theme.typography.bold, + ), ), + ), + ), + const Spacer(), + if (!isSearching.value) + IconButton.outline( + icon: const Icon(SpotubeIcons.search, size: 18), + onPressed: () { + isSearching.value = true; + }, + ) + else ...[ + if (preferences.audioSource == AudioSource.piped) + IconButton.outline( + icon: const Icon(SpotubeIcons.filter, size: 18), + onPressed: () { + showPopover( + context: context, + alignment: Alignment.bottomRight, + builder: (context) { + return DropdownMenu( + children: SearchMode.values + .map( + (e) => MenuButton( + onPressed: (context) { + searchMode.value = e; + }, + enabled: searchMode.value != e, + child: Text(e.label), + ), + ) + .toList(), + ); + }, + ); }, ), + IconButton.outline( + icon: const Icon(SpotubeIcons.close, size: 18), + onPressed: () { + isSearching.value = false; + }, ), + ] + ], + ), + ), + Expanded( + child: AnimatedSwitcher( + duration: const Duration(milliseconds: 300), + transitionBuilder: (child, animation) => + FadeTransition(opacity: animation, child: child), + child: InterScrollbar( + controller: controller, + child: Material( + type: MaterialType.transparency, + child: switch (isSearching.value) { + false => ListView.builder( + padding: const EdgeInsets.all(8.0), + controller: controller, + itemCount: siblings.length, + itemBuilder: (context, index) => + itemBuilder(siblings[index]), + ), + true => FutureBuilder( + future: searchRequest, + builder: (context, snapshot) { + if (snapshot.hasError) { + return Center( + child: Text(snapshot.error.toString()), + ); + } else if (!snapshot.hasData) { + return const Center( + child: CircularProgressIndicator()); + } + + return ListView.builder( + padding: const EdgeInsets.all(8.0), + controller: controller, + itemCount: snapshot.data!.length, + itemBuilder: (context, index) => + itemBuilder(snapshot.data![index]), + ); + }, + ), + }, ), ), ), ), - ), + ], ), ); } From 780f5dee2e01316e127047e8d277e6d6820c2845 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 4 Jan 2025 20:34:42 +0600 Subject: [PATCH 036/112] cd: upgrade flutter version to 3.28.0-0.1.pre --- .github/workflows/spotube-release-binary.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index 6a1c713f..eb251d2a 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -20,7 +20,8 @@ on: description: Dry run without uploading to release env: - FLUTTER_VERSION: 3.27.0 + FLUTTER_VERSION: 3.28.0-0.1.pre + FLUTTER_CHANNEL: beta permissions: contents: write @@ -68,6 +69,7 @@ jobs: cache: true cache-key: ${{ runner.os }}-flutter-${{ hashFiles('**/pubspec.yaml') }} flutter-version: ${{ env.FLUTTER_VERSION }} + channel: ${{ env.FLUTTER_CHANNEL }} - name: Setup Java if: ${{matrix.platform == 'android'}} uses: actions/setup-java@v4 From af295be8c62962f01f82c7def787e4cf6f4c5329 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 4 Jan 2025 23:31:09 +0600 Subject: [PATCH 037/112] refactor: remote playback page to shadcn --- lib/components/titlebar/titlebar.dart | 19 ++ lib/components/ui/button_tile.dart | 95 ++++++++ lib/l10n/app_en.arb | 1 + lib/modules/connect/local_devices.dart | 22 +- lib/modules/player/player_queue.dart | 2 +- lib/pages/connect/connect.dart | 129 +++++------ lib/pages/connect/control/control.dart | 306 ++++++++++++++----------- untranslated_messages.json | 26 +++ 8 files changed, 385 insertions(+), 215 deletions(-) create mode 100644 lib/components/ui/button_tile.dart diff --git a/lib/components/titlebar/titlebar.dart b/lib/components/titlebar/titlebar.dart index 5c3f7940..cba33ab4 100644 --- a/lib/components/titlebar/titlebar.dart +++ b/lib/components/titlebar/titlebar.dart @@ -1,3 +1,4 @@ +import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/components/button/back_button.dart'; @@ -60,6 +61,7 @@ class TitleBar extends HookConsumerWidget implements PreferredSizeWidget { @override Widget build(BuildContext context, ref) { final hasLeadingOrCanPop = leading.isNotEmpty || Navigator.canPop(context); + final lastClicked = useRef(DateTime.now().millisecondsSinceEpoch); return SizedBox( height: height ?? 56, @@ -71,6 +73,23 @@ class TitleBar extends HookConsumerWidget implements PreferredSizeWidget { return GestureDetector( onHorizontalDragStart: (_) => onDrag(ref), onVerticalDragStart: (_) => onDrag(ref), + onTapDown: (details) async { + final systemTitlebar = ref.read( + userPreferencesProvider.select((s) => s.systemTitleBar)); + if (!kIsDesktop || systemTitlebar) return; + + int currMills = DateTime.now().millisecondsSinceEpoch; + + if ((currMills - lastClicked.value) < 500) { + if (await windowManager.isMaximized()) { + await windowManager.unmaximize(); + } else { + await windowManager.maximize(); + } + } else { + lastClicked.value = currMills; + } + }, child: AppBar( leading: leading.isEmpty && automaticallyImplyLeading && diff --git a/lib/components/ui/button_tile.dart b/lib/components/ui/button_tile.dart new file mode 100644 index 00000000..d865b583 --- /dev/null +++ b/lib/components/ui/button_tile.dart @@ -0,0 +1,95 @@ +import 'package:shadcn_flutter/shadcn_flutter.dart'; + +class ButtonTile extends StatelessWidget { + final Widget? title; + final Widget? subtitle; + final Widget? leading; + final Widget? trailing; + final bool enabled; + final void Function()? onPressed; + final bool selected; + final ButtonVariance style; + + const ButtonTile({ + super.key, + this.title, + this.subtitle, + this.leading, + this.trailing, + this.enabled = true, + this.onPressed, + this.selected = false, + this.style = ButtonVariance.outline, + }); + + @override + Widget build(BuildContext context) { + final ThemeData(:colorScheme, :typography) = Theme.of(context); + + return Button( + enabled: enabled, + onPressed: onPressed, + style: style.copyWith( + decoration: (context, states, value) { + final decoration = ButtonVariance.outline.decoration(context, states) + as BoxDecoration; + + if (selected && style == ButtonVariance.outline) { + return decoration.copyWith( + border: Border.all( + color: colorScheme.primary, + width: 1.0, + ), + color: colorScheme.primary.withAlpha(25), + ); + } + + return decoration; + }, + iconTheme: (context, states, value) { + final iconTheme = ButtonVariance.outline.iconTheme(context, states); + + if (selected && style == ButtonVariance.outline) { + return iconTheme.copyWith( + color: colorScheme.primary, + ); + } + + return iconTheme; + }, + textStyle: (context, states, value) { + final textStyle = ButtonVariance.outline.textStyle(context, states); + + if (selected && style == ButtonVariance.outline) { + return textStyle.copyWith( + color: colorScheme.primary, + ); + } + + return textStyle; + }, + ), + alignment: Alignment.centerLeft, + child: SizedBox( + width: double.infinity, + child: Basic( + padding: EdgeInsets.zero, + leadingAlignment: Alignment.center, + trailingAlignment: Alignment.center, + leading: leading, + title: title, + subtitle: + style == ButtonVariance.outline && selected && subtitle != null + ? DefaultTextStyle( + style: typography.xSmall.copyWith( + color: colorScheme.primary, + ), + child: subtitle!, + ) + : subtitle, + trailing: trailing, + ), + ), + ); + } +} diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 4109edb7..0be79bda 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -97,6 +97,7 @@ "pause_playback": "Pause Playback", "resume_playback": "Resume Playback", "loop_track": "Loop track", + "no_loop": "No loop", "repeat_playlist": "Repeat playlist", "queue": "Queue", "alternative_track_sources": "Alternative track sources", diff --git a/lib/modules/connect/local_devices.dart b/lib/modules/connect/local_devices.dart index dd7db971..138e9e13 100644 --- a/lib/modules/connect/local_devices.dart +++ b/lib/modules/connect/local_devices.dart @@ -1,7 +1,7 @@ -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:gap/gap.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/ui/button_tile.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/services/audio_player/audio_player.dart'; @@ -10,7 +10,7 @@ class ConnectPageLocalDevices extends HookWidget { @override Widget build(BuildContext context) { - final ThemeData(:textTheme) = Theme.of(context); + final ThemeData(:typography) = Theme.of(context); final devicesFuture = useFuture(audioPlayer.devices); final devicesStream = useStream(audioPlayer.devicesStream); final selectedDeviceFuture = useFuture(audioPlayer.selectedDevice); @@ -32,7 +32,7 @@ class ConnectPageLocalDevices extends HookWidget { sliver: SliverToBoxAdapter( child: Text( context.l10n.this_device, - style: textTheme.titleMedium, + style: typography.bold, ), ), ), @@ -43,14 +43,12 @@ class ConnectPageLocalDevices extends HookWidget { itemBuilder: (context, index) { final device = devices[index]; - return Card( - child: ListTile( - leading: const Icon(SpotubeIcons.speaker), - title: Text(device.description), - subtitle: Text(device.name), - selected: selectedDevice == device, - onTap: () => audioPlayer.setAudioDevice(device), - ), + return ButtonTile( + selected: selectedDevice == device, + onPressed: () => audioPlayer.setAudioDevice(device), + leading: const Icon(SpotubeIcons.speaker), + title: Text(device.description), + subtitle: Text(device.name), ); }, ), diff --git a/lib/modules/player/player_queue.dart b/lib/modules/player/player_queue.dart index cdda39da..a91c883d 100644 --- a/lib/modules/player/player_queue.dart +++ b/lib/modules/player/player_queue.dart @@ -224,7 +224,7 @@ class PlayerQueue extends HookConsumerWidget { ); }, ), - const SliverGap(100), + const SliverSafeArea(sliver: SliverGap(100)), ], ), ), diff --git a/lib/pages/connect/connect.dart b/lib/pages/connect/connect.dart index 1a5dfb31..55c72026 100644 --- a/lib/pages/connect/connect.dart +++ b/lib/pages/connect/connect.dart @@ -1,7 +1,7 @@ -import 'package:flutter/material.dart'; -import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/ui/button_tile.dart'; import 'package:spotube/modules/connect/local_devices.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/extensions/context.dart'; @@ -16,79 +16,74 @@ class ConnectPage extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final ThemeData(:colorScheme, :textTheme) = Theme.of(context); + final ThemeData(:colorScheme, :typography) = Theme.of(context); final connectClients = ref.watch(connectClientsProvider); final connectClientsNotifier = ref.read(connectClientsProvider.notifier); final discoveredDevices = connectClients.asData?.value.services; return Scaffold( - appBar: TitleBar( - automaticallyImplyLeading: true, - title: Text(context.l10n.devices), - ), - body: ListTileTheme( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ), - selectedTileColor: colorScheme.secondary.withOpacity(0.1), - child: Padding( - padding: const EdgeInsets.all(10.0), - child: CustomScrollView( - slivers: [ - SliverPadding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - sliver: SliverToBoxAdapter( - child: Text( - context.l10n.remote, - style: textTheme.titleMedium, - ), + headers: [ + TitleBar( + automaticallyImplyLeading: true, + title: Text(context.l10n.devices), + ) + ], + child: Padding( + padding: const EdgeInsets.all(10.0), + child: CustomScrollView( + slivers: [ + SliverPadding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + sliver: SliverToBoxAdapter( + child: Text( + context.l10n.remote, + style: typography.bold, ), ), - const SliverGap(10), - SliverList.separated( - itemCount: discoveredDevices?.length ?? 0, - separatorBuilder: (context, index) => const Gap(10), - itemBuilder: (context, index) { - final device = discoveredDevices![index]; - final selected = - connectClients.asData?.value.resolvedService?.name == - device.name; - return Card( - child: ListTile( - leading: const Icon(SpotubeIcons.monitor), - title: Text(device.name), - subtitle: selected - ? Text( - "${connectClients.asData?.value.resolvedService?.host}" - ":${connectClients.asData?.value.resolvedService?.port}", - ) - : null, - selected: selected, - onTap: () { - if (selected) { - ServiceUtils.pushNamed( - context, - ConnectControlPage.name, - ); - } else { - connectClientsNotifier.resolveService(device); - } - }, - trailing: selected - ? IconButton( - icon: const Icon(SpotubeIcons.power), - onPressed: () => - connectClientsNotifier.clearResolvedService(), - ) - : null, - ), - ); - }, - ), - const ConnectPageLocalDevices(), - ], - ), + ), + const SliverGap(10), + SliverList.separated( + itemCount: discoveredDevices?.length ?? 0, + separatorBuilder: (context, index) => const Gap(10), + itemBuilder: (context, index) { + final device = discoveredDevices![index]; + final selected = + connectClients.asData?.value.resolvedService?.name == + device.name; + return ButtonTile( + selected: selected, + leading: const Icon(SpotubeIcons.monitor), + title: Text(device.name), + subtitle: selected + ? Text( + "${connectClients.asData?.value.resolvedService?.host}" + ":${connectClients.asData?.value.resolvedService?.port}", + ) + : null, + trailing: selected + ? IconButton.outline( + icon: const Icon(SpotubeIcons.power), + size: ButtonSize.small, + onPressed: () => + connectClientsNotifier.clearResolvedService(), + ) + : null, + onPressed: () { + if (selected) { + ServiceUtils.pushNamed( + context, + ConnectControlPage.name, + ); + } else { + connectClientsNotifier.resolveService(device); + } + }, + ); + }, + ), + const ConnectPageLocalDevices(), + ], ), ), ); diff --git a/lib/pages/connect/control/control.dart b/lib/pages/connect/control/control.dart index 03406546..b92a5482 100644 --- a/lib/pages/connect/control/control.dart +++ b/lib/pages/connect/control/control.dart @@ -1,7 +1,7 @@ -import 'package:flutter/material.dart'; -import 'package:gap/gap.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/modules/player/player_queue.dart'; import 'package:spotube/modules/player/volume_slider.dart'; @@ -53,7 +53,7 @@ class ConnectControlPage extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final ThemeData(:textTheme, :colorScheme) = Theme.of(context); + final ThemeData(:typography, :colorScheme) = Theme.of(context); final resolvedService = ref.watch(connectClientsProvider).asData?.value.resolvedService; @@ -63,23 +63,6 @@ class ConnectControlPage extends HookConsumerWidget { final shuffled = ref.watch(shuffleProvider); final loopMode = ref.watch(loopModeProvider); - final resumePauseStyle = IconButton.styleFrom( - backgroundColor: colorScheme.primary, - foregroundColor: colorScheme.onPrimary, - padding: const EdgeInsets.all(12), - iconSize: 24, - ); - final buttonStyle = IconButton.styleFrom( - backgroundColor: colorScheme.surface.withOpacity(0.4), - minimumSize: const Size(28, 28), - ); - - final activeButtonStyle = IconButton.styleFrom( - backgroundColor: colorScheme.primaryContainer, - foregroundColor: colorScheme.onPrimaryContainer, - minimumSize: const Size(28, 28), - ); - ref.listen(connectClientsProvider, (prev, next) { if (next.asData?.value.resolvedService == null) { context.pop(); @@ -87,12 +70,15 @@ class ConnectControlPage extends HookConsumerWidget { }); return SafeArea( + bottom: false, child: Scaffold( - appBar: TitleBar( - title: Text(resolvedService!.name), - automaticallyImplyLeading: true, - ), - body: LayoutBuilder(builder: (context, constrains) { + headers: [ + TitleBar( + title: Text(resolvedService!.name), + automaticallyImplyLeading: true, + ) + ], + child: LayoutBuilder(builder: (context, constrains) { return Row( children: [ Expanded( @@ -106,7 +92,7 @@ class ConnectControlPage extends HookConsumerWidget { vertical: 10, ).copyWith(top: 0), constraints: - const BoxConstraints(maxHeight: 400, maxWidth: 400), + const BoxConstraints(maxHeight: 350, maxWidth: 350), child: ClipRRect( borderRadius: BorderRadius.circular(20), child: UniversalImage( @@ -126,7 +112,7 @@ class ConnectControlPage extends HookConsumerWidget { SliverToBoxAdapter( child: AnchorButton( playlist.activeTrack?.name ?? "", - style: textTheme.titleLarge!, + style: typography.h4, onTap: () { if (playlist.activeTrack == null) return; ServiceUtils.pushNamed( @@ -142,7 +128,7 @@ class ConnectControlPage extends HookConsumerWidget { SliverToBoxAdapter( child: ArtistLink( artists: playlist.activeTrack?.artists ?? [], - textStyle: textTheme.bodyMedium!, + textStyle: typography.normal, mainAxisAlignment: WrapAlignment.start, onOverflowArtistClick: () => ServiceUtils.pushNamed( @@ -164,19 +150,25 @@ class ConnectControlPage extends HookConsumerWidget { final position = ref.watch(positionProvider); final duration = ref.watch(durationProvider); + final progress = duration.inSeconds == 0 + ? 0 + : position.inSeconds / duration.inSeconds; + return Padding( padding: const EdgeInsets.symmetric(horizontal: 12), child: Column( children: [ Slider( - value: position > duration - ? 0 - : position.inSeconds.toDouble(), - min: 0, - max: duration.inSeconds.toDouble(), + value: + SliderValue.single(progress.toDouble()), onChanged: (value) { - connectNotifier - .seek(Duration(seconds: value.toInt())); + connectNotifier.seek( + Duration( + seconds: + (value.value * duration.inSeconds) + .toInt(), + ), + ); }, ), Row( @@ -197,93 +189,155 @@ class ConnectControlPage extends HookConsumerWidget { child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - IconButton( - tooltip: shuffled - ? context.l10n.unshuffle_playlist - : context.l10n.shuffle_playlist, - icon: const Icon(SpotubeIcons.shuffle), - style: shuffled ? activeButtonStyle : buttonStyle, - onPressed: playlist.activeTrack == null - ? null - : () { - connectNotifier.setShuffle(!shuffled); - }, - ), - IconButton( - tooltip: context.l10n.previous_track, - icon: const Icon(SpotubeIcons.skipBack), - onPressed: playlist.activeTrack == null - ? null - : connectNotifier.previous, - ), - IconButton( - tooltip: playing - ? context.l10n.pause_playback - : context.l10n.resume_playback, - icon: playlist.activeTrack == null - ? SizedBox( - height: 20, - width: 20, - child: CircularProgressIndicator( - color: colorScheme.onPrimary, - ), - ) - : Icon( - playing - ? SpotubeIcons.pause - : SpotubeIcons.play, - ), - style: resumePauseStyle, - onPressed: playlist.activeTrack == null - ? null - : () { - if (playing) { - connectNotifier.pause(); - } else { - connectNotifier.resume(); - } - }, - ), - IconButton( - tooltip: context.l10n.next_track, - icon: const Icon(SpotubeIcons.skipForward), - onPressed: playlist.activeTrack == null - ? null - : connectNotifier.next, - ), - IconButton( - tooltip: loopMode == PlaylistMode.single - ? context.l10n.loop_track - : loopMode == PlaylistMode.loop - ? context.l10n.repeat_playlist - : null, - icon: Icon( - loopMode == PlaylistMode.single - ? SpotubeIcons.repeatOne - : SpotubeIcons.repeat, + Tooltip( + tooltip: TooltipContainer( + child: Text( + shuffled + ? context.l10n.unshuffle_playlist + : context.l10n.shuffle_playlist, + ), + ), + child: IconButton( + icon: const Icon(SpotubeIcons.shuffle), + variance: shuffled + ? ButtonVariance.secondary + : ButtonVariance.ghost, + onPressed: playlist.activeTrack == null + ? null + : () { + connectNotifier.setShuffle(!shuffled); + }, + ), + ), + Tooltip( + tooltip: TooltipContainer( + child: Text(context.l10n.previous_track), + ), + child: IconButton.ghost( + icon: const Icon(SpotubeIcons.skipBack), + onPressed: playlist.activeTrack == null + ? null + : connectNotifier.previous, + ), + ), + Tooltip( + tooltip: TooltipContainer( + child: Text( + playing + ? context.l10n.pause_playback + : context.l10n.resume_playback, + ), + ), + child: IconButton.primary( + shape: ButtonShape.circle, + icon: playlist.activeTrack == null + ? const SizedBox( + height: 20, + width: 20, + child: CircularProgressIndicator( + onSurface: false), + ) + : Icon( + playing + ? SpotubeIcons.pause + : SpotubeIcons.play, + ), + onPressed: playlist.activeTrack == null + ? null + : () { + if (playing) { + connectNotifier.pause(); + } else { + connectNotifier.resume(); + } + }, + ), + ), + Tooltip( + tooltip: TooltipContainer( + child: Text(context.l10n.next_track)), + child: IconButton.ghost( + icon: const Icon(SpotubeIcons.skipForward), + onPressed: playlist.activeTrack == null + ? null + : connectNotifier.next, + ), + ), + Tooltip( + tooltip: TooltipContainer( + child: Text( + loopMode == PlaylistMode.single + ? context.l10n.loop_track + : loopMode == PlaylistMode.loop + ? context.l10n.repeat_playlist + : context.l10n.no_loop, + ), + ), + child: IconButton( + icon: Icon( + loopMode == PlaylistMode.single + ? SpotubeIcons.repeatOne + : SpotubeIcons.repeat, + ), + variance: loopMode == PlaylistMode.single || + loopMode == PlaylistMode.loop + ? ButtonVariance.secondary + : ButtonVariance.ghost, + onPressed: playlist.activeTrack == null + ? null + : () async { + connectNotifier.setLoopMode( + switch (loopMode) { + PlaylistMode.loop => + PlaylistMode.single, + PlaylistMode.single => + PlaylistMode.none, + PlaylistMode.none => + PlaylistMode.loop, + }, + ); + }, ), - style: loopMode == PlaylistMode.single || - loopMode == PlaylistMode.loop - ? activeButtonStyle - : buttonStyle, - onPressed: playlist.activeTrack == null - ? null - : () async { - connectNotifier.setLoopMode( - switch (loopMode) { - PlaylistMode.loop => - PlaylistMode.single, - PlaylistMode.single => - PlaylistMode.none, - PlaylistMode.none => PlaylistMode.loop, - }, - ); - }, ) ], ), ), const SliverGap(30), + if (constrains.mdAndDown) + SliverPadding( + padding: const EdgeInsets.symmetric(horizontal: 20), + sliver: SliverToBoxAdapter( + child: Button.outline( + leading: const Icon(SpotubeIcons.queue), + child: Text(context.l10n.queue), + onPressed: () { + openDrawer( + context: context, + barrierDismissible: true, + draggable: true, + barrierColor: Colors.black.withAlpha(100), + borderRadius: BorderRadius.circular(10), + transformBackdrop: false, + position: OverlayPosition.bottom, + surfaceBlur: context.theme.surfaceBlur, + surfaceOpacity: 0.7, + expands: true, + builder: (context) { + return ConstrainedBox( + constraints: BoxConstraints( + maxHeight: + MediaQuery.sizeOf(context).height * + 0.8, + ), + child: const RemotePlayerQueue(), + ); + }, + ); + }, + ), + ), + ), + const SliverGap(30), SliverPadding( padding: const EdgeInsets.symmetric(horizontal: 20), sliver: SliverToBoxAdapter( @@ -300,25 +354,7 @@ class ConnectControlPage extends HookConsumerWidget { }), ), ), - const SliverGap(30), - if (constrains.mdAndDown) - SliverPadding( - padding: const EdgeInsets.symmetric(horizontal: 20), - sliver: SliverToBoxAdapter( - child: OutlinedButton.icon( - icon: const Icon(SpotubeIcons.queue), - label: Text(context.l10n.queue), - onPressed: () { - showModalBottomSheet( - context: context, - builder: (context) { - return const RemotePlayerQueue(); - }, - ); - }, - ), - ), - ) + const SliverSafeArea(sliver: SliverGap(10)), ], ), ), diff --git a/untranslated_messages.json b/untranslated_messages.json index 05b5aca3..fae95f00 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -1,5 +1,6 @@ { "ar": [ + "no_loop", "undo", "download_all", "add_all_to_playlist", @@ -9,6 +10,7 @@ ], "bn": [ + "no_loop", "undo", "download_all", "add_all_to_playlist", @@ -18,6 +20,7 @@ ], "ca": [ + "no_loop", "undo", "download_all", "add_all_to_playlist", @@ -27,6 +30,7 @@ ], "cs": [ + "no_loop", "undo", "download_all", "add_all_to_playlist", @@ -36,6 +40,7 @@ ], "de": [ + "no_loop", "undo", "download_all", "add_all_to_playlist", @@ -45,6 +50,7 @@ ], "es": [ + "no_loop", "undo", "download_all", "add_all_to_playlist", @@ -54,6 +60,7 @@ ], "eu": [ + "no_loop", "undo", "download_all", "add_all_to_playlist", @@ -63,6 +70,7 @@ ], "fa": [ + "no_loop", "undo", "download_all", "add_all_to_playlist", @@ -72,6 +80,7 @@ ], "fi": [ + "no_loop", "undo", "download_all", "add_all_to_playlist", @@ -81,6 +90,7 @@ ], "fr": [ + "no_loop", "undo", "download_all", "add_all_to_playlist", @@ -90,6 +100,7 @@ ], "hi": [ + "no_loop", "undo", "download_all", "add_all_to_playlist", @@ -99,6 +110,7 @@ ], "id": [ + "no_loop", "undo", "download_all", "add_all_to_playlist", @@ -108,6 +120,7 @@ ], "it": [ + "no_loop", "undo", "download_all", "add_all_to_playlist", @@ -117,6 +130,7 @@ ], "ja": [ + "no_loop", "undo", "download_all", "add_all_to_playlist", @@ -126,6 +140,7 @@ ], "ka": [ + "no_loop", "undo", "download_all", "add_all_to_playlist", @@ -135,6 +150,7 @@ ], "ko": [ + "no_loop", "undo", "download_all", "add_all_to_playlist", @@ -144,6 +160,7 @@ ], "ne": [ + "no_loop", "undo", "download_all", "add_all_to_playlist", @@ -153,6 +170,7 @@ ], "nl": [ + "no_loop", "undo", "download_all", "add_all_to_playlist", @@ -162,6 +180,7 @@ ], "pl": [ + "no_loop", "undo", "download_all", "add_all_to_playlist", @@ -171,6 +190,7 @@ ], "pt": [ + "no_loop", "undo", "download_all", "add_all_to_playlist", @@ -180,6 +200,7 @@ ], "ru": [ + "no_loop", "undo", "download_all", "add_all_to_playlist", @@ -189,6 +210,7 @@ ], "th": [ + "no_loop", "undo", "download_all", "add_all_to_playlist", @@ -198,6 +220,7 @@ ], "tr": [ + "no_loop", "undo", "download_all", "add_all_to_playlist", @@ -207,6 +230,7 @@ ], "uk": [ + "no_loop", "undo", "download_all", "add_all_to_playlist", @@ -216,6 +240,7 @@ ], "vi": [ + "no_loop", "undo", "download_all", "add_all_to_playlist", @@ -225,6 +250,7 @@ ], "zh": [ + "no_loop", "undo", "download_all", "add_all_to_playlist", From bbad701c074b44594dff3fa8cc96067a91f5f013 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 5 Jan 2025 08:58:57 +0600 Subject: [PATCH 038/112] refactor: dialogs to shadcn dialog --- .../dialogs/confirm_download_dialog.dart | 106 +++++++++--------- lib/components/dialogs/prompt_dialog.dart | 6 +- .../dialogs/replace_downloaded_dialog.dart | 60 +++++----- .../dialogs/select_device_dialog.dart | 53 ++++----- .../presentation_actions.dart | 13 ++- .../use_action_callbacks.dart | 2 + .../use_track_tile_play_callback.dart | 1 + lib/modules/album/album_card.dart | 1 + lib/modules/playlist/playlist_card.dart | 1 + lib/pages/artist/section/top_tracks.dart | 3 + lib/pages/connect/control/control.dart | 1 + lib/pages/search/sections/tracks.dart | 2 + 12 files changed, 124 insertions(+), 125 deletions(-) diff --git a/lib/components/dialogs/confirm_download_dialog.dart b/lib/components/dialogs/confirm_download_dialog.dart index 897c64cb..a2df0e9c 100644 --- a/lib/components/dialogs/confirm_download_dialog.dart +++ b/lib/components/dialogs/confirm_download_dialog.dart @@ -1,5 +1,4 @@ -import 'package:flutter/material.dart'; - +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; @@ -9,13 +8,15 @@ class ConfirmDownloadDialog extends StatelessWidget { @override Widget build(BuildContext context) { - return AlertDialog( - title: Padding( - padding: const EdgeInsets.all(15), - child: Row( + final screenSize = MediaQuery.sizeOf(context); + + return ConstrainedBox( + constraints: BoxConstraints(maxWidth: Breakpoints.sm), + child: AlertDialog( + title: Row( + spacing: 10, children: [ Text(context.l10n.are_you_sure), - const SizedBox(width: 10), const UniversalImage( path: "https://c.tenor.com/kHcmsxlKHEAAAAAM/rock-one-eyebrow-raised-rock-staring.gif", @@ -24,58 +25,53 @@ class ConfirmDownloadDialog extends StatelessWidget { ) ], ), - ), - content: Container( - padding: const EdgeInsets.all(15), - constraints: BoxConstraints(maxWidth: Breakpoints.sm), - child: SingleChildScrollView( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - context.l10n.download_warning, - textAlign: TextAlign.justify, - ), - const SizedBox(height: 10), - Text( - context.l10n.download_ip_ban_warning, - style: const TextStyle( - color: Colors.red, - fontWeight: FontWeight.bold, + content: Expanded( + flex: screenSize.smAndUp ? 0 : 1, + child: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + context.l10n.download_warning, + textAlign: TextAlign.justify, ), - textAlign: TextAlign.justify, - ), - const SizedBox(height: 10), - Text( - context.l10n.by_clicking_accept_terms, - ), - const SizedBox(height: 10), - BulletPoint(context.l10n.download_agreement_1), - const SizedBox(height: 10), - BulletPoint(context.l10n.download_agreement_2), - const SizedBox(height: 10), - BulletPoint(context.l10n.download_agreement_3), - ], + const SizedBox(height: 10), + Text( + context.l10n.download_ip_ban_warning, + style: const TextStyle( + color: Colors.red, + fontWeight: FontWeight.bold, + ), + textAlign: TextAlign.justify, + ), + const SizedBox(height: 10), + Text( + context.l10n.by_clicking_accept_terms, + ), + const SizedBox(height: 10), + BulletPoint(context.l10n.download_agreement_1), + const SizedBox(height: 10), + BulletPoint(context.l10n.download_agreement_2), + const SizedBox(height: 10), + BulletPoint(context.l10n.download_agreement_3), + ], + ), ), ), + actions: [ + Button.outline( + child: Text(context.l10n.decline), + onPressed: () { + Navigator.pop(context, false); + }, + ), + Button.destructive( + onPressed: () => Navigator.of(context).pop(true), + child: Text(context.l10n.accept), + ), + ], ), - actions: [ - OutlinedButton( - child: Text(context.l10n.decline), - onPressed: () { - Navigator.pop(context, false); - }, - ), - FilledButton( - style: FilledButton.styleFrom( - foregroundColor: Colors.white, - backgroundColor: Colors.red, - ), - onPressed: () => Navigator.of(context).pop(true), - child: Text(context.l10n.accept), - ), - ], ); } } diff --git a/lib/components/dialogs/prompt_dialog.dart b/lib/components/dialogs/prompt_dialog.dart index 30a63bcf..3498bf02 100644 --- a/lib/components/dialogs/prompt_dialog.dart +++ b/lib/components/dialogs/prompt_dialog.dart @@ -1,4 +1,4 @@ -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/extensions/context.dart'; Future showPromptDialog({ @@ -16,13 +16,13 @@ Future showPromptDialog({ content: Text(message), actions: [ if (cancelText != null) - OutlinedButton( + Button.outline( onPressed: () => Navigator.of(context).pop(false), child: Text( cancelText == "Cancel" ? context.l10n.cancel : cancelText, ), ), - FilledButton( + Button.primary( child: Text(okText == "Ok" ? context.l10n.ok : okText), onPressed: () => Navigator.of(context).pop(true), ), diff --git a/lib/components/dialogs/replace_downloaded_dialog.dart b/lib/components/dialogs/replace_downloaded_dialog.dart index 00461d34..3a0f3a1d 100644 --- a/lib/components/dialogs/replace_downloaded_dialog.dart +++ b/lib/components/dialogs/replace_downloaded_dialog.dart @@ -1,5 +1,5 @@ -import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/extensions/context.dart'; @@ -13,45 +13,35 @@ class ReplaceDownloadedDialog extends ConsumerWidget { @override Widget build(BuildContext context, ref) { final groupValue = ref.watch(replaceDownloadedFileState); - final theme = Theme.of(context); final replaceAll = ref.watch(replaceDownloadedFileState); return AlertDialog( title: Text(context.l10n.track_exists(track.name ?? "")), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text(context.l10n.do_you_want_to_replace), - RadioListTile( - dense: true, - contentPadding: EdgeInsets.zero, - activeColor: theme.colorScheme.primary, - value: true, - groupValue: groupValue, - onChanged: (value) { - if (value != null) { - ref.read(replaceDownloadedFileState.notifier).state = true; - } - }, - title: Text(context.l10n.replace_downloaded_tracks), - ), - RadioListTile( - dense: true, - contentPadding: EdgeInsets.zero, - activeColor: theme.colorScheme.primary, - value: false, - groupValue: groupValue, - onChanged: (value) { - if (value != null) { - ref.read(replaceDownloadedFileState.notifier).state = false; - } - }, - title: Text(context.l10n.skip_download_tracks), - ), - ], + content: RadioGroup( + value: groupValue, + onChanged: (value) { + ref.read(replaceDownloadedFileState.notifier).state = value; + }, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(context.l10n.do_you_want_to_replace), + const Gap(16), + RadioItem( + value: true, + trailing: Text(context.l10n.replace_downloaded_tracks), + ), + const Gap(8), + RadioItem( + value: false, + trailing: Text(context.l10n.skip_download_tracks), + ), + ], + ), ), actions: [ - OutlinedButton( + Button.outline( onPressed: replaceAll == true ? null : () { @@ -59,7 +49,7 @@ class ReplaceDownloadedDialog extends ConsumerWidget { }, child: Text(context.l10n.skip), ), - FilledButton( + Button.primary( onPressed: replaceAll == false ? null : () { diff --git a/lib/components/dialogs/select_device_dialog.dart b/lib/components/dialogs/select_device_dialog.dart index 3a3bde60..5392a403 100644 --- a/lib/components/dialogs/select_device_dialog.dart +++ b/lib/components/dialogs/select_device_dialog.dart @@ -1,6 +1,6 @@ -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/connect/clients.dart'; @@ -16,31 +16,31 @@ class SelectDeviceDialog extends HookConsumerWidget { return AlertDialog( title: Text(context.l10n.choose_the_device), - insetPadding: const EdgeInsets.all(16), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text(context.l10n.multiple_device_connected), - RadioListTile.adaptive( - title: Text(remoteService.name), - value: true, - groupValue: isRemoteService.value, - onChanged: (value) { - isRemoteService.value = value!; - }, - ), - RadioListTile.adaptive( - title: Text(context.l10n.this_device), - value: false, - groupValue: isRemoteService.value, - onChanged: (value) { - isRemoteService.value = !value!; - }, - ), - ], + content: RadioGroup( + value: isRemoteService.value, + onChanged: (value) { + isRemoteService.value = value; + }, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(context.l10n.multiple_device_connected), + const Gap(16), + RadioItem( + trailing: Text(remoteService.name), + value: true, + ), + const Gap(8), + RadioItem( + trailing: Text(context.l10n.this_device), + value: false, + ), + ], + ), ), actions: [ - TextButton( + Button.primary( onPressed: () { Navigator.of(context).pop(isRemoteService.value); }, @@ -51,7 +51,8 @@ class SelectDeviceDialog extends HookConsumerWidget { } } -Future showSelectDeviceDialog(BuildContext context, WidgetRef ref) async { +Future showSelectDeviceDialog( + BuildContext context, WidgetRef ref) async { final connectClients = ref.read(connectClientsProvider); if (connectClients.asData?.value.resolvedService == null) { @@ -63,5 +64,5 @@ Future showSelectDeviceDialog(BuildContext context, WidgetRef ref) async { builder: (context) => const SelectDeviceDialog(), ); - return isRemote ?? false; + return isRemote; } diff --git a/lib/components/track_presentation/presentation_actions.dart b/lib/components/track_presentation/presentation_actions.dart index 41f518d0..01228524 100644 --- a/lib/components/track_presentation/presentation_actions.dart +++ b/lib/components/track_presentation/presentation_actions.dart @@ -97,12 +97,13 @@ class TrackPresentationActionsSection extends HookConsumerWidget { case "download": { final confirmed = audioSource == AudioSource.piped || - await showDialog( - context: context, - builder: (context) { - return const ConfirmDownloadDialog(); - }, - ); + (await showDialog( + context: context, + builder: (context) { + return const ConfirmDownloadDialog(); + }, + ) ?? + false); if (confirmed != true) return; downloader.batchAddToQueue(tracks); notifier.deselectAllTracks(); diff --git a/lib/components/track_presentation/use_action_callbacks.dart b/lib/components/track_presentation/use_action_callbacks.dart index e9b9c98e..0012594a 100644 --- a/lib/components/track_presentation/use_action_callbacks.dart +++ b/lib/components/track_presentation/use_action_callbacks.dart @@ -40,6 +40,7 @@ UseActionCallbacks useActionCallbacks(WidgetRef ref) { if (!context.mounted) return; final isRemoteDevice = await showSelectDeviceDialog(context, ref); + if (isRemoteDevice == null) return; if (isRemoteDevice) { final allTracks = await options.pagination.onFetchAll(); final remotePlayback = ref.read(connectProvider.notifier); @@ -90,6 +91,7 @@ UseActionCallbacks useActionCallbacks(WidgetRef ref) { if (!context.mounted) return; final isRemoteDevice = await showSelectDeviceDialog(context, ref); + if (isRemoteDevice == null) return; if (isRemoteDevice) { final allTracks = await options.pagination.onFetchAll(); final remotePlayback = ref.read(connectProvider.notifier); diff --git a/lib/components/track_presentation/use_track_tile_play_callback.dart b/lib/components/track_presentation/use_track_tile_play_callback.dart index 261d01d8..74608205 100644 --- a/lib/components/track_presentation/use_track_tile_play_callback.dart +++ b/lib/components/track_presentation/use_track_tile_play_callback.dart @@ -37,6 +37,7 @@ Future Function(Track track, int index) useTrackTilePlayCallback( } final isRemoteDevice = await showSelectDeviceDialog(context, ref); + if (isRemoteDevice == null) return; if (isRemoteDevice) { final remotePlayback = ref.read(connectProvider.notifier); diff --git a/lib/modules/album/album_card.dart b/lib/modules/album/album_card.dart index 86935698..2efacbfd 100644 --- a/lib/modules/album/album_card.dart +++ b/lib/modules/album/album_card.dart @@ -91,6 +91,7 @@ class AlbumCard extends HookConsumerWidget { if (fetchedTracks.isEmpty || !context.mounted) return; final isRemoteDevice = await showSelectDeviceDialog(context, ref); + if (isRemoteDevice == null) return; if (isRemoteDevice) { final remotePlayback = ref.read(connectProvider.notifier); await remotePlayback.load( diff --git a/lib/modules/playlist/playlist_card.dart b/lib/modules/playlist/playlist_card.dart index 945f3571..43f2ee4e 100644 --- a/lib/modules/playlist/playlist_card.dart +++ b/lib/modules/playlist/playlist_card.dart @@ -94,6 +94,7 @@ class PlaylistCard extends HookConsumerWidget { if (fetchedInitialTracks.isEmpty || !context.mounted) return; final isRemoteDevice = await showSelectDeviceDialog(context, ref); + if (isRemoteDevice == null) return; if (isRemoteDevice) { final remotePlayback = ref.read(connectProvider.notifier); final allTracks = await fetchAllTracks(); diff --git a/lib/pages/artist/section/top_tracks.dart b/lib/pages/artist/section/top_tracks.dart index d52ed470..5ef68c9c 100644 --- a/lib/pages/artist/section/top_tracks.dart +++ b/lib/pages/artist/section/top_tracks.dart @@ -44,6 +44,9 @@ class ArtistPageTopTracks extends HookConsumerWidget { currentTrack ??= tracks.first; final isRemoteDevice = await showSelectDeviceDialog(context, ref); + + if (isRemoteDevice == null) return; + if (isRemoteDevice) { final remotePlayback = ref.read(connectProvider.notifier); final remotePlaylist = ref.read(queueProvider); diff --git a/lib/pages/connect/control/control.dart b/lib/pages/connect/control/control.dart index b92a5482..afe68b16 100644 --- a/lib/pages/connect/control/control.dart +++ b/lib/pages/connect/control/control.dart @@ -188,6 +188,7 @@ class ConnectControlPage extends HookConsumerWidget { SliverToBoxAdapter( child: Row( mainAxisAlignment: MainAxisAlignment.center, + spacing: 20, children: [ Tooltip( tooltip: TooltipContainer( diff --git a/lib/pages/search/sections/tracks.dart b/lib/pages/search/sections/tracks.dart index c0daa853..bacbbb57 100644 --- a/lib/pages/search/sections/tracks.dart +++ b/lib/pages/search/sections/tracks.dart @@ -55,6 +55,8 @@ class SearchTracksSection extends HookConsumerWidget { final isRemoteDevice = await showSelectDeviceDialog(context, ref); + if (isRemoteDevice == null) return; + if (isRemoteDevice) { final remotePlayback = ref.read(connectProvider.notifier); final remotePlaylist = ref.read(queueProvider); From 4afe0cca68d0b6f18cb1812cb776deb7b340f63b Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 5 Jan 2025 09:47:32 +0600 Subject: [PATCH 039/112] refactor: artist page --- lib/modules/artist/artist_album_list.dart | 4 +- lib/pages/artist/artist.dart | 41 ++- lib/pages/artist/section/footer.dart | 2 +- lib/pages/artist/section/header.dart | 372 +++++++++++----------- lib/pages/artist/section/top_tracks.dart | 39 ++- 5 files changed, 222 insertions(+), 236 deletions(-) diff --git a/lib/modules/artist/artist_album_list.dart b/lib/modules/artist/artist_album_list.dart index a2dd8006..7131aa3b 100644 --- a/lib/modules/artist/artist_album_list.dart +++ b/lib/modules/artist/artist_album_list.dart @@ -1,5 +1,5 @@ -import 'package:flutter/material.dart' hide Page; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart'; import 'package:spotube/extensions/context.dart'; @@ -30,7 +30,7 @@ class ArtistAlbumList extends HookConsumerWidget { onFetchMore: albumsQueryNotifier.fetchMore, title: Text( context.l10n.albums, - style: theme.textTheme.headlineSmall, + style: theme.typography.h4, ), ); } diff --git a/lib/pages/artist/artist.dart b/lib/pages/artist/artist.dart index 9e8b5be4..5565d897 100644 --- a/lib/pages/artist/artist.dart +++ b/lib/pages/artist/artist.dart @@ -1,8 +1,8 @@ -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:skeletonizer/skeletonizer.dart'; +import 'package:spotube/components/button/back_button.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/modules/artist/artist_album_list.dart'; @@ -30,12 +30,14 @@ class ArtistPage extends HookConsumerWidget { return SafeArea( bottom: false, child: Scaffold( - appBar: const TitleBar( - leading: [BackButton()], - backgroundColor: Colors.transparent, - ), - extendBodyBehindAppBar: true, - body: Builder(builder: (context) { + headers: const [ + TitleBar( + leading: [BackButton()], + backgroundColor: Colors.transparent, + ) + ], + floatingHeader: true, + child: Builder(builder: (context) { if (artistQuery.hasError && artistQuery.asData?.value == null) { return Center(child: Text(artistQuery.error.toString())); } @@ -50,31 +52,26 @@ class ArtistPage extends HookConsumerWidget { child: ArtistPageHeader(artistId: artistId), ), ), - const SliverGap(50), - ArtistPageTopTracks(artistId: artistId), - const SliverGap(50), - SliverToBoxAdapter(child: ArtistAlbumList(artistId)), const SliverGap(20), + ArtistPageTopTracks(artistId: artistId), + const SliverGap(20), + SliverToBoxAdapter(child: ArtistAlbumList(artistId)), SliverPadding( padding: const EdgeInsets.all(8.0), sliver: SliverToBoxAdapter( child: Text( context.l10n.fans_also_like, - style: theme.textTheme.headlineSmall, + style: theme.typography.h4, ), ), ), - SliverSafeArea( - sliver: ArtistPageRelatedArtists(artistId: artistId), - ), + ArtistPageRelatedArtists(artistId: artistId), + const SliverGap(20), if (artistQuery.asData?.value != null) - SliverSafeArea( - top: false, - sliver: SliverToBoxAdapter( - child: - ArtistPageFooter(artist: artistQuery.asData!.value), - ), + SliverToBoxAdapter( + child: ArtistPageFooter(artist: artistQuery.asData!.value), ), + const SliverSafeArea(sliver: SliverGap(10)), ], ), ); diff --git a/lib/pages/artist/section/footer.dart b/lib/pages/artist/section/footer.dart index abe86410..61d9d100 100644 --- a/lib/pages/artist/section/footer.dart +++ b/lib/pages/artist/section/footer.dart @@ -26,7 +26,7 @@ class ArtistPageFooter extends ConsumerWidget { if (summary.asData?.value == null) return const SizedBox.shrink(); return Container( - margin: const EdgeInsets.all(16), + margin: const EdgeInsets.all(8), padding: mediaQuery.smAndDown ? const EdgeInsets.all(20) : const EdgeInsets.all(30), diff --git a/lib/pages/artist/section/header.dart b/lib/pages/artist/section/header.dart index 713e0d26..b6224428 100644 --- a/lib/pages/artist/section/header.dart +++ b/lib/pages/artist/section/header.dart @@ -1,7 +1,7 @@ -import 'package:flutter/material.dart'; +import 'package:auto_size_text/auto_size_text.dart'; import 'package:flutter/services.dart'; -import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotube/collections/fake.dart'; import 'package:spotube/collections/spotube_icons.dart'; @@ -9,7 +9,6 @@ import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; -import 'package:spotube/hooks/utils/use_breakpoint_value.dart'; import 'package:spotube/models/database/database.dart'; import 'package:spotube/provider/authentication/authentication.dart'; import 'package:spotube/provider/blacklist_provider.dart'; @@ -25,19 +24,8 @@ class ArtistPageHeader extends HookConsumerWidget { final artistQuery = ref.watch(artistProvider(artistId)); final artist = artistQuery.asData?.value ?? FakeData.artist; - final scaffoldMessenger = ScaffoldMessenger.of(context); - final mediaQuery = MediaQuery.of(context); final theme = Theme.of(context); - final ThemeData(:textTheme) = theme; - - final chipTextVariant = useBreakpointValue( - xs: textTheme.bodySmall, - sm: textTheme.bodySmall, - md: textTheme.bodyMedium, - lg: textTheme.bodyLarge, - xl: textTheme.titleSmall, - xxl: textTheme.titleMedium, - ); + final ThemeData(:typography) = theme; final auth = ref.watch(authenticationProvider); ref.watch(blacklistProvider); @@ -48,190 +36,192 @@ class ArtistPageHeader extends HookConsumerWidget { placeholder: ImagePlaceholder.artist, ); + final actions = Skeleton.keep( + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + if (auth.asData?.value != null) + Consumer( + builder: (context, ref, _) { + final isFollowingQuery = ref.watch( + artistIsFollowingProvider(artist.id!), + ); + final followingArtistNotifier = ref.watch( + followedArtistsProvider.notifier, + ); + + return switch (isFollowingQuery) { + AsyncData(value: final following) => Builder( + builder: (context) { + if (following) { + return Button.outline( + onPressed: () async { + await followingArtistNotifier + .removeArtists([artist.id!]); + }, + child: Text(context.l10n.following), + ); + } + + return Button.primary( + onPressed: () async { + await followingArtistNotifier + .saveArtists([artist.id!]); + }, + child: Text(context.l10n.follow), + ); + }, + ), + AsyncError() => const SizedBox(), + _ => const SizedBox.square( + dimension: 20, + child: CircularProgressIndicator(), + ) + }; + }, + ), + const SizedBox(width: 5), + Tooltip( + tooltip: TooltipContainer( + child: Text(context.l10n.add_artist_to_blacklist), + ), + child: IconButton( + icon: Icon( + SpotubeIcons.userRemove, + color: !isBlackListed ? Colors.red[400] : null, + ), + variance: isBlackListed + ? ButtonVariance.destructive + : ButtonVariance.ghost, + onPressed: () async { + if (isBlackListed) { + await ref.read(blacklistProvider.notifier).remove(artist.id!); + } else { + await ref.read(blacklistProvider.notifier).add( + BlacklistTableCompanion.insert( + name: artist.name!, + elementId: artist.id!, + elementType: BlacklistedType.artist, + ), + ); + } + }, + ), + ), + IconButton.ghost( + icon: const Icon(SpotubeIcons.share), + onPressed: () async { + if (artist.externalUrls?.spotify != null) { + await Clipboard.setData( + ClipboardData( + text: artist.externalUrls!.spotify!, + ), + ); + } + + if (!context.mounted) return; + + showToast( + context: context, + location: ToastLocation.topRight, + dismissible: true, + builder: (context, overlay) { + return SurfaceCard( + child: Text( + context.l10n.artist_url_copied, + textAlign: TextAlign.center, + ), + ); + }, + ); + }, + ) + ], + ), + ); + return LayoutBuilder( builder: (context, constrains) { - return Center( - child: Flex( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: constrains.smAndDown - ? CrossAxisAlignment.start - : CrossAxisAlignment.center, - direction: constrains.smAndDown ? Axis.vertical : Axis.horizontal, - children: [ - DecoratedBox( - decoration: BoxDecoration( - boxShadow: kElevationToShadow[2], - borderRadius: BorderRadius.circular(35), - ), - child: ClipRRect( - borderRadius: BorderRadius.circular(35), - child: UniversalImage( - path: image, - width: 250, - height: 250, - fit: BoxFit.cover, - ), - ), - ), - const Gap(20), - Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - padding: const EdgeInsets.symmetric( - horizontal: 10, vertical: 5), - decoration: BoxDecoration( - color: Colors.blue, - borderRadius: BorderRadius.circular(50)), - child: Skeleton.keep( - child: Text( - artist.type!.toUpperCase(), - style: chipTextVariant.copyWith( - color: Colors.white, - ), - ), - ), - ), - if (isBlackListed) ...[ - const SizedBox(width: 5), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 10, vertical: 5), - decoration: BoxDecoration( - color: Colors.red[400], - borderRadius: BorderRadius.circular(50)), - child: Text( - context.l10n.blacklisted, - style: chipTextVariant.copyWith( - color: Colors.white, - ), - ), - ), - ] - ], - ), - Text( - artist.name!, - style: mediaQuery.smAndDown - ? textTheme.headlineSmall - : textTheme.headlineMedium, - ), - Text( - context.l10n.followers( - PrimitiveUtils.toReadableNumber( - artist.followers!.total!.toDouble(), + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Card( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ClipRRect( + borderRadius: theme.borderRadiusXl, + child: UniversalImage( + path: image, + width: constrains.mdAndUp ? 200 : 120, + height: constrains.mdAndUp ? 200 : 120, + fit: BoxFit.cover, ), ), - style: textTheme.bodyMedium?.copyWith( - fontWeight: mediaQuery.mdAndUp ? FontWeight.bold : null, - ), - ), - const Gap(20), - Skeleton.keep( - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - if (auth.asData?.value != null) - Consumer( - builder: (context, ref, _) { - final isFollowingQuery = ref - .watch(artistIsFollowingProvider(artist.id!)); - final followingArtistNotifier = - ref.watch(followedArtistsProvider.notifier); - - return switch (isFollowingQuery) { - AsyncData(value: final following) => Builder( - builder: (context) { - if (following) { - return OutlinedButton( - onPressed: () async { - await followingArtistNotifier - .removeArtists([artist.id!]); - }, - child: Text(context.l10n.following), - ); - } - - return FilledButton( - onPressed: () async { - await followingArtistNotifier - .saveArtists([artist.id!]); - }, - child: Text(context.l10n.follow), - ); - }, - ), - AsyncError() => const SizedBox(), - _ => const SizedBox.square( - dimension: 20, - child: CircularProgressIndicator(), - ) - }; - }, - ), - const SizedBox(width: 5), - IconButton( - tooltip: context.l10n.add_artist_to_blacklist, - icon: Icon( - SpotubeIcons.userRemove, - color: - !isBlackListed ? Colors.red[400] : Colors.white, - ), - style: IconButton.styleFrom( - backgroundColor: - isBlackListed ? Colors.red[400] : null, - ), - onPressed: () async { - if (isBlackListed) { - await ref - .read(blacklistProvider.notifier) - .remove(artist.id!); - } else { - await ref.read(blacklistProvider.notifier).add( - BlacklistTableCompanion.insert( - name: artist.name!, - elementId: artist.id!, - elementType: BlacklistedType.artist, - ), - ); - } - }, - ), - IconButton( - icon: const Icon(SpotubeIcons.share), - onPressed: () async { - if (artist.externalUrls?.spotify != null) { - await Clipboard.setData( - ClipboardData( - text: artist.externalUrls!.spotify!, + const Gap(20), + Flexible( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisSize: MainAxisSize.min, + children: [ + OutlineBadge( + child: + Text(context.l10n.artist).small().muted(), + ), + if (isBlackListed) ...[ + const Gap(5), + DestructiveBadge( + child: Text(context.l10n.blacklisted).small(), ), - ); - } - - if (!context.mounted) return; - - scaffoldMessenger.showSnackBar( - SnackBar( - width: 300, - behavior: SnackBarBehavior.floating, - content: Text( - context.l10n.artist_url_copied, - textAlign: TextAlign.center, + ] + ], + ), + const Gap(10), + Flexible( + child: AutoSizeText( + artist.name!, + style: constrains.smAndDown + ? typography.h4 + : typography.h3, + maxLines: 2, + overflow: TextOverflow.ellipsis, + minFontSize: 14, + ), + ), + const Gap(5), + Flexible( + child: AutoSizeText( + context.l10n.followers( + PrimitiveUtils.toReadableNumber( + artist.followers!.total!.toDouble(), ), ), - ); - }, - ) - ], + maxLines: 1, + overflow: TextOverflow.ellipsis, + minFontSize: 12, + ).muted(), + ), + if (constrains.mdAndUp) ...[ + const Gap(20), + actions, + ] + ], + ), ), - ) - ], - ), - ], + ], + ), + if (constrains.smAndDown) ...[ + const Gap(20), + actions, + ] + ], + ), ), ); }, diff --git a/lib/pages/artist/section/top_tracks.dart b/lib/pages/artist/section/top_tracks.dart index 5ef68c9c..72709751 100644 --- a/lib/pages/artist/section/top_tracks.dart +++ b/lib/pages/artist/section/top_tracks.dart @@ -1,5 +1,5 @@ -import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/collections/fake.dart'; @@ -19,7 +19,6 @@ class ArtistPageTopTracks extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { final theme = Theme.of(context); - final scaffoldMessenger = ScaffoldMessenger.of(context); final playlist = ref.watch(audioPlayerProvider); final playlistNotifier = ref.watch(audioPlayerProvider.notifier); @@ -93,46 +92,46 @@ class ArtistPageTopTracks extends HookConsumerWidget { padding: const EdgeInsets.all(8.0), child: Text( context.l10n.top_tracks, - style: theme.textTheme.headlineSmall, + style: theme.typography.h4, ), ), if (!isPlaylistPlaying) - IconButton( + IconButton.outline( icon: const Icon( SpotubeIcons.queueAdd, ), onPressed: () { playlistNotifier.addTracks(topTracks.toList()); - scaffoldMessenger.showSnackBar( - SnackBar( - width: 300, - behavior: SnackBarBehavior.floating, - content: Text( - context.l10n.added_to_queue( - topTracks.length, + showToast( + context: context, + location: ToastLocation.topRight, + builder: (context, overlay) { + return SurfaceCard( + child: Text( + context.l10n.added_to_queue( + topTracks.length, + ), ), - textAlign: TextAlign.center, - ), - ), + ); + }, ); }, ), const SizedBox(width: 5), - IconButton( + IconButton.primary( + shape: ButtonShape.circle, + enabled: !isPlaylistPlaying, icon: Skeleton.keep( child: Icon( - isPlaylistPlaying ? SpotubeIcons.stop : SpotubeIcons.play, - color: Colors.white, + isPlaylistPlaying ? SpotubeIcons.pause : SpotubeIcons.play, ), ), - style: IconButton.styleFrom( - backgroundColor: theme.colorScheme.primary, - ), onPressed: () => playPlaylist(topTracks.toList()), ) ], ), ), + const SliverGap(10), SliverList.builder( itemCount: topTracks.length, itemBuilder: (context, index) { From b8f2495acb995eb5eeace35a2f58eb582748ca2a Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 5 Jan 2025 11:54:50 +0600 Subject: [PATCH 040/112] refactor: user local library --- .../expandable_search/expandable_search.dart | 18 +- lib/main.dart | 2 +- .../local_folder/local_folder_item.dart | 206 +++---- lib/modules/library/user_local_tracks.dart | 88 ++- lib/pages/library/local_folder.dart | 566 +++++++++--------- 5 files changed, 441 insertions(+), 439 deletions(-) diff --git a/lib/components/expandable_search/expandable_search.dart b/lib/components/expandable_search/expandable_search.dart index 157e180f..0c40b843 100644 --- a/lib/components/expandable_search/expandable_search.dart +++ b/lib/components/expandable_search/expandable_search.dart @@ -1,5 +1,5 @@ -import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/extensions/context.dart'; @@ -39,11 +39,8 @@ class ExpandableSearchField extends StatelessWidget { child: TextField( focusNode: searchFocus, controller: searchController, - decoration: InputDecoration( - hintText: context.l10n.search_tracks, - isDense: true, - prefixIcon: const Icon(SpotubeIcons.search), - ), + placeholder: Text(context.l10n.search_tracks), + leading: const Icon(SpotubeIcons.search), ), ), ), @@ -69,16 +66,9 @@ class ExpandableSearchButton extends StatelessWidget { @override Widget build(BuildContext context) { - final theme = Theme.of(context); - return IconButton( icon: icon, - style: IconButton.styleFrom( - backgroundColor: - isFiltering ? theme.colorScheme.secondaryContainer : null, - foregroundColor: isFiltering ? theme.colorScheme.secondary : null, - minimumSize: const Size(25, 25), - ), + variance: isFiltering ? ButtonVariance.secondary : ButtonVariance.outline, onPressed: () { if (isFiltering) { searchFocus.requestFocus(); diff --git a/lib/main.dart b/lib/main.dart index 57cfbd88..5b20acd8 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -215,7 +215,7 @@ class Spotube extends HookConsumerWidget { theme: ThemeData( radius: .5, iconTheme: const IconThemeProperties(), - colorScheme: ColorSchemes.lightBlue(), + colorScheme: ColorSchemes.lightOrange(), surfaceOpacity: .8, surfaceBlur: 10, ), diff --git a/lib/modules/library/local_folder/local_folder_item.dart b/lib/modules/library/local_folder/local_folder_item.dart index a965a42d..84e43e96 100644 --- a/lib/modules/library/local_folder/local_folder_item.dart +++ b/lib/modules/library/local_folder/local_folder_item.dart @@ -1,18 +1,17 @@ import 'dart:math'; -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:gap/gap.dart'; + import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:path/path.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/extensions/string.dart'; -import 'package:spotube/hooks/utils/use_brightness_value.dart'; import 'package:spotube/pages/library/local_folder.dart'; import 'package:spotube/provider/local_tracks/local_tracks_provider.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; @@ -26,8 +25,6 @@ class LocalFolderItem extends HookConsumerWidget { final ThemeData(:colorScheme) = Theme.of(context); final mediaQuery = MediaQuery.of(context); - final lerpValue = useBrightnessValue(.9, .7); - final downloadFolder = ref.watch(userPreferencesProvider.select((s) => s.downloadLocation)); final cacheFolder = useFuture(UserPreferencesNotifier.getMusicCacheDir()); @@ -60,8 +57,8 @@ class LocalFolderItem extends HookConsumerWidget { final tracks = trackSnapshot.value ?? []; - return InkWell( - onTap: () { + return Button( + onPressed: () { context.goNamed( LocalLibraryPage.name, queryParameters: { @@ -71,58 +68,54 @@ class LocalFolderItem extends HookConsumerWidget { extra: folder, ); }, - borderRadius: BorderRadius.circular(8), - child: Ink( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - color: Color.lerp( - colorScheme.surfaceContainerHighest, - colorScheme.surface, - lerpValue, - ), - ), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - if (tracks.isEmpty) - Card( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Icon( - SpotubeIcons.folder, - size: mediaQuery.smAndDown - ? 95 - : mediaQuery.mdAndDown - ? 100 - : 142, - ), - ), - ) - else - ClipRRect( - borderRadius: BorderRadius.circular(8), - child: GridView.builder( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: max((tracks.length / 2).ceil(), 2), - ), - itemCount: tracks.length, - itemBuilder: (context, index) { - final track = tracks[index]; - return UniversalImage( - path: (track.album?.images).asUrlString( - placeholder: ImagePlaceholder.albumArt, - ), - fit: BoxFit.cover, - ); - }, - ), + style: ButtonVariance.card.copyWith( + padding: (context, states, value) { + return const EdgeInsets.all(8); + }, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + if (tracks.isEmpty) + Card( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Icon( + SpotubeIcons.folder, + size: mediaQuery.smAndDown + ? 95 + : mediaQuery.mdAndDown + ? 100 + : 142, ), - const Gap(8), - Stack( + ), + ) + else + ClipRRect( + borderRadius: BorderRadius.circular(8), + child: GridView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: max((tracks.length / 2).ceil(), 2), + ), + itemCount: tracks.length, + itemBuilder: (context, index) { + final track = tracks[index]; + return UniversalImage( + path: (track.album?.images).asUrlString( + placeholder: ImagePlaceholder.albumArt, + ), + fit: BoxFit.cover, + ); + }, + ), + ), + const Gap(8), + Stack( + children: [ + Column( + mainAxisSize: MainAxisSize.min, children: [ Center( child: Text( @@ -133,25 +126,47 @@ class LocalFolderItem extends HookConsumerWidget { : basename(folder), style: const TextStyle(fontWeight: FontWeight.bold), textAlign: TextAlign.center, + maxLines: 1, + overflow: TextOverflow.ellipsis, ), ), - if (!isDownloadFolder) - Align( - alignment: Alignment.topRight, - child: PopupMenuButton( - child: const Padding( - padding: EdgeInsets.all(3), - child: Icon(Icons.more_vert), - ), - itemBuilder: (context) { - return [ - PopupMenuItem( - child: ListTile( - leading: const Icon(SpotubeIcons.folderRemove), - iconColor: colorScheme.error, - title: + Wrap( + spacing: 2, + runSpacing: 2, + children: [ + for (final MapEntry(key: index, value: segment) + in segments.asMap().entries) + Text.rich( + TextSpan( + children: [ + if (index != 0) const TextSpan(text: "/ "), + TextSpan(text: segment), + ], + ), + maxLines: 2, + ).xSmall().muted(), + ], + ), + ], + ), + if (!isDownloadFolder && !isCacheFolder) + Align( + alignment: Alignment.topRight, + child: IconButton.ghost( + icon: const Icon(Icons.more_vert), + size: ButtonSize.small, + onPressed: () { + showDropdown( + context: context, + builder: (context) { + return DropdownMenu( + children: [ + MenuButton( + leading: Icon(SpotubeIcons.folderRemove, + color: colorScheme.destructive), + child: Text(context.l10n.remove_library_location), - onTap: () { + onPressed: (context) { final libraryLocations = ref .read(userPreferencesProvider) .localLibraryLocation; @@ -163,43 +178,18 @@ class LocalFolderItem extends HookConsumerWidget { .toList(), ); }, - ), - ) - ]; + ) + ], + ); }, - ), - ), - ], - ), - const Spacer(), - Wrap( - spacing: 2, - runSpacing: 2, - children: [ - for (final MapEntry(key: index, value: segment) - in segments.asMap().entries) - Text.rich( - TextSpan( - children: [ - if (index != 0) - TextSpan( - text: "/ ", - style: TextStyle(color: colorScheme.primary), - ), - TextSpan(text: segment), - ], - ), - style: TextStyle( - fontSize: 10, - color: colorScheme.tertiary, - ), - ), - ], - ), - const Spacer(), + ); + }, + ), + ), ], ), - ), + const Spacer(), + ], ), ); } diff --git a/lib/modules/library/user_local_tracks.dart b/lib/modules/library/user_local_tracks.dart index 23fb3be0..86b36dfb 100644 --- a/lib/modules/library/user_local_tracks.dart +++ b/lib/modules/library/user_local_tracks.dart @@ -1,9 +1,8 @@ import 'package:file_picker/file_picker.dart'; import 'package:file_selector/file_selector.dart'; -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/modules/library/local_folder/local_folder_item.dart'; @@ -58,49 +57,48 @@ class UserLocalTracks extends HookConsumerWidget { // For now, this gets all of them. ref.watch(localTracksProvider); - return LayoutBuilder(builder: (context, constrains) { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 12.0), - child: Column( - children: [ - Align( - alignment: Alignment.centerRight, - child: TextButton.icon( - icon: const Icon(SpotubeIcons.folderAdd), - label: Text(context.l10n.add_library_location), - onPressed: addLocalLibraryLocation, + final locations = [ + preferences.downloadLocation, + if (cacheDir.hasData) cacheDir.data!, + ...preferences.localLibraryLocation, + ]; + + return LayoutBuilder( + builder: (context, constrains) => Padding( + padding: const EdgeInsets.symmetric(horizontal: 12.0), + child: Column( + children: [ + Align( + alignment: Alignment.centerRight, + child: Button.secondary( + leading: const Icon(SpotubeIcons.folderAdd), + onPressed: addLocalLibraryLocation, + child: Text(context.l10n.add_library_location), + ), + ), + const Gap(8), + Expanded( + child: GridView.builder( + gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: 200, + mainAxisExtent: constrains.isXs + ? 210 + : constrains.mdAndDown + ? 280 + : 250, + crossAxisSpacing: 10, + mainAxisSpacing: 10, + ), + itemCount: locations.length, + itemBuilder: (context, index) { + return LocalFolderItem( + folder: locations[index], + ); + }, + ), + ), + ], ), - ), - const Gap(8), - Expanded( - child: GridView.builder( - gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( - maxCrossAxisExtent: 200, - mainAxisExtent: constrains.isXs - ? 210 - : constrains.mdAndDown - ? 280 - : 250, - crossAxisSpacing: 10, - mainAxisSpacing: 10, - ), - itemCount: preferences.localLibraryLocation.length + - 1 + - (cacheDir.hasData ? 1 : 0), - itemBuilder: (context, index) { - return LocalFolderItem( - folder: index == 0 - ? preferences.downloadLocation - : index == 1 && cacheDir.hasData - ? cacheDir.data! - : preferences.localLibraryLocation[index - 1], - ); - }, - ), - ), - ], - ), - ); - }); + )); } } diff --git a/lib/pages/library/local_folder.dart b/lib/pages/library/local_folder.dart index 8cfec3a8..23326c68 100644 --- a/lib/pages/library/local_folder.dart +++ b/lib/pages/library/local_folder.dart @@ -3,13 +3,16 @@ import 'dart:math'; import 'package:collection/collection.dart'; import 'package:file_picker/file_picker.dart'; -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:fuzzywuzzy/fuzzywuzzy.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotube/collections/fake.dart'; import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/button/back_button.dart'; +import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/string.dart'; import 'package:spotube/modules/library/local_folder/cache_export_dialog.dart'; import 'package:spotube/modules/library/user_local_tracks.dart'; @@ -65,7 +68,7 @@ class LocalLibraryPage extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final ThemeData(:textTheme) = Theme.of(context); + final scale = context.theme.scaling; final sortBy = useState(SortBy.none); final playlist = ref.watch(audioPlayerProvider); @@ -93,282 +96,303 @@ class LocalLibraryPage extends HookConsumerWidget { return SafeArea( bottom: false, child: Scaffold( - appBar: TitleBar( - leading: const [BackButton()], - title: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - isDownloads - ? context.l10n.downloads - : isCache - ? context.l10n.cache_folder.capitalize() - : location, - style: textTheme.titleLarge, - ), - FutureBuilder( - future: directorySize, - builder: (context, snapshot) { - return Text( - "${(snapshot.data ?? 0)} GB", - style: textTheme.labelSmall, - ); - }, - ) + headers: [ + TitleBar( + padding: const EdgeInsets.symmetric( + horizontal: 10, + vertical: 0, + ), + surfaceBlur: 0, + leading: const [BackButton()], + title: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + isDownloads + ? context.l10n.downloads + : isCache + ? context.l10n.cache_folder.capitalize() + : location, + ), + FutureBuilder( + future: directorySize, + builder: (context, snapshot) { + return Text( + "${(snapshot.data ?? 0)} GB", + ).xSmall().muted(); + }, + ) + ], + ), + backgroundColor: Colors.transparent, + trailingGap: 10, + trailing: [ + if (isCache) ...[ + IconButton.outline( + size: ButtonSize.small, + icon: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(SpotubeIcons.delete), + Text(context.l10n.clear_cache) + ], + ).xSmall().iconSmall(), + onPressed: () async { + final accepted = await showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text(context.l10n.clear_cache_confirmation), + actions: [ + Button.outline( + onPressed: () { + Navigator.of(context).pop(false); + }, + child: Text(context.l10n.decline), + ), + Button.destructive( + onPressed: () async { + Navigator.of(context).pop(true); + }, + child: Text(context.l10n.accept), + ), + ], + ), + ); + + if (accepted ?? false) return; + + final cacheDir = Directory( + await UserPreferencesNotifier.getMusicCacheDir(), + ); + + if (cacheDir.existsSync()) { + await cacheDir.delete(recursive: true); + } + }, + ), + IconButton.outline( + size: ButtonSize.small, + icon: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(SpotubeIcons.export), + Text( + context.l10n.export, + ) + ], + ).xSmall().iconSmall(), + onPressed: () async { + final exportPath = + await FilePicker.platform.getDirectoryPath(); + + if (exportPath == null) return; + final exportDirectory = Directory(exportPath); + + if (!exportDirectory.existsSync()) { + await exportDirectory.create(recursive: true); + } + + final cacheDir = Directory( + await UserPreferencesNotifier.getMusicCacheDir()); + + if (!context.mounted) return; + await showDialog( + context: context, + builder: (context) { + return LocalFolderCacheExportDialog( + cacheDir: cacheDir, + exportDir: exportDirectory, + ); + }, + ); + }, + ), + ] ], ), - backgroundColor: Colors.transparent, - trailing: [ - if (isCache) ...[ - IconButton( - iconSize: 16, - icon: Column( - mainAxisSize: MainAxisSize.min, + ], + child: LayoutBuilder( + builder: (context, constraints) => Column( children: [ - const Icon(SpotubeIcons.delete), - Text( - context.l10n.clear_cache, - style: textTheme.labelSmall, - ) - ], - ), - onPressed: () async { - final accepted = await showDialog( - context: context, - builder: (context) => AlertDialog.adaptive( - title: Text(context.l10n.clear_cache_confirmation), - actions: [ - TextButton( - onPressed: () { - Navigator.of(context).pop(false); - }, - child: Text(context.l10n.decline), - ), - TextButton( - onPressed: () async { - Navigator.of(context).pop(true); - }, - child: Text(context.l10n.accept), - ), - ], - ), - ); - - if (accepted ?? false) return; - - final cacheDir = Directory( - await UserPreferencesNotifier.getMusicCacheDir(), - ); - - if (cacheDir.existsSync()) { - await cacheDir.delete(recursive: true); - } - }, - ), - IconButton( - iconSize: 16, - icon: Column( - mainAxisSize: MainAxisSize.min, - children: [ - const Icon(SpotubeIcons.export), - Text( - context.l10n.export, - style: textTheme.labelSmall, - ) - ], - ), - onPressed: () async { - final exportPath = - await FilePicker.platform.getDirectoryPath(); - - if (exportPath == null) return; - final exportDirectory = Directory(exportPath); - - if (!exportDirectory.existsSync()) { - await exportDirectory.create(recursive: true); - } - - final cacheDir = Directory( - await UserPreferencesNotifier.getMusicCacheDir()); - - if (!context.mounted) return; - await showDialog( - context: context, - builder: (context) { - return LocalFolderCacheExportDialog( - cacheDir: cacheDir, - exportDir: exportDirectory, - ); - }, - ); - }, - ), - ] - ], - ), - body: Column( - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - children: [ - const SizedBox(width: 5), - FilledButton( - onPressed: trackSnapshot.asData?.value != null - ? () async { - if (trackSnapshot.asData?.value.isNotEmpty == - true) { - if (!isPlaylistPlaying) { - await playLocalTracks( - ref, - trackSnapshot.asData!.value[location] ?? [], - ); - } - } - } - : null, - child: Row( - children: [ - Text(context.l10n.play), - Icon( - isPlaylistPlaying - ? SpotubeIcons.stop - : SpotubeIcons.play, - ) - ], - ), - ), - const Spacer(), - ExpandableSearchButton( - isFiltering: isFiltering.value, - onPressed: (value) => isFiltering.value = value, - searchFocus: searchFocus, - ), - const SizedBox(width: 10), - SortTracksDropdown( - value: sortBy.value, - onChanged: (value) { - sortBy.value = value; - }, - ), - const SizedBox(width: 5), - FilledButton( - child: const Icon(SpotubeIcons.refresh), - onPressed: () { - ref.invalidate(localTracksProvider); - }, - ) - ], - ), - ), - ExpandableSearchField( - searchController: searchController, - searchFocus: searchFocus, - isFiltering: isFiltering.value, - onChangeFiltering: (value) => isFiltering.value = value, - ), - trackSnapshot.when( - data: (tracks) { - final sortedTracks = useMemoized(() { - return ServiceUtils.sortTracks( - tracks[location] ?? [], sortBy.value); - }, [sortBy.value, tracks]); - - final filteredTracks = useMemoized(() { - if (searchController.text.isEmpty) { - return sortedTracks; - } - return sortedTracks - .map((e) => ( - weightedRatio( - "${e.name} - ${e.artists?.asString() ?? ""}", - searchController.text, + Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + children: [ + const Gap(5), + Button.primary( + onPressed: trackSnapshot.asData?.value != null + ? () async { + if (trackSnapshot + .asData?.value.isNotEmpty == + true) { + if (!isPlaylistPlaying) { + await playLocalTracks( + ref, + trackSnapshot + .asData!.value[location] ?? + [], + ); + } + } + } + : null, + leading: Icon( + isPlaylistPlaying + ? SpotubeIcons.stop + : SpotubeIcons.play, ), - e, - )) - .toList() - .sorted( - (a, b) => b.$1.compareTo(a.$1), - ) - .where((e) => e.$1 > 50) - .map((e) => e.$2) - .toList() - .toList(); - }, [searchController.text, sortedTracks]); - - if (!trackSnapshot.isLoading && filteredTracks.isEmpty) { - return const Expanded( - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [NotFound()], - ), - ); - } - - return Expanded( - child: RefreshIndicator( - onRefresh: () async { - ref.invalidate(localTracksProvider); - }, - child: InterScrollbar( - controller: controller, - child: Skeletonizer( - enabled: trackSnapshot.isLoading, - child: ListView.builder( - controller: controller, - physics: const AlwaysScrollableScrollPhysics(), - itemCount: trackSnapshot.isLoading - ? 5 - : filteredTracks.length, - itemBuilder: (context, index) { - if (trackSnapshot.isLoading) { - return TrackTile( - playlist: playlist, - track: FakeData.track, - index: index, - ); - } - - final track = filteredTracks[index]; - return TrackTile( - index: index, - playlist: playlist, - track: track, - userPlaylist: false, - onTap: () async { - await playLocalTracks( - ref, - sortedTracks, - currentTrack: track, - ); - }, - ); - }, - ), + child: Text(context.l10n.play), + ), + const Spacer(), + if (constraints.smAndDown) + ExpandableSearchButton( + isFiltering: isFiltering.value, + onPressed: (value) => isFiltering.value = value, + searchFocus: searchFocus, + ) + else + ConstrainedBox( + constraints: BoxConstraints( + maxWidth: 300 * scale, + maxHeight: 38 * scale, + ), + child: ExpandableSearchField( + isFiltering: true, + onChangeFiltering: (value) {}, + searchController: searchController, + searchFocus: searchFocus, + ), + ), + const Gap(5), + SortTracksDropdown( + value: sortBy.value, + onChanged: (value) { + sortBy.value = value; + }, + ), + const Gap(5), + IconButton.outline( + icon: const Icon(SpotubeIcons.refresh), + onPressed: () { + ref.invalidate(localTracksProvider); + }, + ) + ], ), ), - ), - ); - }, - loading: () => Expanded( - child: Skeletonizer( - enabled: true, - child: ListView.builder( - itemCount: 5, - itemBuilder: (context, index) => TrackTile( - track: FakeData.track, - index: index, - playlist: playlist, + ExpandableSearchField( + searchController: searchController, + searchFocus: searchFocus, + isFiltering: isFiltering.value, + onChangeFiltering: (value) => isFiltering.value = value, ), - ), - ), - ), - error: (error, stackTrace) => - Text(error.toString() + stackTrace.toString()), - ) - ], - )), + HookBuilder(builder: (context) { + return trackSnapshot.when( + data: (tracks) { + final sortedTracks = useMemoized(() { + return ServiceUtils.sortTracks( + tracks[location] ?? [], + sortBy.value); + }, [sortBy.value, tracks]); + + final filteredTracks = useMemoized(() { + if (searchController.text.isEmpty) { + return sortedTracks; + } + return sortedTracks + .map((e) => ( + weightedRatio( + "${e.name} - ${e.artists?.asString() ?? ""}", + searchController.text, + ), + e, + )) + .toList() + .sorted( + (a, b) => b.$1.compareTo(a.$1), + ) + .where((e) => e.$1 > 50) + .map((e) => e.$2) + .toList() + .toList(); + }, [searchController.text, sortedTracks]); + + if (!trackSnapshot.isLoading && + filteredTracks.isEmpty) { + return const Expanded( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [NotFound()], + ), + ); + } + + return Expanded( + child: RefreshTrigger( + onRefresh: () async { + // ref.invalidate(localTracksProvider); + }, + child: InterScrollbar( + controller: controller, + child: Skeletonizer( + enabled: trackSnapshot.isLoading, + child: ListView.builder( + controller: controller, + physics: + const AlwaysScrollableScrollPhysics(), + itemCount: trackSnapshot.isLoading + ? 5 + : filteredTracks.length, + itemBuilder: (context, index) { + if (trackSnapshot.isLoading) { + return TrackTile( + playlist: playlist, + track: FakeData.track, + index: index, + ); + } + + final track = filteredTracks[index]; + return TrackTile( + index: index, + playlist: playlist, + track: track, + userPlaylist: false, + onTap: () async { + await playLocalTracks( + ref, + sortedTracks, + currentTrack: track, + ); + }, + ); + }, + ), + ), + ), + ), + ); + }, + loading: () => Expanded( + child: Skeletonizer( + enabled: true, + child: ListView.builder( + itemCount: 5, + itemBuilder: (context, index) => TrackTile( + track: FakeData.track, + index: index, + playlist: playlist, + ), + ), + ), + ), + error: (error, stackTrace) => + Text(error.toString() + stackTrace.toString()), + ); + }) + ], + ))), ); } } From dd0bb01af53c7d62bc7681e17d5e4de8438a9bda Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 5 Jan 2025 16:16:57 +0600 Subject: [PATCH 041/112] refactor: generate playlist to shadcn --- lib/components/ui/button_tile.dart | 7 +- lib/l10n/app_en.arb | 4 +- .../recommendation_attribute_dials.dart | 185 ++-- .../recommendation_attribute_fields.dart | 240 ++--- .../seeds_multi_autocomplete.dart | 60 +- .../playlist_generate/simple_track_tile.dart | 10 +- lib/modules/library/user_playlists.dart | 2 +- .../playlist/playlist_create_dialog.dart | 11 +- .../playlist_generate/playlist_generate.dart | 917 +++++++++--------- .../playlist_generate_result.dart | 141 +-- untranslated_messages.json | 52 + 11 files changed, 868 insertions(+), 761 deletions(-) diff --git a/lib/components/ui/button_tile.dart b/lib/components/ui/button_tile.dart index d865b583..099691d0 100644 --- a/lib/components/ui/button_tile.dart +++ b/lib/components/ui/button_tile.dart @@ -31,8 +31,7 @@ class ButtonTile extends StatelessWidget { onPressed: onPressed, style: style.copyWith( decoration: (context, states, value) { - final decoration = ButtonVariance.outline.decoration(context, states) - as BoxDecoration; + final decoration = style.decoration(context, states) as BoxDecoration; if (selected && style == ButtonVariance.outline) { return decoration.copyWith( @@ -47,7 +46,7 @@ class ButtonTile extends StatelessWidget { return decoration; }, iconTheme: (context, states, value) { - final iconTheme = ButtonVariance.outline.iconTheme(context, states); + final iconTheme = style.iconTheme(context, states); if (selected && style == ButtonVariance.outline) { return iconTheme.copyWith( @@ -58,7 +57,7 @@ class ButtonTile extends StatelessWidget { return iconTheme; }, textStyle: (context, states, value) { - final textStyle = ButtonVariance.outline.textStyle(context, states); + final textStyle = style.textStyle(context, states); if (selected && style == ButtonVariance.outline) { return textStyle.copyWith( diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 0be79bda..45a8d78f 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -22,7 +22,7 @@ "filter_playlists": "Filter your playlists...", "liked_tracks": "Liked Tracks", "liked_tracks_description": "All your liked tracks", - "create_playlist": "Create Playlist", + "playlist": "Playlist", "create_a_playlist": "Create a playlist", "update_playlist": "Update playlist", "create": "Create", @@ -194,7 +194,7 @@ "invidious_instance": "Invidious Server Instance", "invidious_description": "The Invidious server instance to use for track matching", "invidious_warning": "Some of them might not work well. So use at your own risk", - "generate_playlist": "Generate Playlist", + "generate": "Generate", "track_exists": "Track {track} already exists", "replace_downloaded_tracks": "Replace all downloaded tracks", "skip_download_tracks": "Skip downloading all downloaded tracks", diff --git a/lib/modules/library/playlist_generate/recommendation_attribute_dials.dart b/lib/modules/library/playlist_generate/recommendation_attribute_dials.dart index d7f51ffb..564bfb55 100644 --- a/lib/modules/library/playlist_generate/recommendation_attribute_dials.dart +++ b/lib/modules/library/playlist_generate/recommendation_attribute_dials.dart @@ -1,5 +1,5 @@ -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/pages/library/playlist_generate/playlist_generate.dart'; @@ -29,23 +29,21 @@ class RecommendationAttributeDials extends HookWidget { @override Widget build(BuildContext context) { - final animation = useAnimationController( - duration: const Duration(milliseconds: 300), - ); - final labelStyle = Theme.of(context).textTheme.labelSmall?.copyWith( + final labelStyle = Theme.of(context).typography.small.copyWith( fontWeight: FontWeight.w500, ); final minSlider = Row( + spacing: 5, children: [ Text(context.l10n.min, style: labelStyle), Expanded( child: Slider( - value: values.min / base, + value: SliderValue.single(values.min / base), min: 0, max: 1, onChanged: (value) => onChanged(( - min: value * base, + min: value.value * base, target: values.target, max: values.max, )), @@ -55,16 +53,17 @@ class RecommendationAttributeDials extends HookWidget { ); final targetSlider = Row( + spacing: 5, children: [ Text(context.l10n.target, style: labelStyle), Expanded( child: Slider( - value: values.target / base, + value: SliderValue.single(values.target / base), min: 0, max: 1, onChanged: (value) => onChanged(( min: values.min, - target: value * base, + target: value.value * base, max: values.max, )), ), @@ -73,109 +72,111 @@ class RecommendationAttributeDials extends HookWidget { ); final maxSlider = Row( + spacing: 5, children: [ Text(context.l10n.max, style: labelStyle), Expanded( child: Slider( - value: values.max / base, + value: SliderValue.single(values.max / base), min: 0, max: 1, onChanged: (value) => onChanged(( min: values.min, target: values.target, - max: value * base, + max: value.value * base, )), ), ), ], ); - return LayoutBuilder(builder: (context, constrain) { - return Card( - child: ExpansionTile( - title: DefaultTextStyle( - style: Theme.of(context).textTheme.titleSmall!, - child: title, - ), - shape: const Border(), - leading: AnimatedBuilder( - animation: animation, - builder: (context, child) { - return Transform.rotate( - angle: (animation.value * 3.14) / 2, - child: child, - ); - }, - child: const Icon(Icons.chevron_right), - ), - trailing: Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: ToggleButtons( - borderRadius: BorderRadius.circular(8), - textStyle: labelStyle, - isSelected: [ - values == lowValues(base), - values == moderateValues(base), - values == highValues(base), - ], - onPressed: (index) { - RecommendationAttribute newValues = zeroValues; - switch (index) { - case 0: - newValues = lowValues(base); - break; - case 1: - newValues = moderateValues(base); - break; - case 2: - newValues = highValues(base); - break; - } + void onSelected(int index) { + RecommendationAttribute newValues = zeroValues; + switch (index) { + case 0: + newValues = lowValues(base); + break; + case 1: + newValues = moderateValues(base); + break; + case 2: + newValues = highValues(base); + break; + } - if (newValues == values) { - onChanged(zeroValues); - } else { - onChanged(newValues); - } - }, + if (newValues == values) { + onChanged(zeroValues); + } else { + onChanged(newValues); + } + } + + return LayoutBuilder(builder: (context, constrain) { + return Accordion( + items: [ + AccordionItem( + trigger: AccordionTrigger( + child: SizedBox( + width: double.infinity, + child: Basic( + title: title.semiBold(), + trailing: Row( + spacing: 5, + children: [ + Toggle( + value: values == lowValues(base), + onChanged: (value) => onSelected(0), + style: + const ButtonStyle.outline(size: ButtonSize.small), + child: Text(context.l10n.low), + ), + Toggle( + value: values == moderateValues(base), + onChanged: (value) => onSelected(1), + style: + const ButtonStyle.outline(size: ButtonSize.small), + child: Text(context.l10n.moderate), + ), + Toggle( + value: values == highValues(base), + onChanged: (value) => onSelected(2), + style: + const ButtonStyle.outline(size: ButtonSize.small), + child: Text(context.l10n.high), + ), + ], + ), + ), + ), + ), + content: Column( + mainAxisSize: MainAxisSize.min, children: [ - Text(context.l10n.low), - Text(" ${context.l10n.moderate} "), - Text(context.l10n.high), + if (constrain.mdAndUp) + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + const SizedBox(width: 16), + Expanded(child: minSlider), + Expanded(child: targetSlider), + Expanded(child: maxSlider), + ], + ) + else + Padding( + padding: const EdgeInsets.only(left: 16), + child: Column( + children: [ + minSlider, + targetSlider, + maxSlider, + ], + ), + ), ], ), ), - onExpansionChanged: (value) { - if (value) { - animation.forward(); - } else { - animation.reverse(); - } - }, - children: [ - if (constrain.mdAndUp) - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - const SizedBox(width: 16), - Expanded(child: minSlider), - Expanded(child: targetSlider), - Expanded(child: maxSlider), - ], - ) - else - Padding( - padding: const EdgeInsets.only(left: 16), - child: Column( - children: [ - minSlider, - targetSlider, - maxSlider, - ], - ), - ), - ], - ), + ], ); }); } diff --git a/lib/modules/library/playlist_generate/recommendation_attribute_fields.dart b/lib/modules/library/playlist_generate/recommendation_attribute_fields.dart index 7feff03a..351fde1e 100644 --- a/lib/modules/library/playlist_generate/recommendation_attribute_fields.dart +++ b/lib/modules/library/playlist_generate/recommendation_attribute_fields.dart @@ -1,5 +1,5 @@ -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/modules/library/playlist_generate/recommendation_attribute_dials.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; @@ -21,13 +21,6 @@ class RecommendationAttributeFields extends HookWidget { @override Widget build(BuildContext context) { - final animation = useAnimationController( - duration: const Duration(milliseconds: 300), - ); - final labelStyle = Theme.of(context).textTheme.labelSmall?.copyWith( - fontWeight: FontWeight.w500, - ); - final minController = useTextEditingController(text: values.min.toString()); final targetController = useTextEditingController(text: values.target.toString()); @@ -53,126 +46,133 @@ class RecommendationAttributeFields extends HookWidget { }; }, [values]); - final minField = TextField( - controller: minController, - decoration: InputDecoration( - labelText: context.l10n.min, - isDense: true, - ), - keyboardType: const TextInputType.numberWithOptions( - decimal: false, - signed: true, - ), + final minField = Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 5, + children: [ + Text(context.l10n.min).semiBold(), + NumberInput( + controller: minController, + allowDecimals: false, + ), + ], ); - final targetField = TextField( - controller: targetController, - decoration: InputDecoration( - labelText: context.l10n.target, - isDense: true, - ), - keyboardType: const TextInputType.numberWithOptions( - decimal: false, - signed: true, - ), + final targetField = Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 5, + children: [ + Text(context.l10n.target).semiBold(), + NumberInput( + controller: targetController, + allowDecimals: false, + ), + ], ); - final maxField = TextField( - controller: maxController, - decoration: InputDecoration( - labelText: context.l10n.max, - isDense: true, - ), - keyboardType: const TextInputType.numberWithOptions( - decimal: false, - signed: true, - ), + final maxField = Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 5, + children: [ + Text(context.l10n.max).semiBold(), + NumberInput( + controller: maxController, + allowDecimals: false, + ), + ], ); - return LayoutBuilder(builder: (context, constrain) { - return Card( - child: ExpansionTile( - title: DefaultTextStyle( - style: Theme.of(context).textTheme.titleSmall!, - child: title, - ), - shape: const Border(), - leading: AnimatedBuilder( - animation: animation, - builder: (context, child) { - return Transform.rotate( - angle: (animation.value * 3.14) / 2, - child: child, - ); - }, - child: const Icon(Icons.chevron_right), - ), - trailing: presets == null - ? const SizedBox.shrink() - : Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: ToggleButtons( - borderRadius: BorderRadius.circular(8), - textStyle: labelStyle, - isSelected: presets!.values - .map((value) => value == values) - .toList(), - onPressed: (index) { - RecommendationAttribute newValues = - presets!.values.elementAt(index); - if (newValues == values) { - onChanged(zeroValues); - minController.text = zeroValues.min.toString(); - targetController.text = zeroValues.target.toString(); - maxController.text = zeroValues.max.toString(); - } else { - onChanged(newValues); - minController.text = newValues.min.toString(); - targetController.text = newValues.target.toString(); - maxController.text = newValues.max.toString(); - } - }, - children: presets!.keys.map((key) => Text(key)).toList(), - ), - ), - onExpansionChanged: (value) { - if (value) { - animation.forward(); - } else { - animation.reverse(); - } - }, - children: [ - const SizedBox(height: 8), - if (constrain.mdAndUp) - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - const SizedBox(width: 16), - Expanded(child: minField), - const SizedBox(width: 16), - Expanded(child: targetField), - const SizedBox(width: 16), - Expanded(child: maxField), - const SizedBox(width: 16), - ], - ) - else - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: Column( - children: [ - minField, - const SizedBox(height: 16), - targetField, - const SizedBox(height: 16), - maxField, - ], + void onSelected(int index) { + RecommendationAttribute newValues = presets!.values.elementAt(index); + if (newValues == values) { + onChanged(zeroValues); + minController.text = zeroValues.min.toString(); + targetController.text = zeroValues.target.toString(); + maxController.text = zeroValues.max.toString(); + } else { + onChanged(newValues); + minController.text = newValues.min.toString(); + targetController.text = newValues.target.toString(); + maxController.text = newValues.max.toString(); + } + } + + return LayoutBuilder(builder: (context, constraints) { + return Accordion( + items: [ + AccordionItem( + trigger: AccordionTrigger( + child: SizedBox( + width: double.infinity, + child: Basic( + title: title.semiBold(), + trailing: presets == null + ? const SizedBox.shrink() + : Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: Row( + spacing: 5, + children: [ + for (final presetEntry in presets?.entries + .toList() ?? + >[]) + Toggle( + value: presetEntry.value == values, + style: const ButtonStyle.outline( + size: ButtonSize.small, + ), + onChanged: (value) { + onSelected( + presets!.entries.toList().indexWhere( + (s) => s.key == presetEntry.key), + ); + }, + child: Text(presetEntry.key), + ), + ], + ), + ), ), ), - const SizedBox(height: 8), - ], - ), + ), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const SizedBox(height: 8), + if (constraints.mdAndUp) + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + const SizedBox(width: 16), + Expanded(child: minField), + const SizedBox(width: 16), + Expanded(child: targetField), + const SizedBox(width: 16), + Expanded(child: maxField), + const SizedBox(width: 16), + ], + ) + else + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Column( + children: [ + minField, + const SizedBox(height: 16), + targetField, + const SizedBox(height: 16), + maxField, + ], + ), + ), + const SizedBox(height: 8), + ], + ), + ), + ], ); }); } diff --git a/lib/modules/library/playlist_generate/seeds_multi_autocomplete.dart b/lib/modules/library/playlist_generate/seeds_multi_autocomplete.dart index 73c58deb..8c19ca6c 100644 --- a/lib/modules/library/playlist_generate/seeds_multi_autocomplete.dart +++ b/lib/modules/library/playlist_generate/seeds_multi_autocomplete.dart @@ -1,8 +1,9 @@ import 'dart:async'; import 'dart:math'; -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart' show Autocomplete; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/extensions/constrains.dart'; enum SelectedItemDisplayType { @@ -20,10 +21,13 @@ class SeedsMultiAutocomplete extends HookWidget { final Widget Function(T option) selectedSeedBuilder; final String Function(T option) displayStringForOption; - final InputDecoration? inputDecoration; final bool enabled; final SelectedItemDisplayType selectedItemDisplayType; + final Widget? placeholder; + final Widget? leading; + final Widget? trailing; + final Widget? label; const SeedsMultiAutocomplete({ super.key, @@ -32,9 +36,12 @@ class SeedsMultiAutocomplete extends HookWidget { required this.autocompleteOptionBuilder, required this.displayStringForOption, required this.selectedSeedBuilder, - this.inputDecoration, this.enabled = true, this.selectedItemDisplayType = SelectedItemDisplayType.wrap, + this.placeholder, + this.leading, + this.trailing, + this.label, }); @override @@ -61,6 +68,10 @@ class SeedsMultiAutocomplete extends HookWidget { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ + if (label != null) ...[ + label!.semiBold(), + const Gap(8), + ], LayoutBuilder(builder: (context, constrains) { return Container( key: containerKey.value, @@ -101,13 +112,15 @@ class SeedsMultiAutocomplete extends HookWidget { focusNode, onFieldSubmitted, ) { - return TextFormField( + return TextField( controller: seedController, onChanged: (value) => textEditingController.text = value, focusNode: focusNode, - onFieldSubmitted: (_) => onFieldSubmitted(), + onSubmitted: (_) => onFieldSubmitted(), enabled: enabled, - decoration: inputDecoration, + leading: leading, + trailing: trailing, + placeholder: placeholder, ); }, ), @@ -120,22 +133,27 @@ class SeedsMultiAutocomplete extends HookWidget { runSpacing: 4, children: seeds.value.map(selectedSeedBuilder).toList(), ), - SelectedItemDisplayType.list => Card( - margin: EdgeInsets.zero, - child: Column( - children: [ - for (final seed in seeds.value) ...[ - selectedSeedBuilder(seed), - if (seeds.value.length > 1 && seed != seeds.value.last) - Divider( - color: theme.colorScheme.primaryContainer, - height: 1, - indent: 12, - endIndent: 12, + SelectedItemDisplayType.list => AnimatedSwitcher( + duration: const Duration(milliseconds: 300), + child: seeds.value.isEmpty + ? const SizedBox.shrink() + : Card( + child: Column( + children: [ + for (final seed in seeds.value) ...[ + selectedSeedBuilder(seed), + if (seeds.value.length > 1 && + seed != seeds.value.last) + Divider( + color: theme.colorScheme.secondary, + height: 1, + indent: 12, + endIndent: 12, + ), + ], + ], ), - ], - ], - ), + ), ), }, ], diff --git a/lib/modules/library/playlist_generate/simple_track_tile.dart b/lib/modules/library/playlist_generate/simple_track_tile.dart index e6cc281f..afa723f3 100644 --- a/lib/modules/library/playlist_generate/simple_track_tile.dart +++ b/lib/modules/library/playlist_generate/simple_track_tile.dart @@ -1,9 +1,10 @@ -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/image/universal_image.dart'; +import 'package:spotube/components/ui/button_tile.dart'; import 'package:spotube/extensions/image.dart'; class SimpleTrackTile extends HookWidget { @@ -17,7 +18,7 @@ class SimpleTrackTile extends HookWidget { @override Widget build(BuildContext context) { - return ListTile( + return ButtonTile( leading: ClipRRect( borderRadius: BorderRadius.circular(8), child: UniversalImage( @@ -28,18 +29,17 @@ class SimpleTrackTile extends HookWidget { width: 40, ), ), - horizontalTitleGap: 10, - contentPadding: const EdgeInsets.symmetric(horizontal: 8), title: Text(track.name!), trailing: onDelete == null ? null - : IconButton( + : IconButton.ghost( icon: const Icon(SpotubeIcons.close), onPressed: onDelete, ), subtitle: Text( track.artists?.map((e) => e.name).join(", ") ?? track.album?.name ?? "", ), + style: ButtonVariance.ghost, ); } } diff --git a/lib/modules/library/user_playlists.dart b/lib/modules/library/user_playlists.dart index 58462bf9..06f08ab6 100644 --- a/lib/modules/library/user_playlists.dart +++ b/lib/modules/library/user_playlists.dart @@ -110,7 +110,7 @@ class UserPlaylists extends HookConsumerWidget { const Gap(10), Button.primary( leading: const Icon(SpotubeIcons.magic), - child: Text(context.l10n.generate_playlist), + child: Text(context.l10n.generate), onPressed: () { ServiceUtils.pushNamed( context, diff --git a/lib/modules/playlist/playlist_create_dialog.dart b/lib/modules/playlist/playlist_create_dialog.dart index 8b231b84..55e7ce77 100644 --- a/lib/modules/playlist/playlist_create_dialog.dart +++ b/lib/modules/playlist/playlist_create_dialog.dart @@ -16,7 +16,6 @@ import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/form/checkbox_form_field.dart'; import 'package:spotube/components/form/text_form_field.dart'; import 'package:spotube/components/image/universal_image.dart'; -import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/provider/spotify/spotify.dart'; @@ -267,19 +266,11 @@ class PlaylistCreateDialogButton extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final mediaQuery = MediaQuery.of(context); final spotify = ref.watch(spotifyProvider); - if (mediaQuery.smAndDown) { - return IconButton.secondary( - icon: const Icon(SpotubeIcons.addFilled), - onPressed: () => showPlaylistDialog(context, spotify), - ); - } - return Button.secondary( leading: const Icon(SpotubeIcons.addFilled), - child: Text(context.l10n.create_playlist), + child: Text(context.l10n.playlist), onPressed: () => showPlaylistDialog(context, spotify), ); } diff --git a/lib/pages/library/playlist_generate/playlist_generate.dart b/lib/pages/library/playlist_generate/playlist_generate.dart index 63565362..2b1e7512 100644 --- a/lib/pages/library/playlist_generate/playlist_generate.dart +++ b/lib/pages/library/playlist_generate/playlist_generate.dart @@ -1,12 +1,15 @@ import 'package:collection/collection.dart'; -import 'package:flutter/material.dart'; + import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/collections/spotify_markets.dart'; import 'package:spotube/collections/spotube_icons.dart'; -import 'package:spotube/modules/library/playlist_generate/multi_select_field.dart'; +import 'package:spotube/components/button/back_button.dart'; +import 'package:spotube/components/ui/button_tile.dart'; + import 'package:spotube/modules/library/playlist_generate/recommendation_attribute_dials.dart'; import 'package:spotube/modules/library/playlist_generate/recommendation_attribute_fields.dart'; import 'package:spotube/modules/library/playlist_generate/seeds_multi_autocomplete.dart'; @@ -33,7 +36,7 @@ class PlaylistGeneratorPage extends HookConsumerWidget { final spotify = ref.watch(spotifyProvider); final theme = Theme.of(context); - final textTheme = theme.textTheme; + final typography = theme.typography; final preferences = ref.watch(userPreferencesProvider); final genresCollection = ref.watch(categoryGenresProvider); @@ -59,14 +62,11 @@ class PlaylistGeneratorPage extends HookConsumerWidget { final artistAutoComplete = SeedsMultiAutocomplete( seeds: artists, enabled: enabled, - inputDecoration: InputDecoration( - labelText: context.l10n.artists, - labelStyle: textTheme.titleMedium, - helperText: context.l10n.select_up_to_count_type( - leftSeedCount, - context.l10n.artists, - ), - ), + label: Text(context.l10n.artists), + placeholder: Text(context.l10n.select_up_to_count_type( + leftSeedCount, + context.l10n.artists, + )), fetchSeeds: (textEditingValue) => spotify.search .get( textEditingValue.text, @@ -83,15 +83,15 @@ class PlaylistGeneratorPage extends HookConsumerWidget { ) .toList(), ), - autocompleteOptionBuilder: (option, onSelected) => ListTile( - leading: CircleAvatar( - backgroundImage: UniversalImage.imageProvider( + autocompleteOptionBuilder: (option, onSelected) => ButtonTile( + leading: Avatar( + initials: "O", + provider: UniversalImage.imageProvider( option.images.asUrlString( placeholder: ImagePlaceholder.artist, ), ), ), - horizontalTitleGap: 20, title: Text(option.name!), subtitle: option.genres?.isNotEmpty != true ? null @@ -101,34 +101,36 @@ class PlaylistGeneratorPage extends HookConsumerWidget { children: option.genres!.mapIndexed( (index, genre) { return Chip( - label: Text(genre), - labelStyle: textTheme.bodySmall?.copyWith( - color: theme.colorScheme.secondary, - fontWeight: FontWeight.w600, - ), - side: BorderSide.none, - backgroundColor: theme.colorScheme.secondaryContainer, + style: ButtonVariance.secondary, + child: Text(genre), ); }, ).toList(), ), - onTap: () => onSelected(option), + onPressed: () => onSelected(option), + style: ButtonVariance.ghost, ), displayStringForOption: (option) => option.name!, - selectedSeedBuilder: (artist) => Chip( - avatar: CircleAvatar( - backgroundImage: UniversalImage.imageProvider( + selectedSeedBuilder: (artist) => OutlineBadge( + leading: Avatar( + initials: artist.name!.substring(0, 1), + size: 30, + provider: UniversalImage.imageProvider( artist.images.asUrlString( placeholder: ImagePlaceholder.artist, ), ), ), - label: Text(artist.name!), - onDeleted: () { - artists.value = [ - ...artists.value..removeWhere((element) => element.id == artist.id) - ]; - }, + trailing: IconButton.ghost( + icon: const Icon(SpotubeIcons.close), + onPressed: () { + artists.value = [ + ...artists.value + ..removeWhere((element) => element.id == artist.id) + ]; + }, + ), + child: Text(artist.name!), ), ); @@ -136,14 +138,11 @@ class PlaylistGeneratorPage extends HookConsumerWidget { seeds: tracks, enabled: enabled, selectedItemDisplayType: SelectedItemDisplayType.list, - inputDecoration: InputDecoration( - labelText: context.l10n.tracks, - labelStyle: textTheme.titleMedium, - helperText: context.l10n.select_up_to_count_type( - leftSeedCount, - context.l10n.tracks, - ), - ), + label: Text(context.l10n.tracks), + placeholder: Text(context.l10n.select_up_to_count_type( + leftSeedCount, + context.l10n.tracks, + )), fetchSeeds: (textEditingValue) => spotify.search .get( textEditingValue.text, @@ -160,22 +159,23 @@ class PlaylistGeneratorPage extends HookConsumerWidget { ) .toList(), ), - autocompleteOptionBuilder: (option, onSelected) => ListTile( - leading: CircleAvatar( - backgroundImage: UniversalImage.imageProvider( + autocompleteOptionBuilder: (option, onSelected) => ButtonTile( + leading: Avatar( + initials: option.name!.substring(0, 1), + provider: UniversalImage.imageProvider( (option.album?.images).asUrlString( placeholder: ImagePlaceholder.artist, ), ), ), - horizontalTitleGap: 20, title: Text(option.name!), subtitle: Text( option.artists?.map((e) => e.name).join(", ") ?? option.album?.name ?? "", ), - onTap: () => onSelected(option), + onPressed: () => onSelected(option), + style: ButtonVariance.ghost, ), displayStringForOption: (option) => option.name!, selectedSeedBuilder: (option) => SimpleTrackTile( @@ -188,42 +188,65 @@ class PlaylistGeneratorPage extends HookConsumerWidget { ), ); - final genreSelector = MultiSelectField( - options: genresCollection.asData?.value ?? [], - selectedOptions: genres.value, - getValueForOption: (option) => option, - onSelected: (value) { + final genreSelector = MultiSelect( + value: genres.value, + searchFilter: (item, query) { + return item.toLowerCase().contains(query.toLowerCase()) ? 1 : 0; + }, + onChanged: (value) { + if (!enabled) return; genres.value = value; }, - dialogTitle: Text(context.l10n.select_genres), - label: Text(context.l10n.add_genres), - helperText: context.l10n.select_up_to_count_type( - leftSeedCount, - context.l10n.genre, + itemBuilder: (context, item) => Text(item), + searchPlaceholder: Text(context.l10n.select_genres), + orderSelectedFirst: false, + popoverAlignment: Alignment.bottomCenter, + popupConstraints: BoxConstraints( + maxHeight: MediaQuery.sizeOf(context).height * .8, ), - enabled: enabled, + placeholder: Text( + context.l10n.select_up_to_count_type( + leftSeedCount, + context.l10n.genre, + ), + ), + children: [ + for (final option in genresCollection.asData?.value ?? []) + SelectItemButton( + value: option, + child: Text(option), + ), + ], ); + final countrySelector = ValueListenableBuilder( valueListenable: market, builder: (context, value, _) { - return DropdownButtonFormField( - decoration: InputDecoration( - labelText: context.l10n.country, - labelStyle: textTheme.titleMedium, + return Select( + placeholder: Text(context.l10n.country), + value: market.value, + onChanged: (value) { + market.value = value!; + }, + searchFilter: (item, query) { + return item.name.toLowerCase().contains(query.toLowerCase()) + ? 1 + : 0; + }, + searchPlaceholder: Text(context.l10n.search), + popupConstraints: BoxConstraints( + maxHeight: MediaQuery.sizeOf(context).height * .8, ), - isExpanded: true, - items: spotifyMarkets + popoverAlignment: Alignment.bottomCenter, + itemBuilder: (context, value) => Text(value.name), + children: spotifyMarkets .map( - (country) => DropdownMenuItem( + (country) => SelectItemButton( value: country.$1, child: Text(country.$2), ), ) .toList(), - value: market.value, - onChanged: (value) { - market.value = value!; - }, ); }, ); @@ -231,395 +254,394 @@ class PlaylistGeneratorPage extends HookConsumerWidget { final controller = useScrollController(); return Scaffold( - appBar: TitleBar( - leading: const [BackButton()], - title: Text(context.l10n.generate_playlist), - ), - body: Scrollbar( + headers: [ + TitleBar( + leading: const [BackButton()], + title: Text(context.l10n.generate), + ) + ], + child: Scrollbar( controller: controller, child: Center( child: ConstrainedBox( constraints: BoxConstraints(maxWidth: Breakpoints.lg), - child: SliderTheme( - data: const SliderThemeData( - overlayShape: RoundSliderOverlayShape(), - ), - child: SafeArea( - child: LayoutBuilder(builder: (context, constrains) { - return ScrollConfiguration( - behavior: ScrollConfiguration.of(context) - .copyWith(scrollbars: false), - child: ListView( - controller: controller, - padding: const EdgeInsets.all(16), - children: [ - ValueListenableBuilder( - valueListenable: limit, - builder: (context, value, child) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - context.l10n.number_of_tracks_generate, - style: textTheme.titleMedium, - ), - Row( - children: [ - Container( - width: 40, - height: 40, - alignment: Alignment.center, - decoration: BoxDecoration( + child: SafeArea( + child: LayoutBuilder(builder: (context, constrains) { + return ScrollConfiguration( + behavior: ScrollConfiguration.of(context) + .copyWith(scrollbars: false), + child: ListView( + controller: controller, + padding: const EdgeInsets.all(16), + children: [ + ValueListenableBuilder( + valueListenable: limit, + builder: (context, value, child) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + context.l10n.number_of_tracks_generate, + style: typography.semiBold, + ), + Row( + spacing: 5, + children: [ + Container( + width: 40, + height: 40, + alignment: Alignment.center, + decoration: BoxDecoration( + color: theme.colorScheme.primary + .withAlpha(25), + shape: BoxShape.circle, + ), + child: Text( + value.round().toString(), + style: typography.large.copyWith( color: theme.colorScheme.primary, - shape: BoxShape.circle, - ), - child: Text( - value.round().toString(), - style: textTheme.bodyLarge?.copyWith( - color: theme - .colorScheme.primaryContainer, - ), ), ), - Expanded( - child: Slider( - value: value.toDouble(), - min: 10, - max: 100, - divisions: 9, - label: value.round().toString(), - onChanged: (value) { - limit.value = value.round(); - }, - ), - ) - ], - ) - ], - ); - }, - ), - const SizedBox(height: 16), - if (constrains.mdAndUp) - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: countrySelector, - ), - const SizedBox(width: 16), - Expanded( - child: genreSelector, - ), + ), + Expanded( + child: Slider( + value: + SliderValue.single(value.toDouble()), + min: 10, + max: 100, + divisions: 9, + onChanged: (value) { + limit.value = value.value.round(); + }, + ), + ) + ], + ) ], - ) - else ...[ - countrySelector, - const SizedBox(height: 16), - genreSelector, - ], - const SizedBox(height: 16), - if (constrains.mdAndUp) - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: artistAutoComplete, - ), - const SizedBox(width: 16), - Expanded( - child: tracksAutocomplete, - ), - ], - ) - else ...[ - artistAutoComplete, - const SizedBox(height: 16), - tracksAutocomplete, - ], - const SizedBox(height: 16), - RecommendationAttributeDials( - title: Text(context.l10n.acousticness), - values: ( - target: target.value.acousticness?.toDouble() ?? 0, - min: min.value.acousticness?.toDouble() ?? 0, - max: max.value.acousticness?.toDouble() ?? 0, - ), - onChanged: (value) { - target.value = target.value.copyWith( - acousticness: value.target, - ); - min.value = min.value.copyWith( - acousticness: value.min, - ); - max.value = max.value.copyWith( - acousticness: value.max, - ); - }, - ), - RecommendationAttributeDials( - title: Text(context.l10n.danceability), - values: ( - target: target.value.danceability?.toDouble() ?? 0, - min: min.value.danceability?.toDouble() ?? 0, - max: max.value.danceability?.toDouble() ?? 0, - ), - onChanged: (value) { - target.value = target.value.copyWith( - danceability: value.target, - ); - min.value = min.value.copyWith( - danceability: value.min, - ); - max.value = max.value.copyWith( - danceability: value.max, - ); - }, - ), - RecommendationAttributeDials( - title: Text(context.l10n.energy), - values: ( - target: target.value.energy?.toDouble() ?? 0, - min: min.value.energy?.toDouble() ?? 0, - max: max.value.energy?.toDouble() ?? 0, - ), - onChanged: (value) { - target.value = target.value.copyWith( - energy: value.target, - ); - min.value = min.value.copyWith( - energy: value.min, - ); - max.value = max.value.copyWith( - energy: value.max, - ); - }, - ), - RecommendationAttributeDials( - title: Text(context.l10n.instrumentalness), - values: ( - target: - target.value.instrumentalness?.toDouble() ?? 0, - min: min.value.instrumentalness?.toDouble() ?? 0, - max: max.value.instrumentalness?.toDouble() ?? 0, - ), - onChanged: (value) { - target.value = target.value.copyWith( - instrumentalness: value.target, - ); - min.value = min.value.copyWith( - instrumentalness: value.min, - ); - max.value = max.value.copyWith( - instrumentalness: value.max, - ); - }, - ), - RecommendationAttributeDials( - title: Text(context.l10n.liveness), - values: ( - target: target.value.liveness?.toDouble() ?? 0, - min: min.value.liveness?.toDouble() ?? 0, - max: max.value.liveness?.toDouble() ?? 0, - ), - onChanged: (value) { - target.value = target.value.copyWith( - liveness: value.target, - ); - min.value = min.value.copyWith( - liveness: value.min, - ); - max.value = max.value.copyWith( - liveness: value.max, - ); - }, - ), - RecommendationAttributeDials( - title: Text(context.l10n.loudness), - values: ( - target: target.value.loudness?.toDouble() ?? 0, - min: min.value.loudness?.toDouble() ?? 0, - max: max.value.loudness?.toDouble() ?? 0, - ), - onChanged: (value) { - target.value = target.value.copyWith( - loudness: value.target, - ); - min.value = min.value.copyWith( - loudness: value.min, - ); - max.value = max.value.copyWith( - loudness: value.max, - ); - }, - ), - RecommendationAttributeDials( - title: Text(context.l10n.speechiness), - values: ( - target: target.value.speechiness?.toDouble() ?? 0, - min: min.value.speechiness?.toDouble() ?? 0, - max: max.value.speechiness?.toDouble() ?? 0, - ), - onChanged: (value) { - target.value = target.value.copyWith( - speechiness: value.target, - ); - min.value = min.value.copyWith( - speechiness: value.min, - ); - max.value = max.value.copyWith( - speechiness: value.max, - ); - }, - ), - RecommendationAttributeDials( - title: Text(context.l10n.valence), - values: ( - target: target.value.valence?.toDouble() ?? 0, - min: min.value.valence?.toDouble() ?? 0, - max: max.value.valence?.toDouble() ?? 0, - ), - onChanged: (value) { - target.value = target.value.copyWith( - valence: value.target, - ); - min.value = min.value.copyWith( - valence: value.min, - ); - max.value = max.value.copyWith( - valence: value.max, - ); - }, - ), - RecommendationAttributeDials( - title: Text(context.l10n.popularity), - base: 100, - values: ( - target: target.value.popularity?.toDouble() ?? 0, - min: min.value.popularity?.toDouble() ?? 0, - max: max.value.popularity?.toDouble() ?? 0, - ), - onChanged: (value) { - target.value = target.value.copyWith( - popularity: value.target, - ); - min.value = min.value.copyWith( - popularity: value.min, - ); - max.value = max.value.copyWith( - popularity: value.max, - ); - }, - ), - RecommendationAttributeDials( - title: Text(context.l10n.key), - base: 11, - values: ( - target: target.value.key?.toDouble() ?? 0, - min: min.value.key?.toDouble() ?? 0, - max: max.value.key?.toDouble() ?? 0, - ), - onChanged: (value) { - target.value = target.value.copyWith( - key: value.target, - ); - min.value = min.value.copyWith( - key: value.min, - ); - max.value = max.value.copyWith( - key: value.max, - ); - }, - ), - RecommendationAttributeFields( - title: Text(context.l10n.duration), - values: ( - max: (max.value.durationMs ?? 0) / 1000, - target: (target.value.durationMs ?? 0) / 1000, - min: (min.value.durationMs ?? 0) / 1000, - ), - onChanged: (value) { - target.value = target.value.copyWith( - durationMs: (value.target * 1000).toInt(), - ); - min.value = min.value.copyWith( - durationMs: (value.min * 1000).toInt(), - ); - max.value = max.value.copyWith( - durationMs: (value.max * 1000).toInt(), - ); - }, - presets: { - context.l10n.short: (min: 50, target: 90, max: 120), - context.l10n.medium: ( - min: 120, - target: 180, - max: 200 + ); + }, + ), + const SizedBox(height: 16), + if (constrains.mdAndUp) + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: countrySelector, ), - context.l10n.long: (min: 480, target: 560, max: 640) - }, + const SizedBox(width: 16), + Expanded( + child: genreSelector, + ), + ], + ) + else ...[ + countrySelector, + const SizedBox(height: 16), + genreSelector, + ], + const SizedBox(height: 16), + if (constrains.mdAndUp) + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: artistAutoComplete, + ), + const SizedBox(width: 16), + Expanded( + child: tracksAutocomplete, + ), + ], + ) + else ...[ + artistAutoComplete, + const SizedBox(height: 16), + tracksAutocomplete, + ], + const SizedBox(height: 16), + RecommendationAttributeDials( + title: Text(context.l10n.acousticness), + values: ( + target: target.value.acousticness?.toDouble() ?? 0, + min: min.value.acousticness?.toDouble() ?? 0, + max: max.value.acousticness?.toDouble() ?? 0, ), - RecommendationAttributeFields( - title: Text(context.l10n.tempo), - values: ( - max: max.value.tempo?.toDouble() ?? 0, - target: target.value.tempo?.toDouble() ?? 0, - min: min.value.tempo?.toDouble() ?? 0, + onChanged: (value) { + target.value = target.value.copyWith( + acousticness: value.target, + ); + min.value = min.value.copyWith( + acousticness: value.min, + ); + max.value = max.value.copyWith( + acousticness: value.max, + ); + }, + ), + RecommendationAttributeDials( + title: Text(context.l10n.danceability), + values: ( + target: target.value.danceability?.toDouble() ?? 0, + min: min.value.danceability?.toDouble() ?? 0, + max: max.value.danceability?.toDouble() ?? 0, + ), + onChanged: (value) { + target.value = target.value.copyWith( + danceability: value.target, + ); + min.value = min.value.copyWith( + danceability: value.min, + ); + max.value = max.value.copyWith( + danceability: value.max, + ); + }, + ), + RecommendationAttributeDials( + title: Text(context.l10n.energy), + values: ( + target: target.value.energy?.toDouble() ?? 0, + min: min.value.energy?.toDouble() ?? 0, + max: max.value.energy?.toDouble() ?? 0, + ), + onChanged: (value) { + target.value = target.value.copyWith( + energy: value.target, + ); + min.value = min.value.copyWith( + energy: value.min, + ); + max.value = max.value.copyWith( + energy: value.max, + ); + }, + ), + RecommendationAttributeDials( + title: Text(context.l10n.instrumentalness), + values: ( + target: + target.value.instrumentalness?.toDouble() ?? 0, + min: min.value.instrumentalness?.toDouble() ?? 0, + max: max.value.instrumentalness?.toDouble() ?? 0, + ), + onChanged: (value) { + target.value = target.value.copyWith( + instrumentalness: value.target, + ); + min.value = min.value.copyWith( + instrumentalness: value.min, + ); + max.value = max.value.copyWith( + instrumentalness: value.max, + ); + }, + ), + RecommendationAttributeDials( + title: Text(context.l10n.liveness), + values: ( + target: target.value.liveness?.toDouble() ?? 0, + min: min.value.liveness?.toDouble() ?? 0, + max: max.value.liveness?.toDouble() ?? 0, + ), + onChanged: (value) { + target.value = target.value.copyWith( + liveness: value.target, + ); + min.value = min.value.copyWith( + liveness: value.min, + ); + max.value = max.value.copyWith( + liveness: value.max, + ); + }, + ), + RecommendationAttributeDials( + title: Text(context.l10n.loudness), + values: ( + target: target.value.loudness?.toDouble() ?? 0, + min: min.value.loudness?.toDouble() ?? 0, + max: max.value.loudness?.toDouble() ?? 0, + ), + onChanged: (value) { + target.value = target.value.copyWith( + loudness: value.target, + ); + min.value = min.value.copyWith( + loudness: value.min, + ); + max.value = max.value.copyWith( + loudness: value.max, + ); + }, + ), + RecommendationAttributeDials( + title: Text(context.l10n.speechiness), + values: ( + target: target.value.speechiness?.toDouble() ?? 0, + min: min.value.speechiness?.toDouble() ?? 0, + max: max.value.speechiness?.toDouble() ?? 0, + ), + onChanged: (value) { + target.value = target.value.copyWith( + speechiness: value.target, + ); + min.value = min.value.copyWith( + speechiness: value.min, + ); + max.value = max.value.copyWith( + speechiness: value.max, + ); + }, + ), + RecommendationAttributeDials( + title: Text(context.l10n.valence), + values: ( + target: target.value.valence?.toDouble() ?? 0, + min: min.value.valence?.toDouble() ?? 0, + max: max.value.valence?.toDouble() ?? 0, + ), + onChanged: (value) { + target.value = target.value.copyWith( + valence: value.target, + ); + min.value = min.value.copyWith( + valence: value.min, + ); + max.value = max.value.copyWith( + valence: value.max, + ); + }, + ), + RecommendationAttributeDials( + title: Text(context.l10n.popularity), + base: 100, + values: ( + target: target.value.popularity?.toDouble() ?? 0, + min: min.value.popularity?.toDouble() ?? 0, + max: max.value.popularity?.toDouble() ?? 0, + ), + onChanged: (value) { + target.value = target.value.copyWith( + popularity: value.target, + ); + min.value = min.value.copyWith( + popularity: value.min, + ); + max.value = max.value.copyWith( + popularity: value.max, + ); + }, + ), + RecommendationAttributeDials( + title: Text(context.l10n.key), + base: 11, + values: ( + target: target.value.key?.toDouble() ?? 0, + min: min.value.key?.toDouble() ?? 0, + max: max.value.key?.toDouble() ?? 0, + ), + onChanged: (value) { + target.value = target.value.copyWith( + key: value.target, + ); + min.value = min.value.copyWith( + key: value.min, + ); + max.value = max.value.copyWith( + key: value.max, + ); + }, + ), + RecommendationAttributeFields( + title: Text(context.l10n.duration), + values: ( + max: (max.value.durationMs ?? 0) / 1000, + target: (target.value.durationMs ?? 0) / 1000, + min: (min.value.durationMs ?? 0) / 1000, + ), + onChanged: (value) { + target.value = target.value.copyWith( + durationMs: (value.target * 1000).toInt(), + ); + min.value = min.value.copyWith( + durationMs: (value.min * 1000).toInt(), + ); + max.value = max.value.copyWith( + durationMs: (value.max * 1000).toInt(), + ); + }, + presets: { + context.l10n.short: (min: 50, target: 90, max: 120), + context.l10n.medium: ( + min: 120, + target: 180, + max: 200 ), - onChanged: (value) { - target.value = target.value.copyWith( - tempo: value.target, - ); - min.value = min.value.copyWith( - tempo: value.min, - ); - max.value = max.value.copyWith( - tempo: value.max, - ); - }, + context.l10n.long: (min: 480, target: 560, max: 640) + }, + ), + RecommendationAttributeFields( + title: Text(context.l10n.tempo), + values: ( + max: max.value.tempo?.toDouble() ?? 0, + target: target.value.tempo?.toDouble() ?? 0, + min: min.value.tempo?.toDouble() ?? 0, ), - RecommendationAttributeFields( - title: Text(context.l10n.mode), - values: ( - max: max.value.mode?.toDouble() ?? 0, - target: target.value.mode?.toDouble() ?? 0, - min: min.value.mode?.toDouble() ?? 0, - ), - onChanged: (value) { - target.value = target.value.copyWith( - mode: value.target, - ); - min.value = min.value.copyWith( - mode: value.min, - ); - max.value = max.value.copyWith( - mode: value.max, - ); - }, + onChanged: (value) { + target.value = target.value.copyWith( + tempo: value.target, + ); + min.value = min.value.copyWith( + tempo: value.min, + ); + max.value = max.value.copyWith( + tempo: value.max, + ); + }, + ), + RecommendationAttributeFields( + title: Text(context.l10n.mode), + values: ( + max: max.value.mode?.toDouble() ?? 0, + target: target.value.mode?.toDouble() ?? 0, + min: min.value.mode?.toDouble() ?? 0, ), - RecommendationAttributeFields( - title: Text(context.l10n.time_signature), - values: ( - max: max.value.timeSignature?.toDouble() ?? 0, - target: target.value.timeSignature?.toDouble() ?? 0, - min: min.value.timeSignature?.toDouble() ?? 0, - ), - onChanged: (value) { - target.value = target.value.copyWith( - timeSignature: value.target, - ); - min.value = min.value.copyWith( - timeSignature: value.min, - ); - max.value = max.value.copyWith( - timeSignature: value.max, - ); - }, + onChanged: (value) { + target.value = target.value.copyWith( + mode: value.target, + ); + min.value = min.value.copyWith( + mode: value.min, + ); + max.value = max.value.copyWith( + mode: value.max, + ); + }, + ), + RecommendationAttributeFields( + title: Text(context.l10n.time_signature), + values: ( + max: max.value.timeSignature?.toDouble() ?? 0, + target: target.value.timeSignature?.toDouble() ?? 0, + min: min.value.timeSignature?.toDouble() ?? 0, ), - const SizedBox(height: 20), - FilledButton.icon( - icon: const Icon(SpotubeIcons.magic), - label: Text(context.l10n.generate_playlist), + onChanged: (value) { + target.value = target.value.copyWith( + timeSignature: value.target, + ); + min.value = min.value.copyWith( + timeSignature: value.min, + ); + max.value = max.value.copyWith( + timeSignature: value.max, + ); + }, + ), + const Gap(20), + Center( + child: Button.primary( + leading: const Icon(SpotubeIcons.magic), onPressed: artists.value.isEmpty && tracks.value.isEmpty && genres.value.isEmpty @@ -643,12 +665,13 @@ class PlaylistGeneratorPage extends HookConsumerWidget { extra: routeState, ); }, + child: Text(context.l10n.generate), ), - ], - ), - ); - }), - ), + ), + ], + ), + ); + }), ), ), ), diff --git a/lib/pages/library/playlist_generate/playlist_generate_result.dart b/lib/pages/library/playlist_generate/playlist_generate_result.dart index f44cbee7..87d6fdc9 100644 --- a/lib/pages/library/playlist_generate/playlist_generate_result.dart +++ b/lib/pages/library/playlist_generate/playlist_generate_result.dart @@ -1,9 +1,10 @@ -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/button/back_button.dart'; import 'package:spotube/modules/library/playlist_generate/simple_track_tile.dart'; import 'package:spotube/modules/playlist/playlist_create_dialog.dart'; import 'package:spotube/components/dialogs/playlist_add_track_dialog.dart'; @@ -27,7 +28,7 @@ class PlaylistGenerateResultPage extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { final router = GoRouter.of(context); - final scaffoldMessenger = ScaffoldMessenger.of(context); + final playlistNotifier = ref.watch(audioPlayerProvider.notifier); final generatedPlaylist = ref.watch(generatePlaylistProvider(state)); @@ -48,8 +49,10 @@ class PlaylistGenerateResultPage extends HookConsumerWidget { (generatedPlaylist.asData?.value.length ?? 0); return Scaffold( - appBar: const TitleBar(leading: [BackButton()]), - body: generatedPlaylist.isLoading + headers: const [ + TitleBar(leading: [BackButton()]) + ], + child: generatedPlaylist.isLoading ? Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, @@ -74,9 +77,8 @@ class PlaylistGenerateResultPage extends HookConsumerWidget { ), shrinkWrap: true, children: [ - FilledButton.tonalIcon( - icon: const Icon(SpotubeIcons.play), - label: Text(context.l10n.play), + Button.primary( + leading: const Icon(SpotubeIcons.play), onPressed: selectedTracks.value.isEmpty ? null : () async { @@ -90,10 +92,10 @@ class PlaylistGenerateResultPage extends HookConsumerWidget { autoPlay: true, ); }, + child: Text(context.l10n.play), ), - FilledButton.tonalIcon( - icon: const Icon(SpotubeIcons.queueAdd), - label: Text(context.l10n.add_to_queue), + Button.primary( + leading: const Icon(SpotubeIcons.queueAdd), onPressed: selectedTracks.value.isEmpty ? null : () async { @@ -103,21 +105,25 @@ class PlaylistGenerateResultPage extends HookConsumerWidget { ), ); if (context.mounted) { - scaffoldMessenger.showSnackBar( - SnackBar( - content: Text( - context.l10n.add_count_to_queue( - selectedTracks.value.length, + showToast( + context: context, + location: ToastLocation.topRight, + builder: (context, overlay) { + return SurfaceCard( + child: Text( + context.l10n.add_count_to_queue( + selectedTracks.value.length, + ), ), - ), - ), + ); + }, ); } }, + child: Text(context.l10n.add_to_queue), ), - FilledButton.tonalIcon( - icon: const Icon(SpotubeIcons.addFilled), - label: Text(context.l10n.create_a_playlist), + Button.primary( + leading: const Icon(SpotubeIcons.addFilled), onPressed: selectedTracks.value.isEmpty ? null : () async { @@ -138,10 +144,10 @@ class PlaylistGenerateResultPage extends HookConsumerWidget { ); } }, + child: Text(context.l10n.create_a_playlist), ), - FilledButton.tonalIcon( - icon: const Icon(SpotubeIcons.playlistAdd), - label: Text(context.l10n.add_to_playlist), + Button.primary( + leading: const Icon(SpotubeIcons.playlistAdd), onPressed: selectedTracks.value.isEmpty ? null : () async { @@ -161,17 +167,22 @@ class PlaylistGenerateResultPage extends HookConsumerWidget { ); if (context.mounted && hasAdded == true) { - scaffoldMessenger.showSnackBar( - SnackBar( - content: Text( - context.l10n.add_count_to_playlist( - selectedTracks.value.length, + showToast( + context: context, + location: ToastLocation.topRight, + builder: (context, overlay) { + return SurfaceCard( + child: Text( + context.l10n.add_count_to_playlist( + selectedTracks.value.length, + ), ), - ), - ), + ); + }, ); } }, + child: Text(context.l10n.add_to_playlist), ) ], ), @@ -185,7 +196,7 @@ class PlaylistGenerateResultPage extends HookConsumerWidget { selectedTracks.value.length, ), ), - ElevatedButton.icon( + Button.secondary( onPressed: () { if (isAllTrackSelected) { selectedTracks.value = []; @@ -197,8 +208,8 @@ class PlaylistGenerateResultPage extends HookConsumerWidget { []; } }, - icon: const Icon(SpotubeIcons.selectionCheck), - label: Text( + leading: const Icon(SpotubeIcons.selectionCheck), + child: Text( isAllTrackSelected ? context.l10n.deselect_all : context.l10n.select_all, @@ -207,32 +218,44 @@ class PlaylistGenerateResultPage extends HookConsumerWidget { ], ), const SizedBox(height: 8), - Card( - margin: const EdgeInsets.all(0), - child: SafeArea( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - for (final track - in generatedPlaylist.asData?.value ?? []) - CheckboxListTile( - value: selectedTracks.value.contains(track.id), - onChanged: (value) { - if (value == true) { - selectedTracks.value.add(track.id!); - } else { - selectedTracks.value.remove(track.id); - } - selectedTracks.value = - selectedTracks.value.toList(); - }, - controlAffinity: ListTileControlAffinity.leading, - contentPadding: EdgeInsets.zero, - dense: true, - title: SimpleTrackTile(track: track), - ) - ], - ), + SafeArea( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + for (final track + in generatedPlaylist.asData?.value ?? []) + Row( + spacing: 5, + children: [ + Checkbox( + state: selectedTracks.value.contains(track.id) + ? CheckboxState.checked + : CheckboxState.unchecked, + onChanged: (value) { + if (value == CheckboxState.checked) { + selectedTracks.value.add(track.id!); + } else { + selectedTracks.value.remove(track.id); + } + selectedTracks.value = + selectedTracks.value.toList(); + }, + ), + Expanded( + child: GestureDetector( + onTap: () { + selectedTracks.value.contains(track.id) + ? selectedTracks.value.remove(track.id) + : selectedTracks.value.add(track.id!); + selectedTracks.value = + selectedTracks.value.toList(); + }, + child: SimpleTrackTile(track: track), + ), + ), + ], + ) + ], ), ), ], diff --git a/untranslated_messages.json b/untranslated_messages.json index fae95f00..a31de6a2 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -1,6 +1,8 @@ { "ar": [ + "playlist", "no_loop", + "generate", "undo", "download_all", "add_all_to_playlist", @@ -10,7 +12,9 @@ ], "bn": [ + "playlist", "no_loop", + "generate", "undo", "download_all", "add_all_to_playlist", @@ -20,7 +24,9 @@ ], "ca": [ + "playlist", "no_loop", + "generate", "undo", "download_all", "add_all_to_playlist", @@ -30,7 +36,9 @@ ], "cs": [ + "playlist", "no_loop", + "generate", "undo", "download_all", "add_all_to_playlist", @@ -40,7 +48,9 @@ ], "de": [ + "playlist", "no_loop", + "generate", "undo", "download_all", "add_all_to_playlist", @@ -50,7 +60,9 @@ ], "es": [ + "playlist", "no_loop", + "generate", "undo", "download_all", "add_all_to_playlist", @@ -60,7 +72,9 @@ ], "eu": [ + "playlist", "no_loop", + "generate", "undo", "download_all", "add_all_to_playlist", @@ -70,7 +84,9 @@ ], "fa": [ + "playlist", "no_loop", + "generate", "undo", "download_all", "add_all_to_playlist", @@ -80,7 +96,9 @@ ], "fi": [ + "playlist", "no_loop", + "generate", "undo", "download_all", "add_all_to_playlist", @@ -90,7 +108,9 @@ ], "fr": [ + "playlist", "no_loop", + "generate", "undo", "download_all", "add_all_to_playlist", @@ -100,7 +120,9 @@ ], "hi": [ + "playlist", "no_loop", + "generate", "undo", "download_all", "add_all_to_playlist", @@ -110,7 +132,9 @@ ], "id": [ + "playlist", "no_loop", + "generate", "undo", "download_all", "add_all_to_playlist", @@ -120,7 +144,9 @@ ], "it": [ + "playlist", "no_loop", + "generate", "undo", "download_all", "add_all_to_playlist", @@ -130,7 +156,9 @@ ], "ja": [ + "playlist", "no_loop", + "generate", "undo", "download_all", "add_all_to_playlist", @@ -140,7 +168,9 @@ ], "ka": [ + "playlist", "no_loop", + "generate", "undo", "download_all", "add_all_to_playlist", @@ -150,7 +180,9 @@ ], "ko": [ + "playlist", "no_loop", + "generate", "undo", "download_all", "add_all_to_playlist", @@ -160,7 +192,9 @@ ], "ne": [ + "playlist", "no_loop", + "generate", "undo", "download_all", "add_all_to_playlist", @@ -170,7 +204,9 @@ ], "nl": [ + "playlist", "no_loop", + "generate", "undo", "download_all", "add_all_to_playlist", @@ -180,7 +216,9 @@ ], "pl": [ + "playlist", "no_loop", + "generate", "undo", "download_all", "add_all_to_playlist", @@ -190,7 +228,9 @@ ], "pt": [ + "playlist", "no_loop", + "generate", "undo", "download_all", "add_all_to_playlist", @@ -200,7 +240,9 @@ ], "ru": [ + "playlist", "no_loop", + "generate", "undo", "download_all", "add_all_to_playlist", @@ -210,7 +252,9 @@ ], "th": [ + "playlist", "no_loop", + "generate", "undo", "download_all", "add_all_to_playlist", @@ -220,7 +264,9 @@ ], "tr": [ + "playlist", "no_loop", + "generate", "undo", "download_all", "add_all_to_playlist", @@ -230,7 +276,9 @@ ], "uk": [ + "playlist", "no_loop", + "generate", "undo", "download_all", "add_all_to_playlist", @@ -240,7 +288,9 @@ ], "vi": [ + "playlist", "no_loop", + "generate", "undo", "download_all", "add_all_to_playlist", @@ -250,7 +300,9 @@ ], "zh": [ + "playlist", "no_loop", + "generate", "undo", "download_all", "add_all_to_playlist", From b7349851999995591cfad973d28807761f70019e Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 5 Jan 2025 16:32:14 +0600 Subject: [PATCH 042/112] refactor: track page --- .../adaptive/adaptive_pop_sheet_list.dart | 1 - lib/components/track_tile/track_options.dart | 112 +++++++++++------- lib/pages/track/track.dart | 79 ++++++------ 3 files changed, 112 insertions(+), 80 deletions(-) diff --git a/lib/components/adaptive/adaptive_pop_sheet_list.dart b/lib/components/adaptive/adaptive_pop_sheet_list.dart index d81ca977..95d3fae7 100644 --- a/lib/components/adaptive/adaptive_pop_sheet_list.dart +++ b/lib/components/adaptive/adaptive_pop_sheet_list.dart @@ -110,7 +110,6 @@ class AdaptivePopSheetList extends StatelessWidget { backgroundColor: context.theme.colorScheme.card, builder: (context) { return ListView.builder( - physics: const NeverScrollableScrollPhysics(), itemCount: childrenModified.length, shrinkWrap: true, itemBuilder: (context, index) { diff --git a/lib/components/track_tile/track_options.dart b/lib/components/track_tile/track_options.dart index ec2fd2f0..14514cde 100644 --- a/lib/components/track_tile/track_options.dart +++ b/lib/components/track_tile/track_options.dart @@ -1,10 +1,10 @@ import 'dart:io'; -import 'package:flutter/material.dart' hide Page; import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotify/spotify.dart' hide Offset; @@ -69,16 +69,20 @@ class TrackOptions extends HookConsumerWidget { void actionShare(BuildContext context, Track track) { final data = "https://open.spotify.com/track/${track.id}"; Clipboard.setData(ClipboardData(text: data)).then((_) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - width: 300, - behavior: SnackBarBehavior.floating, - content: Text( - context.l10n.copied_to_clipboard(data), - textAlign: TextAlign.center, - ), - ), - ); + if (context.mounted) { + showToast( + context: context, + location: ToastLocation.topRight, + builder: (context, overlay) { + return SurfaceCard( + child: Text( + context.l10n.copied_to_clipboard(data), + textAlign: TextAlign.center, + ), + ); + }, + ); + } }); } @@ -161,7 +165,6 @@ class TrackOptions extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final scaffoldMessenger = ScaffoldMessenger.of(context); final mediaQuery = MediaQuery.of(context); final router = GoRouter.of(context); final ThemeData(:colorScheme) = Theme.of(context); @@ -220,36 +223,57 @@ class TrackOptions extends HookConsumerWidget { case TrackOptionValue.addToQueue: await playback.addTrack(track); if (context.mounted) { - scaffoldMessenger.showSnackBar( - SnackBar( - content: Text( - context.l10n.added_track_to_queue(track.name!), - ), - ), + showToast( + context: context, + location: ToastLocation.topRight, + builder: (context, overlay) { + return SurfaceCard( + child: Text( + context.l10n.added_track_to_queue(track.name!), + textAlign: TextAlign.center, + ), + ); + }, ); } break; case TrackOptionValue.playNext: playback.addTracksAtFirst([track]); - scaffoldMessenger.showSnackBar( - SnackBar( - content: Text( - context.l10n.track_will_play_next(track.name!), - ), - ), - ); + + if (context.mounted) { + showToast( + context: context, + location: ToastLocation.topRight, + builder: (context, overlay) { + return SurfaceCard( + child: Text( + context.l10n.track_will_play_next(track.name!), + textAlign: TextAlign.center, + ), + ); + }, + ); + } break; case TrackOptionValue.removeFromQueue: playback.removeTrack(track.id!); - scaffoldMessenger.showSnackBar( - SnackBar( - content: Text( - context.l10n.removed_track_from_queue( - track.name!, - ), - ), - ), - ); + + if (context.mounted) { + showToast( + context: context, + location: ToastLocation.topRight, + builder: (context, overlay) { + return SurfaceCard( + child: Text( + context.l10n.removed_track_from_queue( + track.name!, + ), + textAlign: TextAlign.center, + ), + ); + }, + ); + } break; case TrackOptionValue.favorite: favorites.toggleTrackLike(track); @@ -286,7 +310,10 @@ class TrackOptions extends HookConsumerWidget { case TrackOptionValue.details: showDialog( context: context, - builder: (context) => TrackDetailsDialog(track: track), + builder: (context) => ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 400), + child: TrackDetailsDialog(track: track), + ), ); break; case TrackOptionValue.download: @@ -299,8 +326,7 @@ class TrackOptions extends HookConsumerWidget { }, icon: icon ?? const Icon(SpotubeIcons.moreHorizontal), headings: [ - ListTile( - dense: true, + Basic( leading: AspectRatio( aspectRatio: 1, child: ClipRRect( @@ -316,8 +342,7 @@ class TrackOptions extends HookConsumerWidget { track.name!, maxLines: 1, overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.titleMedium, - ), + ).semiBold(), subtitle: Align( alignment: Alignment.centerLeft, child: ArtistLink( @@ -449,7 +474,7 @@ class TrackOptions extends HookConsumerWidget { leading: Assets.logos.songlinkTransparent.image( width: 22, height: 22, - color: colorScheme.onSurface.withOpacity(0.5), + color: colorScheme.foreground.withOpacity(0.5), ), child: Text(context.l10n.song_link), ), @@ -471,11 +496,6 @@ class TrackOptions extends HookConsumerWidget { adaptivePopSheetList.showDropdownMenu(context, offsetFromRect); }; - return ListTileTheme( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ), - child: adaptivePopSheetList, - ); + return adaptivePopSheetList; } } diff --git a/lib/pages/track/track.dart b/lib/pages/track/track.dart index 30f2e998..54563bfe 100644 --- a/lib/pages/track/track.dart +++ b/lib/pages/track/track.dart @@ -1,8 +1,8 @@ import 'dart:ui'; -import 'package:flutter/material.dart'; import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotube/collections/fake.dart'; import 'package:spotube/collections/spotube_icons.dart'; @@ -32,7 +32,7 @@ class TrackPage extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final ThemeData(:textTheme, :colorScheme) = Theme.of(context); + final ThemeData(:typography, :colorScheme) = Theme.of(context); final mediaQuery = MediaQuery.of(context); final playlist = ref.watch(audioPlayerProvider); @@ -53,12 +53,15 @@ class TrackPage extends HookConsumerWidget { } return Scaffold( - appBar: const TitleBar( - automaticallyImplyLeading: true, - backgroundColor: Colors.transparent, - ), - extendBodyBehindAppBar: true, - body: Stack( + headers: const [ + TitleBar( + automaticallyImplyLeading: true, + backgroundColor: Colors.transparent, + surfaceBlur: 0, + ) + ], + floatingHeader: true, + child: Stack( children: [ Positioned.fill( child: Container( @@ -71,7 +74,7 @@ class TrackPage extends HookConsumerWidget { ), fit: BoxFit.cover, colorFilter: ColorFilter.mode( - colorScheme.surface.withOpacity(0.5), + colorScheme.background.withOpacity(0.5), BlendMode.srcOver, ), alignment: Alignment.topCenter, @@ -89,7 +92,7 @@ class TrackPage extends HookConsumerWidget { decoration: BoxDecoration( gradient: LinearGradient( colors: [ - colorScheme.surface, + colorScheme.background, Colors.transparent, ], begin: Alignment.topCenter, @@ -125,8 +128,7 @@ class TrackPage extends HookConsumerWidget { children: [ Text( track.name!, - style: textTheme.titleLarge, - ), + ).large().semiBold(), const Gap(10), Row( mainAxisSize: MainAxisSize.min, @@ -170,9 +172,10 @@ class TrackPage extends HookConsumerWidget { if (!isActive && !playlist.tracks .containsBy(track, (t) => t.id)) - OutlinedButton.icon( - icon: const Icon(SpotubeIcons.queueAdd), - label: Text(context.l10n.queue), + Button.outline( + leading: + const Icon(SpotubeIcons.queueAdd), + child: Text(context.l10n.queue), onPressed: () { playlistNotifier.addTrack(track); }, @@ -181,27 +184,37 @@ class TrackPage extends HookConsumerWidget { if (!isActive && !playlist.tracks .containsBy(track, (t) => t.id)) - IconButton.outlined( - icon: - const Icon(SpotubeIcons.lightning), - tooltip: context.l10n.play_next, - onPressed: () { - playlistNotifier - .addTracksAtFirst([track]); - }, + Tooltip( + tooltip: TooltipContainer( + child: Text(context.l10n.play_next), + ), + child: IconButton.outline( + icon: const Icon( + SpotubeIcons.lightning), + onPressed: () { + playlistNotifier + .addTracksAtFirst([track]); + }, + ), ), const Gap(5), - IconButton.filled( - tooltip: isActive - ? context.l10n.pause_playback - : context.l10n.play, - icon: Icon( - isActive - ? SpotubeIcons.pause - : SpotubeIcons.play, - color: colorScheme.onPrimary, + Tooltip( + tooltip: TooltipContainer( + child: Text( + isActive + ? context.l10n.pause_playback + : context.l10n.play, + ), + ), + child: IconButton.primary( + shape: ButtonShape.circle, + icon: Icon( + isActive + ? SpotubeIcons.pause + : SpotubeIcons.play, + ), + onPressed: onPlay, ), - onPressed: onPlay, ), const Gap(5), if (mediaQuery.smAndDown) From dff8fe2e64fb334e1c77afdc24417145941c42fe Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 5 Jan 2025 16:50:04 +0600 Subject: [PATCH 043/112] chore: fix alternative source list item theme inconsistency --- lib/components/ui/button_tile.dart | 24 ++-- lib/modules/player/sibling_tracks_sheet.dart | 135 +++++++++---------- 2 files changed, 79 insertions(+), 80 deletions(-) diff --git a/lib/components/ui/button_tile.dart b/lib/components/ui/button_tile.dart index 099691d0..7318e8c4 100644 --- a/lib/components/ui/button_tile.dart +++ b/lib/components/ui/button_tile.dart @@ -9,6 +9,7 @@ class ButtonTile extends StatelessWidget { final void Function()? onPressed; final bool selected; final ButtonVariance style; + final EdgeInsets? padding; const ButtonTile({ super.key, @@ -19,6 +20,7 @@ class ButtonTile extends StatelessWidget { this.enabled = true, this.onPressed, this.selected = false, + this.padding, this.style = ButtonVariance.outline, }); @@ -30,17 +32,23 @@ class ButtonTile extends StatelessWidget { enabled: enabled, onPressed: onPressed, style: style.copyWith( + padding: padding != null ? (context, states, value) => padding! : null, decoration: (context, states, value) { final decoration = style.decoration(context, states) as BoxDecoration; - if (selected && style == ButtonVariance.outline) { - return decoration.copyWith( - border: Border.all( - color: colorScheme.primary, - width: 1.0, - ), - color: colorScheme.primary.withAlpha(25), - ); + if (selected) { + return switch (style) { + ButtonVariance.outline => decoration.copyWith( + border: Border.all( + color: colorScheme.primary, + width: 1.0, + ), + color: colorScheme.primary.withAlpha(25), + ), + ButtonVariance.ghost || _ => decoration.copyWith( + color: colorScheme.primary.withAlpha(25), + ), + }; } return decoration; diff --git a/lib/modules/player/sibling_tracks_sheet.dart b/lib/modules/player/sibling_tracks_sheet.dart index 9bd1ea22..14773156 100644 --- a/lib/modules/player/sibling_tracks_sheet.dart +++ b/lib/modules/player/sibling_tracks_sheet.dart @@ -1,14 +1,14 @@ import 'package:collection/collection.dart'; -import 'package:flutter/material.dart' show ListTile, Material, MaterialType; + import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/collections/assets.gen.dart'; import 'package:spotube/collections/spotube_icons.dart'; - import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/components/inter_scrollbar/inter_scrollbar.dart'; +import 'package:spotube/components/ui/button_tile.dart'; import 'package:spotube/extensions/artist_simple.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/duration.dart'; @@ -18,7 +18,6 @@ import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/provider/audio_player/querying_track_info.dart'; import 'package:spotube/provider/server/active_sourced_track.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.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'; @@ -161,40 +160,36 @@ class SiblingTracksSheet extends HookConsumerWidget { final itemBuilder = useCallback( (SourceInfo sourceInfo) { final icon = sourceInfoToIconMap[sourceInfo.runtimeType]; - return ListTile( - hoverColor: theme.colorScheme.primary.withOpacity(.1), - dense: true, - subtitleTextStyle: theme.typography.small.copyWith( - color: theme.colorScheme.mutedForeground, + return ButtonTile( + style: ButtonVariance.ghost, + padding: const EdgeInsets.symmetric(horizontal: 8), + title: Text( + sourceInfo.title, + maxLines: 2, + overflow: TextOverflow.ellipsis, ), - titleTextStyle: theme.typography.normal, - leadingAndTrailingTextStyle: theme.typography.normal, - title: Text(sourceInfo.title), - horizontalTitleGap: 0, - leading: Padding( - padding: const EdgeInsets.only(top: 8.0, right: 8.0), - child: UniversalImage( - path: sourceInfo.thumbnail, - height: 60, - width: 60, - ), - ), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(5), + leading: UniversalImage( + path: sourceInfo.thumbnail, + height: 60, + width: 60, ), trailing: Text(sourceInfo.duration.toHumanReadableString()), subtitle: Row( children: [ if (icon != null) icon, - Text(" • ${sourceInfo.artist}"), + Flexible( + child: Text( + " • ${sourceInfo.artist}", + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ), ], ), enabled: !isFetchingActiveTrack, selected: !isFetchingActiveTrack && sourceInfo.id == (activeTrack as SourcedTrack).sourceInfo.id, - selectedTileColor: theme.colorScheme.primary.withOpacity(.1), - selectedColor: theme.colorScheme.primary, - onTap: () { + onPressed: () { if (!isFetchingActiveTrack && sourceInfo.id != (activeTrack as SourcedTrack).sourceInfo.id) { activeTrackNotifier.swapSibling(sourceInfo); @@ -222,20 +217,17 @@ class SiblingTracksSheet extends HookConsumerWidget { child: !isSearching.value ? Text( context.l10n.alternative_track_sources, - style: theme.typography.bold, - ) - : Flexible( - child: ConstrainedBox( - constraints: BoxConstraints( - maxWidth: 320 * scale, - maxHeight: 38 * scale, - ), - child: TextField( - autofocus: true, - controller: searchController, - placeholder: Text(context.l10n.search), - style: theme.typography.bold, - ), + ).bold() + : ConstrainedBox( + constraints: BoxConstraints( + maxWidth: 320 * scale, + maxHeight: 38 * scale, + ), + child: TextField( + autofocus: true, + controller: searchController, + placeholder: Text(context.l10n.search), + style: theme.typography.bold, ), ), ), @@ -290,39 +282,38 @@ class SiblingTracksSheet extends HookConsumerWidget { FadeTransition(opacity: animation, child: child), child: InterScrollbar( controller: controller, - child: Material( - type: MaterialType.transparency, - child: switch (isSearching.value) { - false => ListView.builder( - padding: const EdgeInsets.all(8.0), - controller: controller, - itemCount: siblings.length, - itemBuilder: (context, index) => - itemBuilder(siblings[index]), - ), - true => FutureBuilder( - future: searchRequest, - builder: (context, snapshot) { - if (snapshot.hasError) { - return Center( - child: Text(snapshot.error.toString()), - ); - } else if (!snapshot.hasData) { - return const Center( - child: CircularProgressIndicator()); - } - - return ListView.builder( - padding: const EdgeInsets.all(8.0), - controller: controller, - itemCount: snapshot.data!.length, - itemBuilder: (context, index) => - itemBuilder(snapshot.data![index]), + child: switch (isSearching.value) { + false => ListView.separated( + padding: const EdgeInsets.all(8.0), + controller: controller, + itemCount: siblings.length, + separatorBuilder: (context, index) => const Gap(8), + itemBuilder: (context, index) => + itemBuilder(siblings[index]), + ), + true => FutureBuilder( + future: searchRequest, + builder: (context, snapshot) { + if (snapshot.hasError) { + return Center( + child: Text(snapshot.error.toString()), ); - }, - ), - }, - ), + } else if (!snapshot.hasData) { + return const Center( + child: CircularProgressIndicator()); + } + + return ListView.separated( + padding: const EdgeInsets.all(8.0), + controller: controller, + itemCount: snapshot.data!.length, + separatorBuilder: (context, index) => const Gap(8), + itemBuilder: (context, index) => + itemBuilder(snapshot.data![index]), + ); + }, + ), + }, ), ), ), From e6408ccc0d5153f634af991ea1ef3f138d30b49a Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 5 Jan 2025 17:11:58 +0600 Subject: [PATCH 044/112] refactor: genre home section --- .../fallbacks/anonymous_fallback.dart | 4 +- lib/components/fallbacks/not_found.dart | 8 +- lib/modules/home/sections/genres.dart | 88 +++++-------------- lib/pages/lastfm_login/lastfm_login.dart | 19 ++-- 4 files changed, 39 insertions(+), 80 deletions(-) diff --git a/lib/components/fallbacks/anonymous_fallback.dart b/lib/components/fallbacks/anonymous_fallback.dart index 62ed8ddd..cd7a218f 100644 --- a/lib/components/fallbacks/anonymous_fallback.dart +++ b/lib/components/fallbacks/anonymous_fallback.dart @@ -1,5 +1,5 @@ -import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/pages/settings/settings.dart'; @@ -28,7 +28,7 @@ class AnonymousFallback extends ConsumerWidget { children: [ Text(context.l10n.not_logged_in), const SizedBox(height: 10), - FilledButton( + Button.primary( child: Text(context.l10n.login_with_spotify), onPressed: () => ServiceUtils.pushNamed(context, SettingsPage.name), ) diff --git a/lib/components/fallbacks/not_found.dart b/lib/components/fallbacks/not_found.dart index ce168f17..d35a4b50 100644 --- a/lib/components/fallbacks/not_found.dart +++ b/lib/components/fallbacks/not_found.dart @@ -1,4 +1,4 @@ -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/assets.gen.dart'; import 'package:spotube/extensions/context.dart'; @@ -8,7 +8,6 @@ class NotFound extends StatelessWidget { @override Widget build(BuildContext context) { - final theme = Theme.of(context); final widgets = [ SizedBox( height: 150, @@ -19,11 +18,10 @@ class NotFound extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ - Text(context.l10n.nothing_found, style: theme.textTheme.titleLarge), + Text(context.l10n.nothing_found).large().semiBold(), Text( context.l10n.the_box_is_empty, - style: theme.textTheme.titleMedium, - ), + ).semiBold(), ], ), ]; diff --git a/lib/modules/home/sections/genres.dart b/lib/modules/home/sections/genres.dart index 574f3294..f0ed1fb3 100644 --- a/lib/modules/home/sections/genres.dart +++ b/lib/modules/home/sections/genres.dart @@ -1,5 +1,3 @@ -import 'dart:math'; - import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; @@ -8,7 +6,6 @@ import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/collections/fake.dart'; -import 'package:spotube/collections/gradients.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/extensions/constrains.dart'; @@ -84,70 +81,33 @@ class HomeGenresSection extends HookConsumerWidget { final category = categories.elementAtOrNull(index) ?? FakeData.category; - return HookBuilder(builder: (context) { - final (:gradient, :textColor) = useMemoized( - () { - final gradient = - gradients[Random().nextInt(gradients.length)]; - final text = gradient.colors - .take(2) - .any((c) => c.computeLuminance() > 0.5) - ? Colors.gray[900] - : Colors.white; - return ( - gradient: LinearGradient( - colors: gradient.colors - .map((c) => c.withAlpha((0.8 * 255).ceil())) - .toList(), - ), - textColor: text + return Button( + style: ButtonVariance.secondary.copyWith( + padding: (context, states, value) { + return EdgeInsets.zero; + }, + ), + onPressed: () {}, + child: CardImage( + onPressed: () { + context.pushNamed( + GenrePlaylistsPage.name, + pathParameters: { + "categoryId": category.id!, + }, + extra: category, ); }, - [], - ); - - return MouseRegion( - cursor: SystemMouseCursors.click, - child: GestureDetector( - onTap: () { - context.pushNamed( - GenrePlaylistsPage.name, - pathParameters: { - "categoryId": category.id!, - }, - extra: category, - ); - }, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - image: DecorationImage( - image: UniversalImage.imageProvider( - category.icons!.first.url!, - ), - fit: BoxFit.cover, - ), - ), - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(5), - color: context.theme.colorScheme.muted, - gradient: - categoriesQuery.isLoading ? null : gradient, - ), - padding: const EdgeInsets.symmetric(horizontal: 16), - child: Align( - alignment: Alignment.centerLeft, - child: Text( - category.name!, - style: context.theme.typography.large, - ), - ), - ), - ), + direction: Axis.horizontal, + image: UniversalImage( + path: category.icons!.first.url!, + fit: BoxFit.cover, + height: 50, + width: 50, ), - ); - }); + title: Text(category.name!), + ), + ); }, ), ), diff --git a/lib/pages/lastfm_login/lastfm_login.dart b/lib/pages/lastfm_login/lastfm_login.dart index d5466544..89b8270a 100644 --- a/lib/pages/lastfm_login/lastfm_login.dart +++ b/lib/pages/lastfm_login/lastfm_login.dart @@ -36,14 +36,15 @@ class LastFMLoginPage extends HookConsumerWidget { ), ), ], - child: SingleChildScrollView( - child: Container( - constraints: const BoxConstraints(maxWidth: 400), - alignment: Alignment.center, - padding: const EdgeInsets.all(16), - child: Card( - child: Padding( - padding: const EdgeInsets.all(16.0).copyWith(top: 8), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + constraints: const BoxConstraints(maxWidth: 400), + alignment: Alignment.center, + padding: const EdgeInsets.all(16), + child: Card( + padding: const EdgeInsets.all(16.0), child: Form( onSubmit: (context, values) async { try { @@ -136,7 +137,7 @@ class LastFMLoginPage extends HookConsumerWidget { ), ), ), - ), + ], ), ); } From 6dd9b753b01dee248362680999a06e962e23432e Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 6 Jan 2025 14:13:53 +0600 Subject: [PATCH 045/112] refactor: migrate stats to shadcn --- lib/components/links/anchor_button.dart | 2 +- lib/modules/player/player_controls.dart | 8 +- lib/modules/root/update_dialog.dart | 4 +- lib/modules/stats/common/album_item.dart | 9 +- lib/modules/stats/common/artist_item.dart | 14 +- lib/modules/stats/common/playlist_item.dart | 9 +- lib/modules/stats/common/track_item.dart | 9 +- lib/modules/stats/summary/summary.dart | 6 +- lib/modules/stats/summary/summary_card.dart | 26 ++-- lib/modules/stats/top/top.dart | 164 ++++++++++---------- lib/pages/stats/albums/albums.dart | 14 +- lib/pages/stats/artists/artists.dart | 14 +- lib/pages/stats/fees/fees.dart | 68 ++++---- lib/pages/stats/minutes/minutes.dart | 15 +- lib/pages/stats/playlists/playlists.dart | 14 +- lib/pages/stats/stats.dart | 9 +- lib/pages/stats/streams/streams.dart | 15 +- 17 files changed, 206 insertions(+), 194 deletions(-) diff --git a/lib/components/links/anchor_button.dart b/lib/components/links/anchor_button.dart index c6f0b889..a0b3fa73 100644 --- a/lib/components/links/anchor_button.dart +++ b/lib/components/links/anchor_button.dart @@ -1,5 +1,5 @@ -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; class AnchorButton extends HookWidget { final String text; diff --git a/lib/modules/player/player_controls.dart b/lib/modules/player/player_controls.dart index acc3064e..964ff54f 100644 --- a/lib/modules/player/player_controls.dart +++ b/lib/modules/player/player_controls.dart @@ -148,7 +148,10 @@ class PlayerControls extends HookConsumerWidget { ), ), child: IconButton( - icon: const Icon(SpotubeIcons.shuffle), + icon: Icon( + SpotubeIcons.shuffle, + color: shuffled ? theme.colorScheme.primary : null, + ), variance: shuffled ? ButtonVariance.secondary : ButtonVariance.ghost, @@ -228,6 +231,9 @@ class PlayerControls extends HookConsumerWidget { loopMode == PlaylistMode.single ? SpotubeIcons.repeatOne : SpotubeIcons.repeat, + color: loopMode != PlaylistMode.none + ? theme.colorScheme.primary + : null, ), variance: loopMode == PlaylistMode.single || loopMode == PlaylistMode.loop diff --git a/lib/modules/root/update_dialog.dart b/lib/modules/root/update_dialog.dart index 27b857df..4aa2fd13 100644 --- a/lib/modules/root/update_dialog.dart +++ b/lib/modules/root/update_dialog.dart @@ -1,4 +1,4 @@ -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/components/links/anchor_button.dart'; import 'package:url_launcher/url_launcher_string.dart'; import 'package:spotube/extensions/context.dart'; @@ -19,7 +19,7 @@ class RootAppUpdateDialog extends StatelessWidget { return AlertDialog( title: Text(context.l10n.spotube_has_an_update), actions: [ - FilledButton( + Button.primary( child: Text(context.l10n.download_now), onPressed: () => launchUrlString( nightlyBuildNum != null ? nightlyUrl : url, diff --git a/lib/modules/stats/common/album_item.dart b/lib/modules/stats/common/album_item.dart index eec68717..0920baae 100644 --- a/lib/modules/stats/common/album_item.dart +++ b/lib/modules/stats/common/album_item.dart @@ -1,5 +1,6 @@ -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/components/ui/button_tile.dart'; import 'package:spotube/modules/album/album_card.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/components/links/artist_link.dart'; @@ -14,8 +15,8 @@ class StatsAlbumItem extends StatelessWidget { @override Widget build(BuildContext context) { - return ListTile( - horizontalTitleGap: 8, + return ButtonTile( + style: ButtonVariance.ghost, leading: ClipRRect( borderRadius: BorderRadius.circular(4), child: UniversalImage( @@ -47,7 +48,7 @@ class StatsAlbumItem extends StatelessWidget { ], ), trailing: info, - onTap: () { + onPressed: () { ServiceUtils.pushNamed( context, AlbumPage.name, diff --git a/lib/modules/stats/common/artist_item.dart b/lib/modules/stats/common/artist_item.dart index 7e7281da..26691ba4 100644 --- a/lib/modules/stats/common/artist_item.dart +++ b/lib/modules/stats/common/artist_item.dart @@ -1,6 +1,7 @@ -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/image/universal_image.dart'; +import 'package:spotube/components/ui/button_tile.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/pages/artist/artist.dart'; import 'package:spotube/utils/service_utils.dart'; @@ -16,18 +17,19 @@ class StatsArtistItem extends StatelessWidget { @override Widget build(BuildContext context) { - return ListTile( + return ButtonTile( + style: ButtonVariance.ghost, title: Text(artist.name!), - horizontalTitleGap: 8, - leading: CircleAvatar( - backgroundImage: UniversalImage.imageProvider( + leading: Avatar( + initials: artist.name!.substring(0, 1), + provider: UniversalImage.imageProvider( (artist.images).asUrlString( placeholder: ImagePlaceholder.artist, ), ), ), trailing: info, - onTap: () { + onPressed: () { ServiceUtils.pushNamed( context, ArtistPage.name, diff --git a/lib/modules/stats/common/playlist_item.dart b/lib/modules/stats/common/playlist_item.dart index 515c97b3..3859db6b 100644 --- a/lib/modules/stats/common/playlist_item.dart +++ b/lib/modules/stats/common/playlist_item.dart @@ -1,6 +1,7 @@ -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/image/universal_image.dart'; +import 'package:spotube/components/ui/button_tile.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/extensions/string.dart'; import 'package:spotube/pages/playlist/playlist.dart'; @@ -14,8 +15,8 @@ class StatsPlaylistItem extends StatelessWidget { @override Widget build(BuildContext context) { - return ListTile( - horizontalTitleGap: 8, + return ButtonTile( + style: ButtonVariance.ghost, leading: ClipRRect( borderRadius: BorderRadius.circular(4), child: UniversalImage( @@ -33,7 +34,7 @@ class StatsPlaylistItem extends StatelessWidget { overflow: TextOverflow.ellipsis, ), trailing: info, - onTap: () { + onPressed: () { ServiceUtils.pushNamed( context, PlaylistPage.name, diff --git a/lib/modules/stats/common/track_item.dart b/lib/modules/stats/common/track_item.dart index 44e81340..8f0f5b8d 100644 --- a/lib/modules/stats/common/track_item.dart +++ b/lib/modules/stats/common/track_item.dart @@ -1,7 +1,8 @@ -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/components/links/artist_link.dart'; +import 'package:spotube/components/ui/button_tile.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/pages/track/track.dart'; import 'package:spotube/utils/service_utils.dart'; @@ -17,8 +18,8 @@ class StatsTrackItem extends StatelessWidget { @override Widget build(BuildContext context) { - return ListTile( - horizontalTitleGap: 8, + return ButtonTile( + style: ButtonVariance.ghost, leading: ClipRRect( borderRadius: BorderRadius.circular(4), child: UniversalImage( @@ -42,7 +43,7 @@ class StatsTrackItem extends StatelessWidget { ), ), trailing: info, - onTap: () { + onPressed: () { ServiceUtils.pushNamed( context, TrackPage.name, diff --git a/lib/modules/stats/summary/summary.dart b/lib/modules/stats/summary/summary.dart index 46068fec..351b0264 100644 --- a/lib/modules/stats/summary/summary.dart +++ b/lib/modules/stats/summary/summary.dart @@ -1,5 +1,5 @@ -import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotube/collections/fake.dart'; import 'package:spotube/collections/formatters.dart'; @@ -48,7 +48,7 @@ class StatsPageSummarySection extends HookConsumerWidget { title: summaryData.duration.inMinutes.toDouble(), unit: context.l10n.summary_minutes, description: context.l10n.summary_listened_to_music, - color: Colors.purple, + color: Colors.indigo, onTap: () { ServiceUtils.pushNamed(context, StatsMinutesPage.name); }, @@ -57,7 +57,7 @@ class StatsPageSummarySection extends HookConsumerWidget { title: summaryData.tracks.toDouble(), unit: context.l10n.summary_songs, description: context.l10n.summary_streamed_overall, - color: Colors.lightBlue, + color: Colors.blue, onTap: () { ServiceUtils.pushNamed(context, StatsStreamsPage.name); }, diff --git a/lib/modules/stats/summary/summary_card.dart b/lib/modules/stats/summary/summary_card.dart index 243c50e8..e78dd080 100644 --- a/lib/modules/stats/summary/summary_card.dart +++ b/lib/modules/stats/summary/summary_card.dart @@ -1,6 +1,7 @@ import 'package:auto_size_text/auto_size_text.dart'; -import 'package:flutter/material.dart'; -import 'package:gap/gap.dart'; +import 'package:flutter/foundation.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/collections/formatters.dart'; class SummaryCard extends StatelessWidget { @@ -9,7 +10,7 @@ class SummaryCard extends StatelessWidget { final String description; final VoidCallback? onTap; - final MaterialColor color; + final ColorShades color; SummaryCard({ super.key, @@ -31,15 +32,18 @@ class SummaryCard extends StatelessWidget { @override Widget build(BuildContext context) { - final ThemeData(:textTheme, :brightness) = Theme.of(context); + final ThemeData(:typography, :brightness) = Theme.of(context); final descriptionNewLines = description.split("").where((s) => s == "\n"); return Card( - color: brightness == Brightness.dark ? color.shade100 : color.shade50, - child: InkWell( - borderRadius: BorderRadius.circular(16), - onTap: onTap, + fillColor: brightness == Brightness.dark ? color.shade100 : color.shade50, + filled: true, + borderColor: color, + padding: EdgeInsets.zero, + borderRadius: context.theme.borderRadiusLg, + child: Button.ghost( + onPressed: onTap, child: Padding( padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 15), child: Column( @@ -52,13 +56,13 @@ class SummaryCard extends StatelessWidget { children: [ TextSpan( text: title, - style: textTheme.headlineLarge?.copyWith( + style: typography.h2.copyWith( color: color.shade900, ), ), TextSpan( text: " $unit", - style: textTheme.titleMedium?.copyWith( + style: typography.semiBold.copyWith( color: color.shade900, ), ), @@ -73,7 +77,7 @@ class SummaryCard extends StatelessWidget { ? descriptionNewLines.length + 1 : 1, minFontSize: 9, - style: textTheme.labelMedium!.copyWith( + style: typography.small.copyWith( color: color.shade900, ), ), diff --git a/lib/modules/stats/top/top.dart b/lib/modules/stats/top/top.dart index 5c2cfbf9..8e9134c7 100644 --- a/lib/modules/stats/top/top.dart +++ b/lib/modules/stats/top/top.dart @@ -1,6 +1,8 @@ -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; +import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/modules/stats/top/albums.dart'; import 'package:spotube/modules/stats/top/artists.dart'; import 'package:spotube/modules/stats/top/tracks.dart'; @@ -13,94 +15,90 @@ class StatsPageTopSection extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final tabController = useTabController(initialLength: 3); + final selectedIndex = useState(0); final historyDuration = ref.watch(playbackHistoryTopDurationProvider); final historyDurationNotifier = ref.watch(playbackHistoryTopDurationProvider.notifier); - return SliverMainAxisGroup( - slivers: [ - SliverAppBar( - floating: true, - flexibleSpace: TabBar( - controller: tabController, - tabs: [ - Tab( - child: Padding( - padding: const EdgeInsets.all(5), - child: Text(context.l10n.top_tracks), - ), - ), - Tab( - child: Padding( - padding: const EdgeInsets.all(5), - child: Text(context.l10n.top_artists), - ), - ), - Tab( - child: Padding( - padding: const EdgeInsets.all(5), - child: Text(context.l10n.top_albums), - ), - ), - ], + final translations = { + HistoryDuration.days7: context.l10n.this_week, + HistoryDuration.days30: context.l10n.this_month, + HistoryDuration.months6: context.l10n.last_6_months, + HistoryDuration.year: context.l10n.this_year, + HistoryDuration.years2: context.l10n.last_2_years, + HistoryDuration.allTime: context.l10n.all_time, + }; + + final dropdown = Select( + popupConstraints: const BoxConstraints(maxWidth: 150), + popupWidthConstraint: PopoverConstraint.flexible, + padding: const EdgeInsets.all(4), + borderRadius: BorderRadius.circular(4), + value: historyDuration, + onChanged: (value) { + if (value == null) return; + historyDurationNotifier.update((_) => value); + }, + itemBuilder: (context, item) => Text(translations[item]!), + children: [ + for (final item in HistoryDuration.values) + SelectItemButton( + value: item, + child: Text(translations[item]!), ), - ), - SliverToBoxAdapter( - child: Align( - alignment: Alignment.centerRight, - child: DropdownButton( - style: Theme.of(context).textTheme.bodySmall!, - isDense: true, - padding: const EdgeInsets.all(4), - borderRadius: BorderRadius.circular(4), - underline: const SizedBox(), - value: historyDuration, - onChanged: (value) { - if (value == null) return; - historyDurationNotifier.update((_) => value); - }, - icon: const Icon(Icons.arrow_drop_down), - items: [ - DropdownMenuItem( - value: HistoryDuration.days7, - child: Text(context.l10n.this_week), - ), - DropdownMenuItem( - value: HistoryDuration.days30, - child: Text(context.l10n.this_month), - ), - DropdownMenuItem( - value: HistoryDuration.months6, - child: Text(context.l10n.last_6_months), - ), - DropdownMenuItem( - value: HistoryDuration.year, - child: Text(context.l10n.this_year), - ), - DropdownMenuItem( - value: HistoryDuration.years2, - child: Text(context.l10n.last_2_years), - ), - DropdownMenuItem( - value: HistoryDuration.allTime, - child: Text(context.l10n.all_time), - ), - ], - ), - ), - ), - ListenableBuilder( - listenable: tabController, - builder: (context, _) { - return switch (tabController.index) { - 1 => const TopArtists(), - 2 => const TopAlbums(), - _ => const TopTracks(), - }; - }, - ), ], ); + + return SliverLayoutBuilder(builder: (context, constraints) { + return SliverMainAxisGroup( + slivers: [ + SliverAppBar( + floating: true, + elevation: 0, + backgroundColor: context.theme.colorScheme.background, + flexibleSpace: Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + children: [ + TabList( + index: selectedIndex.value, + children: [ + TabButton( + child: Text(context.l10n.top_tracks), + onPressed: () => selectedIndex.value = 0, + ), + TabButton( + child: Text(context.l10n.top_artists), + onPressed: () => selectedIndex.value = 1, + ), + TabButton( + child: Text(context.l10n.top_albums), + onPressed: () => selectedIndex.value = 2, + ), + ], + ), + if (constraints.mdAndUp) ...[ + const Spacer(), + dropdown, + ] + ], + ), + ), + ), + if (constraints.smAndDown) + SliverToBoxAdapter( + child: Align( + alignment: Alignment.centerRight, + child: dropdown, + ), + ), + switch (selectedIndex.value) { + 1 => const TopArtists(), + 2 => const TopAlbums(), + _ => const TopTracks(), + }, + ], + ); + }); } } diff --git a/lib/pages/stats/albums/albums.dart b/lib/pages/stats/albums/albums.dart index b424cd70..eee6694b 100644 --- a/lib/pages/stats/albums/albums.dart +++ b/lib/pages/stats/albums/albums.dart @@ -1,5 +1,5 @@ -import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotube/collections/formatters.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; @@ -25,11 +25,13 @@ class StatsAlbumsPage extends HookConsumerWidget { final albumsData = topAlbums.asData?.value.items ?? []; return Scaffold( - appBar: TitleBar( - automaticallyImplyLeading: true, - title: Text(context.l10n.albums), - ), - body: Skeletonizer( + headers: [ + TitleBar( + automaticallyImplyLeading: true, + title: Text(context.l10n.albums), + ) + ], + child: Skeletonizer( enabled: topAlbums.isLoading && !topAlbums.isLoadingNextPage, child: InfiniteList( onFetchData: () async { diff --git a/lib/pages/stats/artists/artists.dart b/lib/pages/stats/artists/artists.dart index 468ddabb..3a719725 100644 --- a/lib/pages/stats/artists/artists.dart +++ b/lib/pages/stats/artists/artists.dart @@ -1,6 +1,6 @@ -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotube/collections/formatters.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; @@ -28,11 +28,13 @@ class StatsArtistsPage extends HookConsumerWidget { () => topTracks.asData?.value.artists ?? [], [topTracks.asData?.value]); return Scaffold( - appBar: TitleBar( - automaticallyImplyLeading: true, - title: Text(context.l10n.artists), - ), - body: Skeletonizer( + headers: [ + TitleBar( + automaticallyImplyLeading: true, + title: Text(context.l10n.artists), + ) + ], + child: Skeletonizer( enabled: topTracks.isLoading && !topTracks.isLoadingNextPage, child: InfiniteList( onFetchData: () async { diff --git a/lib/pages/stats/fees/fees.dart b/lib/pages/stats/fees/fees.dart index 1bbcb103..14f432d6 100644 --- a/lib/pages/stats/fees/fees.dart +++ b/lib/pages/stats/fees/fees.dart @@ -1,6 +1,6 @@ -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:sliver_tools/sliver_tools.dart'; import 'package:spotube/collections/formatters.dart'; @@ -20,7 +20,6 @@ class StatsStreamFeesPage extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final ThemeData(:textTheme, :hintColor) = Theme.of(context); final duration = useState(HistoryDuration.days30); final topTracks = ref.watch( @@ -40,12 +39,23 @@ class StatsStreamFeesPage extends HookConsumerWidget { [artistsData], ); + final translations = { + HistoryDuration.days7: context.l10n.this_week, + HistoryDuration.days30: context.l10n.this_month, + HistoryDuration.months6: context.l10n.last_6_months, + HistoryDuration.year: context.l10n.this_year, + HistoryDuration.years2: context.l10n.last_2_years, + HistoryDuration.allTime: context.l10n.all_time, + }; + return Scaffold( - appBar: TitleBar( - automaticallyImplyLeading: true, - title: Text(context.l10n.streaming_fees_hypothetical), - ), - body: CustomScrollView( + headers: [ + TitleBar( + automaticallyImplyLeading: true, + title: Text(context.l10n.streaming_fees_hypothetical), + ) + ], + child: CustomScrollView( slivers: [ SliverCrossAxisConstrained( maxCrossAxisExtent: 600, @@ -55,10 +65,7 @@ class StatsStreamFeesPage extends HookConsumerWidget { sliver: SliverToBoxAdapter( child: Text( context.l10n.spotify_hipotetical_calculation, - style: textTheme.bodySmall?.copyWith( - color: hintColor, - ), - ), + ).small().muted(), ), ), ), @@ -70,39 +77,22 @@ class StatsStreamFeesPage extends HookConsumerWidget { children: [ Text( context.l10n.total_money(usdFormatter.format(total)), - style: textTheme.titleLarge, - ), - DropdownButton( + ).semiBold().large(), + Select( value: duration.value, onChanged: (value) { if (value == null) return; duration.value = value; }, - items: [ - DropdownMenuItem( - value: HistoryDuration.days7, - child: Text(context.l10n.this_week), - ), - DropdownMenuItem( - value: HistoryDuration.days30, - child: Text(context.l10n.this_month), - ), - DropdownMenuItem( - value: HistoryDuration.months6, - child: Text(context.l10n.last_6_months), - ), - DropdownMenuItem( - value: HistoryDuration.year, - child: Text(context.l10n.this_year), - ), - DropdownMenuItem( - value: HistoryDuration.years2, - child: Text(context.l10n.last_2_years), - ), - DropdownMenuItem( - value: HistoryDuration.allTime, - child: Text(context.l10n.all_time), - ), + itemBuilder: (context, value) => Text(translations[value]!), + constraints: const BoxConstraints(maxWidth: 150), + popupWidthConstraint: PopoverConstraint.anchorMaxSize, + children: [ + for (final entry in translations.entries) + SelectItemButton( + value: entry.key, + child: Text(entry.value), + ), ], ), ], diff --git a/lib/pages/stats/minutes/minutes.dart b/lib/pages/stats/minutes/minutes.dart index f6cfafca..39438b47 100644 --- a/lib/pages/stats/minutes/minutes.dart +++ b/lib/pages/stats/minutes/minutes.dart @@ -1,6 +1,5 @@ -import 'package:flutter/material.dart'; -import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotube/collections/formatters.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; @@ -28,11 +27,13 @@ class StatsMinutesPage extends HookConsumerWidget { final tracksData = topTracks.asData?.value.items ?? []; return Scaffold( - appBar: TitleBar( - title: Text(context.l10n.minutes_listened), - automaticallyImplyLeading: true, - ), - body: Skeletonizer( + headers: [ + TitleBar( + title: Text(context.l10n.minutes_listened), + automaticallyImplyLeading: true, + ) + ], + child: Skeletonizer( enabled: topTracks.isLoading && !topTracks.isLoadingNextPage, child: InfiniteList( separatorBuilder: (context, index) => const Gap(8), diff --git a/lib/pages/stats/playlists/playlists.dart b/lib/pages/stats/playlists/playlists.dart index 53885570..f5d7a285 100644 --- a/lib/pages/stats/playlists/playlists.dart +++ b/lib/pages/stats/playlists/playlists.dart @@ -1,5 +1,5 @@ -import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotube/collections/formatters.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; @@ -26,11 +26,13 @@ class StatsPlaylistsPage extends HookConsumerWidget { final playlistsData = topPlaylists.asData?.value.items ?? []; return Scaffold( - appBar: TitleBar( - automaticallyImplyLeading: true, - title: Text(context.l10n.playlists), - ), - body: Skeletonizer( + headers: [ + TitleBar( + automaticallyImplyLeading: true, + title: Text(context.l10n.playlists), + ) + ], + child: Skeletonizer( enabled: topPlaylists.isLoading && !topPlaylists.isLoadingNextPage, child: InfiniteList( onFetchData: () async { diff --git a/lib/pages/stats/stats.dart b/lib/pages/stats/stats.dart index 9c35df63..a17e7562 100644 --- a/lib/pages/stats/stats.dart +++ b/lib/pages/stats/stats.dart @@ -1,6 +1,5 @@ -import 'package:flutter/material.dart'; -import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/modules/stats/summary/summary.dart'; import 'package:spotube/modules/stats/top/top.dart'; @@ -16,8 +15,10 @@ class StatsPage extends HookConsumerWidget { return SafeArea( bottom: false, child: Scaffold( - appBar: kIsMacOS || kIsMobile ? null : const TitleBar(), - body: CustomScrollView( + headers: [ + if (kIsWindows || kIsLinux) const TitleBar(), + ], + child: CustomScrollView( slivers: [ if (kIsMacOS) const SliverGap(20), const StatsPageSummarySection(), diff --git a/lib/pages/stats/streams/streams.dart b/lib/pages/stats/streams/streams.dart index b835b3a6..2c2e0c9b 100644 --- a/lib/pages/stats/streams/streams.dart +++ b/lib/pages/stats/streams/streams.dart @@ -1,6 +1,5 @@ -import 'package:flutter/material.dart'; -import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotube/collections/formatters.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; @@ -28,11 +27,13 @@ class StatsStreamsPage extends HookConsumerWidget { final tracksData = topTracks.asData?.value.items ?? []; return Scaffold( - appBar: TitleBar( - title: Text(context.l10n.streamed_songs), - automaticallyImplyLeading: true, - ), - body: Skeletonizer( + headers: [ + TitleBar( + title: Text(context.l10n.streamed_songs), + automaticallyImplyLeading: true, + ) + ], + child: Skeletonizer( enabled: topTracks.isLoading && !topTracks.isLoadingNextPage, child: InfiniteList( separatorBuilder: (context, index) => const Gap(8), From bf94a490bbb4d88c028807522f636a349459160e Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 6 Jan 2025 20:45:37 +0600 Subject: [PATCH 046/112] refactor: genres section --- lib/l10n/app_en.arb | 3 +- lib/modules/home/sections/genres.dart | 217 ++++++++++++++++++++------ lib/utils/service_utils.dart | 14 +- untranslated_messages.json | 78 ++++++--- 4 files changed, 236 insertions(+), 76 deletions(-) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 45a8d78f..c95ec54f 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -408,5 +408,6 @@ "add_all_to_playlist": "Add all to playlist", "add_all_to_queue": "Add all to queue", "play_all_next": "Play all next", - "pause": "Pause" + "pause": "Pause", + "view_all": "View all" } \ No newline at end of file diff --git a/lib/modules/home/sections/genres.dart b/lib/modules/home/sections/genres.dart index f0ed1fb3..57006b59 100644 --- a/lib/modules/home/sections/genres.dart +++ b/lib/modules/home/sections/genres.dart @@ -4,14 +4,16 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:skeletonizer/skeletonizer.dart'; -import 'package:spotify/spotify.dart'; import 'package:spotube/collections/fake.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; +import 'package:spotube/extensions/image.dart'; +import 'package:spotube/extensions/string.dart'; import 'package:spotube/pages/home/genres/genre_playlists.dart'; import 'package:spotube/pages/home/genres/genres.dart'; +import 'package:spotube/pages/playlist/playlist.dart'; import 'package:spotube/provider/spotify/spotify.dart'; class HomeGenresSection extends HookConsumerWidget { @@ -19,7 +21,8 @@ class HomeGenresSection extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final mediaQuery = MediaQuery.of(context); + final theme = context.theme; + final mediaQuery = MediaQuery.sizeOf(context); final categoriesQuery = ref.watch(categoriesProvider); final categories = useMemoized( @@ -28,7 +31,9 @@ class HomeGenresSection extends HookConsumerWidget { .where((c) => (c.icons?.length ?? 0) > 0) .take(mediaQuery.mdAndDown ? 6 : 10) .toList() ?? - [], + [ + FakeData.category, + ], [mediaQuery.mdAndDown, categoriesQuery.asData?.value], ); @@ -61,51 +66,175 @@ class HomeGenresSection extends HookConsumerWidget { ), ), const SliverGap(8), - SliverPadding( - padding: const EdgeInsets.symmetric(horizontal: 16), - sliver: Skeletonizer.sliver( - enabled: categoriesQuery.isLoading, - child: SliverGrid.builder( - gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( - maxCrossAxisExtent: mediaQuery.mdAndDown ? 200 : 250, - mainAxisExtent: 50, - crossAxisSpacing: 16, - mainAxisSpacing: 16, + SliverToBoxAdapter( + child: SizedBox( + height: 280 * theme.scaling, + child: Carousel( + transition: const CarouselTransition.sliding(gap: 24), + sizeConstraint: CarouselSizeConstraint.fixed( + mediaQuery.mdAndUp + ? mediaQuery.width * .6 + : mediaQuery.width * .95, ), - itemCount: categoriesQuery.isLoading - ? mediaQuery.mdAndDown - ? 6 - : 10 - : categories.length, + itemCount: categories.length, + autoplaySpeed: const Duration(seconds: 2), + duration: const Duration(seconds: 5), + pauseOnHover: true, + direction: Axis.horizontal, itemBuilder: (context, index) { - final category = - categories.elementAtOrNull(index) ?? FakeData.category; + final category = categories[index]; + final playlists = + ref.watch(categoryPlaylistsProvider(category.id!)); + final playlistsData = playlists.asData?.value.items.take(8) ?? + List.generate(5, (index) => FakeData.playlistSimple); - return Button( - style: ButtonVariance.secondary.copyWith( - padding: (context, states, value) { - return EdgeInsets.zero; - }, - ), - onPressed: () {}, - child: CardImage( - onPressed: () { - context.pushNamed( - GenrePlaylistsPage.name, - pathParameters: { - "categoryId": category.id!, - }, - extra: category, - ); - }, - direction: Axis.horizontal, - image: UniversalImage( - path: category.icons!.first.url!, - fit: BoxFit.cover, - height: 50, - width: 50, + return Container( + margin: const EdgeInsets.symmetric(horizontal: 8), + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + borderRadius: theme.borderRadiusXxl, + border: Border.all( + color: theme.colorScheme.border, + width: 1, ), - title: Text(category.name!), + image: DecorationImage( + image: UniversalImage.imageProvider( + category.icons!.first.url!, + ), + colorFilter: ColorFilter.mode( + theme.colorScheme.background.withAlpha(125), + BlendMode.darken, + ), + fit: BoxFit.cover, + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 16, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + category.name!, + style: const TextStyle(color: Colors.white), + ).h3(), + Button.link( + onPressed: () { + context.pushNamed( + GenrePlaylistsPage.name, + pathParameters: {'categoryId': category.id!}, + extra: category, + ); + }, + child: Text( + context.l10n.view_all, + style: const TextStyle(color: Colors.white), + ).muted(), + ), + ], + ), + Expanded( + child: Skeleton.ignore( + child: Skeletonizer( + enabled: playlists.isLoading, + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + spacing: 12, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + for (final playlist in playlistsData) + Container( + width: 115 * theme.scaling, + decoration: BoxDecoration( + color: theme.colorScheme.background + .withAlpha(75), + borderRadius: theme.borderRadiusMd, + ), + child: SurfaceBlur( + borderRadius: theme.borderRadiusMd, + surfaceBlur: theme.surfaceBlur, + child: Button( + style: + ButtonVariance.secondary.copyWith( + padding: (context, states, value) => + const EdgeInsets.all(8), + decoration: + (context, states, value) { + final decoration = ButtonVariance + .secondary + .decoration( + context, states) + as BoxDecoration; + + if (states.isNotEmpty) { + return decoration; + } + + return decoration.copyWith( + color: decoration.color + ?.withAlpha(180), + ); + }, + ), + onPressed: () { + context.pushNamed( + PlaylistPage.name, + pathParameters: { + "id": playlist.id!, + }, + extra: playlist, + ); + }, + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + spacing: 5, + children: [ + ClipRRect( + borderRadius: + theme.borderRadiusSm, + child: UniversalImage( + path: (playlist.images)! + .asUrlString( + placeholder: + ImagePlaceholder + .collection, + index: 1, + ), + fit: BoxFit.cover, + height: 100 * theme.scaling, + width: 100 * theme.scaling, + ), + ), + Text( + playlist.name!, + maxLines: 2, + overflow: TextOverflow.ellipsis, + ).semiBold().small(), + if (playlist.description != null) + Text( + playlist.description + ?.unescapeHtml() + .cleanHtml() ?? + "", + maxLines: 2, + overflow: + TextOverflow.ellipsis, + ).xSmall().muted(), + ], + ), + ), + ), + ), + ], + ), + ), + ), + ), + ) + ], ), ); }, diff --git a/lib/utils/service_utils.dart b/lib/utils/service_utils.dart index bdc3877a..2abb98ef 100644 --- a/lib/utils/service_utils.dart +++ b/lib/utils/service_utils.dart @@ -4,6 +4,7 @@ import 'package:dio/dio.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:go_router/go_router.dart'; import 'package:html/dom.dart' hide Text; +import 'package:shadcn_flutter/shadcn_flutter.dart' hide Element; import 'package:spotify/spotify.dart'; import 'package:spotube/modules/library/user_local_tracks.dart'; import 'package:spotube/modules/root/update_dialog.dart'; @@ -20,7 +21,6 @@ import 'package:html/parser.dart' as parser; import 'dart:async'; -import 'package:flutter/material.dart' hide Element; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:spotube/collections/env.dart'; @@ -304,7 +304,9 @@ abstract class ServiceUtils { .map((e) => e.matchedLocation); if (routerState.matchedLocation == location || - routerStack.contains(location)) return; + routerStack.contains(location)) { + return; + } router.push(location, extra: extra); } @@ -418,7 +420,7 @@ abstract class ServiceUtils { await showDialog( context: context, barrierDismissible: true, - barrierColor: Colors.black26, + barrierColor: Colors.black.withAlpha(66), builder: (context) { return RootAppUpdateDialog.nightly(nightlyBuildNum: buildNum); }, @@ -439,14 +441,16 @@ abstract class ServiceUtils { if (currentVersion == null || latestVersion == null || (latestVersion.isPreRelease && !currentVersion.isPreRelease) || - (!latestVersion.isPreRelease && currentVersion.isPreRelease)) return; + (!latestVersion.isPreRelease && currentVersion.isPreRelease)) { + return; + } if (latestVersion <= currentVersion || !context.mounted) return; showDialog( context: context, barrierDismissible: true, - barrierColor: Colors.black26, + barrierColor: Colors.black.withAlpha(66), builder: (context) { return RootAppUpdateDialog(version: latestVersion); }, diff --git a/untranslated_messages.json b/untranslated_messages.json index a31de6a2..ddaf9ab0 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -8,7 +8,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "bn": [ @@ -20,7 +21,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "ca": [ @@ -32,7 +34,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "cs": [ @@ -44,7 +47,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "de": [ @@ -56,7 +60,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "es": [ @@ -68,7 +73,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "eu": [ @@ -80,7 +86,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "fa": [ @@ -92,7 +99,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "fi": [ @@ -104,7 +112,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "fr": [ @@ -116,7 +125,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "hi": [ @@ -128,7 +138,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "id": [ @@ -140,7 +151,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "it": [ @@ -152,7 +164,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "ja": [ @@ -164,7 +177,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "ka": [ @@ -176,7 +190,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "ko": [ @@ -188,7 +203,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "ne": [ @@ -200,7 +216,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "nl": [ @@ -212,7 +229,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "pl": [ @@ -224,7 +242,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "pt": [ @@ -236,7 +255,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "ru": [ @@ -248,7 +268,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "th": [ @@ -260,7 +281,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "tr": [ @@ -272,7 +294,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "uk": [ @@ -284,7 +307,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "vi": [ @@ -296,7 +320,8 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ], "zh": [ @@ -308,6 +333,7 @@ "add_all_to_playlist", "add_all_to_queue", "play_all_next", - "pause" + "pause", + "view_all" ] } From 46852545a942160164bab13f5e2a6707da7eb7d6 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 6 Jan 2025 21:33:26 +0600 Subject: [PATCH 047/112] refactor: add genre carousel buttons and indicators --- lib/modules/home/sections/genres.dart | 440 +++++++++++------- .../local_folder/cache_export_dialog.dart | 19 +- 2 files changed, 274 insertions(+), 185 deletions(-) diff --git a/lib/modules/home/sections/genres.dart b/lib/modules/home/sections/genres.dart index 57006b59..add61a5a 100644 --- a/lib/modules/home/sections/genres.dart +++ b/lib/modules/home/sections/genres.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; @@ -36,209 +38,297 @@ class HomeGenresSection extends HookConsumerWidget { ], [mediaQuery.mdAndDown, categoriesQuery.asData?.value], ); + final controller = useMemoized(() => CarouselController(), []); + final interactedRef = useRef(false); - return SliverMainAxisGroup( - slivers: [ - SliverToBoxAdapter( - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 8), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - context.l10n.genres, - style: context.theme.typography.h4, + useEffect(() { + int times = 0; + Timer.periodic( + const Duration(seconds: 5), + (timer) { + if (times > 5 || interactedRef.value) { + timer.cancel(); + return; + } + controller.animateNext( + const Duration(seconds: 2), + ); + times++; + }, + ); + + return controller.dispose; + }, []); + + return SliverList.list( + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + context.l10n.genres, + style: context.theme.typography.h4, + ), + Directionality( + textDirection: TextDirection.rtl, + child: Button.link( + onPressed: () { + context.pushNamed(GenrePage.name); + }, + leading: const Icon(SpotubeIcons.angleRight), + child: Text( + context.l10n.browse_all, + ).muted(), ), - Directionality( - textDirection: TextDirection.rtl, - child: Button.link( - onPressed: () { - context.pushNamed(GenrePage.name); - }, - leading: const Icon(SpotubeIcons.angleRight), - child: Text( - context.l10n.browse_all, - ).muted(), - ), - ), - ], - ), + ), + ], ), ), - const SliverGap(8), - SliverToBoxAdapter( - child: SizedBox( - height: 280 * theme.scaling, - child: Carousel( - transition: const CarouselTransition.sliding(gap: 24), - sizeConstraint: CarouselSizeConstraint.fixed( - mediaQuery.mdAndUp - ? mediaQuery.width * .6 - : mediaQuery.width * .95, - ), - itemCount: categories.length, - autoplaySpeed: const Duration(seconds: 2), - duration: const Duration(seconds: 5), - pauseOnHover: true, - direction: Axis.horizontal, - itemBuilder: (context, index) { - final category = categories[index]; - final playlists = - ref.watch(categoryPlaylistsProvider(category.id!)); - final playlistsData = playlists.asData?.value.items.take(8) ?? - List.generate(5, (index) => FakeData.playlistSimple); + const Gap(8), + Stack( + children: [ + SizedBox( + height: 280 * theme.scaling, + child: Carousel( + controller: controller, + transition: const CarouselTransition.sliding(gap: 24), + sizeConstraint: CarouselSizeConstraint.fixed( + mediaQuery.mdAndUp + ? mediaQuery.width * .6 + : mediaQuery.width * .95, + ), + itemCount: categories.length, + pauseOnHover: true, + direction: Axis.horizontal, + itemBuilder: (context, index) { + final category = categories[index]; + final playlists = + ref.watch(categoryPlaylistsProvider(category.id!)); + final playlistsData = playlists.asData?.value.items.take(8) ?? + List.generate(5, (index) => FakeData.playlistSimple); - return Container( - margin: const EdgeInsets.symmetric(horizontal: 8), - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - borderRadius: theme.borderRadiusXxl, - border: Border.all( - color: theme.colorScheme.border, - width: 1, - ), - image: DecorationImage( - image: UniversalImage.imageProvider( - category.icons!.first.url!, + return Container( + margin: const EdgeInsets.symmetric(horizontal: 8), + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + borderRadius: theme.borderRadiusXxl, + border: Border.all( + color: theme.colorScheme.border, + width: 1, ), - colorFilter: ColorFilter.mode( - theme.colorScheme.background.withAlpha(125), - BlendMode.darken, + image: DecorationImage( + image: UniversalImage.imageProvider( + category.icons!.first.url!, + ), + colorFilter: ColorFilter.mode( + theme.colorScheme.background.withAlpha(125), + BlendMode.darken, + ), + fit: BoxFit.cover, ), - fit: BoxFit.cover, ), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - spacing: 16, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - category.name!, - style: const TextStyle(color: Colors.white), - ).h3(), - Button.link( - onPressed: () { - context.pushNamed( - GenrePlaylistsPage.name, - pathParameters: {'categoryId': category.id!}, - extra: category, - ); - }, - child: Text( - context.l10n.view_all, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 16, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + category.name!, style: const TextStyle(color: Colors.white), - ).muted(), - ), - ], - ), - Expanded( - child: Skeleton.ignore( - child: Skeletonizer( - enabled: playlists.isLoading, - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: Row( - spacing: 12, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - for (final playlist in playlistsData) - Container( - width: 115 * theme.scaling, - decoration: BoxDecoration( - color: theme.colorScheme.background - .withAlpha(75), - borderRadius: theme.borderRadiusMd, - ), - child: SurfaceBlur( - borderRadius: theme.borderRadiusMd, - surfaceBlur: theme.surfaceBlur, - child: Button( - style: - ButtonVariance.secondary.copyWith( - padding: (context, states, value) => - const EdgeInsets.all(8), - decoration: - (context, states, value) { - final decoration = ButtonVariance - .secondary - .decoration( - context, states) - as BoxDecoration; + ).h3(), + Button.link( + onPressed: () { + context.pushNamed( + GenrePlaylistsPage.name, + pathParameters: {'categoryId': category.id!}, + extra: category, + ); + }, + child: Text( + context.l10n.view_all, + style: const TextStyle(color: Colors.white), + ).muted(), + ), + ], + ), + Expanded( + child: Skeleton.ignore( + child: Skeletonizer( + enabled: playlists.isLoading, + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + spacing: 12, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + for (final playlist in playlistsData) + Container( + width: 115 * theme.scaling, + decoration: BoxDecoration( + color: theme.colorScheme.background + .withAlpha(75), + borderRadius: theme.borderRadiusMd, + ), + child: SurfaceBlur( + borderRadius: theme.borderRadiusMd, + surfaceBlur: theme.surfaceBlur, + child: Button( + style: ButtonVariance.secondary + .copyWith( + padding: + (context, states, value) => + const EdgeInsets.all(8), + decoration: + (context, states, value) { + final decoration = + ButtonVariance.secondary + .decoration( + context, states) + as BoxDecoration; - if (states.isNotEmpty) { - return decoration; - } + if (states.isNotEmpty) { + return decoration; + } - return decoration.copyWith( - color: decoration.color - ?.withAlpha(180), + return decoration.copyWith( + color: decoration.color + ?.withAlpha(180), + ); + }, + ), + onPressed: () { + context.pushNamed( + PlaylistPage.name, + pathParameters: { + "id": playlist.id!, + }, + extra: playlist, ); }, - ), - onPressed: () { - context.pushNamed( - PlaylistPage.name, - pathParameters: { - "id": playlist.id!, - }, - extra: playlist, - ); - }, - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - spacing: 5, - children: [ - ClipRRect( - borderRadius: - theme.borderRadiusSm, - child: UniversalImage( - path: (playlist.images)! - .asUrlString( - placeholder: - ImagePlaceholder - .collection, - index: 1, + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + spacing: 5, + children: [ + ClipRRect( + borderRadius: + theme.borderRadiusSm, + child: UniversalImage( + path: (playlist.images)! + .asUrlString( + placeholder: + ImagePlaceholder + .collection, + index: 1, + ), + fit: BoxFit.cover, + height: 100 * theme.scaling, + width: 100 * theme.scaling, ), - fit: BoxFit.cover, - height: 100 * theme.scaling, - width: 100 * theme.scaling, ), - ), - Text( - playlist.name!, - maxLines: 2, - overflow: TextOverflow.ellipsis, - ).semiBold().small(), - if (playlist.description != null) Text( - playlist.description - ?.unescapeHtml() - .cleanHtml() ?? - "", + playlist.name!, maxLines: 2, overflow: TextOverflow.ellipsis, - ).xSmall().muted(), - ], + ).semiBold().small(), + if (playlist.description != + null) + Text( + playlist.description + ?.unescapeHtml() + .cleanHtml() ?? + "", + maxLines: 2, + overflow: + TextOverflow.ellipsis, + ).xSmall().muted(), + ], + ), ), ), ), - ), - ], + ], + ), ), ), ), - ), - ) + ) + ], + ), + ); + }, + ), + ), + Positioned( + left: 0, + child: Container( + height: 280 * theme.scaling, + width: (mediaQuery.mdAndUp ? 80 : 50) * theme.scaling, + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.centerLeft, + end: Alignment.centerRight, + colors: [ + theme.colorScheme.background.withAlpha(255), + theme.colorScheme.background.withAlpha(0), ], ), - ); - }, + ), + alignment: Alignment.center, + child: IconButton.ghost( + size: + mediaQuery.mdAndUp ? ButtonSize.normal : ButtonSize.small, + icon: const Icon(SpotubeIcons.angleLeft), + onPressed: () { + controller.animatePrevious( + const Duration(seconds: 1), + ); + interactedRef.value = true; + }, + ), + ), ), + Positioned( + right: 0, + child: Container( + height: 280 * theme.scaling, + width: (mediaQuery.mdAndUp ? 80 : 50) * theme.scaling, + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.centerLeft, + end: Alignment.centerRight, + colors: [ + theme.colorScheme.background.withAlpha(0), + theme.colorScheme.background.withAlpha(255), + ], + ), + ), + alignment: Alignment.center, + child: IconButton.ghost( + size: + mediaQuery.mdAndUp ? ButtonSize.normal : ButtonSize.small, + icon: const Icon(SpotubeIcons.angleRight), + onPressed: () { + controller.animateNext( + const Duration(seconds: 1), + ); + interactedRef.value = true; + }, + ), + ), + ), + ], + ), + const Gap(8), + Center( + child: CarouselDotIndicator( + itemCount: categories.length, + controller: controller, ), ), ], diff --git a/lib/modules/library/local_folder/cache_export_dialog.dart b/lib/modules/library/local_folder/cache_export_dialog.dart index 1d1421be..0f10defc 100644 --- a/lib/modules/library/local_folder/cache_export_dialog.dart +++ b/lib/modules/library/local_folder/cache_export_dialog.dart @@ -1,10 +1,9 @@ import 'dart:io'; -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:path/path.dart'; +import 'package:path/path.dart' as path; import 'package:spotube/extensions/context.dart'; import 'package:spotube/services/logger/logger.dart'; import 'package:spotube/services/sourced_track/enums.dart'; @@ -22,7 +21,7 @@ class LocalFolderCacheExportDialog extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final ThemeData(:textTheme, :colorScheme) = Theme.of(context); + final ThemeData(:typography, :colorScheme) = Theme.of(context); final files = useState>([]); final filesExported = useState(0); @@ -31,7 +30,7 @@ class LocalFolderCacheExportDialog extends HookConsumerWidget { final stream = cacheDir.list().where( (event) => event is File && - codecs.contains(extension(event.path).replaceAll(".", "")), + codecs.contains(path.extension(event.path).replaceAll(".", "")), ); stream.listen( @@ -76,8 +75,8 @@ class LocalFolderCacheExportDialog extends HookConsumerWidget { ), TextSpan( text: "\n${exportDir.path}?", - style: textTheme.labelMedium!.copyWith( - color: colorScheme.secondary, + style: typography.small.copyWith( + color: colorScheme.mutedForeground, ), ), ], @@ -102,7 +101,7 @@ class LocalFolderCacheExportDialog extends HookConsumerWidget { ), ), actions: [ - TextButton( + Button.outline( onPressed: isExportInProgress ? null : () { @@ -110,14 +109,14 @@ class LocalFolderCacheExportDialog extends HookConsumerWidget { }, child: Text(context.l10n.cancel), ), - TextButton( + Button.primary( onPressed: isExportInProgress ? null : () async { for (final file in files.value) { try { final destinationFile = File( - join(exportDir.path, basename(file.path)), + path.join(exportDir.path, path.basename(file.path)), ); if (await destinationFile.exists()) { From 3ffcb48db9bcc377b78cab33342172464180ab7d Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 6 Jan 2025 21:44:06 +0600 Subject: [PATCH 048/112] chore: improve carousel performance --- lib/modules/home/sections/genres.dart | 174 +++++++++++++------------- 1 file changed, 84 insertions(+), 90 deletions(-) diff --git a/lib/modules/home/sections/genres.dart b/lib/modules/home/sections/genres.dart index add61a5a..9309e2e7 100644 --- a/lib/modules/home/sections/genres.dart +++ b/lib/modules/home/sections/genres.dart @@ -31,12 +31,12 @@ class HomeGenresSection extends HookConsumerWidget { () => categoriesQuery.asData?.value .where((c) => (c.icons?.length ?? 0) > 0) - .take(mediaQuery.mdAndDown ? 6 : 10) + .take(6) .toList() ?? [ FakeData.category, ], - [mediaQuery.mdAndDown, categoriesQuery.asData?.value], + [categoriesQuery.asData?.value], ); final controller = useMemoized(() => CarouselController(), []); final interactedRef = useRef(false); @@ -159,101 +159,95 @@ class HomeGenresSection extends HookConsumerWidget { child: Skeleton.ignore( child: Skeletonizer( enabled: playlists.isLoading, - child: SingleChildScrollView( + child: ListView.separated( scrollDirection: Axis.horizontal, - child: Row( - spacing: 12, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - for (final playlist in playlistsData) - Container( - width: 115 * theme.scaling, - decoration: BoxDecoration( - color: theme.colorScheme.background - .withAlpha(75), - borderRadius: theme.borderRadiusMd, + itemCount: playlistsData.length, + separatorBuilder: (context, index) => + const Gap(12), + itemBuilder: (context, index) { + final playlist = + playlistsData.elementAt(index); + + return Container( + width: 115 * theme.scaling, + decoration: BoxDecoration( + color: theme.colorScheme.background + .withAlpha(75), + borderRadius: theme.borderRadiusMd, + ), + child: SurfaceBlur( + borderRadius: theme.borderRadiusMd, + surfaceBlur: theme.surfaceBlur, + child: Button( + style: + ButtonVariance.secondary.copyWith( + padding: (context, states, value) => + const EdgeInsets.all(8), + decoration: (context, states, value) { + final decoration = ButtonVariance + .secondary + .decoration(context, states) + as BoxDecoration; + + if (states.isNotEmpty) { + return decoration; + } + + return decoration.copyWith( + color: decoration.color + ?.withAlpha(180), + ); + }, ), - child: SurfaceBlur( - borderRadius: theme.borderRadiusMd, - surfaceBlur: theme.surfaceBlur, - child: Button( - style: ButtonVariance.secondary - .copyWith( - padding: - (context, states, value) => - const EdgeInsets.all(8), - decoration: - (context, states, value) { - final decoration = - ButtonVariance.secondary - .decoration( - context, states) - as BoxDecoration; - - if (states.isNotEmpty) { - return decoration; - } - - return decoration.copyWith( - color: decoration.color - ?.withAlpha(180), - ); - }, - ), - onPressed: () { - context.pushNamed( - PlaylistPage.name, - pathParameters: { - "id": playlist.id!, - }, - extra: playlist, - ); + onPressed: () { + context.pushNamed( + PlaylistPage.name, + pathParameters: { + "id": playlist.id!, }, - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - spacing: 5, - children: [ - ClipRRect( - borderRadius: - theme.borderRadiusSm, - child: UniversalImage( - path: (playlist.images)! - .asUrlString( - placeholder: - ImagePlaceholder - .collection, - index: 1, - ), - fit: BoxFit.cover, - height: 100 * theme.scaling, - width: 100 * theme.scaling, - ), + extra: playlist, + ); + }, + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + spacing: 5, + children: [ + ClipRRect( + borderRadius: + theme.borderRadiusSm, + child: UniversalImage( + path: (playlist.images)! + .asUrlString( + placeholder: ImagePlaceholder + .collection, + index: 1, ), - Text( - playlist.name!, - maxLines: 2, - overflow: - TextOverflow.ellipsis, - ).semiBold().small(), - if (playlist.description != - null) - Text( - playlist.description - ?.unescapeHtml() - .cleanHtml() ?? - "", - maxLines: 2, - overflow: - TextOverflow.ellipsis, - ).xSmall().muted(), - ], + fit: BoxFit.cover, + height: 100 * theme.scaling, + width: 100 * theme.scaling, + ), ), - ), + Text( + playlist.name!, + maxLines: 2, + overflow: TextOverflow.ellipsis, + ).semiBold().small(), + if (playlist.description != null) + Text( + playlist.description + ?.unescapeHtml() + .cleanHtml() ?? + "", + maxLines: 2, + overflow: TextOverflow.ellipsis, + ).xSmall().muted(), + ], ), ), - ], - ), + ), + ); + }, ), ), ), From e54a6460732c8360346187a5a250853b368123a4 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 8 Jan 2025 19:11:29 +0600 Subject: [PATCH 049/112] refactor: downloads page to shadcn --- .../local_folder/local_folder_item.dart | 20 +++---- lib/modules/library/user_downloads.dart | 11 +--- .../library/user_downloads/download_item.dart | 58 +++++++++---------- 3 files changed, 39 insertions(+), 50 deletions(-) diff --git a/lib/modules/library/local_folder/local_folder_item.dart b/lib/modules/library/local_folder/local_folder_item.dart index 84e43e96..20845ef7 100644 --- a/lib/modules/library/local_folder/local_folder_item.dart +++ b/lib/modules/library/local_folder/local_folder_item.dart @@ -77,17 +77,15 @@ class LocalFolderItem extends HookConsumerWidget { mainAxisSize: MainAxisSize.min, children: [ if (tracks.isEmpty) - Card( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Icon( - SpotubeIcons.folder, - size: mediaQuery.smAndDown - ? 95 - : mediaQuery.mdAndDown - ? 100 - : 142, - ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Icon( + SpotubeIcons.folder, + size: mediaQuery.smAndDown + ? 95 + : mediaQuery.mdAndDown + ? 100 + : 142, ), ) else diff --git a/lib/modules/library/user_downloads.dart b/lib/modules/library/user_downloads.dart index 7fe9800c..5db30342 100644 --- a/lib/modules/library/user_downloads.dart +++ b/lib/modules/library/user_downloads.dart @@ -1,6 +1,6 @@ import 'package:auto_size_text/auto_size_text.dart'; -import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/modules/library/user_downloads/download_item.dart'; import 'package:spotube/extensions/context.dart'; @@ -31,15 +31,10 @@ class UserDownloads extends HookConsumerWidget { context.l10n .currently_downloading(downloadManager.$downloadCount), maxLines: 1, - style: Theme.of(context).textTheme.titleMedium, - ), + ).semiBold(), ), const SizedBox(width: 10), - FilledButton( - style: FilledButton.styleFrom( - backgroundColor: Colors.red[50], - foregroundColor: Colors.red[400], - ), + Button.destructive( onPressed: downloadManager.$downloadCount == 0 ? null : downloadManager.cancelAll, diff --git a/lib/modules/library/user_downloads/download_item.dart b/lib/modules/library/user_downloads/download_item.dart index c4bd7bce..4b104ed1 100644 --- a/lib/modules/library/user_downloads/download_item.dart +++ b/lib/modules/library/user_downloads/download_item.dart @@ -1,10 +1,11 @@ -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/components/links/artist_link.dart'; +import 'package:spotube/components/ui/button_tile.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/pages/track/track.dart'; @@ -46,7 +47,8 @@ class DownloadItem extends HookConsumerWidget { final isQueryingSourceInfo = taskStatus.value == null || track is! SourcedTrack; - return ListTile( + return ButtonTile( + style: ButtonVariance.ghost, leading: Padding( padding: const EdgeInsets.symmetric(horizontal: 5), child: ClipRRect( @@ -73,10 +75,7 @@ class DownloadItem extends HookConsumerWidget { ), ), trailing: isQueryingSourceInfo - ? Text( - context.l10n.querying_info, - style: Theme.of(context).textTheme.labelMedium, - ) + ? Text(context.l10n.querying_info).small() : switch (taskStatus.value!) { DownloadStatus.downloading => HookBuilder(builder: (context) { final taskProgress = useListenable(useMemoized( @@ -84,39 +83,36 @@ class DownloadItem extends HookConsumerWidget { .getProgressNotifier(track as SourcedTrack), [track], )); - return SizedBox( - width: 140, - child: Row( - children: [ - CircularProgressIndicator( - value: taskProgress?.value ?? 0, - ), - const SizedBox(width: 10), - IconButton( - icon: const Icon(SpotubeIcons.pause), - onPressed: () { - downloadManager.pause(track as SourcedTrack); - }), - const SizedBox(width: 10), - IconButton( - icon: const Icon(SpotubeIcons.close), - onPressed: () { - downloadManager.cancel(track as SourcedTrack); - }), - ], - ), + return Row( + children: [ + CircularProgressIndicator( + value: taskProgress?.value ?? 0, + ), + const SizedBox(width: 10), + IconButton.ghost( + icon: const Icon(SpotubeIcons.pause), + onPressed: () { + downloadManager.pause(track as SourcedTrack); + }), + const SizedBox(width: 10), + IconButton.ghost( + icon: const Icon(SpotubeIcons.close), + onPressed: () { + downloadManager.cancel(track as SourcedTrack); + }), + ], ); }), DownloadStatus.paused => Row( mainAxisSize: MainAxisSize.min, children: [ - IconButton( + IconButton.ghost( icon: const Icon(SpotubeIcons.play), onPressed: () { downloadManager.resume(track as SourcedTrack); }), const SizedBox(width: 10), - IconButton( + IconButton.ghost( icon: const Icon(SpotubeIcons.close), onPressed: () { downloadManager.cancel(track as SourcedTrack); @@ -132,7 +128,7 @@ class DownloadItem extends HookConsumerWidget { color: Colors.red[400], ), const SizedBox(width: 10), - IconButton( + IconButton.ghost( icon: const Icon(SpotubeIcons.refresh), onPressed: () { downloadManager.retry(track as SourcedTrack); @@ -143,7 +139,7 @@ class DownloadItem extends HookConsumerWidget { ), DownloadStatus.completed => Icon(SpotubeIcons.done, color: Colors.green[400]), - DownloadStatus.queued => IconButton( + DownloadStatus.queued => IconButton.ghost( icon: const Icon(SpotubeIcons.close), onPressed: () { downloadManager.removeFromQueue(track as SourcedTrack); From 88906098dd229338cf811963c5b539aabccfeadd Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 8 Jan 2025 22:16:46 +0600 Subject: [PATCH 050/112] refactor: use shadcn for TrackTile --- .../track_presentation.dart | 15 +- .../use_track_tile_play_callback.dart | 6 +- lib/components/track_tile/track_tile.dart | 399 +++++++++--------- lib/components/ui/button_tile.dart | 129 +++--- lib/extensions/button_variance.dart | 21 + lib/modules/home/sections/genres.dart | 7 +- 6 files changed, 309 insertions(+), 268 deletions(-) create mode 100644 lib/extensions/button_variance.dart diff --git a/lib/components/track_presentation/track_presentation.dart b/lib/components/track_presentation/track_presentation.dart index 4f1db832..47089bd6 100644 --- a/lib/components/track_presentation/track_presentation.dart +++ b/lib/components/track_presentation/track_presentation.dart @@ -1,4 +1,3 @@ -import 'package:flutter/material.dart' show ListTile; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; @@ -21,9 +20,6 @@ class TrackPresentation extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final headerTextStyle = context.theme.typography.small.copyWith( - color: context.theme.colorScheme.mutedForeground, - ); final scrollController = useScrollController(); final focusNode = useFocusNode(); final scale = context.theme.scaling; @@ -66,10 +62,11 @@ class TrackPresentation extends HookConsumerWidget { TrackPresentationModifiersSection( focusNode: focusNode, ), - ListTile( - titleTextStyle: headerTextStyle, - subtitleTextStyle: headerTextStyle, - leadingAndTrailingTextStyle: headerTextStyle, + Basic( + padding: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 16, + ), leading: constrains.mdAndUp ? const Text(" #") : null, title: Row( children: [ @@ -85,7 +82,7 @@ class TrackPresentation extends HookConsumerWidget { Text(context.l10n.duration), ], ), - ), + ).small().muted(), ], ); }, diff --git a/lib/components/track_presentation/use_track_tile_play_callback.dart b/lib/components/track_presentation/use_track_tile_play_callback.dart index 74608205..b519f781 100644 --- a/lib/components/track_presentation/use_track_tile_play_callback.dart +++ b/lib/components/track_presentation/use_track_tile_play_callback.dart @@ -32,7 +32,11 @@ Future Function(Track track, int index) useTrackTilePlayCallback( ref.read(presentationStateProvider(options.collection).notifier); if (state.selectedTracks.isNotEmpty) { - notifier.selectTrack(track); + if (state.selectedTracks.contains(track)) { + notifier.deselectTrack(track); + } else { + notifier.selectTrack(track); + } return; } diff --git a/lib/components/track_tile/track_tile.dart b/lib/components/track_tile/track_tile.dart index 560d2255..0ca14979 100644 --- a/lib/components/track_tile/track_tile.dart +++ b/lib/components/track_tile/track_tile.dart @@ -1,8 +1,8 @@ import 'dart:async'; import 'package:flutter/gestures.dart'; -import 'package:flutter/material.dart' show ListTile, Material, MaterialType; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; @@ -14,7 +14,9 @@ import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/components/links/artist_link.dart'; import 'package:spotube/components/links/link_text.dart'; import 'package:spotube/components/track_tile/track_options.dart'; +import 'package:spotube/components/ui/button_tile.dart'; import 'package:spotube/extensions/artist_simple.dart'; +import 'package:spotube/extensions/button_variance.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/duration.dart'; import 'package:spotube/extensions/image.dart'; @@ -89,225 +91,232 @@ class TrackTile extends HookConsumerWidget { }, child: HoverBuilder( permanentState: isSelected || constrains.smAndDown ? true : null, - builder: (context, isHovering) => Material( - type: MaterialType.transparency, - child: ListTile( - selectedColor: theme.colorScheme.primary, - selectedTileColor: theme.colorScheme.primary.withOpacity(0.1), - selected: isSelected, - onTap: () async { - try { - isLoading.value = true; - await onTap?.call(); - } finally { - if (context.mounted) { - isLoading.value = false; - } + builder: (context, isHovering) => ButtonTile( + selected: isSelected, + onPressed: () async { + if (isBlackListed) return; + try { + isLoading.value = true; + await onTap?.call(); + } finally { + if (context.mounted) { + isLoading.value = false; } - }, - onLongPress: onLongPress, - enabled: !isBlackListed, - contentPadding: EdgeInsets.zero, - tileColor: isBlackListed ? theme.colorScheme.destructive : null, - horizontalTitleGap: 12, - leadingAndTrailingTextStyle: theme.typography.normal.copyWith( - color: theme.colorScheme.foreground, - ), - titleTextStyle: theme.typography.normal.copyWith( - color: theme.colorScheme.foreground, - ), - subtitleTextStyle: theme.typography.xSmall.copyWith( - color: theme.colorScheme.mutedForeground, - ), - leading: Row( - mainAxisSize: MainAxisSize.min, - children: [ - ...?leadingActions, - AnimatedCrossFade( - duration: const Duration(milliseconds: 300), - crossFadeState: index != null && onChanged == null - ? CrossFadeState.showSecond - : CrossFadeState.showFirst, - firstChild: Checkbox( - state: selected - ? CheckboxState.checked - : CheckboxState.unchecked, - onChanged: (state) => - onChanged?.call(state == CheckboxState.checked), - ), - secondChild: constrains.smAndDown - ? const SizedBox(width: 16) - : SizedBox( - width: 50, - child: Padding( - padding: - const EdgeInsets.symmetric(horizontal: 6), - child: Text( - '${(index ?? 0) + 1}', - maxLines: 1, - style: theme.typography.small, - textAlign: TextAlign.center, - ), + } + }, + onLongPress: onLongPress, + style: (isBlackListed + ? ButtonVariance.destructive + : ButtonVariance.ghost) + .copyWith( + padding: (context, states) => + const EdgeInsets.symmetric(vertical: 8, horizontal: 0), + ), + leading: Row( + mainAxisSize: MainAxisSize.min, + children: [ + ...?leadingActions, + AnimatedCrossFade( + duration: const Duration(milliseconds: 300), + crossFadeState: index != null && onChanged == null + ? CrossFadeState.showSecond + : CrossFadeState.showFirst, + firstChild: Checkbox( + state: selected + ? CheckboxState.checked + : CheckboxState.unchecked, + onChanged: (state) => + onChanged?.call(state == CheckboxState.checked), + ), + secondChild: constrains.smAndDown + ? const SizedBox(width: 16) + : SizedBox( + width: 50, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 6), + child: Text( + '${(index ?? 0) + 1}', + maxLines: 1, + style: theme.typography.small, + textAlign: TextAlign.center, ), ), - ), - Stack( - children: [ - Container( - height: 40, - width: 40, + ), + ), + Stack( + children: [ + Container( + height: 40, + width: 40, + decoration: BoxDecoration( + borderRadius: theme.borderRadiusMd, + image: DecorationImage( + fit: BoxFit.cover, + image: UniversalImage.imageProvider( + (track.album?.images).asUrlString( + placeholder: ImagePlaceholder.albumArt, + ), + ), + ), + ), + ), + Positioned.fill( + child: AnimatedContainer( + duration: const Duration(milliseconds: 300), decoration: BoxDecoration( borderRadius: theme.borderRadiusMd, - image: DecorationImage( - fit: BoxFit.cover, - image: UniversalImage.imageProvider( - (track.album?.images).asUrlString( - placeholder: ImagePlaceholder.albumArt, + color: isHovering + ? Colors.black.withAlpha(102) + : Colors.transparent, + ), + ), + ), + Positioned.fill( + child: Center( + child: Skeleton.ignore( + child: Consumer( + builder: (context, ref, _) { + final isFetchingActiveTrack = + ref.watch(queryingTrackInfoProvider); + return AnimatedSwitcher( + duration: const Duration(milliseconds: 300), + child: switch (( + isPlaying, + isFetchingActiveTrack, + isPlaying, + isHovering, + isLoading.value + )) { + (true, true, _, _, _) || + (_, _, _, _, true) => + const SizedBox( + width: 26, + height: 26, + child: + CircularProgressIndicator(size: 1.5), + ), + (_, _, true, _, _) => Icon( + SpotubeIcons.pause, + color: theme.colorScheme.primary, + ), + (_, _, _, true, _) => const Icon( + SpotubeIcons.play, + color: Colors.white, + ), + _ => const SizedBox.shrink(), + }, + ); + }, + ), + ), + ), + ), + ], + ), + ], + ), + title: Row( + children: [ + Expanded( + flex: 6, + child: switch (track) { + LocalTrack() => Text( + track.name!, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + _ => Row( + mainAxisSize: MainAxisSize.min, + children: [ + Flexible( + child: Button( + style: ButtonVariance.link.copyWith( + padding: (context, states) => EdgeInsets.zero, ), - ), - ), - ), - ), - Positioned.fill( - child: AnimatedContainer( - duration: const Duration(milliseconds: 300), - decoration: BoxDecoration( - borderRadius: theme.borderRadiusMd, - color: isHovering - ? Colors.black.withOpacity(0.4) - : Colors.transparent, - ), - ), - ), - Positioned.fill( - child: Center( - child: Skeleton.ignore( - child: Consumer( - builder: (context, ref, _) { - final isFetchingActiveTrack = - ref.watch(queryingTrackInfoProvider); - return AnimatedSwitcher( - duration: const Duration(milliseconds: 300), - child: switch (( - isPlaying, - isFetchingActiveTrack, - isPlaying, - isHovering, - isLoading.value - )) { - (true, true, _, _, _) || - (_, _, _, _, true) => - const SizedBox( - width: 26, - height: 26, - child: CircularProgressIndicator( - size: 1.5), - ), - (_, _, true, _, _) => Icon( - SpotubeIcons.pause, - color: theme.colorScheme.primary, - ), - (_, _, _, true, _) => const Icon( - SpotubeIcons.play, - color: Colors.white, - ), - _ => const SizedBox.shrink(), + onPressed: () { + context.pushNamed( + TrackPage.name, + pathParameters: { + "id": track.id!, }, ); }, + child: Text( + track.name!, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), ), ), - ), + ], ), - ], - ), - ], - ), - title: Row( - children: [ + }, + ), + if (constrains.mdAndUp) ...[ + const SizedBox(width: 8), Expanded( - flex: 6, + flex: 4, child: switch (track) { LocalTrack() => Text( - track.name!, + track.album!.name!, maxLines: 1, overflow: TextOverflow.ellipsis, ), - _ => LinkText( - track.name!, - "/track/${track.id}", - push: true, - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - }, - ), - if (constrains.mdAndUp) ...[ - const SizedBox(width: 8), - Expanded( - flex: 4, - child: switch (track) { - LocalTrack() => Text( + _ => Align( + alignment: Alignment.centerLeft, + child: LinkText( track.album!.name!, - maxLines: 1, + "/album/${track.album?.id}", + extra: track.album, + push: true, overflow: TextOverflow.ellipsis, ), - _ => Align( - alignment: Alignment.centerLeft, - child: LinkText( - track.album!.name!, - "/album/${track.album?.id}", - extra: track.album, - push: true, - overflow: TextOverflow.ellipsis, - ), - ) - }, - ), - ], + ) + }, + ), ], - ), - subtitle: Align( - alignment: Alignment.centerLeft, - child: track is LocalTrack - ? Text( - track.artists?.asString() ?? '', - ) - : ClipRect( - child: ConstrainedBox( - constraints: const BoxConstraints(maxHeight: 40), - child: ArtistLink( - artists: track.artists ?? [], - onOverflowArtistClick: () => ServiceUtils.pushNamed( - context, - TrackPage.name, - pathParameters: { - "id": track.id!, - }, - ), + ], + ), + subtitle: Align( + alignment: Alignment.centerLeft, + child: track is LocalTrack + ? Text( + track.artists?.asString() ?? '', + ) + : ClipRect( + child: ConstrainedBox( + constraints: const BoxConstraints(maxHeight: 40), + child: ArtistLink( + artists: track.artists ?? [], + onOverflowArtistClick: () => ServiceUtils.pushNamed( + context, + TrackPage.name, + pathParameters: { + "id": track.id!, + }, ), ), ), - ), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - const SizedBox(width: 8), - Text( - Duration(milliseconds: track.durationMs ?? 0) - .toHumanReadableString(padZero: false), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - TrackOptions( - track: track, - playlistId: playlistId, - userPlaylist: userPlaylist, - showMenuCbRef: showOptionCbRef, - ), - if (kIsDesktop) const Gap(10), - ], - ), + ), + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const SizedBox(width: 8), + Text( + Duration(milliseconds: track.durationMs ?? 0) + .toHumanReadableString(padZero: false), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + TrackOptions( + track: track, + playlistId: playlistId, + userPlaylist: userPlaylist, + showMenuCbRef: showOptionCbRef, + ), + if (kIsDesktop) const Gap(10), + ], ), ), ), diff --git a/lib/components/ui/button_tile.dart b/lib/components/ui/button_tile.dart index 7318e8c4..8f5a7581 100644 --- a/lib/components/ui/button_tile.dart +++ b/lib/components/ui/button_tile.dart @@ -6,7 +6,8 @@ class ButtonTile extends StatelessWidget { final Widget? leading; final Widget? trailing; final bool enabled; - final void Function()? onPressed; + final VoidCallback? onPressed; + final VoidCallback? onLongPress; final bool selected; final ButtonVariance style; final EdgeInsets? padding; @@ -19,6 +20,7 @@ class ButtonTile extends StatelessWidget { this.trailing, this.enabled = true, this.onPressed, + this.onLongPress, this.selected = false, this.padding, this.style = ButtonVariance.outline, @@ -28,73 +30,78 @@ class ButtonTile extends StatelessWidget { Widget build(BuildContext context) { final ThemeData(:colorScheme, :typography) = Theme.of(context); - return Button( - enabled: enabled, - onPressed: onPressed, - style: style.copyWith( - padding: padding != null ? (context, states, value) => padding! : null, - decoration: (context, states, value) { - final decoration = style.decoration(context, states) as BoxDecoration; + return GestureDetector( + onLongPress: onLongPress, + child: Button( + enabled: enabled, + onPressed: onPressed, + style: style.copyWith( + padding: + padding != null ? (context, states, value) => padding! : null, + decoration: (context, states, value) { + final decoration = + style.decoration(context, states) as BoxDecoration; - if (selected) { - return switch (style) { - ButtonVariance.outline => decoration.copyWith( - border: Border.all( - color: colorScheme.primary, - width: 1.0, + if (selected) { + return switch (style) { + ButtonVariance.outline => decoration.copyWith( + border: Border.all( + color: colorScheme.primary, + width: 1.0, + ), + color: colorScheme.primary.withAlpha(25), ), - color: colorScheme.primary.withAlpha(25), - ), - ButtonVariance.ghost || _ => decoration.copyWith( - color: colorScheme.primary.withAlpha(25), - ), - }; - } + ButtonVariance.ghost || _ => decoration.copyWith( + color: colorScheme.primary.withAlpha(25), + ), + }; + } - return decoration; - }, - iconTheme: (context, states, value) { - final iconTheme = style.iconTheme(context, states); + return decoration; + }, + iconTheme: (context, states, value) { + final iconTheme = style.iconTheme(context, states); - if (selected && style == ButtonVariance.outline) { - return iconTheme.copyWith( - color: colorScheme.primary, - ); - } + if (selected && style == ButtonVariance.outline) { + return iconTheme.copyWith( + color: colorScheme.primary, + ); + } - return iconTheme; - }, - textStyle: (context, states, value) { - final textStyle = style.textStyle(context, states); + return iconTheme; + }, + textStyle: (context, states, value) { + final textStyle = style.textStyle(context, states); - if (selected && style == ButtonVariance.outline) { - return textStyle.copyWith( - color: colorScheme.primary, - ); - } + if (selected && style == ButtonVariance.outline) { + return textStyle.copyWith( + color: colorScheme.primary, + ); + } - return textStyle; - }, - ), - alignment: Alignment.centerLeft, - child: SizedBox( - width: double.infinity, - child: Basic( - padding: EdgeInsets.zero, - leadingAlignment: Alignment.center, - trailingAlignment: Alignment.center, - leading: leading, - title: title, - subtitle: - style == ButtonVariance.outline && selected && subtitle != null - ? DefaultTextStyle( - style: typography.xSmall.copyWith( - color: colorScheme.primary, - ), - child: subtitle!, - ) - : subtitle, - trailing: trailing, + return textStyle; + }, + ), + alignment: Alignment.centerLeft, + child: SizedBox( + width: double.infinity, + child: Basic( + padding: EdgeInsets.zero, + leadingAlignment: Alignment.center, + trailingAlignment: Alignment.center, + leading: leading, + title: title, + subtitle: + style == ButtonVariance.outline && selected && subtitle != null + ? DefaultTextStyle( + style: typography.xSmall.copyWith( + color: colorScheme.primary, + ), + child: subtitle!, + ) + : subtitle, + trailing: trailing, + ), ), ), ); diff --git a/lib/extensions/button_variance.dart b/lib/extensions/button_variance.dart new file mode 100644 index 00000000..cf66d528 --- /dev/null +++ b/lib/extensions/button_variance.dart @@ -0,0 +1,21 @@ +import 'package:shadcn_flutter/shadcn_flutter.dart'; + +extension CopyWithButtonVarianceExtension on ButtonVariance { + ButtonVariance copyWith({ + ButtonStateProperty? padding, + ButtonStateProperty? decoration, + ButtonStateProperty? mouseCursor, + ButtonStateProperty? iconTheme, + ButtonStateProperty? margin, + ButtonStateProperty? textStyle, + }) { + return ButtonVariance( + padding: padding ?? this.padding, + decoration: decoration ?? this.decoration, + mouseCursor: mouseCursor ?? this.mouseCursor, + iconTheme: iconTheme ?? this.iconTheme, + margin: margin ?? this.margin, + textStyle: textStyle ?? this.textStyle, + ); + } +} diff --git a/lib/modules/home/sections/genres.dart b/lib/modules/home/sections/genres.dart index 9309e2e7..b273b970 100644 --- a/lib/modules/home/sections/genres.dart +++ b/lib/modules/home/sections/genres.dart @@ -43,7 +43,7 @@ class HomeGenresSection extends HookConsumerWidget { useEffect(() { int times = 0; - Timer.periodic( + final timer = Timer.periodic( const Duration(seconds: 5), (timer) { if (times > 5 || interactedRef.value) { @@ -57,7 +57,10 @@ class HomeGenresSection extends HookConsumerWidget { }, ); - return controller.dispose; + return () { + timer.cancel(); + controller.dispose(); + }; }, []); return SliverList.list( From 2daea2b3efb9b273eb6843c2106fd08d142edc38 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 10 Jan 2025 19:51:21 +0600 Subject: [PATCH 051/112] chore: make genre carousel items better in light mode --- lib/modules/home/sections/genres.dart | 334 ------------------ .../home/sections/genres/genre_card.dart | 114 ++++++ .../genres/genre_card_playlist_card.dart | 88 +++++ lib/modules/home/sections/genres/genres.dart | 180 ++++++++++ .../player/player_overlay_collapsed.dart | 1 - lib/modules/root/spotube_navigation_bar.dart | 41 ++- lib/pages/home/home.dart | 2 +- 7 files changed, 406 insertions(+), 354 deletions(-) delete mode 100644 lib/modules/home/sections/genres.dart create mode 100644 lib/modules/home/sections/genres/genre_card.dart create mode 100644 lib/modules/home/sections/genres/genre_card_playlist_card.dart create mode 100644 lib/modules/home/sections/genres/genres.dart diff --git a/lib/modules/home/sections/genres.dart b/lib/modules/home/sections/genres.dart deleted file mode 100644 index b273b970..00000000 --- a/lib/modules/home/sections/genres.dart +++ /dev/null @@ -1,334 +0,0 @@ -import 'dart:async'; - -import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:shadcn_flutter/shadcn_flutter.dart'; -import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; -import 'package:skeletonizer/skeletonizer.dart'; -import 'package:spotube/collections/fake.dart'; -import 'package:spotube/collections/spotube_icons.dart'; -import 'package:spotube/components/image/universal_image.dart'; -import 'package:spotube/extensions/constrains.dart'; -import 'package:spotube/extensions/context.dart'; -import 'package:spotube/extensions/image.dart'; -import 'package:spotube/extensions/string.dart'; -import 'package:spotube/pages/home/genres/genre_playlists.dart'; -import 'package:spotube/pages/home/genres/genres.dart'; -import 'package:spotube/pages/playlist/playlist.dart'; -import 'package:spotube/provider/spotify/spotify.dart'; - -class HomeGenresSection extends HookConsumerWidget { - const HomeGenresSection({super.key}); - - @override - Widget build(BuildContext context, ref) { - final theme = context.theme; - final mediaQuery = MediaQuery.sizeOf(context); - - final categoriesQuery = ref.watch(categoriesProvider); - final categories = useMemoized( - () => - categoriesQuery.asData?.value - .where((c) => (c.icons?.length ?? 0) > 0) - .take(6) - .toList() ?? - [ - FakeData.category, - ], - [categoriesQuery.asData?.value], - ); - final controller = useMemoized(() => CarouselController(), []); - final interactedRef = useRef(false); - - useEffect(() { - int times = 0; - final timer = Timer.periodic( - const Duration(seconds: 5), - (timer) { - if (times > 5 || interactedRef.value) { - timer.cancel(); - return; - } - controller.animateNext( - const Duration(seconds: 2), - ); - times++; - }, - ); - - return () { - timer.cancel(); - controller.dispose(); - }; - }, []); - - return SliverList.list( - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 8), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - context.l10n.genres, - style: context.theme.typography.h4, - ), - Directionality( - textDirection: TextDirection.rtl, - child: Button.link( - onPressed: () { - context.pushNamed(GenrePage.name); - }, - leading: const Icon(SpotubeIcons.angleRight), - child: Text( - context.l10n.browse_all, - ).muted(), - ), - ), - ], - ), - ), - const Gap(8), - Stack( - children: [ - SizedBox( - height: 280 * theme.scaling, - child: Carousel( - controller: controller, - transition: const CarouselTransition.sliding(gap: 24), - sizeConstraint: CarouselSizeConstraint.fixed( - mediaQuery.mdAndUp - ? mediaQuery.width * .6 - : mediaQuery.width * .95, - ), - itemCount: categories.length, - pauseOnHover: true, - direction: Axis.horizontal, - itemBuilder: (context, index) { - final category = categories[index]; - final playlists = - ref.watch(categoryPlaylistsProvider(category.id!)); - final playlistsData = playlists.asData?.value.items.take(8) ?? - List.generate(5, (index) => FakeData.playlistSimple); - - return Container( - margin: const EdgeInsets.symmetric(horizontal: 8), - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - borderRadius: theme.borderRadiusXxl, - border: Border.all( - color: theme.colorScheme.border, - width: 1, - ), - image: DecorationImage( - image: UniversalImage.imageProvider( - category.icons!.first.url!, - ), - colorFilter: ColorFilter.mode( - theme.colorScheme.background.withAlpha(125), - BlendMode.darken, - ), - fit: BoxFit.cover, - ), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - spacing: 16, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - category.name!, - style: const TextStyle(color: Colors.white), - ).h3(), - Button.link( - onPressed: () { - context.pushNamed( - GenrePlaylistsPage.name, - pathParameters: {'categoryId': category.id!}, - extra: category, - ); - }, - child: Text( - context.l10n.view_all, - style: const TextStyle(color: Colors.white), - ).muted(), - ), - ], - ), - Expanded( - child: Skeleton.ignore( - child: Skeletonizer( - enabled: playlists.isLoading, - child: ListView.separated( - scrollDirection: Axis.horizontal, - itemCount: playlistsData.length, - separatorBuilder: (context, index) => - const Gap(12), - itemBuilder: (context, index) { - final playlist = - playlistsData.elementAt(index); - - return Container( - width: 115 * theme.scaling, - decoration: BoxDecoration( - color: theme.colorScheme.background - .withAlpha(75), - borderRadius: theme.borderRadiusMd, - ), - child: SurfaceBlur( - borderRadius: theme.borderRadiusMd, - surfaceBlur: theme.surfaceBlur, - child: Button( - style: - ButtonVariance.secondary.copyWith( - padding: (context, states, value) => - const EdgeInsets.all(8), - decoration: (context, states, value) { - final decoration = ButtonVariance - .secondary - .decoration(context, states) - as BoxDecoration; - - if (states.isNotEmpty) { - return decoration; - } - - return decoration.copyWith( - color: decoration.color - ?.withAlpha(180), - ); - }, - ), - onPressed: () { - context.pushNamed( - PlaylistPage.name, - pathParameters: { - "id": playlist.id!, - }, - extra: playlist, - ); - }, - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - spacing: 5, - children: [ - ClipRRect( - borderRadius: - theme.borderRadiusSm, - child: UniversalImage( - path: (playlist.images)! - .asUrlString( - placeholder: ImagePlaceholder - .collection, - index: 1, - ), - fit: BoxFit.cover, - height: 100 * theme.scaling, - width: 100 * theme.scaling, - ), - ), - Text( - playlist.name!, - maxLines: 2, - overflow: TextOverflow.ellipsis, - ).semiBold().small(), - if (playlist.description != null) - Text( - playlist.description - ?.unescapeHtml() - .cleanHtml() ?? - "", - maxLines: 2, - overflow: TextOverflow.ellipsis, - ).xSmall().muted(), - ], - ), - ), - ), - ); - }, - ), - ), - ), - ) - ], - ), - ); - }, - ), - ), - Positioned( - left: 0, - child: Container( - height: 280 * theme.scaling, - width: (mediaQuery.mdAndUp ? 80 : 50) * theme.scaling, - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.centerLeft, - end: Alignment.centerRight, - colors: [ - theme.colorScheme.background.withAlpha(255), - theme.colorScheme.background.withAlpha(0), - ], - ), - ), - alignment: Alignment.center, - child: IconButton.ghost( - size: - mediaQuery.mdAndUp ? ButtonSize.normal : ButtonSize.small, - icon: const Icon(SpotubeIcons.angleLeft), - onPressed: () { - controller.animatePrevious( - const Duration(seconds: 1), - ); - interactedRef.value = true; - }, - ), - ), - ), - Positioned( - right: 0, - child: Container( - height: 280 * theme.scaling, - width: (mediaQuery.mdAndUp ? 80 : 50) * theme.scaling, - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.centerLeft, - end: Alignment.centerRight, - colors: [ - theme.colorScheme.background.withAlpha(0), - theme.colorScheme.background.withAlpha(255), - ], - ), - ), - alignment: Alignment.center, - child: IconButton.ghost( - size: - mediaQuery.mdAndUp ? ButtonSize.normal : ButtonSize.small, - icon: const Icon(SpotubeIcons.angleRight), - onPressed: () { - controller.animateNext( - const Duration(seconds: 1), - ); - interactedRef.value = true; - }, - ), - ), - ), - ], - ), - const Gap(8), - Center( - child: CarouselDotIndicator( - itemCount: categories.length, - controller: controller, - ), - ), - ], - ); - } -} diff --git a/lib/modules/home/sections/genres/genre_card.dart b/lib/modules/home/sections/genres/genre_card.dart new file mode 100644 index 00000000..722e6644 --- /dev/null +++ b/lib/modules/home/sections/genres/genre_card.dart @@ -0,0 +1,114 @@ +import 'dart:math'; +import 'dart:ui'; + +import 'package:go_router/go_router.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:skeletonizer/skeletonizer.dart'; +import 'package:spotify/spotify.dart' hide Offset; +import 'package:spotube/collections/fake.dart'; +import 'package:spotube/collections/gradients.dart'; +import 'package:spotube/components/image/universal_image.dart'; +import 'package:spotube/extensions/context.dart'; +import 'package:spotube/modules/home/sections/genres/genre_card_playlist_card.dart'; +import 'package:spotube/pages/home/genres/genre_playlists.dart'; +import 'package:spotube/provider/spotify/spotify.dart'; + +final random = Random(); +final gradientState = StateProvider.family( + (ref, String id) => gradients[random.nextInt(gradients.length)], +); + +class GenreSectionCard extends HookConsumerWidget { + final Category category; + const GenreSectionCard({ + super.key, + required this.category, + }); + + @override + Widget build(BuildContext context, ref) { + final theme = Theme.of(context); + final playlists = category == FakeData.category + ? null + : ref.watch(categoryPlaylistsProvider(category.id!)); + final playlistsData = playlists?.asData?.value.items.take(8) ?? + List.generate(5, (index) => FakeData.playlistSimple); + + final randomGradient = ref.watch(gradientState(category.id!)); + + return Container( + margin: const EdgeInsets.symmetric(horizontal: 8), + decoration: BoxDecoration( + borderRadius: theme.borderRadiusXxl, + boxShadow: [ + BoxShadow( + color: theme.colorScheme.foreground, + offset: const Offset(0, 5), + blurRadius: 7, + spreadRadius: -5, + ), + ], + image: DecorationImage( + image: UniversalImage.imageProvider( + category.icons!.first.url!, + ), + fit: BoxFit.cover, + ), + ), + child: Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + borderRadius: theme.borderRadiusXxl, + gradient: randomGradient + .withOpacity(theme.brightness == Brightness.dark ? 0.2 : 0.7), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 16, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + category.name!, + style: const TextStyle(color: Colors.white), + ).h3(), + Button.link( + onPressed: () { + context.pushNamed( + GenrePlaylistsPage.name, + pathParameters: {'categoryId': category.id!}, + extra: category, + ); + }, + child: Text( + context.l10n.view_all, + style: const TextStyle(color: Colors.white), + ).muted(), + ), + ], + ), + Expanded( + child: Skeleton.ignore( + child: Skeletonizer( + enabled: playlists?.isLoading ?? false, + child: ListView.separated( + scrollDirection: Axis.horizontal, + itemCount: playlistsData.length, + separatorBuilder: (context, index) => const Gap(12), + itemBuilder: (context, index) { + final playlist = playlistsData.elementAt(index); + + return GenreSectionCardPlaylistCard(playlist: playlist); + }, + ), + ), + ), + ) + ], + ), + ), + ); + } +} diff --git a/lib/modules/home/sections/genres/genre_card_playlist_card.dart b/lib/modules/home/sections/genres/genre_card_playlist_card.dart new file mode 100644 index 00000000..bbc42c61 --- /dev/null +++ b/lib/modules/home/sections/genres/genre_card_playlist_card.dart @@ -0,0 +1,88 @@ +import 'package:go_router/go_router.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:spotify/spotify.dart'; +import 'package:spotube/components/image/universal_image.dart'; +import 'package:spotube/extensions/image.dart'; +import 'package:spotube/extensions/string.dart'; +import 'package:spotube/pages/playlist/playlist.dart'; + +class GenreSectionCardPlaylistCard extends HookConsumerWidget { + final PlaylistSimple playlist; + const GenreSectionCardPlaylistCard({ + super.key, + required this.playlist, + }); + + @override + Widget build(BuildContext context, ref) { + final theme = Theme.of(context); + + return Container( + width: 115 * theme.scaling, + decoration: BoxDecoration( + color: theme.colorScheme.background.withAlpha(75), + borderRadius: theme.borderRadiusMd, + ), + child: SurfaceBlur( + borderRadius: theme.borderRadiusMd, + surfaceBlur: theme.surfaceBlur, + child: Button( + style: ButtonVariance.secondary.copyWith( + padding: (context, states, value) => const EdgeInsets.all(8), + decoration: (context, states, value) { + final decoration = ButtonVariance.secondary + .decoration(context, states) as BoxDecoration; + + if (states.isNotEmpty) { + return decoration; + } + + return decoration.copyWith( + color: decoration.color?.withAlpha(180), + ); + }, + ), + onPressed: () { + context.pushNamed( + PlaylistPage.name, + pathParameters: { + "id": playlist.id!, + }, + extra: playlist, + ); + }, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 5, + children: [ + ClipRRect( + borderRadius: theme.borderRadiusSm, + child: UniversalImage( + path: (playlist.images)!.asUrlString( + placeholder: ImagePlaceholder.collection, + index: 1, + ), + fit: BoxFit.cover, + height: 100 * theme.scaling, + width: 100 * theme.scaling, + ), + ), + Text( + playlist.name!, + maxLines: 2, + overflow: TextOverflow.ellipsis, + ).semiBold().small(), + if (playlist.description != null) + Text( + playlist.description?.unescapeHtml().cleanHtml() ?? "", + maxLines: 2, + overflow: TextOverflow.ellipsis, + ).xSmall().muted(), + ], + ), + ), + ), + ); + } +} diff --git a/lib/modules/home/sections/genres/genres.dart b/lib/modules/home/sections/genres/genres.dart new file mode 100644 index 00000000..5e6fa330 --- /dev/null +++ b/lib/modules/home/sections/genres/genres.dart @@ -0,0 +1,180 @@ +import 'dart:async'; + +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:go_router/go_router.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; +import 'package:skeletonizer/skeletonizer.dart'; +import 'package:spotube/collections/fake.dart'; +import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/extensions/constrains.dart'; +import 'package:spotube/extensions/context.dart'; +import 'package:spotube/modules/home/sections/genres/genre_card.dart'; +import 'package:spotube/pages/home/genres/genres.dart'; +import 'package:spotube/provider/spotify/spotify.dart'; + +class HomeGenresSection extends HookConsumerWidget { + const HomeGenresSection({super.key}); + + @override + Widget build(BuildContext context, ref) { + final theme = context.theme; + final mediaQuery = MediaQuery.sizeOf(context); + + final categoriesQuery = ref.watch(categoriesProvider); + final categories = useMemoized( + () => + categoriesQuery.asData?.value + .where((c) => (c.icons?.length ?? 0) > 0) + .take(6) + .toList() ?? + [ + FakeData.category, + ], + [categoriesQuery.asData?.value], + ); + final controller = useMemoized(() => CarouselController(), []); + final interactedRef = useRef(false); + + useEffect(() { + int times = 0; + final timer = Timer.periodic( + const Duration(seconds: 5), + (timer) { + if (times > 5 || interactedRef.value) { + timer.cancel(); + return; + } + controller.animateNext( + const Duration(seconds: 2), + ); + times++; + }, + ); + + return () { + timer.cancel(); + }; + }, []); + + return SliverList.list( + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + context.l10n.genres, + style: context.theme.typography.h4, + ), + Button.link( + onPressed: () { + context.pushNamed(GenrePage.name); + }, + trailing: const Icon(SpotubeIcons.angleRight), + child: Text( + context.l10n.browse_all, + ).muted(), + ), + ], + ), + ), + const Gap(8), + Stack( + children: [ + SizedBox( + height: 280 * theme.scaling, + child: Carousel( + controller: controller, + transition: const CarouselTransition.sliding(gap: 24), + sizeConstraint: CarouselSizeConstraint.fixed( + mediaQuery.mdAndUp + ? mediaQuery.width * .6 + : mediaQuery.width * .95, + ), + itemCount: categories.length, + pauseOnHover: true, + direction: Axis.horizontal, + itemBuilder: (context, index) { + final category = categories[index]; + + return Skeletonizer( + enabled: categoriesQuery.isLoading, + child: GenreSectionCard(category: category), + ); + }, + ), + ), + Positioned( + left: 0, + child: Container( + height: 280 * theme.scaling, + width: (mediaQuery.mdAndUp ? 80 : 50) * theme.scaling, + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.centerLeft, + end: Alignment.centerRight, + colors: [ + theme.colorScheme.background.withAlpha(255), + theme.colorScheme.background.withAlpha(0), + ], + ), + ), + alignment: Alignment.center, + child: IconButton.ghost( + size: + mediaQuery.mdAndUp ? ButtonSize.normal : ButtonSize.small, + icon: const Icon(SpotubeIcons.angleLeft), + onPressed: () { + controller.animatePrevious( + const Duration(seconds: 1), + ); + interactedRef.value = true; + }, + ), + ), + ), + Positioned( + right: 0, + child: Container( + height: 280 * theme.scaling, + width: (mediaQuery.mdAndUp ? 80 : 50) * theme.scaling, + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.centerLeft, + end: Alignment.centerRight, + colors: [ + theme.colorScheme.background.withAlpha(0), + theme.colorScheme.background.withAlpha(255), + ], + ), + ), + alignment: Alignment.center, + child: IconButton.ghost( + size: + mediaQuery.mdAndUp ? ButtonSize.normal : ButtonSize.small, + icon: const Icon(SpotubeIcons.angleRight), + onPressed: () { + controller.animateNext( + const Duration(seconds: 1), + ); + interactedRef.value = true; + }, + ), + ), + ), + ], + ), + const Gap(8), + Center( + child: CarouselDotIndicator( + itemCount: categories.length, + controller: controller, + ), + ), + ], + ); + } +} diff --git a/lib/modules/player/player_overlay_collapsed.dart b/lib/modules/player/player_overlay_collapsed.dart index 52847c40..d0961ade 100644 --- a/lib/modules/player/player_overlay_collapsed.dart +++ b/lib/modules/player/player_overlay_collapsed.dart @@ -40,7 +40,6 @@ class PlayerOverlayCollapsedSection extends HookConsumerWidget { ? Padding( padding: const EdgeInsets.all(5), child: SurfaceCard( - borderWidth: 0, surfaceBlur: theme.surfaceBlur, surfaceOpacity: theme.surfaceOpacity, padding: EdgeInsets.zero, diff --git a/lib/modules/root/spotube_navigation_bar.dart b/lib/modules/root/spotube_navigation_bar.dart index 8d3e71f4..c19b3a40 100644 --- a/lib/modules/root/spotube_navigation_bar.dart +++ b/lib/modules/root/spotube_navigation_bar.dart @@ -55,25 +55,30 @@ class SpotubeNavigationBar extends HookConsumerWidget { duration: const Duration(milliseconds: 100), height: panelHeight, child: SingleChildScrollView( - child: NavigationBar( - index: selectedIndex, - surfaceBlur: context.theme.surfaceBlur, - surfaceOpacity: context.theme.surfaceOpacity, - onSelected: (i) { - ServiceUtils.navigateNamed(context, navbarTileList[i].name); - }, + child: Column( children: [ - for (final tile in navbarTileList) - NavigationButton( - style: const ButtonStyle.muted(density: ButtonDensity.icon), - selectedStyle: - const ButtonStyle.fixed(density: ButtonDensity.icon), - child: Badge( - isLabelVisible: tile.id == "library" && downloadCount > 0, - label: Text(downloadCount.toString()), - child: Icon(tile.icon), - ), - ) + const Divider(), + NavigationBar( + index: selectedIndex, + surfaceBlur: context.theme.surfaceBlur, + surfaceOpacity: context.theme.surfaceOpacity, + onSelected: (i) { + ServiceUtils.navigateNamed(context, navbarTileList[i].name); + }, + children: [ + for (final tile in navbarTileList) + NavigationButton( + style: const ButtonStyle.muted(density: ButtonDensity.icon), + selectedStyle: + const ButtonStyle.fixed(density: ButtonDensity.icon), + child: Badge( + isLabelVisible: tile.id == "library" && downloadCount > 0, + label: Text(downloadCount.toString()), + child: Icon(tile.icon), + ), + ) + ], + ), ], ), ), diff --git a/lib/pages/home/home.dart b/lib/pages/home/home.dart index 2dfbc0f3..ea0a651b 100644 --- a/lib/pages/home/home.dart +++ b/lib/pages/home/home.dart @@ -10,7 +10,7 @@ import 'package:spotube/modules/connect/connect_device.dart'; import 'package:spotube/modules/home/sections/featured.dart'; import 'package:spotube/modules/home/sections/feed.dart'; import 'package:spotube/modules/home/sections/friends.dart'; -import 'package:spotube/modules/home/sections/genres.dart'; +import 'package:spotube/modules/home/sections/genres/genres.dart'; import 'package:spotube/modules/home/sections/made_for_user.dart'; import 'package:spotube/modules/home/sections/new_releases.dart'; import 'package:spotube/modules/home/sections/recent.dart'; From 5a14f587a0cbecf5678c928c76d00f5d4a662a0d Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 10 Jan 2025 20:33:59 +0600 Subject: [PATCH 052/112] chore: titlebar buttons not working --- lib/components/titlebar/titlebar.dart | 2 + lib/components/titlebar/titlebar_buttons.dart | 17 +++++---- lib/components/titlebar/window_button.dart | 22 ++++------- lib/pages/home/home.dart | 2 +- lib/pages/library/library.dart | 37 +++++++++++-------- lib/pages/search/search.dart | 4 +- lib/pages/stats/stats.dart | 2 +- 7 files changed, 44 insertions(+), 42 deletions(-) diff --git a/lib/components/titlebar/titlebar.dart b/lib/components/titlebar/titlebar.dart index cba33ab4..215b63ed 100644 --- a/lib/components/titlebar/titlebar.dart +++ b/lib/components/titlebar/titlebar.dart @@ -7,6 +7,8 @@ import 'package:spotube/provider/user_preferences/user_preferences_provider.dart import 'package:spotube/utils/platform.dart'; import 'package:window_manager/window_manager.dart'; +final kTitlebarVisible = kIsWindows || kIsLinux; + class TitleBar extends HookConsumerWidget implements PreferredSizeWidget { final bool automaticallyImplyLeading; final List trailing; diff --git a/lib/components/titlebar/titlebar_buttons.dart b/lib/components/titlebar/titlebar_buttons.dart index 35cdf08e..42765d7b 100644 --- a/lib/components/titlebar/titlebar_buttons.dart +++ b/lib/components/titlebar/titlebar_buttons.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; +import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/components/titlebar/titlebar_icon_buttons.dart'; import 'package:spotube/components/titlebar/window_button.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; @@ -20,6 +22,7 @@ class WindowTitleBarButtons extends HookConsumerWidget { final preferences = ref.watch(userPreferencesProvider); final isMaximized = useState(null); const type = ThemeType.auto; + final scale = context.theme.scaling; Future onClose() async { await windowManager.close(); @@ -34,7 +37,7 @@ class WindowTitleBarButtons extends HookConsumerWidget { return null; }, []); - if (!kIsDesktop || kIsMacOS || preferences.systemTitleBar) { + if (!kTitlebarVisible || preferences.systemTitleBar) { return const SizedBox.shrink(); } @@ -43,8 +46,8 @@ class WindowTitleBarButtons extends HookConsumerWidget { final colors = WindowButtonColors( normal: Colors.transparent, iconNormal: foregroundColor ?? theme.colorScheme.onSurface, - mouseOver: theme.colorScheme.onSurface.withOpacity(0.1), - mouseDown: theme.colorScheme.onSurface.withOpacity(0.2), + mouseOver: theme.colorScheme.onSurface.withAlpha(25), + mouseDown: theme.colorScheme.onSurface.withAlpha(51), iconMouseOver: theme.colorScheme.onSurface, iconMouseDown: theme.colorScheme.onSurface, ); @@ -58,8 +61,8 @@ class WindowTitleBarButtons extends HookConsumerWidget { iconMouseDown: Colors.black, ); - return Padding( - padding: const EdgeInsets.only(bottom: 25), + return Transform( + transform: Matrix4.translationValues(18, -12, 0) * scale, child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -92,8 +95,8 @@ class WindowTitleBarButtons extends HookConsumerWidget { ); } - return Padding( - padding: const EdgeInsets.only(bottom: 20, left: 10), + return Transform( + transform: Matrix4.translationValues(18, -12, 0) * scale, child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ diff --git a/lib/components/titlebar/window_button.dart b/lib/components/titlebar/window_button.dart index 3201d191..fef9d754 100644 --- a/lib/components/titlebar/window_button.dart +++ b/lib/components/titlebar/window_button.dart @@ -1,8 +1,6 @@ -import 'dart:io'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/components/titlebar/mouse_state.dart'; +import 'package:spotube/components/titlebar/titlebar.dart'; typedef WindowButtonIconBuilder = Widget Function( WindowButtonContext buttonContext); @@ -86,14 +84,7 @@ class WindowButton extends StatelessWidget { @override Widget build(BuildContext context) { - if (kIsWeb) { - return Container(); - } else { - // Don't show button on macOS - if (Platform.isMacOS) { - return Container(); - } - } + if (!kTitlebarVisible) return const SizedBox.shrink(); return MouseStateBuilder( builder: (context, mouseState) { @@ -103,11 +94,12 @@ class WindowButton extends StatelessWidget { backgroundColor: getBackgroundColor(mouseState), iconColor: getIconColor(mouseState)); - var icon = - (iconBuilder != null) ? iconBuilder!(buttonContext) : Container(); + var icon = (iconBuilder != null) + ? iconBuilder!(buttonContext) + : const SizedBox(); var fadeOutColor = - getBackgroundColor(MouseState()..isMouseOver = true).withOpacity(0); + getBackgroundColor(MouseState()..isMouseOver = true).withAlpha(0); var padding = this.padding ?? const EdgeInsets.all(10); var animationMs = mouseState.isMouseOver ? (animate ? 100 : 0) : (animate ? 200 : 0); diff --git a/lib/pages/home/home.dart b/lib/pages/home/home.dart index ea0a651b..78371c4d 100644 --- a/lib/pages/home/home.dart +++ b/lib/pages/home/home.dart @@ -36,7 +36,7 @@ class HomePage extends HookConsumerWidget { bottom: false, child: Scaffold( headers: [ - if (kIsWindows || kIsLinux) const TitleBar(), + if (kTitlebarVisible) const TitleBar(), ], child: CustomScrollView( controller: controller, diff --git a/lib/pages/library/library.dart b/lib/pages/library/library.dart index e107f413..87b6a6cb 100644 --- a/lib/pages/library/library.dart +++ b/lib/pages/library/library.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart' show Badge; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/modules/library/user_local_tracks.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; @@ -11,7 +12,6 @@ import 'package:spotube/modules/library/user_downloads.dart'; import 'package:spotube/modules/library/user_playlists.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/download_manager_provider.dart'; -import 'package:spotube/utils/platform.dart'; class LibraryPage extends HookConsumerWidget { static const name = "library"; @@ -19,6 +19,7 @@ class LibraryPage extends HookConsumerWidget { const LibraryPage({super.key}); @override Widget build(BuildContext context, ref) { + final scale = context.theme.scaling; final downloadingCount = ref.watch(downloadManagerProvider).$downloadCount; final index = useState(0); @@ -38,20 +39,26 @@ class LibraryPage extends HookConsumerWidget { bottom: false, child: Scaffold( headers: [ - if (kIsWindows || kIsLinux) const TitleBar(), - SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: TabList( - index: index.value, - children: [ - for (final child in children) - TabButton( - child: child, - onPressed: () { - index.value = children.indexOf(child); - }, - ), - ], + TitleBar( + padding: const EdgeInsets.symmetric( + horizontal: 18, + vertical: 12, + ).copyWith(left: 0) * + scale, + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: TabList( + index: index.value, + children: [ + for (final child in children) + TabButton( + child: child, + onPressed: () { + index.value = children.indexOf(child); + }, + ), + ], + ), ), ), const Gap(10), diff --git a/lib/pages/search/search.dart b/lib/pages/search/search.dart index 9e2bf20c..d0f59ce2 100644 --- a/lib/pages/search/search.dart +++ b/lib/pages/search/search.dart @@ -19,7 +19,6 @@ import 'package:spotube/pages/search/sections/tracks.dart'; import 'package:spotube/provider/authentication/authentication.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:spotube/services/kv_store/kv_store.dart'; -import 'package:spotube/utils/platform.dart'; class SearchPage extends HookConsumerWidget { static const name = "search"; @@ -70,8 +69,7 @@ class SearchPage extends HookConsumerWidget { bottom: false, child: Scaffold( headers: [ - if (kIsWindows || kIsLinux) - const TitleBar(automaticallyImplyLeading: true) + if (kTitlebarVisible) const TitleBar(automaticallyImplyLeading: true) ], child: auth.asData?.value == null ? const AnonymousFallback() diff --git a/lib/pages/stats/stats.dart b/lib/pages/stats/stats.dart index a17e7562..e543900c 100644 --- a/lib/pages/stats/stats.dart +++ b/lib/pages/stats/stats.dart @@ -16,7 +16,7 @@ class StatsPage extends HookConsumerWidget { bottom: false, child: Scaffold( headers: [ - if (kIsWindows || kIsLinux) const TitleBar(), + if (kTitlebarVisible) const TitleBar(), ], child: CustomScrollView( slivers: [ From b25ae332b86d0a86f0200ce3af821f619b71b4b6 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 10 Jan 2025 23:41:22 +0600 Subject: [PATCH 053/112] feat: flag to hide spotify generated images with patterns --- assets/patterns/black_white_visualized.jpg | Bin 0 -> 343650 bytes assets/patterns/brazil_carnival.jpg | Bin 0 -> 80205 bytes assets/patterns/cotton_balls.jpg | Bin 0 -> 509803 bytes assets/patterns/cute_worms.jpg | Bin 0 -> 34160 bytes assets/patterns/flash_cross_axis.jpg | Bin 0 -> 41323 bytes assets/patterns/memphis_shapes.jpg | Bin 0 -> 175703 bytes assets/patterns/oval_gloomy.jpg | Bin 0 -> 144698 bytes assets/patterns/oval_sunny.jpg | Bin 0 -> 162271 bytes assets/patterns/red_nimbuses.jpg | Bin 0 -> 184678 bytes assets/patterns/tree_bark.jpg | Bin 0 -> 51461 bytes assets/patterns/vibrant_pentagons.jpg | Bin 0 -> 171063 bytes assets/patterns/wiring_pattern.jpg | Bin 0 -> 70479 bytes assets/patterns/zigzags_gloomy.jpg | Bin 0 -> 52678 bytes assets/patterns/zigzags_sunny.jpg | Bin 0 -> 50600 bytes lib/collections/assets.gen.dart | 79 ++++++++++++++++++ lib/collections/env.dart | 5 ++ .../playbutton_view/playbutton_card.dart | 39 ++++++--- .../playbutton_view/playbutton_tile.dart | 42 ++++++---- .../track_presentation/presentation_top.dart | 34 ++++++-- lib/models/spotify/home_feed.dart | 2 +- .../genres/genre_card_playlist_card.dart | 66 ++++++++++++--- lib/modules/playlist/playlist_card.dart | 50 ++++++++++- lib/provider/spotify/playlist/playlist.dart | 36 ++++++++ lib/provider/spotify/spotify.dart | 2 + pubspec.yaml | 1 + 25 files changed, 307 insertions(+), 49 deletions(-) create mode 100644 assets/patterns/black_white_visualized.jpg create mode 100644 assets/patterns/brazil_carnival.jpg create mode 100644 assets/patterns/cotton_balls.jpg create mode 100644 assets/patterns/cute_worms.jpg create mode 100644 assets/patterns/flash_cross_axis.jpg create mode 100644 assets/patterns/memphis_shapes.jpg create mode 100644 assets/patterns/oval_gloomy.jpg create mode 100644 assets/patterns/oval_sunny.jpg create mode 100644 assets/patterns/red_nimbuses.jpg create mode 100644 assets/patterns/tree_bark.jpg create mode 100644 assets/patterns/vibrant_pentagons.jpg create mode 100644 assets/patterns/wiring_pattern.jpg create mode 100644 assets/patterns/zigzags_gloomy.jpg create mode 100644 assets/patterns/zigzags_sunny.jpg diff --git a/assets/patterns/black_white_visualized.jpg b/assets/patterns/black_white_visualized.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e56a2780440cfdfbaa91f0aa6b4c0022545b3b95 GIT binary patch literal 343650 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

dDjY$6O3N~ZsLJ& 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

lOoZ&k#C zhROT0@F26Moo4&zPjt1U(NAw*N9I;>WYXf{}xN0owP45|BRmgySVx;o?7RmnLmXrdxU;CGJOXal14QsZqro9J$ zU8af4XtQ{@fn;wXC?W9g4cZE!KNDV|N*t@ZMiYcWn1V9%YU3S4kdCCY-u|DYw;7h} z4&G*JNKI-(d!{`U*jrh5Kn)8TsgM@=7Bg#Kz9qNYU9*Rr*5Vla5H%kOEDI{kFRVRI zQ2$0AdLa}e@_6eOG64*A{Y9D5WE^3i1jIj6@x{H!IuAlnidV5A7mGlK9gvNC`3O4i zNm=Ud=X)9Ku!C7*2E~Q}q5s`i^Z`H-=oXH`zwwFX;PcQX>U>ZKFaY8cu$pCpy&CmB z9ZsE8GVKo@gZ6aXGl;y1S<5WK9NY%Q683{`F5*(bl^bIKNzXOqbCa=97Y^BM{*eHC zBv#p+_#E_DJ?xnN%OYCxI{;#_sw6%;96>(!b)OUhuY3TcfC&K~vr6?>SIxc$RksD= z+OMQA!1Ya@#(0kq~PN0>Ah7z4FqSWDg0;5ycXuRQdR$yHC7`=Ev zyd)Wx<)PL}f(-l&3Ycg1w>3(R!e6u4951F_nCWCBD>u z)%B5iDNqb|LD;A>;6kVTBUh4vVNNo8R!JU+TI6jR!cF+PM>&FaM+yHi>I7Ep-)d3T zKkb`?sf&V=quv?sz|(KhWfx-V3&NinUroHeuc}Weg|%}-Hq3SE$zvB`Z<}uJ{eRMT z&jzLrqXLnp;XyvE3G-OzjmA-l{IQsvi77gbIl0GDhG5w_w{$U}_ljrI_gJnff^AKG z;-jOQKm&Kcq-sZ=;VDF)gK5qq29rTQ^r%r5wDI!#cUW_Fn=lRhk=Pd7tYQ}59m*!q zf=w^J{;r@q=M=Yb|L!-k!QWF>1HDq}_Os770w|K>waI=Xy7xqK>r5LLV&)1(t?U19 zlyX&0ewcT}3b&yiB|&hE>+RnY|jd=Bazq}vF_GRis7U=9}dHHZ4H z1|8sF@J*2Rz%r6H0WyMYxQ2T>?$n(3%ZIeGPH;UTY7sH8)sQfmb(WA}h#jT<<)kfP;y0ztyO*Ydrt<+ZM zpIcJr8%b7-fCeBXlGGVzH)DOQpTsChiM2&xj+99>Gpk?7N=T0u@k};>Da;F$=!aup zEExsvf$$<|bxLHFdzNQqavS(3nBmmEYJ(Ti3`sBFvMt{m4~L<$zL4)s^w;O2ESf26 z=`8A`dW=1@Y~rg+q})v+XyEg=2wzwB(eN8E@7xzOpUCXPSAT!TmKR)T&S!R}_JwLP zrGJ_D=HV4y5Y`-8Tfr{dlV<}`aLaA&lzmfters_~=hgnIG-!;0?iU&j4C4O6PGESW zaOOjQG(jW|tGyCxZsjSdC2GjnV%K4#HZzABa7S0|Mz&h#h~1TDeDhYY;R!-7sUuH= zltg*do+PWb2+~dQvte?52wrtMO`Lq2zq2o?F_0|1zs&H#!gJfRZg;A@M?D3gLzJV< zr_E3^SmYJxK6ykz+oVkF%GqH`ik*vnoZDbi)xu_Xy#GXYEV9%i$NB#o{>$e%_RbtR zkvCCZOO_x``j{8yc}Ki;$f>C2#5gyEF5AS+HGR=w)zHGg+9g%p1ZxulhDG2t#Q0Up zH$u63no~`+Q4y|;f(D%#6C|^~6O;NfTK?ebrH|?bsANhJwlv8#un{d*%EVddp7IJZ zE7yA6?i%VlnV4j_^qmP>e{;wL=hE6`&DDrjlTjvJJ(Pbb_k8lV6F#)n`@f;djrRo@ ze;*)(-VX`peqsA$)!vxYVEeRS1{D#e+H!&HWakBW`h0S?w3})o(M%(+Pg`o~(H7`yaB- zr_Vkrb4lxBX%@0Q*v0|RH&)r0MKCR}S)EjA^ve_%;pX#xHAge`F{QN29JUO4a`7&r zVRP=z;g>y(qKricGK%!xU}K9KI;anLn&T3p()hlyj#No7FXSi$smVDbc{V!AIx~i& z=jeQc54EpVh+I7nkbEC|7!Ui;Y%Pfu=$FZFcW_wD z$-`Y?GYTS>G9IE^<$eJ2z&k<1y+{L2*w~XS<{0T* z)LtwdbLVdkpM56AQ8LoLQIXI?GscT*NG$isYdJ2wrXhfp*=vEL>~f`Pvt>$~(W>1k zfjVxcJd<|sh8y5D4UOUY8q9j=@+%Fuf^8mDxSC+Su{;;;w1TuAAQkJgsCDuQzjZ|4x4^rxs{BdsK<3Up}D>X||@xBomoV8X+&YY=smvTFRe8_4gOc4VCUb+zZCW3#wHI4M*oQsvaf-X^DP?ZBPjwR( z>kJ+mdn*+eK_iM`lF?jatYfqla>#l2YBymrl>GW3lg|H!-gAn?a8UR+Dz{fxPq_w; zft3&M)LoW`dmcKWh2RVZxuS{wErabLA_t*q4OqHpR1cO!S3s+AD{5hpte8&gJ)dw; zuc=`M_tTyH_`wYqcohHwWH1Da0u(eUQ<0NSW$ycjQtz&QXBE3HHcGhVbRIF(rxW@7 zQ-rEoMOOfdwc+Nk$bIGxU9}#;Zh($E$^))==gVuqYBp1Tp=TCY_AEy(kc$7frrFqTB;lw<*Tun+rf2+QXCGO(hR>iG#N%AQI zB(Y1*ZD|n#@Bu}|B!#x!&y`;I_iPijVJS-=z&IG{NW=6y08xGjeX7Gs|5+zBD8mDz zP`G#hsAhZ4kX+e6+|HA;#8|V`yKF1*Z z89b%qmxUP(8+qIsgR|*_LcstI$Yg#&Pa>js$;Jv@EW5+o<$V`VPH-Mya2{*Uz+Ucc2AN|?&*O|^ zL^E@~?Z^70L{x44$mo+gBNK4g)*@B%+m^`$2QGkw0%`zN+1qw)Dc zOU;e#?Z!3vtwE!~e9U*=(VttZy}Uzpj!$_Me2@2 z+5URf$Mr>-{YRfV&{d;ThbO7O;Z>-gg?(qZFq@eZ8{QLN>wGSBFAm(rFT(-RO@u)qZE=h7Qb0A3o8@*C zJJv?ApaU3VT3(@_(rH(F@Ds3nu+0bZ*ftTnJSE>~;a{U)7s-k5@1umd&=1GJnlGT7 z{fs*!WASHPtZxI3-aaaf890=R@;~t!fVE@qfM0Pb2}*v7;*m41^)byK0BlM|2hyAS zCWZY^K%2X!Q!p_##P9oA&8gEa0+klZ!V0HnK&}52M4kYTu2G32E_Lp8YD3XPidwoT z;U_I-GvmQWmx}gN;w{aG??!blbzRd>6|m=TMZbIn16HpGggem*yK%RM^MfPBEu9@2 zF0$y#_g1r%E^+Y86|RZ7=dN`vDYyVIZhvB-x)s$++2c3Sx*QpH0c?V~Y~Z-m7kcd4Y`yN_(aMJ|7p%TAiEph@)%oO5fV#g45nB8KCQl)TVO-LwRX||BO4! zso*H^5c;0FMMzFP`V4M1_jap_LtT{v!Kdq*7Hux0Z}{fXo`=F&C#EnK(A6srQsMP2 zz|#H?c-P&$@wx$VZpKqS5wF*8E)rg+zt-@WfAS_;wd4)k+mRFSwB5w1j)dw zl5*hm1HQ2RRa+>rV@W*@6>;iZ&)qX29+Mx~`4|l3?Zmxn_c#A&zPd)%t*0C#<5JPO zY^(@ug9p+FJ`BwK2uAKqb|L*T;eBe6@RkEp*7bejub7JY4Rb+4~w; zKNtuZ=gt4r=X!BQh4{vN8_I|RqX(-Q7lA=#y7)ClXeXU|^ZjL3xsu=ZmIRI!8!uQo z$3OLvJsUa<=Hkkor&SC=i0meufNb)ZKFj?>`PsVWaT#x9X#PUC7e54}s&>VQbv%GqX|nLPGOHr$0=Ym|bL0ON8a{--5gQlZvw5=fjQS?t6xBB|3VWPW{e3UL zW4)x>mn}zTcK<=GiPB!vv>}s)eNi|ov*_L*oWi})#9T!=x)_MeW5QHCgCLm=*R7Je zvp~?j?uY6C=Zat+OePl>HxwtOYT+PM+7ssNB9m0Km9%0Ra`Pl9E7Z6YbJp_}NnzP( zJxJ$KJq#A?>^pPWkLCQAv1A#MsXi>WZP=xSW%0dcWJwv5JdvXEBTDJ*QidfN zX;xrBEB?KHL9nl~;WecX`IxJ34{1B+nbcN4_b7TxW=yQ!S2%M0-8tD+5{&_7Ed}^B zv*pkx4?TxpFk+e6BBe8Ks>3(Sdjm4Jqr^v3oQ& zI~`=GcJP3-TUQ36dCZJ`eN0Nts9rgOVW|?=Y!)cJP0!Ee4}at6Y=4Ys3PGOE*YWg4 zu#<8O8No<9`9$|(=t5UOwvsV%&EE=Z4!v&|JpaNvmcE`z`{~TuSGMh(*{}pR+WNYI zi79>y_hT#(|9bK7HXgDd0!9=P6$J#;r$CZtT-OU4xoz>f@tD$}?)wH9s0Y!n}N*#}$=Nfp`TN zDOz2^Sh8Hu-17g|{)EXL%<0edxeS|M&9OlUi4aLB8{S_FpjhYo=;L^KQ>p|6RXWi> zMl;(iJn0=I-6*E~@tUw~-TazR55^p@A3gTV^h=X-6cln?NJ9vkc`_i;>lzbzBmfgU z{ywaq-+g^8F5IkdH`O*ambL`J#Q^K&H&WWBHBa$o51Y<=MgY=d4-{8&PDwbrE#a+- zAL;{8Gh{MpT~E3YKPaR3c_{(N__d8nlUR%xSfP6cE@njdpQ?7W95w zD02RN{ydQfi0ehRa(!r^l29w7c`(>w>mVR3NEa1xzE0x07um*_I zN`$RP$Jxwtj0O|~9Km*|%Njr#ig_{0yL+Ngo0}1+;hl&^56HPGw$8SpqD=krF!c3Q zshg{#uQ=y_p7{rBK}5JHO5Lhp`{>!qU_F>z*#xHm8}ZUd2Yi){BHo5a@?_R@RdiNV z$l$11*uf4{owiY(GnVJpDo{nj@(N^0S<>`wNWkTTN4t zzH8+6t8sFd>b&xV5FkqTBdw(EG%f~kG`~S;)my~NnVx;(h3hugV-GpnP|f;I2qX!0 zYIhik*}Ld7nG0iCq013jlB43mz)8TOXy^{Q)+(RL2H_r*$-e?#4;TA_$jKf4y^js# znd7#|GpehjgwRj==Zl;^2gY*O1zV8^bJ9m3v6*o6l@=;=?tR*hN+6=cAtqi6)3Asl zEGf%W1`OKDw6i^#uYDR4Y{!-b#S%$}c-z$mo|sMX+~XwCU;)d-Zse8>TspayO&_)~ zS5RK02zid}$_L&;(Mf{7U<>gdb?$bILkIq+>Z0uKzt`Fo@Rr&g;XV^-AOg<+Utf{@I`qVH_(jOEM;}Qb18N zxanHoOxqYACPw?g-l@YL-;E!ExYYSaOrFyaGyoNG%=BEGh^i) zfiKjV(IA+}ec+{&u!@hfKclDeMv_tq@1uJOUHj!eT#A%59a;17j`$MK-^?}1-oshtJ9tw%>0FQ1PW+}5v zm}m4CwkiMM#pb;u!jF9Vg~K1YC`#2gtTj;zj3Z3DjPaAIM2(AA78csnCmh?GLLhKa z69iha1C2aQ3`~~%nE~nc`7Un#egv(~);t_+za8Bo24h^UI3{dlg?3MLuzK)SpQ9w{ z&i;xW*?n(D*kT{8{*rQ`qB$`2sOP|%#Qm+^-8f@nsj27;DqImzs%m`?5ed_469s3K zdIyLd->nu{RTV~86b@EP!(?-dJ`=n8}$y!JK%Pna7+f5eGp;ecGR%j<~{E~WPIyzzUkgZ(A=U7h)({Mg?}l6 z4P^U=zNK}wYD4etzF+Go_V*^K;*m~J9r0W7cUrxru;>SW?=EUP*xUZ6_>AFpnJ%4R zO1dY_!KX;&U0)+^4UMTWKIAFfiiMr4`bA!h#wt_Z2z06Y1Di&XYE|5yaB~xMitq=3 zfjJsftY5{A&V!&49wt=Q>|e#6Zqv1z&1_Hw3LPl@L)D?aMM&u0 z$m7|Eel>u*k9kxKO16&3-47)Q&yJ=DdebE?q>cRK1&cV|IbXFkFhJja+f?H>BDiM0 zy!`*;w;$9Yv`|rT%EBR~Dr>vqT`Kkih!S}AYO@1ggSBXtp$gO_;t$NkVmzMn)!jKr zrKbkd{~N4afQBAfhC5nW#>GY3N>Ij?m#U}+o>ts}z{k&YC(Sd`YMmyyV=*%~7fiRW zyQh#lP3jn9rm$;lGP|V9Kwa`Uuc`ljKEGMk4Hvm9M50zJ``0Xmjv*R6Dh>a)>>)LnmD@f{oFrFtjNvxkGt z#ZI3e!svkk7HkMl{nllcVof+RiDW5)|D>nw-@a-nih`i)HjgNEFO5SEsyCB`7vrfx z94RfazwMbrCA8uzKrb`E`hZx8p6Sn799D}eDj~K1c9k!FQq6++^YyeaO@M>Z6XAV$Ol|9#M#ap_uQXI|C6y?5@jVGE~tHIZb*7afD9m ztwyres#O0-U`B(onh+cVXx;)QF+27tR`e$$mZ1l}YdMTJzxbMF+_O(a)*_boIjg!) zYIz&JGuVfmWFl9M6y2~poDmOyeJ4n(4B4LC{WcQqF^h9zX!rIFXc^Dc=Tdx$X6!+q zyq`!9rEK+ar7L%lp1pPzZSR=!2w3Rw9 z&2E%Jv;Q}z)lXhmyUF4k;1x2AM)HgD%l>KHv8mip$BCLXn6*#}RqzzBijEv9jD14< zRk7`2oL490PKbNb{2L`e#Ris01D)9GuJsvRKl=JY?x0mB-Q>#5=9t||)^!*jnJ%j_ zzo%I*D5!mvgQ3370UjT;;iod_A0!k0Qqt3qI;y9w@pJJZe%_Ko6erGqX&swIP8nF; zC&^;3@)267OOoBSvf4WtMSn5fwWD?<0BNB8{)QxpFeyPzSR7f;E)iP?j#1!qmfTRS zIAX!iZ>$9R<+t!3*8otXz#%vYsj~bO)}q}Fx|3oc9S9O<$T-HV<_EAymD3Tyu0=7$t~BBSj+BKArG)2SRSL>*t)Fvdc0 zZK0Eq`1lctryS?HC1uVmOsBVs#bhn9k|-ubxg%3Sh;;w_;(uF9t1V_@sXgxQe3@>r z--Is5J?P3rVBIPUYyAC?Wk8;Q?d-Xw_lLlH5DOmVwI>kM_wrUsZI-iDXpU?}Y7Qr_ zHU<*o_8%UI!5@HViZ-dsWnh!Exa+At=*3~qPd8og*XU0zFW;JgHnPE^q<3049&hM3 zI0Z8WLQxuGF>pdWNq+o&F-K0!T)j0`T7xhAMC{1s8%j!kV~CTfJiJ^ozG|g&4IAx? z^grc#Zyav?k)Uhm1qgH?QgY$yUACAI zbN{4!9Bn&q@QwzHu|-11=?EjZW%v4YbG~Ldu4$As&&2_*n6mE-UU#fgljnh%xEFiG zE!=j^nZ#}V+hKT8IQWey(}=*R{Iy6>#3r^z!&{Qr~lHtpYqNsMx9}S z1sSmwC*6ycM$6FA9h5JACNcm}))}4KvTVkJzLmq1QGH<*w(aujK(;cRhGIk;wA; z8}T>H>@zD_Qe5jNVk%5K$LUri(t&?!Pa}NwjTpp5DT!L^e_$b_zEKXKNz^N=1$0SdlNoJi+Fnr2jLM& zVh7xR8xr#h#L}~SvLdh(6?=zULeRQtSI^`39|zj_tkp-Z{RXt@HpD@(5U|2d3XkR| zd2m`#IRr!~nxZ_UliQJM{dt_s2-0Y&1gKKI1FOODSB3Hfp9$}fhIFrxRXT@o1XC@a3^dx*`RpUqQbB5j@4s6}KJ|%@V0A+19-eTs z>&FDB%m`t$xV93f*kGAYQ|I-AkZQ~pVOHY)YKfPRUoKoZW|H*NLNdMc~W zg$L%Qa2;f6H(tJ2uNeI&7#WX_lzjF6k{e0RGcKwRRbjC1FJjhdBh3FD0z&$h zMDXAR>D{aQH;NOe8(7u?nQXjAfF-GQ&w_Z-pp;ijRVoKaK5#tF2g%esh=G3?fd1LK z%}<9RO)J4CBXgY)yiI-EimoBkm!iutyBpir3Nb!WYZMc(D{^Uiw4mby7Sa zg0ivlUpnMO^xS$Sq_@=97Lc&+c@z=^7aRwo^D)pxQ#NNL`ESLOL^vNGxX*{ApN8#N#j+KP(G+KvG9;X`m{-eo###}~?E2-47BI^&5f zMGr{EwBU!olH@?yi>UTR69Zsr>Ur7Ue5-{zrMrYFm`Qp!VB zd5SxSAOcQF0RvP$Fulv)OJ}{#SN{z`j(nO{J~7YzhaLzIMd2DrIbwqsRES&MPU**F z++qio!@;NG_(7kakwbhx6qgqsuANmw+ZUi4h1&gpEO9A(a~heue-wLA7j<{) zm&P(DbA(IQL6GXqKN;(4&!?x|t?Lsw_K3{Q4D~THiNH@z(M=1T`na{L-^G9n09Y5R z4$0qaL{_Fbc-%kWaOH2z$(@6RRT!iGQFpcr39%(TAv>+mt#wvdtD~)D&h~Mq6QXI} z05F%Ugh-`Yd#)mlJ*F4t@>XEX=P&P zMyHdRuI%J4y#Gay^@nJ5M$=Z-!j$jX^sh%qEmsp3FMJhjI_4Rv&C_6QZ7%MUD%~P6 zn|+Epg%`0s60zy;*Jd76au3o}e?W57mtmtZ{PM3>XDMj=G=oM0J(jeV5E%acv-C5o z%4>z{{QMb>Nn}OOZNHSI`0YM?eHTMO@{5yp9aUX%iZMDknXRnN7)GEd$JrfhtN z5R9a=*5pi-98>W#d5iQ^o2b9Y50=>)3LB0Go=T^@@4C-|RxqihIfvKK1c+rUyse69M3d4d=H{)CN%lHHAAK1pW@@fmmv@6X z6x!hIQw-S!Hz+`(V!Ztr`q7|)&It_MyuoN$w@#d$d9BdVo{#3s!<)=xlTr#y`JnV~ zy2G&0bbrZYO}{7@HAUr;ESv>C{q|^=YV0V7n0>>7|C+Jr?{AcF9q-)dK0#;-bv90j zo%311N|#91?76XmF%le=7^~nytGm@T2WJ)2 zeI8Mj!#soR`Buc+-#j$Ck_aqo^F#d;Va77SwL966eh!_Yd7wXF42?J&pWf`WJM>D7 zS$HLbX=vu*c>lxC3%KI{NRxXw+3CPE3}8v}n5OSwbhvp}U|icSgnF0h)n^5)V1BZC zEj_O#MWBtrj8$NUJ5AYfQaDo=NX_`;PUIr<_T8!-tAjCj)vTq2a%^V=?do0BN9%q=)i&+ zptX?Hr3WIsM;J8T!PC2Ak&M1Xrq2OMvLWCLtm zKWd_;*3HS+kKiwDT__ayuif{V!4Vjh3BqdY;mqWy_W1_EU5?&>tiBe2ehMzZhA8t|NnP*|-Mf%+u!KL(3^USBC3B+Y zA&q)u)iCbojL36}%yOF)v>m^mAS^{##A&@C$y>5iYg4Zo^8q_Hx8ml!z#x*jBQ7bU zqBw+lIud%pT5sHJ*h|a-Fx*!`f(axtiOv*k?{4k5%IZ`V8f>60? zy(D<>6hJ8LO%^M>3e)pR-%lm}75>f@c1i@H4Lq@!Yp~z5Zfr6MoDf6!!0Yde`ce-p z=3$&_#tQZTNnY>qcVo; zlifK<-TCseBLJy+mCP0Nz7o3CX*lZF^w^Qj0-l#_zl0Ys z2&%0K&ro^jaS%i4JQrd*Ejcm?_KaXYDdW^U-VA9V^r23i_q{~7Y5dVEcS_De@YIBc z{>6KEce;Srxk~)@j8QZqUb%ha&g@PjtXLom>A3d}^}Vs{2pIlieCIQulxJ?S%G{Hm z!990j0~WB6%LYw0V1`!sAX6)RIILV{g`e?zqm)=${-G}pPOmF+WF<5{+SumD-9*7Y z8mwz>g6lr(4*Kef&BJDsPS%=c`Z0RecYSY$K!SEE?|z+8D&?lV)!_oLUk=l>}0+iq;-^rVAMUab=A zE8(e3mmkgk6XbFD4D-{Zu-n4%vfH=m;M8TTeuZCd5^es=X^w4U+8je90z{)%O5Q9K zk$Z4arpL$8cMAT%I6=4CmTjF`{8}yz$%~P;eqF7f3ru0#(3-9q`(L{;`+i0nlNSOt zO<4U80`%Dg$5dz+pis1l{p#(N#U3D>j0;FcTxPp2wgm@hy(%u}L``962bgW72)~er zEnHAD$K0cUUURoy{sbfZwBJ1gBE13$(qF6<*$TvZb;_}Z1m{O=f^tH!K8UHW!O`SFxDGR^2Lki2yD8NBioKN2J z^PY3kc63PG_yx_l?5*RUuqxTA2(zjYQ>q%4XUkH}Gx{d-ncD3oFm2PUwfeBS$#(OX zE!lvlI=}d_KZ&G4{Hj3LXktqho;KOP&R%Tal5__kqdi?v4oAni(_DVq!+kX4I(bN7 z@T-1dnQVCE6+UugZ*%{6{rx(u2R3SnA*HvDTSZ+>w+S1$Axd9J_tEEeAVK8ypZ?LX z7tq5H0^YA6g|aNIt6Be1xw=K@@|3kFU!01T1C-gsguysyNB8H^^bU zK1Z}2+aW!a($kdwv+GCI)j{JX-!73c1ZpJUrXn>LWRumiQ`wr-M9)5=mlNmax@IlR zN44zLqfs;-=4s>G2GQVQJzt7tG#fyK?|1Ltpcn8l*LRuU_PxS&<*()oo|bt0V=pr@;4reVAL=1!eudpgq|(%VZqF-sq22QVh^^PE3yozA|0m6Ghn=F zDt6r)$#D#gp^Cf8K+WEm1BFVCtJS3`@?!6@$qX21lRaraff?=UyIPr^tE_Kt=qyRZ zt8A5EvaPqv&>w7!kMr@pc0dsHUgY|u3sz!t*c=8%6?>lfcrMYs8q?om{s_Fyr&BT@=DJZ8%Q)yO9$T+3W zb==KbdYc!>C`|Pws6wC1y^8`w`3Ou-XuV$l={^BGwR*n;EwaLMytsFStx`IoceZCY z3|6QAC_j8($ilMkd8(&Y|3FOLf&)rOnua!McA;Ml`OCsG1}0fG-DlR9JnVcq**;L7 zPgk&;$hzmBT4*^+qTyG|RDyA3f%UZWvUZ>onrkRC5oJrBMw!0W(igq5oKA4lBMay| zQF6T)b$Z%5h%>?3)t$Uw(|V4 zrD01mMMWKF0-oI;_BR9Jg@o#BTV-Xw?BYw#0Ut{6a5=vnMc7)$t9miQxtSq$m{sTr zow&75d~+3Rt_mt(G)WzP90})b&lOU92y1er7p`^Q=NO33E0_$2Z9IgGF-g)w0QH4o zLRx10_V4}y6%_m>ZziXF5t%_zV?)<=N@5D?DCS7>)A$=91y6TO+6de7&_a;n^KChx zSN1AEY28!$Zl-&s8=?d;&6xQ8muwO++*D4$zBd;yvx#H9gK!w;`!-XPHK3X2wM&K1 zj>rw@+NjAg8QURY&DBJf`=>h_Y?#=*XmwSk-LRRy3i3FsAnz+W@}JcnM{y>bdAUPh zzg!!|l`}r3`pMrYyQCgZgwM{0^wU z@{z&vCd%e|b-k3+0ZMne_JPLbM7^DW(Cfpqy!_?P zfL)r_YfoW;i_?Nq)s`Kx5Q}x&&&T5|W3+k;I)6gp&PF^z5XB%eADS2kn0J#+f^C7Q zo?uHb?yG^eRY>KtjyzyWPoM3$a1-eP=YnFxEpH*{BWc2%GHwg2rfzX~+t7mMH_3u~ zB=u#=3U;r_q=oo9iZpgEA)P%iULB!k;r>Hu@oi>RNz(bEgXXu$Y4Dn((I#V|>fI5< zrhN3Jlp-%Y58V3Kj8sIBN(h#rGJD#HLkMgfnXKTzqNQ`vDW#0`-?vd^12@wKee6W`tf5l=;ni>MhtBbBU@H7WvsZ)37N|+GS|rM zJkw2lm0LVpwSYep-4?64*kZ>b8*OpcPe{V-eNu?ohDSKNOk!f+%J|xDdjy!XklK~R zEP97kwIA2Xf5)a=-GNgOTHG+q?(T(**Du%)a8MR-_}QNk>e^_9(Xy-_v!8G!t+9%m z*BOqi#z#{;utYG5orJ>#C; z?yEQ9+VO0}4%+k?r2^of}loo8G!L+g2y^mtV zeM7d*fD)G}FZ$l4?KID0YckV3t5H&hL3DQMk>7!dO;nfN9uUxzmA-`DVEYLgRR)wJ zM&mn|i>$E{F8Ua>Klvgo1WL38&^n#^X$|qtuu2M!irZ9RCYjAz(~3pNJs;%&^7_-sSoTtfem2c?uWqqy%wBE; zM$C<1qu&1u^!1Kd1ND`4yCH=J>ZrmDcZC1V{&5~S{XlR4(C-OMHV^v&KuumK#f9D~ z4kC1?PGW_?6)0|RX&F!wh(YqR(_$eu_q2n^}=|G=Drp9q15@} z(5&&rm%Tx5(!fclDU6lk61J{`D=d5xNO>z+3NQtDc-yq;Tj-dF(D^U-#DEYafIw9s zwUbV}(xiFc*{p6C$rnW!r$}wP{Oa?;lrZtJfW4zn2khwr|B@JV4-B8fkGmnj5fime z{R@y?KDwG>sQ;#?jCWf<<7enpKU-*kNPED>6yz=is~SPkdH|COx&K?{5p`G?{)vEb zq8^5Rd-D|1{l5@9_^4g7=NmrtE8sN=Dk8>qW;!L;_k78<{ooY8`?(riy#t^SezdBkTEQ9b^X0?NqaI!0)W?~!{I{%Pcb zV>9;h)ZiA|WIuu`Pl9U(esd5)z|!vBLIYdHOr=TO9-D{Wh)os8d}Yx!A9zuAy2KZ| z-6CcG=-AN@xk=$W!|8BGZjR?19or{jdN|SBFo~YpkH3-nb+(cJ#K`x?vo+n7rbnn+ zI0g)ZKCBc+$b|yuF|CUy=HbLIpq?Z?XJ2_GmqTKmUdSvn-{LR;I7gc+PFB)S)8DNg z-^Q%(;yiPv*lTMUzNLAeXO^$ zLLhFp-Y=S1gr8nzB2HYCmqqURipAqlGGQm)I30kWmNQ7C=pKA)+i7rmqkYKJu|I}l zPVI2@#Rvsy{5}QGV6>jM0`DH>)Zpo8zh`j9>?b-s7;eV?4cOHKPo0=v?S(o00bs`l){5vO>pL#*18C}mU zcGPoO(&_3GcZgNSfV?>rv`gDuV={SpmuLz3bp8u+9Pz?HH%J%=k_h$6)L0?}mXk0< zOoj72B&`t>($0O&#A@H_xQLCBb4I%Y1HVR}0#aBcq3W13=SctVuhfA+miZ6>SOP4B z(jiOH^B@>omB)P)t)BrMy#?6#sgoXKn7bm5jEmygn=>I`6P?N15LiPkz+FpSn1I$y+musal zU|C|>L;Z+Qok=E|eVTA!pc(c?wR;aVG zTv%49wcn>v_gfVN&ZwEJih9Kr#Qu5PwM%OTUFZ{GR)MS(Sg{vNTc2&%v>vp4)ip$J zd49mz=tlkY?M&w{6;ztQP481|dIj;hRHV4na3r5VfV3@dlO)EGj#Lf4lacfTqtjXK zbS#AgHVyyY(;TKEJ!ex~4OrVFNG%QPdLrRW=bt$v|h3|eqF z@KH4>o!uh@=9$%134Z|^&oA3=h73l~N@RciKYfiLPeK!DAFWm%R3bcZI{fja>rfuh zv1+H9K)NCe3(tRIs;<38)W0(Lk2?7Ny4c#;#;VG08vFmm>TIfqI^*Zw*&K8cB(4=x z@?KUh;C4uw{+d*}LBvYeWFEa@-0D)u9x-~Yz0m>C4<;Hb$TsK|mXE+f;T4j$q@Rd} zKQHbIa;u>yv`cQ19wmHMT8fx(nYUsQPGYPd6MmROkPbvCcF=Le9whlU8>5dsjW6OI zEh2%;UiLoHM>am`S`0^F=t$m~1(0+4=av^(9{uB4Pv9fAhD~8CH%Qr+zvL!$f2Ue~ z<+1jk@C-fpTuAvs$VcZCIt?3wCxhtXqtDJn4vh>BC1RSk&uCY`+?3z=Ki&~U{0)2S zF6J)b;(n-O{<=@|<2p>NX4d0KO}qqeMM&Lt27orn${D;o^!nDMD~4AMBS{2_k9+3| z(X`_5P?2W@!aWj1V9A0kg_a+bgX0(LT~Q-=abWG1$+$&Qv}LJYjUPlRlxaaN7qP@t zwP3H40vm#4uczHF#LX5=@J>C070XSHja{Luv zF|NDx*v8NL?&nxU7aM0oSiZLYCO=9e5%AT#7@&dGaQ7n6NCdz+L?5Xq5 zm%1zY93M%S(ZYUGv5AIrluvnNO5JoaNz5SUkz10O$ydVux(M4g0gQ*H{u#B3W{wsF zn6D@@HldR%B$~qb?>cHJZfwzH)1Y|SOPTulnYSXb{^|{Nw z)r~e@^Cg*5o9h;p0%)O;eT&UAPTG(?4j6+ec(EiN7ru^v6@BrP2AWMTMY0`82YS0 zBQFO0)OU3C$O`|zv*}UvmF1+}kAa)rdRBU3kuUiPhf;*0C!CU((n)8W>M&v#ywkCm zu(|VV>et+=LP5HdN;3boiam)f(^w{S{1)|rV$f0j|6NNFUR(us#%ndA3||LCHce^> z%DgxT&e8;2dL0P^T{RP;7WGYZm*seoRB7q&@F96N7&k~WurOko=Je^`Ec00L%pR5@ z%cCLprjPcv>9o)Vq?lI%J`O}gVIe}*hW1q%Ik%1np*uf$n!@i5sjMSP4A_$~p#Y)S z%pa^5M!d-?)Hp-qDy5nM{_j~$bo9K4oQa>ISzRcDx>JYE=zbk?$8(jDw~8{D#&9XW zl`+JGfQVCu`|u**&qE@mh4&uXlZyK_D~txMJRN`sE0J$#%C#0$&}*h``PgVR=SP_{ zlxS%cnV@jjcB8E;ZWv&*&ihMpSt$8zmVI^d zm-o>U@+FZv=%C&Ww8snEkL2`hqc;xQ8v`%wwyVe{vD;5v(z^;#UZc!@NvtVZ!;|*g z0Ih=%CRK@10p4%F)>o|El*>|7>^JSb0w08d0;XsK3PFS7wmA>M$$z)IvC`%}`1qv# zGu%!+kZn={u9T#g7%N$LF1Ps&^C)ouy!s;{ieG}`~ZyV`-I)sHAh^#KoCkr#% z^sMYwl(raC?)854mQ zf<4o#nMT&kF4#k9TVu7SgVu-muO~l;hZTaazTOmH= z_e?yKw5sDX6`DHP2OBHZo0T@Qn9jN)rwsb2lDn)Ew?z(X8MI0&jkqnRLno6Z!Le9MgoZI($=4?cA$h1T^mW5<5qIR z0&OBa`mDq%b%!3fYMmbl1wKcG_-?&26XDI>G9c#%F~u1uPSz$t*c1JNy-mP;bni(v zqRkHhimG14fA8D3sZ9f6>5kp?9h5wp&E0dCqr@Z0D)u#1^O-b;4Z%hI+lN*_e+C~t z!05Al{{+g4EhpJL3JT>EO&hhvqlF~yVff4R&qy_30AJItbhZ@q5c`__G8yZ_b? z3MCXjUqBs(Kfyox3~%(Apvr^#wa+@$nhcGDha~Q6tQy;j!x=0E-bBP)Ed2a!1Lt5P)y?b+RDzPF?3wcu*ywN`BI+;%7szR3vo+R#7j6hh zx2Pc@WG=W)H?U-T9s?2Q%5B$ z+AsNoDD1uM`{c`B(%KBLn~cne&asXE70LD6jXKK;C?jwz`z|e!{Ylt-YEgVJpoEL9waPofo^|AO_!)Fmge_SW} z-%&VHfP|RKtr3ic7x$T`e7n5g5AJPEm!efP7)0Z0cH)2nIIovG5$!p|io}OV1OF23 zKEmZeUO!Bem-I-TTl|A_%8vJ39y{n&oM^r|%fC#-;gID=&st6%*x14z1d@WKSLAPVI= zpZn75AxbIQ*?+BIQ9R~K>7CUBqI_v;K3*L|@qR2I8Q>iueFZ(O#yXBhRlfPBVsli> zmd{VyZ#MrIyN?C|d~_%v?IH6RUoA>@Yf(WO)hTlgGkN z>+8^j?fOeE?jAnk(ZkKf@!VoqYt^eq#G-dEKnRmFu-qs9B%wfm^$Y&R%#}RKdl8LD z0bhp!MNj<>kjo+296tJc2)FolW#hl@1vUL1jwK?BzAMXr3JJ-)2>M_j1ETNQd)OAJ z&|$MObe1X!504n9^*hd|t}RZMTEVb$7=`4>%L;hr7jjb$Wpe%!1-*F=prk$hWpBaI z(s+_ibO5EfkKTm^C^>VGxnK)WTsS! zaA^9z!9(MM$uJ9Ygh>H=ozj9H(}wJZYF|)q#GBc|S~fgH-347G*iMj4{nY`)o+i<@ zo=PJ{jx4r{z}h{Uv5in%x|Q;*-WTs4@O7)ZnnjSB6{rO{DqFr54B|F%s9AgvQ0OOx zDY3SNEqKyy%ivK1Ua9fqy}_hZi)b;1K}9YuovGqG5I{zAbqXml02!#A=t0o^Ax7&t zsykq`HLDM@$qT7&oZ1F3?M9zc^BNhDOqxoi**~gW+l1%{gDjZm$4JtXXNgGd|7fsh}2r?7br;ia8K#Nk&b2ZTvN2tgeH zQEtw2ddL?WQ6>64jSnu_Z8(_a?|B!+#GTUpgrezKI56tJH$!l%B@CO9w3%{it+jFk z?sL{d1__6PN;%{`Ycc5a!C}UH(-ATsO9AdT?1~=OeEeX>TP)&y#`#6jZ?gJjU8qo;qSXgMXPMO9P3+PBbwWr73*y5YgLQ<)Cw*`(=`kh+4Q)NR4rl^6#ocJ}a*u#q1TA-EYqETu>Zu?iT<_j-3(K~a2mp{eIdWD_e! z{B33+9%m$J^h(RM${S2TDE*rsRb2tb_q^~JEzZ1IHg?_sU0`nxhHv-|%=~z|&DUDT z*x9ksPm*Op&jr4)-~H@5AVE8Uz{*C$#|a#?$=w#8Zs%yCxhl!Ce-5(P=svp+vZ|I% zXpTF_x1!pnbS~DOiI>^-C>q<&_EkDE;;0j?@0jL&ta75@o2_c%!m2&#_6Iu1Xg)gD1@spt{!wAlP_`EHs zZ&K0wRaZ(<5Ma!6+MzSK%R-L6okd19t;SCDttLESJ?Mb9mG6TY&J+4hHiRkxDk48@ zJQPxi#&d{G;Y*aJ$Wh@f>zSWaL#;fc%>$5D6KeV=-ko_f)R?`2dNtC#-s#4_`B8$v zl&neBO?4QEIBxdw9UEkc_W(oBl>%1A2*zoQdW@}Md3ZOin>Qg9;}a#PxMWBg+W%b( z+x^zmKAT>MR_w7E`T29{P0&UOOV|3fgXamaW2uL3FbGxHW0voAqn6VMt{Op0%s zW1FU#xD&Z;kGwd}e=ePqg*oD=FPdgh^EXwcEfj_~wE7;#qjKeXrFocCJk5-Coz#bg zqEgSgV9Dg;xO_RMzJv)T_eA1f@pN13?ib7z+t(9z$s!l@l9wO`1ezi(dH>;HO|~f= zHIMmj4Gg01?U|+;5-IrM^2wE@)*F^PBTmxJatR5ID(x>Kx>(wbZu0U3AxI%?Yo^m^ z+&F5~od4gKKWb?N&G^Q^N16Gxd(1blj@ug9VYUp_o$~E-0;qdx{`P_W39sa3-^I_W z1Z7vyoB2zWIe7Kt!v*WZ_Kbt^9q=|+AR09ZHa@cXr!%+aA+teTvjRyJI8{TJ_3zK1 zHYotBxYuW5Q@1QOajMHk7vwsR6~eSnkV)QSDNCVy=J8#S%QUQ@HN}uQt<$}JJ>0EY z&5Cv+;@pi@>-_*hagQ{7hn3Oo)4b)m)uXo>Q)S7e{_HFYC2keyeN4;q);eWHhZc8- z!{D>w{YH~X7UF~Mz-@-cVBrhFuQw8GZ_lfLXMS`LlUkp|m4upmo=^SPU)t6{=)Il9 zk5S(RJyt}G=l_MG@_?}SQiyb5a@vlT>o<>JVjo%KTp?2oCKb_OWxS*EEr$vnCgLgl&T zGt>PmOoX$0->y?K$DI+1UPnPGY2=Jb$Th?0)Tk%PZO~~Z@TA)NRNPrH;HV=eAy64C z1Gny(a~huLtsTMEc3I3LGselk2`6L8l%UGvm6WQVW>J!e?C6{$OO6vMWzqN9l4lj( z#?H7yG>>QP)z-~F*`kmoa8()og%S=bz}Sxb0M~cL*Qi5$fw}-Vn&7Urr_$u1>8hV8 zE~E}b>qx{L#humdq1?M&8sEVA2c8ghsrX~iDp)c`iDynfPp5yNiuut8&Sjci&)qI?QSM>8dclJG(C8cD0q)MbSg>c)seR4Ax@TQUIG*66 z^&~?khJN&F>f?E4H7BdPylV$;q=QSQPyP^pM;w*u5 z@re+C9Z!zG1d&ByRoBkkoIzsd-S}kh7ZJA(pE&obptX^7W9Y%(z4}>RV&2gkqZk6$ zZm}W`q3jmV%x0C&Z)>m|D1iYT((+~0{m_TgqGcTkP}gjWDW>mnY!aQd!8k$Lt+9z_ zpncI@k~@zl$%kNW1+9T6$w?GnBVwy!>hKZ3SR?I_-VOI>@Z$%za-6-sCo6DN1>v^m zUZaQa#h<;;9dGWoiznjRAgQe){xrt5vT2?pQHrd{N@s_4p|~{a*(3IF6cm)#2_oow z^STj1YLgwF>Ll_9XvN;k)OCW=g5#G?)y=kFfis!jW^;**+o@dN6e*O69OH3*WRjBX z0Jlha?&;cv=`!m!+3R~;bV>L(FZT{J59dMWtV?VFRI&eJ$B!Pie8We35E=QVgOKT$ z%+c6-K?CZ5vzFKTS z`T96_ZN@jitMO^4Ik`(>C{D_@6e{#y4<4_5JHrbTDXYB!LiBE^We&)OfDmf&M5PAo zcRcaRyf8uMCv-D2>u*5~VF_rsPKOO;+Jq%sYW z0GxX&@mA_Hh#yI|8KGGQTaW6g|xgs0l><>gozD2b*V7D}Z8o7m=Wjvo#thPfE zS#fX=T6}3trACG}q{U~rloQpG*)a4`Nr`Xr)dR4INZ=6~O2mYzErxq-`@;!bNK*!`u?`S(M z&rVz+Q+P2vdTlb4)lL1YWe*Y8`$PHm}>)(Sz+*gYK`N>~^rXvuP< zA1yo!8OG>`BHR1Gj*1-VUR{&_qKg;(eZ#9klmK>3?9midf#p1Y4~$jP?2r>RMxufY zVSsD>;_;l8&x=eE@%kb9;lUU6jf$lX7JWQd!WBDD-9UI-jN|yO2LNvyi%#3)R!rzb zc;(~hib_7rCXNUdr~V!7JI;Js4^9+7PdeGRq_EqtDJ!j}O^ny0s0CLGbLq&yEzcsyQ&3~=t|cr~3uzn;Y*SF{&dhw!U02l$M05I_1*EBi;?2ED>bSUNnx5HC@Ojp{(=PX@WBT+LKmjjqM4mCXD%w^bPy$p;y(oNWPJZbs>{;$0^{;ci z2&Y!U^#uAkLRJJ`X8kQXN$v+mPo7G}h9q<^{B}YPBNEnChn9*|_Tr>W1wTL(mtS~1 z%4#Pup~nh3ATTAnGfJAWPP)=ANa&=fK3N#ue4MmZPdwS+8q%ya1xoD;iC_ribRgm~ z!&6}&$OV?;S_aB^PTbFzRTk=Ms-ZD4^P~_ISw@%?$Z_j~*ubDkW5SFlne^#j$Fz;^ zC_Hs6jQ%f*Bu%leKQA%QXock~8#`EobPESg$Yl(MGR$6iArQ<}(Ng3U8d1X>-X>^1 zpYt%_7q4ZMvp6L#V}T9gd=cjX5MN%u=p4mS|GJ0qZzMKjV#UI6t4NkGyt zdJl1a;DSc~1O#_oQ2{E2fUFy?xrw&`y(`&*vz5qoq9XhvvyJ@CjMLrsQ-BM0s7nR{ zt$`u-qSDV6?V=j!jFRmQX1x&(@2KYIf;&NA~dMHz!y^3Zvr|@RNo;@9in!IduE*GoB2*NZwPnp<`!L)4o z9s1;r83D_5c8YngC&g+82huwP&QkSJp-RCSk=HDf=ud@eQ^Lzl{pq*H+hXPW)1mY)PVjZn>l6p+Ox zLNAHT&B`hS(O9wN%)%UpKKNgwGTW-_n$2w?!HT5sp=FQ&s)REM$_6ecC*s0 z?i31YK(aBSEvJcrg?Ymqm*OGN?A3yV!AkYxh!)XoZZKS@h)D!as~y%c2a8Ep3LKEBwK zZZ>#|UR62LrBiiPoK)s@*$4WBEr;hNW2>~k$UG;Xth94L@aV6O&wx6o_+b7qg@H`# zY0r1m2+uaXEUcEKE^Gbq7>F>N*Ci}2q>SP89Z(-nPhNj`&o)zRJOcOhIxnFG=m%SF zhOR%7;TR{7zV+~q-&q~4PWp6hxO}R z$+K~*&bc^TE0Lbkx|Ws3=R$z5f#^LU#4}Xm?G@+Y;gXF`oD~-j6@vU5r}(juCNQP= zuqPM6NgF7f@yVXv0>=E~FbFW)s&@knpHpgEfG$8LH{T=p@gcROo_9CLXuzg)aVbDp45KMkOTpt_ZPNz6Gkc833!7cv*0!DzfosQHMdQ^ z?Sw231YjY&2InVXN$PbbT*_(EU!90^26gMqe~3X43%Q=7&-6zXbjkV8Tihn2CJgYTM0wS{#Sw66+D8hNLv`p23{=ABlljvfGu{Du2H_c{pVVBBdE#|>_1r>S}P^6K;un@l*v7PpMQ z;<^7IS0d+D@Tb^Ffd9{)0Z0qmpc}6Pe2c&6dT_U1Y9eq3?ZS0qLZTvI+2{79V10K3 zFB_DvcfE>0@kakfRMD=SSlvHHfSJl?*|Cr?Cg^0S--6EdaEIEa8=FQt<_-4{m__}4 zZry7ius9l44^5=VPL!JU3cT2RnBn1}>K$4)t;ho2`7h^)DYd*h1`P{)4eV zS{(>t-~L?v0lAjt^40|@*jnFNgX4xt|2jE-S3ygi<1?HyP!@RXT^^0~ImO-dY=_g| z{)3U0VV9LxrrmJ364fObvt{%nu;#Ck{8$V(r%Ad?{n(Z#{z~jW5FfM;QAFk%p6UCs z?paMOIr$S-H7uVvO}NhC?sD|gJyc1!lBd_{+@qJd*(O74#FME^?gc`>zaV@2c``XP z0N!U#AWR;Tf;cD$66|KZKn<(wV+(_wDt0RA0MZ0|MJw(S4V9P2wcYzDx;!>fsNL8_ zlQJaCh1_#e!fx`;!$?pVtiO84oIg`#OX^5?4SdY(XFXP&+Zwwx5OP>xS~x0^*8&X6 zv`EkdDCUUpyek}lzZ!0p;>g^%Zu+feEeH5(AnEI3 z^ai>1U3o9lNFblwlze0B$Q|jUXzNGcYSX3pr*zhUNyCI@DQC#rXwrCzIn6`zb&D_) z>0Rb6!$p{UEAm&*Lpy|kC^eQ~QyNF=KrJoF^$=b}y0Dn)%CRc#pIWCdc-VIiyrL`^ zI;RGDT;2qNfVfn94xM%jOzDC~Eysi8?Mt(+Q>8JuBcHSgCjt8sh8(NX!JJWo%l}6* z3S)_)+>?@CyZoa?=$Y*Z>^g!DmnKl2T@5tzt3i<^6DU`c;|MIt*kH^T(pA1p&|yPT(gQk28r@ zV&rc6Ox;$d^Vt#a50AR@O>s1Dw9p5Jo?en#oLdfw<4^NaZbUO`kEijlC5!z`OsA65 zT=iY@Q?~v)Zi|Qs91fR}J^uMpSdLHvGS!bJ{Xz^oSkcDvM{|m;k6rC8jU3@*6s|ZZKko8%5M;C=UvdQEHp-7wT zrXjRa(Ax3=p3xXpE#fNtm)1f1g3tU`5hm=I+D*8FvrQBx84k;TM6>kIy6rbbDdQ1N zN6VXnSgfhj5sG;V@|m>gc0$tm`x7&YHUg%;;(p;^N&Days8wP)vW8=di ziBfFbo61zQe+o2!&f{pN%y;! z4!V-};uj!F=*<@#hIJO(^HmU%1AGAhm0`)r<`Avq2LW!Hk*{KL$b4JLu{;NGl~r6_ z>FUM~v<6}^aG`(+7p2uUi9^lEJf$_3EF=a$^Nugpa9nD~AJI#2D}AOumPp5-vp-lL zHETNqEWP^v92MiMD)dRqRg+2Rk9%fC!B2f=jJ{_zS7qCMaK30R6$R3^mG8rBNg$xM zDIMXmB-tX}R+UTzt8uqHSgsLQ;3-Jv)|v<(q4~Y#>q}(hsnwSN9shW)*LjA; z3QCm55lfMY*HrYEYDIYhyh1${oyV3gn(kvtK!wh~Lsq|t?^WV!Jp}xuC9gt44^9IF zJUX^l^ZfJnsEVe}=X@njQypl*Dq*A>SQZR5NH60F%!d!I0%@e)1sai>MYe7ZkK!Bj z+5ORstdl6qVt=Lv{Fj(&G7b7xe+Dx2TxQ2C7T@qlw=ygC8TxSau^#lNeZ0Ci>#CgJ`Jg$2NzKT``QlPgx|WNh0zBbBbY2!422jA7bor>lmj#I9o1yD_eLT6oucS;t z1WngToD-pwPuSX$C*-#iFU{=<2Pb&L-broIRSFIuO45!WWppPRZZ!1uqUFhq{ zkrqG7CgakyS|h8GXoH={$ndt6`sWltD2@3dSnlqPz&ed5ve4O%D2sCIijw=gYP_X~ zvxl`@ibNoDqWhiz(RU5M3=*j5!uJ^tNY0?QSzQuDc}PqpAY(+rEJ5#!vM5-7g^c4X z%0gM5!p2P>O}VM!MDY%grPGj;v5i4SvU#gLBCm)R4SHZ}owLi-W~sgi+ZoB-rTq9B zuB72RVonjq&SuQy5wiv#DIvK~U6QBTq9E%591m}MoRc!wJXO3>pCK~s{UH4MPcvd% zSrso=qBtK?8FHaU1g;0Crq(Tc5LK7jL`0hFvY3DLStHLcB0rSn+sdjhc1QW^1YB%+ z{*>RQrAYCayw#ej=B`{h0Nnx1BG@tQ1o^oAg(4w&o3b5cV}YzwK@fF*jo=XS#3$zA zkUTQ&cfa2Iw#k7S3ZULV4D9!&KlX5RC@0#~_p(RUU$nztbxUsiamgxe-AhxVMfv~> zoAOMdN&@V~D0Jr!e3=WH?g%fTcV$3|VNK`9zA`uBs}s+XHo20~2TfTj{CYR~{m(u} zo><~$r41f-f70qL%ltD%BpQO^LuEp&H(>r8#&#QxEFY5}8 zA}JAp2rIoTNz}X;KIH1{R3LV{nVFayn~sa=@Jig4)$X?$D7AdPF(IjEbuD+Cqia{H z@TU*gb5G=1?ReaGC9i zsb?PDm$m{pvtnWBt5rtF_xNH-y^F?yC1qN%W35Po=VfIXWp z;qdz<=>D|L$jwKC*sanzC6Pdvq~io>Q;tS#dWmUPL0FO+&gzPv06QiOS|GLJ+o{W> zr~{y#RcH}CMWlXRxy?7ryUHgaA}BOxurzARf|3Yz!<622V0KR?gszh0;Ow}cptXw4 zcK4S|Uyj98q)|_*Q6ne^sMOr^0rZ1WB(^PS zD$W^mhI<$~h~{X}EZ?s-^%w5qjNG50_5Pu$dJ3?vIEx$xstgUGX_G>2r|!WZ5+7=` zKwN3A4gWX{0>)+wXGY`xX{~Bg%7X4=Se(y9t={?@0bVofAB-k7b~L7ZXZUX>T*ZmN zGCB#u?grhed&@Bs<(rCHX`rgCL4u#ATD*aQaWNX+#`GmJIjBaqSiaFL{r3XtA}8PX z7o_S3xYxxv=5kEg9ky492KYU6|M`S|Y^J~fZ`ueFcgFxRK+eBTY~8q6Pm-1( zURfccbX)+i;i<@WXt4h~uCO60yUrlsVy>=LP^ma~JTOI|!WJqBxlNuz2+GdM+FKloT8RWu_u&&E~i8zB%_T#Pfp1}k+Q zA%|~YGtZ0fEmf8Au!k$U(#!K&E;K82v7FJhrTO^;V^45N4oWiCsM+&8sUJ~G&#uc* zQXwU;zJCTShX|cX0?>3tN2F!h5nAV)<~fZt1uWbW#Y7SLGKT-mkb0J}e0)+AL^Cz7 zMakV4gzYMD+`iozl*hXCjdgAUaw7UL^Pt?`&?_AU(1dxH6}L7%Y0~K%FT>SZ^E`3L zyu09;*SbP@I8jpv?38=0bhz)Jldegq31J26VZmTJ$v+#kf<|`8f{VMyjy#HCwj2{~8 zzC7a-eJn?`c;kAMxKpQ}139Sy`FZ>7k13&0Fl%!0v>W%fVqdWf>(Ssd`U?8`BjR#e z=8FrLaeVbD%w3?ildvx&)?b$`ERf_W1BaiZ* z^YEu>Z6Kp5UT4B=Q0CfS=r8B}KjzML|8bC!=2n$!7;AuGzNLfHCS(}l%2L+?8HYT; zdnuO{Jf>}ZiT@qUh)LfxiX9$%c^o1GS@{<{^@rHsaS+n`qdRBSS|P9&b4k-HS1s30L{pex zJ;1-w+HW@U3VUf~=VbO49I(|Elb+OTE8ClTlxeq0c+FNtu4>UlU$4(9r1_>plNhv6 zC<>9K_-4#=du*}96;fm2wHDaY$o`7SN{ufvRr6E$$LjwaB6>?;Zc`Y{cYJxlHHxyg z3{CzNtNtf;rPV!qsnwI7x4Cp;sww9N^@T>^y?U1-w9f*+|Kv0mFWe**j0&=D(^e>h z?Z?Snei{9i5w_X+K93c!U%bX82E!~g2^S9bs-1v#Wjt4-Jvdd>ZhUAFL8nHHsDRHD zq+!Y`TZ{p-JLV3(;2x$gCoTzC?g~n93|AUh3`X22Y59D-1Hha*;uY7*ADumS1Gh;l zB#`_LQ)xBYUaP3zau5PcS3NOEEVhn3yYcOQJ40q=`JYg_#Y~5eMA+mHI&P3Ly<3Xz z!bTBpTi5abH!GYIEQ*ec1A(#WiprD9(6sN#_&*{{;(5Wa~34LAxa<=)y$r}MF>2`|3+%V4*J>wh3GnRxe^ZlcRCz0=GpVfF~u6Mg_fjYjJmy~tVf|xjV z8qKMEelfVjs?jO;U#HQU@=n#O7i{YVlv_a(CNloeCvNuIjNO8XgU0T;(0WokZGHxP zG(Oz4Y9v?s8nCsNbZ*7zbv%iMG7RKkfuXiZkzJ1~LNXfxMR7CUU-QJWE%75=U~6W} zhzI$_P0*d(2^30BF+ltO+|>G z-_q|kV%k};NYgO8+)iy?oq0O>$^L^iW=i9m1ka}sk@`;|>p##}8sf2k%h(H59_m<4 zPcS<3>}3`ol^q#kpZ`1ZI75$gr>uN(Kw7^DL}FESJpH9y%QW4$BgUYiQa_Qw{m=4Hs5Hzvl?`FS z8>0A(E=6-J@)BRjvkFs>=rmdM8**-yjLtTDr-GbdXzbv7TpQ={$=LfAU+8@d@+d&= zi&tq@_fTx=-E8IPxi3+vYDHBV72Lk9av!{K0X#z9K}HIEbhwv%48WdPf5}usas_V^ z0c9h3tD?rO(gVo4usVU}*Em$OMyWaF+jagI(EL|n7=hm#0oy90kjCtmowHe%oSUUmVo^o51z zU;y_-&8pIg^-_;g^mao&@y3k z1UcBXc8*jRv*r*4S0oXKl>5c8ca>T1y+BWBrvWiTV^I`9@1$+sPS~zM*#N!Dpie}~ zeGIQKuu?9mjpxHAXq@Mi^u#}-Kn)((8sW?It-gcii7d3py(Q;BjbW1J{}WmPnC6nc zbv(nv#bkjpcP@>-!ZG2BmA>qTgkXWg0=ov?l`{^&lk6dXB(ojgqf}VV;Y2iA3aGK%OsVNSGl9yPvkm~ z{({XU9{WlNEwYN7^Dl;YgcpAnxikuTC@}}1cM+bx-Gg%pN;$fVXAyR6PFCzFfO9~BF=1&w zy3=a+jA-L!jJ~0$OsH6^q#^4ZuvSCF=E$0}2ZxGthz8 z<~(^=*_L&j@v+uQF7bF6044{hTBUOPR{m}JC7g98)5E(W4TRNn{;(!H-?r{c^rAO5 z(MU93ViH|G7fmO}Vbw3Uk79tQF1|u+{;A`E`7_UurBaQ6YJnKc#Y!8h?!pW3ems9=sFOoZA6r6Zi|k>CYI#z=!O1tyvYWfTShui zaZ{6GHN@EZ9hInYI~fot|Is>L@V0IOm-yc+F84+G3K7jx>FcQNQqbr>vR=YxJuoj= zTXFNpZ>BWR$J#|&>;?hDsZN^dU{8f5q^(nyH3eKahLx+!8hwhUc`E_QQGX62+WlBYa_N(ggwTrnCnlr0CC^d2<%E40yS z=N(b|<=w#P_lO%j8kgIG5Z57lqOo~y2u%4v$z0+`M`Cl`2wUS{NAy0}p^2;Qu8ai2 zOrt$4uO+vk1D|l0$ta&)YRxT4-MJ-_$zf&X0(v;hjf!j~1l6U&_&z}O2$sy4)B*I? z?gC}oBKbW4TdyX8U_;tJmeH^92@PWZWy7m};a zAS=OD_ZxQW>>=DKWIo=xX$0pgS!)Nrc!BAO=JZ^c&KbvqM^lMuEX-3DjNpx+3}1sA z#Mu7-{rLNp0aIIq%k+{yNc|yv(=)^q^ej~UZ3bZFuke9rz#22)@gQ@J30}CVn>hLO z=`2#7Dx#W6Q=&7KS5+Py^`3s`YB#~JEn1!XO^faPY`EKUry_0kQ(Co3nQ#>%oeA*= zOkJ+svNhLEp%nQRcov`n@4K>Ym+`k(@Rt}IwRU4E6^qVGc7?zI=Y^%u`n`K6%P>~y zYw@O#u4K=h6J{ACLw!{%w-fr(&9gAtoYGLa;l}1vrG$r2`pB8OqPdx;3VnlTC+tw% zD(P+U^(ho+{t<~$1}F&}(@)-Ly0zCm(2<%N15dF3Lo^tgzg0ps)UEc>LZ5qQsWf0C zzjigzgT4PX`Q!NGiP0LQop)H}q`Q(14zV-f^^I5MQd$k#cy+qP8DFfAN5`JM^EY@7 zNO0;_oM3v`BJ0$IZt^XZyyS~m!=A4S9~Wk1y)SO$ztuWDWVsAfJa*jZ$6Np39d(AhIxFtBRW$O zcc6A0e8ZDFY}!Wfqh(UFLZsSSB@0Mm0MCgs{l80Cr(MOa7D5gS2hRZP2g>XhJXUig zU-a{mjp|romT07cAOtT1bs<2wAdyw3Xa3%5_*KV-^|iJ8^J#LxTBIGy$L)bj>zTYN zV450Z(>yox2V{{gSzee*0@WEkb=%lxG$>8C zxSYl5nvI0DohIz?3H! z4EU1ult9clSqA#`N&Pr4T)chbx`mbB+(W$RqjwlED=9HgD+)cZ-x5(^>QtpgP`Z1 zQhyDKLm(8{2Bek$Vro=IE-N6d$HLZI|FsuBn_sHP*#D9=4uJ?V;g*XG3ls=4s{3C% zp|4_qR{W=|3@QSUYR>KU{tk|?KIiZ9qs&A{z5yK2QMUfdoH8uczt4%uSfeH4`C#88U^wSXKOW9jc)Jn`#2w-1k5QEBELjv0bnjTq2lVgw41E2Rhmc?$`RDipf!#Y%C zil2br_w8?52iE*Y@}h$@lr2S5Z#S@DtV|efbmU+F9>8+OcQ+m|^d*l8(D3+qcy9Xu zachv*DfrmVX6Z4E*R72IO~XQi&Atd`<+~FQ2+e?{Ag2nEjWQ`%j14Yy2|8C3X1ATT z9#xmt%Y;nf2DjV1AaCyZG8yY@S_xjz5*pr6|1_{CUQT66+_nUqWT-Z3G@6Nyg;2$7 ze{R)xP4JK8Y~U38qD6$!|Ja_`3AYHEy#OE|i=-L?d|*}nw#xGUB(>8cg9e3}v9$P1 ztoFYsRw=Xnn=bea>96ux6WZTKyBBZ^P|iZw8r%)AQ$NEf*yYd^<6A82mSOJ|^Ebu7 zW|C!lWJUr}l>wi0*Cdvp1NsPer%m~?mF)dw3w0HKRH}ARj-=0m*^ETj)|lySIug+S zKxH+%JN0LyxCIL6R%?okeF;X8?O@mc@&YgtN-df2!iIn-5I@>{Kg7sShHzgl43;Nq zy>1@CrXr26>S`eETQn)ie`V9tST~u`w@U_C!bM6y8rz<$w?Z~Ug*7*a-mQPZ!^hcw z^aEA{&aW+@`$5%p^e28Y_eW7uNRRG5^H83lYqI}>h5<`4+2TNw zZ72A(jzp+DetWM2N{9u$mo2$v-S@&1anC_r5jC!Y?co;BCsh{$(pv>W`Sr?oC&lmK zL2+YlZ%o~q!f05*x8jr(f3< z1J-a6Da7DEFS(}4Kb~9ZZ#u2w+4zIJU>HN&1c16wel*G&DSaC2}h0Eb?>I<=?UNs)e9QX+T9^NZnaJc>iF z@ed-8+?o^K=SZv`HhPHlihVwO*5E#9@a%J7w%dy_lTS@$6 zB+g`EX$OZN#@R&2t zmkNg^IM%}B4s;={O9RnzX!!U0%Dx1lFLboPPSYWE2rQI?PRWhZusfs8=8(J!FiD5m zwbTo>6LEr1XX-RV8J1Ae;k_IdJD+O9~Z6rH5tZ$vQ(7a z7>}3TN}`vs?qdFN)`WqfO_pa*Ij!-L2{8gkbysoeqfQ8k5i3XukI{U zh0L8MgYf^CHUB+L2Ac{5@N~WeD&H(=zDVu+#n$^ZCa1$XWT3nHhFICfra*|5ksudkjZt#kHRW2k7gX+q5yPmZx_#&LG79>l4|P ztTp_R4S?Ng!v2{A`gyP^0z)L3S_$+nuuuN`Fg`A&iH@eg3WMe~JTARlsF8Y|26jiV>HJ)FBUyO7);PZ=4!3AVWjS}4H1m<% z9hslkgk+nf7Kg%m4ZJ1p7OzSsn1e9KYIzm&(m{vNDz6rT|B?Zlh|m*tS_v9VfaHd_ z8&RCTXryA8Ik|3jDIT{ox*}xZ(dETlgyJ@lJL-m*hoId7)F)UZE(>r#vh(?#FPs`+R4ZhB&&L2P-cVO(DJ}0Gej*Gy{qgjagSanyI zZae#-CU|L4<$439!*$}dj=;=_1=_&*2)bH!MRU~!+`p;WuG--+I`6jEc3eho1k8h0 z-y!IoMg6YS{PYfFO!v|UpLXnNdGOEclyULrqUQ>gs611z{m8?mG&#*;v3S-|;i7cd zCI2SGg`S_7Mlpm57*azGuAcuA1^1Y~*8xK?JTiF?dM)lY#yz2cfm+Hc3o-xtl{*cD zUks@nRqe$9N*-;(Ni^q8W39JXDfr=42Devd1;)3;GBH3uuiWf$kx)V!- zcavF7c6*ImGp6hvBz#ci|4<8Qb%Ojc&nB{DSGo6k+iHLeUifa#uY*o=Ym4Da{}_mJ zbS;<9N#Oj>@DieH6LEX!G;5YxF%St`$csp7Uc;{W8s~#&F0jvPQ1d*2*293WIX2Sf zk2_8j?tMBR9V{VRb{pP;9b6bW8&vAaY(6cFdyoq|FNREDpNc##BK1C53&J5jt#Zwk zQSwhF8uTzHVg`PoXUA{B*fEzIi0d5;Xiq4n;htx)e(z9S<$mTl$aT&KJr7}sqH5TW zf6k`1u+C6+e5J>hT%T>gM9LR?^tUQ%?XaKGn6H3}_P1DSJ8dT($Kc68 zSi*C+&DxceM<9pHlK_os?netEj)toKKcl;C1q`BwQM>DXGtzkTx@<MxG{=ehyN*jQDRy@m>%BrH1lMc z&+U=>Coz|wW=jp%<`<2ddJo#)W_2!R#)Zr$Mkjjpn4!gpQ+qbQn7}4=E?*0^ryn*N zXcU)3@SxLU^Io$0a{6QL@J;~=ICcCAx7sFn8ZVzUl&3~o*869#D@lx7AY+wDAcNB> zcF~QOGswA1NTbkH4UQOBW(Ed8azf?n)zBA?T83~%D9W#QjqI9Pt$D~{lGTSclk%Yp zN&OjC4oDg{2;-J|19Uk9rD3GAA{11S>{u}=)eqyf z1g2qa2|#0jPQp(&v3^>mrVa;Ofx`g+15Pf&=gXIOq!(ch_%E7mzg$&DNzSNWYqNvy z&^L1!6<7MG%iC*QU*vn8bdxuB<|WN`Qk7#Q#u@m z2&`-{Ff4_r4gILJO+Nxue!4KFDiAGGc=B(S(r)rsz#VVSoPd*Mq-RQI;U zqH4g8nf@r}F(CkWcQM2MOQb)BrU1G4QY~j)aGjT z)rReb8jQOeF|31#zy9MG<6W%ur7(d( zplNd9%6Q?oPJ8!s{MbS_5@VBl5?p6CRw~TS+|@Q<%`dJCiZxj}QlTtG@UdFUSz_P1 z&FL>X^vWBKa&`C5^E1+U>tu|@;PQXPmLkh+n3fV)Y)~(v5qt(&Ax}kh9TR^&q8Vc* z>|HK6#s7Mfk|E66BUnk2HqEHSjPg`s&wdMF>ZZjEC4L)EaQ4MYGz)9h5~=m;Zo|KG zDfH18()~mLIS7T;q;QJZ;GNmgHI#D=10k+x2NwP7mouC5A&3F6m4b~EX)L7yy@VvW zxp@&r;MA^ra8v+849~pLqoUQu5dJKu8@72fSWGK8abpF+(uX+}@jh+h%o=Mz5};0u zFp)v+dBW7c?bwK$4Pd7rOpX+v=D_dFg60S^#D57AbXl!3gBUOzu#Bz!jUFPWbtlI; zUmuYJS4_69<)s~ipNC>BPqYr2nSpGJD@-&%LyTc+DITf)8D>3#|7KHe(?h^p{7l{p zo3tW#ZHPA&j%lsVX>jSZBq?7J-%nni@pad5EyU0LA2C!S3fnJ`PkVmjnT}Vd{E~7b zH<-|-5!ytRw+#1)_2fJL*dNher;S_g*%tf4yf5W~qwFWMt~r++H>5u}1xhr74LHjC z3&N|vqj`Ve6vNC*Yfc>JGy|dKgxkB6yEM9YGWynb?({8rL%<^B`(k#D3a?XFpvlv~ z-_v*gNIkv^`Ij8u>r1mahaRr@A4uQ>VOy!^V6%wf0j%cTfqZmO2aRZSo!+au5FiPA z7X#a+%Px)id1miB?UAPR0Mrr=Z5r=uJFMpCR9W`V+UJ2^vKuXY`3Zqgi5~=rchggv zVJSE^MvvmwT-kF@D<1=3O|?ErYWf7Rbu*A(}k))ao##+f5xmCdTeBhzDV%~e} z1PFLU){~tS7jHZ3_CWs1yRXO+S^?VR0$79NjFA$c&NL=p37e~*4E8_r&X3MCLsYTvaWh4FogI9g z-%*T?@YD8777}rC>`uIqjc#vFpQvCm1uD7%xV(Smm_b3f98ShM#OQZB8qN6K7WsWZ_3IjM%{Z!I%HQ#&%~lo$l~I z!Lh3+9C@W`Wn|t&gpv8wyfSPHhWs!|z4#i|JdWq}jMU8f4gspzzc5o?7s>A~DMe%x z=|#XnEC3} zb7hIx3R}!5g_*Fw_Yh6$P85&odJd_{Jf58AB^x%I7yGGgZ&OUOQ%+w}T z>3kTyT+i--AQL|yxujT^0oDI(bMXO9hNRnqoGk6^2I5o;o*0$Xs z{1RkpYJ{mnep^n4(L zi4%Om+X=F)cMi~5>EGh@3D%-~4E(+5R=ex)WQ+LbfhVu5Xb0ABwKPk$iBmkZ>U$(9 zXR988`6P3*<@MT_KdwlcO3nxU5~>4@4`jz-sHeX1CWOP1YE&cLsThk9l~G45!8i~~ zn7__er<$<3sLz8zE8!&*>itd=5|+L4am8rCu#x^6`+~q~&U9yQU!iz1{bLTMfH>%6 z6zY*kK;TR&${bMa_DeO%5sVq+L@Ws24m|`|RQX#%>{S7)))u>gl<$q2&GH<@q_V zT7FGKaroGora=M_1nHL;fGwagmjEMO;bbQ^xS4*Y4@a3}V0HiEsIzKtstE#F}FQr)?s1gRh4TTUrKO# zOqj0SoL^+a$MCt`L%nR}=nmdd^Y|*~(%A zN+HUrb%Yv@TtsKI8zamh=p+^^O3l;peBdc>4!#sdS8iE2oUKa3ucnR)bhUVqoG&4X zGZKJ0h=uO553KP)>!C!mBGz@IN6gRb5Mzs1B}W}w_R2BEb-~zX(xchJG3g^WFIDNq z;y6Niq+zB!)x-l1dc(PnOOyf9qD|KqC&j}SO5BddT5|yA<3;6)9ZC#wlEQgWxo_|V zt$?5c4jGEKR8OE+xh38dbC(~$RrIkNAdZpgCr`>02kENNS8O&DMqA&%rw|emWxv*o zObs}5e%@Hv=xj&1r#@ElH46_L-{*I8|B#cy2ad`Kum_HphNd7;F~e0-cm9PuGJ3QD zamG&0g$h6dagW?pv;~-GOhGgiKVj%-nn;GYojHO?FDvGJI%na7!Iq#jVOw(md?T0RJ#hIZK~De#wOVhhU!Vt|fw1 zq7W3iyp@&BX4Ip3D)XWW`~wdO!`c^WM33b#DYm;k{S&Pdc6A3PYl)P{FwfHIg*nh3 zJ7ap39ur&LZOzkH-sPXp)i-}gCPH%!-_X2@V&A}0Kh`31zb5s?w3#k+ z9TQQY$;E!eV1Y-R{v`PHg{G>tQsX8C$Cfqg=cA+Mk;nIf;$?Rjg(cYhrifxGK2Mu# zdrkf4*4#7u<%hC|Vrrk=nDEN+19Va$(Y7`4tqF(-WQ3^Yx&bZ0T$Jlpf}_5qBIXv4 zvb{AB7RRI@Osmm*!^s$x?;(s7THRwcrh=XKD_I}Rg z6dgvl+mL9g&T>l>l7$z5*V;MwIy&XfS@R*a;@a~^!FMbII+|`3U1u+Cm8*uV^<&1N zLuuIQ*zfAQw`W;zErgXd!f6LufrTF1>J>t(h~fiHE4Ww2TxuHhn zQjcsfbd)RcbZI0+%D7@OKpOy|Zao8Me_q48?FhGLmf+%Ol zXNHEkks(G-eHV$v@E^m}Dysv~@ie^0d$PFZ{roThY1O`b#5M-XI6{ob{cdelS`51Kz`N)qlm>32R7Pxtj=%}WUJ{vS9 zK|$;G{8h0!g?5780!r~3qxV2tbCaIdQ_lr@q7UD)nxO^MQxSw6_p3DDS}Bvp<_^!u z00eOi@kdW)5^`%dpu&3ro`eNsfOhJpq+z8X&)& zZC!Y&D=$l@C*wAfT3e4Rv&#lB;sJ=%(KUI+#Zkd>H)TheVU!#&61PaBzEvy-rP?6nLO6q#@c@lPBzD}L&#=3|J zvrHR5-{mRPQ6woiqHN+82!_?q{$bi-ylYFeN8ZsV&t{ky8?JNQfrEJ!*&VgF?X+&2 zNJssD^$;=@W60Qv?eB!yId?65+p4#Gtzg-rYVJfGs*aaIf1foz(e2MQ)mqRbvah7b zK-W=@%Gc==#ms5%Q*Unara`_3u69xY)kMpxj~alOm1sdrz9)i6^6<2S5es<*I^QvE|+f-#^RJ#s93gwOR?yeokOCaH}H*uOPP^&@JB^6>1N!1wSfmlAOUimdTC~l zvpPpRiTfeq=%igH+VT)yfMbdvbB?)F>|s4dTcOE89!EFikU!n@Lwf+)*0FVP z->7;Op9RQ!uVT5zH`cko{GTb;WBhQo35KL$zOW|od#Oy9wlRb9CPkjJBVys3O34#V zpWM+t7Dx%76GEYc*6=XzHOm6m2Q7aYby=w!J;Prdz;-cv@t7mXV2xEjd<{#y3cRB=;rb9!Te@coTfk29)v+lA4M@)5Dl|uLb!10K^eo=C#DQDgz z_dc&)9k3hY5n5uOjK`(3hS8*SVmUpj5Xin zbli<)yUox`1%TJ|L4Q-&+_gsjs$^|siSg*t%2w3xEk~K@F(_VPUy3|~i}S}sgOh#B zO}waln^N2E`?a{wXexqE?M_DqDN)p+Ok3ZW@+tL3Z7C{e39xEp8=cGg)llFMsE*F5F#la&gbYr(h)Spc=wrG=ai!k2>6W}FMxDja+&2G@K(|&5Bo(s2 z$K;0Av}y^V9Yk@`9b%%VeancqA|)2Cd^}?%x#N{yO!bdP@7{S2vCqdEmy-b!xqPSt zbuH(GG*d@y^4$S%tO%yK@+{^Yv^L7=mjXl>6EXf;jpPK?6`~%c{rdAx5KXA+=$Rw7 zhzP{>4`t>nFO5&k%@);8S0acdUd{V69%xL3O1FjLzU{7@^jYO4MhFddGIY3b9wa#lSp(kHFs%;ey67B> z8B2OYnnN)~1EoFI&i-KFQq)n-RE+S(lC~pUSRvN3nqS$p$%+%on9hqrW+*K5RyBo99(}tC-7d1d`44CFn;pdfisC&ZibH7n8yqR5dZgl ze?Pq(1R4j(=w;mYl5{(+MX2BoHlTT4vARaylL%L7d@o~pN{b-^_#@&{4DP6zxNcG% zKv;5S;2%nX!iDl?sX&X>D(28Ecj8ur$mfj857Ln*BP=r2IB;PwXE9&}GvT5A!@9>o zbP7D~kg)jr_ONQLCoIL0T51l~iC--tS4BRciFD?3$&LBeFRuC$_XBSs{8e6P_?-Vt zLR7m2udSBG|DS!P3{roT*yz@iCq1n&YA)~P@dEAj_-dMg(gQ};j9rMenqSYJpp8kn zT%S{46B_wrJyL$0C&?s5K5__f=mrJz^xL)GB$IZSy(gSZR%3QSUuE}$XllVh7PP#h zQI(it+45tP^E$KPXIT|i4nmlai>%+Q00c+eiabKZTcr?NOto>xL2GwA>YT-~ii+Td zzMSUSbX6^Tb8R2E!W7VnS&)uknvzvBF>&S>8{&`;xpbzvycO5NeNzK|aS1hj&&?`d zu=3O%RM0o9+9JbGqP%gjqlNrdZr?qGQV3GuI}K=QVP#DtcUg}Tlgiix*5(E%qS?a9 zY#+ZUVS3B+k7xDF_|@O-3M+i&UsbIo3&6vr9KXIkxz|nXo?9sklQjn9qz;-QB(py3 z+j2NOk`UYZLwD!R;D3{u3PHLJ)kI#8Cq^Y?^~nZsM--)`GB%}cD_dKV{%utm>IQ{` zdL6s91SS>AI-Q)8f-z;>{%+uoM;^~Fe**j**c`K8$n11n7MD zO*n@|e4M4ljG>&!rZ<-S;oR9h{u873Fg9uMCQ-j8*LzsHe|jlMeUKZzSfcQ$F#yOp z7c7#dj@+q-5x*hg-Dcz3V#zyRxHE};Bj-Ob;R*((CHKATw}8N}(>21}DDFb?uG1I( z8mM?X`OArP-Kp9@AphKZHIFDoM&iDjt+i9fa+F&?`X*o<@zYG7x80$Ugo0GUk7k;( zaROcqky`yL8C;ToehJ2^wV(mi1S;#X|A4)_%;*n$f!4N-1Kg!t{ZCD0JBY2o2CpK~ ziI@KQ+Yv()OdAD%0zjjTARU7 zAZKFyT&*yrtE<*`Herh;B8o%#n(OkI7)05hX7PJhX{&g<7k??IpP;yv_ixn-o*Rc{ z$4Tz173Vx2tJ94c94xm0c(l|;dqO{@19le{K?xkT)Ii#hRA=0P4YkG8N&yQW_1raJ z$%|m02K78qd88!gHzun->-9!%oC2aa5vKrH-gHX%6&)u~ddaF;H|&~|BXqNYmA^f)-DatbTWd^Q5zh$jrq{MfO11FnXkc3a-vrsHhNwv#;qN;|Zs3 z9q_LzFvq2YTudzcN>B9qFr@Ixs|ioVeXxkVySzwLbl#t0zuz_kPG1^6mcVmHm&Z(s zZ^tlP55@x*z)0d?1g_Ki8wfogJrhC;>wB+$6mRVIH3L5IK2)96%F)YkhKglu)+}{U zH2TUb$n}h_aB9XASTuOf5qH{QI0ABuSc?kaHIed2B4`cZ&ga#jatfnMSR z6j=A_$8olR|2=DXpMwPU>^a|bsa|PKcXFM3EnQDYs4ic?@~tZ|S74hGIjM8_bifZY zwhrPxExSq?1x?u~`V*7gH8*eZZ=MlD!XN8xr5{^Pwa1IxBAl)4-e!D<$n60^k9_zM zHCf_gn}q||IZ*0bgzLs080z+qDMe zsl6o8kOtuj^$?m0p4UjH-&SGwAOVlFWYQP&0WF>X3&nx`j`ZWP(TCq;nw%&sj7=t4 zT66thM)hruLV+Ozubi4EzBA_tP!p&!&;Yso?$lQ)dzb`Bz!w)$6R%6fu3*GDf7!T{ zD%oIt$+{vY0LYow&fMfp;ZcEdR)Nwq3pSk^9J zi}KyO!N}arRi4!b)_DI>6RiNNVda_vw}#t$B`HW zCWpPAhih-1I8qkSYtZYbc$x1<_h};^*<1u;1rhT=;1IUuWnVWc)k~A6L%OeKH!BfX zeFiWz2P}-vBSsq>)3q!CT6Gx??s?NFH_spg)~O`9dX20h)9UW{MB~eNlEX=!8|sK$ zBfgyAWOQ`MuNqa=nu}%(eD+F_o?Z4IBGY_+d=aO2isJ>)06Rd$zl+X9 zm8{~o{cZ=T*n2y_Q;r@)S(uSnV(PZ>6K9!~LtLKix6l(k^CB*)BZ`{2-5OfR!IQM_ z1ueLKml;yW=doE;ZCC*($Cgz{I8(`NM_fl6T*3YrWPqvXgXJ8e1_CEmI;UzYnUqUo^dJ~x)( zZB}bhkK~=zdOvAUiE>-dg`JOE$kc*lurjLY#;XNe{++h4Vq2q;&&DDxei@~$QyCU8 z4h{}+S0ic+)myQ&VATv5a~)q^Xe|<4`(n{sy_`(B*3;!El>vluXJPPY2!aP4HmPjr zCBRo-9!?qt0cHi9<1~s(;3R*el+Z6f5wZt&6|ijDyB(DOPkKq7@Qlbj@U2z~0zndZ z#4gr4;w^9f-CSz6y8-!-lFH$_@zaESOSOq{hgGt7LAfORaTe=5b2vEp)Amq|wRCC} zQsp*ihgt}A_HeJPAHxj5F_u~f30t8JxTV}&qJgxPB_v9d*lE~BQd?j=cA@*-o#=9^ zljOG*fDTptPG*upz()G*_wn(g1)9b1oStGZdc4BNY&KheT$0Ep*{{@2vP- zVmzJbOZA4FNy_mj6Ip8TjOE&rg;VA4-vnuwcP7)uAo$^hedbAF5I1-tLL2~0`I4zA z;TgTiU7P;8=?`FyM_GV0hB{MWwitfGlfoNC+*pQt2Qy8o1YNz7(T#8dqtPX>nuGs{Bt1j)(+81ragY^dmK$-d?O2UTM& zaJ7L5MeRVs3@{Qvrz*c@c>()dad&@u?J=s#tXvzcK@`tc+E^mxcBJ^n9hBB+ky$KR zVHedZO~Lr7R89a3#2YjD-^I5xEUrY_BBCGVwm2J2+X-WS-7P5{AYZ?M>QYoExV)68Xpj@; zm~vTvpx7q?yF$+L3zMq-3-{^sj6Ip1^}M27`eWN191VSD5)e=)C6l)|k?r@Zvv^pi z)z)$iW`hPpOrKQwh5QQ^jWPlErrosPij|{KyvJ%JGjkO(4oHzK;3;EMo%;no%8Y*s zRsZb6qk0xnT(0iSo~joVGtzkLo$Gg(;QY63x^U!8W5}clWl!kmBj&IP^uDBfFjvRa zb$ILjrP{6CsaGEW$mSDFt0&)4aV-<9`Jol$8J|le-$O#13tnLHuD6JWNtwE_0igVH zxJMp=Jhj+~@{&p!jG2)INQ)Obv^Hz_qiqH*^EkaJjh2iR#C3GpDGQ|yY1^Lm$U4Lx zbE6@3rDkKwyzU-ElO;No5q`+N5P%%etZt+d$9sC=(#Rs8 z5K;U#3umo%>dy&ZcXtBG2>LlflOVuyH~Zk327DUyHX^cJ`c! zo`LzW({u}+Fupe>30apy>9HL`*i5U1XS-$%75EgK>PGhIZO+?}%`2|`zs<7%hu4lS zKiklwv1e@lME0E@4VOciv>A_uRhfA8>hft%X2-fZQ?!i2fK{Z2Fp=M}Er?$cItl9h z0i;MZmno~)&j-C5&<$F?;9+&7zXU9{>X3{sq9>lU@UIr#yQ0PGmWKcX^BEPPcBh2j?q$I&W~5lF)o(ZgU~tbzI>uHQra2G6vfG(bOTO9y-jK=<(x{0j6}s>1&^jE} z+b7jY2o9m4s_n+7k13?8hQ(zr={0ZVIw8eQ@6a`Pm_O|uP&yLQmcr!%lAX2qbFdzJ zaoLT^&0*uU+q=pjzy-@;|US`uIdj0TNw+y~U5h#?7H z`j#MWINCUo5bQ}oY2|!`(0tvjnsNl1X&|>2D>$K}J|D-W4yBj0Mc!&zGo$#<)QGqw z7?(;{egGM3k{0Tpa?N8-gW;&7OUay<&LOh8i08~w99#S`VCb6KV+nAp!AcY)!as>a zg8VQ|?&JMxe9ruiEXB)wV~Lk=9lcWqCtY_Z!4eH|S~teD2^qRMu`(wbmj-)xjm=m*))GjEdM zzTfkh^`c(MtQu2N^K@#A+hd02RB1|iASf?Uku;SA!Qpa6{-=;LK{Q;9osx#* zT$xku$ZS@`(c}?qGD}z2Al9iL2_S{fVgarV=Bv9B>?W}HAwb)m7>>zCrbuqjzAO4I2>oY3jpHwCXO~g!CszK@Cm$-rkebB zt?C~N%KKNQ32f*gJS0Y%!IF}ac{@e(ZWjsls`8pVG0^}T4cb3Gi7y#sh9O&wsFO*~ z0tbQxxG`;~&-uVT1^VeH8&F&bJ7RDfk&;#cbu36oQI(+*Yg@KcA1690QggGgCP9=l z+cYOWTzbeWUTwxyr}CV${1PQ0Dqcyh9k8IR%(wfbcAx-}GFzrr``=9#J&O1d zp=)q8==e%{PEKKCU40ntt^LIW+v36r!ar-AEz0Bo^;}Skk2VcXzuvRwCX+z1aER%gf*rt1T z5VW~%qRtKqDHcwEHi9t){YL?9nsJ-58&=&3Z7sZPTue=H5{2m~#t2OV&yKkk3d_8S zrS$~m-XB^q%7NOpWATmyneZNV3h`kHO#hp<3@eca44+hP%os+wN$j;txZ$Uo2@lvL zU8%;|S4|BGXQ(_#{X#onp3@{nlg=8M|^CHYYQ zlY6Nw>+CQ$sNSat@j8%^2~wu&w8A#GenHrbwz<}DfrO7dm76n|QLqHo^n=}?P4#Bt zIN-Tx?)t-x*5%fcUPB?f%xwa^wNi->tI8dW@}wYDUhCzS3Df@3Xz-6BQeT6dShpL> zJe$VlG#tU%M}RAIR40OQt!LpV>1}43=2N<*(VJmwvs}<6g0h-mN&6=}L$>eXEEBiY zIj&(cm8xT^6ny7#sVbPXy7y|PbR8{%$s9>NY?5GMG>c!71F5|PweSo_U&5LEJ!gf| zTm23sTay4cLWMGtzH5aOeD-HyV73UyN9mVtu7v2Fiikuh{x5#i@BOaLaO~HQ!4k8k zLMN#Mni;d}Ii%cUwrX>$E>Ii9M|m+o0Eu5%HyBtZ?$L2uw@8{Ci)FocT|bMILT!)n{lBOW4Kj zKLAi#PpEJ0n>cECsJhhV7ad2#LQVTqNt@)1q(Yyjx)3*nY};;D>}ahkl8MA$a8PrU z+8&mvofy|Pml!i7K?$Oz5_pPu3v&@foD~0yKVEU`k0i%)k`-Whqbwhzm?jiR&q)!| z63-X)kIc+0sD@xG9pS%C2L5dX649_@p@akLi04dpq-#8rf5*}Ew|X^C@jidbeVASc z80RF3*%u-yArFHD^-UIx0H4}HsSHb7F#0u$d2{K|nVv!WZA*M4)bBY6G+4RRf@+d? z9(M~j->PK>dT3cva@!vlhgd$xwEsMcL`J&qB*q@1Ha54t_R}pSoYJr{C$hLt;d%jF z38Hcxp3UCt&|paZE3==)HU|%t)3s5N!47B5!)~d{`%7IHwe=_kYd16s9-IXF?Fkv< z_i^pkXn_-|jw;Gs&q>*y^on4kDD?2oHCo-{!j1c<*Wk`dtU(S{<;jmu1^L0|sq@Sc z1-*?xo@j$|e0fj*>4+^ffaa+b&JeW4S~mqgKW9JU1#Pg+sJNuW?N`@n=H!cvNHaHG zFm&2_Hi369oieY_RCc!UyY6VbU_ z(lC#Fo_)q#RAQ0OYDFv9(*3>7lxd?M?spK`QuVEWTP?k6vn9YUsGYI`Uh?y3eSA%E zHI9IKKRG&973AF{F0`QC##kl$0`}{K#SC%K@Gf4IYl_GhP!qRXnt^oK`K@Y88%jJp z%+%UWp9$YVLoK1NSby<{5N{{Bh9EzVi>|_aZ%2AMoIBQwpI963T26CIHs3>ds$0{8 zbOv(E*9$$TwQ!KJKe%ber2#q7V=Y3MVha}|j6_*-esKEgRzbt;qF(aW{awvC0q=f) z@}=h~Dyp`pcnu}1|FG!dYwq4>Rq!S6UAgqMXOva&@-F+3M=dl?yNRyjAkOv#Tzkgv zIp*Ke!}1L9eHIh+pm4_sFBe}&(iI5mqwB)I?@IHqr%41G4KJ{SH~y?H$krEjU>oVl zoWz<#7YYw-)J>)8L%(}Y)Vp~)%T4q`7XiIdDXfw`txwP$2T~HukqT|> zRIK}QsLSAr0Fgx4l|mI=y}_Jc65;ms+#e47?BYsP;?G70r{^Ay)eRU{ZoA;e*>lsv_-)E)uT^0Z>nAG zi{2%|Z8Zbz^lK+L3m5T8dG9ICDRLhonTgdXC9?jct(99f*HRqfGb3XSJyIYtOqU4SIMz^_d8QhuOSHIAVcDM13SslqLjkdUnr%$g zorhI}nSjC8w;KWsm=h zb4Oiy_(mm%D)Zn=irkI!#7v6Q+lXTCugq?dZ~fm&9GDu5dQHXX7j9w)LKJ3~(B6z> zUmB@Gj3A?PYrgI78!+qg^Pa?O7adw!98_?8o^>GI$`yQM1+Ce2Ba0JrTl>L zjh2ZR7x8P78UoxLmQa!th;@^%qrT1q)U36zkg`CmC!&89J};&efn1PjYCthUOQs+6 zuuLqP<&)or_@vXbhCuZZrgfX`VLiU&wiS4rRLn1K-(%Vg?j2(b`w;vI1Ai7-y$}*ddwYXae`;9WH_h~_t@7kOdt~E9pY`)DcJF4E zns%0f_rcz>`0sr)Rp^0BT0DYA8VQB;?=K+^HBG<&O;%>zAc$)=S!Q%7EE#$uy{tay zoWzMI#mr>qGUrv#6EoWHrt4^Ez^V)vN=sU|XrRVbz}HKze!jr=&SdyF63E3vAABS> z#UE;Kzi5^fGsT^6xszJ;C_yqw;FMk@_}puXdd@f5?qeWNdbJ@Yl_K8>pabF>Pvw$)pF)>!Ac9lfhhf2&5IRnVE3GS+aazjizC% zb4k89jI9ePhjhRGQIMx_kYS4Sv`a)y9=@11FH^Y{<(-6KK)+{6dKLmFDxwupvOasA zOT)XDj;HImybS|4Ijws%f%BOQ$!TAZG$Biq@ae;g+%~-~6k_Vxki0yJJ3314To6ZN zN>A6z9C`MwiUn?*FekZE8ODc%qteeL`*=^9sGhe3&?<^YYWUJ3dr+i1&0b` zwd&ODO3sD8MOR$x0+#7$iKx=faAl zN3iv;uCkJcjB22CGDx9|uP<;{E?Of)Tcj0wn5YM)QVxVhwD*06 zV4#S&0efaU=%1wdBN->eD1j&C>&6GscbHL=BxbR;rH`SjL#!sI=@3z@N@{pOjcB%W zy;5KHkc|WwZ{wh-)VEj&y^Q0)1WnJ1hqAseS|>BGZAKTAFOD(qd{kvi7K?v4EP-+K zXXwu_pA6g6(S-XtKHm(qs88;?fodmLIpK4&j685tR4U*-0m`PV%vRWbVxOALzJen^ zruE&J1&3Ko)$lA8eWhw;8+#r)+`@)uTCmWtU?M@pprwY_Ru7=Yb#^Xpk`IpKJ3#(`T2);Gp|W2x(hNTT%6t>)Ye?q&u4cVATkON`H5f$HmMB&!6krb}~?vq2f;0;y@S8=V#e z1fsm(2vYb*)h7lEu}Z{N?dyiGlc>?xnqJS=tUy!f$gT>kWWNxZrcwxgRxDiRjf zaLX4S0SgVhCM@LpH?%Hj0GejUs=bZ5mDrlQ9>5+A8sCZZ%s|d{2P4VE4KV>!QcL6> zLs~XtVo&MS&X|NB;^#FoSo;QQvo|MiqDw-w?{$IHUEr*t8syX9W90+B$UsERk>K6> zidW&}M2$Ktbm9j6E$|_+?nbn*B*IEkS`D-RQl7e`(@{e($WN?i0}#5!-M z!vcr@cBWd+j{mvv>Bli1BPeb<+M2P%d*t2l-Ib9b78o+L1%@~zgh4+ah;b$dvy8CE z00>E5Anil5q$#~9&o}hgpMhF3QnlLfgR-=3_sa1-I?lfowgGbxF7&-vk4SmOB(hm<+Va;&9tv>K!I^f}tasOWO&G2i@^y)D-Ic_&7Tb05ms zj+JhROMPu4K(lhSiBzx*L+wjYfiAn6+&ZRN@?Po7%Od@gmebweMc=Dbr5?U*9% zzk`s|O=8eI;er5g>(fDF+Pqw@UFYnkB{gSb*VGA{2I#I=wNQU39mau1Qw9V}_{oj%(j21h7<-wCRg-Q09hS5IcT6s;9p&7P}72uX5SQ&-HLT{}qL zyFC3fNcw!fw70+3D{}Ek;EcyXl)*scnqzvb6hY#F`dyqxu1^C)FBAc%PXM8W#~Lnj zAjp|YPcq9`o#cI7U31r{Sn8?CZBj?(Q<=|ZGE5OL)jlKt@qPW9hU9dkATR&r3n_rk zexx)xJhf)^c8xJcroZJQHUyx9zc80f6 zCUmv(u0FZ&^nHw1{AL#gJ}{I|mJO%P-K6Qux-<4u_8$ldy29(i-MNJlM2}%PjtIV9 zke+|S+iAoUL-3~<2sw6`vQsHoLiwbrR#ESaLuD6IE{qD5T9&!D1OuOOcKZ<}=Y9~# z{v*QqVAQy3VOLD$&L%D;T3cw~a#jI9OMhod zaKz7Jd~)A=q6FS%8?OP5xw@$pt@vy^R;}ku9WS0C#qCpacu(?Hw}~96N-c5ZM5fpS zTS6fU4_lzqjb539W7LVbvytwc73YJBBzKnaJD!{HKw{NX|Nf%4h?d0Eyxz{aNNU4) z$JAF>30LI-g-DkT4;lMKKM9Kxlq>Ok zG=@~_!h`-SF&wsqTes%U`>JcpIfZ(md+_-{J_+ws4@lpgxRwnIZKmV?gvKdgu=a|= z@CQ9eZLp29X0Z=<67XRw(Dk%#se&EOiu`2mO^W9keG6fF10F?=rgf&UBA6mK8v=Vf%-)nKqP()5*|4pIa0lrjnz(mHVZ1H9ZEc&?Znp`_S9fa+{ zF_=~gZQ~*UdkWotgj1icW0!A9au3_Mdb$1HqUP#c!P~z+P zvC$~pMDMe=C1}A7QR=&h@SqIdbb7Um{=@P{r*@`9Lmq?=Hrd(^!%oj9dB7WbVL=iI z;<(Wc&+~ohvs~usOP7u`^~gJZ?RYtV?0%+2uM%yuOBzs9)Ik5GK2s4IZ-l)AB)$Ip zuJmx=*sl#sl@@F*_e3J*U~lqt_pVDA?8ofb#=J%j0p@atW0!Ep3p9S6WO#kwU=_^!;Dmf3~6W{r*j4czRG9P)7e2bfKz zuwWWGUSp{J9%=`4(Nq$BHx05=2!;tu!kEyxXTre=fL2PZ3clpOVJwMa^tN(^X@`T^ z01raJy_C!nn(wC-4h2K{`SXb|DzG%D=VZJFYLh4(>8%J%Y@Le9CIThvh(qwS4{=Bq zxMyOy@Jqjf!x#i3_J=X^4~Gi%+Q6#tcM496d6dLN%>qnKlFcFHI^`P)KJvSbN>k-EbV$0V{=C#Co}|JXpi;t8N|sC)*h3c56mJ?liSD{*xFiFm+q z4AVH2jSLXdxmJNEGYJcte(oN!K7Hh62)zEkPm30@G0*`6zpNU|z+$6VvbnRH+_ET> z*S&w$B`Z^%yt~mfxEGK|8k&a{iljWqR37Vgo62=Aax~>5)!d)h{W|!S`U)dAd28DM zFWe@`RF`6W4Rq1!kqp`XS$U@q0|-{d?i6WhzHRqU1fr-59-SF?Go2DdkAHRlY_v%v z4Weppr%@}V5qJL6`tNlrLgHua4l(@%3kW(32!?IO9HUjjZ8ECjbpGSsoj)-cMz&I} zJ)7eQ#-uUxdEprr6aboX0;fHA9+O#bC?d*qC0G876=Ff|BY{xX zRt#5(TB^tv3Eh=yG(wV`IuW@9lwCih4G%b7$AIp7?rCklFaej(~V9ES4zvs2Fi#>($ z@jKp+zbA-6_bf?==D3uq!FXGsfnf#seqqvdF*GCsgoC z^n}727|&E1qvu~IredI55D*&zN|TS1be~L-C*B@Jim3FvM#!h3FFXRAtWh5aai^cG z`AL@BTsLEDJsF|)L1)o?sIUjFvPZB7VJ;VHoPQvE`wE?gC_H_#9L=Rb_%Vqpn^EvZ z*Ib6$mr4lWv>n0^3tv@+1%)#U-@fZJ022JmEu9x3J7MYTI5V{oeg%=)wPs9#c;$jy ze4f9qMj9K5tvYhDsOcfFFU~u;Yb+!)uwX*MQfBF2h z9>MAVTo50>a!ahDRD#%+7ra)wr9MCYmF_rZXxKs;%Aad;B)8+;hESiE?BNjr#yL^8 z8j6*Ebi!jw$lfY%_fLm?ZBDTkPEKv9i{*H%1)cUgLqtye!0yFK0_)FWZ@9@*!()5~ z8DH1Xho=t%^MstS$9QE0?D1ScddVOU7H01=yIN&j3FOK$17x*29ZlF{bf8trL)$Xv z8A#4<(HrUjPUKb|H84}$PBMI0r5#`ia+S`5pOaG0`RmX_FC+t_-LxMafj`VFX}`Gh zD~9kKSIr1*FXJ)%GM@PEzAB3CMY>^(Ano~jiR$E64uY5=b7I3ApZxXIrQP@G1`@W=9$gBQuO3aS7fA-`mk3ydo&pj4ot&1u@KFr5#z4%=dz0PnAJ7{# zPc9sNoa[@R1U;UJrM(;HVK*Zk1s`iYK8NFsc7yYh)Fxar5{=Ror2$}CHz!GPfW6lwk3RlCjomt?y?0<&g(_Ydb#~s zvzP29xaK6-ic_|hBoQU^(Hw_Vx;EFDg%*%wENMBru68DUhslG58BMdYO9?-ylBNUF z&Z{tno^GLSg(?Tv_Ili$x09Ohum-*GcEqJklYc7kpaypw*UP7J_hvAPUTPojMRd}D zz#UyxaiR~1wg3R5<>Pj0tfE{CD`w|}6vjhlDJRqcmc!P9qOvr*y>GD4j0QX`$VA^f z0llZnEwuHnveg*{($k^_qn2!r5X;MRNA5*@lGKKzjdH%sQx#DX36bHa0wx=Nr?NaS zql~S~ml%w%wj$gJ4{BK|9)+nycW`{IuG=)S4f+g zloyNCB5va4yRt{&~^TTDQdQ=8+Qs^gDOyR#W?wmX;dAb%keq|F-CSjhryE zh7mn}11j#fBkbr|*>VD5c~>C{hekGct-c5>8UkPZZ1QwxeEE^9)ZODA+ze|=*DJ6yj^TOSaR)z!2go$=S{xqCUl z5kcjf;$Nu|mUhMDV+5t!)R>|b5EqA?li%76`Zdqf))RQ0rhT?Y#d^ea{9kG4#yUC0 zZ*f3#)x_Jqj9;B<$jmh_;yyu~=VE=-?2fGS6uG93Pzw;7D+;keE&CM^BSyGP!nWP5JDsY^lLC321ODic5Ge;|Ug+YrjTU0ULdVpJB@9$K8O+wLp3|~A zT-g0G@G}I~OLOL;2bO}j7aW7?$&+!&|DjIsYcE1PgNvCp?n4=0R>FMt-y!Kee;Ad_ zvjchB<-Fic^Bh^e*uj)Em1!b*_Vhmu^Mn=hMVMY@Dapoku=Z!j4f4ETkFxF=thcBd z=nBY;RvXiLn>1{lS6S<3ay)9$GgPiz$MP#udl*dp@h%S=UO+tLCyPfA3V~`YH^Io% z@O>z9XL7Hjq(qi#4PEA#zEA+%ZiJbZ-7t3Xi`nVYcmQM!j&we%O>YjP{nO%-z(w!s z`POhS~_q`cIwt^Eq)5>xahK?bl{cTW(7tx zyCvO->EZ{ES=M6-TChW8IGsiARePlp@Cx!)`j#K%stW>SQ#8&I*){}#q#9_Hk?KZa zuA9HmD-kcpGHU&T6DggM#RbMeJ0M&*hszYqlO8F^OgO@&|TI@tJYMkJ8g#bIfZ^vU&6#P4` zG>59~8$i#j!AV67>A7ksG-kt^AIR^M zdFPp`-_k^sX{CkWZzXvly->a7nJ#-yu@q6kT(v;j%~_Oh zy>x~O7um})8!g&a^HneOwdwKdlrumvD!v&=V^!>3qcD3Qm+*~ubi8cW@|U5W!>MqZ zq=-VMRt1Ydy{3a(8@@a1+x5|~%dSA6AR9DRiB;HU+s=OF3pn*2muaNW7cei5Sr#TAydw*>mLz!Nj zccIxhz2G>ROcr~LH+T2RqFBo6oZXsYP31;_tWEcs}mk9eKz^7US zOtY(R&BDuiahQYr$84@qTS;72}VmIVh8xKFS4QAoU zC>y<$=&}lb9FL7R0ut>%Ey(0={qmDj)*nNC=k~xI)3K_QX{84r6pgXO86SJwau!Fz z&x`|e?i9R_L_GfIiGrdCicM}Ij}=#xTcIWlTq+5&G;a;CL5(#*6!07z50ix=@klAl z;%VP1#P5#{E!sm)yFzgq69_4B&z3!7)~imGuTyM4%Qk6Q-e^Tb7&|Tb%IOj40L(hB zKfdTaZGSN*3)1GJzbolbO3VevjOAWgz0Bj1J`(t%=bBb>Ilk1%#ogR;%dsau{qUEw zMw&zYKat#;hTx2|Y!rSq==FEJ!w^K!YSVu!tgp57KC4{s7^hu`T0 zny#r*d5ZZ3JAo|*^)da^Exp0Ygpn{i@)qRTfZLOsFJb9@JpCdj+|D#wcW>fiJli7P ze~?>rj3!SR<~k*n5*k*18aMi}Jm6%tLtTZ+0`-bAd4-{PpccR}9qwp6^EK;nL{_!> zu-c(rNk;?ARH17YetnV+rV%nH+}zC$v6mB%*t|QFVQeRrke)(Ne0BEG2X^Xhfx|L} z=~@p?W0=JJoDPYFY@G!v%nwzbrZwB%8m-}Z_|R%=rywa|!i5|enE&1ddDwDTZs&3p z`g_EIi%gfyz|c)}+oWWpiPGnvJ9C}-LjA|=&>ry$EU)VB`uhRBeaXFd613N5MVrI>O<&w$kWS% zd3B*8G}~XTFarOhxt+eQmOR+@boWY8*mS(2e0TyqqUQvd6Ya?rD(ojA%VP*wz-(gw z5+~V*41wT0Mdr@a=oifgl?!rC6^EDW_CZTk@<>+&kti5=;B4W_(w=-uFPvn$gTY8s ztvl~#1yLDx!fvRY)IO_TAa8}NUUbTy)h^c@;e*h*bMBfzHC)_z+qtl^2m;YRlG=1Q zf!@^-HJdEyB(g#UiFklyy$<+A$8E5{UQ|NEQ~=3Lz$6B*to0ue(gNnMeOj|di5Gx| z072)PpYy7MDsI`XpBTA?Up!cIkITOhPBvmMV?0=Io053XBt5RN?cE?5x|FZE8yV?_ zX_2ROoXqN0rbhHgod-kh`}29YBM~~T7t!ImfU7_{%J|el(vOdyGm;P?*R52V({>6G z4fpG>H^%5F_?%2HtZ_ofw{dzZ1HPmFAXai-e6UN>IK%I8RCaJOH0z@dB5_dU)B+SB z$d+vaRafacrL}EBq-zv{tIw3g2$Fw?v#O`ttZHd z3VM`_Y`{qCVg*QRNA8s!KxdtQ9)4cop}Y%;T`hc&Um(2nwoX=q$Az!<+(m4kD3YAA zUdH@J2cz_;;G);kl{vd5sE#J9(`RGPTuU1LNZ|den1y#_sH=1!X%!H1fllwd_}WANk2zlyHV6xJM5JT zb-kFhBmi>pvcp^A2twG*k_i%M?y1D*L>li8Jf{s$j3m6OFL&Thg&Z_N;6$A6ZbE4c zd4t{pUGv#WpFxk?GP_!z#C?6N{UPyF!T{3j(dnfSJpCF|9hubf@V-1C4`hhxr|(HS zU?}}`{S|_tP(bWhCI!vn^1i^wN#U{bjv+ynRVoLm^hP7~sJ2~30>&Ft{c1GaU{#eS zrkS*O75FWX(xBn|IitExd&I=>4ltwe&zKCqBx$aZ=UzVts(PSSTY%Q?5p=y#PeqcF zrDAtdEA-4ywm?Yc%7ZT@YS0Gj*IpJC+GoG95*LYdf8vCm^wY6&a9&;wNVo5b>e`^h zFuH1E$&#}5_~uAg{!WjQ?&lex3tOQ}99vJcK>S!feYuLaeJWukQY%>15*!_%G9Gr} zEe_qeuqm;$iOSq}NP+`V4&=NoVh^8Rf0HJjBnEzFWi|5EqJM>8tjq<77dekW$kvIC zR4V8{(MCm8o8Pq2TyrTlu=4$l;>_MU)Co-6V&0nUIxGwo1@)gg8H1`9wOKZXtp$}s zb@*HEPXJZAqX7uXq(F@k1XUNMl-;fYPP6_?vteRQI@U|yYD(y~&ra#w<}1-V`G0Ki zEx4(IRXg7Nj)E6qH?sV`PnM%$BB9RqKZ1PiG|@xzxjY^K!d#!BdY>((&Yi;nj`s7R z{gIn&LAJwH*`=W}cp{i19yz(1APSE4vjTA` z&1he%7WS9Q%VlgZRKFy0kW1+L_yN7DSU0jpwCfe1_3CE1_eL<@&>BxU0m=>e)&WB3 zSa+QNs2@;Lg{GAaB@cp}8;~KE6?4F7x20+lDWw>hzUmtc>!y&umn^M&01zLg4ZA;J z46~Z}DT&~dBQ3vGsr2R`Si(t0*NmLP!BXv+8Fs%%)-~JWPD?ppUXCE?HBF??8JLY5 z9;{=F`7BT}#cKKSc_`>hlosswl2&QUsdHjv2?uxIB`#88jl8@U()Y(GC&8mu>2LLp zw#6O$mfKMtFbyIxx9;t!UMmb%%{nbI#JPiuPHTZkGEw@*4Ftt>)vBP9#(>E#`=;e< z=}v8=au+Yz`pr+=sR?TJ;8Z1mc^jyZ(6X~%<-*=Swpzym5%Vjcl zv)n&;jH**gP<4Oun?ho(upS?EtaE4d)$aK0mhuL*2w`H=rhASpudp-TwX*Sihp>1r%!EsT(5H5=6szjF5;X{$Oh-Y9CvpQQ%m}O2GunR3XvZ*yGOByo6-|S7 z{4MYq`&5Hn;sY>uE1Zf7RTz(IX=iTvjUh)|>K&Evr2=hrqVO9Uk=)^dE{j{6Qnj8W ze+ubOIPdcOddbf({Ig&Gh6RK8Ld7&WS(;(U~Ei!HdA4GdAIu64=5x>?_`$3T>QN6UfqZJRXu7B zx61---3hnKb{E|(aFA`nB^=~pil`yoirtj3#s?6?K{q8>uWn5i?hWt^W^|6Dyo^=_ z4d6mf9&nYiYeK=s1r;_T<89LSu;B)E=~r)UMgknJnS5Xq`j8SBvHaF+S;f|i3e>9I z7j;VWSUihD>pAn9*&F*nuB-3QmT{F$YU&%U%usk!z}+kBSv>jJMYw?os{HJdUP!Yg^Rgpjd006h4AqS*#w4@C2DigP6mzI*LlRs$d7s&OC!tJIfhrGk_4xJBE&c|2aTA8`)gUcic|>8|h}$ z=Vm<#SBPIQUw3ma&MI1F8}Q-*Yxj_(?2#){yR3Ey$$`%z!XFr(m&EycJUXufDJ(eC_X8()3yq}Z8NvY zAnXOtz-KZ*05d?$zaUEtmbP4lY*ps_lZV7=VC0ogNs;rb*mZ8tmz{1wtkmyo0u?o2 zWLfdR^12$J*e!vsczz^>M_`J5QaYn4JIX&eoQv97Q9Zs64*)Aurs+LX64uN9*;&6p z+X2Ud2j4R?Oblpk7Qhing(pY}X?4=VrJpC`&hn4rHrlm`9nUcr$ERsJQRIE&^|2A{ zm3Sz(1}juwdnFBXbl&w_cA`(lONN11wT;V?)kuZtRcE~e3fNsmIDITaX2QQ0GzjhE zOTfej#LUraEOUNe*braUdi*5J24W@~P32A!DwxS~t<(nUe*p>m)Ih>LSgKxVTjH6I zQ~UHrx9Ketmb3UDp*`LU6-67qBp#YMVCaUNU*<3D9socA&-|6B{m=KqG@;B4tJ4!~ zgh6Qrvqei?lNZsCB;}Wx`okA5!kbtw#;bhi;K#j}MkHfVol(N%Z&SVgnCuoqA$TXIrAfiR~O zpwkqVnFGdt6!`I4Z>u?cD8@o079=Y7&C z7B#M*ne9Za`)i$eCb;DEpJm?|c08mNTC%hLVfAqQ4w>HMy4bQS-i1>FQd?Q^|m9pNlAkn1f`B)hlZ!HmR&Bhaq= z+L(H=aW*4j4{F#Ww(Of`5lk;WnYof%Ibe3*rvW^3?_1N)yZ!i+{Qs3tbWO&T8ax-c zho~0Ze}~+6*qAW@H_*&b+b}d85=UXy0nme+^go~Y2r5jDpo~5$i86xZp_ZUuh)dzI z8UqH#^GWl1c+^hSTBm9#V^|Y|>4+K-fO@0vm*(n$pk|ImP<}00K zA}#@ZT=zJ21i|0g-Hb%L3{OWZXQ_{iaL+TbGjl=a@cWIua;@_a>U&sKf(f?2ER8gx zHcFO!T!q(5#SovCS7jCt3Ep_Uq2C%y&t=5rRw2L_3a*df5CcJsY%h(!>tG(st}$-{ zioS?GId<-=t87AZ219U>9j>oiMKV04vTmaYpv^uK{cSt-hRg^HUn7X&v+@F@tY2UL zGTerT5tk!NRQKsTLFRCCXJjD|!h_h#>b4|lZZw3Sn@pkSq~>K(mf$NgFB*&9m9Z23 z(DKKQ(!E@dyn7-JrK>@igAYFL?DUk5W3bjH3wG`;!Y4KFQFBM|;_@)(Ps3fdDG$He zcqizjtPO^}AkWGvI(n@QF?m2y0Hps6NalQ88n}P-AyX(NpENS64o%QepCf@aBzvO+ zt7ePcOEqVFx-FEYGSh;U*p(LMbag%44futA;c;H=Mh&`u2g2KUwzD;s({dMke0T#X zU7Oo}ptY>pVluYt3w#PBtn=#z%`ntqYU+paN^)4B@S$eNzMk}4$XElF(HHgDiVWu1 zRwJ5wDdA3wnoREerRKV4@mk7%1chV8SX11w-+Xuv@M#fUxo<*)VBW}~mV$(3Kc)gK zSp%26Vp+n6mRMFY!B)I_`xU-#)jLt(Y3xNhq)9O;&y=e*#n~$NZb0*a_BpJ|Yc?4r29(F}2p{vj=;Uus3kYW*QDyFaBH4K~ zpg(fH^tvm>7NX0{9>hQOsL2#N)2|aNFBd3&_eKyMXe^QZzAo8mk8Q16XTfv$z z^69*N#misF0~#8?y*ix=7B9ugcR7Ci4u`>w7G~q|g^zH_{YW>QzN$iL-vp?r>g>{7 zq(7_LkQX^nE|&QB@?R>g_)!6H;Yjz`P?X?9kTI#}6UrnHh{d**25tOQ4d^N^D z3+rBg)YT)*i4UGs?>_bYRgSB{aQI<_*>UqmYr>D~KK3W*?cj)}2kb7>ZuK>;g~R3& z9qvE_&yw>JMz}f`{rkbdX>d|b>etFa{PNU_{apKit(G{foQ!$T$w+%wY{YDS;tR(u!?YJ&b>Ja!_v{rqRPX84ogIUO!~M9QyH6 zL&c{{epzU6S)rweF*boKKIxuvKH6b0u`e5;x>R3E6ZU1`xy6UeB)PbsxMieCoTIh% z+@2Gx`600t6cLV-KA#>?!ci&yV4=4Ex+2q&FCzB`~%#Rn20)LR{*7*Zp>LmjUV|v-_1^k9qe*A$^5{u6NiG{ z9)w}oswY^|&N+Su$uD9ASsk!ukyMkL!V>U?HyHUHqn|?w3jC17r;N%_=iobAPM>?h zi9vS=ej;^|!qy7q2hd1+Gkh{VM1JV@>X5$x6srEz=b+l(QEdU~+2^0*UzutWmJ{CH zC&afM-2gX9E}rCV$A>c0sWxEo3DauEtczNDsMx{M ztFqo$xTD+X4@P)_kdg$0T;8fcV$)ugO@zf0_`!EUIUmHaQ2Q-eoz9?Yp}Uyw4hxy} z<~s9(pLV#wPN&TNMsE3ueC}J{hPupm+@eJ6 zn&n)LfnuI#FMx25S!Xn;4d$1FJQ$u#Tz7eW25`%%QOkxAV#5Krix}CthQ5!!5Qym% zI%}T3LaE{--zTw->>Lc?1%A22LudXy16j%)M*zl~5LHM6Ocyauvs)fgu5k1c@g?AO z?J{CN5O z(*eW}!O7j{*5f;!JkS(HpqK6pKZe#zElV(3JyGn;gKM-Blk7dh++d#5_DOOjmiaL% zWF#La6}6S8hpWRe`?&hllAbPW>2y2(ZAeE;CE4TX2V4w0v=h58r8dMXsc2p^`_v@R z29&J*Ls}K7;h-u%Qt?Y@`X*JEGlpyI&!<#@msd8O>=4U=Apx)Bj*VCnoA4`N_mZu8 zm9WdeRk1D$zEDLv6#q(ZhfX&}pI?8W3wiJ=Im=NS+{~W=L?mhvQ`J6uD(wZNVgr zJFlAx70J%&a$vf_{t*33i^|7SB*n2<_ZOZUfJ4Mo2(2C4_pIEp)gq8ER&Y|-y2han zi7tjge3(lkSZsQ>;DHpMX2}7i5NPdQ;ea@VK18iTjmH!jbXB)`93VGClaD z4N@eZjMi>9GAI^_y|^9JOBvq*e9pYwH1b6djn20cEu$9}+9!kuvar5D7DLjAt>e;~ zSE8_zG1zh6Ha%9$zfa-2>Af6E9q|L9+wV+9%oDl^(uZ81gaYl40F8Rz%mO4 zbQRr!(>GkLEgPL)FBL&?*?V+?ZU!CVp0S&i^oP!KD|~qe8GIb}3s<`n^R~;8BdsfAzl=_|^kh z?;8?_n5>STOK;%kn2$;GTD6%?ZW)R`s5S<^|Em%sB(fET4R?kLdnNw32}Kgg|Mv;E z0hm$`b+`Y!qwCEZ?Mb#-e#txq4Yq98iQ-|MOI%a5d?jW9`oaH32qq%Alh!g-x0=zN zb`Bcp>hZ|`q0XD2E&7v`BC{{_J^}33rrS+P8&!F9K@fA(+f;dQ-Vku>i|HubpUo_a zxmWKVyO4uxHDqkzzqlLrJ6Whap)8?< zrW?`blGhei+NlxGGB7U_XOY~nx;Be>9e0i#=>{zG+^NF09$#Kg3~{K=o*iJ>JSL>$ zN+IL~_GzR=7Z)dt6oAtJIjVc{7j2VqQolPxtjN@{!ea6KXvj1jHeU}xnCRJjq@{Nc zTDG;6rY4GGUc4H7u{B`Oq^(}vL6X@r0_#^i9+wJ!u^M}QF$1a<$~E6OZJw%clBkoI ziCGHlDiM+`-y?muFfd+tDxX3(@>H>=m4W1i>bBWE+E=b6Hb&lwop*lLDq~Zt7xZOY zRd)sK{&wdjzuVJ=(Mh0}^aZPZ6fqh-8`1$?9E z!YqevDUgL}KrfIGCm_mALX^_@D?0yh8DpOVB{TyE*W>IzHr{Ie{@?X7%Csd*Ol7nW7^P|Gq0sR{Oq~o_a zZo%PbsTu>JGJb+T`?Nuu7?5Nw3~nEHqiW>BnGuMPg$VtA$|oC6ZjQa;P^oLHmWfVCueH^m@x#QS&eOL>FOD?$iZ|D%C5z` zsDnimO`%nWymB<|jxbo53`g3I1AJi+CeHXuROJM`bYiy{2J;F0AHCFT65SALqf%jY zPuGV_(q?6EY;$=Hs?)_^L<3Bcg$$39IsQeL1_WfY&iSMsTqf}*v^Qg~Jp%a^ubv^E z5RV{QA8&keBxcS|$2p;TFgM`N{8u$wDU%(!QFD=V#%gtYIoM(eK%B1N$mR*UP4D5J z#3vlkb6dPjI`q9>a(@_9hk{!UbyEV>lXMwgpIuG0Ei*G1qK&Zov6DgOa>9ENoB}Nb zuU#UgM_Y~_+tSAlt%0oWp}*BDP0>3B0{C0 zgpJa-hW_`#1M3$qn#)+bK&v$|+x>2d{l-ttR-!slPlKwDUce_8E_4QJ4#^ zaun4jKe&!qvAPQ3Xj!;?0>qghoZ<~VAt2ISU%o@+!G36@kZL*GNxEZDd2}R5u8Qz> zG7ia?)9}LY4Ra0#E)nS-ePMMOhsV2>Ej03IokXLnsRdiS4xp@h4l=5>CXk z_Kmmx8rC$6JQ^t46{m+co)y)5zSi6a#@@)9$!->!RRp_*o3!aE!r<6R3Ni8m03sq3 zJ0Qt`Y{6WXb6d(^e!E1G5w=j##z>Z#&a>igP-Db*)`Tk+H3Rsa<_Gq0X0u%2{#vM3 zN=-dh*cj#Gqt!n~kkkGiym%kE64<;)IrCF|8=*(sKjO=chsdhKw2P?O;B<=kTa}K{ z=$Q|&b5-chvW!JEh(^>-^&_%3m&@69Q$eThh`A{DDJ%m{*iqcqC#qJnbFOyJtk5^7 zvZ?T$Wfs`Hi@j7(S{CrRMpx?}F&MD%sbk6^EtrNQx5RShqS(U8yHkHa*8Zo{)~xp$ z%L8-esb6x8y-L7w6$|Zol(y$@CT_0JzbdAhdeY!}6A%V%Vn3jX-UhiUu{Lm_4LQl_ z6y#R*h}DThO2Iu+hC`uLma|A5>A{5Ys?Zzgejh}M>*IZSYOzYAa&SJNJ;*p`mwYO^ zYZ)vBL9BfU7TG3kJ-7WuIpvUU-MSZ5)znCJ*nLnFJRM>n$%44FIrs zEurYs<|+0-(rhSX?|6S(*NCQ7`z4}U6yfP&%7^Kf5)1WJ zhC16wAzSafde4P?Dd{!sm`E3QyGu;3YjB1#N4H8p`DH`OYyPU`EIylwf9q`r?AfMV zsh~aBt^CtpXk2gm5nuk{6u$NVJk+J#M6Y^eaOHC$tY>LK;$fB*pKl_skEGORycSNf5m4*)| z7SS8S0+otl5avywg`UJ5M|v~)6HK7$X4J0QP8J?N%FpwXKK8?)-ZxdNug}?z^TjYh zr7e6}o}ra<1@r?G6G}O_!Lz_01wgOJuNLIwbdjY=C`F3V^I@dq=c|tX*RiUCmK?m% zj+HSlRu=62FP_S|h9~Ilk|^GRMzaucx?#^gE`*%&Aw+!VVK@<2f-)Zdt-b1Z>`#dq zUgyU$Si>Fyvj&`|k4^Jy2M$i(IY;`icAyu4aAy7!(cCf{l1ICNIIe2miB~AU1@GhnLR$&=-so3x&WF9pM!>z8zjPAmw<+e?AEM3 z74j*2^ePNYqV#0M$A=d}do$~Rq7MZ0rZw1!fE>$iA^(Jtp*I750=Am+z z0n>@e7eHBDGph2@z(@w8$p3ItP~J)#z|<2=8Wby8{lvC>sCzntoBl3O)Qy)o=G8YmW$AJk4$dx0rw#vX< zlq}cmw{YbP4^~Ji*TFG|(Bgh=#-GN7yI-z(>=wU_@Y8)$Uxi}0l>f99c>r=+O2x2xVd z%g23qYRcSM3qJTsb=(z@u+BO$(3hw7VlgZdI!Wb4+*?C{@1Y)JR_SzCB>nLLL^oF4 zJ@UMCv?G)vaQ~v4NiMU^kY@o{OmEqp@>~$V~6L{4r&*eP~&wuO%xRYiLCSN zf!B^TCU25ywbluWtm=cJ(!!ZX28}1zkuwzga)8P{Jp{!mRdqSk-OBh8vJ^_#DDrow z-bt2+>=VkrukVI~3D;-pqh;lN+#-33%dwIu96Po65n6d@_s$#U`GngZ-d(p^0#M0^ zr`Ro*mJe8^8$&*sna?*iH;UO8e&dX1Xuw@@iZp*Xbdvn|M~Ji_n~^J9jg)X+4kB43nDy zfDu4`>mwndqhg`7h^NKII&W$HJE3lJYy)ceB~0zs&q>m}Wo6^8E6f3Y6=$E-MboYb z-utJp*%e!grsbwcORsn;mIloufT5VyPdN%Y#w!mB8b$$OEnwvOnxk>q6?T*j=7tYQ zLJuVe+=E24d&gbkd4VB|D!)zb8wn&W%amg}zMz+yZAiQbF*VqT75*N*=`6!f9J+v;l;^W|XMhyNFA=R9wB1u#|RAmyZC2B_%=bj z(cf2)*y#?T=k#yYcy<`*H-ClnNu5Bdi5yqPP4{tVc#QvYTRT+PwYzp^0e8xL-EhD#W$ zG?|k516vrk#rV8$&ynC*w*QIQGKP34_WW$mmXN6#MS@dRD^OA5_#Z>L#amDV^VrTi z%fb5s9@U>lLxjKC`w!jyun)a~%orTN?sOp$Lnk5ig`ZDMKh+dYoE7*#Jf2%t;?t6Y z03*A1Ob0F>u(zG;_f6#1UKBQ(jZMH4yn8X2DDs1WXD)kG;FEQNRb*8-j+Y<_HNHac zwQ&Z(ZQ*d;#68zjKSK0_jj6q~+F%=ip>K;2aYa52u6dI-L|jUmFSC=SCql3V)(<(N zLx33##zWP|Mnw%r!KQVZgpw^zw}|xvGP?5?v?eK1!Ya9`@9}ta9tl8eOVmDN1p`sxdohvx4U|S2)z&vpX>q z^)JM}wt+`y&mU>WQ(F)`U8LD~#NO6(Oi1hy1yj43?fPa_bjzGz>O!*~b_XKpBgt`0 zxTBiw#rw^@6_Ldo9PQq1YLcdOH+-K!tcsVYT$wIUL7ggWEcmkd+fyj49|smK*`fu| z%LeIUCxhEASPxe01I*vXT(VFC+w&dsdB1svQ?Bsw5ob%|3zhHYX4gFkQsSP0F+P!O zkCq;+jdQ=V|dWyhfM$k{u9xVlYt+;!Y zt`ZY2+d3r@6~cA{%bR+w@+gaS?$i+Uo? z)D;zRKcT+$8u^8|KL-0I9a6qLqZiXtDR#sN*TTO~&p$g5v|52A`T>njPAtp~XFkJ~ zZBaBar(fV1$97w#oU@Os+0dtj3DmlT*NC#{0oaD1gTU~s?l)h6i&cu2ol{w?AEMOuf>6aJ~^&M0|T}&NQX@fq`DA9YdB+kACcm+x;aXprz}7C(rg1T;5|G#aC|V)-uD1Id>e}ua@^)k_lb~Or;v5%buYwLp>GI zSS+N$r~C)X>8)qpD^W3Puvwc>@2eKdS3sCEFyj$K)gmjgrfp(K0-QTtbgJ=XhDBs) zg%-J9@Q<_%Ks<`kocYXP-S^n~qam)$maw2GO6dqhGamEI_f>{(@U9jYEJlapL|!V? z08Lqo3)_~|cMzmI>OSJ_G^96Ky_}~R(`CIpfXez!s}Y?~vblnJY7GdPUSbHd7K2vD z-H&&-=i}88wzxCZ!Zd={q#1capZqZr$&rxGR2nowsCII-_^f|{_0AJ5f|ze9m4AcozR~~O;4|nTEp~7*NOr8I8m(6f$>25mRza|V_wflT=XIQ=hTq)0 z*pug%`ovNRVt9`U*XG3kR=d5_bj!7fJF41B==C)8RJ2)y-%HO2eub+2;w-G( z7h!n^O0EW&_y2||rlAVjy46nm1Lr(T!+222HCM)kf!{KIa$v>|T5C#I`nHN*=#^RL zpr@j)k2j**{d)Rf_ErJtq$5_&d3j5=Z5QfA-uQ%%iD;@Q$&ZbsOpm9E(TvaAd0D3T zJ!G>nH>>AYs5W|q<#jieP4+v6(VcRfT83L=+XsFLVY23?)l14Ko7`M;tVeflxx3a% zT~dB)25M`hE~N z{OyzoN`Dl-*oqev#P+K|W9DoTE=pwhZ`(8jS*NRb1sOBgvai07A?s&p!!S!Y_e0^B z2957ag1uT2Q_;*Qe9r112z0;bX9_0lu|+}Lmn}+pV-!EA+TE4tnVG0@4l{nz)h1ffk~BD0Y#rTnEwipfSQgDY)a8 z1|P+A#YdSGayEG4XmD%pe0cVV3C(#vtM9fTbonPGhNLEPkR+i;1He#_u0dsC7|0IC zdzybSN-Mw@A;=1UnXrKtM()?(s-A*H9?7-ah$r()vHVphggT3xJrvO9AH5Ny${{h+ z*m=E5ZBBuxYoRw+r|2I@G7^xRW!vW{&A5+^Mntru5)f7~5=Vd{pu)sds?8hrW_XRr zBSi*@aDv^a+MpPucTrEk!fahyk$i5+jf_FnRfx!@;6#E66Wb4JRn8^?ySoN3`w&5Uh?jQdzixp&Kn>koQdZBm=%W=u2|*L8v}m>BsDzhKs?s z_`W269`r0_e`aKQa&2uYm1qA07Oh)2bkIH27sq;loH)YpDg_YCOP2iuro{b=whZ^l zt&$<7<`3zralu6>c57(``dHvyIZ~I7`$F7p4I;$N^7js;$+yNR7v+Dedc&%e0W3;I zeGKskH}ZC#J8@?q_JPe&7^-lISd|5fwbxIwQ9oG}2Q&OmM?0(Z93^xS3TnA}%&W*R zAe#7M!hP=8N4>Ch?7fn;jmUsuRQ#ECR?(dRS1yywI>A>zVh2EX^gC!4RQ*}!f8Av9 z5Uv|jxL49Ab806JeiS{n2^pgkuILfdV%*Unvj#`&nP=bFXG5Pab(zg7yr3}GAD@R^ zCQcg{_j?ij`m$8}RN`(#w+!C0Z)a0PiVh;Zz4)@1l1TIq8bQ_z9TqeSgNyFr5*6mC zJxX&&)xZ>WeLRQ=YoV&I9#lOsz6r9m;~bH{GZvI&yI--amKz+iR8adI?$19G1`$g5EoU1n0E7kcWNVXzKmo&A?c=1&RKsgr1><_@Dv`XW z8dEJaZCNqCH)FbaJ7p8LvS5lf{hvYCo_VHIkz%L&dYoUJc@pnZI)GXdHC?{b>UNaJ zPS}V`l|H8QBz!nCa&NKRIIGZtQeO77L|RPMw(J;4pjNZsKQS%*!0$jB-#06g*8rlZZg3$bRQ~9>INQp zgx3FCIZjot(m^?jxloy$u`K_pxm+&rjm`+(CGd-ANpZuav?ni|<3$x`bAFyo*mcdq z$rwxtz+t$t^EPKUcl&&?G6lu^-(k0#v?GicOdSn7b60-yPm|lKPmMo@CLv* z-K$Lr`X?Ir%-uYBL1Yqp`WM;(LDd>J3l@GHRrs!_s5i2=vn^QwcW4s zdAgxDEZP>ZfKH4P{j#1`zox7x3HC27k=%3lDxVFS6wrNEAG$bD81p?)uJ*E!_LQ1U zHqEK(m~X#SKKx`cK~9GxF!1y=LD*BZz*pi2CYjBeo%!h+gV>&g+lkm8kE=+)4%2vU z4kvDP#mkFdu|MH+G-v$rP!NvHB^IM2)r9uNy5-86fBrJdq?1!cW1>fed<~#w#i6bRCUqMR0Y5| zJE(m608iR6zn_)3vsX1)f*E(;CMKpd)dj7QP?gv?`MqsQ?lcT5Ir~LMuB9nntq#3$ zzCK%fT-fl9rC&;Pb-PA;V|Hf-S0jkW2Dd>RjnNxL-D`|13s}JcS5ipK4S4JL0Kxcb zC{suqi9NikX$zhx5RxDu3CUToZ<_G^bCU*YqUWyk0JLeMl5ToDu>32_lvG`~mZx81 zHcjKmrp7j?tc_i}&n9)_=7Jk!HJ*!n{d;c#_{B^?W&#m*Yj{Hn3=$TMBbYr&1nf=I z5J%$Az&1KkuAMhFOb8x>JWP32DzQMO}L&W>%JsO;*cEcv<&V zW{g=(z-E+n;rZ6@TAAXe=uP>2lOE^94}kJCRK<_RlP?akN{gxpy~YZ4yr?)xNhH7% zX(``)ELS|B*ynKJoboUVeSeSm%UnYFGuQctnufds zW-E++EMqpfFzuy&Zui3Ao!(s2bHw=HvVT8Vpi(obP8OM5Nox@iWR9N2E$_6(xrS+~&o^R;s^pY@_iQFi#d>)0-dAbSlHGc{YCjK!L z8cjgixm3C<<{!tenkEx1c@Q<>+PE+panylkS!FY^)m6`bs`cpP0prgmr|2WrqjHqu z%;*GaT{MQ%Q0cP%wr%16IC1kz@mtA@cVO&{OxT%TvAih4aRe;tis5TEAIZ7zQ+QZn zj+T|`UK|#1r-OG5w3jE0Br^*>K<3aHch<(wPmFFQ)F!tMg9%ZTblRP7y+e@I_kflQ z3c$yUPeU8i5n0g6`iEGIlh!yz4ZI{CFI<$#qnCB)afhav1#G6{^4QMO0)f7lmjmsi z1Wm*)eg@@i$2!_g7Gq5OAwAZW$rPjF046Y(;4ga8(LL?%96*>Yobk9S(gz)+Mc_DU z-QGf}OoVQNdFn@SU!s6Nf)J5Z7hw?n;`d=%RkD8^XR$)3sg!9^$3>bR$strA*g5Gc z1UCs-xWNHGg}Z{fg+?2q^Nu&Je;HL^;V4`b%?7{W!F{moJqG zYDj(oC%*Re0h@Nd2FlT&Iln2ov0rOGxKn4m6Ft7!C2wrC#a?!-M|Kpot;6@Z>`PJA zW);OpDYU|`Cd<7e5d$C?B{{SuNpu>ULPEie4Kb3y-}B>)DD*HUFwNNi9lo zG=0+Q0MATR8L<*&ZvUYh&K)>q6v7>rgnAOSD1E<62a<``RNF}wDBfmPth3ynIBrUlLfuo(f*k}uYcgaCdN4Or~XzuwG$CTVGJOBBSMDi+jJQb)dogQ&c5W? z;2vR%Y;VY=I;#y4+;n_!xMjk%S>Yuq)sx}br*QM)AYGfwMem-)$owJbL!2J$3K;^a zSxK5?UY$MbVZdEU9JeMfDfMV27fRC&E8Vx%DJL4#A)$YNP08upacNV-Wl1LgFtUR1v_?6b6MC_MI6nbCG zjVn#QR(+GqHC6K@?BTuC(!L##=y7s0j8o8r{lUQNtg^rW020*YQLzh~noqCjx_i*Sj8D;4@FK0MwZ% z?RVARCp0P_Sp? z$8Z(D;?vEI5?LRF$>7&@)L_ZH&6a1(@xz&2n7%nivB=`xht@LM{XuDp)Vh$`tv)UT z;h*~jw^_k!OZmIQEpumugZ76Sd}Qv+%6C{ZkDoQTwp|;dVjOG#w;C~^z^uNNt)=}g z`|@v~A~an?8UVU2zD#|>W+O!&{wN*+pAH1rc%Ge3eBUFN+fF-plT59o2EgW2h52nw z1B7E!%bWV$xs865P8M}e6cSBY4Kk8!-^sHG_t-^djigKG;u@O9pd%uaKyZzJPL~;o z4Lxh5CKdVoZ!RnPd(L<%8UOzyi{q1N?oXa_+8C~Xoj@|z4nN|--f69i#c6VPbgflM zcr%v-Q$br(ta|Y)W`?UmE~E?W7%R8nZcJ!R-_S#22qfL}8hFDtfW;n`gZZ6$7}=Aoa+2*RvQ8&K)liAHo6s6mZdpLkMT?%ykg zSDkaF<0IniFD}fE)1+s-na0ZL12Wqx=-23c2YB+zAQEmvVQ08J{xFW++t1pMj4GsQ zhZ-%K7d=r?aWvUzLI3)4nyNY9C6~6e^2yp+YW^!I6QR{Ld1cXP&qG+;B~xg=l=qXpWj6S| zeSzezk@1faAOnk8^n?8y6U-eD`__M|OTkP;PrG-aH@TQfCx&q(k5b<$=5|DU-iY=J zg?_cf|2V1N!;k=RA!-zyZsx>en*w!oq}DdIoR6=`y>u z#d6bwJs*U1?Bm}N5n7}{`)an9tyhUW&!5KC<++7(8hYm*7xdhzLP22Ed5yN#uw?^S zHGntzO`*s9=~4<$YRO1T1+q&y^plTy;U2-(S1{65&@G`Qy!_4nN%J54G6&lXV9(yS zCS4k}#K4){b={zMNz0*&jDfjh(w2L_rg`vBvxw@DBLIrRP@`&a`R1p(;J{(QjA{j` ze~i#oIIlKvO{dUCMQ5N`Zxfk>!Ro@oMz-v|K*0Yu5`Iy>iECwVcPubYR0jNDPKwEF zGWEP6S@}MIYB!9h!EtaWsjFP6krsM)um)qoHQsS+rtA8%E^Xpt4;d zPM64bkUiFUA}lL?{s8rZdigu)e{;&(X$VswX<+Z_5A!^mBnxr22^$gVW)5~8f`Q9R z$amZ%Xw?F#ze=n)=*IA|-nZhC9rn7}hN_fYz6^gNk4feibS#=J$UBa>v?^sROP^$l zE9iuiQR}gSrx(JFbM>2T9z{_!4F+GAI5gjt*3o6^;0mG=US)u?=f|N9T4a!*foe)r zf%WD(_K08b;E_x60^ZtO-K-l|vA^gg7*w3N=PTa4TWDs$MH{?W5o#FrdT{i1ajH(- zg+A#2gl99=WuL_DRfM=>{xz8>z$2R}m zKvD#NQGmR=lNC=sxII0s8TA?}_^&DkJ}z{LfRe*2Cv9U^lZYl->eB?}Y6+RNnoyl% zs&z=}gv>5-0f5$!g9-z-AgK$Y8JDa z%tp(SDOrHDKJ!8q>>Zg?new&}fykU%=f4{^`nU&saE68(m`bYji2sP{hviAWf16_3-%t5ZC-pjKJ(GNq_IW{|MQ4iFX?#+j=`l_fimhqj7 zRE|{q`Lv+oh#oLyULh<{W#m(Q<|e-VP^c4GTw{JBj;*e{scm+F`nQSC)d#r@25Js1 z`2_;nE*BM<0keF~VL|)bC&htOd2a<&xU-}%g4o_M;wR)|n!E$jZUL}UPT&~uQ56(A zui&w}q$MlZFs@wPU!U4m+i4EJ8?Aj7#!Bv0=?=Ed=Wo|<*IVl8!!BcSn*6Wv3 zDP5J#(WXsDAzcjTs}{eC*(9HB`5>WzYn(+@VH=~#!)Od6UHwEDehX#&qs=+bgqk6x)hlx*yk-}#&NHu8C!0zE-i9PGy`$h zaO~(3zh7xvuju-n_T1m^_+XDActC-a0uMt)e9n=O^AVBK0`^_U#&r8PBJwu&ok_y~ zj-`TEGkr*7jM9vE2!N`&=k zyXB_sj7Wn;z1&QBQLr)AdBehTyxMrCpKHt{JYx@CsTc!_3W`~AqXJ9U;HdQ24uLSJ zfE_ry<#u`^sNsQKJDBfbqkihWqUfxYw5!# zc2lsAlcv_U$P)9{a$9N()R--gki@kv0dy@Ca)Va{uU7Tiy_`Wq?0qfTMZkJ7XVc?P z+S+*xWh^n!lz&V36va$effpwHoD*uVK6FvZ)!R}ZW_tzYiQClwjr8+DO8=KCeej&k z^A&OWwGNSz5-jL1Z6>eXz2ghsc0Po+Z-2lu)&1bkc+=Ujzm6lWh`w0tlmndoTpfZa zl#C5?cY%8exO} z1|h>fP1ppB&WOqaK@fkZEm%k6dLfEwq@@KB3NzrFpougzk1}KF>r22BDmu3qNZjjLWrj%(>$bR@TX3Ep|A+BgYAF{Yo-k70 zymBR-;kC1Nm#9AWQv9fcbX%~{c@773@y zS_!DnrM&0<0_UkcQ-=PEss_CegOy&|qdSd6kjb!TlZfBiYcC26=|L?xp$UY~pV1hi zX~QkCcl$SVWKvmLKL2C|{n>25s9Ew!7q4Nm>-%2upzdBIz?${LcjC-XZHFm~O`df3 zLpB=LnsRVbumLuKf&vDfftqJ~VxfYIZ!@Z7*qNQX5qJ%f>9#u^m>Jx#HDMHYdl(=tMP@5;+% zcP=b}+O4S>PFK25LrJc{>GGzM)Eq{4E4aPjW_{?2?vD@!SC%3U<03X{mns1 zw6FHy!szZ0&V0)Tq7nMP&>~Vw|1otE8Vf0H6k}iqo1b8jriH7rPZr;6?_;p4bBj;~ zvM+be(6H2|tM}^R+^@>YC~j=k1wtlHy-GFI2s=tZ0e!8tqte@a&f6opI?Z1Kt0^U}-y&+L329gk` z2AT27?w)!}5T#Gqyc&k-g2m{Pe$F&{viYGgKGHl})td}-YQ6}du(Ac$)O zrx9pEs})z5Jw2djg1vrm?r>SHw$yQ}uzA3hYjyOfnYtdVjp$OF@JT7x#|mvLl+Wg# zVo`5T;!Yo)>M2wL(a4>bqiUS$fZv4z1i}4LSAF}EuG=C;)VkK{cQ*z-9~xgJ>X*m2 z$K!GUtf4+DV5(*PCWv{z>lF#qW56(cNQI@{d!Y9iewn7G0E*9YG7XI3E%z#F^?mN& z3fZ{evZR6tJu)+LqhZqUSWKBlAWB)PI1iQ(HH+>;L)H^6e=H-4|2Vf9q>#T$8jn&(3b)Z$XS=ZQ&z|5}hff96_#PJe6na{ZT*XEg-fTcs zq~^L>SsLzj)a=3syIY0e3vh#2Bm#Fu-9IJN<=c=?Ct~JjZ5qkVr}r~#mOvI0e+ zM0v3|rE;*A>N^V7(MDMhqt6E8E7(fdftk^)p;dn8$PNB+o|IsIGGGEzrK-cq<(XSD z>JoTO^v7`TO)sFeeUQDQab)4$oV^XwrYCY7`qv-8&fC<_~>8W`ow#D5alCyVUx`d36g;u{95F^$>iS{EkW!sPk!a8vc`u}b+Bqm;@8JW6z9Ay#iLy2-}JuF(wGgt zb-R%oQ6x`UEaz6$4-(&8_Up`oIAW~n4yx3i+Jsh!&GuP|HaV@^$USi5io1`GzM7ma zMwUpwD;mmj#GAGqYdMC@cFP~v_B=8#17j~bk&WrJg=w!KW9hB-OQhaLkZR5}^d@wH zwV}GhSrza(Dwx*9hn@g8=%)x6ay1QrTjWkkU2Wa;2gA_epA6o2XvQw}adW zpc5AJR{JDk2Ff52tv}S>+KAEAH>IH z9!SNd`TQvCbE=LwAsK#xZN8tBhL0Gddd$l>p>ePb+oc=uX_bh?aB{48B(COANS?(c z1T>OV_p@ZCpkX(>CCkQ3ad^t&tKo=8wQS_Hvo0~1p;)Gnat?iI65Bbf0=x-BBngxl zh2s@*VR8#CH>LHC*&;^ujoCBzd_g@%iWC{WnfUuazs>DZE{kc}7hK5@M$bNXqm??E zNg|KGB-p-jTF$l%ce*^F)pA7@l~bYo#N`1Tx-nXAx?jf^=&V+Qd{XqICmMXCU*vZ% zg1fFfu*TM<9D4&^d#ttH#72Oh#7*+0pZqR>fcVzW5jsn&$MQHhn3a>Rag+BA1Bz-$ z?#Ih`dU2&s<6#rNg|pQ>Rmhno>{{#wA*(_4ET?LOd4bO7uZy z4oEb|vnk6yM?CG3NZ*jKV6HOXs9 zJ?uDxBIH&tjWn#(Tc(q%`th{mX*GHH)*IlZ<7ePpYqjz-4pPWlB~XG?gfPPAfk?rqRt1)&hNEx4{7m^!ZKi$RH6jQhFm3GN#=Tx)A=(flK4)sh z%WMFztXPm)J5C}wV8GfIsPplF2XSLa2Ri^K*!JYERwrLlo4|G{|I7CS17SQ!ICfz@ z8sQ?W#J??{X~zKeXo6*IU3jT`%ahs(jvA~&3Pgl{4?DpF2jA4F~4F!nc= z2^6z)zf2Cte#QroWJ$NwML+I2VRyr&N+{$?Zpynj#J$CB#o8BE$64s~? z>QQf$TsH-mR^0QQo*S<}R8VGoaX_(51cpGES59Zm)Ai1cywvzH>fO@PGnpi>T)q7IWK5M34RaK<3VokBYWmQ?|;xM(HAm z#>cu>5l!|!;#;WQH?(IWWuwc9$N94Es}k)hNt8)y1dCiuB<5wmC0AI7@h__xbv`8A z6Nch1zOjL)mLEglz=K>+*4gBVloT5|F>7~tTzlQEKQ)1T;r`dQXNUX&<;HR zzyTRRYA8OXqLgWXVvguWLtn6{#Kd#kjZR7T@Or@vFEi|N07DT&4bd*JXHOdPYc%y9 z0Ju6&B@`B@F&xjiGN=3Ft15q1x+yW0N|I9WW3s#xgNN!s0BM8u$`>$47>xIpyp>P+A zHRk(KqSG?;*iY54g3*aco>AMF00SSjAb@Cw0s$~Ld~jJJKVB&Q;(rPDFfJ@{mJ7pFJje0`#1yfZ_?y9+lI>xE(+azfr(H1r&cEs7gI%B0jOUY7VffI8R*c(r11f|=wBuQp0n!N9CvgweDoDv z1?q&756dMZhzJT*K7*eBv@)i|_dH|%37WIhz);))2^xnIMk}A>(Be*(ZO56sA4sxR zFXi#H!DJgm^mCv~7C(+AmY!!WxY@MI6^0K{{ki3m{u>2Pc|nH|Qn1?l?qKq+?&Ho( zsYhTv#d(|ALBAJ(%s#zZ*6A66G``j z!EvUhZ8nJ>?k9d@X~cpiIYR=|;mxk;r0shs?1bPFy@;q6i6HZeCI{wd7K^YkpcHkO( z4N+k0!>hW>R)}2YzKBT#OdI_l3R1o*oo1Q7Kl$d`JySr0zV!@Z2l5O8a{tlV&L*Cfo@Jkj4ErRC%;4gu0W>XY z>Rw@iQRb6?>l_S~KsVjLHpbe7gc8x<3ht9l+9jUi9t5IB=S@z3w#0(6G+rtD=>-MG z9%01PbrNmX#a&k>l6+HEnjX!5zPh=#0o#`ia?YS+?GQD)|9^hC7V5<^Mc4B;i@gUL zGL*%8w(HdF^&&m&=9tQyYm(nS3UdyE%w@GHkR*WF3sYL3bOS{7<+aG^RH(P|E*TD( zx&Cqq8p6*elZYG(=ZG*9re4%$%OY@R17~ayrAixOt<<9!4(OC|8#R#o>w3g?EY6)h z<5u>kHqv*13}!Izxz##IfM9JY{RH}Vj}4#T+UyoMZRXE})Mrd3>5tI$5LS~SMo1yG zV{eM{zTFqeMw@e2gBeE9+rsJgvJ@T*l=M7^GJ_E>%`@8y9mx~l{X3*r|U({Rf`FGcF50IuJ zGKK$-tNbYf@EpbZ-E=wLNuLuL6W))r8ziOQP4k_P1ydi0U^Q-a*#MXWqp6PC2C!fR znq3m;Qz}sCj4;?olQAeWK9uFb`%vZMu^e~ zg7-h=>h3QUm7c8TsG!g2sihJC8s_;AHzH$WWylH!tvP3F#ww8q@^igtquKWQ48lX%d1 zocSs_q1_9mY_l#}Y3xN(r48Fy8e!TBBW0B7;5>yLZR?$`k!WT9t5=| z7&f#?bt6%I2S<5HJWicay<_WyN{0#Z?k_o0PriHEv^uGzrdv zK+|D>Hv+^J2p}qDTthtneB}01WU~%3cA5}pvhBsJ8|BL7n%&U6mKq4%YpyD%8QRTo z7=w^IG^R98nsC`6owFtU^vLGYk9{T9TGGJLC8-H~*t?-M4iR?_jC*|`XUL4<@XBY( zRX^GPrnB~otG1zCV%RGg@><-lec;?#9T)vx_G$rpmD)*e3TniP!ax^C4Aqq-UhZlh zt7E9*3h0aYY_`sHL@GF6Kj5qam0%08Ncz5g4+v&1L%c6O7h>cIYBZBgdJ{=O=SB?&|AOa^?|v2A67~R$(%&5v=7ByW+=N{1b(dJ%V~@Q<$i&* zXmh(b**ijRNW!LS;)y42p$=&NOH?xX3zQ%dF~o~pJoGvw;H-j=lUo=+a8}5^zomxA zJ@7%h_3m*-0veS#@BWOUG4dXvgSL3;Oshfth#@i^k(2CP9-(agB#SQV`Iz*d%VkqCb~l{DK6E|M}0q#>b2DV@4ZBbf?Q@A z3F&^irhaWq>8+eof+Koe;FgVAnKiiPN{GtRE|RPyDMHx6d`{%{hpnfX>z#JZNR%GZ zn71%R?)DXNTD`PWq4C97ztd;m*om0^5xEga7AvDNipZ|BvOvtgh7-kaT}A)*P4hvA zzppZ5ng&$B41HM&!!9OUD-c>TpUGL8GtCIN%9QXlvUU)TiAvsR(_;7GgEi*ZQh;D@ z{=-D-mU;6pB}#X%{)VC?Bb__&E}A(?V8C}LM%CsGl_1kum~={#kv)zbdeW1D7sPS( zHk!#|0;cm0<`*;e8U63r4yIQ+9&+h&D^}li`<`_zp-oX9A~^OubrzZNkRxCvjmOU4 z)@6=aD?#KvCo3m0C*OMuwLaPKG`Ch5Q!Isf7kHCFU?p!xbTwKrhaJ-&?6!)wK}Gnp zqHnU}(pr_oXvyASs+yvE;MyQeznHr~ptJC(7o+Io)&oM8jbwvBI8zMSO3-7(zNMI( ztxe%Kqf%lnD*Ef&#gkCHm_^_#wvNMH5|w*Lm$&PbZ=%^3(NTC|bJSd-^S2F5F_Tzw zli;6F6~4-ImS)b1(iNChZgfLHQgpP>L>BF!)ctgZbGH9l%sEa1%CE~biO91?-@Zd7{r8LUW2&Ts@yhUW;ZeLzs zzvvPZJC%*(~>)| zzO^PB!9?qOJCe{NI#mILDb5Pvj_Dpn_Z{2h4wy&OzMHsh$gW_ExY*^q6@>OP-8O^) z^fKtls&s!hdtP9#v!nM#jFJFMp~ZA){r)X1W^3WH*eJ89MF`d^;BnRZeo=OpXHEte zdUh`Bm~b4JhVkVeA@V7A2egEEehB_|Q7 z5ZzRRUgJTn)XML%1jU*Mk``OyK zm{m#RM=@6F0FN`M%dbqOUKeZAk9`G9zp%Qb^aHa3XZLyDwHnM28Pczq+ zmu)=pl$8@<>IEk<-kCg}rWtcFc7?j4qmPaZZjx9>$q@4 zLSUw}^pAZ{s>&|Ar{%6CRy?}lxTXmNwah&-W&G*#h=pn^0KupP(-VktVHk*csNTSz zzjIG;jFO=qCW8Qb;t)Fk3xs-Av;7hni)uK)Y{{+>*IL@R8|4>;Oa)bKjB?NUle6_a z!k>j2m!tUIm|phI)C;$FRpwpFvS){DE~l_-=`h?L#ZC#vXrj@B^^m`H>;Jgd)<)}z z_ukO^Qzev$;6^X#gGU~mfXS4#GI^<`iL7wm5uprQ=FJ zx2R-Sl%4L^iuy+MNs~k^_ePZ{i2!SVTklNghM`6Ajm^)2XqkW*R)7Ei00000&#V6( zs+y6J)btbVmJqKcqZrfMx)qfX(-Q=h!wZ~iwC_h@uZaG9c%a!U2=sX1WQq%d{+8($ z)?M^{UQbi7SbJpm)pH-Wv6Ld=LmUkSe}ZMF+~*NME1ib9?;R- zj8pr0L$yPLrdh4eupWM}(gqJToyPm!(D6lz%nb&C(Q@KfJ~x7;N{cKvb`+h;)mAhX zS4%k^OEyi`tz0??b8Drj^h-lQ{@6*AJZ|3tSujAdV;G37r`IMGBnQ5~f{;|wAm?gl zt2ugEuIjXv4+z8M%V+yMOiI@$>)0Ob!KJxWC_TO1%bhg(0Vt^$*lSa?=0CDOfMo5y zv*0>(#zIInhGymt@5qkNn^JCg?u{FR>@GyI0g`0NDrMbhL(pL{`lOHs0=Mi@$hD|? zz^tVpgB#Hsm~yhDMyAgVGdtil8{qbj&=Ex^Guzga&$~6U88*T9@Stiu?6;V>{;9Hg z>D_~KM98KJ){Y3!xk38Ce*cR)`!{w~Yfo9(UGJD`AJ06whGSiM!0G7T`;tePVP^ca z;*sL+HSi)<(TLf^7BMnxq>ZgqP@;I85QQw88=!Uqxw|sX=`*7u%$_b}M&>5V!w>=s zq%(LTzCz4#0Vza$$d}dnoL66STJ=`ol;QpcUVtyeDGdTO|qEs@FnoM zMB9-RM0n{*F0Wol*_@2MF$jU4ykSP*=aCZtn08z7(8ge+uO^9dcgZlhb{OKU&|Nra z^avMECPtE^8OhVb8uOPL0US*g0;s`Is%MpM%TIL$!~>oOH%h3p0)0?z3^Zv@1K*pR zL0N3TvTh2`$y3oUk6zlduKWdeq!Un?C1>2wjI=pXDSMzriKuqk2Wnp{3w@|0GZ(~|3@n^urndATjGD8<43c)1SF2*?^ctUi;pnN7PaN>Fee++CA> zmnBoVP0&Yv1_c-&2j8=W2Ih6>d*op{SKL0xA9v2OhKT>D`ZK=Ft2fUmbBAh2%gI$a z9Ly~%gT#Yfng=Re`O^svu6uF&AOyO4@ga|AA&}=#`!=ST9g03g{+C)n> zecu{HZw3_1uciCyclct`KoX^#(6Ln&Wj#{pzs$Dv@2FlGjQPAXD@qMl5!RKJlH|<@ zrUFz$Uj^haziYM`{ne(vzXb>~i&$zf;OlOrA%*2cM=K_7px!8kbMn6ylu2XN6h4vA z(+P1*x1Wp{;3OpRzX3w}qZu0{s|ZpJ3qu8A(kw%ia`qyr%fuM{2u#{ckco6hPM))n zI1#y>7dief+P#1CpoY5^&{K*;_-1IM87>7{_DWr!!v%W_J8wolGQkB9%bYyxquEQd zjZ>OJDnPRgD&8uNVu<)!CMbnz-=h6Xwk9O6bPk@b2iO($#4Xvs|3SEyk^Y%zrt;uuSl-`O@3AbC0#HnG8s>6=#!?Pd9yg zr{!ekO=~D}&F{+k^zif}OnNqFIIgV*h^3<|IP3$k)1{9SZ6cG0CpixEpt3Eva+>8_ z5C$(kpe|7!7;^grupQ0=4dlq<8V|J%= z#*-TB_S@QfeU`8lPjE>l+Iy%;8*{if2ZVKoeSO7i;qzwNW2LPD_9%9cTTQvJPT9X9 z4tnm(vX&GqiX(?wLM3=A%BS>cWAZfkJCaxuBD{htD7SnqO95qeT{vKrps#^ZO|L)l z6~;T~2h=%Sw7it`m49gAx0j*%x%|T637cGF1VxVkS=4!yUo^J%kO*9=E|Y2j?0;PV zAv4Z0xO4VAhH%8=gdtq6#vzY=9ErO#tqV7jBg!ObD`+4%(+wr9(~?mpdjgTz_~d$C zkmMNmMEuy>m*hW;rG$1+mkGnfTHQ}0=TBVs%4!4zhe0~G2%HKgoHtj-0Y8AECkWpM zc5Mt9#g4_GE*G-2{?Swb2wFRH$rB+`8=TNzX{(1jXtF43#K~fFM}#-QBPjr1UsO|u z`9B^vLxxuVT0F7{Y<9FW>SS?Ma8NKA?IUF;(3xIZ)iGy_{0f-LL73ckoB`bDKVIVb z4)Lz#PUov0`CAPhRx_6RNayYOkx$}!Ic91D>S3qG{Xu6o{HU>;P)ev*PhUp(t`bf= zFZK<`+BEw*Z|(Zl!=)Yd*RqXifIvq(+QVu#-H5;m~gX#Uw+~8=qY+5rJ9P^Oj#ezNP9>{{TR&mT;%uee0@*Pr+3gPl?xsqiw8- zU)H!a4Q%uGzlk(z-RpmYK_-_EZHIWrzcN6t@60R`H-`%K0Wzll^q4sjvB^XC!mnw0 z3r5bi{h;XgVLpX~()vaOWt-jQbFJ+#VOtR)D_cD+fT61(0UlIJ28%Q~7VbyCV~4DO|RVcHkq1P5wVO{eY(^`3mE=W69zor=SzQ`2+8xKypm4p zO8YYFxzh@55^S7T2^5t_orYAUy=Ywy4K7tyx6KE@3tLx zr9WeRvEF~gD71i^V$JG&Qkdfb4&Yz`RoKi@Li;*b`we-ox!Q-^Je~o`cotv;#()U=48rnRI zwbb=vNmDGw7dffU8c=M{4yEhDWw3S&{B{u@KdwWzOU+t_QmkN)hol%-C#(kK!@j2X zTJ9vn4C7PJyT(@+G%KPrbN#W6OcltBS7c5+9%$0$kkM~al!?!~NOHs}O${1PtEnFH zdZ+Q-!EOLRO{Q?U8IYEbQca|lk2=r~u&~+w+BG`ukh}CyPKP?xzA3F7ub#Gq3bYi{ zX>&j)FRLaXw_EJkKZ*MXlcexwb&ohVo4a(aSx4bD;>ntHjWU;{4r?@qyLPL!gRiar z3FX-L4xD$NxeNkm=TJ7z#$$cACEzz^GJc|z-pM2e=gCNoNOlDzM8z#4?EsW}`iNHzU{<~8IZiws!d+ItX^)3< zK2h)zL~XIrb^?PrA{6i2_CmOIZP9x-vv+b8RB^Dp9t$U_ziI!Jd364K+biOUekjwe zH(5KvAt6c!Eo}V-Nb~^PQgf8`c{yySUDA{VG*F! zf6n4M5S6KKFb@FK$OOL_F!v%Waq}dguW8h*Sl{#6EhCOq*QK9*L9CoHi2VVzASo9e zs~j9LxT(XEQKL=-(+8{{`C_FdK1*uY?%EjN@&VvEl=D+N6n8#*KyR~`tX7og6k z+uAPr(rBUfFXO6{F|R-tR<#Ful|rch1A-3iw9_QNXRa;gf#*mswI<;Ovsxz&zz#hW zj>!f9NBe0o{*ioXqzp4US!V$ko3UA8D!webr-#q^HZALD)bz~0G1q&A#RO9T=gIcr ze)N^`u$t(MWp?casWvO)?Duo6xnp0rzN;BEkpq_xw**P8$r90SMDyBhHm>f-$mU`d zLz?)rC{JrFs=PH{c%v0*+@a4;Sp+Y-`9URe3L4QO3ve3nzFE}mjz#7h-FxG{8NKu| z?>i?hbL4R<@a;dlcSAl*LQ5VN8NnOlW) zMKNz#?hT7~cjICC3U!450oDKj000000k$!Dx~15IT{M?)?wk{t6~Cu2z5EP}Cj%Tu z%J|}ijIq4rUH2T)rN=)j(>ij!Yx~ofBbcD%(|WqPqvz35<6tiNhl8n79xh= z#>%`LayH&YZSTR`vXxXdthXAO`yT7d5iNDuJPSVyyfh{6*pz+ZBrV%#JGP!sILp;- z$D<#1#k32XZJ27PH9DtBI|8AwJvp;7aLpdh`U4ov!DOK(7`6dC_PbPpkVCpT>5O{C@60;X;;)>uauc zy_hAGFXQR%j7-rnNJ2DxuX9OBo z8sTx<8uFsLv0EbPxefm~t6YYVm%2$_M@w82`B@klBPs@Wd6pWs=k+Kze~_;Oo9@x2mqr}k z;S-brr=t1ddUMmt+9a;_Zek^#%wG91?KgmgFrHietgC0Wt1509yjP?>Gp-)L_C#?$ zN(-skW`ekzi3R88&-zcL)ZFI{!&VpWiFZFf2t@TP)Eb8k8z5oZc)uV&ncnA_9 zf`H``t-SiRltGj5=G6fsS{R8+-=6Xw2=ljXgieOwa3~oSgg$PZi`YkWPv5SS*KN6_ zzj#6rm89kq>qCkdDEPf|#dVT03Ns8heikkS`JV~NY7HVT&U?Zd@<{vSE*@z(4VGl% z|C-dWt(bk-_R^_gZgPL7k_bN$#9QY%O(~Wpp8x?3DZ9F=CF}Zpz4sf3+vF}mVYp^9 zT(lQmgA=adt%nC-luHiJ5OMD6XwT|Eg0?+a>2pp@@xI4#n7O7oWTe~_!&8hS8xhTi zPGi6DAncbL!+ap$?)b#CZ+g4_prpG`1?DGHA80BN2IK<7W2iJPcTm#8|tXy23Cu2ToApW&1$rNM|(A*{ZN z>IP2Q=4I$wHuWI2Szr9A=;|0@7$uye++avMUpyuo&F@ZPIAUM z+}bM#W7oT_LbHpbcyE@HuGjdJLBeJ~24 z)0D$Q{$ikPZQ&|T^`;Q)THMhg5m_I^}!pr|LUtx7K+un*AH`{ z>Hz8>4z`&Q{G@71I2{h6Iz@LN|k9)o^;HoCXctQ zViSQG#3O`kJRqh}pq>`dam0mogZ1j^FXH{JpcPR=ng7GZT+U%l{y}sps8$_*kaeQN zXTord1W#f(A}IOLi=3~<%bt6|E{S)m71c^)j?1-KHke1JE3Of=`~Mz$NmMdm9-RSp zJAZ!22PmS`i@&U<3h?_t&}&)!X^X%|`}Q+=LwX9?9OsrV?FF9#{Q%&yIMH#CQzQ9o ziv}unX@pV8$ztIG9Y$_$zs!7M@a_zFCAWe#FkN1=yuM0)`#oea(&oIZMwnJWZh?9l zrX@PXK7p*|n%z*XY;+{gh^TrFk6hc$o}!VMVZl8kSwzk1%J$sQJ6HsTK?e`ir#fe& zn(;^Oo=yV1v=uKp>Pdr4cuNzYT4y38Fp1zX!M+|$!?Y62)IDyCz+2R(>lLHOva0T&912MR}|_kdOCNaJ%RXb6^*OmLwEV0vrw1n1_rFODz9mU=RVtCukHy~ z3Z^BacpNm&J-uCH{f%a&^5}Mij~NQQkgpKN1ow>W5zToA&X-YX1JMp$xF5EC)3~H1tVmVhb9y_o!rI^ zA;ChM!{YO;CTSKtv5K2_eA{dY9-ota{r4z*r==n99oVb zBzim9@D1B?(kt)sr(ByfBir6+6%-;^gqKpeL#Ce?+kDKba`?$ig zE(#D@4GKYpn7lW=>~j>Yq6lnm0cr<^H3mI(=XmIXcho5#UgT1{v|D9}7325NNzLn( zZT*_k@XHiKbnsqTKX(SMa;G+$uci_we5j{Fl^Dg5IK#gI&r`sVcgBlWZe3gS&t)Zx z#)z4_HFa88?xt^h^eHlR*gWoDntojbM{*Ue8_YjvU^WS4AN84QQCdA<+BFjJ6p$-4 zrE6j6F5gK_1`G_CmeQ}XoI(Mts=wc`mgIDyjhS+kgjlkTbo)uRty;Q_l!3~q>xnJS zUFQ8ntH>T=5)IY(#z>o4Gb}Rr#q-^6_G2Gt&wO^jZ{Np-;R7BOXU0YrlS9^>78g*DQ2~ELur?(Z&Ep)OS~JU5 zl@rBJ=uU+7RzD+!KWav?Dya~(AIrtR4d%cwMgLdR<>ek_Hs}F}xsH_HtBb_%r3#VY z{rL!)752n%`OnVR=;qsO_sh&zlSCjw=II@Wv8UjLT;_2HRo_=z?cetSDg7rB`Ai6+ zi!9n%uK=Vn8x~)W_6kwt@P!Q3CKie+UkffC*~Y=jWp&jbR|4Md5RIu0M=rT-2uGS2 zbrX|R=r)jG`AnC&ZHgjeM21@f8P@4zWg|T>;e+dQZ!0=(vV4Y3gj_;R!ALgbgVC^T z&a0>vxXU%fiN+k-=$1!sTk!$3(bPBF0WQ_&rg+v*NdE zIw?K59Kz6H$U^=i&BxBuqd%~%Hi6JVX4Uszm`HJ2`|k4D?w+&1V}hexYT#}OfDg#U=N|%QdWlN6SS6+wBq?Yh@ps{*P;HcUz_Whl}j3nrfes9x~H<0AfnrQ z5|glqjS+gu{ca{?f>-xIAq+WnqJDVGJp^0ytHRR97yRBl3j9F$k3|}7vlrP!es`IH zrD{>lcM18^Qop2o006N7Ao&l3$I&Un_vYvPD`Ra7dN*}k#Ss1W5)!Z-e7Q&;i^U*? z17!2Fscso;rBQW6@&HoZ3AaK30008Wl^i0)`)j^yvgj&&)LIp*m3A)uP2OYS`dFL< ze5fKjpR`={=Mc`xsdWEM()dWxzm@twxz+hrA$PJ%W8sX#7=|Y>|MdfN7NoM}zsW)J zpsn<0bqoPmn^L5^G4O<_?^jD2s?n(}TbfO;oh-n`Qg_CVEnXBm)Bp|P)NEAMz#AAs z?KBi!A0|!I?+jv;)HlVKFyJ30B1Et55$k04(#@ZGySl&NF-^$<^ciSrM(xt7` ziT+MTBta93gHJ6WiH?vHMey6L zgaO*x)pOokW*H=seqPSHSXo>m(=fOfY~;WeQxkUJm9$`HhdE)HOJb0n^BXGwwe;<- zSOw-4g06FLqX;dxTrCt*nksh%bA)!t=m&%_Xt4Aj+7)(ow&p#79=1~sAquStMjth1 ztQPd1h-lF31~KdzsK{YGB%gAKQ@NNDiNpx{Br7WLV+8?V1Y^Qd*p6VsVWO%*_ZYuMc> zKDA|Sp@xyMHXi@OltXY;MYZpQlOPIiFbrz*yCyOIu88=W!RWJI$~a|rHAIl^Qf|<5 zuD#Vr^ny9VTQ>>s6J#R~Miy}sYbP?3-g)LE#^pL}j2(giZwmo(Cm8btl5p>^;_o7< zZeJ}I0=(UssbZ0a48Y-s2B4*^(3M^dhTZLF6wk77+Yz5aqwanO3k41~fz z6a45|Fu;#Xppf@*py*3stt&MDl`dE7mn-v`!S^;^gdl4R{t$}$t98&}Gzz{9;_1Z5 zy=0K=Rsn~oh+?h82QPB5ddI>Iv_3%cqg)p9e}a?Kv*g{X&3m-@G^*|%bfK4YTrY$V z*vy;PwuK2f1_7us6u;b@ad90%e>u)gd{FD)&bhtNjGz{fFtdg1EdQX$nIcHe38d#!@dsbDD}b{kvw zcAh~=o2#fOdvjDMzvad&KV|pbpprLMK$59kN}Jl^cA8sm!!rg8Un5!EL)McP7)F0A zq5u<)_k`L?nFH^Ug#5YFRvaS(y{v{KDzMmdsK(zYI@kru}MV2nkbr2^xdLTtvUMA?&Y zFy^5225$qt2{DPh+MItM=F|d!Et9C?3NkJfSG3V27Y5&L0md03whw>wxIvyk4Lc&w zC*}FNPzS&bre2Nc0cBuMYaV(0`hLiv^rGg!=>Vagr~wZHb~=Y$)VDi5HmF&9m1-?RP;e{%7$d1Azvne4cv{qf|d6S_h{spx1Ygp*i@;>kF` znsX_+y~xSul-^OCgL>iBkCwE9E z%YKyhbP7lECgxu)Qj$pQ9e&fn8uAm{Cf-;vpl9;kSihqza#trZvQgNpK5|x z$`x9!2+3z%^MJ0^180>(E({v9@>@j}iKzdP(5~HDl6jNp1<7)mwByA#Z!Il-wZSgc zk+1;moYdP#w{_VHZ5=cEzcCcg%wTfeDAEza`ywmw*I0Lb+B$=Z>K&JD6zn@I!ske) zVoxC|VO7@G83OFMTw9rUG*VZEm7G0S7lMnINr2R!EGsV8>41*fG+ST#g8Da@v*>h?oO zGhNW%imroolhXPmyB!qapk(%HR^s|V3~+*=ctv5V#XVyV@JJ2(cSDV}74vEzd}e-_yzHJrqTu1j1!NfJfhT`UQQ=Z3tIN}ilEun z6D{bSA1zJVqB|K;KMSMHp8#+5i-(8*BI@6#6R3xs zBLDKN-ZI;5NTckYYgG)iu4wewZc;Ap4AH{VVyJ}=2*gU&{B0*>g0^yz6k+x;`Agz@ zOP2kIM%r1C#$&JJi!1SuCG2?f$nN|yn{V6KU*LB?2(5gLr~T2UvM#Pu$s$uB9=7N< zNM4hta$j{y~DkPb+4aWaYI8Pqd)nx5POX6J{gK z!#w1pag$|8tLlP@tU*l*CJ%lXc>8-H^Y%LJ>8LDtBSm8}HH#_t?MpENwKks?76)a< z7QWFqE!&`Q3LFdB4xO{*?jb|bruWjX;%%QAxVM0qP`UM`wP5#BWQr4?{OZC{aZDZ% zC)g2tYi-qp)~iUUN+pmTr3yKdCU(dW$G$V0p2QBtPKD6U6B9C&pdpGe2AzeGl` zb29=In39fKvSXy zn>gf?>Pk~M2{<%Ibsb;fkiApm389pCL7TcXEFaX4OE(jvHQ@-lR$uta){mT#q=82C zqsbxt@FGxwElmX||KxYSBJC8xeBM*Pk9Zy0;ZTR&3n>P&52Lo~gP`=@C+Lr=3I*Fo zu$=YLMhA$(CjQO@JWMj#>&$$w%v3|r44QI~#h8Ck@9TUysglLx3^@zGQPDg05PrkB zJfwi$wAov!e#+0Xe7->mek=0+MNt;%LbIniut4R9q&}7o49!ys!Q({WJ(37%P!Y|f z(K{J43aq0?SgJRw8ZkV^A69mhhe{1`67vpfW01h0wEyqgg_7F+EOpK1>o;$GWonO-|=$HOF;9X+{7}635OZ- zAZaiHs_0D3`WP~KoNdhqIyl6BN{m)sO1zfOFa_Q!XJO0V^h@ZAce#N+(PWFH_Atw} z*41aNq@8B8QWcAHmS-Xm6VlTixJAizr^g2jYgL<(gpTV-RlKWul5&b}6*p#Zam`@l zr3WwgrKEu~OEelBr+b1KGNl7M&qMaD{E*j|%v{0a@)wC`Ef&^3ehhZT8bXf)DrbG^ zQ1U+&hKvso!S4aNY2HhRS~4p0W`nT@Q>52j#IVcUQJwac*AD^cn~n1&^b2<;zosFF z{t}X5tSJdcvDF)242R$`wIB_yIG4~4j*_3VR{iHH790OWPByie<>_E)Q@P;K$MZOQbKon0LJD z?hCxuHk}2LrV;?AH++RS4HSE(jVF@(@8A6pLe8^YMi`pxN_!D}MQwz6BkW&_Um^h% zf5#hb4QWk(!}^bdzYsh?gGIzIpT~9Tvc1ppIJikC8W8>5gJWv|gM*c=nRbI;3y&qsG0~@-__=6ST=!WP` zz*6uELI^7mQJ!o=$*4YUg++$QsWh#BKVvzG`jE)L zi1nr%eb?r0dEZ~vmT#uiANLcVLt5iE0EF&yc^{pZ`Y|e*QP?-v98tEr=8DONZd8r~ zy5S}mdel$ionr*<^cZ7L6#?jVy;wN4dl0u=0`yaI?jg`!CnL96CL>(wIXmLpRNIa5 zyvzE}Vty3q7zGvL$u`$#MRg8~(^2Xj5%m;R=k4%(nP(8}{%P11b&Q@*Rqf?`b}~Yx z$=emHOOU6aSHBxl+VIGkwFf->_N2JVAbs{u*e}i14NO11#HTU z`AJa)gKS5}q|LO`yi7=ycF;Ko{)bc2$oX5qV_jOnBcKaS|D2zk%s!%j;beOb1Y6k) z@c%`_sy^p4VobL`80Y)Z|JC33xzexGD4ZNoW7`(Hvr1avq2NKXEy$RLmHX|j?0kOA z%P0kr8`6w;VXP5LV)@P?LYN3J_%uhxQu^QZFg_3Ltm>eERFYYw&F0iam_GU6Iw^gX z?63~-v;bxcoxYoQjzSo3qzemIfk}kgv z+9EEtsZ{vpy*kUz4>9U}b+2*gSp|| zN?8&3LY0}!9h%u3X2aU0AEkX_29E7ju?gR9r431%91Xx;H*HtiIbp^*bmJb;h`dRW z7boP-7Ku;95G)|{Z1oF^Sc#cK&h1`9V%Xu13U}{-tvNIBz(jYdqNATSUC~a; z^`%nPK!QZjLAlkz*Xw|eN7nFer>Bx~^(|7?AXO2|Y@`QYjV$5x=6fkSsbHzWZgGJt zVKigEbQQw0-`ljOhiQ{pEybs%f<6`q2>+8*_Q?CSG>@IGDjNj&AO^3IP_96!DF|Rq zv|FjFp*40bEH~bRtW)VQ+4Q8VM%5%_FiTr#0000001mbR$SKUXbZ4U!lf-ZO%jGUg zGFxk1BRMppqn_h`yG2EyX)CbU-g3B`-HJ|AB_jZ$aL}+Zg>!3Z9w8PBbu$H_FtXuZ z3tcCUMp|PBa$1L+2E7I5BXogF>~;iS%zuH0ZH%v!J3@%?aMqcO>#p^$-l`9+u_1=u z@|rMN*}`I-1x$R!@7qcq5@W0f=e#x1srL1zC)tDwK%ZoGSKNHP%7a&5uAx1^_hz8j zHVHo5ht1x4KG7fYSa>A5Xz>&e_g9quqO_5hHoNeYG@a(fuZ&t-XHwj3axVMr^>uwO zeVuw#Gdb!|Pks?lA>cNzNVmWj7-v*8&~&nbru$In1S3M&KI4KRLb1a!6%;F2G*8u~ z-KgsGxig(4>hVHsZ7IHbe}Pe~asZ;GJ&r+7s$U{X4uH?i96JPP4H-4eLAsulhaJ22 z1oUu`61$_>XXpWj+eE`Xa@OgbnA^Y}Efz>Yh-4;QA5&?l-dvI1rybHGX7Zbv{7C@o zhrySCvD*gNlfFrJJTk@7nvM%lLU?zx3%KEIge~Xj3XI~rzmQYHX^EtxDf+@Q3ZCGj02> z{X59_*mkvQ^nAxl%OV zoLn_P()g;sQfsv>9>SZF!PIjhs@uWjdtM4GmG}gHzZ}3(u zZRV(&NU8v$HdJGP?0nPC?+D1K>8s!_iY=X4!?sz?g}9{ zpEcbM(@H`-7nPq%viGqSUt}9z929(NBTSL?tPtA*M+T#s}Ga7>rA zB`%uN0%vkF6qt}psjNSohh$ ze}z%Jvfuf$s=m}9il|GNFxVLO**0weTFu00JjmrildWlef{i$(hfsE$%RxyZ&EmO( zr(p5NcCim?K?itKvE0Q#3hhF#yhGA>sK?1|L$izU{GPL-6E87xIG_1ojO!C8Zlg^y|C7gHK!+*eM zWEw_z8q)#!&V~jc?gr3| z<1^>gIM!^b!r~4Id1iSMsCOQoFdXO~mvlvmz$zn*MK>8$?9}?WI1@v#Y#R)Z#Vi*I z4xHRc{I5=f#^tMSe^;@M@+9~$Uq71SyioYaG&&Fln1IST4}2qPp3&6(|1y03nuXwG z=JNEX<_&=s&Z%-U-&3l!%vRsCGGk8Lmjz=JU7-E>{+2aQ=U8M;WYuoi#8avq=x*Zz zl`*pe7Ak_r2B__apWmlVWEm3lBm1?kYEIPhW@`J}I^Xxq%-^XXE-C>m!_M%!t4>l+ zo5I_xhUU~ONhomREx=ec*lDrG>vq|7rEUDkBQ?4 zb7b10Ie)fz*!tEJH9n#Ok@!zPef5FvpC#)^ zzzX3OK-*DQ9ZH~Vx{+|g9ciXV4>0d+zg&P9o6PGxnEV>cx-a>*flm0J2aylswb?rm zqYaGQ7#MNRej(rO{KD6z;wY-dU5>%mJ945Fy0*t5o*JBEgW6)GUK2h-Rt=K7>A`6A zJV%B!ExUJw41n;{NIDUtb&e$AG9!Blea|$0k?m|Q(^cK3DtPa^=cPPSJ+wN2r;eyc z=qzd;PZL|YvCfi~c}3@m?00p8zBeZr---U3gj12N5aG=*6~#M0F8_mBXw(6soS zQ3<)BKc%gR3az|<756>UA@ah4Ay|<9z@rP?W*Fhhw8!F_pFwl*>la|{;!Vb&!l^jN zV_-yZ{M-%}sX7%7v~8?&S}Clu76hr>Sa7WCN_fyNy{>V{@UI!)wLx zUNTHVde)CDat)xpf&$6b^<`w~--cYm#13HGqIrB>W}t5G=ACN*r#no`29Vi;xadd+ zQ(t+5n0sK3thetgd%2U4Rss}GqK`qHK^_15zBZym>?T|$^ljf$zSTZVbR%wh#4vcl zE!A2T!{=@CYoZj5-n=_6Uk*0VeE3MgHeQFz8T-mP2ptr7l1wtb#)bOCI*^Pc4%2YT z6={jyg6C#l^fc(cbhZ2NAD*4I>U=%IYrD|=$MlvQe&_=pYf0L9Q#L>kFdU zVi7s@n$j-Jjk%a53b#b4dD<-0Z)^_BFw$WVWqxg562JjTd8{ZG6%zD>r%B;)2!=%9 z$>{Vv_&HRpY*H@u994a+O7KjN&qD21jVW2q&bf!$Dpe%+OxVayTl9yxE&wBKKi}GW8MaMdmxh@;AY7paXG!>6Z^7QO+`WK+y3QGK;H-g8 z>{!97^R4IbaHSm9DZv{hMRHD&M{@aHB6YeOP?!c*N&+XgkPm#7at@~y7-?SJ@HyJ- zt$oitD1Oi#30vVN5DDD1M1~<*JNK{l-*TS*NlJMZn?E;7;yE8tYRCd(jaZ4iBre$lx-tvldoWt5 z^zPGfJ9-%7BeB1(l3jMJqDW4U9!P$2e>Zck=P-{JV$tGwUl$MW6VjIhOeLt))`9@x z=vfvtpjwuV`c4nNU6D(D6x83oij6B+z0f$HtNE4qFJf#gQ?d~qPi|gqp;}IEag=JE zqJ02ft8+%wJ&5+O(HfN?T>=YVaagiFYrP&aQmuH@rF7c2CX^0frP%D#=1S(T3r+ZO z>cWGSgbt6B#={i~{NbQN3AM~V2jXKBUIV!N=SA?nSzDLOo`3W_|MQB z3*3{zWFu+A{PY(+qDX5QEvekLUx0jEc>oebLzxT)zLv#;p>8F2a2}fLpE?IG7x5e@ zE2o%C24$UfQLJKCgKPsU96i?OxwRO~-rvywjbsvN&%Y$#6awc2@pu-d#9>R90Z`2| zA@~*x7|cF``TyXSpdhXC01+u`T&9jF#oHa+(CdOAS?x8?1w&nlD2`sjSBnutPN&(D zCkEIO0K1{urlHHJ|6a_z$=RzG7*KkOwyR%p>q0a(-#wKFkCsw%eT=|N(5e>)if=%T zv;d)$Xt7nP?sWPH`2>3`^X6vY^Z{=AUD;GI@ujR@1pqbvkYK9PO;|x~MAWWb3=)#8 zOXERDe*r>NN(fFvhQ#euWY*p7FTc&2VD{s%1&jW+kH#nz!S45oH2A`TH9 zZHMD^s1aE3Bf?~vru1*Q2yJsC$dd#5uxzw2)vOiQMi?&EbGm4` z+}UtWBq;kQU9~`6uVW6@*LuV6MGJIPepJYYl+}yY;1@BO8N9!>e(=EAbHk9AI9uxj z`}GnPh>^i!_UXyKKg_sNd(oJc)u*l&rb?ixEI;3w1Msh6qs>IQa}laxPtFFj)524GFGUu9zWMem4+iBGMZvZb0J+#JP9>* zb4v6)HWvlgMXe@>>)?h}J#lGS3O%)tDO|Le&om@n_Q6hY6!W8|v#i?DOD|Pv|ND#) z>VfP^(DlkdVa*Aa`^5ch!61-m(|IW1@M!rjJ?s7L@IA;UEist~hn1!!viTJ<xo7LBcj2j0yJcV zwP$vrZp?iU77pAV76egMLehlyq)NC>8(2YT5n)bzfEcyVU6t0e8}_smO%Hk^-fb*- z-gEaMS=1_4rfTF=JWK_oF(=>a2Z7eEK|f)#lM*>;)lf*kSXkxgF;&HahPHu_aZA3U zYPK8*U1`~;>Jr%lSxFiZv>DHY7MB5Wo z7=R(?NzhE1hDAhv9L4Rw%3vrJh~^1HS`Fu@hiHdLnc9DmNM($&YI;%obmo4MSxQs? zD=lnl*3`~M@FZ1fu%;Vr4p9E861fqqNBLdzu(8Y`%~c(*Zo&hi6ejbUq1@S z$t|m{+}Hlub-swkCwt+IeRB!VDXB5|AWysTg@{7M+jwuG5FLMsj~+eB&AS)Ka3@@BilAuYrYES|}0v^(vx zrN|b#kF{~c0S0(+7tG>K0Wn+FC?C3&Jg4--!zObL=uSI&YybB8JQjzmBi-Cv`Erz* z-ni}Nc|^S;8?+sIp)}x8uYAf##y8NVsw-f3d~j|uyG&}E*-k|YtHx`bbC#k(&<~Gd zY2sb}a0)W&r3>K%LvMc2nS*^6j|;cNia~X;F~1 zhe0tN&$TKF%&2#ebW7B$ezmai)k--ID0x$&QS$v#2a*A-@28@NEHw{|*W>c#d-DwY zB`vIKRiGgTcnr4sZ|eFkZNRddk2TO*xjg|=~yp4FB9J6;o$~Q*? zP**kp@&3R6A#7G$A_(=3_2dE-dgQ$j000IV!4#>$*RNwT3tk$4_eFmxWZBlYoAb}9 zwL>)CEu@p4ZlFxbHxUz)rXP6XTR`oz=h%la@#k@H^yOPcoCI`=w^0|%rNOHu_}g&q z<*VP_rn%&m=rif6hHldZ6VKVE5Cgezxu!35SA|SxO%XGd(QhNeu5EZIZ)Q6nlI6!c; zKG{(R1M^O?(LYb)lBNlWnFyxVBBfY>D+AiZb!(WZyVIlp`E(6B&LcoqWv}!d2W8&A z?Ce%hAW3c;OCY{(Nb^$sWS&B)LcDufIcE}ad_U-ZNfMVe+^YKl<=$lXzDo4- z*K(5@lq7xymTp0X;yGy}A98xR^;Uu>iW2P}Ts%4z;b`-{tvr;Jh!B=ZL2Dw%szu#t zT$RX?Jn)`a#o%Dsgoci10)wToKZyxbAOI9*^G=%13ZP_d{9pLwR=eSIYDL4Mt}kqv z&BwBCB6@MVko;`{t6dIQ%4J?^O;c|!h<(xUKATPRF>v;TDzaY4`B@bxqV%03F7IRn zPQekTMB}y>BW}O61;MTgoJrvd)&xXjU@oHO3G@X`Y+eBOjlW{`FaG@k0aHygTu73{ zF}Fc<<5wr3RUEK)yy`bd-j5p7&T-d7QYRz?&=E)rI3ekt7Txhti~Z-YArL86ciNr3)~&~q5*=+Ne|KoA-h)=a(#J6xhRtmNr5_cShgdA4*kcDLq<_ zw>%C%<}{omjoM+)-HDJ=8g=iJi|MvL(_S+i)6~8)>%j;tRJFnp*ERMCcr)qa{XZ`@ ziZl{Cmn6y_E0HxcGMFR>jes>edF8ck8k9jMq$RePPx%)7`(vw*G@~_LOR6!N#dPt? zTFv{JcEj%g_DwMmb>>s_trV=uUP`!WSG{jVnZB1s8SAjI8*7?_T*}Xdj)}sYI*^oT z!>$tR>$2bmq@9Ab8|l@Zr}GxjQX5>1GxF5)EbXqmE26Br@oLPMkkV!rbwK>cS0zuA zMTptAbUPj#4_GTykU(x7`X9%Nh2F3S<6t(oG1j#;+>et;4ZGW>LI~k|&C%LFAMH;d z8WIB>;8^df#)&5kIOA}T0#_@_;3W`EV0Uu%#PO|#gry^t>9?7G_Ula?q0zdgI)_S;D{~vc+J`LdeoQn-KeXVr#r}(DW0EnU1Ln*{co4Ho zp3%TyL%nJ>w`33Hit&pZe|gs;Xj7E(5Z>r`(mIY~cR4S&M$lV23^F_K8Tbv*q zfBy1Rcg)*theQM)>m}_s{tJn`#0;OXaX}7&WC_fGp<3f2Aqn{vy6gp42J3899%xfk zPz>-rTOUJmQ>quj(IO6gv#!p|2XdfUM7Ea#Z5k>)K<{mtp=hzM{dGnQ9w*jDmaDTc zm8!)B_$$oNfbh%-p~eJO-tYZK16QybfH^mMKh7(^7f~EksLtc$rR!Yspn)!2mTcEQ zrv!o!?ee9tjVVP^0tPAQ9WL;e-ly>ak?-kV76@^Yg0upI9h3heyHNq^hoRE)7dG2#?2E_*{*o28 zVf?*8x{dOrLW7Z$iToxnrD9%>Hge{~OL670V{2g0T)u+zS`d!cWef>tW{dZG2D|GK zw)aSoJ9UIXlRuwq6Hk3xlTBeVPNwoDgpn8jLxu=zk9dFnUAPAv9pktwxB>E)c4RF4 z)kjTdItSJyqzJ+Jzb&rH`RR-`xq4LP2LLxZqu5-ag5+>Om>RyZ zGwUB;NqK;FZnEYrf|al!$FZWSa@j^-I;7aOgx$eldMcWD@NXsH`fnY3@c~`t9g!FI z{(#n{&#?5IFn(z5lb6r#K|TA@J>Z^fo4m;V2DZn&&{&2`C-lIGNxfZ^u@qR$W>|fl zm(LK#q@aPy+i?VDjc_9$HV%r5nGGs*X-;e#tz8;f#*0~rLz)nu+e-CDn`cNe7=3K( zp8$4>^Ty6(GO+s@8J0>&AJYF?B0oU4XcLz#D4^fD49={$RzdCa>sqGqHcKHR`WBtH zTW&kk3s(voYFL$ZSQcC&-wa`$*78q>m>Mc4M5CYPM1GV_O(6NT7Me z>T>3%>ITkUUc2W)GA+W7r`^+=N9Tf19C)2};dO%ZE)dS)+#AJV=o$=X3X2TEm*IUXvu~H+Fai2KbPYdceDp)EOJkXVFZXjvLCn^ z=ToV0^``o9O%e>z z^9fo>q*tqIF_e44B-~k|!Gosv47Lb8-I5GC1KmyT&eTxPU7NZM2B>fJY?){xa0Jn2 z3kW$+KU{xJ88eu3LsbfZsEnTiFj*73N9PLyc@83n6rtH7nes>P(CI;y*b5mrE@}R9 zOiajpGX8_k^!4)CRWNc!9t)NqQ`NCkQ#z91w&(dN5!ci!G?%p=IE(`=tuPT#X&B}# z{F*e~B1(rWpv@n}#d`LVbc6+2)whfL$fp^>W%OG4flk$RF6r8UT0+i7dg_rrUx0U++cv%$kTS|Ff>B)aB8R8xG>G=<4| zl%$oI^J6j=NZK!wry@6fJwSfTaLj?|I=B5y^@jkkev(LON-wQ5c3X1bS?y;tVNm^q zozWQ3X-)y*;02nDTGi{>^t$4$xoBqocE5^Oj4l0k)py~vT-d=u=@>~pFqR0Tz~ibn zJ|EGgvQ)BF+vmFV(bNdKa$quPo6y}oAwhZI6aY$%RDy8)qgXjSE*J^H0u?wzGVNbp zuPu4{CrqoV1bkl!k&Aj#YEzmm1x6Z7qoT~-nn@lf#VjEcOA7LevR)rC?n^ME7#Dvs zI=4MII;Za-ZB7b&n#1v9ue={NG<3j-3IGgcoeAJ__s^0g-aMb^WhHp+7n*tRQ*DS# zdnLqvJRw(Gk_HB;X@ZVwjqIMcMB2;6z+zcBy4Ze45aJIIO zP&abK?$0%O@m56_IU%ojB6TtKA9F*qwNf<5XQ-uBgsUS2bu4djMo=j1jx>A8aE%}V zy`kQ~VcC9t*qa9Gohk4pXE~7NCU&1S)nV_9EF5Aq%3`~1x}`Zi1a$;gf`+h~mSb(} z(ds!{yTDeMv6<2`9pQow_23XXmA{a2q>!FTv9IP2w;=s_b6_==m#?UaVn-y@Dzi1G zH}e2%f%IN`TomTRmJiq$f7S-%;1BnKSl{LF&4|KKyjE~LPaEl(-u z*+6_5DA+lc$>3lo4wYqDg_jfEC2pKkZ&|?E_$gL3%tEgl3uz5QiAD5>Zw%$9yCLC~ zvB_JictG@Ib@5thcM%w91l2h-oMy?=pMy3a9a*gPEw{L8%uT&EG*gfzkh)+_rqb;L zmM~8*m>mjEDiO$w_qg1?BDKJogDoPw5$r9{%`0sl!!xq&gNsex=<#bi?6i~z1*>O_ z22uItB^V4+1rQTu6?^#o2;0oOpP)@M;>;^3SJqVzXy2#RdfgjWG{6faz0VrJUwS3c zJfvC@Cj~mlt-tU(90!!$2t*?lFa~6oZUg1hn;U6?hwO~qb^(o&PS!BcP6NkN@vIhAcEeQ~ zXfc!wje9|rH9Ysq*n_ys8W{H^s2iQKZn2vH&WR_(QXWc^{GnY{x_ zBze$5p|~}|g1nD92sAdTo3Oz~QCOpXhN{pLdIZO^S6S|d_8BBm*H?JR%6e&?JTCT~ zs2om?FW(BVKAO7`1iqZw?-ur@^e=a^-eqkrNEA8y^X+-G(2l`WgmQ=&Tw$t4%tUUa zim4+>WTQ^GJ-`{h5DfcSNA%u$StL6r z+cPz8fL5f`6Tsvrx#DOCU9;?>S+0RKgTKRR>KL)|KEBPHXfQ;z0cwOAZpyBKYU$`& zniQZZsn<-RK}b|nEtuDa)0tt!$N>>@p2PY)+T^%AluMDVZXd;8;E&75k(lLD5JxC z6s|m*VL$@D&DNmBDxp`_aP{`pCipe|$EVcc#$;sv*e#GH`jPT0)e~7$Ridg*dU(L3 z)#R~ExF=Oh(J;&ft;NlCzS-+1a=aH&;kR{kCDK&a;*RnYo}Dh#GlRQDS&={e$Moo}UOE#`kWj zN+&6ex%A^FdGm}dyza>FDN${Xic~ezBPhD2h-ThSYnNK;M)6CLkq` zIzAT9Mc$RKYp;S@YbFs$?BMGV4l{8CW~6(H%bJqHzAD2D8!I{?OP{;#voAS^=0>gX zr;Z+&KeOf-QOxQr1Ft!kCrO;KE4vH(Vm25Apy8DEbhnhf+x92#ml4a8{ZJ%!b7{6p zmG|(FMgzRZK{}j>O~-l9X*+XGczk97Ci~w+s|sjY$wSDPv+&)3n{{F}!X~ISsG7Ko z)^ye~aD0Nhkz}e*$$IL6!XJI`0youx(aHKbFj1XYSfbTrCCNvIA>UV|rcu&kIVJ%3 z{6*Xh@BJuJE6yEC(N#BfuQphv)AT4N9v->Bt?b8r(BG2}awefWVsvw;nzE6s5lz<< z6%9H3>Fk1anOsdEXzK($pz+3~lKei{$X>8zXZV0PZRVNv19&HPu~q@{D(Lmvuufbb z2%?PTntNt!AH~X~Vl~pue1vkN25cqYgPt_Sq|mlH$}H%VyC>MqmZ>$VIOIw}ECYq6 zo&%WPmkg3@oxpxoQ9_dszC_eDL!df=9FnnFNSt!_*jn> z_Wh{YCH@=bppm~tlF)g?c8av}hS-kVe=1a{%fyXSnq|0brG9PjvE*x(Op_q_zT%!$ zo|=1sxF5BPMhllEV2?wb=`V$xUKnL2NRI|T&hw9z^3vJ5m=R;CI4*5Z^Pk5Wr1Pb` zI~5}9C7Z1s3u)lWQ~Pna2{TDd-PNs{>{UQ1>PE_BOE|ZZo@woEE7ZHz-3*4WKBPya zAoHDE20+tVSWjaWE^9+ViDzHGMs1bR`)=>(Ap8laC;E0BfQS8w{&}A#@^~H6Cre<3g}dP9U_}Jf1{TpI0{+ zcGd}d$KJb!zd}uH1Vk0OK2h973Or!r$?J4FjS6vp>aSqFr&3YT@1;Of-KHRY6&5!~ zyFwKya!XoqKpexwPQ5iwHRhQ~l{wYP$Ui}^ziNdrJ_w#bM*;;B@u{^XH`1kwWJ=e9 z6qfsQw*Lo_ryLA+5_wY>wv_65Z+kGl4vUeq5`SKQH05z8v&H?qT`qA_a$p~nS5!{I zc5z={nS*5x)SJgrlgYqc%_f?%r!?f+3L>Rui+QeU$Q;>cq@O+@i9!$^vcUA{=%{| zw3;DX0UUf*72neqjhvK>@1KmA52am7Tm61Oq7J}uDuOOmvLJq<1q%a_-g%?D3|JSWtQ;G_n$DOWJD;Hbw{Px z;A*{?^Qhv!!L0lBp(^3+R&)nXtMsgvT;eE#1NK7%=?nDDs0pqg{CV{E`43L4M$Qi^ zc`XiJiTg`>`&%Ox)VV(Gi&8iqO)^p2h@TOpZo-f#&Qfe0iwGmt4?t0OaODr@1$H8@ z=x0-iOMFEf1QE*omnSO>K7Sb@+US+ZBj|Yy3eb=ul_z%@k9h4v`v1-FHT=OU^h4~u zLP1Wcxk^uk&UvL(4foJw&w=WUwDZI9og3{F1P_AJ<1vx!jo33YX8lE+&9W#x`dd{h}_VJ>FoaMJ_LK;HCL z{^so`hx5(R$1u>rA9sFq81sYJ^`idEsbvw|(>JH}uf`-fdrSGPg<1J6@QrdaBfy-d zHZzS>pcuAy1CZ=GRINc_(>)a-jzLKIMe`$jr;(mf8x^osqk|5UeMhv2wt4mVw{a=c zd}4J87eaQcs41tU7vTJYVS5@hyt=dU!%ms%D^;$fc7}*R&5pAia-0207RRI;nER(tS) zatk`EP9_34QQVK%PjBMfq^&}@F+!Zgi)17?=1fCsxQJCP7-c|$4YdU8>wSix!q9O2 zY(yAjY*C!e0Y&H;%rBY0jK2|?>Ab)4LW>cq1QpISYTA0E5c)Fu0Js1hcWl=Kt`8Mh zoz10L-E*@u_EYIh6^tx~bO%H$FcRbP5dBTF7qH}-&>=yU3__G!BB|F|sVAm`!X@5p zj|3O?u@6mM28kddeNk76FS

^&VOzjS=GHrnYXB2R;a*`k_D(-xkT>M$hP{Z`5n;8k6W4jp9!M~rZI@_EeRjmt3n}a1W>XUBJLU$?b`$?|GU&C$F0Mwyw)w54RZnw*=rQ-G z3@DdD*l5H6cYSf9ZNGE5%!F>ws~Q^Q>>nuu$w#cs-lRMv@>P%aS9&X~|%Q)e-o*e8rSRAV@rBt$-vs4&l0Yrr-49MV}^g696 zhuA+!W&X5TO-?)*16Taqhdp%gMOX?-oV}RH#kR#eY(xe#xgEpW`6l|Kd)V}1cvtM7l18jX;>iFmNfsQY$7{a<5-XGh<(G^s@& z;Kzp-{t7)Y$X;=VS?V%IfF=N(7)qAV3OYy_?YI#xh6C7@*0su; zIwEWcOZNZ={^wi)ov?W~(*O;&`)8bItB85PNo9`b+fJvM@OhuDsL~=&R)mcuO}DL z@_zU2l&1)+; zKMdVXmQ~yaNBA$$obu5732fWKPaSG${w$JFvdaRd{K9idDxqXwB}LNB(W56&O}xQl z%OrYFSU2++tp~`#F@b4TSf%jxNjT)lkAvxSloZ4vZ}>()#n43*J$>NJ+{};D=lWtT zZMJclJ0I&|kHFU?^iJxz;sku$*@g`nZhXzY@#gD&Ip29t-ek;cU}n<)FS+HTUvasb zm~YFtZ^z1%(Rwb>o8RA1k|iK{~=O%f1L9_l+TaSUYXF3x#*G1!_&3H<_T%2d}I z-JDD$o~cg%rSfzzu?FqStuxf0;osmd?1MttHNbT89N2h=fp`p=;*7iH^Lntu_^|;ML>LEZ?U5_ zdm@yCnH*7`uOy9~j(zQm$>9n5IR$1_80Z)Z%l_0<8nLQ#p(zLV6bR8|-yM`3GB8fg z(nqi#-Jlu2hTh(=^HH^j3{6pZVSm7%?1nnI@*D1GbFAh2Q}6?wkV{H4!m`IA$?)q? z)7o?;1J*Qj3ahO~&u{O8bgF5PHt}Uqt_G#G!!M9*;psciFoXZm1G~?=+JUqmHqx{2 zfBEw-@yj#&y~1p#QBMI5n+kOysTm6>pYq^=geeO0fPg2QwX?*~V<4k4?Ss%_;5UY}fT?w2PF&a@#i7lF{cc-Rx)mqbi_QfMF9V7TC-_C3q76zs z#N){S1@f3;ZJ%s%sE>VPl_*^{V2J*A?i3K2dki4_@!pn~7)x&_A4>6$RWs-<| zA??=!Nd%NLz$KbQ_E>7 z6}3M?aA+oq@tVq4g^pfoiAjyEdzF9e52h;r0u+JPhrTimZ#`x7f%rIJ!_APYzIv}ss*67mbfcX-l!QGPEEFFt=BEDcIk;jc6vnNRlW|)BzM(J z(ngtZ_KE|_PbGqP8^ZCSL+1$~%ZR00O(x#H2Htm*^<0R(J+RW>g!dj=iviLP+uWr= za25@gl$C>Jp@ywt#$hJAi%NW?Yo`?P{qD1|Ht8VyVNWItbHvgaSzo?fO24v zuJ{7*1gOxX#(orouXY84s~>=106;*$zl(9J zcA3i&qfMSM@objGKZCgMtx8mjWiQy&=z3Gbo59R*j zLt6NETuYAnxjuZcHB1ZLQ4e|7*^lQ*JJZ5Gbx+FBz{(w4zKx9UYmGj)zx8xXEnCt0 zR0yusxJuTbR*xi_hG}I*0rtuz1Yx~TFlf>(fQAb8lDOCZoAd?kj0lX-DW(K zTaN%~L9OdaQ;uW$qR>GE6&WQ6+W{y;El#u=2_0xyI>cr+SPB_fKU)K99JE3N@1k8U)B)j&qrR3GuVPp`SzA$`|Vt^NZS8VIp5gK7j`SlA#Wc zAltIPYB6yB0pSLSXT%;7)r-gwb4V*;+O#>J@b?}(G0XCvt!bNK8D090jDne)+Xtuw zA1Zel*vi}@|6aIq07dT4r-mm>2vHglUSijyG%jp4TRYsl=eOCG`Qtj;+2v=k3bX$G z8;~kmiK(#)>ZPx~Y|4C)R#&Q{YX^W6?8aBFZPnPBq4&#AILK z(@h4mfLeWQ7CQ629b(#==^|*c4xSJt8_)3Pi`SM~1Lwf7;s%-q26<8rdpafiCQY4X zZpPoxIaVNB`^kc*$6rac`n*^JAZz8$f~3^ z7r-7LycwAz+n%Z79aj(EP`mI*bQ0VUlJB1WmO1^v%AXDe7HDuj(p`h9L2Dzc;UfEN z)yc%gi=?b`o`&YjdZ5w5n6C2&Qt|@gC?o-U6cGzr8KLy4r5jeQ)meeaxsBI=Iu&D) zAEUFwY3~v&REX_6EKy@O*OgSY{nB;~-3#65Yvk@a$2_dZFn(G~-Hs8whYD{!RG_wh z(G>0d>ptk@X{P?#7!{V^Kf*7qM}qM-;%q1S4)_UN0XP-)F8xyyyY}tkf{S4C?8{>{=Ux1U76Z!-m5(m4iO4K_WA_4l8K z#~=}6x6mx_i&&3z@tiku03s;}Gm|@e5&Zz`glZ~K5|06ewk@l@$!S&oFi_Am{p|2!{OO| zQ4YlU6@ZvvVkwiHT$;{a?`!)li9RpU>dzh6Zoj*$pQ1!mJ<=Y__i0$|*qJWoPZ8^o z#6|&7ML!SveoS$g(3kCtNi-AofxKo1syB_Cn0w5|F}S2-=+8tqw-%-CorD8pWaNEH zkaHeXVk(%ip6h@Yde2uNcG*{|6aqT*#!0C``|%z=2eb!LVBL~eN4zs6j3I4}hB%gTYN5*Q6GgV;GHgq6Fe z6+BlaoA_dv>Iyk_9!B9hi~TdHwf8TM-KD6LqC-(KhXDeb_v4cpAOWTz08@eQfMSHX zi-OLK)B*cMk&8PC`FbwI1^%j11rkMr_Wjg{I;8tve_FdwPW+6do{mdHR^jIPI_@>% zx#gN?TWn7t!*2wQn*Hxz#>o@8Kg+`UlUvj|io1l3jeaJUN8u(NAmWOrX@>Duq#BNW zGexW&e*!m%mDHM@;l(D^Z~wGm+1+!p=uD45j0fZ6RSieGp_1uIJa- zRLjAKbR3(nxyvFS&Ho{Ok85rq#l0ag{6yitVvuPZNy{^&-Q5@aUYQ;y^6s5#>AJ1*8_GptJ8dpb@59orPOu43?bW&q_ot#BY{R z_JPF&YYs2J$;u5`&l5aS8al$n7+Z1YnH3N`*-elph9yBk0V^Fc#D%Wh1ud47G{4CY zv&B~s40xaoF4dua-Ac0AzUr$Qo%^YsnemK6Kjih9G^EZN%E1T5_^i*cXau8LVe=Qo(k7~9a$@? zf_$#60gv9!lAt?}f&j8S^&E4c^kkr>Pa>sy#{M!e5MuC_ zhEt)~h6xhgS2C(w7C_J~L8N~LKEsFZ3C5|61J!+#l9@5{N(MZt2*=;Q@5tg(JQV1p zo^c5EeDNecm9`6gWve(31oyS^AU;QC;w0zG_ zEPq~ngrZq9#6e(gnttjBU1887FWDHR!cg@4H<_aHN18aO%kjig<3aRxrQ^+f$Zv2~ z6%Ux5o1t0c2q8Bih(cw4 zT0GWs+WH@gJ!Ai3;4FN}=f15;wl7CN!rTX<-;aPNmB?;Ko;Mq#B#^rYC`s7Wr@!in z#G2xN3g!(>tcZdTRd?m_WwkmXb)ripq>8ESd{vDRyLceNzKw0-#6qN$AtkF&4Ido6 zqDM?&;p=>R?g-z~_RD0H?0eeVFWbQ%&*r|WF%>Rq1seA0vpJ7*SOkSk)eT4et9o7wZD zjA1268;%eE8?0CoKR8#8wT%a%%_~WI@g`p^1GkU-fZ7>tgaR0;G;mIPsl4pUJ6uzn zgQFA4$=JyW?~LK$ZLf@U)EJ+?@znpakw^ro6zyDSVx+37a1qx5yd=m2e&Sf%j7k#Q zd)@fxP?3*!$m>bB3irOi^4~Z&K=Lq>X|YK~b27=|Hc1T!SqvE`#}| z?>R$R@;rA)Xxj(jN}}2Y`kav9EU~inapboUDVB z%-#jc0(3nM|6Cl#$dmJ+ic4ubZ@t+!+9bS^;jWF$aj^Co@J*P_!l;5+n7|pV(-7M< zVkI!i3QueB7SY`vvRMK1U{(lYxy*E~fsU98%eVZ|DOVaY38*=c@3a??E&{?kc!CS)X|XB8H7dVF+@lhaf&GQ=Gy0C03cJtMtGJ8|+Gz zzkjwt99&UswENluvMSKVYF71rn^)dvRhMdx-ftzJNhVdSYROj6jf-1g*8FS3TG~pgT4`h))ZErP|!@e*#?b)Oz%q*q? zZNpE2MjGGEihT`V3+wa|9cdQ1z9L+ri#i1YA4ZWIqp>0Djr9G}Lzwjg6wC0U9e!!2 z6s1-grzlWsxO|q2s#r;Xe95-KQW5bspW|_a_m9JNK*nLqsd2sobEhxCd$`=a&X6%D z>woFTXL>$jlX04=~3GzfDRh9h^YhQS>IQ;KqN}#NmZ~$#z-3^ zg&gjRmoeBb*7$c|@~$JCQ|MH~4ox3G@q!wDhFL(Yk4i>b+!0bzrxKRZT5}5FpLO>hyKrJ zA_VBCw+=N7pJ=h*h1|vDlaS-X7BwRN`;ShyD5`oAC2)y^iu|9E6K|v<)~HzlGxQ5N zyH#Nq=k}bhG2JJ{y5mO` zFD`h$1qU{DVm*3Y8PQ-XZ(7ZJtElQXT>m?>y*j{gD3O*S7$ep6k1zC8kWA)26bWQY*l^ssGNq^1Rh1MbYs*(Q$E46_|D6bu6gWYSI$wLhWM#+nEHf) zN^Lq_eG#gaO|y7RSL?HZ5F!VI-)83*{LWj0aG9onA_M)s$44=tni9j?5#@GhFBwb8*UGPP&*L1Ib z`_ZG&ThQ-VTb{EuVE+x;I6p@*xNBdv(27TLxy0o+?ACPtC(US8cyP9 zE0B3)>nt&|+^z}w?bI~o&E2PE(|b5lqt)N~;)BUX21fT#0)r2+1ROmj- zMK}qPP^DJBeVmG=Vi6sya3;@oxaGJL1P}xyMHstp@lCkn)O0@L$!uavch{L#+>6u( z3M~i&a>NgeM_8ARts)qS#tlFo54sT4erbv{(5{U;E06z7(=rAxIy>@@?1-l2@_Z|0 z<(REQwa@{Rf%wg~N_o@)j3UD<^U}HK$y5KQRg{O)5Jhsu&i9X;qgnAA5ExdPHvb7x z64SertuzK(!Y(F#kSEOa*^cMs8Ty2!6Ue==8x7cTV}E?oNW)7OKrco8B5l9+Od1KV zCPHZEOU=xi?#Y0M@WQ-U))Xq*Y!QW_I*YhU+Gwa`jCnif`PYkA249@pz$@V7E`A@sqlkSQmOmw+*raL74c1g^Il2l0fe z9;14Pa563vEfxbMTo3l^%r66MNt!EH-7yNikgQ+`MFg@LebpB-hPoF@$PNw~ICl8Q zpj2SW;XRUZJz^1tw5C2=RI6D(_Mu9}mQ#Zz-c!p>)%fkmYbLhuA6d>r@fH2lGTQ~N zdNEu}1s>+5z~|rO2;VWQ{k!7CRDb?eR^KBHZWNdDy~)^^TylNyp@UI0=&ametD|Zu zVlGB3_U7v44Es7FS%y8ndCcT=7Ah0t-gkiRg&0lUb4|NFUg10 zdBTuc*oDuDTH5&e13oi%skr)8<8$LCWIyTG3U8z?*B#x%f)L@Vl>5`i*eReLvcW#= zyO#RCw5Q$}GUWSsbBx1f55MJn!?y_=CMkss7=om9nYN)yRxB9ln{~iS!9M~~6_#Eu`Gpwh@t>%f3}-v}*bpH9VR*iJ7Qn%y4q6@VT6?{o~K96Xaybm7;PSR&5FO1cILz6K}e zsZ^6~KgMEbBO@E&zHjM)`1CY^;9lBm;7;V#W2`&t+Uav8+%C z$Hv1fE(o6>6ToV=4cZ4HUIlIMdFN}jYnIs_0cpIOOV@m#Viyr3+dek2z}eHvUKdo( ztr$%a_6w}2U-8<1ldMJp74Y@M_K?cmc(!3hd+g8J3N=7C^-nLaUgr3aWZRK&9_>E3 z-|CM&e6(O@s?IK@-xOLL(VIA{_R?AjQb)s0d2E|L*g81cg}W%{Enzz>wqN?tD4v2l z8}ROse~KZbp}}6UB*r&)X-E&uU*A}(+JH;A4dT)ghXnDNjN`}-ee0s|4~O4z{s??> zT-LAQk-|!Jdq?Vcc?C}HM+<`D0je9*UYs9RqKPT+YR2gO-tk+}H6;i4Z)>((gGgNi zCwB3)@LMGW(~Kl0BiWJ~uxpjd+FL4EwEu=q6cz4k({X!VEI7po{JP#Bc!^yt;_NQ_ z=#h+G;Sbb%Q{@WGdJI5izNZ2o=L0B1&-(1WuYUp;gdcPikQbM?-;TxNs=aph%~HsE z)bwq;XMhI5lXW3YhzF(FRw}uEY|vebH~#fX9l81AZjDnB>IHfh&i(^-XkV6_NdS9i zMkEbYdfi%q!ucXqQF7cm?&vGybpGTd4fChVF8IX7DrrfWSQL1pU!Wfgo7)ZA zCpQBl1AP72(lq}fsJPJ~>4+LGuG#M`PyyFOZbZh7GijFo<$&Ks7PLq-8wxgAQ%vje z?d@F{?vA?V;~0AKBkP*y*+3>Va#kc7bi}&q>%!qDU|gor1jVhdUYsaKQv<=cj|uOY zz%6BGfJ6*hrv-q(u(Xu^`i%mxeKiG_>W>O_wBH%v#64g@pwogP3e~I-7|&l?{3!Z! z`60rpf7nMAV)M4MsfE;h@HO8=h#jm>+-q53<&Zc*iY75rKL|*_jA*)yC~{V7(pqo~ z{GKrmOTW}vb}*z0d-xhGG!uh+nm$?T7~gbUV5e$=PdCVz=ecx58i_;>Oq4mDm2)Do z+^VJ0bT(Xd3u=8Pt(;5lnF?TFJ3U=diFjtTtNpH*FO{lp^3`%Z))6iPvy;cjY~XJJ zHiKeobt=C(V|t5P5Kh@~6l-@B=~JU7sRvup)X}OwFEIY@e9!^r`kf1@9ZxcN2b zRX6@nZRmmH1oMNwTrlocq-Xn?QCrva$<6kmhl2i@+CNrO?cYBdlogeYAw|b>40Bkyu3hJzdSOb7_*ilV%{%)Y zRu?tlWv8g6nwz~B$d(WYX^Wl=o#vV5tSxTa&fdPw({#;r#H#Mp#COLJ;!L_6s1AoX zbA&V8fisa#*#)v}8yA34SULQ=G3yM04T2tE%dgqDTQQqq!=vj!V0|`!!1U<7$0`{LznkaL>ilA^eBMQ znjH$@y z?!Gemg>WkkMCTZLNagamAu0hk^hWW>Peo>{VeMDR;-_73{d+6R(Tr=u6BhQ;hhf}X zc=#M)hn7_>hE7qx6q#YQs`L0;n?4I{iwOQ3Qlh;=%1pFM$elo7x8+Ox;#AfM@CF9CIEL$j8;<*WT(A(|*>q4a9+>rQu2V*8 zY75U$sN^eQCv6s#j~kIok*}#P%+15=kt;b6CsG%H8v~;dyGTFHWey;b7Xi^u4nO)- zcoNnkRWTi@v?{dB@v5hS2fu-o_kyBqHTpv$i-Y(2|6P>e!1~V|iV!7Gwlr4eiVLdL zhhU)~8+{lpBzbZG!oJ*2(ATXuX-2}r@Z(BR&q!#ad&{g&rEjLL|KILkGkp8t@pd({ ziD|Kj)VSFHd}CnEMpBBd_nLt4P4H@rLSE9}CDJ(XnnVyMidjLHYP0z+%E#Zeg~yai z0RUn%tpd{=b5m@y2#cf!$ISWZXt>b0OjM3*h6su3bM~Om5H_Q5`aWT+fEFvbKBrMBR0z>B7di z?Vw^p6nq+{MH$B5m!rUiOOk7%&#uwSQ+QdW+PuQQ;^d)xVw%nR)HEj$C#38#u4p#6 z1*}jKIy6`x`M)+$trbJ%ke|>vh{iVbAzFwY+dRugq=PA$q$(Ksz_KO_JVaLKJp~al&(X(D zOPc+CgYCnRI{=6LWOO}Rdl)Vxq!4+dtl-@g=lz;rLQ>Rx>u+DhgY%ysP9tD6W;WDm zj}v-@<0{M>WZ>jEGf`!z=W?EZ(Dxf~UW2aa_m8lgni)ldNhe!A>nGrxR18DaKpQuf zD%1<8SCcIys(m{D1D^FZO#Z*y>-!o}4DgK=1o?XbK-fahMa~i^%P_b6DW^?Zh;lii zWVV{VJiXAMz7`uI~0uZewzqD~2*a8MbG@7dY#2Efsj`qgC*ZSCRsy>Y(j3^{R>=oZ>Qe3@ws;S*GevmAKcJBrD}s@9L1Ov$LKjd;VY5R3>&$;0 zoGSxA*0S8-bqWtVDaN`}@{RuMTd)i@CItfj67(ZGrxNBlN991H(DB6qBG;0IJWzO< zfzQ4+N&hdGkKceGj-D{{!r`lIhNDsw0~(P%*KWQA7L)-(6@CPR=yZ(HHQzjg`1$l~PHFsFX2pq{>qjrT|iEob%`c>#r-MEukTh2%X~pGEfJ z4~y{li7&S-x@_*7{wFZ(%->(KhUVB3GY3eZn5Q3ZkduIxK+5rY+dCgcemSC|fsgWy z9}H2hSov1@K9By$1_p(;7DR*n7fHOLsOd-F!DH>`sdsQNU%Z2}#wC}mwV^-QZB(lb zfUf~8e(@Y`AZtKc>7mc~yIRpuv;rac?lW$fsKa7tHcjs7K>WMKe!Ww>$pQ{;AufN& z)59ijCj0!AY&6^r>6JzcR~oebo1aNSemR?Z_^8B+NcBOOkt zn7jkFEuhX+?v^h%WOEkOuY@8`{&dtvDoyoif|&$P)K<|jx+^}X)RdAPGlScBa-e?s zjtZ>TzwW7J6gV&mfr*8Om?lYrH3P~I55xOa7H71Prn!4*{UbH}r@5lN_|w!i&?3{o zEpFbE-2lsiVnyB6SB@&B!%`oq;a^oHM0rs?VnNIT8F#F3>Cih@OC zxaT1$yBWJila61(%lZ~dBkVl<=C{~!*7+q>Fj_K=*sbnqg#Ax*l1Z?*V&CNYGcQ!Q9Xa~kElMrb+1I4bMg;#*ygA7zK;x8`{is^9Tggx`$<(ir1`8(K9jvPa%SN~r)fSp8S$yGLpKK-_ z+1Y|b2`|VnWv$$a;uTF+R)-w)!)YAjIz5#XR+m>bgD@#^g25`9-n}XpWWLsm+ z$#`_7xxiVqfyn9E!H&}bqzEX~4gDq}Bg$F%QOd`U0+d`2Tpdb>_@e+>nqR~6H|Mg# z4xe=h`53~pwY9dNcTKW~0^o`@g6~&hEj8q6Y!oq4R|2{>!>rk&mN}N1BEutUMLl(q zV3ol-S1+@bUpO)Wylj&~w6f>xeHYNV*@W84213yHA2)TpetZqBtUE0&V8OQCnKO&z z80sZ!G_Byr5wE^7M3)8`fy}k>=oK}1y@8#=DOd4e^BFww`7I7{&-18B?@vMOrK7;& z9}g5JPFD%-0c3`(3QJ^L=2bfniy*2wy{PH;F)!}7qK&$nNhrK$e9^Q9qXB$Mi#Siy zn@g(kB~a=T;|!D*`$4zgz|=wF@memF&S8}(rG0J{>GS9$^8~DvmMgQ70R1`D->A;k zAht!Z9|hz_;lq5Gcv1X-sxpV>K*69lXNOixPg+ufe}R69p-jbRio<-xm{N!*Hcg`K zjd%lJCx~JG!-L67>X$yjIa|?OVCrmIk)w4Da7N=cEtTP-9!!KH77|6O;SyHr8^Z0- z>&4&Q|5wyS8YL1Ov_mbx+X0l43u>iauSSBM0%!POF;1w4h236Iv4`87iyIz}v7qQ^385y&s zNaV_D9p_a27S(W#1;+@CAN<249d z<~od1)$BMMrj|56y-!?SeHLR$EacGXFITw<`vlA)8uXfouZ)yr3hKZo&F z2iv3%`oqhT3!_`QIL;YKZz3Gm28ArXzkK4g+&g%bbj#xmIJB zmvd}19n9Yu5Kyuw<$pNSyc`qDoi3qdX^?*(hNxc7p-PA@FY63ggx$A}XX9VgDvIZAbAh3tHtW6GLrW=uUScU&vs!dkYq zU0CFjlB{S?HD)!IoHk=voF$h-4x7u2Mh+xF@Si8|S2W3W^@2mKt>u0Htb|=7_RbFQ zbfzEf;1&N?L_YINLohVJEN3LCH+?Eyv`&545CihAnZZB8lNfmNL~@UGXSKv`L5}qb z(Fp;s$Qai4)hFs^!h?kkl|EoL_J`K?@{o76d{eSKQ;i`%37*B zMZ9U{1_HJhVHVm_{%`Y4zU}OLSy8L*BTse&>dVV0rEN*2icYLS;u+fpcM;D{-RY8#yrh%j-G@3l?Mhs#tgMX_Ws}&uNY~Y5zIt~ z^gP|_20?=>vw7aDIJ0X#)Gk@rm)zbWAUCn7IaPKaZf@y}xdJklaO$Wchu{Vn3E4m44|?qQFD=|yZjp4R z1itaL2x2QI%CYGghk=D|^#M}N^J1smpOUBtfCn=6ig`ap?Mc?Nkd`uZqz^lkbu?3O zDCDwYlMsAym5=}>^4y{^-GV!QZ!xA?ZU|ni>eDSv+#aky@0-K8n7|DPUpAt< z49BiK^$}fLhKP{$xQvLkiNM`fB_w;;#8sPM$DS^!C+Pdw?P;0HZohu0U3P^{Yy=XE zVd0cj;gVf5lD$b^Wu_;Mt0C2NaGoZVS-C`KOhdO~*8fbs_-kh$mGaur@Kr6PYSiqu zek$__-?u+(`#^Cq0aWF0dd-egs|edWV%c{Jmi~c8Sn6H5sq6hoIeUhBT`gj2^-wdV z?efY9=RB4%pn zsk?(b#XnX?rnQE_V7EQjGNZyxNc17o|GSc@Ds-j#M z>}#9mX5@)UP5t+<#<;F(n(VW~82t$k+c}ojE*;)eL(GsrlK;JUi`ak2P&3xtZlL1b z#?zH@zdK|DPh#f8E)zRr=VQ`mD_e)p0ZKkVD=#uBrCG!&Q zNKu4$#WK{e_wcq`)(CyAT%~@RSLo6eE&f6+^2ix&BM9|A;rwpie(Gi~l~kLS)(!Q< zq5qlV%GPJYog#pqb*kHcZdWyRWLDV1MFosWS5_#9V%yeWfbkg&F1o&T3B5o^B*p3& zdQw5IZT~}%;G?B*UhvgAMVZ#IM2V&yNasGqk0R5%Npe+O;l;tV(^!|2zbBSQHwMRN zw8*+La-1Hf=(!Zjh!_hqV`Ga`Q@@l2xtz;Qgs-u&w&@j>wmNh9^tquN+*|*u^u@uo zXedT(<|Vfktd`W(rrFZVVhLwu%)a?(g5o}$j@9(E0aC_gb1^lh21|guxxC-%c~l?H zgiaWj_qB8i8**DP?brkVwdSk6CE{`%%U%#VLi)sKjTGj3S6r^_{yt8RKzjYI9drbh zy*z5&Bw8M;)D7!$2kz;ai|kT`qp0lSi+H>4Tkt4~g|%>!j0hx$uPZ>SeivfTw$Ti~ z1%SPYakwsG`D6zJ`2l01Bi{{i#YfO2#A1HXbd@Ba%mpcL?Yk#0Wx|Iyf*M)UNHSLC zd6Iv1W+8ie<_n>SXnJUrkPX8d6)z8o(*3Z>{XMlQrX`W9x(6qh7i@2Lb(UG|lNVU6 z*h5e0sF^>Rg;DjG-7L2@s&`<>Zsd0Dy1V zp2$LGBTc!lMY4q8;cf%M+V$dTAiPTDdc8|Eg`t_-L8{F6saV|++-IubLq5-ZUe*n? zy-hP)KA7(qYJaO2hxLuej3&)yp>H3lH+h`3zU?I?8Is>a8#UjAx2KF8)lB6k{kZ5L zs3*90iamytW~T<^H;N&L)a+mLTNF)kb6fz3UmxNEbr=?VgTN6jYr4+h5bCublNN3$n!aWvW8mKhLo zIDKQNJRhlaUgtaR#2k6oj1a>c_opg_8W zU1Y6X>&H-z-_Ah6{((jCGGOv3k-1LTP19@CR^~MBzpn|-1mgPu)`bb3+yuknrVg=f(Y#tzxLf zm(&Z36-1LYjJmk46`e_P!J|3{%8NeZ6rNnD>33z)_Yeep`os*sEc0y8BwKc7wkT$@ zF^-}H&4sNTkq`PaqhQzygOOr;D865((qX)F_M+++&mmw%sSS{mfLs5lec~?`nbE?? z7gh{iiO33_NcV~Bw51i$2!(cvU$#oCm%9yHn2Z=8RCekiP0*`M>#BY*?hmCm#Gcbo z^EE*VyMZog$LF@#xs_M;kB&f;$;v>EjW3i0=0uNt-R z?lju$cz1MAcY<}u=)#7Qis0x6(VX-G54<4xM(O)AVGx)Zq!i8Y<>@!u_l@u|NgB+-8W!pbOvb&0FB}oH-kkRHOPUYB68`G*~f~O6At2NLWUw#RxJ2@l! zVHXXko`}dWUv2B;aa7IyGHK6#kY=G7HRE?5DUuUinknp_)l4GcYR{1c^wOZm-Vk6s;xo??(RF3#O;cg42AST02xZ~} zQwfQsZZo)uRQQj`U35w%MB_&Ietau97;l*fio8GHVRA4h5WjwucA1Y-Bl2wFwPpLA z)FtU!uTpd0)_er`qkvP#mK=dnEcDg$)8v1|Kc-Q$)A=d*ghJ^TKcyX+XBt9WohQQx zoc?C@{Aab{6~h`evg6qwF%$j-wM~;~neZ<02UCi(q8|3EvmbDxKDLfMDn00hiPC1w z2D0x;2jpvO4*|9YZOMV{u-0(^^7Rxk69d@Cv6E6e0Q0_tK7!#6A z2k;hdW!jlYQp9+o&nV8L-_yj2P4V;trA~V8)9B(#w^X0sAs}eQ1qUy-kFPa5%at5Z zTx(wCsrX}=Sm5LZ?`;voD*|eG8AnWX)Gp*63Zceef6blK0T8?dU6}Ct6$H7QN~?36f|r%FI$ z4-FG%ug>c~-~drwd#XSjO!mA$sl#3ePap$2HF0bPVLv1I(ULpQ7dv^nQNBS#Q6I2$ z;_9V7)X6K-qw}Op7?y)l2D;1AmVX{lQFE688u;VbaGvDsor*M(APu>*%;r`AHou^ zCx!bJvA}9kV1E6>*)!XzS{x0JC&1;_#qm3*b|t!vS)Y9nybg$YjZCN zYy(yL#e!U(-(s^@Ht_xwE7m2H#9n==Is5uQwEK!QlDPt1!IzG-ufA0hK0Y@~??lyE zoPbRX-1_Le1tw-w^@2-r%qeKD0(`(ZJ_}^HgOW$v2In@*bB5J$GjJfMN+}dIc!0;J z3fuo;O=M!)ut4`WWqGl`iTWGbz;&0(OsBRIt=zNxTHI6X5vsb2X^}U5do!D*t zg8o0s;g=kI#&U#(jMB|#ScxOYSC!)VK59sJmU*sIc@ibyBD{} z(vx09V@3;3!CZV1^m zm-U*b!LkPPRJ6Y_2M~%SEu$XvG~>;jn2@ey7JQpW6CmIQI|K&vPQF%#R!)6AA_sY+@QSN{4U89^LfTumxF1Aijfs?`spU{$vb97 zeg!BZqkX!0zn~IkK6{d^+Cw1S4iC2fSfl23I=Ywtgvt;fiHg% z&vV(k!Nvq6Onc;$P3ukN3-;OPS0Ef?Cz-cA&UYc?Xn3 zfH2VV$rxW63!}NG6=LjO5C3^jj2G=vh%1O1?M%OhIz&m++g*i+pbE;x^kZ%!EdjBa zpJTM}EK>od)=+8ilaba(?(5ED;_#P6EG%?7Tu8)xj#RfOc&! zBOBJgAuzq21VI@?5SVbNyqn1bjhBqD{Qf8z)pE=*1**;u#%)u%;e;$@2?!uXghQuE zLF{ZSqbyqh5%I+mh(0(YmPyY0|qx(&oPj9`q@(% zK)GGd|74lXl3oEC1a~AG_p>Cr1+7lA4s^?R0%yQ2h6M)#2F$DOPneM6oaDq|CQxmO zBjB*{1Jxo*9+%m~ee{JrbF7azZ#C4N7z!8gl&6R}u%Ofj5Vuz|c7!Zsts z!nDC{S2h(#WOA}<|6cJXNz{WEFsA+z4G(oEibBwgsO@&spALsaeSVgrGQ(uzL=) z{~j7;r7Zk3hwkN%c?T>pjFm8ul&FWUuppxZhwq#mt3n9r^v3r1;f`O=gM3l=deUK2 zehUXlbwzXBBX@RpGc-c(d3Kc#SV5cq8w$*~O)66kKbUJ!pn=T$H-OWF1vBqj(GLsY zrfywoZU6}aaFN@624!9B=SlJ0xE@AP+PdcNnIU$=PRY+2`BYp=EH-MbET&W`qC;20@e3+XR;ar$0o zt(-1Vm&>^wFu*6XI$hZKv_GYSI$AF8D?umNHLc{X7oDpacI#uy((C&z1k(F~t}&F_ zKvX`AJ3+SHY5_^BXjPJSPpaFTTjhNgF|bkC;=3VAXVE8wIhL{9w+3;blZ{RlnmBzm z_IoB`-vC~G;jhYV$8dA5oIatIE{O25W6KiprMjK%A?E>-X9r z6KFHXnF1FVQpV45*19SUkwC7W2ziw5&Tx(D^n*pom?UQC_}xO84J^HpV!SlCDM;a|Pm zP4;EbZ6)PSV70|suYQUzn`X0FM3jMUR9s!-qr-1!q>t*n91`>DXyvg3kfcXWnzzmR9O+w4Ansfleugt=BWOaDJ53TAc#^7ZFu7h?Gn&gllgM}4 z4!`bmHms8l-lJ;*mXgepRogUpOdEFJhYccMT2Gup;l8ooZH6h7HtalM*H*%=!=zr9 zy88M8@s)R6M}sE()P~q(Z;#&>eN&Z(#%Sf}Kp<+j(MtrvuchUppG6EF-1ENOb7?OX znWwB4%#p{!|3sjQml`_Tz%X3Evy!fTzFL1Q;%ud8XNTRR z%)t%P&CDfC{KTqS>S?qduKxC0G}yF6M=&2_p>T2Uf65W)07NRGy*I+6f=3PlilTCVOP~ zu+Uh4URc<$`t-z;W1R_89Jmt^;L_GL!aP?yXfY<50dR!dVLYA~cW^~KZj#&Pry80H z|D02R;K5!%NBq&z)ax*@Byv1ZXzM##Ysg*#C}w~oH97#*Hyw3-+sGAxtY%TGAr9&+ z|A}Wq^J7^#nvjZt1{k!iU6Q1fN;${;aa6m7-GZWdJ(~D|ercfvkzFOx_*3pXLw;te zJuB+87x;srD_1DWsApRrKI!s`TpW6{>Yp{QMwy}E=&SXdG6Qo&|95ihF&{zkYI?F%D{u96v5NbP4!+ok;0-iY@3g{sa{ z)>%kn|BHh_;rkT*)#c5#(qW4r?viRA69T^Khv**I=n zt7#?g(KdiKtIR_JtvUe->P8*SbmaK4@on@cd%6G@)6y=xUFY77lzo0pDCHxK7IpYX zujt>oOcS|=>{$*X1z!&MuZpOyJ@@_$Kf4*tK6Qm5a4p6()Tf|%f52W3aylI-y&~d; zqeLMlLDqkiyu{wLriFa{2whwRt@eV8%|c@nFR1fwQp(CJz?ZXDZd=2_1SuRcNGOra zlpkL{#b3ZDQM7){YB)uxv6 z5-H*(-C49xq1C35zDKVWEazf?921`x$NJ*ByU*N|UBcubSLZ+}2bZ&!9Wdi_p2SU#Ah+42?Fp~kxxl>x#CxW54IT7OYz6(CF6&f6DswHn_ARbt{1JglDKWC zG)?m4T8JXE4pRwx*amzVUgJEALZhcibdw1L7?HS3QWX&8nqyZ>l&RC(NmW)*KTQOZ z5)yS1m%f;e&Yo()7qV;3J5auR*WBws{jkEDB)nw4P7&9LdXbH;CYnA8~w_q&RWi5wAlgk zOB6Q4c!7C@c?F(FufolvCdBvLPvXa2wdc=R{EOh%FkUyVqPRWinGXd4{2w?3tBya> zzW&Jb#iR<`WnfHf?9tp0mQj3rD@Fow4f*0I6F*8L`HuojdIoDdL z3XSYj_{wS{dL@b^ItW`CVmLKUpnxJl^?+C!v6hC0rbH07jFUUSV96d)+Mnj)S{C8P zj&Ppj%nc;gSlZCZcQjRo&Q4EJ@H{p-c=L5uE=g(OnZ=&fc4w&h^~T+xfYQ1?B9RS?0C z(FRv!NH5ONGs`s)kl<7+)T&fw9yfbY+(iHuG9(k2-+z%mS z{FO#i?}%<^;XcWc0%|Jt;jQJb>K(a=bq{n2C6_`}YxzxPc@QeE$PRW1Fa~6Vt7*Ti zj`G`88M2sN6B^)n6poW;KP+5BxxfhN$75y<-x&7oh?v9`e~`9t85bCyN?XF}r7`R0 zj%VK!4JZHMYJI_X4!{2cfTP=r3OEwi1~Di?jIv&dN=yopj0Q;Al8W^(HjuF>-f0OR zqj%|1)5JX6*u)^={@&i*pkthSThEuN;;kMyy>nW|R4dTw>*>|!zVf8o7(QUpe-P)1 zKIZL*mw`rJ7ouS$9{tYa?}yvzAZ+!k3RNRlyE~*ja?<)N<=)^WIUJL8CPe%UN1W(e zN9Q;h6Qm;OmfK}HPf*#SQz!kZ3)UXRXJr)17b;aw+S7gId00!0abb2H6H80vSka^O zW?gW2^pn!$dg>ADt>w%634_JixXA*}HoX+gD)hSAL>PhX@yzbA~)qAXnUq^iD zK*3uc!JltJc^|e|?=X4o;@Enge4pWSPTZ@3J9KdnG1IV;Kdimxlxa2;Dq`yLD&k;M zCuG)V(};FF{h>@p*;%t0bf6rEeA+a8QplwTTUDC>^9Vx)iqh#}&|N)Q*(e2P`EZyJ zPK?PE!DqHRTm!E~5gn;%{Ecz%oA@0JL}qj4>yorvME~RtGZ14|24AtN zfuQPFLlRI|_h#Nl^nr)QT3C~+C}WAg>Bk3Hev=iFPQ45YhK z%UpInocS2?id(7M9x=|CT(3Bhx)jahAh8|4blT~~mPTgcw=IcD#eSNCX!!=+(QI$a zz%kXBbm&q?ZyCiRcI46k+0La`rpx6%`n$2%N& zRUV+=i?n;ccYbV`QFArm+CRfAshlxod0Da4?G3?!J^YLNdHK!lH1`J+ynAw2gyKu( z7)}JZQB0*q^A8PjgC6OTa+>4fAl;_ZR2mf_wtGwOxZ88z2zyM#r!tpjr!!u9fisc9 zkw#j@G8+vG%;-al8%oY$Ij`HZM@JCfmwHy?*7Q=kJuZ*L(J(S#}uGb-kJmSb{GKaLn0 zQ>Hje06S1p$Hy(Zl}flOy% zh{Pt2n&SH0AVA-a$S+wOqoTaAIab%`ta}eq!m(zmDXPzJnd!**lkYLbDVfs}gLKNgBArk4nm5oa%XM?2vV`ui1;a&=hi&Yyq;dJ zJ|1mP%M|k8#ZuQ^chb`e_VuF(pt0MDJXNO5$nW@0bRnH;OtCi1V_WQX@h)}K<4}s- zK4?>EGIQ~*p6cjA8x~QlRsEG(@6ih9$HEc(TGmYbcE6gT8iw;) zi5UU@sEf&$>%!s^8*J>;vf$6VqaEC?3K8lU@u@*;78Sj^UX~Fxr@Px$e*qVZNfB2 zJnuG#r)o614?|*+Kk8y5%RY~?Zqxj<Kf@29Oqme8ass}EMB<&7$_ZaE(l3=O++ z3Lwh9r$wKV3eM(aQuVR@C4+m%CXM4B-y$3UrR3!E%jtFCa5Z~u^#Z|G&2kh2Cq zo)T-l0XRynLK1n^g*Nzz?=5TaW7&pNoh989^uh8VA5M=H3~+=Hr6~3?*_%1f>n8u{ z9@$tqWd)_piiZ-o2rL`H5;YS^r1O3cYz&vQj#=LfMceD)UY?LIwU|*-vp#m!;>Ki% z&gZvp#{uiT@>BE{^&l48Y8emQ%+T77yWV;B^|hz|ppPvMvO*1M{nT;+PutoXpNBIG z`pmZ84DAS=Pi@hgpM6JNiqrzryiRvEAR3bvTZqfVLfzGwOJ%BEgm}UydA3Jf-eKu? z5|cCs>gViz5}7APl3WSAep*_4z;ID9aAL{9qreehqT8ZKp_azz4nHY@&`;rwf{eRi zBN~FH1dmj&;=&27Rhehc&W{~>h|#m*40rGNp@Y2m4%JIfB9){fQY=>1SE^e=NOXKu zw?O^=PwZd}#K zutIn7a4>7?u-jQar?A@{TqPi2DJnqfqr~DX;(>LbE+!h;k&+Uf3 zzO8KStZo#0?Cd_s2&$0(qPri0hsXk-pgiZlz)CyC98{SLmOEBYXMSr#kszX_73U{* zq}ju__Uu!;-??Gdx&*&iZqgNbO^ktmwBpxp_^?DgOecY~($XUF2s8})6gLtFY79-H zDIrr*v83IN~$6tAU)Gq);5J85WXBwN?-@?%4#WSAR~XP_Z_oxkdpQ zV*sZDrQSW@4)FwddfNLD%j$XRqZA?RcaCofvZ88_k5-;4pYYHza?tJUe<&YziP+V( zUT%FFiKoG{`qtq&!!cav_UeSiwV_FDyxU_(E$XV>I0RzYeYUDvDC;C|ug9g-$7#hN zUmhl|)JUJ(mQQux?CoHx+raT;L)rywf*-0@EVR-jMu6bS{23LaZ%hv@k^0PWc!#5q zd*~07_D4EIiZ8a|&t@U9xRU)O=rq;M@Id#>m4jOl4A0_LdJ@0ZZ4{ z+jkqD0vgn+25J%O-1~dHGf4S~Ees>y+Pl$L6;0^LF1-#?Yqh%VXc%>0@#^^$<9_yq zeI#KHD+#aYiz(xv1yp3c)PK3yKdqzXCt@u4^%Ummi(2N5cpyLT=PPKkL8pWzBJ%8aEmZ zuE2fpnJ4Wm@cgweB4zvcOXd*Ni%)$P*V}5P&!5;4&Q-55E7Z!vYuJ2~Aj;1}1ihKe zN``ibQmFL)j;?P%cG=RP zn`E(f}b5$j;?jKnKw0)}t)38s}(O86cQA_s3rz<|j0SkEVRa)?`HNrg_aB z^TPgfL4A+FlT3Zt(CWL;JX2AoY1bXuOgaPhQF37dUb!VV^riEdBxEtXgTWWDTgG%4 zpl1^m6Za!HZ-gKgNjJgi6WC0Y(JM-fht_TJgiNfUXQjSPp4qm=DW*(|}| z)~Zi5zTd%*x;u?Np&Tv@avrNeX56h*4T+d)vfMej??QKb1E2245*?QJ%C&E;k5;L7 z+qPM3BXEAfeqB)ouRxw_m%>0(gk6%X#XC3QiwyY(r6w<_npfm3GUQS@)Gy~YbA*no zdfRlg0*>}>pu1m7?{4L|mW@$Wg*iuY1T0FaWfMEno2m(s-VN!Qb>hiC)W9GtTnW*0 z3i`rWgmcw*`o>4C(C3r}QQL8ruuQcd&bo6pqKdP|?X{+lZ1&WK##uBLJ(N*6?dk4% z#rwA{fqmNE7TJ(DyuFS?tgr0w%SR{=cq5FGoI#sJyH$_c2y@aNTLvTr z)0GE}GW8a%>Yvpng*j4jk`9bg+CwWw+nyKN4`mNg7vo~1@m?ijA$=@a3u{~>5Zxo( z3=6p9Z^R&qP#kNZU<<#LF6>T-DbZdprNTSxvI?f}_iwC{un3qT>FL*AkFc>fU*~TTh>|qVT6n^!APmgtQnD9yYZmvb=o2N#uiAwZ zX@G6ElrAs!C71kSI`yyIX z1p7~Z-o+_rS!{YLe7-*Ic@`As&%%S^`^=(krsx8@&unp&ugkChEA2f``lL}zG%y%H zRjjCMl-rNxk*ALEhA13SPnF&q(p?*unt&2EAvII61<8x>Z7;LL(Xxsy#_FV9 zB^lGsa$GyDTn(T-$b}GSbIxw>=+dB}L{&qPon|eH@n&yfsw*NNQ|jJ4-&?r3Ad!O7 zmry!(At?3JHmfc6<2JvZRTYuI4{U7)IMb8|D>oUBpD($yCek>9w~7Gpd~G5C06^h^ z5#XN9%^Q%r53ChZYxz71|D^TdTZ!}D9K*NQ(N0mH%J}>YG_#N$3{ia|j|?#sR`S#n zUrXj@N#eD;=!-zN@dpOECAzFibs`$!%%v zHYCi>+wJ&Jhh{`Av2_y8IoHi=%}x%c%elaKN>H39x{rkEW&U#7bIAZ(HbFPMXp`R) zx~pMbG=`iyMYMW!1)=|JSu%RS)P3{?W$BD@J3Guq?$ZFhvu(rI7T|s<{+qqnGFF-! z3j#sjNKU5ok#}nN=sw7a6NA|b^Ge932haRMfwGkF1b8hSOF`zgQKAb2g!x3$c6A0a z`nUbrYy&GLkwG8DUUI)Qd?+$2@T^f73nPs+9r99e`JPIbipBHAD* zkT~eQ&aJ(JlKQx30uhDZ!`LdmupKbNmmMS^W)NipJRPL2bq1soQ9dF0ZDRV0z@ywJ)#UhDqB3mTOSVk+p8ScJ|mU4*2Ofho)iSY77d&cn2o){`OblGHsb{xlXlPbyL!IB{cGgD|gsJa<9A*|1)A#E2#NAh<$8O-c&~#R&wwr8neyWh}bp6rnCHU$(edKE9~Gk{bqBNQrr$#9J0hZgD$jH zs+Lw>E(T;i+$cj^4nFuSEHK{tqTar&7hg9pQKV^^j3KJ|nf%7_S0@ze8E4<1ugda$ z7mU7Sz5R-%d`RwiNRflnj#D%lF@Tmj}f3od6K{g1Q>A;vMSQK5+Ivgu}kRuotv*y~l_< ziaj)Fp(MUCn9!I~>zdynNMs#2Zpn3dFvBNQ@Osr$bBXzOS9z*bBIm;}k8y=2d(*q4! zQT=hs#7=pY2H>1zP1nks*<$@xN_(9I2gmbyy0D?QB#*}lQ>|&P{Ey}suqPA%TG>4~ znOZ=Gr%KY$V0grG-x3R{DFY7JwkYpXip(m-V`=C^)k5*c&`c(~rnHj@OQ{T*1Wytf zvwZd2j~7+TLMP1Nt?B-T*TDG%-&PIP+y+KxqTfQOeX;)QlEljD zjt8Fg>+Wrj);^Dxo)Hp^o=F1E5a~uz>Oy+~%@kcPe8}}5h{^3bYn~tovbdaN3BC%L zTYvs(jSADR;DHoDgip|<82JQG)l(jaFLku9E*lhkuSqpii34p0Qp0zv7|bmJredR9 z@pULg1JN&6x7PhLni9N-A=RAwIHr=?r1N5RNz7xM#Ls@GY`?_Xt)x2;7K}%Uur*vOGObg?r zq*#9asRmBqpd2;DR9F4+qg!9h?LE?g5cjA14GIt8F$-=TwDJp*w6{H_DAI6k4A@x| z_Y6fXl(?EmeX&VuiTKrFk9vO*|C(FRfM16)Eac#v!B4ks&0T20C@zKWlo-Lce^MS& zP?n-?&SZrhEhyp?qY}uitY@+4(4r~PPQw);xtMGWCIqSVSM{9Sr$1irj-(QwY}|B} zONQ+UZ|K4Fj0t1gzObvo`iK{i=~zbS=8@-~&KjwR9<5$a~fNRtxEn# z7FyDe>K)DL!(YdzAc_E(Qi-N8qs6)kN|*DCvVEF%(4AU_v4TW!BLYgPI?p%|u^5e@ z_^!H~ULl`w#kanh22QA$CW=SQ*ZVZ4$xrG?$tQJlKJ85;MMV|cD1SmYv{A_gKBN_+ z>h>Y5-hKY2WRU0uJ=WKE>`LM^4+cf-VGDO}(hm_*?ZVyg#pQM}>tuVF1VufJ1BJ+p zZ;4PDKiSrPLlg&pzj)zDQqFr65SYd1yCQG1+NeH412A^!rc)lIA|H{$U%E_tF+Cd; zUXhJ_SpN03H+M#GXt2u5=_nGdcM(3-TenI(`W5u#qcBP zg+y?BUzq_>Kb}iJjgCwu6B4yzI6D^IspIld4ZP|WE&g5`8&8$<)?@tbW0406yTV}~ zVb5FDiLZh@f&V5zOPxnkW869>kI6zS(prY66z9G2?uGr!^p+>j4jvHYe$5w^`5e>| zsw9gj=KPLkC8&)mq4{fOm;V^)T6U{Z61&<<x~^=3i0uub%olQTukp~iSmR7}IITXGpm8YX ziL8>O6U|v>_6lX>k~Dz@nu;@cg_F=`uG3?QNX;-@&3Q2rbsiq#;%j2zi%2me4!q9+ z2sU4flE5ST!q$5LNo`rF{vSs-OEUmKQ4v4~tDpdo;cx*6uo4{X2LSg7fb_Er0GPl% z{zusgj^;NRcmMz%@1OGiZvn6t02b`m>5U}-@wan*VMo{tj^W3j-;Zj>t`3%NU>l$U z6vPAoAVmWJ$gqAy7B*Ivtl!J5EG$`Yzwqzx0e~#{-!TytvJieR!!N+j186I%0B;`x z00P2p4#uX|U?|W8Y;I{MNPW=MMh&zC2~uluDzYd#h=VOGWjvg~>K;lOrXJR&ydY{} zAv6IuJ~vwjTQJlZ=w@qU2jO!Qq&5cGn}GRX0$n+n`4$e+C zKXE~(%wQX^E!YkUVP<7wWro24fdU{?K2s;KG1T7aNA(xHI@s}N z9nb*+`U^XM)BDrTe=+QbtxlHa7Es9FHS)+mjT+^gJ5~_*P_4r{=G53M*ln9 zU*r7V`-j2*O1VFY|El~J$DeujhamrmIn)wr1OB@y_CNbh_}!#mw*P@z{_p9=;SWq^ z2Vwe2j6b-78P);g8us6~23F$}b%t8NxaQA{@`nx>!~Nux|2I2qoFV@pKA0iS5U>NR z=_mc!z)XQrILsWD-_3z_@hMoEg6$yxj{SZztb?%=1gzoi02ZWH14HbcolL<$`SS;5 z{!sA`oEK^eLO(bi@*AoDaiGkWKPCodE>;#cE*=g6=Kt-)AC&sr`2U(<|8xc{js6?H zg8AZ)uKH)p+>HO|B$ybV_^%1#$6WR=f&16qA2Z62HZ^0YrJcDDx4;jV|6cp=nydDc zpZ~qlzZmwn0K;_uI)_gSY@!Y|hW?!W{_F5Sz)mi(bbv71{7i};g!^AW{N+%71p_v} z!)AKsf2S(^|w6mw}k)yWY<5h^nmSPmv>xY*Kq*<3q(JP>Hq)$ literal 0 HcmV?d00001 diff --git a/assets/patterns/brazil_carnival.jpg b/assets/patterns/brazil_carnival.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a7cdb3a1108080409232987b93fb607a5724c729 GIT binary patch literal 80205 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 jQ|LDlSMcHI-SA;Zpke~3pNZ=m9->LrtDQPt; literal 0 HcmV?d00001 diff --git a/assets/patterns/cotton_balls.jpg b/assets/patterns/cotton_balls.jpg new file mode 100644 index 0000000000000000000000000000000000000000..db6f02a88997585ad0e51f40f3d9333f38d5c273 GIT binary patch literal 509803 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 {c0!=+Q}HD9D~h7FyADfQVZM@fJvDkSq;p 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

-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

8Zi=WXV2#WAr#7f;+77Bg$xCwjQo6xOV47 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 LP*J67r*r=WT5u>t literal 0 HcmV?d00001 diff --git a/assets/patterns/cute_worms.jpg b/assets/patterns/cute_worms.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0c9f4fbbba9004a4be79f0c1ff08bca3cfb85454 GIT binary patch literal 34160 zcmbrl1zc52_b|NAp}RXIq`Nyrx*Me7(A_N_6%-^yT3WhMNkNd7Zlt?GQjiek+o1P8 z_df6c`@Y}%zH>Hv&#YN7vu4ejHM2L@Q`buXuClz6JOBX`JA@qou9tzwa{dms0HCDA z3ZMc2fB;}apnwpV;|2f7AxHoOd^&)C6o2v_VE!iEcXM^Mfq6T)xzf1Wc>B3|Iyt!7 z(O6n}d3##IylI>rTy4B)tSn(pcAjoNuGTcxHeL>PuAJ;3zZ;f+J+GIMp4oeQyNhyh zxq5M0TDw`;zjh%z51l>X7CpsDjYY9370X1$l z_xm>X4vK-EHadaoy0Aben20r9Nvw|Db)^Rjny|C{~4`ucbEZIAyVQgZi( z@q?YX@8)UqHytPgcH1Z~Z)>i9V%(D6c9n~chUSl41siYg03{boI~y+rC3)Syxqw_b z?QZHEZtHFpZs%a@{V(~}u)p!$eLS6SrCP(dY@BUeY+Sv)KwKVB)Nk#&JNtP3jScqA z$IIphbW7uGZOa7;{KNYX!A(Ep{6Q7{QTPAYFA#x?mz!IdgPWIwSLAPDATwhW*&{|oEZ z4c!jXKm5>*d%J~!{tX;tuD=~3Soqte+PH##)bGY&Uhe^(nt!<|8a_^LKv+ge4H5Cy z*XvV4H37sMTcCvc1493YLq`d91u*|P^{!`u`v5u$3MvXRIw~qE20A(hHYqMP78W)Y z5iuSq{T+t8ba&`z8QFxm7+LsPXz94`@$id?NlHpGaLOv(7grRLkQBRN0zt>Xz{bL+ z#Kol)W2R#k``=F2Z2%rBWFBgb0Ko&Gcn}0U$aM!m0j^X~1jx;D^;bebgd!nBP{2xZ z5DwP;vl0SDKtw{mo&hisKtfyuTyUu?+_ih#90G?tR&FpTgCnneG)Dghi2S(J+muG0 zCHpGO4s3|AWp6)rjh_#wJwYINep0G_cq5JEK!r~exgu2o|F>-9S=ILd^rKOpOl!iS%Q%e;iU;@TvoT zQv@LOV>Cda@mM(=%vKV&eO$QvQa$8XV!$vUB&?y-BXU1$CmKZ+G86E9+J*+3exw|W z=7#Qn;)5i*kl_pT$>X|Ny z2l{QF6|(lv0a+8X1fMCn0)g-AU5)^tLU3}2vjxlbUFRhc;79FKX-8u(ur;<@f74tD zC3UMRLEMV%LQFC4Z!{- zXpy%COY*4uOc#wVBy4>OQqlZz@Tc?*N5pxvkiaFNvUBIc7%XB){F0tDP-LUQ(Q(Rp zuj~krIVAiHu_v8W6mH@Mi0am!s{+sgyQXjKz}NxhOCRZz{g1Q8d5?1^bCoKVZWtm} zyyP0#Le^5gGONYQ1_4!zYxfDt3*ZnZ>>jTv0C4NupDU^rpI;c02B3u+gudMn+p2|& zB*5V;Mxh}aBO$Z!h0CVsyuk3@SojS`z}frg;jFM*g_g01=g!e3CA~DL38%)M$w}qY zSWuahQWih}v(Ls;6LDQghWERdstMx&PmROLp+Eeeoxf!U-Y6Q}O``zHjm$h1u!L3n z+OcY~1xLp#?Gx)1B)ZffHxexy0GRr6x+J6_$a52?8~^I^A2yK2LZqn{$e_cH>{}4@ zDNr-N1%J%Ro9_?0H;DCjmPC>v(Hp4iE7Gg#8V@-C7vf&RH?m5b9P8nd%q#J z{lxtlp5&i4V$BP4b^+L48rlqS06-b}SPDn3tQ;(@6Fz1#$QpJE3<#Dc>)iY17lcng z#+r5nFb(CpsI&QfgBRCX>yN7`4Lu$CvZ(dyLnfA+pD;C^Y$pMt5p&jW?ylRdAt~#` z$1t)=p~_>Q-YK*eX!}&>Dyjc@QWJ_8Ae6 zf7d@p8h|_!+3_#Zw0k9y zs}C9(NmCcP4Fp~KH}?^aE!L6M7R2-$xh&#D^u4o+48s3gueUIu`LZyFk(ok4j3 za--quj};a;Fbk6eY>2C#n;7)6>64${FVOQ_1$<2O=e-8lw%O%M#-5!xsVE|hFRYz- zrGHCzuT3#ZtX&5JNRDfJFKpOfrQS_Rg3*8)Y0GfauRWyLci2AP+X5v3(3n@CbBK|~ z%#Q+f>XrNvLYy+O7zLT|Fb)`^!KN4~=K$w#Q2Yp>5WM5<4hKo@res=mma>Aq$5d}_ zFz*V|kX(R6A`}eEtz(1X-S$eWhhW$1&&EO~j*R`lZj+3bi?vV}oH6A9F&E=o z;GocE~AzAy`O9aAS)iKI`&2e8IH#G2H-erPZ^68NQi#A6PzO*V}ett zxQ5i-wH~mVw(BzSLVCx4uVEuYy|I#BqxMY!7(wxx%>)&|i$B;{M~>{e#aY z3V`3OPMvF%2)627$*i`iFhL8`i3 zzI`8VhC81g+SW0zpPa%^g#sSpSVFSsbDv3GhL zuyMJXvGb?l__L||;5r87lYIe-z;bD*(f@h~HO$Hm@I8TMtcIPGAa_kWA1}wTEE||L zu~njCEsF02H1Jb+uc(Os;0R_fcnXR+bqb#U@MQ^yk;NzA7Y$_Y;!9&XT==DYH9s7s zxT$9gPT%Y!DhzsxRCam&Rf?L;L`~q?4+R&;>M!!Y0KZI^a&2i!gEywWZv{#6BPz7a z8H3eJQkNmK0pF)=cnT=)rU!&{Pwqk)zkm3_Tiyb#y^7t2BUmPUUw8;7+M^^XGzb1A z2LMh!kh-vZ7JY(oU~HDnCRe1r&LBsYI0O`e$ z-R3}pA~j`YTadf1h{a-kG73h*0K9_1ITBoftjFbQ^!a=(!d2E z3F-$!r#}_RO*iBB`?1sF=26%mFZW%Z%h}_}4p+QtxtR}$BNFDAdmgV0jJ|~w&|vt_ z=6(}|ig?b~jDe2lZo#`n8UVrPW_+6fJaY*tx5PC#fSKbL@~Co0dh|d%%h%$!QQ%-3 zPqv9kQkB!{)36k_)pxx;g>PR9BGgaK(iI}>jyYI z_Kb|0Ua8(dfF!2km5eTYfSU4?udZ(gC>ulgbSQIrQdw}cHlcW=4aBgE#OM$k?U)<} zxYa8q#BazDSez@ zi~}rRPIfK8y5BAqKzN`=7XcOl%;owvzpEyPCHtgCjbuUN*Wb zQYlC=TyB6}+9MwY(sT!L?4 zH=X?$=u%(Z4M5~)Jm;w_ur>@`k2k?kEN#qu%!rDxOBx4VpviFxKzy-Z-0H}CLxVoP zKe@RF?kqSfr8>|U1(W-4pul$u?4Z5+>dZK>Aq4^0nO_0XU=cyWe#l^;;lxZcXs*zF z7v(xYwct!jR8JZJ#1%X4qU)Zr>3l*nSWFVLMk>`mEdmY?L9MGM7!FSI)GP$q;e(t} z^B?kyo~-iK4qDfzBs`vVg$ED0(+ox=9*5@0u;peVRnUO$dUBX$`xYG~l$GCy?1Hb@rb%r4kNy5%-y#SG&3&W2?#qY+( z>#;z`8#S5;05jinyhZ@{Et6}LZ=`&hvgL*o+J>M|KSaH@&=?Mum{O+9rKEXZn6-xj zG?ivA)z8aQpaZ2L<6yL=isy`@WXrDR2_S&;zypp@xLSJ+q{I2RE;(QFf4Cee5G9a6sU7(BWjB?)FN|G$6sX zki?h`RzsF63u0yA$n9B`H7lDZ2=~S)Kif!?AbQfQDJno;*73WuiaYpmG11 zqZc6ZP{M*Yp{SLo1;XAncrm2PzTOKwX-b`IYWcHgL&-1IUoYMQxznqmn=!`%Nohu# zU$@?E%xs27i)-X7`@y+BOU|S}02_d><1&d;0DSTB&;=vlzU^H!hWE`6pownUwSe=< zkmXClnr=vW-`tZXIBIoQ#gzrXm)NM?F-Zd;DwP@=lz#*egqxaO53C+?jfvzml&_kP zbV~?MtV~U&fb!Kc8)LXMA(h+9xg*^G7zc&joIBuPsRy1zJSXO18`f|he!a7ezC3_t zGP8Lu8$ij6$5*xXw@S$Y<8DZT(V~>E-dltoo$aMAd%@E`Y!L!dBHcfY2^iC1mMtLG9bG-$6ee zshZo&v&e1>hBjX1YX$E&oAurT5US(SktjR7NPXT%-Xsmh$G1;orRIoAm-k#B~9rl)gtA!jOtO^_=-^pExBwA%%hfL_8W?d~PHHUP4+PK52eBBKmva5gsat06~IA2{p^A zGUt2tzT9nl)QFw-)8EIuO4+_~f>dm}#4a%6gT-OX)ippNkVcT~=-2H1$c*6UluqAt zM&@3*_xw(VsILDhORd}h$}^PB%e%?XUhW#W*!_5ySK+Uzd!L?g1VQfI@=3ye!FIb# zS)UU}S?&9on@8HT>BKyEJxKau{J_PgCSJbJzGA8n*{0?X;6D#zGz}-~R`0ffqEF{7 zKZg{Mz4u&EXO5T6zUQ{ZAwR)#TB-ULgLBX?S8cj~9&U`+`OBwf1gWa5!I^SFD;-}`rjLCaEj4}$`$(<-B>bd~|1e$syYqvxDY0o0^H2>I3iRJ? z;@Zl;bdUeK^7uXxZPhWl^2|! z)*4*XYF@m4?MsC#yiLE-zu)Mv8XUIYZOLSoA+FxD-1wcu@*Y;9pDnC1O2>zYNY;xp zTWtFWb|YggL5QPyA)4f1K;GP?m}wr>OL)!Vst&~}#g8`XnUv|1$oCs?U?!sU{XQIx zRJ}WDp_=k|wfI{1=#ujrS?GkbVpCVcVAntt{hcfB6koN6Sdw+RgS3~UQkmxnLZ8XBhw_8*$o z*nZ-X9Sk?|%+20sw6$F;$whw_#~XeWlB@OTQUK#uw9GY-tC?0bZa%60qCm!U)u18% zGj`&M7!Th_%NEPZOXZ>6&WKJwHCJ!huM%UXzkhAUJ$`C_(SGxOW2!6>SuZ9Pun7r+ zt^p)H?s3Rtd4H+F-1X2*VeiUZ^r77)DQbCM>#>4ZmC#iybxtk?wH*fADy#jrPE&P^ zU+HKK(PG)DB7Bwk`_FK`6w{*cIYhY{9ZdE5^ihUFADX!Pwz)h})?`bFRH#}fX4wO6g$5HzA{(dvi_f&O-V^j% z)I@L3imSk3IB(Ct1|*3d-QY$sc&MtXmD9L9$IjPrWevzglTG=Ip7KMFOkq7V<>X5Z zBN0wu3~F;9Zx!3^#ZlI1vAq;AHVS3smBV|9Ar=`LWfbW`rJ4c^tVzHMSxE8_bseTV zPq#hyqawmy7V&XiB0sD1%w#NzA9-?O8RfDUnrWzoJ)?@YZ-VzQJq(pxR6+JGSGwoC z%w!sNPLP8@VPt*axZFp9?akVXl8~>dT|v(oodj|AFY6lNdsucHvF@GUy@cQKCqztl z9>0k@CG{~cG?Kpt`VhWL&~v=EM9Ji-z5AV#x&4FQb1jbQbe@M<@KrK$BhQztLN#Vo zT9q2*^q@hN{@}UTR;B8FVu$|)xifWtVXFK5r0D12PT@g2#oMe9fyHRQRnzmy+f1&i z)s>eH49__kz34~vOv`sX#)p!486yD>WAyV9dR!i2!VRc%V}f5MQnwVGEDmhD;y4E+ ziQfCM)@yuz95Ich8ujd5Y&S}LkIkG9Gk@eNI&5EO*%-z4A?=~TLzO;d<{Y1=j4Nvb?57jJs~dVfk!8%wbd ztxfaX!b~>-iO$y2Su}kXwnR76?2%J=Fz~b~HOK7aN?~<~u#?~e&yt%(d%?IXr7H5h zRN7~%EL$s>d4f@li5tnh9K{Rg;U5zDu{5xW(lYPJJB_5C*fx<>{?0TaK6|FEF}AKP z>mhQ!OsT+Dr}BE_WV=;dzGr$CuGZNxRqbghAG8Qzg60=Fh98v#jax{zM?W<1ucEJg zD4AS46->{up3W0wFU=_6{$0h$-z)$YWrf9>ZAEy5krOui)WiKg&pieSXawk5dnx>rjmCjy}Dzq<4vziH^V({`Q%+!+WAtvIgZnC5wXh zc@yQQZ^O876{lO?(Rz{;z{Ke&nbpV?#Q*$by=C(3eV!=Cf`BYTMt_DEnkoDxMYhhS6czz;GtrEIKlsB^M?S4##rMsK2Ns3k-kbHAHmKB2w0 ze}9RBH@1$1`7uTN*j)xJc1_y@+p>!N5Q3wX7b+`izN@5jv5^=sp6L&;?YB@|T<5`i z;f|%sk2*rcEsUR|8GTOUYp_=u?x262*>!O>LG)^@xG>Iho%HVAVb1P~DUK(#&^`G^ zt%`A{8gilN#Mi>Sw6mc&2T!X+r`RmYpVXp*k5VB_EyBF<;n^|iCVq@Rw-O0{)V@Hs zbW)cnl&dwIi+d6J8KV`$o@(kJ1lyQ zCJIJP@xGB`rS8Q7n}053q~|rBYa8)3U}&1OVf@X|Pq0Yvk1^8jFdV$o3 zdmrDXIA2MNDWI8cUReF$&WecWL@c}Lr7%rBz%+f+(SI+mm~IsRtaawA)zTH7LS$3g zH@WYYQZydh0mQ<`S-}_ydIK$UHOrQV#_Ez=V{x3TAt9E;H}d;H0DS~X-9EO z!S3nOVRR4`=L~v!1-tHCd=2Q=xUcy3WPE(qay1$I=bBno*l}$Hh=(8Xk2^sT{0h$W zZqAss7)^6Cdr{ivhr#p`2cficY1k!qRt2GV$B!FM-dC!y-rh(t(Xhk|GLvl8zbN1- zHnEqE_TJq3KI6F(4)}H5pEDwOa1^69H~3v!sgd>3)mnQ=@-KhX55n4_q%g{%uGEaM z>Lk1bSrZjOJD(Z;rTbAf)d?;Kq4^f$se7@i&Hmj}S`?YmLOu$bU7}=BFdeaRwKCm7 zd+B@i;5j=H0<0Uw>+RdxxX;e8pwJLu)iZHSx0Lu7WUu+EHjYtqUM~tded>B+%*?cd z&$1!H{UmeFLn6N||L1Yor@_koDe3KI0lz9V(2dw1a&``|NeP9%EgyERcH&tZ-Q#?l3YazsebA1GqSHslB0nJzBPLn*tttm zX7*0N>Ah=-b5=oLPE0E7!fe4U9ey!gUZhhCY_H$A&ZM^Q-P)<*j}vBtI$?u+|~&bKmi zSE5JyIr`?}*qDv3WfyziBL&2+P&Sylm}Ogu%BM9P$~&8e&BG`{q)5rO{O%9*ej4&T z;9GnF2H)Vsotd-tuWPKUatCy@=6olqqCGjBBJNh z*0j3a+khV~NI{rrFzU0|9Q-kJcN<3bAg?+uj8$4}Bh`b-sk_OW+#-0a`NI1|=q~)J(OB^*#+4P5LSNajrY&6i5PS_O-nYyrA%A@< zWHaX4S1^#Qmd2STXe#Io0vW zmckyj07Xa}MRp@;cURkQ@=b>%G6m^Z&h+IV76mUif}+|i_*=M-M&WbrwbA1f;g@0$ zR`{eFGQ@@SZ3U;*QU*?0K6@m2+SeTnuTcH6f4ASppba{ueiChKKM^7dwMF|Hfu~;! zET9yxv{KZyx}Aiy3Bza=|LbM~ZW&lzT)qhIN9%`fCbP_Xm)e$f=gqJjH zUu){XGcPd}W6E?55IBYYMI&$M%&hrF2G$Psqi)TjT-9lN4fY+lHuoJd%47coOP%W3_MQY6q%JxD2M zR>o*G%UJpF8C9pcR=D9YK4jr))j0kpE}j~y57f?|^OO{H6WG`;*D7}uj;@G*!8cI* z!Hzu}FD@U{&!6V6AW!Q8aq1ABYDd=Mwe2-CnO@^q3HJ1084QDVYvziy$r`r{z4NKY znW*4(DVoFPcprZC;VH7_fgOI3yh-sXOt9(B+JbknXz{Z`9m4Hrkw&lvr>7sr9}QP? zvOU`gQJcV3fOYdX%62UiYn9%K*f@KJy*vd0OuQ!oZCn#~$(GNpuCRA9IejE8& zIC@=lZn9Q)Q`d6ONy;@q)677XER%An$HFZr1J7nghdM=in<}{G=;OXEV?*o5K6|~! zQNC*5Lp*Uf5Edq{DB@W-Vi#Kra=B}4&^{dYoW@+TR6MNa%7qM!@Te2$IPDMib&iQA zM@Ql~N|$%=oV=?qPZZW&9+k=~)X&zWkNssm`?p&?E|Xh9?uI-bA~U&R0T7ij|Yj59&L-17j0~%bvzoy zMp1o&`(@0=Zkehq=ZbO0<*^-+Lf)?#vk@qVN3up?=QWVG`9wYCwlmKt5?pRrN=BL)=M)->u}^nkf3v{1#1e_tuYIKX$fD0^P97JR zZf5X+I8rTVftf%S-k>qRVu|U*%iSz7mjy8m&UL_%cE5#7T?h%7uwNlTzyU^7&A$G~sQO zg2886$<8q?>q-1XhLgej_4{o;n^D`oyn%Q_lhl^kl4jLF=u9(NW%gLkLm?qEZ{stV z+Edz@8QznI(!=mRAq>ZJyYV;QCvpl`x5SL)HW?1u@c6bO9nS-aSe_R^5h;*z&YbLr zg4(t2z83Leea00xactDAV$kDw!C}r&x>obZ-L~hWI#>P|RADM2bBx@Cs5k}%ZhD@X zOSe+0CybswVOr<&B7`iy9RW|#20Jxq+Y`XW=fvc2{4#9%qnySHFZtchs;Mas@mA?e z*U>M#DLWM+6L%iJkI1|LTGL?f-Ws_eKV+hKF!<2QLP?Jm#+N8lc_iMFu(4biyJ?1b zi8v>QB-tqs``RpK@Y(Tv&z!1swILMEKBfOrk8lJ`6MokFf;#C^11 z5*c0t43nkTfJ(XM&x+hS(DWN(=3%}&&oR$JG?;blFXiKvgD{+ZMsKXv6P`%In|YU| znlsH;BcH0vm3?$+UZ?)$g?dm%g#nTZ#oAB9WjegQ{!6$rloP5-L)RPqG{L-|NJOKO zDm8-1WN7;r<4mT)7pz6Pti+n;$_~7TOADLG5v=*zSNrG{B+F911fXs7U($x7_8?lQ_R^v6ep!I^)eeZm&^f3ag^EWP`Tx zJLP@1tT!^2Q|&_M!&4T@@G!byAw6{ zCE5P9G**Dma+(iSn-jvB;Puw9 zC4f$1tXml-F}yhXO2y&oL9FMUQX5ULcbGan0?~7h3_p>MlulE>=T2TxC1mQ$*+^m< zSqUJXHzLybYsLUwYrhS|TpQ)(rYByJH9c=O zI98e~1rZ$dG}hga`}qrl9LF+O&J8_jEt{e{G;!%)=Z!Yd>OMmy)+?7tOO|c#{HV2$ zwBO_D5pRL7hvM7rqx=ZQ2yFv>AgWgEmt^XmaxCI_w80L$49BYTs2M$;7*}`uxXiEe zZtgw4NhA1&)vCU{gYn!JpgW7z7J zuFa9mgGHzf<%(ZL;-NYj;RD$OQ;eDjePg*RS!$IN!Ilj!$T14Wto{`Kk2t*-!w`fT zV!ErNy^NJQ1yfv3SuLx=y-};txQoXysq^npsMqQq3LgH_=Pe+_TqEaT9`WR$J5uXJ zr^xQAQ+<)honzZOm^^zgmM5?}*hO?&r=@`VV~g7Ilz=ID5No=)pX2h?9;{EtgsMOn z35;X%z&HjBUS>H?VQ;HvMi_~c6lfHt)SM_AT&BHe-*4C520Qa05;%cO1;73UcJ&6i zPhA7}#Z?Ga{iKeH_4xd%CD_gH+{p_kI7fFfkryaKd@)GBGKs#7E;Nac?G0=G^)wz(atd{O5zy+W-%rhMNZw7Yy(2X%P^D0Uo{fZEOdZ*k94lUQm0&GCXJ4z|Mmu_5 zhTVORW|Bxf%Ey-|>Jz!zv)w3-SoO#L@^94Qp2E`7&{uGaPf-vGRMW}tc5(UJ$7Ps) zwz-trA=0SvFd+K-3QF8J_+YmFr>tgq)?KSp;aFe#;$PR2x~o5GeWtfO=VD3#D%r5_ z)W|_sZiO$VuNM8#- zW)|c(8G5ZF`Sy{+=jZ#!8gP$*?RZ&-rsgALY@9ve!=DREhd2bkxYiy;UffyvrEvb~ z)h{Of`mb;XqufNE1AJ-o93o_O+yJ9;nH0%kXC!o@dp|X3+CK3c$t?dEXFeK=REuRo z-Fb%1O?)-A)s_7{mD?fHM+_YXLx-}$&is!(JYwp{I~y(b-q~I)&Uoa{ z=aLVW4M+P?z48!SVg1N>bVt+OcP6{F!!26<>x0>xfs4%g5$cm=`N$n)rg5+8$Mn{{ zzcNbI3v>HZR2RuNC~^4)_D_m^G4E|4X49ibW#*XateuaGz0=yOTdY$|s$Y6% z+@ElVm=H69oO6~uXtl!+rt;Rls!?CJcqB&8++vt8)8J_C6H3mg&|tKRDiw)Kw8YVh z*t`5G{s;3*${ElSQE;%|NSHjm@7sA|NfapAF9@&Ypta*joP zy&0O4XQUq44Cj=Pwzo-)wcN;FjOsMf9j}GCRi4HB9Wu#)uR{7)+YcUt4XtB+{)GeI zqr~z#In+FF{))!4bjoA-$6NQ|BFjSJ6;(Pra@d0S{U%s@^kBT-Z_{){08fY=QoNVz z<=zdHM+rauX(=$$kJgc*?!AJzt~Dt}E<=_#xW}x&L0X1BXGYrrQ#un$Sw~>4_%N4m zqPKrp?Bkq>j^~cr;0c3O2$(u~SbP{M7~C_|8hE;Zf=%0eRPX~c+gfpruUuQIr~{1~ z{+OKIdHune7&TS%$@F}M0^?rx_qnOw44IBe6z6ApYzp@hkxv`t%F|1lzpQo5OpV$3 z!DU>hD4nW)y+@2rBq8Bd7htVV=|%Bj?y=SZ4Wx9=uFGdMsXu*iCOW}%8Fj-&@6nqudM0q5 z->mZi!==b$y@dYQ_U=zI+u9>#QCqtZ*Oim2QXH7MF?aP|?(pU<2BJ9I`&o8SXIr&% zprqg8mS}Tq%GF7cZ;-(ezZQ?w758&vq1U)<@xok1nQpPMvsYTN5b(uOMzE(v(^Bhw z@7qzc%wlV?RHMxcJZ^LvFW>$EVTrDG(6f8jkER<+Nj)3N#9!UIDU*;EW7k3^84;9^ zj`jVi^sGs&kRBU}H`!=Dm2!s*YLQ=Uf%Y zJ%gN!qPn@ohh+14*b0W2G4E(xGfc4JOGIY3wDYMno(%4B2b1>ilJ7Ie`3(b^k9G1W zmiZc6MY(hNR^NkB41({MM8|4obY$MhiB6P+Np*zIVoh!(`O=8j28}ySi=Z7;`b`8i z7bIsnD#vBGPnFJ}njMs!J-n^;a#E>PU0yA%sTlKUA#L$bWPQdYT;J1eb%Y{U&N>2>KR(rktJrlkhvz^nrD-r^3X+m8Epkk3OLL`)SGC ztmg3T$o_OWbV~qvM%EuU7k>f?IWBdo#Zgf{S4Q9$;?4wiE5+c>*pX2Pn?|R@dASr( z;Y#(De%6aykm-@&@@@j*ZWEGI^WXIw_=VEZ!uMW`JU+yU;t}$z;XK&t!OS4zOBbvRUiWw2wPLG!kI(qqX$4|#1HJt@AunK}Q9?_PiZ~%jIBreO+~_g(P1BV^^( zylIw#Nu)NMoli#*+C#Q0In3V+D6I*$tSq=XZ=q*t((EL|BO?aN)3K%fUoPU+q7W}_ z42B2DWNY(%q}N&DWV%avuGbWe{tgyaIITj)U9vAKr&YvltKsC9a!z&kQvj zR8opf_TIhmD~A2!A7c^XD|L)qrX ziUT(D9$7_8%X=9Y8V>TRrq@9E@Bz0g8b~sbeOYx<;~8xR#f6&0&+zPd z?4um+s95F_D}j%pF^_0DBgM-t3j!;ZN<_HOdw-|6=?6E-knNvI2@)*qld!_?#rvr& z+e3gCGkf*Xxt3OHW39$M{x5BzkImP>VFT6zpY^Y0u5~u^&rweq#WLD>GkS$dhJsD9 z<`}N>BOQgq>T&`^0;7-L#20VmsQHnz*-0FUS?PH8{A@Gt3ph)hKU{5S86e|*$ummltxws_6a+F=kHEkn8G34U#RW}G>dgauQVAQ@PjN~_^pG%0@9_Y3nB3oAOb zyNo8^yJ#iV_>tf1x8Pc;ib^vmZadOFeht`=)W5da^F1|El^m0GZpZ~JrS_9q7K3uu zY)6--tI6a;4*91nbmclb3ez09kqMf&J+pj&7=_Zg~%3g-CO;6&g%=INm zZ7qe_+$M`!g|PQUin{Ks<*hlp>DbyN6hP!a|EsqKY+4Jtn9uJ%icT=GAkKx2mp>~- zD%hcpv@g$PcYpsdpD7cyvsC}harQDMstDi5!k?r{1eSOGBPf0qWedt?_@UA)$S5>k zEo1uQ5m9D^L21RvZS3ZmKIZuhqPE8npcwW(8hM60XR(ySI{p6Py2IKwEz3bh^hUV& zT_$Y&Pb_gk%k)W^6(ka~fS zt~LSdYJ;I+{%1x5hc&9>0~DhAVtIv^4LQb}A}wO_g@RT0%+mC`(A*sf# ze&8UlO|C9b*17*yZZn44$x#_|waXMag@hx!_Q?!}{p|yN*&V~71jm{2DFu-MKPUFr zvJ&o{24%`IDB+{n`q!f|WA=O&!AshYN{-50M(vjzC@(qjQ0tzfA%Jm-1$?MrHtM7T zX%IP$INq(pGokTyEOr%TlHypz=ihdiCLOc{VfLe^U;Kh!@5yU$N9h@oeWTtr@Nu)8 zfr^bWz8^Z=Gm`c3QE|f5&jBJzzy@o>I!Lt3fZA4(Xw3cT=}gfUwVXYMpn=pZzljAQ zuhHhR+18!t3Rk07o1AUAh{Z(?)e82Dm88$IS#!kJqJ+H_=XkvAjDwB^ z3uZ%m!yz+`aRa}3uvxSOXo?7CE(fX}HZl5}#fx((Ws>9#VT@S%F>^eNX*KjW5>btW zY$9#*wVk~F51IxEDYJDbilp#c`xldvt&UNg=Lp_w3r=!XB-E(&b3Mi{EIPZ;$$0j4 zO<-xS^x7h~N2F1$(9}IXNHedCGo#J3Z4?`fey#D*Rf-xR&creq61P8Yp$G+DOimc( zE+W>YatPt;?}OiR`09DP=S*7=B2#@CHoo6GL#;o2oHL2T*X0!EUP07WZ!q8s22TbY z@zgsXqz`%=KRlfW{dkl7g;{QJrB<^+(IVTpTjGvT?)w7}Qnk z&;AQ>FsQ<@x@DAXi4gIWl>`0Q!LmIFKZ=!g)IX9LX)cFe=<6~6fqpM_YWdvI9G z{{emXEqvkl$AM2K*%GdO62rX&iq)XLgXd~njS27A3NFFA)tMmHRqUE%Y4_%X>nV6;J!JMe*Eg) zVe81U=AV!TB1OyI%L)g$^X|>Vc&mTu9E_OJEcgg ziHE+r74EA35KWMY$Im@=QOUlZ1k)h|TZ&@`(|+DDv&VIfEo{%Wum3jdi=QyZT&*G!B*z~>*sLBmPOQ{Z@UhV(i6!ky+-?A zepC$lVZ!`)_<-l9J=qd2tZ8L?t3*1|cTaCyx2SVQyWimEkEoLTq_{|i$1}=n#OZ6~ zPxp{o%l!5qJ0WWllWOH_TvE7kkY2GFzvkh3R4HTb(dD0~Ql8Y?1@4MuzIQ&BKR;lz z{LwoVavWoats5W2AozTlAbv4#;oSZWLIXspM5ZfH4e#9MVH_G}<$Jd$Zcnh%VBWIQ zKrwT>TQ#~(M%=JsK|T!b)k*eT#u1dnA+ZxB0d%f>%iiZP@^T!5GhKtd4SE! zuU>C=7iEuwo^B#s!6VD>2oHF|iv4Dese5OK%i3Z3S>hwaC$9K4&x@Z-p`{+Clw4KO z+{0!Xrd!MTfbfk<5zg)M;Hty)2_5%cIw*hyOuU`oTjvA9d2t_I0~_HI!i@2rp(#Oh zvTN&_8+TgYs&%N~#)y4Jd?|c~(Sx*7d6;A$Pr~FSD%&Z>?GH7xDKhB&Pw3LQ%nq>F zMBpic9!fUM`JRN%JZbwy4FpU*ru}}M^U+Sr4j@8?V6G9YBBD$1P z($?jLaA58McO2kpi0B?=t1~TT`~i-S@uZU&=|EDq>zn%v)w){id*&%(;r3oQOH=kK zWdaY0)V}7+(|PwCpwXZ)z#Di(utNhL&ubgh$c#YIi$}&ULhVAjWi)!>`sB@V(ob75 zk@@^#2vvMs8;R8RWT+kWl%(!Je0b~meMjP_3GMZZ-q5%G(a+naf;s-aF+J)b4=a1s zCILvSC|A~cn%AqS6Qe{)*;pMvYai%>C`V^P$1Db+A)FEO zM+*YbiJ;x0MB0(rVi!`aSHec5BON-=4FPluScjiFyudS8N(~n>!0`;GTaak!Zqt@x zKtT3FB`q^mGe$t`7mOI)l{vKRY8|qFP=`osu2ukPCg~@pb3b~1d^bB~9wMxk&^bRD zpvc0*$gT0+lJDOCQ`cL-Rn=_&!}}b%ySqzLq!FaMC8SFbq`MC#ol=5IsfaYv-7Qkm zB_UD*(*5p(kN3Iv_xZo9?VkG1nwd3gV$Ycw0c2coA&Ea)`TE6^&)It!vgWM!kXB`6 zWW25)8(eP2*0Ffd#gGbM@Kim>aHZu@7?@EL!H4u)OR+ZI)Fm`&eqEwn&Lb8_Q{WjO zwFMWCa0Tg{S<|`9UAn2ihsW|UUrKRc8B_O!o9#ySlRBoP?Bc$A~f~+SsDWIMJ$h3l#A<#w@&}<^KKiOKc9$SEEioDKeRZ6x^!5h~VDWV2>WA zOWpuWG-7jV`h?-fer#dt&Bz|zcF<$JE9K})w!+rYAGvwjxpc&8BaAgNYV7(c*1{Jy zhR18JO_)%(GE$=ybRYxf$xML@gHUoj1VD6lLPz1PLZXng>XRg+#9i)KyCyGaQvx+oOD6EYj32C4c4#O2P!-a?>FcZ)|gR1d^GL{2GL*0QS@$p0^ zebcLxO2SKm6ueHu2KtX!D2b=2l(7dR+AkTF(NRr5QWAb0kYlYwK$U$9Wh)V=w?$Tr zW=#IU!DTHVr2tih3I~cn0pUy!J|HqRo6ZZd4U`gQ(2>Wfvm zV026i{_o#5e8?FvAVdRht_MvHF>%lg1T2(Y@O(1_Rz*8pE<>mD(}7O1&IS0zC5c&q zIy~|M;1`m+xBio&c`JY60c3xj?*H3WbQlcP{W$9m_d6eN%SiDQiOvRWMR$p=S zXj2s+AP9&IgHfhINW)4A4~lxq$eZl`HNeH2w#0VSV7fY}55mIZh}gAo9;Xz_Azt=8 zbcm}r%;H1_pLW6?SMt@Pr>8u9PAoYl9q(t(=84`u@K zMp`BT4amqt{^t+RXv0Ij(DxrN7q#n!lp(3S8i>syqDCfAY(Iy>VviseO+?=8cfpp= z5+B8TT_iKUOkUd(fpBaiDN<}IcAG&$A}tnF7jIs!OJPDH=A{dQN6%e_VeNijZL3h7 z#t@d%u2~kB<09?skFekAquZ)Iu5==5+0J9HIz+6{=NLUxab*-H0!0=)6uTQF@0Br=)YWZ)G_{$Ac_rUW6j^)SLlI!>kFDI39 zOB1p6nH$S6hR2TGE;p%Nt(o3XYk11wQl=m~eqy^9q<6jlSe4ot)-CmlIZcGqx;#vt zgWf3FX=~$j;=$KZD5Tv5HCBi1qM07S2AS{@M+-avBt;Tl&Q=~t$0ID=Bov+DYViio zN23?Pin%i~;fgGAdLkH6=pE*FE#g>qDHD}N=iw^enT$31pikG)B&c-kgb#xA@cMDX zwXu{?C&{*~j`Zi*7OJu3^Rt%>jzbm57Q?v2ldv=jce_*^L@%I{!g&G%iLLGcD>5b< zfHgfLs)H2vTQAX&hN&r10;1g%zd7;C>h;JoL%*%U{BPqni-#hdbb!{{919E7NG8<%POR7%} z@gpWGdEI5o2qcf;$Sdp-25FD(;${xjqfi%&$|K47?_R{o#45$sKV-EAqDi;agwSQ# zbStRd0mxLWMs#Ylgs|j#yxqxgzY)xR>@qWT;me(U=w4_?SG%p)M;ouA3 z{YqF&*CuGEl1%8+urxO3v2 zG3;-dhqOHw4y~1P=o6t@lcbcP_K~yssbs_42Oyxn;%inB>8d2kMeCnN`Yr1k#aN%6 z_aRuLE>GSu6^zuWUh=Dt1e@OG6LGf&d84G!FH5Herom(9XX-q!U%~VxM|_o>Cw^cr zVF|H_C(=^N>liaevhmAmMZH1zpx2Ru1sPxmd4_rpz3@}6-+b1oogwOLNtr^PFB9qF zk)iWFV_k(VCXOCChqG3L?6Ye9<5Yb}Y&0@Z1@Kzt;eIkB=TU{W{6ygYt%N1|12wiJ zF1}{Yp=S2=1L4rBT;%OGbaY01HC(I23p0e|DB8qGvW~Rpl8kQ=DKI~C9v6biF<*~I zR9sV`IY<#u$F|eyD7?|(ejAuY#6);V+ZAKoO)K06yJICu z^9K)qA29y4ZxVp3FSo#zA_I6v3GN9%TF(HKzrpb2!0fFKWtKjQM;s$`;0_Qr!V2#W<#LRMnZ|PfL599=9`}7vL$-V-R{^j!5 z1`6$ub?Mp^JbMPWU&CJ#X8^`u%)cghLFXOa1c9K7e`3@ z_7Xg%qkI!#b8-!6{~xwj0Ky;KK7feAeYMmJ{_YB(ah$Pn&i%t59(?%;^oP?jL=qAN zvO5Q1kmS}IEk#CfH}xN?fk8?o;MO(-Gq9*2#OW5`fikk(FeWShQxjJ?;2F!i6k)&! zn3Ww+I9HD1il)bkAczx;eg)PnfDERcHik9`o(qIIo&AWY8QV8x0|6|TFnBN|=tg4W z7MQvPa)70STj20-7H*;#lhqi(dy3k?`n?MJdJBNHBnfF<1qJXI16GM5W0DyF9y)9U z)f>!a_AOv~149S`%LvB!OE*uzD^Tx*c!di{fK|8zuAE#0pvETLMfr;Zf4I>y`m0Kk z5J9+q&{fbCJT48m4U{osPaE!c!;cCLI@`MideP!quY)dbffFF&M&bruB9u8e!V}J= z4YXX}06}AS65Iz}S754le{jqtfCev-1jr9`-DMZdI#?!9A?`pBuoPDS!A%>uJZ^If z&qV7Dm>CcZ3TmA(c^^c9s`?wAw*%+v_8SC{$xkp%IOD%^y0nA=Y(eJ$(v3pyIeN+r znA{Rr`S1$;S4fwyk&|im0j#TJ=@B3sPk zVE`S((tvsn_kh#QfI`p>0Ej5^0Ayg$4VcnBK-8gT)h_5}9S4rchyjZz30NhYLAc>= zu;Sp&7%Yz&DDxe_1mtxE{=0TY+++a2_6`aQ{@S?{OAe@PFjRbLxX&M=L{8TDw_)G3 zfoFdKNE^xxfY12$F9u}6%UG@iX6O&C0mv{oyVe^?az*C9zF>C86fwZ0|Ij`RKm&DE zJV_l?V!336e`7PI|HXie%>cxILK6NF*FIyi=^wz2h~ixt|F~)ZfZ=aMn*YeGka6jc z=NTisv-(3_VB7g?2X!k5ZogUi!)$O&k?n67ytf3X{TNl)O&n*Fk>PJHwA0+X{Mq* zJbV@m1`vXF!9B|G_{v}|At*O62%H^QVauSC9!S7BS7cUXE`yIg(AR7LP8S(t^3n?c z5cQS+lhN|zyN2{P*YHl8^N*uVkuh%>AhKp`{^KrW`WN)ac9d-R$8zJU=nh^+v8l)m z3N15P8O(L|otWUkn~b36A1Y4H0Z_ptk`)7u!h!4S9~y&?O@C;e34pqQGKLpB zSy=+?@ZdUqL&;du_U`2$$fXVdw&BZuIOJ{wG(!lw1TXdw!T}I&z@ZTA0dUSFZcac3 z3SivRHau`}1cd-Y08p0SwceP4Nx{dYb6-U!Q0zBOJ_!qO8G*~iI30?u7t5e(|D{%4 zurB~HU{lBj54nTt$_~)Hdue(E5Q40agZ|>+CY3;&&}Y30YPNu!LYsItPJ& zX&H=QS_R;N(7$vuOd0eO;BEsG$@=Ser;}H$W)PBpeZYFX>y<_TQ&2C!w85~OC>l5b z?3N@EK(BuZY^Y%WQ5fBN3#k9`_2In(oV9Mju&-a<4XdYj{nI`?X3@V<;kFAfUK`+a z{WtR6z}tKEcXna=-{^X{qa2X90x16D-374Wf!hk8;HFCWHiLhT%;3@T((ybp$CcD{ zNy@DV9zAIPzJIqA4?iq}Tf}4hhz~r632fkfxp>8ST+=H(%XygE7;NzK!aX?paD=O6 z`lsL9%hA!JBMKRrB}pu0rtY>$u8T{{++U)<%zd-e=xT>>7nhDh<_3R4lfA8;s*N=M zh}wm&G&FW!nK@{F`9SZD)CT4BL*dbYIVkz=YegAmoI>dGnVa- z4g=YK53qW;Lszu+=lwppA=@(Dmn~KWVOo78AMG7;m@p63`Trk}>iBZ_V|q_jX_u_0 z?-jxa;z`;P+z6uYv2&x+ECy|h zB7WJU3CmQx!(tIVw4B5n1-HO`JZt>S09CLw*Q7U)9e}lxL03ks;1HvAd2iFtNcTJT zs&HpU?d?*u}Q6qqd%NGvOGg6 zSL+H4kZ)$Ju5skMM{LIL`vxmxEceO2(_jSd&ha<&A4@v;uS(`Hf~D7?m)xURbZ_Nn zS*lMWv$A0xTk5fT{StdOt8H~7JOwYTmr&#<^nG|KO~oOq((AzXC(L(08a5C`nXs`N zZhwiwt4h4>+Hqa^ zm8dK(_ihg>a`D`hw6wI>nnxOSZ2qlj zkI9+KN*~Gf(fG8LmJp>f zHAz|o4_IyGCUmg=EJXBxUJxrODSzR85V2udv^^%;X-W0A9aFP3L_U(zYK>Gd*~}hi zxL1Dao!5&VQSoG|ZoY;YZW$-S)f{dzmy6X8T>I0#HdVy*P6+zx3id2MGeNPs8JjUp z0=%nNL6wF-{w1Fra#L?o>h^@O1|8a8Y+HnSvYEn`vuOSDyGWm73GwspSCNNfpsbnx zV4Hpm^~QXrUs}+^+#pJN)4H>@o4AN11`)UEa#;s=~Q*B}FE zm6E@nF+o&Qkm-rXw`%Q*(?<>_Hu&yJ+p9#@2V2kIx(F^y91NzM^vrZEida@8Y~Osf zSSW075~k=?5jw*~hTbbW1Nn(-d?#lKB zdOM;1Z%Fj1Cj5Hy*wNMqq)|d1;eS;#Tk3c?ySxL<2Y|z{7LA!`tq10t)fgn9DJ;5=q&{n8lz#7+}4)w-+OUG~B=KlS*uLz*QgQD`gm1dsK>tQwaCR(+C zwe8F%>JgOC7rMwHFpeNdcZ@TzWqo}S}USFXHa_vfrt3X zTTh>v4VyRrG0=D4daYiBYm9#h(nzXe9xAza8XftH-O;JI`ksrxB|gW4%^l0nd7<^{ z%*OGbCM`lsCG{TpW|8h}PW4BQ2Rx#Gvu-19=bm=a2+Z}?5(&Sa6B;(|;cDIN{BAiMxcthoC$`swtM6|rG4wFu;(GX-rilk^<$y5l z{J-c((*+=6O;KXPkIa_Y8P(67hTEg$>?l$_zR`bEo4))K`i?5=WEWN$tZ=cpOATnI zO2Sw>-S}iFW7)1-Fov=YRj6kLiLTGEGA!D$-kPaHAKmH5P3yT)JBME5|>a} z1kltz$4ZeYD@`cJi2Q~9hCCATl)PoSh{9`Zx1|$EAl(0Ye^=~l)#1bOpb7LfQ`s8Hy<-;#w=(`q6e6$rH7qbW7~k%_U3UK2wkyI&@#s9Ig;qQ&p5V^+>O? zu@TL(@6kC(7E2?R*?1k7u60IvcC}A=bv<+^$QH2HW2wlE`&HzK8tb$17JO)gjtHuh z>?Dlg4xf$9i3>xiIY&l@TJGa3-);AGbryXt?bMRpO{{8-VZ@mqzNbebf!MBGjYd?hIEyf%9!x1KmAx&)M|LZY|-R~O{<1|hJPc^Na>+P_G{=Yy|%uKqZE+=_OEjvOqpjV zb_a!${eIQkhX`+jiNG(FDD?xj8zzaag0nR4G>!K`T?!G7x4??_)qjF|3*~C;*tEBr zVG~Oc--TjssAF8PKS-X(`Qf{+ND^Ah*KeUV%6Y_8xd{)e0Lv#&o+eRGa63KB+P^{p zzZldX`)>iC8Syim_!h9s==W814-w>6ikwQG?M36xAL2YKpgIdgh`$9sU~W!8o`Q1% z%`SoZEK6ErwJ#5?CPV<+d09td6QSPM4pY_R@mCU%qh%I1Vmh_X6~_yUGV%~pg_^#y zk7oR|$PMzpEs7k`!($xk*y8sga)_E}^P&14;L=LXtjkhx>w5s@Fx-#cs-&>vAfQ5^ z0Mgb!=G`;sZ^onS3j)GTN#n1vDXb{CXX=;dJ*PASiODVdj=))87r^pozK3*oo%`K{ z55D(;mkyT)+)yfcH{S!Ndv~)v`0*Ls&ks-wI4i~*?J*@waB&8kOGN`|b#;`RPI^@w z>F^3r@aCpWuUCh!ypDUF`uC~cG@u>eH#|%7PEh3!YrZCZ;@=Z{`ZdVN^C|%{OvZ=yk55xdlCuaS(4cFkfdE)W|;Z9_@7WQ}OPfuje^U_+e6C&-}p%Ej|a@?$Z((abM)zG_t)Jt5x} z;u)-W6-}L5W%EJBt2aWERNcoxg$I`PxHb^ZEyIc0LMN@o_sz<_X~+NTL|aLyBJ>zi z{(m5hX@n;79VJT$z5pY=oobdn>Mn@NJU5>c&TiDsGIvWXs)b{XM^O)E8ehNFrI`f3 zv1t022#jlc9%wIuQ$SU!RswQltmFSgh`9x}^lkyI){E3zV502iLx}KNp?7|OkVE_! zOFLc*?IN1ni=Qm6Ef)x3Ev@@Q7}4{AAAW$}08u_Z>Z?vsWo@EaTj_O^iJJPZqmP{o z3Ad@CV(~=v+tyHnQK87pPv7F-$|cE{P1P^ z#B7uAE}h+b@Y@qnSv1_(Y*y6qUjD>=8_iD^R7z*Qd3mJ8Bp&1t)rGnS>}^&rqF*dG%$Lk9j*Gb zMKX!t-$YX7MX$?{1*N$lGoddQ$BT|3?1qGC8^a9E1`+ohNwt2 zzPtR^xeQlHd*2!NC}h;Ny(9RP#5B@adJ$`*%d++O#aZT-L&jbz6K^4Jjiuy8_tYvh zGh~e$PwSz1ZX0J|X$`A@3Cb|DLu5%$C<*xC?R~H!(xndXUU%zp;t#*JVU zmj4pnRyfHV&WUfhheQO!un_Gg!Uggv(#cmz^ndP*63{3_H6^Y8)St2+D6=v4_0K_W z5Z(6A6hR$-c+D%Hw$4N+*5kjfHNAN0@~#i8f{6-wLmxB$?^2Z7W8o_z_AxD~SMm1{ zh5%}jPruhK7OcC-c`HoRDn^%%j>bd7C+PWC3i`wgOS!)L6hC(8xfJu%Y=g#n7`kBC zrjk)v=I=ui93%J<&6J79vha-z2F`oK2<~SyHd{TRhwc28}H{1HT2s#6!yTH7m7+D2f5L zXF;Wr7Q@}mZwMp6B}Qos8fkWLnN|Gx53vpD!Sw8Dos8O$Dda9gYPF9REP*gJqqS`X z-wg`WCbJT3b02R1h`C#Uevv~4VBNuxQL=}$KBXb$QBDa&;cU-Zje>8J1dr?Ik0?cb zb)j3})W+epMm+=*&bDv|ihLuD&*&XL}t!-1`x* zH1zuu%qJ+LHjT^b#^!%QhM#HHJ+wmq#p?JlNiX0NCY}NE;CAf_&F(RGkJKy-iS(H$ zhi3hH(0;fESOF~dw?Oe@!?&;f`S5eHv|8OVH-KCN&Eg4q@okKD zB3#ze#z27hlQZSg7Twp%5@(suSjZ3gZUJW{qS@c1C9)>pz^)sd-tlELvJ80JO0=N7 zE>2TsO76E(etrvdnP(Y%PdGN_w#)u$heh}U(B}LEQRM&Th@o`k>zeSHDRLn+x8QUZ(u+wxsY+>F6ju zC){E`F@C|`s?sq{G#Rh*ILU;`yF|OVn{JQm@Da%>uRxdXv5I(NX{Wxo+Cl;~)6l_; z%agiqo$R7a?=PIViTscq;&;1<@~Djc}7DtiasNin$38#_u7VN6Bk$0I_Tu+~lw;mU1&K*j-I0?Sc^1=pNT{=uTod ztdNMeM*Ym-W?YFEvF((nYDl`oBX=cSi*+HFZ#-c>6%3-)L(%KDte0QA;2G_Gj(Hs! zCmd&ovbUM&62O@_(ubw?{WS);$=UEqg{-P*$4p*$#{Uq#Jw$D+v ze%ULp+13p7o$$KMnG;UP98i(%bNW9|U~fKF5>ZELlNB_hsg*Q3lJd>^2hrs&|L+5V zH2K&Ph23t~p2DapH)IdZ(C?2^l?RPeQMH2eFg9H9R!s;J%0KtifGd{Z|F?6u2iDvr z7+iHbz~yNl-Ix3`69b_VxUUs@>??!8)z4~Y-4_lj&SEA4t<;^fn93B*rv^Wyvx{TZ zp-z7C7+homGaAGtHJH|uckn7aFI{x#3=kOcMD)oEWgsAm;aBa6li zDakGCjcN+IeMSWGg}3d5awlgu-bV4cb9zP%4+tigFz*cUfAloJ-dd-W@DbFc$1yK59+#GKz(4oi$pCH;}D;!@bV`gp?7<3y}VYM{$}tG7FY0xeV5h^L$w+PLQZ za`22vFO3*U56ABwN2qQhnW7;pOle({BAMCN$^ZF9w9&$v!S$^;G zyGmW#)q=14q>IlZvC0|)XOO1^1^}gH4VA?M_v+Z?RkQbBITRQfQ@JS4GM`+3Ar6vI zhR7)=MBay8iz2n;$U}+3(Y`Ft{YJXT8(AKe)7)RDZu@GcS7YwV=#spgd^u zq^a7+?)SI#qCvg1GS2^T79`1P4SL(XoAz=4w!f{S#Klz=Xy)*LK%mob%&eZ$?X!z1 z!!s=aJR>AjSm>}V^gNDY>&lUG7rg~LjscMYD`9@r=J4nyjq2s`gMiPbyzgWNDyNYk zzN0Z|qC5Rxda4EVte)*O5UW%@X@OLBp7I-9T}!-=u)0nGFb=`xY0wv0tLX!zGx#Wdgpp-BqmGMJQ zMD!Aq8O3{1Y33x2$lV(wQI;*cTL4j&nCr_{MpWd)&mpTBwOxK`vM%N1{0ktOcQh+D!aVU`5vlNS8RBOsdQ=oh? z84_7~Cx=hf+8H6Q6gIKsST5hIAcZ~Fs;##q&8xF+^}@1#Wq9_C<}8f?m2mMq{;xKIqRkMNHXcz{&_hn z^f8RBBH4-dZ4G58V}9qDK9nwW>-Z(+exy5ot5XAuuguTy47=Y*h1Tv{N46| zi-iIldkP9A))&YeOWkib-Ux%otVPvb1cQB6n~ohCpV~i}dl8<@t#46^pVgu|>h^j2 zn}c!3adM`f(T;xGlFVAm{8o+v3L;*(CfJ6 znMdOrCpR2M_T=Wxa8Vi(A*J!E@^()-nw(YT`9`30DnzT_;Dnys>Dok{6kZ(WtD%Y2 zuA2O+crKi1^|!_(2W6yJZiPRK+-B!^spma2r=zu5L9H;)mO^3KB8^^!zOp{OHICmz z=jd(nAt8hPl18ZWITa=sI7AIf!%sJLSko zBqH^NGf-|ZIz5h=OzfNPM|FQGTx7$d2l-OGHOPxKQ!qs|e9pBrPY`8>lcL6NGliuY zA2H!^0m%X~0t^>9EfaZ#R;X%>DA^<3BZmh=BVatZhGfOIaZh?QuF}W?;=SU;d+(U* zM8u{Q-D9{r7VE?>@D^xCb^$&f%n510WaRm#H<@sIJasgRaH1}R3}nodiXpP^jh0XE zFTJ=JnKGk@#Q;)BB0IE^F_Mf00*WwSJQ&P-LfDkSV;b)%k{bVNuj7qdg(X73+oje6 z@t2uRcK2O{#2k!O67J)qhrhgsrVVI66Vh6@+Zj2bSz_i_8Nea5Fr56*)2Ap~{gNO` zfLQiRxs8vtk%88Kz*moT3Da8(~P7s z`oXUW>6HvEWL+^O|GMwxm9kr_l+;I@x;n4|ZszCIL|psNBff}YwU{|IC zJ}er@)-{uRPW+Ud*s7AcxK#i`4B-?#E4weiBRKQR@8QlIU5y*Nv%LFZNeHdwa~=Aq z5Y27|v`_Dh$b`S7$>Km>`4W>31d~^?0x;Ndo%O)PQ2EP>J~okXaRVtwgNtw}o(v{| zU%L)f=+NUFLHgl^xngwu9EvBHVmQ!yCRLn*om9`4oj%W>1e_=dqvb!vD4V$~SQ852 zEZVg0pvbysHPJ+}5Q0MTRyL^y+7&jTSuyADS4E-}1elV(139 z)G(-(Uv17T^5q5*`pDN8tUcA7BG^=_F}y#*LES-r$l5r5eeblc$X^O91zBFSRrB$83bd|nbE)}};$7Tjp zyU7S~`%kCG)|jmO*e_L3quyhwR=a2VgSRsIY`^Y{r8hp&SE&T(rC2A z%D+E7!zQac&Jv>7Ik~=0U;mP;Vd4I6JMNK#A`3g8-fY%pr~?q`yw zUDI~)X*cJX6w=EslhB~^v=7#_AB-s}TAP@iX}#*Rx7?iNK+4^nDoi41kK)T_KcZo;8ijPfhGTsIA zxXpW2c1w9Z;!hYpOAC+$AW3$|EgTx7W-kdCQm>w`Xh@gWxxLjb7o6F>yzF?53AXA6 zfa%AzEf2Y5-?%|_3}PBO1%Y=5=G@Cv>eb*7ApxglM98@2Y`POImAnX;PT&#F<4vzg z4K!R-V4!dDzE_f?P;>Ju4Bxf_HV$hlv1e)VT;uw<`j`lsZRjqlUBVRcX?Mwi10v+! zqPQwKEV8b+r@eA9(dl{S!a9jh`ovnOC!9-q1*ypldV|b8{U3C`2^8FFr8qW?yD00q)>{oMI%w5_ ziZ6Y-QU%b>sy2z}oD^w@*eF64MPGB&?mfkB;c4_~%V(eOdmU{j*=@Z}pv)jN%J$Gg zzCys!3yV@^s6w0p$5Nm?VOc;E=;+Tq==xSYzizkueFW)EbbOi)nm&5>?wQ*unI8e} zmX#J`>X)ij{GVkir_IIn&iD=5jmY0~cT~vF>d7yXDw>`h<&nH@Orx6N@%C=5&b<<= zcv9;0F@`X)^Aw!;W!YITl}=1SdsFFo7VI%u=}~J7AF~-7x~SHv+^T5@roIWlTsH`w4oqUFul6oRQCYA|R z#Fy)WHFlccypPCjAkd`SaVyVZZ_`}1aLg(egIY~Yq;|^nE|FU0{ZeiFRr7RJ=7U6A z|94p-tNW&=p5_FkYGu9oVveNPoCL|^b^cAl-zMa+=3XxLtR!nw&hP#d(4d0?v=}Us z_$7jR6jcd!KdtIN^B;2wM~J^D!BdbM^D5VpTC1B*d0ZjqB-4M4k{f0|wDgRh4o!>b z*R}ex^gy$%#v@{$e6&-DuE^*ofdIwE_qGMh(k|(($=EL_^yo{6_fXSkifYF0Lm!)= z8|6Z3t9!9HzP4=t|2#i+MD`jEoEESV+tt5FO-_{QR;eV{&70{tEe_9494wk0G-6B?WK?IP~g$oj(|7=98A?TM_tDc`E6 zk&mXzm_=r(X9{{bX^DDctSEKF+NJkh*YqmekZlFCfI}h4@`k%X5lwsYu+2c9spB0& zYW*IvR6E9dhMeY&cDW?WfYn|u;!d>pxJYWlq~Ha@UVa&O9BQG)U6q((^hqIj5p%XL zW)Af0go+LIa$WqS7h_+XA^ZxIN z)H}`5AKjeeVEu8uDuD9`Lhj&z61Xj4U)rx}v9IW~Q^5}>+no?7N>Yow!m=lP+HQP) z&4H}?dqhGi>?P$(6V5-R3|@FZ$yV z^;TOr4wi_{_F^0`-Hg2KRg4w74HLdhtoNlF=*=&LU~(X{teoTy?kInqmGZ8C^J>~U zY>d9ka>^6o%~HQ0BE@)ak;Z)&wfM)uw?QT^fcS}5F`JC>@Q#UpB?(~MX-xjKySf3Hx zym+Ny&JTe&m1N~U{dw*{_{!oVyM{|&|5x;6!=YaiI!P#mX@hRe4BDT6kj>#JS*(#) zv4y7RW6k;vKsdN|cF@g{?icF@c+vToULhqqquJ5EcDwlKLsmvY^Yo|7dj3n*cEFn1oqo0yui-q_g-7wM~EYEN>`rC;P?>pWNy+|!|##hWu7H~>2 z5vmx=Y^!5c9@zBFh($(-LuY4^@llwd)&HpMQ!_ohEV3H|7aVyqfIn z3d+1b{StWjqcz~rwB@{P$$x6E#r|~Z!R6jR0cl|(G}ai1Inl@o3oOW1g98N)o;hxI zryJ}j_HVbsTgsFFCswvewoWfyRm6L_U_U2TT!f6d-Z_lc!uNiGl9PD~q(7e242BAp zDoF#pr4=cT4X>pdmki5yvY!D=j_6d&hR=JESAy>6`5Cld49>n1ms6GQE_&&>Qg&YW zi3|9WQ)_rFuR57OvSw4KRosy87jML-^QkC$VtU?c(cqyK-FuS3NIy3G*~&Q^EOY*; zO|4r%Q0C-w=y7`8NPLSspH-7G!%&zO3R&YD2jd4AmAm}SIHiWony88#!1sZ{SJGpt zk0y8pXR*8bKA={*5|^f)*HzKge$U%?+Eko$3XsZpV_V<}-i`uiny|XiWHFWLz>1H~ zsEn1e@+${GL`te3s~dM9Iu;%FbXvUGkeiJjp4L_KM1AL`qwfBssYcO7*y{vrh3 zBr?V4ndMUbDRCxm-}l$X=cn2Y%e$FfE)dKP<4l?yk(-*hJ~x%Rnd9Q7L@wdSPp)>s zoRhS7ab3GX;Q~_aoQ+}UmBv&VtK~gJRs2N7g&Y4_2!0sAXZG(zE7*uKpu{j1~(G-`;n#H85y!R)LaS{>p@KU36tz>BsRIu2oU{E4BT8t_5_5;6QsUKD~U2tPvz(F}ESP$kz8>jd{%C4+P;!IyF`WDcnqQjwNOM!^(2yu?9=R|kp8;ZnkdpHT&I&p&$z zx;&_5b<<|f?e$GhAq=gk6~^ATa~GJd`lM47JsZdKWh^!YB_}5`Jt`H4rUUL zf%SRO99k@-yzLkXV4p`qCuTQqt({}$G0D4^>@QV!R^t<)P)_>}cOtq!hGefiaNQ7{ z7zK&%yBcF2l?{bnNb7x5b2Npm2QbE!oD-Q6rFe}!-SQ2ulVY~2tma6z=CNQGs^>2m zk@-Izwv8NfBr>_$x6TvFnDgZ3!JGsxT4IG8(R;6rY@a#w^Xn3$z32F}XMy$EnnE!D z6}qH?3adH;{z#uCZwY-89p8;mb$c9b>8YV!ZDI9sm$cb$&Mco@<$=_=;)mO31y8*9D4^;uk1+6k9+T)2ZTz}Z&0#;92vd(snsTkYl^bIH$jOJJ(D63vR z#M$(qmlY~XIPi$G9IVRy;WIiSIkP!c9Qd@xm&E3qrIU9GVzQ7xA}#9LSeff+N9qgl zxdnkQCgvh(9rUNc@9CNKNG65ncL1UJO?+cwK*^xoigef{sYN)Rty>bO%~8{`aAk-AIhidfYoOx@&*8WC(ReEn=v?Dy7=#twei9w3abxhCqsi7t3BVs8Mq%fq}kSk&y!yb#h)MlmmyK6KeIiF9_)L{nrW6^WTp_xmXA5h^Dz|(`GfkQ zbfQk{K+StqZjPNi5{&f&vnQPhA)lAM?lB>9dDD1nF<`SaP73%Qhahz>8_>_ZZIe?r n8w;K~8*x?>zlP;o|)&aeeG*sd*AoW{22f76(UlUQ;>tuz=H#g1A=~hgQ8@8 z?Q9@OL4h5*2tg1AM1Y14iGwR%@JEG)1)+gw7w~uW*R>D0Mn0r0JUrdaEj{VYooyYh zt>~Rxyse$AojvKT%suYYTbNrq*t)xTIa|^D*m>Tk_i#10w5GRlai_O*arNWk0HY!Y z{{8&p8&>RnPfu47Zf<7}E^{jv3u`V*7bk9Cb60L2uAAJDn4~Wl!NJ;--oo0}&RLvs zv$>s--p)##QCC3urn0NF^?kd${_fVA{wi9Q{tlMHR*aGoxMIE{zD}-A)}H3{zD|zL z9wNTtjHtmyz%}x1Zbk`Q95Ht*8xai|xnFI-D{;nOi}CUC;qu|*a&foi<`EVa=Dx|x z&CAOPT5x*!IeVJ>ayol3A&2-mhK#j`rMsQ0r=5#4J#tKQ3l}d>aYn{p1H0aL@pSRH z@8bGr_73GPkw%kXMk?`ZEd`mCF`+&kl7D1-Px9jpsk+x3c`x-qp+95jCroCAYOB%Gn;E zEf1LLC%UeVULJp11KYejtdVb_`Z!wIaDxedjs2?w(hgZ)0MReF|EFD`0XOf>n?js7 zc{zE7|4ar3)3CF>@A;1z|C>4Ps5YS2A9zKi-L0+cz@#W#=zjvkNdGUCM5H`CtUVQE z#2I;b1^90Y^78TuBklY(sfez%g{G&uCkln1>-PZUMe^m}kXm~=noD|lI+;3wX}z4p z0h!F5?JQZ%om@qcZ+p0Sxm#L`+q$@bIQsLhCAe*FXX`AE!~_5j3;vf|teTdltdxfIU0D@*1r=EZ6&YDQ z1r>QldJrmBmLit!*5;lr?h>eg(6n~@dEsa$VPog$BF2rRGPWVSFlo+90^*1#_iX7@apmM;~+<#;dy!a!m*3LjpeUP&GV;%BU`z==Vd|Wpn zp*sr7n3yQtH=;&YgD{bdphowF#Q#qYq(*m!@c$l$KR!d!5H2?MMeGZ>7cXAK!^OoT zxI#p5=@J1A89DJ4COQ^oMmk0Y)*H9DS+Db7XJEW3#ltTwDj^}k!X=|1Eq3>oxP&Nj z5HwsoJc3IE)I>zoqSqL&iT?k7{OE*;FQWCMTVbFPL+He47{q8lx}d8dYhfVMCkhJG zKMYJPbTsS>;3gG#8+r3T_aM~G3qK|yd<--Qod|;nq`fn-pue^F_oa4x51Dd~*n!EQ zP3-Q!Z~lJm?+Zb;QXy0oWoPg5#HpU@e`$>UeeYk-QeB@sSo-Wku@l@%RuEFbr|^Om zVgDFK|9`dn{Sxc$y3Z!LXeh+Ac#l0pz%oZ?(9@_dU*M{S&hIAwdcH2}40Bb0o1qzq zUJ(!s+?jR|uCuJJw&haEM-0Apuv;^D|F0f@USf#g9gcX}ZqVQ?b$2!GzdrLL#k{?LZ z7G&?Wv=}v|K5#d9^RkS$blGZj_+Un`+-gZ#=1;?aUXbNiKhU&=iBC5sI4kCQAoRQh zmSx>d@~0c)EF1W4EZOS~{H9yR|G6ewzft9&t2>(IU56tAC}=);u+k{UiBe7-!CU1su#P{ClP{FQvUK7* zAT-4HKo;s~C*Ge6v*1TpHcC9&ReUnsks6vWKd60#Ga_;$op zKas&%R@v=;4}xCnOP z*$uw`@BR=ha-UP#?j*{8k>BVbO4CxKC-~XX)(-0><@8VEsMa@NIyj|Y3JR9~m$%X8 zru>_pSKT*FPZ=poCz=LCX>_55Cztfv;=URP+((Xp_~PNo>v`XPv_|!df4#vHcwM;= zd@@Oo8vge`w9V{*&6Y5_tZ$kVAd&)vQ(jg^XPgpF{opk4DHR)m3j@bRqCo zwf(9pTr_2C`|GDXtZ5MTnuy+kGyy>ec{5~N;QF}=C*69?kxh+HdrPp^)U1#j?(U@YfpxpKr!K)S{rDhMRUpRIJ{)KD~aN~F97<=Ql znPph+>9HwnpjXGKK_bs>;>GNKMi~9|_n64%{aBr~1I$(#rkxh{00GPDN?Trd^7j(Q z{xzT^1uJ6X+;bx%TT2HsVmm+xF3!jBNi*GvFK{5^)T!s!!PJm`S{#L6MX11(aVI`& zGM%pU(^2l<#wQ3|d8V_eq&ee9)=(XxYMUcIRi8k}3&w00;4JlHqN;e~NfA}a(PvUm zdW5(QLFE<&H~fw-d$Akj`=_J^?%&WWPAYudYlOx|;;^uxOcqVS7vjVEcYZP~-WN() ztAp~%21GJQ_XrkR0{`Oo_}X0Uz^xc~c$9SE)rb3Q1ZT6(v*k3Q&=!KGmyINv!ozn( zRD0vCfCIcX$e(Xx(e}R8A({oA$Wg`vCRLJ_z2FQLu$tcw^m=kyjy@x_R8u(u){&a5 zC`}Vu7LanB6-O*vQA(UUYl)FT^(q>Mmp6h(+<7Q(<#a6--vJ7w~l2WZ3_GA z!PnIxlfwMMoJ#zoY=`2+ zFGDUirkK2dY~F?-gGBBjJZLWqYxOle=DEm0`l%``3xei~P8L;Z{r4qi3p^zDIImeh zkT}UMLs0{?lnwm<;^x_ z_-*a@K{Dk>M^7M*KGVWvrq`eymf_|3S^XE;<!cWYtx^0pFq&EDIfIHbxD$ghIXP4Z)& zBRiqvIPA<&rc)C2Ux?roI*HFJfd~T+KNcd`t5p+ z%$WF+^dX{#JQjYAiB4f-?j>y6w;-yP#cu(%02?v=n{! zwZP51luNhJjDYFa>^}Q%d+k%C3BC~sI-iPg2prl2$L5HpTiOT998F~e*L!KzdVLR}U8V(seP@Q>W6$n$ zKITX>qSdi=P&9#Ci6SR(Gy8BAIVR@oBN&&^K}E}IVYbNfZtU`H@FpZZ&{$n_R3#W{+tFkukX!zH!$(h1la--^UKJ4<_8wOI!WQd=gDjJ(*xF9Qy%Xu4f&jt z2To5KLy;}T_c*fU-(?4Fwu>zH;uP#;2OUdz=7Jl4cSVAs#(W*WO#y{CJbu)XV)bW| zgXSuDYpb0`TfGa;gAjn;StWv{Q^37Wr#a%=3x>z~$BhPhBV}61dCtw|GZ>a-52q9V>gbN=C;vMdJ1^SB~#O!E%cyJqxf$Lo~ zTraJ8%eKNl+kHP*oxLmm~S%x zVb?M=Ix7x&T|wuv?kz7ax8x1}M*ORSL*Iq3D;P3X6e3F}q1D({4hQWDz3?${w>yho zqMjUM_0Dxu)A;d0z+aR4$4CBpBaWKL2??6M2driX?R3!W&A&eCmFSzvKBo1ZOATs! z44~AV^*f0g3&njpIT*hGp{(NU>u*8106yk2l1#yU$W!qJF zjbdGN*3OqVHZu}C$%Qen7BHC4SOW0YYNgoDj2I-c+Q+PAEuh0e}m#HH6->R}gPN!B;X-P?}MLXp<5MoW{?dOOlJP z2wE$88GXNStbeM|Inryb3hA{3H9 zQWK4WcWx9uTAd;3dhu6fgXVAV{j&V2u4Zp8ge|dyIkFh-ST5!gc%aMY0Q39sv9G{6 zB7J{-v^gX1DXh(~G(c6-lv|#vJlzb*md$pdxfwCEnP4$DSg!J|tUX{NN4CdYym-2) zI5_SIB4js%fEH$9t!L;PpLCSc#Ik4b?9fwHj_KIJ`k<~z?p7_qV^#eY6I!#fF z5r;ZN>C?i;Fe5v)(Nc>n2Qm>vx#Nd+@tqs06ghrLkNpuv*1)SEk@(DHx-BKD3NP@t zx%IXjrl>N+d^y=x=>Ys%^3w#{6#J%n=2CxqOJp76k=urO_O8_O7VVptfqni4UWeJV z))0aJ94s*3L!=-bREw{>1+G4yNEfErVvW0W?_|PF;qoWd%G5@cY5dg*i~EI$3d;?8 zFtf<&V5@v@>mI_m;TwM&xcZxGf5Obe?l7HFuv{D#r>iS?2@*em4ViSDPG9-~(JsO6 zJiO(%lM7);Y}j~5>g=-(9l$)-)j?*sn)U;djj7x@J%P0aw8!j%q-=BFDu!qx`mQf3 zH;5nfiOSNo`X`z)M12+%j+XS_n+eu^P)fS9nG4p14bI6}iNME9=;&ye=-{*rya(8b zjsam35tGm}+~i?YBfV|L%LLBME`qygSm-|>Qirk!&FW7nC%j(fpUUpHxMmN$7~zx| zRmamk#bRfB%*wgUmKRjX#Z-=XHvX6W;SVS@fbM!1Tk*8bn`W)E`L8vE^5gg4T1f^k zEcFSbA3J$H@v-M+62;0c2~#dqC>x^;kDPMh{_Zom)fvDWqg6+$Z+)Q{LVH&7mrl9n z`Niyr{g#IK`fN>0hSD*?anc?O1cgp)`&XJ#2ZuVs4fsoz)EYQna;V?sC^HbP2?KMU&@up{$`0zGTX=T2?-KJKf~5@ahexkM-*Y z51*x}Dm8s@@-F_%es8Hf<&Ki#(221bW|{-$>VJ{8T>hj1u7T>Ol#Px&be z<%W3y|6QGa`oy5fijK4co5(5^?$@L^%;y`;5?iBN{l-?badKK*pTGq%?rq$wEcCDISB=%p|KTZdO3~RbEP_c4gY>a z0acQ5JKX8g?*dBC|6*HPmQCMNex+L^29%TWjAkc9$o%-)$nRjI5por~D3Jx#betMt3} zym{X74JqQ}0H1rnV-WgniV5yBY}W^c;p?mJtmJ%^P_-qcSs8MjRW1qe_EY!$R3=x7yiuUZ`(he{Km z9N`;TsSm2o=4)HA87o#2 zg=Yo@#EhvE+@OmoEp3cI`DEcj`L^2Tbga@jNBvATv;v4)}?Sq0BC} z?{fKM0ddi%@ctNMtDmM67(}Y!JgaY+o9m;;ooZ*#)`P7zZM@sHiL(?g>m^tfsGDp7 zu~auIHC;3mqc!Lt(7*2cO+5P|)2z=$(V$3$vgD!>q+wI^1(yg}VxCL)?mE83R;~`k zq6W+Yekexz!PKD_XYHL{8w4?<1tp$_O`KXjOp(NLWQ!532_{j6nUzFP>vZ}K=xskT z8oXnYzXo<| zr|H)b3XJa#%B7VM@nK#rE?jcB^U7^YBCd#!zfM1fSC-SeSjP7LTkGzM*97ZwnUj$( z93D$@*a!IQhsURnW8cn>;J9xMJy!}C6nDRiUeCS!OcYjDAoH%#;~0fjtjGqVIq!*y zkgAQ__Itx|dbJHx_%2QiZ!cjL%RVLR>q~OQnGfGJ+#cLFlVMS$qV?ZoA*8(#0)*vQ zpz!%F3WBYoFWfUoS@~eE?lPRG`rKA z`T{9EyMs=5?pM=Y9quI$J|+EF-fuMvm7lij!4DJ;k2#S_d+Qa_h|hEOBpT*I<>9v5 zw~|CBl1b2$`6Y`Abna-KYr&ZAXJdX600i)A1 z+mP`$9oeczjm(U@qk|*Dz_%~HERT{ zk(py&jq+fSf?Upk>C|DDMr0HlL4?b~GREr~{R`st@AhEw$7OG&)%Ok5^$ED^MwO`& zQkwn}t-E@hm2UaTf-;5(k4!eSK$$R)sPR?K<756;Bzhd&O0${=~iYV zU9z%oV0zykgxsrA|MW`d%r%Lh`BhU5g~a2(hG|O~4z^FYNN4sqtJsppY{fKUSjy91 zQMDpoM;n**3$JpP*v||zNR{_*T}$n)N;{cV+wNz?vHJF`J>(h<;`I+m=Z`@wE8j

4I|zXEn&}LdA~+tSwWiN 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 Bmnr}N literal 0 HcmV?d00001 diff --git a/assets/patterns/memphis_shapes.jpg b/assets/patterns/memphis_shapes.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2db8e775a0dcd706f86274faeed66991f56066af GIT binary patch literal 175703 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

P+;#Y~ia9LzQn6?@KJ*=T0x6B(hxoKP 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%0DbAu0>y4F@UCFwMQS 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 pUE?e&3!34W1Tg-5)l9A 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 aob!ZVIio6260Ex|Yj6)6e_{UF_WuBco4IoU literal 0 HcmV?d00001 diff --git a/assets/patterns/red_nimbuses.jpg b/assets/patterns/red_nimbuses.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6527999ceb457f7e5a1986ac285ba7a3f6ddd293 GIT binary patch literal 184678 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 Gi~kGB4i1q3 literal 0 HcmV?d00001 diff --git a/assets/patterns/tree_bark.jpg b/assets/patterns/tree_bark.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0dac37d7fdf28897de0ecfcda9fe73242baf0b68 GIT binary patch literal 51461 zcmbrkby!q=y9T<35-CAcx|NoOp$1R{gqILO5NYWeVunFdP{aU66p$WD84zg|hYsm3 zVF(dn21%6?6y^NjeZOz-Z=Zes*w^8@l*Ni)JaIqw{j7B`aqtOZHqh1Ag<#-E5+(^j z2XoLZom(ER5Tvg!4$(poLCOyj@Tz zezeOibYOssGyhFTCoi`E-$0}@zvE35I>6Bh&F|-kM!N(cr6j>Hha>&#_rV->xH}r{ zrz$OtL`gY1``&bsa`N?&zUAmAEh{A>4XJD1@&n_!p!sjQxOpHEf?sPJ1^GRk5rUSA zMlwcz+Ai)MmqP+v%tDOKokF~vRGbAhHR#lDsowJO^Kn5t^563DMxs=2Aq0;GR|Ut1 zr=G|y`=lkJ>V~d;6IBA3JQ`6l9%!gaFdo*QBjeWk&~8_I}h$Sj|xVj z9dDgSqJ$2I_ zwyvLdAnM%`{Dh($5XY79-INXQMEnuR5%>BRa3)~7nbLqU!b#0w1=4Lt8hXs#AcABic7W<0v7_T>Sq&@b=Jf_3-vpmp%+>@W%6mzt7D)yT2SNv1{?ol4M(FNuHnDWOQ(KhC_@h? z7bNO`+00R9`Z)%mT+D<0To58xUH*1}h{k_DcB= zOaI5x4_EL%cKo;1|KqMB^f~g)e}kVxR69BcU=8?I`rkMR{`fbNx*!331|8z$!5ZXw zs(V&AVNE@O%c8vBI z4IM2lEj=9_Jrg@K6C)!N&*?KP>_U9!&I>5!~_IoF32jVsA*_uoRhkw zudRL=j?hp$90W#3PtU~2#LdjittKics`h{WIcR}cXek6KoGD=}5Csd2k_C3~9^wRr zi4s)AqrLzA9|a{9jG6{qV?QjF|8WVTfKgH%OhOElFo=Sgk{Oh>pVu=gH^vcWgAlY4 z66{DA^joS?n@MqXhfYZ2(@WCGvnd#xjptMHS`=B2F#h%&C%ens@DNlh;f!gNj**zh z*jTljn(8*Ok(O}JNLEP@<$Z=XJ*U4zAvV9yyv#~-ok@ZyO0uQ#87~OvRr<;|10IK` zn5V&Xx`dT!Fm;d3H+zU`Gu$}hm1WERQrN5( zRP5HfL>@zUcQ=PoWw;{KR$hic$4&^9B}Q*L5o**(r8n@UMPDFFo`8`okqlM@s?VmF z_yFR?YZ?(QawYarcCL_Op{3TtJw-xLaJc%Iccj9=Uvic9($*<2xw1sk!L;AU`HT@7 z;d@I&3Zw1dpDyXpDf8eTEs|`c9=IZEd++CqbckDgqE^x`rk{S!xD(QEXq3JJ(P6^+ zaSjk~T+k2#f@qP!w(4~d=VD2k)k^k@fg$Xk7q%YkKZ|R?d1vEia3q^cNZ46bN& zzBF4X-wA|&wRlMa!Y-mz&S*&zM3iHLg12=tco^Oh4w9M1bMYCW2aZ5d4nNk}bbugU z6B9`|M2Ro!8DH4mSi#i_6+&j^zF8v!XCQ<|L~OvOB>(}CL}sQIz1O9Cz!KEdUDLim z5Zz9IrD$cFQ>hkun-H=9L9JmSI%!_1OUtNjt8^%4VNkg z(_&(oZnHsI%221-m1!D>VC4<8H86us&A4n)vl_G-aeyAE>~IJj$tJd2wy`92LCVV&F;Jid4mnf685 z7fUS0JzN?Dk*P!iM%?m-)u?&lDySl<;364^Npvx|-Zz(Lt(&7bbEC8yyHMpsSe&JM zi%c(e<%)!@Zfr+FeKz~QK0&_zK`>H<5?XTEPK2IyKKs5St4vbDgeMdth4O! z#z3$p%PP{==3!uDR2Bg=fS}Eg;4c#t!41ztE>(qn#NGZYJFmXWwX@IWQ}6bG;Z~o` zG7$=4nFUUUE!t-zv;e#iLh4F!*Vm7dY7R$O!ljmBRTs{8GZO(AI}y%!;vxaUso`<) zkw=*)Z;6l}1ZU(y-ARz@-Vz$3@lQL1Ul5w|gQgWcO)|5zkst_ zx9`_~{}`Net;+REYna@)tnfqfGLGPtau^hm5XVY(c9=3O&o}G`-qotw1%k>@1C0o4 zgtB|aEMjxjtuzE*G6Ec2^hJPR*EbR@@l4_~R3$OCxCFs;^fDs+pedfJan-k&4zG>1 zZV>N|1ofeXt&LVcnEF&eJ^?s85~A!`A{RTuDnq{DQdh7`Ux%%7V0Hs3BYiEsFL%%b z#);h>Vc`*Wb;&)t=qd%eA7`CPt-Mm8f8vaO?inFc)dL68YKrIe;^oTT(nxJo_Y&z7 zv?MvBG6H-8i4zZzl`Om5qAfITD3m%>Q^f31@(`X4SSHD`#t+NeRFUj1CEFnWmxfwUt)FgvpN zJdW^CNiy+fGtzvc+Qbv101}F8{wcvW#iHXVhr-2))uM+GXV;fzRh*iLOwY>?3(9vw z?>uvdTuN`PU^ADV68ugIx@Qy=?A4onxRfC|^pwExroaA4g#C+wL5QM0^ICfe&eQ76 zYUJ4&vq3LhWgirbP_LVA2)S0ph@)7oub7HU^y!8!wS_q!f>h$I{%V`RGB@uXfRaK4 z<36=htNzLB(Ai5v@CY;~J_poy>zH@ie!keB_?$zm8&`kRa|y(A6BJ_lrKhfXAlNnP z$dQ$5E~OUYuUq}Rapi{wno1sI0#6(M8bD}KUYY@!86x|o*mXJw?7AQX)ZcN^P&q`g zS}gafdmM2oNU#$bT)oJHh_Gvjge0cBY}_Y?vg9lUBq!F7b2-&>4Gcck(~=z*_f!}# z{MBENdt34(52?CTsydT0$iz&9_Z&t;qf~r+;<(}V{P}JG`EU}*{H#cbwQnVy_ABxV zh)w@-;6eM8CDaxK@Mo;TcmNP0HW#x>g#m*d-<~O+NM1J+rJ@xYx*d-RaDOnNWwoAl z#C(fe)o)3+1Jr{irl)-|i}-;di+)gF%Ul@-Y}R@PY?dZIK|JR&mi3oU*S@@TZ9N3**BzDW(Dub~bBReiI5?LjI#uVfQ-*CfgsrTbNiJ)!|Aq1)b3T#nE z_Sw81uuENe7P4qJ072sj-7l+0NkAV^Zyb>TK>(vH3`l)_tixQmz`gdgCBT1eezTFH zTF(U#5gtS`X*0s!M9~@{lF_2}v~LPgG?9qua1bIa+T-4$v5Sy&&$@3un9{9q2yVAv zc4zm|j@C)<%|H`dv%wQ0_-9;q4_Rj<1Y_(ckC;-e;2Ofe_1P?DU~H{5$}}%i#K)eN z{D{icA*Te=5-bNZdI(L5s&fgaG3w^ZG6=-%-p9(t-0cq$Uc)6d!$L-NSWD*-m6 z(8CXmsFx`@ebxYR(z{BF;%rn4my(NF6?tpZZ-%FQmd`r-rByvt7SKCLLqB(h3u7Ln?Do-r zdJbcc9~eAFhY=v86WS8Jtt>igC59K5KtT+FAoi8yy<5KVY7l_wsgyi#(+V(NEKnp~ zKrL`S)~X`U;S60iRhDXUxrCK~Z8YV5!{lzY1edhyWe*aA zI)cgLRRv%#r&ebG+uQrm1W9&ROAKN^IW%y1rB+FpZw+Nh5F5N1l6%azzd&;&^hPVn z8`Bk5FBS0!0KmGh7IeznHl;<6&QolnuWr33Be28ckeccRfJ)^*E>I9+lyAO`a|a>R zMgG*lu`Jj`wTWIds+iD24K$qcJ`RfOTaq>kK!)rrkNj|N4o%47qj#;SOIuj-#9BIG z1y|>irUf9bN&%*$Ye32iaVfQn4pHt2h~yS6yn}W#WNV3kc!o5SawD8}9ca*2P>w^B zS0n$9sTeZ-oW=XUHb@!5TO$a!jAsOtMW6jMsKW*n;T^Z+2%C&{Tcxp02Uu$kWLEWP z*9W`%6`QuCUR?PORHXrNuBUw)HNnmk>sIMLL~EebAZo7D-a|G^M93<6d2=g@u{W^e zJnD>#QMoH&S<%DRn%%E2L$m{e%a5q9>~OG+Ytaf%-;=4n zB{J?B;l^Uw1;*~3u&K=`pqlZj=GnSxksyUc3*Y*7tt^Zn1PGO?o0ff%fZ?AHC@7F* z?F0Ixu&`DvgCE4F%yfs1=b>&Rgxm{NB3%NM>?M&$*(zCh7OsQ3D?GJWKv)?Bj%WPN zL$&b=goX1qkVg=7DG#76Yj+h~7tJYxKa`rMzvnvu?zG=f{bJJrQbrG$F4||pN<-GM z#AWG>CB^{}d=mPTNV2tK2ExE|0Hu*F%1v0j*9uw8Uel_=c~&`p3AevR>595LT6 zb3+F$sSg4|k`cUE>fnW|bA7nP*mu}g_#1}7Mqc%`g<(1z5262LA9)cvOC*m~ie$VE z^}s~}q5Dh{(y#0&9vB7bdzcQ#PDmWWnIVX(&NZZ^7KC@}Z&VLDW@I+57%+}_ZA450 zkPSTT`0hw!7^$6J_r%@pZ`25htz4Rb(A>vNOtK4tuTooU_?oC+KN3)@Kp2H>B>+|P z*3X`9$0c21QJ-{3MCC_=e=L4FYa-6|j08FtU~75#eT~YLHrq2ibt`i+oBShr3wZh~x+UmlKpv%!4TtU`SP zc^nSvD9)GettUVWJ*GP#z(El90FaOsGTbI2fQqMN{N7{p4mt+Jc*J#}BXPLvNSN@? z{rc-=kF6_JAFMl-T9TU6ypqzziLnry%L=YWxT(XYu++~v!=iHx5oq#PKrx8gAQR-% zK0sn}joXM0W>wD!uBA7pi{M9U^wO}*^Atk`SWPR`r&GWI8cYhf1sH%QM2 zvGU<|5jhYg;u34j?hNoU&bMS>6oB7h+lt=IVfU>p%RU2_5YUnXR{%hz6D&bH$pe=JiZqp#9f@e8-hjISx>aGIsHuW}LyyGy zfV})TZq?)DnH2R`mL29>Lqm|F%{LwvEHK;1J3B%0EEyT>MGV(n&5mI@GB zki4aOV0V22H8E7EWY0k_z>2UeI*}jTfr?ye34SXcA1m+E6Vpcs%`c~nxj~BAjW_$? zg9E}E;tl*Zi>Mq||J7geWEr(J1rP=BJ(p4kPawr`4+(I?tsa}-hehg8t|h@CE|D@6 z#^eeWT!M(dDG7LI+7;p_Nzf7n(2FGi;9w&~9?Oad+onWgdTf4}c#)er<%0ZC-{y+^p(SL~*Ug6QQP33(wQEYpza zM4!#3r3z19BDgK#7=vZ|-aDj2!%_EW;{EkJFOl$}ehq~r8?fD*~)jSK9s+0J(YBnP4jlC|W1(+e9x2aO>PJCWBa z@h0zvzgr?+-M*Zu~7Pvt!|Spaxm z#HCiyElMX4laUrjEfzHe5KWyBA_8#JNWinKQ$~0KdTesvL6qJYkY|uKs;^No^cl$u zSL2og>7gP)CtHgM(hhhbxZ34=(&`GXo;ozy+o6FQsuuOaz4Ltxa2c>=Ad?N|fzm&h zv9bvqPEp?@ua`D5FdQEVErI6JUkVVl8jxqoGdyoh>>?pS)5DgHDwszEfJ5kJ!NYg! zW)+p8$I0KiY%1)Tj~N4Pn+N#Tq;M0+JU0`?Q1yR0n$R((C)3R~j#U<&kUI_+7xYhW z@rZ+i{&|1HDN79=B|Xm_Cqhebr7uTisA2AYkOcZlBGsk$Olg38*P<)k9u# z-`aSy%nwNN8l)CDbBs=07W5RgC{`OyvU9-8j-P-$@y3PF09^^-c3y5=2BORXF8~1Y zfc~y=2g7#%^vfMR&}j3()lCCB46;CS!1RoM!(&Zdi8&zmuq=nCuT`~z<|o7iUJd|2 zq2R)qn21)3PnQhM<{b97hbn*v07sAMpI9pmiQ8r`zDErAQ9JD&37WTs-m^*|3c4{g zs`HFM6Z&-7)B{OG9;v`w2eEzF6L|pG06+=QRy*WP;FUs&MqG#x0knLJUF)+oc7a1K zKLj_}r|@)R#EEz(o1MP8s!_ggKHYh0 z{N&-N|K``$Qh~os8GF z)h(W@J%7`~G|ZSopP1Md(tfAsxh>AFqnVfO&h4e};gAC;`o3yT?VFjR{=MLS^aU4W zQQr2$avYO9u153vob~H?mjg(HNfPsN)XVb%CUvoGfqGV-@d=w})XaX;+GA6DS+T-~ z;7rQI!j|`v_e!`azV_=*f3kUE7^H-&`H_*-{?$OLH%JbB@1@jmK<4&wi>89Lv#IB! z+F`|*M3dFU>SHRW7w6QhZiV=XJEiI*CdG7Jk#beyJaM5sGVrq>6Pg{ed25?ahK)b@ zDzo$W!P^|T3S8akj1k*iuDAJ@b!NXMtVb}%Hq0JCML!)RPYf^krBrcON{v0K)}%gT zC(j$d{v@38k*UjPKOr8p!mdf`ZeeXe5>e&iTRS8Me|m}OJNpCMmB23!e#+M^z6$vm zv&1%v{2K3^>TH`$1cND%*Vi2^ zdo@zo_FaARl4U%)U|qFE(bS#fQFFWMA+I1K3^8TwY^T-;qgH{!tt0#eErV;klA#?8R=*RvvP)C$zb>Y)Cq#yHSkN4QGynSgU{*70(7?MFJl zUA?5)?>%)LW^w-18a5_fqqDs;j2ogqCml?Pa#(wF>yoM&iO}_I^lB`Hx7gzYX!r)o zg`%YZak;NrJbl_x>rWy~gtrz(9Il369>=SB4a7c{g{zb~&x=)ZUzH*|VRF2Mda97_ z8$Zgb|9nR*sHnC`W@d=o34MNZovSiddURS?$-orV4g%mS2liS1n#kB1>nAPwTG_Dg zVV$G(H%A@CCC%d>=s9IU<_UeHaGS>IdJ58?cbxant6hzi zKBksFCM6oS!dzQr##2$MoXy+dQKOTy6G=!pXS86S*j$(LQj3r<(~)_6kazY=R^Q8= zIU)OHr`hupTgl?lHnl$2+Y;{tJ#%t?7^Jqa!G6_K)_HJIzrTXM5#FWpRDeK+ zhcmHW*7>MA{T(}f7LK+{Oy9jDpr`Xwn4B`!6Oi)hS95&dCCR6l#ORo=lWY0|&bAee zpJ>Q`4xkcOc(?#x>`l@3&Xu-n)6Vd4w&#kpE5%&mQj2B3g)@h&b=%jP%x`PZZEq(m zCa}RPTZy~+#KPOd78@5F{OWRe52E>=gJ3`%L1@~Aocmvid;qi~(gnr#sdqXlL4n?16#B79W!8GY0mDhJS( z@y3cu|C89pIgx>=3hpc?oyjUL;cS`FzuqW*yC~)Es;|bGFtg=*J4qcw$4 zkWH!#9}RrO610%@9Is@3J-pW6-q$%Ya4df6^0E09K8+W@aCk%!8_FsDHuc^(lClGwc!I0SNx*Tvxu?$ps}hT$36e!2O+o{7uHorc&D?DX#tpSfHmMbEFlP{JA)=JoW3UfoIf)xs=8@FdMZdoE~B2$`uLxY-@^O%SR4WN3{@Es2j1|C zO9z=N^L1xcY##48vnH9XeXftFQ5|@nj%nia<|ey2*G&KW2N);!cI5^g(fmjcQRlls z$6irxBoUQHv%^?|G)kh#_)mfHbrjvki+Mp^+j3dMeun25+!^yjH03!>UH0Su+B~^t zmA=||?DY`2I*`}n_pssJxt8&b{4;<35qX^yHb+79`fX;OWohw(D?3mp?`F~(R<^nF z+}`MKX*cZ}ov-jOx{JcC!%Vu&TaSNlga~f1qVi(j*ll%q#xec1kS)Dk$R3HR)?(_jfs<+3na=R?O_FVx7xs1Hdt2T&k;!KTg*pR#PNANzBzYJmpY3Y;0v+JHK+K@? z-R#wP_xUp>%~ve^v zk+}WXRF4+%EAd+@QCUmgOmRl%85Z`FxbjVU`Q7MlO31#rBI@QpPk--;PE) zX%}-b8ar!pGNfV6t%5K6cMAZs%)Fr><2@riJ<6jn?YsCk!H+KxYi-6L;Z1@k)?K*L zO-lG}ex2hhN?*Ox^QV}opps~|39r%H$|5ar&7?6q}@C1ZLi zWU})WTH(bFa_P-|Qc=~d#aYyv3+DE) zI-W>R-_%nw*3OeoXLY#KBkh*>I{w-G88J0|AtajT&qCU(mvA^=>J|m5|Gi;ARt0V4 zUz7UfH5aRW+nt<0XcRrq5;U&ppD=YH$$s%uzEqpF5vVdG*Am&mwQX0VO%JUJA#WW+ z(%_YcS<;x6Sk*J?-mhKP>5V6B#bfaEDr?2t*j($n`sW<}2arCYG1zA2o%X%QuQRzw zH98{KJ0}(B^+a?xb(R<}NoG2$Js(mnS=Nx6vY;;NgYSPHJ_iywk?ZXPxO%}?)A+&@ zp=&X)T?UaeE8K!z?@4P7R$-=EcGzQL##)5WMp1jYE4)c}dRm+?l%DutSFeVIl9cbs zZwo4%F4+!=4zeSXHyWK)UK;hRWk9Fqq187syqpL~jTn*bZmXxrT`P)E$Ed$?ZT z{Ms%+ASqosfHH5u0@U-HzM*P#e`r5ghMA>Dp|(Xdx3{IKv@QvL?JKAFcvX&Cr530n zcLHfcfp$1B2Vn!*K$ICQV7fXvDOstyZi`AZ)teA7^DeL;7 z`#ww)mlpp_vtrV|MLTGYeKI?dOY-8HNSz~F1WIwTK1WjXc>JvWwpd}kHgTyh-~R5Z z8)|3+HL;A2ww4%=gAkM59NRzI?vlkj`_n4A=sN%V%j|yG(Oi>8nDY%K}hmQ`e7OQ+vKBRw>15 z{pI5UL?e1-i9Uq--evD>nVeeI0GS#Mz;WlKJ=krhXSR$hg7<<=87@y{$6fr|uN^da z0QHLkNdsR01R~oX{|L=)iXKDnvSHCPja$#`DyF<|v`ej|Kd#zPaY|!S z+&G6xu!=QZxz96PxVdfW*rMzG&BPi#1 z^5RwhqXrGQM-%4z8fmzHJP~CX^sX!Cq@}=;f1Jpz+IOU$gl)S91`eZs&;3;6R!jEx z`6(iq6AIad+LZHM?lBLvkCQ1JqC(^79=&#fkIopqZz@JuYtwQ+O)I{GvB_mgTIG*# zg~2FZbtUc3dBDxQFmEje+Q{t>MHhx<@nI?_%qdS|smvWKv5?RH{nHpO`ZyQmxj?o| zDufX&L#fW#ys-FY^bib_nH_~pk1`x@nv`LsVUaoKAGgo#oSUR~IZbhuO4B&wBkICy z!=%|B)9><9jR|wGT(hTHpW*)4dC`&!BKFg1wE(jLxEJ56=sv2X)bQx5ZaVTySkeCCZI z;e1lN+D|p9XhQ<*oEk>P^@nL*zif7jK;J66&Hd*?!i#%)Y1MJ29cLQNgPtj9>G?g3 zj5*fsXH#R;1U4)kk#y4{!-?v|lU-JcxFF1Qrh||d6`jwA4Pl1-^l}%f=`=m5$FZ-o zKL$ioy5-h#_0&w_so*Fls_dw){9bys=qZjwrOcWF@&mR+rSI4w8P-Sh9Mw-`w2YfF zR8IV5Xyc?1yz&XI5S-}7!^HgBEMb&C!%jQ8nc~iU7^8t$?(Ifn?bt(SjVZUES3#Tp zxt3uqwkVc*iVq)V<8Y(z%DTphnJ5M!?Vo|%4g$tT7lmG&G%IJVdlTRGRps?@1!1Gr z9qdkxr*E;lkMf**?g=-lmv96-#hS4Yv zStvGR<2*Gia-5*a#-UUVyZx};fKzwg?858MS#jrc2q*O4oxwa>Kv;L&7U=6&DOxHN z;l2?VEcfmxn*H!dqmv%hHopba&*nJ~o|?&XE?6@lHX^IzZf<5+uicP~>I&er4lEm^ z?q$~C#+eV*nlT!G_rHfI@LcpcB}1&b7`LrliYWNy6-PyLo=xrY)R-;>50xQxM^Sac zpo39f{#0g6!t_MYg*{KzXlbGi&Nk=KhF#h{TDe;pd_CiBZZ49_oKYNnLLXN~D!MD-q85mu63#8U!3H%>y`J>Pvmei+ zF8Qr$*3U|nwDME$eKSQtX0pRTGqFW;*x@M-Wfo;8n>2q;9#hw41oH63eueyGe119= zJapSXpN6&a<~aNDI}{5lM$D`Yl)_mPo9W;8HAnqMrYtnV!>pDy zhkgGf9`m|bGQ)m$ato?eBNO_BLL&Cm!_zs++;L~v{hn-!6)@B;uQVkK2E3Q zzs`U0`;-qo0A@!yF93Q!j0iqk3o7}Sk~;&^&rbg4=f5IAxCF{dE{|ZwYlBQF*;o}O z7Ul`lB*g38ckNQDT3W^5SSb!5U-r|OSME`poJq|ObLBkR)%4E!W7noi7L-jd#}qsi zbxtvR8D~{3^jqr5Foh30pOgtptJya}@+a!3J6KLn%<}Z{f*HPJAYLdw_$qq~KRCUxQ8I}%%)MZF z7()Yi_HO^D@7g%NHviPpGQB|19-aMd_MB?AtMHOmbo058A`MRCeZ9NC4k6{3ji&xE#mI z>?m4VKCrO(X{VY@5eM+;mdMuQ2ONP0u7!aB+W7TsDGR;;DXvQqk&m*|BgpCelp!{+7jb zRH9Nfg}bQC=vS6O&jkcOe>mUsW>^4sZlQGmG62sSTBpNJ&&eN#wP~Ds*Djnj2)1>P zAz3ZJ?X_>AV`YY;$yiqI(~J}YK76>bfpX3^<9Wp(HUdwJuqRcz4=aqmqi8aEZGvj7 zVXWOKpLUrwpT;)?Kxk0qOi!vposqS53*vM$F8FpV0@9Bxm$y(lk}?;^)n=5@u0N<1&FZ z=-r;_>j57XrRX8y51|{x;&K6oq?KQny2^RK%riz0QGPbe;5<7-rkH0h-f)*8?ww#R z-oDLVvG`m=YIxaQ>EY9N9bU-#2_O8GJ5vqP%Ak6a4JfFMct|>ZlPd?%Ta^U)MZusdr zII?_6v%A`Z5Y+tZ-dO(UHS2cyi!KUUhKVM&i8^d(slU_O)RQX+_`BQIRzlSQ%|Xk_-zR3|vzHImWIxd84K4A&_Pl|Yp4 zgEMPg?MBySV#uEz{TI4JkX%YIK8xdGiwX{F^1`NuJ3rXj;;6*UE>Z2Lnsh}6p=6V$ z3CdkYlT#@Ik&%g*=usB{q#Ntn!wxMGw)BY<67BLE!EJF(>9vf})6|_IT3U^XmnWOg zsr4{&5wxoXf-XB4soFS+fsYb6Y5|{@oy6E4C%pTUi9KYE9E$EyVCfYT-llg9B5Y}W zPK-1#_2epdy-7Wpkz$0uJXf^Kj1{N8-yNqE$4($BBB?pN;;7p}G(5k3zL+XIP0n-Z zoH{v<`4rhA{awdxSl$Yj>-b$Z?-Bw6%H^6REz-YCe59aNoj_)8G6GeyH~o8D7|!AP zfIE0@j_P-ddsOIag1YWV;y23Uzf56JHmN1k39j~jnaVI}NSN&09o*tes@hOelhVaA zKJv$o3)nclsSX1nS>i5sSCb;o_Ehw|$fxGm#?i1GJp1~1rtpK~L^L33)>lzy7&183 z3NLl#w3@wbd{!!(9o2NhXWEI6B2`wwKk6HW(c=5BUbHud&ki-<(-d8f8+IkhJrbsH zeYtiqg7fjSq~>!0yeWX;6I;TYw070HH+WMlzhl3Oje5Gj6MB*B#(A7{qQ?v!V-R6z zHK{pPa%oPUG5NKh(A+eB>e&2@ZHh?nEkInOEaHF$k>u+ZrkISF10@h9FMMTKQL}H# zL`Fc~3%Og@^(OCFZ|d>8a#=y_1FZ>*OPwgU+xsR6;gAf1@pt7vS4K?>49645WClEk z*gK$vQfXaozj068S^)SnikxS!OD(2}uofK@Fix-*Yd1g|fQ+zob-z;B>Zt(&-6(05 zwv7EJHz9!APWHCIa-9<`hvu9X$uRF%e~}TquRjaCHu)zrJM#4u=h@t4q~S-*ThrBXBjfKhPaD@v ze(m$sW;EUxUcP;=J*)U5L2;A*%`_?}IuP3+Tl>7P=FFpAroX64v%-V~sW`B{Jx zJ`%=9A1)jzV}53t3ly?ij;1UEN1B-8P!s$8aXRZ5VWK**aDSrzVnJS`pDrm=^#)wd z+cBoJ5^IvKK2@W>SP_G#sZdKycx`HVKR3K_PWny4qs%R(Ec4Wym|noBCj=b zCcY8cQEgz^qf=#Xl|-l8meMC{TvXMcK83V?Be7^wyhpgH7||XkH{GmfY7rm&g1ADp zeN`q`4dF0q_MuEMKzDt(S7tm_?h{t!d2!*;x8}sN;?;0v(FNS=6pV@x)-Badla)bH z?pmBevY+mP=v=hlV29^))egH;!1~it#`p4MrA>RwO()H1u5fn+RR#sWC6X=HW~1Q# z1q%%82QK!tR9!_SF3!Dun#ZO2dfpeYch9A|i!aGeaUNghB3POQt&$9tMdzOkUTeLr zA~l!KnAN=&CGkn=R$G$H+$) z-1EF^M`plptn1E#(?-cJ9^o>}?XtvFIo*O7>c#)G|`nB9LO8t8Pw> zA5L^$$IeS}B^0qQiOjidO z>}6x^_3IAN+YB7y4n4V5b+|IJOiVk6U%z8!bc92E_NLUGpkQ70h-Jyqv5C1jk(UVr zCC55-IkpS&j>gxze6KBtAY1tST*?Gev}u3uOUiUG_QeTcGzB<1y`;fVwmRI|PK?y4 zR@r^tBE`WyC!SQdGRQ4&YOk}0b+lgC==GWKTIb^M8^z^n5Q1b{u>&_WQ+zu;HCgT- zK(sESrmYMt1V*wE;{(&Gm?#IPjIe6FyBr^|yJPNM_9xhINGpQC%W+qRGoK zh z<7Z43{Fc@mmE~951Zw-kJrsAMS3Mnv!2k{Pu2C@HDH7gqqs{;RcTDj?&3@`7X3)d0#Txw1F4F5ap5=L;+vO$w<# z?%#KOKW|>PRW?iFN^Wayp{S~~y)s4@kWU}0UaK?A%*B6mknUbLTYBR6^4fBPFA6^?rxuxH-0?IvvK`_k|65{;dK zRLh*fJ(c>BHiLWOa(T0FMAV-D#9NrpI}~b(6UJe z2s6rk9jm2f%VBEOg4%omHH2o+{j#AZ@AWssO#<#(p7QUH(kYFwWTXF+H&DrVaknp* z(BOZIO}CSGopE(c+*0&Jd~=cC2SwDNn}Pzg)WbX}a)Tx*qBl zQZkzJ1*~#$abM6Z+xz4HL)3f6v-y5;<5?m|h&@|D5TmKRRT48+tqv`%T~zGVr9tdb zg4%8D(PcF#ZDSTi%@#pXR29|T>i9f&zrW{s{r>SH?$>o+=UnH!&$&*{^}en)jQk3* z4@tt6ruDw{e(&$5^nlyBEHUi<3!GN8ofoP_=$u69k6x%SO){WG^ZH4VHqnnkPC}c@ z{Q71yynAkwFXmUR@yxKMa~V6UqOLes-S`sl)g}G<7Jo?^=Ofbo5<2i5sqCEfCzrFL z1tNL*lJVZI{*u_&(?K}PFGy&Hn$-h8{f(uEnL;P@>6AV7Tmm(NVRbp4iVl-24) z!^^InLW=FU2&5d1{rWje+j2UQ)g&PRb*j&rg!*b>W(!1m{xIFoN;R&`w91 z(NtJV2x=*#GB^L_x8T~ct;De4_K*HTCFV6htIEq&Mz#m^CWQ?#S6YbSt z1E7HmTrWn-9-y3ox_xM89Z!awGEOo>Cd!k%Qvq%kZ%V9!GM7?MK7)$K#v`b6@MjVY453wmU9iej61@T(pgV}ak$UI4 zgv#)eqQ@d2h{bm_1RwXO4C z#u(HOOn>?hw6+0XG>QDQe)Wt*)f6-^v;_ECV#7k{oLi!UNFHHPHc04GV(?#%uL$JJ z0ED`zS8mA1DA}|paWdMsMxX|B?lg!(YbnbBFqRQ$HFBbCO zEN)dvxR2nSLl$Taq^XTDMcvytq>KZOBX$mD_ARgsuMCg6yO#KefYAeghS z>9?1FgEr>?RNbjMF#C=}-j6o8am^(r%t5arre@4yJ{tY8QCC!U=VhSv#iNR|iw-aj z!eE#DJn?Y?egtI~@{lKeJScOb3oN>p_1kNB?|Lr{uESNK8^6d_s`+*NDajhJEQ~EEKMa#)KmYL4sD@B_jZULk?_$L;3%h8F`hZ=Wy)mxgq?p5DM|VRYqG3d9Ik)1j@7(T=)KuU6UAP!=PX@j!dVv`7Y3kb17RAe&1moJwqbT#APvUT08=ldkg>rAq zBtQ6cy$LyC5aARI4lnyaV!cjfst4iGE$R=&?%c|DODJ2C#!6;D<80FPe;FSeV>n&m z9%Kcp;>TKp7)Q3p-=C)TX1+ENvdfO~+fouY^$UWumV5*dWFlB~!@Pffx@%bHaE6b&H~qOXHA_AS{mwm$~>j?5tp)k~=qrq%mfBtqVQ>dYvV}y2{wDl8rcNMUoZO0@b zMFaf(9(z%0?JY>=1F$ge>{t8W$&8@zDlO=e_r+30o)YV_G{Z5nA+2?5 ztJ50qRD~$LL@ba8$5QMrGdr4iH*-oxozw%4HQG%Fm2fY z8eb8W`%ov0^m$%?#4$QV_oL6`U1GwgowMQuH}{eOiPwI61tTbgPHWcvpondWl!7Vh z9Ass2UMOPvsp9sJ5&T!v4SOYBuq&~{xwIlQW2Ahp`Cc8jX!1_-s$f7k{t+iaJ5P|;t;56I>uhEktsB$6^J*8;Q-w$Q=&GN-W6U`M^FoEn~t^bI?&A7i=m zjmnbc{?_0q?+di!e(VOfpl6;=(fS=g2kLx<)^>XdoS~xkz%FI*rs(1AXhlib1N@_C zMeYdGW>IR|*!A=y`?&M@7ymSb%YzGaEL=Fmn8#$xl_Q!Y3%+)ssEack`cE4_RSA{J zyz$QP6<(hx^G{S=jSXgwi_S;k9YXFUIDEeM2vt0goAJi~(tPIp`W6m?MEsZn;*f)| z;zq33>a}RQsvrQA&ky!{M`ReOVP{)OTO!`vkCCr97it&G;UkGYo+ zu+C7cOuE*9D;ZQ890d}_@=rS-O7-VZc78K_2XilRy^0(5WoN9*6Lu8itb0*|%<(6=H0;J?Hs;O%4Yy+ud1$F1`a{cf8z#!SLBHnd(GsU6Nx=!PV8iw2kPeK-Sp zx2d=kpkrq2v8DLj`PyQrHaJk$rXBl?YI>9i=DJz?E1_MmPUku7u+C}4eFg@~`Rkwv zqR6{8Y}OGP$hVw>PS@-436OQ8hupJ~;Y>*62Cehm`QH2UQ?&MxNDrC8EK^Hgpm*W% zl<8mB2x$GK7LTfj4Iq}t;*d|2YA3y;#o(Ele`6rkgNLFa3WBL!IaWv9iI{hK@*ik9 z-?oO!0OEgbuI1jPkF-}&(@6=XQ96!1gS}o`hkJk2VZS+uH-@a}9!HcJ@)>y)U&{Xz z#Wl?t-*Zt8iBDFW`65_*h6#DPt-D)wrT$%&)2rjf_?Z!Lc@8Lk`f=`1rMtrwOh~{c z4tx3`DIT{l)3eK@YH8vou3^|%Ny?Y-Zh<{YRNIpU-K8Z z;d^cAAd2te1?(Z(z?XvE)yOl6A*W@7RSzW`9U@az`Jc8pcIIX=%)dEyEa!0>c@XAo zsCa~AkyrJI6n}l%7QQAb(HKfABN;!cT}!K8q*K`)D8OLB+cqQtZxt8NCuZ@9YOLS%v?oA3 zM(V%dqrYudkDuiVEtL%|t^IRWO5-8Fp50CB%CIxH4(rO6t2*6~WwJaSU^pPubd zZ|1&z8WzHR_Tn+yN?>v!;O{};0_6bN)T`MoestW@^AXh}5F?{of=3}uJXL~(lYi>t zSQzennWXk&u&;kS`l26$2WIwV z?^Wi*T|JvW!=|*KJj+Jvb{(>tdA1sz{6^_B%;(8V=~lwq#EOo!>`CKG`KvnSQ~!aq zu;>!lrwh*4R)-34;%CUO6ySqMu6?+Kond5)1O)q*(^blD1k%RefwjF z)lr##{&EF5O^-v`jPEIad(Ri9mw<06lCkDZZZ@b3F6VWtvh0SGzJ%ddPt2T}upk=V zma~7;ZXNW?p8lA*#@(jdEHDH6B5MAVY%nILH_z<|Fg#otn@@zO_bO_y0@F5*tK$fSCI`??ZJi`2LJV=9E(GsEvke%_TOJG0 z9F7Swk3-w4hqlx95!@gT1RTWd^&aEDKOx37x)2{%$NKwNmk%C1u{SvccXaTD{Dtnl z?e5_z<*GhY6R|qE{`w%E9w3{RL+Ih>dfqPY@7e^Hu+h1mTBbk0EcwfncCqE?!d4+Z zawWk!mMx=|6?{vDbLmO1mbY}i4LypZ?Zb41+PB4zeOPGz+G2&bSeCdvHeS5(MvDHf zNg^T{quT}#EZxgQaVi(Rtl_;3^*q)c`2}rgD|S8J=mNo+`wLIr4??F=;BULH`1>Wi z45^ljtYF!F6;RPgV!bIJGkbKrt|XoZ=;R(1>T94}7bT9es1Z$45Hvg`Jz6sDr>X&B z#$^s8W)`R_jO%IUN1RZ3+;}|-fFj_Mbfm|4v+Ra`?)hENaH}5QeHD(u`oRRZibf0(&8q z->;MQG8z*!CutDLfP~8Zt$G@>3k^##v`q+{M>e%8RR>M%^13W;Q+kx%k6aw8^sAYk zCPZSPGsEU`N9g|DvK$wC^vwOa{s1kTRTpp65h0qi%#-%-J-jPLU;?L%4!QBgO8YL> z^-pw?{&=I-4jC7mdtSK{6oZj!$)kn@tmg4d*R_q7Jq(E4jQJ(oH&pdOu9{~@O&US? z!Wr#&<&|>MyEbTc!d9VEnN;(Z|LJ<24phDfJhAYC;U;Ku>77(Y?Z9BY_6oJseA{tj z6h#OJJ@ViQ*^bobAAyG?tZzQb3JrXfYrA@VN(9sJ5Y)r8+;!$o*lwNu<)lnD;HLYy zWZylJSe%Eq=T?b@wSvq-%nEO`!NEmQ;Dnr@>-iJm)$aLzr*O%d^5eIw_k%Ej z_HJQS$6c7A1Utf1jXOUop~$!vU#GN^ewJ|haMarfW5v#1vlO-XhZA^@V>>03FNQ>~ z1MPKZE>Eyxo7zJIBs0cgr7j=?{P!=z_fkmczS1GC?EK!RP7yGBOUK)ceW*Bt<-!nF zu#fjYujkk$D|H66kxyW>0NF)1e9%(1XjacdA+s^z02NleyuU(TP#n*j%Acx7&KA!F z=?b>@-v`{qi}G!OuK;ZFSSiaP#Rn-$&p_@h+m~kY@5ifgJpA6Jw;#*HxRjxHF2$5o&9j4T-hbK((w6amiWzHH-+KR3H4^o`tw_D*S)kFe5GB% zCT0_Nx$|V)>Rn#))$b>i>R}Y`VY2|rq02pXDLFdaF|m4L{%f;pfB>jclIt?hHPkn>vXQ*57ZS zLECI|;{HZ>XM_H`s7hP zdgx2p4~oOMTRFb%j(+g}p%nNHg0ZW|1iat?i-5TxU!Sb`Ah&rXabiOwX>S$y6BZm^ zTUyC_{DPzUe|e!Q2)*A9aj=M-r|Q02I}VN3dXgflt_wEZ6bOnR$&=HhyOC(Y6e5_@ z80IZ{``+b9hMPg0Y#TyM3`i_!M^v-RC5x`q=~dRHj4Rk$`$vwi9lZL=3nKH2E%2v+tzf)wC2TJ? z8Ry9!x@oqDi;f=|+69q4ooc@GC)g38rw%J~gGJyMdR}oc+=k6QEHqpjOnPVMFM70o zg_i5(&)>A^UCrX^?GCxK^wRG6>&UTUld(gpqz_5sIX8KODv$hy7d2>jU`it{d_SOi z^bSeSa`V0Za;K@zzfxlOX|+QVz`7(PDRJH+x6{v5KGa2^MxLu65-twz5LRDT*4CKTwi?m^rq#1pW-0JyN zp)LZ4)WDZ3#1J}elsX|Hmj)OT9A&|vChf+*@c(Q^g}?N`t(mh^L)o=g3u0Qz?OyC6 z*gTbwsG&g-HBoTQt9IO^S=0^$^7%}@fPEg}`7e84qS7tyr)Sr$jcToS@|K>t`=mEA zeL_|*ac`zn!K(b6T(uol@v$uW=%)k8jwTmKdM_H`>~z{-Bvr#*D7#qChthXzLTxs8 z+6`^wvD%VVN;Y*#orLCnGGpKm49ssQ#8U%jFG97x+_{ilXq;=P=p}B(60_SGQ9X8> z;Ql=u?Z$9@;m#2`^ZH`^R*WBX%houfc(wuWXqQ@x3HIe;Bf6U*Ed2rcI5GBok7BV-`|fNZXDd&N6^2HpxZq8RGW#s&^8}#+YeVn8q(3K zuErY=jD(Q6v_t=aYy~TMiZ-yLuo4lR7~+ zkDRRV9l2Dp{)t_=0shmNL}r3u4vyECa8kWFRcjmFDX1!#gWTi${Ab{~y|qJPkcF_7 zmnF|RX1?chJ}K7B$}5bNx^UylxkHR-NU9LkZd^xTobwpIX`&EcCt?rp`lzM`WXbKP zXYvSIhY|s@WW_hH+J-6eMgz}d&+ue_=IcSZBF8hmUYT_sN|McL%3Hn{pe2ytd)!y> zre#1^!Y+zN#ZD;ZDVP2rdu(^=<~69f44Woels2@0sStKa6m)w%v0hChB^_h)qHW+B zxqJl++Dw~1QvR_j*;c_u;X!P2e0ie(-AcF484q_(Q(XD{?8Y5XLP1r;kLDJ!6KD1h z3lwcp*KPTcu0Xlu(^HN3ce;7+E3(KnqH^+f;R&}y&)Yrr(@JpS$%fNbUC(Rl5(pgD zXpQ(8>>OWb#XH$}(f>dzE;EfyaVLrUdm)?A(vq?E_o)pDoccmG^zgKSQU9w|O0C1) zP1FtNrfNdVbOeN_1AlGld+(HX0D2JIR z_xZUk!L9F!m*2d1Nf^e%nz+f;rvM4jb@E)iD0dmyJ*(HNec}9;m3`Me5DDATaYO4K zUFI%EAOxZQ0cA?QC)LK*{%_V;7Hl4$ts?cUvV)j3Rp6AG}7IEL+lj+QvNY907vJ#&YF=;NtRQizn#;COKbnF#DKq)jUr$gVdL@+H^e)2Qx`1Y<<|O*u7^9P#H# zZk4AL6yiy~4fm6$J#oM(6v(3sR~C>N&|mH!?_AetMklXI-K7?py+%lH2h_u;!Z=T$ z!t}3@^x%$FQ~owb7K0-}Z)}3s1;Hg-*Fpn|LX+=${jc>xzF9|{tF^x`rtr3bUU8_P zKXob4AsFM+%q6)o5~_nnry9fZxnksr)8)Kxhi(1>+lS-Tk!VfOqMA6_wytHh+9SAC zA~w6K_C>zLiEvXFRs3C$dnjRfTEpS3a&*&*^)a`%_Y!%X83vL3J&(woYW(+WwNlg% zTlJAPh=%>g;k}T^W=Ue7uWp{ftIIqPm#nuc2a*lNK2S-BtZBi`S?amE{w)uk2xmpI zij1be#U|YH$ZeLMb)g@nK=BQfqQP~C&{=>uGjseukoTR@-FJd1PFqj5w#pxsOI~Z& zJ90NM`LkA*U#fx>&Yp+p~+C_xQ$_Tn-aES@qg zFL){)G7z~r-GDd=suPB+lytVIuI7Q!3lIOK7UE0pK8o8!=WtBwi6}%|S-Z=Bl+!eT z(dhwr!S;6M=eM#x3q5u<=cQ&bE&E z=`g>6c~DVT18dD$ZhQ9zRH?gNP@3q`s*`UCMTyCFqaHj-qn@jQOOfrM%TLF5K`fL6 z^v_?eb(Gye$XkMkuZiSYt1M@*(L)#vy?DQAKa?cbvG9&Q^n=?RTP%0K z@GW;2TZ5qH*}3Pmp+D~V@}>{B`PMGNlXBNPe~b5(rA?hh<(hGu*o%OT$vB+sx4d+< z$F|#_#_V##C(z9qgtPyuqr~P9fo2nAd&HSL-DtdYY|Ql3ZS=1$8fSvsWpE--fb>Jq zv)tr^q>0y96+(IeM(ffxPpwlY;`l z$RaXZ{cJn?iyKfcYOeTe^(Sov6y9BF(=Ly0NT}V%EKv+40Yn{ z@(LFSp8#V13>kd#<1K?4a%CuVRYPCLc=7~PlrZ$Kk*iOtsEvd zB0ctiRLebtQ)hIr7 zt&WE13?-4dB9|_v+E#l?oucsi}(-l|R0o6ut zUKgA!*CgN1hMgSAn#w6)$o)hlLiTU?JPEoWyV4zb<6~9q8Z1XU{<{DCT_fG2sq7Tv z3VX!WTSDA*XB!lEUYnkJ-}v~{_*1{{_m(UF#2(xD`{(_!uLmRbw`b$BZiiTY`@jvH zo#pwe{gY?seCKuGTekn*ivwIE2LhofI_!`h&q*e`*)Wm9te6eM%<6>rEEvHf(9u22-LDEUD#RRXT#m}P4;E`dt=O9i_h5H_9`9nX*(wS zrPb42CYz*mh{7B_Z^ovKh2AI2QyyQXE0t21)wz3yl!sn)F*fD&T}LK+a^040Hb)tj z&tkGEWZ6{^I{=DJV$RV|@KCzhX2aMl<}#hkLtzfki7H&o&rVinDVv=ltaH|&-<}~FqmafANB+F8m>`zwR={oG+WEl#xjPAmwFkjyo zR;DneS_FXKtLZ}=lt-EL==ULxSS}GZ-Wxo7EJh8%h-;&dn#hhOq=ApC~3q-T;wZrJ=sOk?Gl z%Pr*J58J20$tUhH**fGQJLY1`V5qpRJp(`4dcbFc~|v$qv83wYAM2ca^6wx9D<0!p!xXrh;S4r4|LbUFNG6 zbG7FRFEo(s-~cTBkPRgbnX}2Je5vNmKT8?6O;&3@^1T|xoZnKyCf{Ul$Y9-dmJ5av zBRA)7c4F1**)qUHmJM5Q2&Ifj^$WA6- z>DA}h1Xp$t7nXiJ&$9taVSavTDqF)GcEzP}J^2-FWkg}V_#uu>5@5Gjuqi!?7G#y6 zmmk81=#I?loE{#^;D>Os;&7V}iphpZxPkl@3vIAD$ESnH*urS`P8F7Jo99OcjNu+m z3~-rvxT(TM^!yZAd-v(>%kx;OPJbF;)%Rla?AgPWJ1A*)N?rlojZH~8JVoZF{8XVZ z=cb<;jJ3bT4k4qq+1jUl2AK2rKVs>E^DV#{F<*zDW`{7ptv}P!XVz;?+s(! znU&hiWr}F#zQQ6PQN_IE^_7I2l~M|`n{MSDM>3>5VUNDJvipra+O~k!S+gCJ>0z?N zz}TGR-$hBKNzCOuJTN$UrP+`2_JtED0~kbuEK2Frt!ba8d=-kUWrzHpRB~g7l=zsv zWK&-D(=RWz;HLv`vQ-&1N0^J0ChaulOe6^cc)_&>Y+AFel;e-x_IrfGl9X@k*v5$6 zTRN-};1z#0$faIG$@8z-acSc9fGU`bD|)4N>uC*IY)aC4p24%654D|sEV`K{Fcc;0 zv?r4tWR-hIH7glF%z%k%gx0RNqN5JCYg&_R;Yy-q(R*uo{6BLp}&_mLK0 z*ck=^Fel7)9X2Hmo6W3kAyh{(*Xb7QCBTb+qL-MTf5KAmirDZ^OWa4?08&1FVV zmW7onj?}(xAlS`<;egLS9aYB-ZI6@&bprl2YW>gW7xVbfQ@;G7TXh9( zfN1SiqRcs`W9$%1A9+9>uK2`lwrd|Y=jNpIFm`kM3Z)YR=p71xDFC}-LWLF_a+kSS4rdn^|8G7Pism}(;9=}X z=I60aEV_#wA|8ff+I|uNhRrP7lcF&HI9W|ox;QSA<&>DO9je)J*W~SV-Ut0u?LEn+ z%wh8ZUAMRaj!o%)o5lPObYNO$xA{%2Q^}6W#*=vgZKS}*fGHNJFs*B>^mhW%#S%Pb#0vabjM6! z@oNEPGd~*)|9fVClTGRN95U0pVJKfP2bhCa79cYdMF*Z~@x8}n|2AzrVsJJ=QfipV zjwSz-nIeu&0Pxsc@}FVaUhC4D4fh9LF%ynt?=pY1{Cj2w07zgCbnd3MLK<+WGvuVHe>?oG!5ae$V2 z|2d_7hi(H1E8oOqYuI4vgz^g&*ia@rQeW@(|3`WO0Rw&U|Nmuqz$JPB=Y^v>Q7tUq zGq-uaqG$4dZ8rZ%FVLd`d&Pfwfc6@r3AhXLKTrq%!`VH5hAq_~^;)lw>BT$oQ0Mfd zR8D1;BDJ}RR+Nlhui}^Z8;&o-h{Lo3uqg{J6M6*04FRi{riO(3L#f5H?l8@%7{kt< zdMZ~hnP3hhm#1{4JnmbG&sIbeK@S0%xgEHRf_wjTw>g9{P3=_^6gal3+69sxqE_E( z1^@VQI*25b$4}~6S*x%udU`^aqHe!}P{}XA+MEUWvrJhY2$ig4Uf$e*uTm2&jJ{x1 z!+3)eoM;5}QjTdytU0xE#e`g3By}SWLMXDq_j>+BYdK4@)>%Fn^}jMw5_Na@rXDZ1 zi9qx;^Yjzm7m1^`$thc2&pIH*p9OzVsiJ<`5Q|oVkZni*Z1u>@b7%*IhgC`tGldGu zMxlSvDk8*4#jB=Em-MW}Ox>(`1)ei-Vo+tjqmJw41KO)86;SLn&E7%6Rv|{FK0L-7 z>VbQt{&h8+;=L_e^r8inKz9jo%pq$IVaO{DNSvMK z-*%j6^JCOgC=_wBbbJLS6eS`QJ*>yayA~xof6EdU zSdT3eV$31BFX3n1EX4a26lP`D#2laBA^0K?GH+r7&Ruk%iGW6^nEM_cvh}0^;B#s$ z8T4@VL{HfOR=p`a)J z_$iV?WDbY{)OWg`Pe2l(;!--Z-rIr-eTf{Prd-Jd_^KwFXHk5tLC9x?AtI1itiTPm z!b$rBOYiR`;E8s^Ed+j3;EfyYC;58CU*`4pB9eSc^2S$cYG|cbPl0?bJ#G76Kl2wy zKoI7IA33OPQ?{G6vU*zD9B2)k9mK)UPqJ%3z!Yg@#) z_j9pSOqHp>OhwZ^*BsUj=8#jdQV-!yqQ-!pITmqCIc`JFoI#H5xu2ohf~5e<2PHHW zaJ24~@y^{ju;p6=kxB1f%8n>?!x*FC|1+J2;;SDu{RWXbhgVhMRYQZbTm~n6X12;s z2kawk^E{9&(wal)P4~N$;~SGxJYQPt0h>U?_G1$p^VC;ukFNAd=4jW)F~g(haJtuYV(cxI=vkc|Ab}eT!kjlO?^w zkw(o%p)u|1Jqd$o{@Yh~PeUqlRlCr?o@y?2NcYQcW{WK$aIou!b`HpT8$6>?rb7Re zpe!hiVD8-X70TJl1-?6KtA7X+ZoHI}oqRzLzrZ^C%T`KNW}8!PW;Bk0hitD8h%cUw z0<(y2ZZHe`W+!wN*~xPm^K?BMiOlGV026}esD|JoHC#|Bkb3=(2zYZcsTX=(9ac_l02eb0ylS=Zpk=9uC2em z7kx`4k3}8P042mb-9p6>w(-f++uS39 ztk#62KFz)&grwOcUOUr2d0Z#KkBC;;DCdK7s_~M>7j}er+mlW82L*YbDMXmuKqZF- z2z+bIS;2AsS(Fdp!EwyRaE6>;RLz*rc0XfOPU%Hi>XH?pF_2)-2?cRy%k+S+UOic1VLr1?$%o=U+N7d-@ zb-#%dU}`GjD@TogWzMh~FRlV%65>q?){t(bC(_0&`BG4QC{`@$&JC>H6oy$(H;mH5>>uh#!bT*X2jHsKOxsQ1KeifEInT| zm1BnAwp`wj=aeE(zz-2UZ6wxCGQ<>cdZry5X+1x=zKMw;+a2~_MC2b1QaCht>;Zhr zDxUz)``cRHAquvL5wds&?_L(5)SGhi@6#?PiIr4>#Y$2+Y74^%vVlSH*tQ<))+DM6U7Fq{R`f*?a{g_=$7<8yH)dY(Byn_!pMdA{j^hprII9X_C!<*Y zE2$SEJp#sHed>~Ca-UdeM>2;PG?MMm_z0sVckDU;5+k|j{ zqtQc6#b8b}^-j8(g2{;&=+EgmG(^2mSFpfI%vt83l2=MX!U`tO!^s!@F;C?67r6w! zyid>{U*;{)I_bo94nmfz);7mzG2&x%O$W^ zoZwhn6IItp)q~1-O@tH9hQBdqSDq7Ah%i7%?V<@)+ag#zw4OtN-E{gaO|3#UG9msY zXmkh>!hK^~%^RH`u;SsTBar;@Xmcuu4Yj^W+VhFsrn=sV_*C;}1(y7owuCD*#wMXK z4rNPybgB{i|ko z$47CUC}M?4xxQD~g6)kzw||9HeQX>iBBk1p zBfr$I9u14gt4LM7Ohe66`Sw4MzvH_tOM^M<(V=6jv{sVmPOps>k5?#?VC17#QN1`~QOkJK zChuLrccg+uMW1ku8jY*t?4;s8a`mQrYH=(hBodLUtG9OT;8R5@4e^euy+aZS@$l>nRV}hAmyt6rilrHG-uWTD1~Q;| z&JwaAz=^yHO*HycHt%$*VY1qx)4gaIn$}SC#~~$keZk*W3rN65uSj!^2Jm4%K!Eu6 z@js9M+wqhJ+mhF?(@pc3tKN+K0V*Pg{FHuMxm^OBV1ejZl^8lAc96Ab}A?Y4l^r%90w692fr(af*FDBBk zDCf{=v0alC!&Y?@ZtB59P{qcq3nWun;CYj9kv~dh(PO1BIuBKyk;*}1j1CEW=nXSe zCg)hC&JgO~0y_r)Kg$>QD zi1rHVFJ}>BkJH4AE4X>Unu6-oxR^W>&jF$c8JfdMkcpDe=XF{rJQ%Q%|2)88mb`Oui6Im}u$O`Jg~}Ndf+FRzD^RdWa15sJ#yy zbf$0X?ib&DJtLzBRini%Rdw4ot(?BN0Kt(PkuW`kLxFj}9r=V72BDnu$MeENB5>S` zKG5}kcNQ-v7A?o7^vsa&!Ce4E(F*e#)TzK}iiKG<@N&mh zQeXV4w^cjbP%0e(`qSnkqc1Z{CXV*4vk1SWq~r@7#1%dFpeblG*tmk}R|MDGUV3qY z``o3_B0~~7Zt_7u>ax5a=tBJOGtXY7q?b)>_a9rkZpAobv`Y#o9y4848w74?C~CWO zxGrq3^TrI^)L@#{STq6c$TYU)766w`R09c~1q@id`Y9I&Rqd3pUbP>*jkH+M`l^O4 zQqZe3P7vr0@Ffr}ll3w=9zj+g2y?4Gecd#nxY5S|tgDg2<+y8sg`Lpk8-muG23@9o z-j{>1NSI?4>WUGC6Y**M@#&NuV_Vk~pnaJb#K0r&V~q@ZBcNobxu0=ux)2OXrhz#; zrQcT&BuPUZT)*2>#lV89k9%Dsu`sQ?ErMel%g?8anp$P=`yw(R`=VK41o~o8kt^hP zpjgrRtK0ov+brR>%WAbGV~2c{Yac(X1i@OY)B)n|;L&awFid`;Pzr|Vk3zYWz(HSo zUBj%}XmJ(_^B9{i3POju0pKKOP+ zpEg!%T|sIkQ#WZbX@)nTJfVkWQwxd_;wg=;R})gR+1?=u>k$zk<(IG0PKI9`q*^Vq zAUILF6#^WZCp%>1EKBdfc=lZ+qn-+Ji0*g?rmyMb^cE$#VkTiPu1|DjAT-qSvQa1b z1gWm^77-2%#rHf%siM^$l+n!h7ENWI;Bc<@zqGw1X)W8a!iTR-p0aydpjtvLyEV%D z_Y7;CR0h_2;u{)BwRFx?)08=n>Pj7=m_b&FWGsBa!zKU6oV z8WldA4*yItKt_!wsUvY8{fIXv^Pyy&9ZK!A( zagB94<|9S(*nI~haq1zKh*B!a?z-^~QC7rZJHD`T*GI1}++uv5c6M$8qGh@L#OuwN%HgoH0pe;e^|tEUgh^+KwkQsZ^n z5z^=2we`T}4z%AKg*X9&Z7B+QkfV6yQu-P2l{amQ7)uv)ZxPgicEZXfVp~lu_dn3n zaXz`%@jcXu&_IGws@*tA5WlYT0Vu+#PEOeq_5~8-e^qFb%=-qfy!goFTV(A%{&bY@ zwVwXimaWeRem=*ticyYKB;bPzhbFrbh@%iXXsniVHbQV6c{$B)8Nu=U1THiDDtB(k z0Bxf920BkoxQI7+bcnhQ0Xb%#cO4@6_9SSl{>5z*yPFWIruD3u2wS8yKTc0iesO#; zg|$AzNO?^yg0c2lzP2EP)QeQL4g;#zUXgUa48bwVK|w&1!#B3|Sj9>X4Tps3qqmJ4 zl>H9P)AmFUy`wCz%vu!zu(85vnzxF*E?C3}938*#nhSl%d_#k0sWP4`=^LE?SLPrh zsDLwfn`6F0ACfZos&+d44SI3q977l`g-oWdF0S`HUyF5tIrwL;jBX-%5VUJSPBOai zUn?w<;7_jWsPiuc&Jd8q=d*l#=Ry)^jL#38Q(6x1n_aZ*;$K-;{Hrt-CLGsVQ}&|a zKhO<`zGiNj_Fvk1)&Jx5`M<5Bv156T+l zRt--QLkzbgEraY}yRIgAB)3Cur^I}AGeQi6weiv8vp0_KG%8y5U*s^;Iwf&-#d!7q z6!jHuO}}rr1EgD08j+9&rCSh?M!Jznx5P%5bhmD zSSOC+8xtfMeL6UD#C{I2)WT}hDnMpA?j|ky*NX9yb4d7O$X&u!qMW#Nd2HX=#j#71 zPpn5I*jU=ThMy3&HK=xIs%bDfEAfZWgPMS4$YA8bUp=UIp-(+>wj(iDBvgmmmKr-G z4AL#j<{;;^UmWjRRF>PRVu+_pVf^iVIqV?wbWpjmkMbpA} zyK*Csv2@fcVaktoR=DqILtWh=2jbe+=?ulIBH8ol{6+25_J}U)=n=td?5&F9saZ+7 z=tgtQ;Lp-;@Oz$3-Eog2oecwYMT!8GATMGsNcK*UEz-f3kQMD1lhO8WkCBV%N!EC) zAYEZ`yxe(wtxMstGkmi=t`!ifS%V?&7H9z4ZGcyaT4R4d-{ZwEP0}*qZqy*sb^1Ud zjwEAjK1T;3Zw0%>-QZHSFnmO&XdJA6?uQCEqH#1I8R`S?MkH1YMWo9!OAW?JnmMYE zN#xMBSIw+qHh1ki|JtX^)_Z%$%4mIAKrg+w($p`RNi8X?#aS2#9*9vE2weVEtG6N^*8qwvtrn(yOx$a1_&1~>+lAD9ctLO~WK9^T6)lzj< z!$pEiH{j=_=VVkS*CmgPMf(T$O)AE|z}hk>vU3Ho?gDse>|?AVo5sfs2hMgh7?A zC>y?}4YWg3P6jkhd=3tIld*2NlIoFb7F=qMp)yx^Q!C7{1TP693k=8;es%YeCjZ!< z{yO{3We{2qK5zxwavy&I?eHNY?}LMZWM1@gMicldURJyd!YckY%Kh7Pw~SYa3}1Kq z`3-uVt)+Uf)b9s=Z9=OI-eWa5DYTCzRbb_|+Ep^Z4%DWCV8Jdrth8|uRrKZNt#C7) z7)!}`mD~QDy)ab=3+GeNsgJB$*t%p3E|uSgs%>y=+Mp8IPk5{rAB0qVoYyJw?Jf75 z#npUvI_R_6f)0#5VNUU}#X;CC{+hx**h{;I>hL#mvB~hSoQB6{PK4l|S6l)))+R?M|J~I4#^z6HE;?rWUhg@DP7)4O&Cr5%dg@ z!&jfm@(Q7^q^|pPK{{wh(NuAtLFEyUhiJ~|JGa;@AH*VMh=0I>){yKpf8d)!oml!a z%Cf}GbG7#hfZ1)_Z=3ALjwBK+rTA% z`WI@ANB_|U2w$%SC1x6KDZ^t~<4}zyWbEzz^GJBZt!E0al9fj!(*C@WrWCcUN|0vJ zO;{5v+0Lu$Y-6?H7*30$x_B24;b`;V2VT0BueL=xX+Nzt&>Z{c1@B&LZ#yymr05rQYIPu-t; z-aB%c?H=FepVei z6<;@_jw!_MF)i|+3y5ewgGDoq9hkDGs3s%5V)qRAID>zFbdqk!bi>P}i(t_wHMcPL(_A>Z9$|7ismv0*AcRBicA9 zn9WxrRTzCh!ooZJ-?ZbWo7upDzJCP-V?u;E5cq#$>MOTdvKb17nJcj1dP*Oix? z7g0<)*tR~jystzW<3~lH9@#E!KR$v=wCFq7@?ccgWb6}jf4iMys&m7a$Lpo*Yij5k z5_zAY%{Gn)i)$1QH^8Hzsk$R7`)kAIbhYC)exR^^$p(B#wasdyS-8Yi{#`*!bjG?y zBh|WT)gKDu(r7m$HtUy_h)tDanv01H0%gfyaVx*N#CBlwrT=VNya6RWPL#u2eh^vl zpbXXH;udLYyf_uBBn>0hG*+pj?CNce)u;-CMqCBS7=Y;qk5d^-3|`Fqc-=Ri{vQ1U zfWfABdN*w2h#qQogI$eTi9p1jd ze*O%P@X8%YRahfgC309rmsJM_@n?uIEA{rv;9a8gDm_HR7TtQSN%^Oy^L>CzgAOqSmZ>g%pthlyGU28w>46hYae;>AY%*mfE?wic{*`qZO2DxkSs&eMAK_O295j+ za%p=1A{U@;-&;>@csShnp?N1j#*f?mNu}(L%t@WJR0tmku`+~m0Vm?lWB=ARa)S(miJfY~UDJ91?5kF78j1?&(Y%C0UWf;M0P;T@U z+tMSM;An4t+Z+g?h*(jU%uBUXK%s-!=unpgLNA3hr7CF?)#wbL_Bh6%G!FtKby60= zy|M;J*2v-0ZfMX*S)+#GDb$*qzg~!lymxweW5VD-Nk2ZH&J8DB8Q*L(A}ZK$o@ChJ zG#<2ahSFr`a%fAhnItMI^TngsxoQ&ssCd9NreqG4nV&k6Kv9&;qn=D7311Pgu5+^A z{Wb(2X>mFok3!Q==k(mi_Z$=E<_y~`+&4^t-upJwOt=_ZNGA-1x-?Sad|MV~D%jll=;wT>CcvM6 z5CXmT&?6QX|G|<~J`Wu=7+&v#q1$0w%FH&Aj{VM2Kcj8SKqS&5N(a{r?@v)$o!k&H z&BMfnuA>Lgg>di0iTFgHXUSvW=6^vPm82W5lDu6?W+~$sQAi<7V1zV%@U|cnLojYg zv#a#>6kZb$xya5^28-z@?oY4%+$M&R4wV-aXQ+m`hp`W?KBXgHBM*$t?R9JbL_`{E zV{--ABw+^af`G8XY{ae}H>WPkR{gGM0KEg_SjIb8$T@< zt*fy1x_|~JFf{}yeY03K^_=W{22-&yhgJC|w&0qfG1D7E8R>I7lho_|JdJd|Hm;lo zW({^lt53z;i_-gXZ2mE6?FTrOfi$%32cyHd3lgFmUoKjen&hjr1I#dKLf`)bAQxU+ z9+0pbkuJ|-a=COah-$CWw|4JS5Pcn|6M(LPON20K(b3y+`m_Q>Yo1)(J}O@qq!^Pc zaC<*})$-GwLJfQ`)d=OfI9Boi-tQrJJeWlVbPkVN1RdkG{{RDd$aeSbsqKW^KJ$aa zRqS{sDB5|SP-`}<$B_3k;$){U`{o8C+58t)&qS)#N);p=1cw`HsST=lZ9E8rrK zd|gh$^hbThPspmaf6~xXE?Jb5^Xvt2Xxp~nj7VB8Unx1w6Rt1A^86)jUs>YtMZpRf}Ucnqi5lDs1n3= z>nrkADGem>qP`)Cr%t~uS8GBX`V(c&tcd@mHwUJTLbSGVB4%4m{2c43Ps7rx|D?{G z-RSEGR~R{V;7<*N8KJ8jC0}>9X34Y4rck#$Dic8C@Iv3w)b3q73X2bOz40=CX*<-+2x+dY+Fy^jdu>lRN`$Pv=u+<~<;UJo##(gU$6mQ-`d@uEJD0 z%3MEg4PInC6jrC6`*~~)^qzKU4PDx*ypY7AD3~$O9YI(k$9D}nTc#VJnNJr8`#xXR zoe$T^zBQg573vFGT&E>??|2~iA|8{(x@0;Wu3~G>hcw=K824XWoo{>vkHYV`o$76B z=gPW+KzwMB8`?oS7G&*yKz@2d>UiLFsO3Rk&rjM-mdb*~UHk8YAc+=D!Z1=Y1yRxF zg%_ zS-L7qf79npnUu>_oavnikK8ZLoKFsg-%oU3?zXboOvl)SWB=Rkr?2#V{6Sd{s&N&rV`bQAOx8%2*7K)|g6J(s>laCDX%hSiyP zZtfRz&Xog|xYN`-eE@(?=v|h_YV2B)!?~(-nl%RybTvW0^7?*H4p4h zh?ZccRl#wTN1U_jEr3z?{cs0&>T)ekkqty@hd%BF}yM;cXjRe{_^>p96YvdnD^<&8zEnyB`MUz4M+bKRc zSw<%ON$7*bSX`m(Upd>-TuvwLTx2OFEbjxC@R?!BZ#LQ=J^L{XxQJ%B2JtBz94iQS zZA6W%Rr2}w;>HuCHkO;Dhag{bjVrbWd4 zz(>ZK-ua?Wmr^e7=e83<+6aPqQeh}cp$Bl@P?+{Ye0)0lnN8p{Yu7@rH5za3vPm7q zuNAs(v8fWieY@V5&AuI_asA6#TD-~8YR*tz0v?kTs|TnF0tJmOg6iagF@zXoZ*QMrQtTuIerB*if)p%V zQI(^R7u-8zv7h*43V(RX)=kdU7`qkPGaBH_`5X*qPac}viOtVcbspg87>`2#ljmdo z4wG0D)=}Lx)wQ<75W@~3i;KV6+TCg1ha$K_S#Q<8(wm~1>nZEHNz>l- zMWW>&Anc=vM?Sk9wV&5CS)A(E;xo%e=wB8EDcyO(36GEHpbNR50?##)wdCFsawOvf z!~79nHX~>QyqcBa?iGRC~-?xB9zH=vc{R8LalK|(cRt8(Gs@sP6t0J?`v1=LQAiY>e=Sn0P{@XM*o zx}cQSy?veBHP5G#mBmLJTF7eV{SD5>k6TFP(HbIyma*IceGhD$@Jqk?P}9`sKfXHv)L@S&ztI z%G;{{tO`5oF#PnL1T6;pLg(!W;;m`%kcO>pq}hq6Z2<5*LUn2_=lw}8iq#IpJ#dve zrLTH10Te=U-w?w`F4X2|mF_a%6z??ql)g%B zUqAjC%|wacyy1BC(FBIVhg9s5J|(HG_+$guthj;ZY4ERr>@QsI}Tt)ECa z#Qq5(3(<(vQ@p~oLY@@l_onkb)yvH+f~9>i5?J-CM?Q-V-5<}zc?e#Q<pqRtxdN*T7(1z|JdeWPM44Flb=P;Yr7Y3S(Zs9Xy|}JiT07v*#+G z0b_mSfW);b=5$>leWcIMFDMy_1Ms_du6r>?7V(t9YJo|px>$1D?VVE-j4AI?HkFtc z<+kH2?mK1^ZlvwS-sVX-^Rxb_Y(KS8<~WkbBzT@^e-x}~!)=96hfTi|!xy|Mq}qP+ zewY+ngiXn(=foUI~WC=qxg zesk5N2wI;beBhRvs_A1cFFTAxmhFqwV) zx{7KuqNev0jOCehRXxN0FbPi^zszVeU5KQ^3yG4U>cA9_r(+qIF+F@U}gp-$=o&%YXEKS{o4e zF1h+yh2JnVnD5l}guQxMtRSBaRkeo6jKur$1hvX(?4?vkA*nZj4sy=njULSGw7>5! z3!UeoCJF*1ypCUyMpfTMeZ&KIz82|>(H>7Cwmw~Zr3%A)Qz82~HuUf^*ZBdVNTTOe z;<57kwd>iM1Qda_No+fz2I~4dv+i+|gO?B`&wvxB9d;aT@3* zg~=^RIOVS@2dpKeVv-pm;%~)0-o~6g5!ZR@bor3v^8VUst7CRB57f8aX|%v!WqloG z{Wp}2=}uK&_KUVoK={xim%g}v2S4`O+Am z>x6%b5)zjkkiyPRlOBFbx=>}th?d!LP6h6>O{`IW_>Oc(-P zd}$!1r6GIq!J!r9ZrNQNoFLEJH^&S#nZ)qZB;VK?lgc7iLXY<8&fu~5 zlbz|qP1>(R{>A5Z0e>WL(Ru^2tX@kNT)_x)Wp%6Ir1+YJ6tLpZAy)xrI?F2Fc1~%B z`+D?Z2iSuv&2)`r0<9LT>hu& z)++JrpDKN-&R%XxT-f&f+_Lo!RB000p=SjG2dcTEhdqO6M?dQxyx>1_zB9N)gj0o< z{^+DWT(v6#7!l=uRiWk-IXeC=}AtTIiVtVy>l zPTJqtomBBYB`_8xH>(^Aw`1ki<8Dj$t3;eHhcX|CvM?v&WqXl@EuUh<)G3m$t|&M# zpFKJZ4TROyf&M}}hH>Iz`rs3kJDc!k6W-9j*u3G`$u|&)pzbQvK z#70Vf>XI4)tgK#KN#P#FBt@Q^uSymDSXcPsP*=c2E>?Fe>di?Rz2(2gRRbCy^t7l= zaCDC)xIuYRrwpKqJ0L5W^y{ZlmofW>Hn=jqgK2C)WF0fn@tO(y2F^G6-Jt~KtwG~% zGUxeyF;5Fz>-wwPwL81_gUfI%62v6Jj(6|OFPYRX9JGDYMeE$Nv~?V{)Rj7T57t;T zasKS1`1BlMxa8u)io;Lvkge`52%fy<_P+T2Isa_d{qH5#@i&m=or+%El5~SK_AQF4 zO|_#=&6Uiy>D^;CW7F9)>@%g>i#XUCe}~MLW!T0COTXIDat&+tlPA(LcoAGq#Y9Re zN~)GdXa$R9)Y=D!|a1X-f>#|q+@Atlp@_KM5?L#v7uX-uM7m@2aU z&O`reGRZy8^?|0ynqM&mfib2(9)Oyh;llBX;V~pits+e2EN6OdYnjp zcYcb{7-3o5l-nvv{on(iyG#75`%rjc*DAqB_WiQypv}?pHiWRi$6QQ8mA}rcw;cmLQACKi^cCR8SIU2^#s9q%9YAmehvPDf(1`+?A%t@%p+L zDHr79b?Hui8LN1?_=cw&eTWz+ByBbaCcg9V{vuXePJ^T|e995!t?}n|GL0b3wTFE4 z!d+a+cHe2x{vY-J=w;-vpDhv}SEh)vb+fM3uYWAlYya&IGCOTxTz%XN|O9dSwG?L#lB)oTY z0bXe2{D6|oPYG1mkuDdt=0E6GJ-V6S?vbHEia(dGJUz@>m({}~i1_1cfOq=gBVw>h zL8dl+<4F%Mm(f4ebFpcp&6tZNwML5DDIRmn;(OV9hj=&QWE?db<^gGjOLny9H@WD9 zwZ1p|pPqvsZMz)Vq2qi#{z~Xzo0n1SsVS$N;lOOtSkJMulRtoX_76e2J1oDR;w{X#-DflNe*1h zqLi|&(Iv;Yr+24P!U|OZh;(}O%IcniMrwZ;t>aY8EX~jG!05gttW9>1IT*q}6Fn#_ zwjO(7R{me@R8qk&VynJRb=Gf?9w71$u!|+Zq|D(6srN*Z)49-&e7`gd`;94U z9C_nb(vZXVssl=l9KRWk+~Bd+mO}r**OGd~-MRg0}0M z(&JU6syfm1A&*r`em<<<5V-Bbj=xJ#&V4=)JHC<6;SZQVDd*#iH8T1|{y7HvSMZV_ zeO1Mmf@hSg(Z%X3>rdj59h`0Ss$uKsV}>W_cNt3jqlaa~<;?{Aw4v;C0RiX}6|eX% zz@4{&Nam4kZ+=k^%mKU|><0|GIj`U56m)hWd)6r+H?fi`at7q=Dy6|8Nr*;XVH{!G z{%LUTzQ|9#n8HXJn4;e{aN;CIU-&I*Dr{yx7jnlhLE?suZF|@LDOO7u#cKETlY)*l zrXKiE$GiX~wH~{yhpaZSJDlCl# zEwmAX7WIIfw*pfb9izA}X9(Y^-~wJm-f}-}pmFT;Vb5)bAK zRy7j5!HtH}BrIIAkZw*+y3fZgch}tUl@p4jw@qcSO+FtFs4B-S&tT@ays-ixAw_^Y z@Y~;f-dbU=#yER+s@LIM*H4`b0uk%RkTd03Cqq@`cNN-cneuFWp~Hn+Yu}2JG?@b_ z$DRo^$4nvP5)DQ6mwxZFeiYT*iED`;1_6Ty^zR%yqmv*;(Ks~3eN=o{z`-29Zf>`c6^&1|3z=q@&?a<<={C^sRRkP2N>p(gyRWnpZH+n} zqI8ka=k5#d!HdpZ6nSp3T$voqPj8;HDa-A$=39$19q)%N7oZ7;u2NSQJv~3*^Dj+c z4HtVGsSU-g3ZGchO&n7YBKgEkF6~lbuziMDKkiJm%A8m}sJ}iGwyMHU_E|@aQ3Z0$ zs>n=ND^Lff?lcn7Ok$0R5aEt03gwG^>U7M&v500_%=wc}l$C1aT?GoJJX=BEncH2S zNi6AB_pVqKR8y4vnw7tIZRSZ-fzDyJ%_~SMUV5jWHR5Pwj11~W@e+&!T6wz2$i%+O zP*{XGUKgZqw3S}D@bAZC8cB$?A0ths-ktoYA;8qvJQ^SP^H%YFW<`5)#x60ED0A-M zS^eLt{x%lTcOtXU#q~^@HK04|*SP{LCLAjEkc-TEW%F<~ya@@`b0wxYUH^a$4j7-{ zBAitctmwG5GHa@ zs*OJK|)hG+d(rC z;n5Y|vj<%0?y!84((ka(#r1@o6_R$J>uZih^ZZe*dq$5pp0_pZyQ(5qpXUp3>ef|P zS(*47u8t8XC0{+Pf;l9$ELK5kqS8fP$QYq9EQN})h^%kP>~cO?c6{ZRIFe#xNBz7^3cmSc?o_bcT2X9CHt%_9g$SgQhJb*2lpvS1CQq*7;38cSb%LrfH$?!!x_ zyl#DOOLkVMUy6SjqXVyR%YP78DZu^#%mTi=rCGX3^DdFgczpmj$Lj=T#j*yf<|_0x zNiF{a4F8_fJ`-ozEi)h$D!k_Ri2prO-@U8!hNx2=nD0tfk(%AbL>xB)wQ!xqh>xo3ideR98^_$;q=gL18|<=!4>WCbJ5B{v zsUbg=e%u>e$j@{y_Dc!0(Ng23Sz#NVpxWeB|LGAd%B*9GIRCEo|-T&+dM zmk>+wRw1g8d?v9uASdHmAZlL*7AKKSS`?1U@tu!gE_gu#S1&t=`$T+yB!$pOs-`={ z`2&bnl*>%Aw|~0M-bm}|!n&1Mc(Sg4VLolI{WA9)wm+Q#8#rsurYA_b9`yDZA&zO* zX;rgLtTlKn)4+CMXV!!)O#3s2f+vj%lD)ydbvi^1J0Jzv>EY)iGPxx9h>CzI?X%-M zo{JaA!1+@Lx+iM&7`=`OU-{9x3Vxd2?K!*L6jL-19I(up|NoppqJ@m4hPgDpC)nZ*;;Zh%&*h))UAF!FHai4>BQ>AU`UyDNScWbd&jlhS~NvH&#XsV@uYAHX(~*LIpUk z&xfj?RY3_Kya*9R++sQK;&E2m|J`xwR`%GItAyM=JJzB4nw;}Y%3tZ%XXkRGCfo3V zw}=64j}}C+>w|VK!7lEPO!)1*k4y+ zq(c_shy7C;D&gFIVQ;HnPq&0!<4g~Ch<*fk+&@p}MfSOKKGZ3&ML*;Y{G?i-AXv>( z0J#x4u;Qr^zx@a3$!eL2IH;T3{=((;=wq*q7(v1AKghqTA3C}eVt1=_=jvH@MQBl` z`Ya=&=AF}Jm6Sks3_e2P&BGYCk!$p4;fzV+*eWOjG}NFps_#u@U*P-03`VZUUI zj$9fPKiW<>jqtm8;Yki<4yekX3k~5aGzqLy3O*n~%yPeMDYsB)MsiE<6}~>e{Ri-J zVZquc_&TEkTWCO)PK-)b<7tV6Mewfe(=qIY`&&!s1j73y6j#1_ zUH`yJC*pi!#tsC33UXDTW!T0nThftPGm3!5Kh0Lxkh zgC%oXBhnGy%{}amy>7I0q-~ilZq@_;ZdU+TgDJkgXO&?$T}61hgx8P5IChNh{7U&R zIXaRaFuW_@3C{QG|DpW$NK-r2I_Wv%=>?6|Eg2~mIfhrr-PcVP$GqbQ{t}c~T-eIH zj2V0f3WxAq7!iR?DiPblP5I{j@;|h}yf8OA5R1vi@M8j!8`>b1yPCk(3GWppv8<^a zfkpA^_16R3Nx_@dcI)p6G{U~epHu=S&^phJY-B)tzYAdAo_?{x{QNWV6O$|e)WCj~ z-L`?`Z{x9`?QnTaf|VB*T{mirwQ#R#>PS4;`E9Y}45ab54=aOLu%A_-Wf#6u6_+P^ z-_PZEeB8TT%(S3VxDQ(&0QUG4|2r7&GaHbA4}{AjeE`{fD-^fus3La;qMZWy@L-h$ z7U*5RhdMKI9SvK~?vFFXW|m&GqC71{?qbXnA(+K3=w2$Hbm=@0{1F>`TpoA>@`MT? zg!op|Lee}uvt@dcJhd0tHgxkDXD(R? zxnEU$G@o?k)@Ee-`oa0h>6Ny*ozcC>)C+}*Br`$#Kfr!Fr|Dkr#jehpDm`%jC*4RW z5VoAHmqIJLF^|MSA6SB~dtXQr39X!DMKe|$t_V@$dN)ju3!y|OirMJSPX{PpvgW#IEV)J{yk<%Dbedacv77O~s~MiY`MiG_$+ zm5jEoe5&299+9LVLdvdsoe^N;i_ywEs}KItA7WHOY^*Yao@u3bhIU$Tdzp)mk-?&4 z26{=0x4=NqTdYKve?o$HjZq4AvbO!E`+ z3W*4<@2spT`s*KqP7Y6+%zr&--OMX%E{hSd8J@Nxu+Q ziEY@_&|6ab_RpL#gU5jh6u^Ev&0tr~`HD3`GpGK zp5aEk%PDAP#!mIRo(*#ZwhM4XKfv`nuMSNgijkZv7?`wDQfw|Zq`pdJOR46TomN=0 zn7G$8iKacy+p5tG4qi_Zh3l-P3o6Xc8!@(yFd8EokbS*?8V7;@p@=4N$M=tIi)%zW z>(XNSA1~}+ph>)&P^s&iEpx^64>iY#ityiD5nSJm**9wi^7} z+~E~+6AqHKyg*M;7C8)6e#$Av?7Ka*>Qwi7^xGiccelvXl)D`07}pZYq>~u-5}Fix zC!|6(cs1~m@npxWWOcZ>qz2bu{NWHu{Sa{j>Qg5 zq~SJHP|SqWD*T>8^Oup&docjWkRAR~3Q& zD#oWK`ZJ)rM>e%Hjl!%J9aX9IOjezUHWwOqF|h~J_X0+xL_WboQ#cT^yBO4P_Get{ zn>`S1KkwIrHJ3w}8iC;!IsVV{UJE%yh^dF4f)#OUpj`c5YS;1}iXXBhOTy}9VeFad z)TO9%oGT8B_E zL4L39oZoHSTyJ`(wO<#X_J}c^V%IFDic87k?a2;E^maY^O!Q0tvV*GV{_O84dHX%= z1vXq3cgD|><}V!ikUNrM+#y~eUD-03@7 zfIk1!$;){<<7|ge+uOX6)2$J8F$XWHwF0(sk^P6Y7@Clw)Rwk_s-F(i3B2i<*Cjtn zq^INTZAW*v@xJ^6yzAzhO+esbxpnT#vpD^gXzuEdr^fHK{KQ3O|E{uiF0@P5@q0hH z6qA^8PU|UUFvDyjRoN{abDpPjmOsnj!>nHJw`?745+5Pspk9)h4|JluaV=!Jymcf2iIg^g1CI|g}Rrw^5hgg(n6^67_stpJ_ z;YIA92K2lTZ1wSQcokKoL)$VHA6c}To!QCUZ-5u;174M_vKP8^u1@FzO&U9im_xCgGdYvSr%Uwpg2Q1& z9~TYf%ue6-@!SmFg#;@w;hzJJx=k)!IK3v|OzLnGGfc&}N;=C-l4 zh3qd1IPEzt?N*T99uTZUx9j+m`SDXGr(ZB85l7jAi80S^TdE3y=m-|Ein$f{Cq&V* z%PxAmMhqaw5L((pZS-wFB->Pkp2d@D8_S#6e*2;MOV>weEAll5#}Wp$YcBsb_P~d| z*%S%H15kT2Z=`=-QfDtz^s~t@b&%UD;I}W9OfB`oaS&fnll|#OtZwy$7wNl3cEjP& zG1c!}JjM9v`?vM{A8Uolx9EG+EhB1RI<=yKB3s3Tl9YK;9jiE0@mP5WUR zQu;@Ww_LDO4ZNDWp2xmiZ&pkQN*7Oe=QQfeEa`!l7EiczYuYcwc;v;e%llpXA)}jW zl<(cH23a?%^6nPDL{}=onUco7>x2qf2PH04jTO&LLhF%Y5+F%HHF*spXgwxLUvI31 zJEc%-X!zF%{C+5B!`MweqaHlC*_^3qfKL}nBe1ml`;X$EW3@Kvv{CJR*@nkqQ^ph% zR`9fzH$gR^hqZvV;Ku3X4(9a;G;a5K|8iX;mhegH%a_BR8{Rl4r6DBQXs>d*_YwQ) z)?a%DKzzJ)%x1aQ0{r{(G~)g15$+SG!0lhb=hTQgUx|~U#@)XM38@FA+5F<_>z)@O zXgia82`&VUSJ{r$4o+llf8)LHPp?R;+r6)(^bhcP!$pCjXfR(Ldw;A%B4@fpTSpYT z!41UEjsQ|Zg6&IB^zjC~*KN+*dqFhGt%~-K&&S=g%_;H5>SvGn*kP!MQhqbN5AEbp zE`wnQvw%}3c}KC!d-1)Bi6SY!P#OCQga=;1r*jjHi6eC>ehonG2L7Q^dq}+tmKR!o zvpd29FjKwAxLB!ua+Y4jF=?4<`_^o<$6KIA;{T2EYUfT&SKN5z)4RuwtBA0c5|14` zF4&_DuHyl1j3855Irid9eV(1ytjrv$H9tSN!Qaf`<+gZy*|E&e>Z*c0S)AzR<1Yh; zyTN?T{NYsK#eNs+ns!mT^1Y|m$bp5{F|NB(ZIC2J6zBwUx)otWT}JBJ;&tS$OkJ46)~Y>?WX~T?K??l?eVt zwE+e!Er31$JXoqmkC5Z|3)ae=CU5Im_m?#3cHJ8rp?TgL1T8j^U=mE>?V)M84N(uS zrj)uP{<}?$4s*a6%z^4teL&Z_FjBJgA0VG%eNuuL1yjPOq^{2+pU_Y8>1snz<$6~^;XDx=zraA~ z>xs|cJxM*L4N`g8rYtg}Wk3$gQ8e0xT8ZjB%kqNJGCffnX9LCf(Zb15zPjH{iO(WA<@^BGhnn^?=tKv8^x zY~R(~egIx~tfEEJAnZ*Dtc8C#UbgQ^ax$Fw6!$PGU` zNyVdV2M6Y_UoyT;5G1vSz)_1&k^*u_U`)FF7x4eS7f*t=;loOMk>g0&J z{rS-l*bkC}^3AB`xr~F?4_{b|&256-rZ3}2_&!x6C|7|0{okte)T6csPg+;|zbB*{ z%E6e=Ysm)ob$5-J-BocugXmI8ho$})+%A^RNC~#pVRe3fM#A9sL{_(;t%m2OW-fnN=P3@13_8QF&f%z>G6a$9CSN3K4-n&Ltw)=pm7#5H=Ty9O=p?oMfoyQDb9OK=EorMN@z;I6@4+K>Bw zzW4dw|9LI~&qa`4y?TX(iS-s6`z_}?@^_s7zmLDa0C?!g(+ysq1F~PL0HxE-r2!2}w8iyh(II8eUB^kI>q6B3f-?Df9f_r&`G=u(P*1Uy|rH z-t!gI{c~HSe=dad{QckKCCUqAR3tR?=d;3i&wWCAz7hIM)aOQk=kERU3-2Aun-84g z>aM8NT->Ig^J?%DyCw-}cr@Hj(FoTi&WLD3&HlmxSkKL0;34Ay!~iS#)QzINcz6H< zL!SF?*{k@=REUAY{}jJvgO%3*-00r1H(Rk`%q)K(tR0)$_Edi35}9qC3;1zkM6IJ` zFYEMGlj}PEQ1~HyrA&)VbTqo#&CUC(*I6JYM#HwOV|Y<{X&jNe@9Gj?DrT!KN$hOg zjEb?h#}rohmtevdKTC5e&3Tky%I{Woo03|EbRR-F$ zZ5b-cz+Vn}a?z&#=rWjKOes7(Kda}iOGzOG2>Csj;H(sxd8J?c1>E5-+5H8uPo`Z# ze>a5rX`FX)VPb}i#7w_;B>U61BbLMdtMq_TN8Kp9Frbc1@X=yMRcdI=kzyHis;My~ z+UyKvRqn@oRfveKTi1fjk^^q)SpT%vk`^3#-3QO=C<3cpD2>v;@>{<^vAT3 zP@A|a(sJ_3SS4Z*V|RAZokIO&#n0G zxy@W#ev0J_UX4 zjv{-)KRawWYf(>a_xX~;GdtHAX#=Wjc=VlxsJyy%UYEkQ9gmtBBW zMP*69dKKB99kVcxrP$HUMolWcb2`p&&1@rU^4a;3+K4fnvf~F&w@!K72j&Bl$r`XBIKm70`enERbHL;P3&0g0wI5$tzad#Ugh*gQD%!?t$n}GQqVR) zI)BLzfhf?1>N-0TUzOnLS2>J@Rm2Awn0ae&wwKt!zwOM5jQIGI>+c|NYzN{AS?g?Z z&KzgrN`JQ?)iJ85BG;_O*%coX(zUBkh~G2bmxy*Z zl~M^n2IrVolJp6uzW%sOn%Ksm{`KpuBlQ%Trb{vRdw$sFAjhuM2>iRBeBh6+m5AYV zzxcg;Nwvx&pKq45xaRwI?h^rC5}fO%Q~L(THUF8>LPHe!c$d3^#L=*p7bfy*vT4Uu zfA%-meAuZ?9EgQ^yfPL&i;{ARY3eJ<$VJ{~_m-r6^slJI0feFp$tb37mNOT%fxfO; zvhvv5?WHF;@|Y{d+H6gwxd219id7#AtBT3f%^M;EsqfIQtWQ4r3Fa4LDEKllSz2)P z!FC5}zUWWzC8?~nr58O>HIkX3ihtY?H@VC_ zp7bTHD8x<**M{uTU2k3tW%;aPJ%wmM;8ymnw8(AFvO+s~ihu%PihYhi!v9e$Ebq?T@m;Y;bf_pjRjh88R7m>+A^~ z4853fei@$&^l(TH?X6eZ$t2@AddH3rl?l(o{C1KAi4Qf%m)>rrRt)%FdN z;(QYM5fY$A*cZCis=2p;x=hBbXYF4~#y}OJ0&)=Mnx&}$*(P90`u3$c zwB(Q++~gZ+nsOweTOpO53{n2&^Aevg9aCp-4;0Igxdt2#h%GO~$Llx=_|82-5q}t( zRMAuP1JWA2DL=rhc+h5n&RBO_?_O~Wv3vyhEkr1&zP1t zF|cuQVX9VLqc6K$&Q%e5%MdvnSq?YhS;D@ES@n^5@&Tr--!z%JquwuM37bteB2z77 zlo=g9y6P}l=FliANFHVh^+={8wg^pV<1=*SX@*xeGqX0+>8w^5m@66u_A6QZ?Ii15 zUB^wtvT$GfRxSdQitqH_h1m5i*DA>L;r1tJ^BD;3mQ37JP>8(saDNXySdIVVg9(g# zZbtR>zs+h4bQT?XiX&5?Fl$*;qxyOCP zv8(CTE4{G=%F1oPiLy&vQ!YfZLe1K=9-v`KvArp*LMoe#JN^PFMA{^vfIo$TKyQq7 zg>1HFzvbcXzW|9$Qx>{y!S7@-!Fj6$Y!tz^N7uz~ev4|Bx;FLSQwlN|3jdi}K}x|E|@HnpqNzUb}}#^<4b)73`Y0tP}sHaXQT{gFIX7LhUa= zy170#@*%}A2F`#O4#qhjNBgp4)wwO{Ok7Koa#=SsI62jGXEInI+A4zSeM;VB{&qSKtr5%fs}} zTsQ*k6;D%SZ_+30nG>J@r><(G9u`vCt7!@n@W7i2)|ti9R8 zAU!AR>0&SMn5M;bt>J01=1tiQvZ-f;8f~1B$2eQFwoyuaDJ}Y$pVqDUGGRc}elgKV z;kLXHX84X{W~!e{K%{wlc~IgQE)aPS(}!R=J;f{dgeYkE9*MOM6sw){0#=>;_w}e{Z3BMl^(Ni1|5ih8zFvIUE&I~IlcN%-0 z`>rFl0{Q;Li}62=f0fd)?*9ERE_r?((T;ZAx&~dS;MCtVmoQJz;pSS2PBw62%5Km# zamLMg8mQOb_Vapc&P2Caj4aH;!ujo98^}ma|IjJv(nAZTbWB(9=|m_rQ{Tf$rMyu; ztLc)1(!LW#EHr~u&wv1rlVP#B-036RjFFRP5?lyK#EzU_fw;<@h&IF2#x6ryHqS4L zBg$}3w}JbQotIKDJ@kn|h*j5@eoDJ`8F&tMQcis9D|owr-fIIzkEm2o`}f)2|BPt< zl8qh_o(E(}kfyC3*xRxPCTFbbV(JzBH^9w?m@4vsUxW6_G=Uj6mFp`8HXycjt4gkAh?bQXu^Q z4)1esZ@sRrJAmy9JqWJdzkqYfrkOt`1^iOdp8~$JWi++;F>VZt_++i>F*l>0w%Kdv z9hopIiW#lf70WixEK?gRry>=B%nS1FPIs99_}Um_o~d zyzan1#+<_ir&m)(n42^M`GuyfhK%ET_7KoK9kV$RN2erM`^1GJQ~$(92Q#9(o&52M zqTb6Ycj|_9TD#)CSj#KDh0Wr`qF?ww#fN{DFTgtGYxs;QCg%>(EJ}W^8+fA`U5>2=q-3^>@6P=j|738$#D#vTZcu3 zTrk{(Tph^e1{K4R*qwlZ?Y2YXVOxDV`3S+tUYb88vJKoVUg9| zhLfbIb)-m%-T1$&mDER^UoCl%(4wLVW%3{7k>=gC!VRo4oV1_(?_P$o&XC|;I~m(e zC^cH`Q-g(klLvuhkM%#YRpPa_jJib}4O`WSI&xWvGgk=mljdH|e1K_@Fj0La<_}%^ zQcHHecsMF?i4;~fJzoqt;bB!~ZHA708%zHdYMq1*0Nz=s1PJREfJMAhFazZa0n-uL zlW5PN?%?T;O0*4v%Wxi)A)3i@FXCG9UAVEriuFfDiz#M1N{h0>P?S8)w}tIlRw}Gp z>sHa3OBZt?hBP5^NegR=OK5}r>O$@qS1eD+&B9ghiEObo2r(=%#XHRDNghFz#-pV`=iP(ePY#se9}7*^q`+^*bNpZ&YVMVXs@6;(Bs zmkVtRDmkNwdMOjatxHQGJQ3?T4GlK9I@W2%axn0l9#>nUePQtZ(9c6VEa;RpexXB* zsJ%D~LKT$d~FJ{6oE=%bz$$E!`xL zHi5JI{EcH|QSYd&NJ!i^Ygj&0L{GxN;9GBjI2?*<2<{NILAj62XQ-9BbD%t7QTlf4 zPvG~_aghhELCIixd8gG4|F3H4$|Zx*C6qF>BX(Z)zAGd@XvI?4fbC1Y#oLm~BHGwo z6oVj4#TXUZ*Bg_+K7#`|5r%(M^}KHEE#aF+$|9`Tislv{MqpFSpJ|(re<6bd+>dlK zCO7GqHoLxuFVz19@JGpGk>+?cnD8}zw|l`8V>o9VR*J?DA^_~?EEwVoF}zueB39TH zl%(zL?dMdL^S&;nt}CmK|Lz(e)Hp&-J+Jd@IW}j!#Q8nb5{!QVvcmpm*#&%DX$W96 z+niaWzGLEqreM|2dC5?fr$%}sN@K@J-lWguRw2iFsBvOW*-mIJD7fV*e6DrA znl?(#q>P5V-;IWjN*1*}Bi_bcgc$4hDp|&XC05ljO+>?#0d>&4$z-ndqHLAV!)ybD zgduI83ANCXB>mOF=aoj8fm$uvl7*%HfS4#gd73Y8C!e8b0+J4Y8KEfRT|uF%Bc{q! z(~xh@nD_@{roe^c!a`Te|5iz-8XN11mEwe({%+DJVy-l9bUXbEm?)lCeC4ZB)VE2w z7qFM-a`B*QUC#l2bDpgj+b1@0Hz~2cdz~|GSEJW2(v?`<-2cg5#^RQx=7Z-S%WUib z-Kg`!e^DLHmcvrCr+nCf<=~780pc=X_rA#|wY{)ma$?K$D+wA*e%3o2X|2J+Rmsmw zRri$olOJE^_ri>=_~@sW#1TG&@>KLG>Bn=%c#< z%b-AVy0E(1maF|SoIN!FXAXHXi^YhJXPiA=b>NK(D0>mG6%kd_aAPf%r1;D$;Yv_b zVf+tN6QAB#Jh$Xqh&M|Qhg(|XAIXjkKRXM}Z(TMnR54v^x(p$)M%Bv2+Z8l4+;!P4 zr$;ZZ8{NJbxhTUI%WpRcUE*`m;X;d@GZ~GVbXiuD*3rG^uGgyCYvW=G;#8sN^Wtk! z2QBNZMr-)mN-HT(%z{-EG{I3{mZAPeiWPJ%;@WQ)e;#F=9W&e2a257$rrkJ-X+Qb} zS?~~BTwZ95?AcKVXz=+{EJYoHzAMOA=zff9?Vax~VQ*NZ9b$!zP3>NDpCdNvIKtQo zUkEu4slsA1vBpG$-{-7Io8CqnVf;Lc@lL!YeSD}trKexZe)gcHUb&&(J~uzd=zGpU zR2re|61--|=^gi`z_cUU(n_P4`>au8_Mv z7k!t4BR|HW%S@mefm(L+0GIEv^G1WpyiR>Gw|cDOiNad_eZ+(I-5z7sE-Tp|IsGB3#&c9al-gc{`x#Nt|(bZSB&Q>R^ zBX^tHZdokmo`*v2pVs9lx>N4~OptqjZ=9;{{<{0>E9~cpV#TN8)YF7{+bXVoXO({`v_bN(004 za=MZcG5^$*#t0+pQr7{IleusGhg+BdGDZ+$kH<`>YKh%Nc4)mbvW5F^)A6RzHHhLh zdFy&~@=taGPM8XB$Wz|tvtQ=-`ij=__IjYNJr2h_%+W<4RN&iXTXQ~;X*}$3y~fxM zNC&n?mAT1!Ozd~1Y#wo0;om)=k_`K_^O}-VntZZF;O$(^BBmi1T9-82{EJ0{3OW*Q zw;XJe>Srz%7llpwz|n(mGTHIX4n&`zcMij-f^-a=HH?05<2QP?L6qu;OqbXC=|Oo8 zbo}K<))R|}<^~^O1Mh7%4tt^46#W?ReA8fF!`n@((ZOEN5o^p=diPiH;)AHHqm@IVR=StEcMI6>i#>x@OSJC`o%&pT~kG zFFv1KL7q41E|XSDdv{ab4$g1_&L;o<2~ zzIz_J3EfYNB7st=Z)CaX5_`woX@@!eaqM+@<7~2XC5?n|PoVt%DWgP@=GtsE^twH@ zhx#(k$GXWj8>P*ceCQ?vBHucrU`D4EeWS|Tgw*ts;X>y%gV^#N6-qIiD+dJnooVS%;4=Rf#a{11SC zMkIu#`MF7zls$a+5|EkySFYMHJ{~ZXoag){B|S!d`=40<8Tk`fzusID3F}VR)n8ze zeSiXeg+I;<%Yh``WWtzrUUAMCy8;VvyQYko*Gpb{>ThN)FHJ%rCa?FSuH0tBX2=|& zyH-tu=ZUM$9mu`9sf745WBUhINw&H5Fu9Fg$~P4Z>zd%}cB~Xd>(~3G=k{G@jZlsw zu34-LUvIlaU}2{Q`+p-NhqEzmy1oyZ;1IR z-`>2^b!i_PQ^x7%e#YCCi=1)78@qP+Ny>4~oJ&zfWQq1zNs2J{xqy?gvPG3S#V@}k zteoFm_77e20b1d*bNA$Ak;`t}7qvMyF`B(fNARP8cks#$^fe#I@U2n8N+aYxttlt< zaY1~0#b`@wMHg%&Cbg3M7qG}Ot3Rc8ru`kSx5}X^%GxqBe_TiA28u8=gWG>|dff_x zXBn8V(#C{@TX+tue561Nv#V8i^^>o+Vz z!=8j)v6hZN5k))74pF~bAG@CtM!YG)xO*owD@VWSEiWs??-1V`M44NRh716L3bLu4{Q{ zQg#Uq%Q-5aC@6=~sd-{~pG?=OJhU=<@ny9f1Wu0j1R zn}gdMPWO-p#kX*zuCJ-y&v!7aw}thR zy~Q%^;rU@DFOYNfLxaWod@-oE16BYTtNbl$)F*Pk$`KK5s`q~_B4C*LUF7-DbuI6U zU4ecoz=qn@`;`cJT9=+XOMegaCIu1|&`s;JC9^cuh5p$>J{z_!RT? zopcNxV4w+rXMrWIX>s&*32GGw*mLfFHGAG!_@O~BK*Uuh%|5{=^RAkYBq4UkKGN7jqJD?l^0wCdIi7v6IUV~bSnJTaF4;JXSSg=9&&j}$A)1n!|GZ+* zc9XsBm0vP2-tlK@u?yIMi_-mjrRm_&_~hxF-!PxSviiS9jt9_;b{{B4viZv4p*0?B!-3uNx3~3T<#bh;8c*6uCQab` zoOiZeR6E2CHN_b9oBm{o8zQ@brDau($+^#u{U1hLuh=Qg%0HNVWxpcwj|NRiC)&@u z{}XkFnQzP6K4AQb}4{j~)b1kj0 zwSkS;=H{MLOc+0|D>A^} zq3v+3_}nl9{W0m#%Kb8&^NIVxqjR6j8}uB(UY61deL^we_T#=nI)iS}L`ym43;&bF z_IX~UkuYEl^vM`|e>!Tj?^E5kl~vZ;tAa-QZERdmjYSFzbJmSe=(w#EBDWk|tDT>D zdE{B$JTXRvaL!TFVzg2^salF_DAJR(P78isRI38GGR10MsxBn(ef9Q%0Od=xLhj(t zHZHsraZ#xCSG9nHmaK-MzksI#7mD+upAj$OHiao2`@pX%QqMw;qJL!JK;O8y+{C?; zOGH{bY_Eh2`jj>3)M*rhb)~7+(*zujgytZZjFDSCeqy15>6izI@pE}{l{s#JUhtC~ z1xDJ`6@f>KV!$L6SzDf0DO{zO&~s?;j(bMr$4<6riWU;i*W zYSG(DJEh#eNsgD_=Uc6m0f~g$*XAFWmiC^LGfILm{ayUJU}<*k6*Sj}6hTN_ahN%_ z)*DHxyDBG>$1;Su_5^J1w^>=JK!F$!V*D@QTfN@H@RG5ZXHdm(dY}T(sO z=HL}q(wxAz)!LLpzF#Mleo?YtkL#8?`3@uo)6-o&Mh9^Gajd6{HbE4D20VW1={mu$ zvKUtMD_ZX}P|}_2b&V|d_G~TE&RBu!E8ZyP`X0W{g)>PVk|6eiojzf{TtfCx^wNAh zNiv$)){MRow9sXz0G$c_T!G#-UPb?v=q^tx-fXhZWpuM8Vz(T?9JWUSc<7w8LwJ6E zaU7BB44JC$ijEo6A^Wq~LXbRw^uyfwW@o%_ABatzC|~b?EZ62=FnC1%Q#xp4M^K60 z-JH~L_v1(8sN(%{b}yCEWGz1yc%a=$nB`QwQg*!ZP|Pt&YIcB*Fwdg*QioO6i(ORc z8&yDq)~rH$tw*!O>IytiF;G=rRe>{%7kaUx8g-(7?z6RB&#W5Fb{m{mFDY+1oPNvt zeRt*wi^<-Il}))?+l? zf0Qy1Vg*C4^x=M936l--=m*vAVxc5+hUH0Li7Ju<$zg)bmfD(O61K<&a8ll0_Ac;4Oe+>824nWKwD z0la(ZiNQw8t>9*Zw^uwWdp)z#SjprCwjymrV+EMY1wW#iQ~LaTNh&IE^%~opL7z}V z000~$kdH_3Q>XNG(0N-4n>x6ZJh;e1R)~~m+>xSFB7S#1>ZsM!UU`#GOA~b@D1)u+ zDIh@W4WeK%_B}KO*U>_9=dKnPyH{U3)9~7#YrENyj5>SskUjiJGBI!z3wqwdSPs-!aQ6DYishBh{ z+?5}(QQn5_R_qv}IjV`}Cd>TGeudOcfI?(j2i9kndX|lFwLLXq3d=O&+K~-Rk0fvD z#BLWFUXHi;!Yfim4i`6(!fRuq7O;pol%+}Yt?yykbDpyc4sDv@t1F}pJaF4!?w})h z0)GDsAPTZ+vAPrd4@a$r>GYwk1%lxh)d7A*_sPedEC;mR$p$OgHgY+NSVkLO8X(cr z?16Fl9j-kCd%XW*|LBBQQ~-G)0J&EFXo$0}BZxM7V1FE@!b$7J7hFXLSu88H=gVt= zu+;DCPe-$k=3*|NINAT)2Tocy*b0_Y&BTyJT&&_BL7rb;nPJAp zeimJk0mun?Wl4+}P52&&eU=EXD}!m(`O4{i>O{`9Gz3nqRF!d!I)r7T;v@69-b%%A zh8+@FLvehWRpswh3VzLAD639R8}C~0eG-x~p9;2q*Wc``K9_OFcG4o6*H7Q{@fM zh_88u{+b(AOoYyr5vESHAGm%Ilc?G+i<*^NFK3x&eu7uIHIpq+Rw&_7x32c}RQi7D z(a~4#9X~rKbvy^I|3nZK$^?(8E`Q#2!U%Q#S2_62jhDm*MHl!5HJi)s@8^6$O_>vc z7u;HFcDh#;*?W+=Tecjs_E`Y;JIFyums7h)5y9)LIj=Y*d=$GV;t8$7rR8$ZAiyT@wBv==K86=e{@3Mwck zdPLnn$w{e?fxRpV3JYe5X9H82#{I9?mn3pc5p1g!f;EPoP9ELX`zqx>yu{)oL=HNn zA#mn;Tb`dbmmL%^Heio_Vz&+>WckmDW-_^|>C(vy=o%KO?BKuTKJ7H2+IZz2cT55xsy19;@jHOqTcSvNT2zE( z-G5&WwT$1 z6C3&oIj$gL{9P;0M0NSCRU^gHjjH-`bg zsae0-Na;s6(AR;)3F{{t#4nW&JE!@4s>l>eYatFThV{LTr@VXlL|NJ{y*zPolhRvI zyj<9<7PhrFPiuYa#h@Z3t;@%Kx&&VS#mtr?5rb# zGaTw7Ede6IoI5tAe7Gi?iT%t$pPKfJ>1#_aethm;7xP_hUFdJNI~~oK`Z#}l3od5J z1KKbG>(9?!Z5GQ0T#t3JTk5})qC+;r^a>KJ`i4ezEq`qf6cN6^vd;34TGS2>m#{a= z>Xbe^JLUAo3foSWJZre2H0uL#i;+6JUNe%2_5~?zH;G-5ij9eRI40t`$*%r)k^C24 z{eM!~U;mTnGhy@BgYCY4ez~+;FOc_LGrpJsnN1Jh1#rVMQ#HLjJo1WxS4WepU=Es@s=)ib!(0z+rs+ z?wEn|4cdf^Y{mUrDFhGc!8XZC4rNi~Vo^-pO!~--_C;P2>Rs`|z`_1tVCxBQn@HZM z3#*Vg8i#I3-<8`Z7Eok`SJR4}@%*3IB+sw0JNn+0XrKtq1xh#G;8R$QV zjOZt|?0P*zU;|zrH9LFb!FV^Ny{wiz9@sfxpPk6XT(U2r=Wv#P>~|Zwpb4{=Y{w%? zR+ExK;kuJqG|~LZ+K9^cK^_G8)7Rc?eQ0w9QI*l1Kix?9Fqbh2iMq?u! zg}l7BL(CLDDVkm?9GZ)}5taCI;xmxPBOG!a`?;3lrPHhs`f6j~AwkV3zGWmLz?q~T z@yz;$zNWO%9bTE`Za>DhAxTpCh@xbxs7#;(CpnroD^2Ai5sy=7igTTc?bluvcv?gY z>OoO17P{1ZqFu5maS0&EgT}ZB9NPKz{{_r9gMyPSD<&6D8g-#z!z@~7xe(0kCuJ=Z zY(j0=Itq|hH3yO}PVU-h>mE5zT+hM#HX3c66q5_nh*oJfdvkXPQ7N);1Pq~~mHWS1 zl^0AWN@*RtUrz0r9K{MCke>t_fogtK`WtfNR{oqMkX=bq`JP54TVN8xi1jxZB0vu0 zos-yswsIiu$ZH2K&@p%J?D$%hE?;!ih8K}|T)KI<@ilE}vj+brXd?1cP{3$uUS)VD z4e{GZFb9!^e~~z0+^<0bnFH#@AGtb9Rn}KdJ1jkFKc-a9tjPTZZAC5PGvIpk?m|zbZD>H6 zPMR%zqUN;b>;}U4QVR4Y^xuS1y&i0Ho;W;qFW|?^tgx$W?E2$@A%yyXGw4jS7yW<( zc|2-LXrsl+CPzwFdDMaT&H{d1;O~784&YYnZqx-WE!E=5WWy3ky@tf`hzitnjLDx& z@*l)}wexFFcMqP37aoQdOf)iM{Tc2urTY|93{+gYn&1phH6EVOnh}0t?1H8f3_P#N zy37hXNXduJysQV{Z5biPqS3YPf`w8RDJSs-&2vmAF}KL<&7|8})PUG>;10 z5>{mb7Azbwnw{6~c-9+g20e)oPw+qnbtY}qg=gEmvRUmrcG-#r2x9uOO-mJNL$IkTuk66Op z^m(F!W`{+7pYchH%hMij=nGanYnpOFP<_<$#;Ee!OM*W)K^UxeDU*x-x86x-r=0y~4PG#msPTueMYXq~S1JR>efyci+Pfct(8l{2&*t6_RkH(>K@9?a)aSV_Px#OCO@ut?AxW;^u`c4*awjKj)(@{u`?dRaoGAl*SA@bD;FG zm-Wk+J2VuT4+1zM3sv-nPCVc3W3H~QaDPIwx6c(W(p~=oI>?FMTN5+KTCS{%1U@f9 zgqm#~^2Y9LVmIBP{m-e=j9KpHF#!OoMJi2q8XCS?BRAZUYxtGeTc7EOV4(&|teK|* zWlZs}kVWtIVQk0A^tU8$-!r-IzX;fM6Ts@YM3V{kPagl2LIXIGLb zHaEqQ3*CUcWB6>_Iqp1Z$R8V&R?7M>aQzmONV(S95JgYych0I|r^_;0iy)8z$*r-2 z>7{RuP}u05j7Ib&lz!DId9E5$knLKJm=NilR0mX$-HKSj=K znrjW~MsRQ*wQ7|2J?K%uQ{-MPPky87Q!QRwbl#?9`U2Pxn&8Hn^@v>7mF&w&K98?f zb6(uBU$2>u$kSSqvTmeTD5Q+!6$}bYbahd%xel0Uv0}e)`d;JAV1<*7-Yt)3h@Gy;7i2=!_!fq z6iWtic;8v3;c^dqJ?5{C&3lu}r;gx~hmI?5-M4c=Ja&#Y`kQb>g>uCUsD~zt)v9ZR z+!T$KeKZ#w$*KE0>o<+Yheuw!fG|~v&l7n->$8MHl7+wTBHWdXJw;pPy!|hxkyp$9yCuqzws;T!C zTCI_A#YuDa7O`=3aIDQbnzfxvi7)rUMcOE{>25)6G@LQQ99r1*lE%Y->^r5NPVI2n zzZyM0wt;IKM0m^zXPmCzzr**&$jHlV?MCg|P<1Qaecpz!EFx8_$TjAaBumVHlhiWP zOV0MwS!8u$P-?Wrn2isTtm#&f0Wn6EwIW;M!$tWTQJ$iu6G`%{C=2-)j{ff)maBO$ zak&6nePxFpD94IsHg*{yM3ha$`PBlNH1p!H8*W#at3!50QXF)`P=a!nbA3WVQpUUJ z`J)vUl^JNk!;zbd-(7pMz0np|`;$$37LusxT$TYgz1Z-z6?uHrwtQr2b~c!N!ZK96 zkk?l!oV?;;7EYY0zXG-JdtQ;w#(oC@-`%XWFpN`7J((Sn@g}aTX#>%^Maa{|$~#o!%hT zhcxz9XeNBP6IMd$haA`Js2HLuC+c*Qr1aI}pQVq`l>zah94M z!&^OgnBCz4f6O&7{pZsL*Z^C&o|xBH7%$dZ2~j@Wxzspi;rnL#Zk%-e?!$0)TWp`I zRpSRcrgw#(FQyd+@;;4@`wk$%wcei;kttKuv7X5r&=>8<9tx?Jil4=O$bF;j!Eq?< z6uDXubK-lMy|~aNt&_<~(IVBf-Vv+wqvU(*>9Mgz#z{Q;T%eWU&nbzZsNA2zDi?<) z{Hhq*W_}y;9vrO8xCqx zoc6Mf(CaFuiut>uiRE7YRAFAq?v29dH1@@96b6R9BY~EOD=z~L2~Pq1S&Xi^k4vbd zGdF4-CtzDj<)vyLrjimzf8&cwXl`bxC>vJM=R4MRG9n2OG7juc*D_i;0r@oz8W^y( zRm}@v7+@C1)0@)|ouuR*A8+Jc z?Wx;pdoh@IJLMl=W6qL68Ozu7K=g0qwb0f1bMlYtLxDp?bdu=(|H`-Gy*@&Jk!291 zRQ&MaNc*zBMz*Hi+sjGwK`|OZ5Jy98X8VwGB*(pI>5Lz(-P?)JgGaEDM$Kw;h^O!J z2;_lvkbaWYt`ul~-d3e>B|W&8z#C1}vMK9O?5XUj#XZp&kkrNlnw*fELF&H|IoA#y#R_zz5!{mw1vp`Y zO80j@%I{r!#16cdAZ6E_oo2GF7qJ0xU$axru4w*4$uLwh{4UPkXguSTr;3PD-!E&? z|E9(z0Z4PE$h|QF58K*=DrjJ=8MR z3Kmm76LqEt!(J9frrB8T?@~p04?FI#C52WBG&tG_2(%-FBraeNQMR8_YrAPS6I=DK z`9p;zs#?ReMb_)?U$d=Wjr%x^%kM$)T>gAnqa`^Z5LP`S5~xQit=B+RbmyOV|TI2-I)XQW%o0LA}oOZP@zTvHpoGp?~A zqCBXA&@r%#`#xCVK``xdW`P%mybAscAVBfYUw)&x)(~AZIyt?vvh>+$Ruj36FSEJz zmlvGjS=?@!feiBN(FqWev#TN|_2c&;F-i2EAzShX7@%8PoYv}%IrvLv_=a*})RayH zg4d&B54Js9bo(s!g)@rPPQ7*^#$E^4fd>-+o*!5tWC`RvEfvpd4SD!aM|#`*8`It^ zB1Hm^Gg&G919wyT-nIvYJiB@m*UcI~#inWNQzkLIuFU8=TDq zWYN(9ta3WfJlJg9)rr@9)&i{uAxEgE=VIcl=?Y&cf9$aB*Gtc^Q;R88n>?1EDRwQk z7Mx!hvD3 z^`JKV-yZ`kV&a~@QoPf;DaVr!S(JAugya+|%qiWy2LR1J4j?sI5F7(fFn5%HUGGij zQ|~LDMnqu8LLS^}2dl(&X(fe+xkkg=OU!Z?pam~8YK$3U*p{b0VrFhEZ+7$O=Er)` z>3V_xypMK;G(zKL)Rt_H)n4sE%yPIc3cP&1&q1Inehr-&H5K~8pGmJ|$72^Lk4tzR z8MLPkdc8^rS)QOEo#tYfl1{6;_^q$5- zaIcEmiWE!YLU2q~ilK4rODVk^(k1b8Z07|+5HsKFfG-Bu(mIOT&kF0%2S(qoQu@OQ z|H1**ODPQ%tmiZZRImF=W&PS5PIP5+7JiW3ebf(SH=lX)L1cr%{#a8knwnIg7)}OR zandkMItY9>C|erWN*xM{Q?Jfh!L-EgV7TtAJYF8=0HA)fAd1|gTc8=I3qJoO>0qtM?5@7fnWc2S5ywi_T>wlQ!OXNX9Tf`ElvC&y_hIo0)2gJdz4Z%gNmA8 z@19*l)Nwp(;tavn;!7h$#<+zf+8n$K&=4es)*z^kg{N10zSY+gFKM#)*RX%76||ZAt`W0Q&LZI7 z*l$rBnqSMX^NE$!cQ|tRSo?r{Mu$zSrevJ3bYXi#_C0x$A2F78N*&fl>9@ZCosYWS zShq~(oWubqJt>Mq?f2=RrhehAC84q~!FsHw|w{3|z z9k)Hz!OoQNf{TEhGz1&eFNEj&!!9;TS&8?F@kiqwW)B{=EtRpQmND0}@7H! z#!w_TH=POdp|RBaG|6+6M!&%*W+w+lY{x}K8R+_qt*@d7pQ7} zJr<@ocx(mq`H$mV9UPEiC|bVc=GHpvQbtCmiTv`uz94kyje3%!oh51kEqwYS=7a1@ zmM9{g#A=J#Mi)%Y;LdKVk^zhRlK9E~Vd%BLc4jeI15vlvUqCd+>H(^YEYkns>#L)p z-uk^k1e6q{Q@TOAQG@~M9Aaqc?oROtNJ=+I!vI5fcS$otcXxw;=sS2k=Q-!O_rCuC zYc{afto7Tozn|RDelI7)D$QfDN|9lp8n2$*cE+0<3TNlgy1GvV`thZdGu2fgWnB|B zId^E_WbhuP$Qj|_d1{)b8c25q7AP}=@cQWtimAaZ#`q>_COcJ=#Ds=gKQa$Cxz;D* z{pg;B2KS@F2~`+CKPI7)+U*c~Z4h0O{}UrdWO7Px0>3${f>^BJ6-NIt=o1ZmR|*ns zy`79rS&c@mCLfv+##16yS(zS7u8=E)4?Z#*9+3u{G$r1(#bk<9-#9no+|WQ27J%tc z4kEvpjhz#yf}ShKQ|9cQv!k`uxz{S0%w>)8R5rn-=Q`zxb0wzT;8_Wc*+fn{{AZ1J zA1iq$Ofw1vH<~nf@$p=g_qeU2(vD0`il7bk`(g!II0S|dYW71M?H@4gNtG=u<*uZK z9FsMcf*lDgJhGAxD<$J>tkkn|jXE$C#3uAZqfmO**LxMS+||6ON1#0`iIS1wRg{V; z!jYh9XG|iahAtLmz2!__ue4#iL`)2eJ)!g}FSMOB~48MWaQW+ zkEep@30r2L$G-lW9+o<|el@!{(V#h1UWUTCWUuCLXj|}PC5tttG9fTcOxyJHW}l^? zqe#%@)-Z#mSQWW0CNF19#t_nZ&?6@ihuZ;SbyeE7-~1+#D`({gz21_7d-;!PPZ>N#G^`<8sm4s= zy&O_^-_a5RgHq-J_~c{?p-+MotbMl)L&RXSUnl(RO6mGO4Oc2>M!Scl=iv5tr_(~zV~gSNV%$|zgREXO#; z)AvG(p~voF7vAJbil^I7&cW>BAjaYY*T|2}GFCNm>Dqh4!b%-(*h^RLMRQU~X?S_@ zy-w8z-xBX`Qc15q7qZrc6lxO}VY&g8jJ{FzJG=9;Y2WD|?^bUOhVeO_p>`?%zv6W>KF8@vy&FY`ap zlcNt_S2z;u39q#9<5^li(5dtd|DHT@;=jk^pXRqSPffiM)e0ATAC7E2Cj~MI{(7u# znU>Ew>0z6r)+lyxv%cYwzG8oBqNNtZJ6EuwI|E8BaCj9lo~=}rPUkK4jB&BFf>46wB1q+N6l`Xv}rv6v^!lE#|z7F zf@UuC)84krCASREs9>WEneO_UrYeh9AtW!CAPDqWQs?zwMj$(zSE!obGbU<_f$zQv zwQXF**JxcQCW-YtmVEQKTS$g=X6w=%8m_ddzP?<_BwldM{}G%j+?N;`li zT|PZv=mKa#Sn*K|O#!%`j7l2WX|LZ>ovcq2F}At_oUSledY49TNSbh}^q z-S`){ZJLBAK0@QhM~pAzQl63z(m9XyVl=LyE-^Ej*~G|9$URmg=%J~L(P^_M3sKw2 zj(nnxCvW3ekp)k>i^G8kQVi0ea*EZ29aZ_7)`5m>qOvp@Yl3#lm;p_C#%o+G1q6rn zl;$2+8u0K7@E=p}lmB?j+kV?LWlglRjkO*u!8Vs6uJQzGDv4|LN>k)grazE-i_c*x zV0_1zbm26ExX5*xiFqd9Hm^T{$K0w6kky?8V?+bQ7osuX>XmKhycXZlt;!L>bDvWQNCJ4NPSG@ey5HJDOV^HtVbg3Iw;Bl6;T#Q}!a8}YuQmc1w=1As8n$N}v3CrVn zFqk|@S4g{2F80{QY12GgWRuYp%xb0+dLzpmvFgM4-o&3>oJ5}LthY_4gxah(sJjdG z0T->TQr37kXrFmF+{L>;tE~q(_vyVAguTJh9iLX4t+jD9ZMN#2{hspW9#dL9cE%l_ zcGy$+>8If!L1sFiAZbE=z1fZNa&Nr7;c$CC1r2d^(*WPc_h#Q5DbSv;HlJt!YgDpI&LgPvmC$M$(Fm zMDg#M3&mMELF8EtO{ukz3jp~*%j|sZ(g8K~$;m%XY!(hIzp`=P%x3WT-+0BQtVp4^ zCC+C!o0_da;2#8(V@!7$yo7*?Q)8k}_?2&ywBr)NI}SC=y(l_-y4-}q(&B24puKIn z3N8WN6*(`0M8rBncRL^Fg;)!YM+(mj>(nJzM8551JUyX}YS2cHk1L5w2%pw_SyrjW z3yGmzHcVcLREi&<m>bu4h5~7oqoX-QV&~kqwFp-GG zV$2rvI`3GMQ}}$C&Adl6v}F`w)46FPnBC{Ck;E_WS2FY%J<{LNe`Fk{PlhE))_EO~ zUp!QD0rcFSoa|%wxlF-sK}`BIg}f zriivz5Y#GQNF-I}zo+lVm9>%KPpxthp}dNAipfh`kx0S6$8QyBsc|;-WTE_`E(Y0$ z@w=2L-BKto11N zd)CG=oh(|_38ab-6Yl&JJ`dwJe)O*)+Y3Hq(+2h-oyDkBOxFJzvMO7-ScJ}+vYOmY-*TPL;)edO*xx;kh zhH~c81bKipw@iloQDf=+9|{NS`&7BZ^ePW46#un65w>*XykN(RU09qxclP$YI@4hV6*&l&SkLhcz`T&t4)Q3khV!0*}gwu|f4_5o^_KmTO z>K(oURm7EV-ld4Y*hN5Y;u;cT@lHarIw5FoA?A8GLOSnSpV{o?y(e?hqF5cDPIb6Wh-P|buVSE2yE^*Eyq2y;3M0&^jqcn z4c~0p|9XJtz1q9CF^!5dSX#QQYQ!f-=_eF>dzaW9S5WT{^(#74UUtnmW0K0pIZTV$ zqyt4x19uH(ciy*SF5Z+hqXrx%;SSFI!hMKPpdzu5<}chAUk2aO@73OsqfIE4i3XNW zzVeTq!rh{1KV0wQ)i8KjvyUaKbn=9z z8sA9zd1Fi7J`Ekc#|`0^3ak(tep}DdTi9T1-35)nr$eK~l{a8ctjG!ia###V0w}wD z9jd!DCMg4)#`84? z6j7XAeuv|jWEN{}6nd2;Q&)v#BH%K%<@yo3S8nI+lpw7DK9Bc{u&el3al7mq)ld+c zmZfC}JIP{Pz4tz`y?;dy3z%*J@Wt$qB$vO z8s4Q&P3x43CuFNF!1zCa1Q4ot;XC8VBmYtqwy$hf7y;H&{T^6K0E#rKUBux zGK$hId5p^V+vQhrQDhDLk>^z<Q#)GmubLiBBsI1rD&>9JkINs;@q82pkLZ&+%gr zvU;`#8ojtrOT~V_kbf7LTiuekYVmw^L0EtvDU}&KYYZ52kr3z0eOyn|yPj^hI=Sdta&8DXc5Q8dY5VTW3m zw&W26(A;o-ee2M4CkvXec1`<8SUbs!;0e-RV4OI81&MnyAl z^$&*#K9U@mTS?7X-9?qtJ?zR`!;Er#qn7=oAmFOBGZ7%eZa%f) z0rwtP4m4XZ5J6fwej@x2LC5pKN>{Y<6JZM8FD7t5UMmS0p!9k2M*ueiT^O5<%~yVi zH$Q96Q@O0YFkg(kNj7yA8}{La!090%YZH2n^ovII5V-E-*vjMY7|Z4oH8b+%V5#C0 z?Utf>3UxG5;RSy$v*@EgTjjB*l6X6lzTBoL!j0t_fD4n#v2Qb;o^SM+d!$~)zkbAU5fI3tlp7&wMz3|`REI~ii53ySq{40e!aFi zp!qgM>_83ihR~8Z0L%^jVQX`zS!_{kX~*LT99IXZC@{iIDntY!6-8f=xWbuV1_XJttJjk>wa^;plud(5QRah|vqVZ!j-SG}GnMpx!M47ktT!$p>4k z6nttNjgdyF$w_7~)Z(*|G3{oJz6#5uvk2e#5vaVjblQQa{zE1Ez+tm^z{_AbUHE&I znn+D0IYpg$dYhT28}ksd`495>ra{`FDd@fo4LsaRR$@J~3g?@WXsVeLWv0ed^=wZj zyT~}v+)euDNKkb?|Iab}X&<{tw5CUI!*LtYx_8P8Lv!`bI?t=ZS#7isXWpV5>Ptz% zl&K0F_3|Z%%Z&>Viis4|Ky$3~#4%!xwWh$N&5}s02UkR+0LlZ1dR}@dpKie196F#W zASfUOS~@TH1}Z-s=Q&)8;&w+#*^oo=jVi!%lzK;JZsLuKlTC*BLZp=7wZB)D^yyg*~nKVvg z{H*j9Osq3c!f9Jzv?eN=IT9XyDB%AC(2v|lAE@*qV3k0Q(bU;lsPurb{QKK)Nq(#% za@vGl6thHdNXpywa>W_hw@2 zH5Q#R6vz#O%BZQaaA$h z0V4V>On9OruM3uMDi;*8C(P3{9xNG)#rm#?UYv7ABw|?{#oTFYbV(VFP=s&ora2Fk zkjdQDZYRhI^hs%Mn@KZJu(>L^*f~lu)*6x0*6HNVeXcSl;%n7Bv6ja5Z_py5B%iBT z%o$=NA6KGKD9rPI@56q$g^kqL_UP)v^e5FpDmTWpXOwU5RcG z54p)&ztiU7}ua1Nnwyz3P8(DIcoyM*&LpE!$UVw8GJrL3mK|Itp6;FdV zL^0bx#tSW&*?~@~Qvg<9jM#>+UtiYSFtA>6sJ}oDbRvdme0Z+K?8rvBwLIdiJijrk zw$c97%>E0R4=h9Qk>X(pnxXsQ5rWV&qmVT-kPwPaJUW4)-MpUDqt^>)P-v$ z%l1QD_MlBk*Gr_&*k^rDKea0f9b;9a?pz`NNj}m#HpyA$w%f9X?AvGfSR~&w%NNU3 zt-ns{6_Cnd?_^O9VwuBxFcg<WrI58 z(4Czl&pddrXiuIXU)|Ytxp^M_di}}pi15J5m_Teh2lej%O7Wks*3*B!2zKmC^h?mQ zU>l2JvPAr)3PizGfuI*?{eNQ&Tyf*~H*$m^bqr?Q_l(uuGfMt82h3+X0U%Nonr`)#g(ui~ zxu1OuVi!ckB(|=Pn)nb?JaZ~M=jBNZ{?vxTi)#OkK-(=p$WwsKyFBc2zC&Od8d83Q zsYJdM=8>yazW6N!>wn{f*QOZ?d42!Uh6Mgpjg&!f)yRrgFvg9K@6=uPXH+0kVFDeriQR^&?qhbsTwH6J{5W3jd>dm^q9W7{-p6@eBz~iOA zj-BVEgagm6o8~lPDUJ8-kSbHa+4LoGIC5{NO?LI>2Xa1LmtcrT?3B}^My{)o=BG#t z30aVc;VKkRdtlL)F|M&n!)+o(M|Ij?YjD%&Q+nYi07|6n8l>|~F!jEqd3J=R+nrU- zD`Owt+&CrchB<8P!JG3zn(lu=6CyuUMVvO4ghz(&FeM~zDbJ!9y6Y1%FNA4xvOjx% z&-K_GXm(Fey~nI)=SP;=^_J@#n>{%qOCx=c91pY+4E3|Iytv6sU9QJ+`4e1x6;{S< z-x>thlE;0YncO{p#oy+hnzpu$yC%cHCA&JpK{rAh<4k+1?N$u5-P=TNTvU7@7K+Ji zNa4hSc_5-yjm8qhL8o-;_<>i5?(Kl{3TsNp`wGN6BVmtpgtT3mIi6R00^X96h@v>z z+fyo&?TkvfXyMLI3>B$(rnhY|zn&T2;g0q8xD7~|o}SQQWGIDX2zhA{8PHaerHl!D z5wqisbGvf|n08vM=6?KmHo&x3larFmM)J0csF-kSZdkCogS*Ru`P1Iu;q2SVirn;B zcXBXN9yt@xIP_dv%A^4PLAVxjz>Rahd_*P;bwC^Ba`eg;lVTIZ*@R~}VTl-mj&)nt zfJsTQ7`E1mW>%6v4QKR$6*b4t<_oG9cJqsZ-Uk32g)3J{2bK=%D0IG=8@;na(>kou zltv;|{aWcQrPGfpW^Hrq1X1zbje{py-Zbx(_9c9h<&fTL>R-=*@$(BH&Q;KrS#O;O_Yj@Wf;^eL7fa#UZ$;-m#ZqfB!2%@aKaFbU#kq z|1mo_1r*)hY&@>>uhBbEvgDx740og1GWuWe3p99T?Aij!m+$X^_%@OTQ>i8-`SOX8<)@L$>saAWB3yJ7#_K%I4#HsUTx2S z=Y-~WdT^j>3L5r7U##kJ&A7JfPe(87&DG!g$O(A_iF?3}gWhs5`;b1yn!3JG zMUGT^L*7v+o!DY-iBzvNc`Km7W!JoE$>E7ci&hZn^kuvwoI^QO9|+eE^_(bh+1_8JgRcFf+cu4I%g_vWbf*azsG z+h#^Nc>v3ET2w3tYq_-72xc-XU|XiQ1CXm58gKnB`Gd5{BvCtSgBvMzz3i@p`dxAs z+e-OUEv>i6vsmH6RU-#qk+lsAo(Cha)1rOiB0idd3I}_4-o!eHHqtVNX}Y$l%x;DX zMN@G-lKO&5HDBYRmS)(HdjUAuCStb~#i<751>?`=|3vVfx|4cVwc0SI?t^J7e3y$( zw5;32CB@m;;1a`?w$hs@Z2bD`HM3uB7Bv2RO5iZz&9SzI9aZs}4zg}34L`R^uCv={ z4{%&+*UUs=Zo8hxJzlNHyd($2A`o{OXZR^1^{I-c_Lss!m*Es;y;L%;A<k8+l)w!A#b{KFCNKeU@P;mxe5^vC5iunVZ4AG3JVZ(83W%^du0LrEgb<6tC2Oz5M2>{+4tVC)ODwWU@NgRyS4pt*sDRQ{jf_xT| zGl`s8ukKbFcCRmPtFg47E(W$v3m=hGsU;)`iB#d5pL@&BV%e=x*wJ#7HrP!2zu(TA zyB$one3uuKtvT7LyR+szV2xh)nIGefI8SaZCSS7yCzL@TK}xR_EP(M15?{SRv{a_| z%))=D5kuw^yk~Ooz?Tm1!>Xs~`uHyn59&d`Zd$!INHTwqUTk~XCP+hujY{x+1#3~C zWwtgIT6-x?4y=VRhtOI$%VA?}ymXSuT~;$hKzhNY3*pwy`uvy1{MXjJ|Yv((TjXsRW(Q$xujIKhHghuIqFsq!G;x&TvIYqtuU4suOUT(|1%-yfrxObzVltI*_;iB&biyo_v7D|dJ4!YC zRM>xL@_9whq(A+Y<7MR3P3nhkchmZ2G$@a_7%Qb98DP#_}Hj}T!A5Bfi)-9T7tp~)tH z7A9fTtrZHN@8D1=iumRgL%o+z@bK{hlB5t7K~P6X1-<}3JX>r@A;vLqM3G4aCy(`# z1NaUkVx_D{<_sp_(VFCwCDOv52rM=6@fDdLw|Xh1lh^BQmXPFbeo%RH{7WeZudvD+*|TL)jWov zm8=lVML1WzTp_YZx3;gQS@*K9iJrgV16Wj6=Wi?B-zs19Iq|WG@Fbv-4cv#{Sz9fG z9ErNgnqyo*^H50ye|{bywS{4JcHlprlgEz&1OGzb55~Jc(RZcFLzTj>{f^RjEg@rI zQ3UUMA_?iXqpBN%4XJ-UjI*0alQnDpfJW#xTo&3jMw70b?W3rjj$6W@(6`s?zc>DD0j z-_RrVe?pH2IP$Rkg*?iS$p1thj+tTS#!3ZWzc1a-V@k-)=@SHv20I+S{-tZIzare~ z%~VRhX}N1&+9nie=#FuVQM~L*(}%+l8NnEjk|rRy_Sy+v>{H+i&^>}i@?qxQ!HqpH z2p%xWHXM`4{|l2`Lc%Z10Re|Ctc}0+-Md`O2#ODa{B==G#Yi@VFAn*OhGdZe$9xO&=Utc;%pw-@7$nLJ8kxym6llAMh=Bzxn|AH1S-9FcM z!B`g)32|1ZJ)Su^9KSIKoO}`evD($5`Q%ZG#j*5*nR6!_7C4Vc0n|+BjRG_;cseX; zk_eA4_E9X}GS+;lZC~94dfHfAz^`CQ#N6~c>UmdZG$cvTq$g~c_r8HQ$5TW`L}pDH z9Y1t2nDyf7zh2i6W4_lfI<~(=ZUET;Z(G!smiN&6#+JhlSGQU>okBtd=YF>j{BG^W z2l^2k?4R9N#e>03*F%>-5o|WyJ4ADvL;W~sqLLw!fblrQzYbx*yn>vHj`EzB7F~w< zO+|O-HYGxd97@nJA;K(Vl576y{CEIuT;yR__cu1a4NX;;y*T8f4I(W9H-jNkXo}Gx z;hOMKZdm~y9%Oz3`sgWn_!68e&>(Nu^2f9qkd~qaQyz0)!o%IEE01DL!1imyhpIPK zgdC3$t;X3x7sXj|hkz;~U#t}kila$uKzx|romK8eBG_F(6FRxJE)rXwmDrel9Xk8r zam?q(f7DDHaN7!MKxe%v>{6Z<<-2fqf6KE^>#MGgdek_bb>ybwx<(P%8Y9^EXccA; zzq#qrdG>T2NJmtoe0fZrycO%auhm2bgD$*Pc?YD{&5|)W8{f#<^byhseI;Qa$0q#E zy6#tsSc6$sPF+cX7yKlo@^@!s6VugH_bcC4D6EO;2RHT{{~Tddj)*U|R1X-FHFzj^m}Ul#y9V)h(Vz zf#&O8GW0pYE$-Pq3w`%-Ovt5JOsUiSYI;O|DhTqrlcc}Z!|{-mYwOLrqVnbX%m9ru z#n_g>v#olwCmU~ivubq?!@U_9EsKcGQ&S%+gbSPtBFFJlEd;=(-m$RJ4JXW{)?o0C z4rye_2GvSr92E(cW?Zg`$eFhFgcn;J@x-g@(G_{psEoLD*Kcf{qrOLfsgixY(cTNdn7B9LqQ2EoCH-n9^iP|Idf+k+P7Y78p=|y6uZGX_Cpy&Y2uT5hM@-1r!4Cjrsr} z|JW9`C+?Z(?961jVVl(;c^`u*G3ud=p`*ckd=^wsAURI-;%v_EOg;S=r()D?D^Mx0 zZ1eLF_lDbbef>A^2sa&(6nb-gPRMes&c~+RrN>S}q7Hoo+X>~QguM&U;2<+o`~;$0 zBa)l`w}%Hu19p1S_N8`q`2}%~^qeVS6wd|4<@9qGysY{`n(wxb0dfac~@aeoy0iPQzq0f)uFc z_#b$O`#90L?zinP**=3+cg#sP*+XXFmB6kUE8|~Fm>}|Y{i$%b>wD|m=rdvd`ueN* zv)nEU7RW}DG2NUH`*qpV&&$B*ujoz=%&i3fY7X*Q4<~-MI zJ`Ye7&#WdnY*a!r{0hi>3+&Om%h;{q-6O&m<1I>jOny&#FNw@5%D>)_zrHq;Py*5H z@-GSG^K`_l?tK8tlGD{nyXv|nMP(m5Y7uFoLEl*&N}1!+nz&4EZbeF@hIU9fW`q?{ z%%5^qkXQK?L6QgqXmNj~S9#=;RVaOi#>7BX&`wcotl@gWXzO;5QFm)H~~fCze04^Lp5)##+5sGHASrB zGbYGJ6u~}Eq%6J<=A<*{U~pAh{#!ewssTu zMtxe8plsL^4f`iTXe8s#(|i*JOyhTZ0fI~lDBOkNPxf8O#)GdsxQgPI zhcoa7LswsE;`WFJvUcZP~m~tm1Paac?2A*z%Wy;=f+j8vs4|)0U2kpHY zJT%p_vHMTa!i8#6bz3%)CHI<$pi(;G@TGcmRKV61wnWlR%RD%oKj=sca*YXwA|_-@ zB>zqlA$r&e{uYb=D`IqKuixD6fi?S{wKON^5vT~kRY5H^Hs8G=C*b-|t>{5S!iBy? z0$Zgmq_eaPlcBcA>dR?uqa;4#?zd;e^u7K63Wy%RGD7GfdAX>@sJTaWB1)JY?zKo;umw(&X9uhN8Bf>U9ycZ8y zOmf_c4{KwDyj=mh4pR+zhc@ZTD>4i24hzLCT$UgmRGFZINFR4%B20jWqzkLVR}>0% znr+MvL5tJC9`HK&NU$WN#->K^U~l3_;>WD2Uw*1b=>PIlc{Yr2I68l#J)}L=Z5VNe zM=8>CGgz3RR)1QhcK>CS(k20bp>U8sIsY%wW6OgB^bcjjBRyx3+39a(!{WE*Ay=gG zYvtdX$J~xNq_i+HBLRhQfHn99T=T%cyhs>)T3ie!R+2+P-$;;vYqj{Bm`s*Z#blZ( zLfmwsk*M2v(nd*989xymR+my#CL%Nh%6MGNWWC9-M;Igfm81Poe23Uzu?7^ zkN_NBbp8uo@VMtRMT$0EsO*c|27CZ&Nc{~-ASD_sZlv%o@R~`uiiV>gNnnO2-(GPF~$SW?1O!u5#H{*Sw^_`zMrbD8JP{h*CO9IwP`SA;piU}~!Y zalGmXH^umcQTj-RrRHEbJu!s0WY)N7g#rDKH1-x-b7xsbo#<*#93#K!^}-&L^XhJu z=%H9e{RzE9sJ|xId;VVBBV*jXtU}N7NMkN|654)f_I9$V{2bMhOcTO*9RDp$>g6K4 z#`YLcv6oQtaAY4NW4xK?7~$}$j8ejnqYmyZiH?(08G#d||8#wUQ`c+CYPNp}$LH~! zs#WQ0lXQHI2QDs9dX#v(3z-YJKTl~{DUV6Zh0Wpl=+B6OCKuh^lir3j;(mtzqfm+9 z6L`r#ZbD<=$Ii6$n&+-GziKZhyKaeU#tDYKid;KY>axrnyM@0s9UZA~4CklkUiv*b ztq!%DeAj4TC4{br0aaSlS}OKltoJCEz_w6MmpMhY)AdP-yYJav5CJww1LW-UO?k;h zlwWtm8h^?vr9d=c4*Ql@HAl)(6c$}lZFC0=%KTC@)+Ike7qKtgGCvwRo6S7S&rr`i}p$2=s!)ye1FSW$*2;e_y-suc10O{!V#wgsAHjZa{s7>iuwGL*Kdy!f< zx{4ZJFrxPoHO&n0#zo>_PD;a!PDz`cKp%Idc?9zy2!UKLPF3VaqDrO}EUCiB)yW%A zu!=-W7xxB0lRav4&~re%h>U0nfHhRfv)#S;wM#_s;BMcz7 zYv*B2IX;Au!_fV`s(-Vp`dKbwshuYR_nZ?c)Hhom3HaWISH6CjbiddXx4%EqHXJcl zC-ZsrmbW+lAN7-QJoUwRIxl@gby{H3d??RgH6Qr<&l^g~u5Uxb4Q<(HDtZRxY@Vr) zPopGOGF`rn&haZk_1LJq$O|;<(|S9<3%^b4v;15L#veg~?ax3;7+sM|p3HFmowC*F zt0wu?tzm#_&DxW9aiXKnDLTnCh6vB+QyyKiSvt5$aMo|s$7o1A-;9Re)_!kCgq#M&oZQ*Q*ESl{^~#1AAbmvzMqpW5?x){r5|rU*m>z_DB0g?w(7aAeSy|a zre|ggP2kL}H?<=_j*+2{pBTJ`+u!WG7i2^?%HlL#)}gW!^*fp)1H=0ag&^U>2`{GA z$n@3R>V|p5Bb}b7ElQJ%<}VH`rzp?}@mql^do83U;X+df%h_Bx-8B*Cv(JAbB+?~P zFj30MN?RLzD|JOqu(~zoapL?Utd444<0}&k!C2^hwb$$oRd9F2$7kG|yooi{XYnah zkiT6JS5mQ0VN9hl@phFeCw4nj*)isZ2h-rKdK4_wI;JlAzN|S74R-{7aKY&F#s-4XoP1Pzhbx&)l*@V z)P4T>>(N$yw&x(LAmmwJlKC$AEc|*Ly3!Pz4!2@Y{&$OLbnH!}S@IjU^d&*$A7`7! z?Vx2T>nvB?7sgeVmnD*_M)L1uKH@~_b-9|b1d|?;fE{$)#(8PSon}aStcw!1 zS^0uLR!>4$7jY-IZYAhToq8Ky*j_2~qUv{54sb1W>Zb2|^1V>m`91O16A7Ra?epGQ zs_49j7QOZpJ&ij!s}?FG#HfRTaSjsAJrymcBRC{z%p~|Ob9QE3rw8}!Dj4BByBNu8 z($rD9v0Q+i8qH0vi`O_+!!`^dKT z$6a>OMybpGp9nk((MHOPj7O{^DQ?ZDcAf$rtUcuUwdMeHDihBym(q+O&D>8K^D~&; z2#092mh1%C*z{>5l568XZcn;(>}e_XcU2G9OqxbbNnMU$B9FX4Y>o#PcjHyx)Us~* zA01s5E-JVx7*}Oz3OHEIpa%9Smkjy72xIne(wX^s+tg#KZ#3cJn3*)3>D4Z&LdU>R zY#PoIP7n=GA?g#uxx43~40uvpJHvRHXg?83e2X`IWlqX|jq|1y!Q0lt_Ft)~FJN#= zSx4CS$EsaFfYZl#XJa4xpeCf*QFYI*fO?K@SUtu6k+*nQp;dciX@2^)5p1q&{Tt-F z;Kvdo7vPX_c2Jtez{KFrh*#fd5fTB!aGbTQprQ5AUxA#x4eb1 zQb?L!WT?mWzO|=3l*+!h#7(~JkLn*2qB-46qHMOjHg9AtlUe*-j#Nx_bD-q<3^=_* zph-4A@}CIN`j$$7xS6@|>9Hp(t(_w|BfV2RK7AQJ>0NGzOMYEMLj3O-jeAPLwK_D( z<6qZtVBSemRj6$1{I&z$thVY$sba$BcY?m9IwwUD*UX#asmB%5Ix%ddq@~p3O8C)J zy@B*7l5_9SNl-DvOq%oT8mH%&0f5#@D@%_?2GdNB1s`Cv;Ut|r=<~AW}WG%t{GkVA%z zn3o4uxQRo+koB7>MT~H`5h^%HKTrk=)%&EYT`68MGM9Zlq+b6;*GsVe6~#jcX*4Yg zgrBg&`*TYA*rTt*({N_Z{&bk zBtR)g#~7%cx_^o_U`i*PRy{EYC4Jswd#J{%3D789Yd9}#mCDLnC!2tk0pTJW6Gfqv zhO_2q#o6Is={f82FrnB(cDhyCQ|^012);mG=UuIilJn9jnriZo5}9b@e7PD*K^Cd1 zqKF0tGB#f_8XG-+@#Zmq@#f@=(Di>>a(?sXmtj#CSsuNIp^=)kq%NqOc(1GFexV%fH7OVBE>2@MoeBbh0PkHaj7q97m1w6r<~|{)vz^ zOGl3PVRVzGk6mHC`C!@YU33EZpY%S`i|TL1mtF-eZBv9%S#5;#UBkYEn>cvRHNS$8 z@Tpelu@*kR7070ed_u$rW_t(A$Ug^)85Lxk)7xJbli3kQ``ubJYfE&C(sp#g*mWmP zbnd-K_fqz}RBp8q+_U*IRVSyG^ZaZJ48y&ot=lT6aAm$81ICOUyqK5#s=i%(kE9Io z(oBslvAU!=*}wTQN9pwTM%RF5;hKV7uyD94WB@g z?)nP;$4>zE4T}|3r$(n(=#C-#Yjy{V$Fb$`4@*;{drZCkA^K*;As-YAvtTg;f5riCUr`q!O2X88%jEFT~R@zAs}N zT~mSCm|^pw%kf0HVI?I6ernm1#{a62_(^!anF9-gOmm_3_=33uv{JEu)yT?MtCppC2B)TEluuATP`4C z3gHvBN2)Idoq-$0a#;8KA<(_b6a|uQKe;10Ucus;dOo;{Oov3%6gL z5nn2lqk~wJpP|R`vbt1PUVIjiJ`YY=!!Dy69S?TB4>??4a7r-H^Ue20S#`;(QB6s? zt+&jg6w(Ze!m_Gs+l@&ex3EzU%DZdMb^wi>EN=JFslo%ecJcK2tq`l^sL}Y%Zg-~> zE$}(z2TjaFueK}$GndV3KECM^1&?knYu)|a&YbK&niFTq9uG3pQ9p`h`D1JLF z+)>uPizr&BmBw*r6$s~!!JERqFOq=rxxd~QoR}xrOI(Zg1?K614MG8z8iS3Qd~i#m ze*yG|e~z#Uj=dP|KYrPl^C)8Vz|lHrn`h(A^8Bf*E4_T-U_R%rjl-$RhSnfXqPlGF za2tv4)IiyFd!;2OZzCA>Ev+-zLQT@vWm{usad%7`-$XBwDF2~Y-t$_!%!by9DkzF; z47l&fg;>MRLR(~Kq{0vkS{Br|P$egPxfwm`&QCVoNnL8MU!eT=Wu$+8f~KhmWOF7; zS>%4x{C#2b$6psVH!)tk64svgGr}RvFaJ$i1!uWQsPKvezBTo+rxYxpZXD+k4Nudr z@ZwUj?{$5-F*wtGa4}!8{9d_*UAGA0G`p4W=`2Bq_1HvwxC!m6ijDQj|D)_JqoQ2< z_F)tiHz`V|bc1w*N`rvJ3^0^*cejdkx3n}2Fm#u6gF`cvba$ukh5L5j`+nAXKm0#& zE*319E06Q|9pOlNPMoyF z-1eTDoXeAi588hNV=$@1>dVydHO&p9$Y=;IuQ_>rK1$0mNm<|w5 zJ0u6D=a4gus4# z;g{yCF~;u2E8{-`YqAr>+=K6T4~p_Uv={Ddi!Iys@Zz<9mi(>7tb!j0cC^Fs8`^t5 zEgxT}bIOwnu_c*QMU@(_^X)tUPeow&x+G_QiB~E;)$CkPyus&-z?O0O+KyMjK;T}y zv^;Q!_8J6sb|||e5%B608W`?4r5N3_YqHt_6P9rEqfaZeU&+|dP4UN;shc#88*&;6 zVr|m&yL{LMThUPCa1G?;g>ulMe&28*CtKP+$5!Qj;q6xAYupe(aW4q3l?Gn&aHF zgklk~h$tkw_LJx zKU&0T5%7@DZ)x&(P5r$#U3mv3XrD(j>RSzmY?AppcLh9bxMz)opU+{nMgQ=G*Px2{ z+d?oKj$$2-L-o@TsC%H0xm?o-A^M_$tJxC^J!)X zwfE`=INi8VHhylc&%4Ai7RfO$WHKJrHgglx4cy@GX{cGMnN@tA-g*>+l@U_3Po~3& z;?j-l5`d~+u;d@Lk5sjb<>2o*)VjE>ggcGWrGK@1R)~7AUE1WSea>}rm?9ufmmlcXI|B{G|D zv8udZYxU1ShUSdHB(wCmXYKYpHM4R0CCu zX8K8Ix<)qhgtef%L+1E0BEB)V_YJJ#Qew#M!E`ZH(7%&8XG#j4J2fI(Z~Kpr)gyt6=5y^T#mFnE%VdJ*xShj(ZX~jJj1Wf^FY;FIp!nFU=wjCAD&wzV51T ztC26)YVw=3c!@YwLLE&HS0SSzdO$cX-@o*z5;0;nMRjAr=0qA$V^I!Td~)D4b(Wes z*B62<=2Xn67Ji7utO&2$UXOVk6=e8uNcL@}rpAIT4OXJcx+VeNC3i7lw8z5~buKmU zhAlbui5au-IWvEI?5WoMUafc`I-_>@C+m!GevY1jy~^-?J4B6n3{~imrgG&)d0Ww= zn&g)!0wQI44USdM+O~oxIN4SB2fyEK%#H`d-N9txfoEQ32AQBk=zOV}N?W(*IzOiN_U=w}WSKX?4wX`&hl?h9{g?s-6q8l$0Nx z0D|kEKf;%3CvLzR3jagpjQt^ZoRv1bohzzu+Wuz5{`m!ovXa&xF1^2yWMlKIxi17T zFGV+%OPd;f=9fmlc=R0^N?_w2PW=7jnjy6GjfO*uHnFgr7#GDSHlgPLGd~_-Q>UcOkgOsG!g$9zdyz&WT7DGV zS2Md^45G|jP~+xmUl-r0*k50Qa`16G%;#lYy)Yk2aZXz=gsb3TaDZA1G0q}YIqmZE z9+VtfFE2({?9`?W2I@~%PfBo>55iv*Qh6Ypp@IjntQw$CAOv+EHq_6#_h&qKj~C2; z;|0~a)NI{*yug}ht{-BMnz+JS#BY)9-Q|QbpVd_$T^(khASNPX5NLdkRJvLsC@$Y$ zSwtxpZn&ldkeS*p)RKX)ywUkhOdC79U0wPRySjfAlgRQx&14}LHdnKi7H4>>?#92dMH6eZ>3EzUb>}9*U1j4YTD9FQmoxUr4o36VSAZL#TTk zYeTv5TBZaG7&1}SM9r3EiaPRjn|HVWMGjY2UMSxrsh zxF}I`a5;$Ximtb^?{+zmD>y1Mx5gQ3ppLX~XF-5J=k9})lEvz2$&-dVKQQpk{?)Ya zLvtP1C^pJhtQSD)&348!&O4nw@EZQYEfsdx4?eG#N)YY@e7*c}N5NO2kbH<5DJC0d zkdd)m(q+xrO+Anz*F*8=o>$@XW<#0gyn5@;kRpobyOVfJp=L)mAnn#X=$0-W2$lU- z&cFoCH=N8(JtUtK#Bx>NXfzYaeP0ghPr{OX$8s^YW7J0e3yE6i@Pa{}v@O0_*xhXU z<#H54u&p3rR=F4bvvk^;khOz?glQU=u6%e1+K5(glV*azRs0n_ZVSPL%1U1~sy|k0 z-NGkjDB5oG5|Y0y^=~4#CE7m>Lm>j>OAMqT1A)Htt(Y9*wU&=D%bJaQ1Ts@qu z$x79Z41JiF>?co&veibY316#&%tlynH?$}(^W&h3kZl)l-Chsl)oylB_C)x&0;SDv zE@4A!LqM?KgxdHlEhku2Mkr-|=V*@v2T@ALvR)<=*KJl}p1^s9M>->YQffk4j{N=? z5~4R*<0o%=-5XfKb?V~E1W0&ik=VV640*mPzsS4`)*RxH*1N<{NUWgg3V7!5j-F~q zdK$CA7RHSR#i;7dfOz3y8$?z%{HY!nAo%!dDTa7g# zVL3#Z+7hctnUP}l)L9;3XXl-1K<2a-vl^NyThhY~sgdpplahdNIY|9Q9|xp!%Y%@C zMgJ72$&q~X=TefOEB!$7CXn0kbL8l#;O$Z#4=-zL)BFQK9{WOrC8>N?4hBNDR>n~O zv}3xkB|%kud^p;Q7#ACBUKLM3 z(Ij5w)xg{3pIw&mGGAX_6m|A7R?oPXLu4#JQ?g;bW2)%|iN4R5P1bIfEx7V~3-UHG z!zbY_V|x`M5DnMRh_ZAK6&1clIoCwI6P0_Skj$TcJwv<&vFJ{@4&qq@=?rf5ta9VZ z8xq?zCZeHA5T&&1Mtv<-vl?R~3JFP>h7}{qaezTFBGAb0(JIat|p(Cox5I zAaskitT74OIWs1cf(N+ryoA>zSLlpuPm)WEvvF-zBjD11ohY<#DLFp!{mM_)i2w}2 zsfIl98wr#VqjTmIJwhj8x4U;$Re5zPV}{&SZFZUkjfVHx^5_BUP+@iF=&3m#$>=b-9npIy= zWmq@FFnvvbHFPK#Fkf@(N*R-3VQS>bYGIGzHi0tV{KT!~MAkY;Kp`zxS=o5)=h^A}RjcFZFAX+)K05k0IZsyoj( zgHG7kimZ5>9cCFe8P>YHHk$qm39ZmJ7QEgDgUZTpmi1AxVLZTo_D?DwDodC*rf;+2 zm1@p^K~S9E?(*F^UJBK`S_~z9U`crCzm79oZB8_yCNmHWOmt71Jl&)4q~tDnuUL8( z!&X)=Xyq`i`)EC5GQlu(VmhsKp(UbNI;SvRJ8>)g4G3Hkx6wS8_M_;u=WxKiu$mQn zRMq(|lvf~kwK>e|GbN)+!T;`!M)hq1GVh4*YFLQo|GV5NZ2~%Ru*iAOp9bb2KZ4K? zDnXOj=<`KItgE#@T0bzMWHxx(ohcM*Kn7ePJtyt8Vj3z~Z{#@5PR~RPss>4t_|J+^ z(U~kVDfR-#7Xn}9&4IA?A4o_KYBAB`vP<>p+1MRz`UI-OE4>ped>%I_ZuvmQ^Xawa1u}sPolGf@n247Z&wh{+|UF)1y+LMGmQHvVo*z@{XQwM+n zN9IdNf9FyB;EQ*4y-bZ$NzPHjrOXz0RQ_50b-|ssNB@r2!5zWgol%3-o~9~j>>L$5rXo#F-1Ol{D7XhCk-M*ATCn-S*-FII zWDtn2YG&-K)@Fc>WxBiUO`VbM2nEmhrjz*fvt*kMFOGD1!skV8IJvQLgVb@VW%KEa ziwg?kqQpp;9p-^H1XX%%BSRdVlKg^54xU3HMT&uZJi5;Dufftw{OuA?F~X5tRyZbH zICoTUAQx@y+AB$XTE~^zlxh2CESgVvs+Lfv3tqDM1J5R_gqKD(>@(9%GWdyE@zO?? zQB4C;U-0VkD6w9Fnm!+Hvt|l9jqipxINGO%CAY*hL6ZtEtE1NOPrTsdK;Rt{bYJ(m zGtec{|42e>S^Fibb@a4REMaxEd38VPaF|uRRrgyT$?DUOK4u@aKj;RabU5X9AkmTsNbc6!r)H8)_*@fb?snefqY4v<*PxB%mL9xC$D|xG8 zX54F6@kZ0iu=_{Xm8hCjd&j@yPU)2dpDVM9`*<~8sd*xYF1KLQ)PlkklbGK%%7G+zKCli{Y}NN_K0xe zPuf&D!Tz&wy&{8U2ipY1Y&ReP)zp6g4?T_e^*c&Rf-mA?Kw6-y{a+}r>>zUfye$x;>4SHey6W-AnD>lgdm**{LTJ)#sXcDSop<+cS7A{v65DpG% z(l3@2knQL7lM?piYXt}(wWmof0=oq$Wc*#H;1tmngIGP*Ez`)1p8R}&tl>JRc?!KfjKOkhyRFg zWunqp(H3>M)YQH_3v98fo@;#f`60>i{BCy56y5oSse|R*EQ76EGn02`lp#N7toUcHlv2Jpa|Q&V!rQNe+Rrd#404X3xwpa! zinhYOwg;#h(TwlHDZH+EGY=&E)W;{`)*L_-NaUX(1u3_!n>=&mw)u8wMZbM#cBK-0 zWvv@_c)UA>cQC;E?RuN4m1u%+g5{;+ghQf(H{aNK z$^PRYI3BM>}vNzh8_1kG!bbRF{nzIF+)-e8shFFf15S$xJt=n_4p=u<@-QJ-I zv2yL}#vPett-u1Sr>?i%vDmKf&f`fwImI?mn;b!G(86GUi%9#K1Ar7Cdh}ROT#SON z$cDvZZMovlgiiY07<73iC}Bz!&Ocl%#UDQl45{MzBEis(5bjWq0L!{_D$4rIGddX9 z?-0-Z#CuVW3o~naMs;#}igWoyl;?^Sfs@&`mF#O&5FYIP8BZ`fv51yur+*0SOa^}( zK3TxsQ@{S6XZ7WHAXyg%@Wf?h^k?)W)y82j=bL$kVL(KLG+_Neb;XWPh7Vjd*_ap* zXK4LJWxDE|VMQFY{sWjm-M>s(<_iCsgIx+RI-t{S8gE5l(zqhD<#~0r+1JV;RMHi@ z)fRr!SCy(Ik#^o1uUulv)T@h-Ei=ZWO9XnQaydTS>4-3bNZti~iYhBIaDGy0_;8%b z6BWHgT8~_f)Z);m>`CRu8o{Yiy(*!0OGe}inxxewo2F68%n=}-q)fpJKo5LG`m>m{9d%~g!Gn0^C_R;Id7hVLi#dx9AIha0 zrXcQS6>M6(N1(qfmYhtk`0NsHMb&5nQ3mdsMJ*<6+p_mspE$oi3fLqZcPR;uK?e%j z;r(k@Z1~#-a*DpUeN8y=i@t>n$6mypV!|)Vej$BQn%0jdM7J*+aGjq-4~`@3(kART z`mmzk#2TV&GjJg;5rzI6?O^!*hiockNzU7|sVq7jJQQ{HmcFLTNFT{syIaJ@K`y*M zz%K!Dq~gnfPk1!iec=J@T;E#&w{q$Q7H(!?M;yl*0vzn@uH!Hqf%RA~qMfb9i%W+& zYxpDp4NJYwL9W&27t)vT++0*13)O+1PqU=!WQ&c(q&l?o2zvWpNI~=i7rZVd+~0tF zlY}NLXC4uj}ql$ch4G2GGKN_`Y= zrVI=AV4s4bhOoNsyQo7U5#Bo3+GzBp#O7j||JGu;GYXbW16HBkb-bsFglMZYi5F>y zEB)2OH;*hS%;S{2FgSCcQ=3-3nq7-9Oq5-iU)a6@1I9SIsmZMdxOe;ZEI3GwKFTD5 z{$zGfqW2L=U=IxM2_Uj_1@7^G#&9`||DenwHXHKu+R8<;qsByRaS2bSPk%OEzsW&D z=YJ5QI;2@G^V-?tZN(&8_ieUN_zYavz$EGVk+|07_&?0u@832n<86ogVEjVTj1RM6 z=k22Zqt#(%a|wt-?jF2tqhxsf`>dj)H9?s=|H_Tq(;L0Q+hcZ8LdcIZk54;`*y&)F;Nzn;fJn-}ZN?v6`L*M>80H2KT?1?FArk zlKsoV7nnQ+b0Os_feh@!ZNMLriN4NLMcRmlK5QoD1+s z+EQtAtU6QW58GVN8Y;@cH~=O>@_dQvj_{Vmi6$u3ui^C z1G-o0Xw{o=c7};82)w!FLT&lLv~7}!tibUX(r6;JXSo2-9dJ(4pW;AWldKu~MFg8{HQJDn@INck+#~;d zj9Jl=AUzNiXAUK_w!mxe=;t}nEF&(FtOqVM^TUI)p_P%h0f+a z*A+ZfCP`EVTTm0h@3&xIrvfR!kdQkfPJ%bBM}j~sT4Nyew7<}(^#-0bSo1O_=P0G+ z%9~gtSz?fUR59o>EP$8jZmzvacpTE8daDR*@Tlq!-3l62Phv>bXAbOq%d!r4A!lX7 z9*`ee>m)!bvFuea16^EMSNDG=0-*lSrCfN@nYC(9+l#TjFLv zJ0yjjvMNkXnWwlMSq!&K6lMOLNZ|j@h2Bf|5`}wBqCNpvhqjDo=&GAYGJTEZ=ZI@f znURiI@QAoK)y4{2m4?{rB=lBoM~)p9iJ>NASs|VF~9~_D>LcC02=q{ zAPk1-KZ`kpnOtg5+MH8Rr%8!;*14!YkFA^RQ^*D0;dHK_fii7ul2bp!$hL8L1wRhl zfqdo=RLf=9T+Gf3M|DlcVGjed`@V!veXE^BDqo|ngQ!n{-9}#X{M8^u=ixCiz06Ij zq~y2B%-Ynp+K&&vTR}rzLJV-LjSWF~(?`B5v?KU&T@ZVfE=f&^(~eDA15UwY?SA$FX7jpslOGA4wKQ&phfD|` zsrBmwTBa_Xuja|`%?EYP)=3EWZrAO}#$~i%AQ$sZCMILY3Tfxs1CozF@j)Qf(>M-Q zRoP49$Zg?${%9~LZBWy*#E2AK;z$r^V^Zgj`Oa)v4(9a1TCB81q$DpiE8b2Mj5#{t zp1#Y?4H}U>jx+@~6SWVNj_?VH(TLX(YGJ7weaCV~Xuhh#Bdo0EdmWv#N6P(%Si9xJ ziXgswd3%?V*3p*IAuHRB@{NE8xzEkhz`WSje?7vT-yD8zZtyBB{>Z6zJ@uSKqVT3*se^kEw8oq*R5`c^2Tw zA*VZ|(O^}=bvya+FJDvbATAZq?Hlqw9aFFGqeTxhv{3H?6X^E+9m@73;iQ@6ttEc| zBWDSJITXfuKr+?-cP3j3$U6#k`yN$%xl?8@kV@U7?i@avv@CFk|xSK|uHFCxHfD z_AEGIYQyj>kpMik0qIB6plxBj0!La=1xuPQ%9Gpm2qao=z>HK6n32q>0L#~XG(vB& z>C(sFkdqGfKUr-h^k#Ch-0Dk>aCjoaj;-j45^4B97A578I4~cK%hBjQiN#LbnK1Bj z{~VKatM)av4YRuFGkw$C_(8M$qVVU$RLiEl*?WXBP0yYaWJa55;=FT=2KEB%+0h}V39qN;o3#=;pk z;1B}uf?1IPkGEaIN>nfADS!k8p1@#@lW!sQ(c!uEdKk>lCxxyiIV2K^L``6w)_wkTU1 zv0=a`X$K7cp3V59QfZuBRshNaw%R*JHZ?Jj7;TO!R_MV5F_ztIan2+cyCPw@I^v9U z*LHy6Sx@wK-LUZ$Z z_To~`+YQAmexV_(grLS{=%HqoPGE=`*zylP{bV^O>fn`Q0<#IaZayXVM4 zR`)EG5@|dPLTx;T-njPo#I(u@9om<_tV%0h z--8hK$7$R3xdoX#?dpm^DlWSap0F{2Hs`UYZ|cwxbw%jtDh{7fSGgb7WXl#{Md6r0=?VS0Uz;q+7rQJwtGMl@GxzC;k)*S;Wx!c`M!vOza(QIU}-Z)P}WE77<s3_x`Ai%F~lP2%ip*mn}%1J7);PlsYC7IXF$P zkrwfR$(k86nZ+!lT zLo}KUiXI8xR(n8Rqa18!Ioqsv#HgjL32I>9cEZcJ1`>qunxqsPx4t|l8?Ox}_~};IXoP%qaVcwMTKvQKplL5b)dEA_TlcKNb0#BsSbnSWK=@g$we1@IT-va%cl{gd zY88=On2BM}l*p0mgN{@{+lioS$0x>_0N`=6RCuvwYD!tdC$m|>@}5HtJ`^eEl*d-= z%2@QUSf8&&9`>H8A3Z0|+>f=KS^|cCAz|fp>@wU)J-$fwe&UO?VLa&1U{FwBmOxzL zZ{yI6DmrJnB&cxLdF*Lm&}*}nkkVCakHV@=l$a?=3bwyyJBp_l1_3N3?$Bv zy+bG2f--`0QQC#9q8W&xXMDya{J3YqW^K8n<2dtN-|eThuC5)lSsGJj=k@|xl0Cf4 zv7%3AfCi~aB#5Lq_E!q=pYYXqw9C3D_+slEk>Odo!SD%`iV9zKv?cvUPiSn{eg0g-LFL0eN z0J}k8$V0$|bp;#SlBvg={riFLvXc>kB``n! zN^nk!$HN+o659(2c6V2B7xhZtFK)Z$WEqcE%V@7lyT$DNEN1~UAl%6G8+zCs!p>dB3x5Srjj0dLe#Y|cE$wOYj((%Z(JSK9iU_Q7ulVqm_VAV6}N)ImJ6Y&1? z!UOUf{v#5DRsClHSboRHqT~;byj(og+OCrqSFZNXO8g$>r<(zU=(B&}vp+a4`2Ppd znFbaPXZ`n2*{%g}0h0}^ay%X3c8h(laX(J+?j}!cyBn9 z+@vxwk|09moGdZucvax1^B(ig$g`*?Bsd2nZBrkDqQn=tqbj+xY9Av$hAcLbE?UwP zZENS^jbWW9O35(XnOGn6${cAGnO|MWX+Jt0A4mUBP8Hz44+i`;auyl?>$lN)52R5+ z4?FF$vN%+xej_dceG!k__5gP?DOu2eK^kACAo}0=Ri|1nQO&ZNNN3qs7qTKCXqK4& zj;Zp1{3oW0@AU7ODnrZrn5y*zjP;sH9wyS3f9y0Yy~V`6OEOD}&p!e+Zae%Yd4Jn% z{{H@wYfMMxWrMyPOAwrA+c7)S@!QvqBY*q{EzH+#FL?rgzfk_wPVA(rA^}3qNaN{! z(YVHEjCv|eSe|%C8kM|f7Moh#YuC^M4vstG6)q7Z5bT`-nlwq@kQF7!`f}EsC^=~^ zxun<0S!{1GgX;<{jDw?t6O)ELs=2corU2gbd%bG8K@y^#(YQGphF{x>-eDpCZ1(Kz z*amYvxvbf*T8*Tq!Tc5kxLaamWr-k9#koqQ&<%iLE%O(NqFk%qtu{)EpMO+hf3w6d zxV4w%*%uqBsAH`>U~06MTqi?>uZ}#!B|mQ#yDY9yd=N zDY6zE*Dk8Us953?YsXn6|nzs^O-)5p>VDVl}T{j!U$3)6Qn-ut5 zQk`jGfi>5E>M@v{vf}B0UWKm|4p6rH6j!*qnh<@pA>C&LjAI-GWypJNs8($JZCOkya55k(bNAu?El5QD5GQ-vn1VkwRR{p zsTlBf!<|X87-#bD#qL)Iq*Uz$BkQD}05M`&tjd<_QceXVdBY_5n|IJ+H+r=3cp0)Vcb9~~Y0&R$Yg=aA z0pD%|CW<$gK#FENLu{gOtwt{+#S-!W-TpJK{N`1Eb@BpcYlAvIHop%^7OD=)U%p)$ zR^B@mD6pUXzi^fK9Tie&4pEC)RYnAL!q2&9oE%$+dZ`mUrmnU42Q8dZegYYv)fOdB zHExD(@R~KU6Q_HQmJvk^i`8;&JK>^%S7srSrJY(whZ`--1g9PxwS?w z_op|)J~>iW<>5gam>hhUNIV3EH!V*hK2Q7X4^UD@s>JU_{6YdzTx$qJ-)CNl-l~S| z8lDxrT`xH+KNj)*v^ReFGLe!+ykhmRToO+>W6-vzs{NJf+vBVTiEfDOYf}?Jhd|>t z56uh1T>5G?%We184NKVc#HsI(EE_)BQ{xGbf}7kFFD}B`2MAt2Qk|GyQ#L-HLH7yI zu{MU`(Kq8R5y(r$3`-?Bg=>H{H+fV4CYS|h=r}8+_(^3fwc1-gF7qCg@#UWxN1fCh z^$hA8E7slY%alT>)zGV5Nb8oyq$4x%#gmc}VTqQWw71%}zSdCZL6+~=aoe|Wm@u_1 zEO>)p7G8dU?6TfX^PG-}tn z8W%zDpIpR`X@qRWd3ks~;=Rr8SvngwpJcpB_*LJ|0GL;_yYWT`5CmGJlU^>bdEmP^AJ@wk0&)}#k>nkslCzAVOJ*$o@z9*oE0Jr zTIt#9rQmN?BeAj!D<1o26cNs}#XOIV6-wI}$_i`HLV5|2SP zVB(f>b>Vs@Qd|z`QwJV=#ZZ}a_NC@9J661fL)>QFJ=O}l{k#&G&%r_!^68x&XM~%#^3A<)cZGkL@cGhQHmy z3EtuNZei>{ZsFf3W?QPBx89&I3o;=iZxOn#q^?$AC>pJx$?!nj#!6l_-b&8inet{qB)Hq($w$1xd%W5`g?RK zpm7d*-#Et)6w#G>PR+CylORbHh@-T?fo^8;2l`rjj?NyA=V*R%44WUU8>1Unh(z}T zaO!3^cFs2U@KOC$MqamF(f|V7Ur3&OCA4OOGUK&d%RknjbY*kQ@SReJVp=h6Y zk3nZ9P(!Nq?iv2*^apQSm6)i=E1TUFKKDM~_Y>oqg?hknL7Gv|)ziKUm`CtF0}G^V zEJ&VS9Bm(O?!Mx4lLzY_aV7)D?BEfWxM?2wVEDoDYEgDHBjPP(8n}W!hu>{b=&~lj z4%M@i`OF;+1DZBtnP((SjWKR$b(UthPZu1%i6#x+d2F(|KAyJt3Mjr8vpE_VU^1&+)HxKtoeHWFy##dpkvbO zln6{gUggQ_+wK=SboJVd=%*^A**h2{_b%-R7Lq3@EpIT9e7_2*F;@Sm;-SxNRjPT` z!srn7E&RQ^u|&eq&Kwl;had-PFa5*K+@jnfg9UjdoI!&*;!qn*3_xL<$I@}{a=J_C ztW*qmwfdSnj|Vg%>5T%^%ZQi+cyA?0)r;5ulgr4KF!Fo@=Uq+WZ|A)-GKv62hm?dOx4i05ZJlPW6CaakEx?veS{Q6|T#Ni59pL4;!HjO}eEa))~1 zBi#cd6}`qE^|V5(I6DGxnNuykGm;4Xxs6E~&;{OB&x&Wvbgs{3lI8LE?U}vp^|?LO z1aAXP%QFNcOM-y$nDWqUO1JIGo1an-8;!zjt0XZyo#M@Ab*55_(X&0NO)Rvx77(b& zh!arkIVzt8gR$kP)fHiK#!iO zDFc3b)bn>f1-8GCh{;dtlu*w{$+xt0ySi^#Ro`yaiZ*yo%ct%t^yI~(Y>S`2I>W8X zZLT#$d_BHh^G16Y+~?Hg1t`&MIRK$h#YTIB%&({=CNQB7S=0bZo-lgBa1Z9~*Lg0}!f4$kH0nE0Gf&T{u zTUx~n#?9TUBLL1xkU;e7j*hG>6L=s)tH`qyQlZtbX}V>R`)s6@dW1Zg*a48>tAkTX zRJsdkM!pT~PfLv31kHP|a%N}beEVAs5s}oj@@*#l=`Ke9fDW?ddEHS-feymaPKBo^ zL8b$J0WLA&5(F6P`KqR@s-2CbWV-~JLjx>^0rq+j*QpLq17RW-)_!={fW6S&xcJ&J zc}-KKGOerN>Z2L&&)rnO^IBR`=}1DnP!Ul8O2*?5Xh8){Diz9* z@j{&*le7jJUa5OZyd?M3(Mmll+maEGmiYH*e_YS}QYU10dKYzAYm)pd@<`wpl7v@S zn#B$_9`)o?iUH&iL4f;|(pD+kd|cp@kRBF*=^2z?a$ei7{Q}gEwB2aoPGttEgS{C1 zilWq*d{HD}qKLj?oP+q{tQIxs}4723%3P6?9k80^Az_MJBcJBx3Yd+4rT%L%B zE7REQnD7g>&P0UE{-teGR6V3uoE!fazw~Uyo?yi16G(SqW=_e+Ry9SEL(-k7Z+=FK zFUpA(olb!?10E@}y$F7ow?#u-o*UecRI;)d1o4%K!>-%u)$9yYN=|$J~Vlv za_`X`NPXSFq{&iX59^{h7Vgoox&Z;-x`rmV0&lrEnW&DE1}jJ1hv(#eaD`p-JGy>? zsVRak|4K_BB0^U>xUuXHQ~cjM6_5@#;cexd(P?JW zGgC^+DeLdUH|FOzROu`E*_meCkFc^i(0&D!i{ zsPGHPKFk^9v^yTJp2B*QIs$hsAFV-b!=g_dRY%_K9MNQb*cbeq3~{ts1NJe)5n>O{ z8V*z}v^fh{97}t8rkN;BBgKCZmqbqVv(8TFm(&Q@BLwj;8Zm=w?)M|g3j^xLPuNG` znqQA&-j(xk9M1znBJ)Y^9ZWr7K>fk@D}|ewLgl%$86^~Q)?-FaEELp1su0R$Ox!MP zW!cT`WcoI3S3U~@*4AWtlem{-S+~uD91m-+L_ZDOp%AmGDP%Rk#mxo>Ce6M&P1;q# zmFOCmP!rNIjQKuU*VN&c%=Kerv|h$Aoc=3M-5!R8l-m@(d7db}fJe~;n%E{WQ!#uz zMx8JbX=jXe=eU8Bs?60ej76%;2;de0=25hZ=J$g6>Wd)#OKOs?_5n&ZvEXQU7AxbW zM%k_N*}euG)XB4M=tdgyE`-}ain#Ok@uH`g#w2-rdZ@eSq+-9AcZedcA>49e!iJ7{ zqi`w4pgy3+rPvBg>)8@=h1JRDT@mW@oQ(ZeO}8#K5Yxc;M+j%QSzZ=Uwfsr`fVTsB z_rn8+;?D{%G{U%lUrP8+L~%zJj;)q1d4J9~(=v(FwV98~>1UdTZIS5xW~3{*5b&8y zZhLnVXzM<_);YPFuP+4{*NBob>MR? z8K=hQjL=j#d1eH3SdARF0E}yUcTG6FYIk-Ep*r>{qi!&;Xd2ZBja7c_ZAeEcWl?jD zV;L<&XC^qzB_V>_g(h8$idIs+>7c=)E-sOnzgn$$NadH1cjUt&j4xMMT+l64LAa-~ z!=3StJm8cjDQr?UcX!jm-r>#8hpnqtrBH^eNy}>+J2jKXN*%(PM*<5{w_h56A&IT= zW%=`TzaZ-30?O45k#^(!qq?J7zzt1A$4!8 zSg5pPa)6Z9pz{)nrFSw8oofFna!dJ0OicW{r|ow4J=$RqJIyezPVRjIP}TDtBufk8 zdwdR*VH7F{pTnO73Kf34FKWAK?uNsqMP9^4kVQ~*yG=J@h&=fr?@e14k~30uR=d_S zDycW&F}?Xrx`#B;VWAg4?>iwSax9ReK{K>2VNyM8TdT?e#DrS(G7WV_TrYMSHX%Y; zds6(}9wdT{>A%+|%kbiPyOmfawW3w{eK?cI+@+6*#vq@TSv&3}kK&Px(eZcAF{NC#7E(xjk6IS?_>vBVN4DQ@ zZsiKfOcC+j_vRs01wPRz1kU*t`Ec(ckg&80WGIClK9?2_J7mbX#ah2_=a#Q9jCEAz z?T~qS#@kVNi!_^m%eLvMDSlytscHgoFw!RS3?oUF8T*F9nlUn#t0VN$(d}t87t2FN|!>a4+{vl2aRcenO3Ul zT1RSHRSw@*J1#qZCW&_=Yl{X`-~aD9LF zlj%V&XTAGYG&MAmZ_DBV@UfB8j<+6a*w!jT^66kD|4NK~zG$0WrMdn`0Q@^e7C+`B zBZsKbLC1^%ZF475luu6(z`^HdMaQND7oB`xZ%nR4^34QF~F@930O=r7!0&Iv&?ydMlCBwrV=EuY&6e{5P#VHNq|&T;lj~?iOAk^JhE#Kp6F7Qp^hg= z(}Ib(&)-T`ltH$)Ans1Q&)@PltDd@!580EXNZ!;YRnP|FVt*mU#{B$vOpB5kyc}Mn z8iS-C-;CEtMx|wpU(L%`qTb8p|GUhs5M@|xaBw@;oTWZ zH7fgvASEYZI(JjY+Q(9C$pfpa-5?h0dM%cRlk)tSSwTnmvKvRoX&evg4oDhtqL6f) zZgNbs!nZ%bkQ`&)a4872lZ=QKl}NC$-Mz2bfT<6~PolMVR%2*z2xhxYP8_>`b+*}msQwbF~sr|}%Ud9BXf2-vhg_Q(|- zt8EF3xYEk^^Vp0yWo277xJzK9aMB{5YqrcCI?KSuEqDfu*DK6maa@-e)=_C8XSdsb z;YZ)UNd9W$gvgl7Fu+bmSIFGyj-2-)Q^;Qjtk*IuDATGlWAB3BqGUQpD2E7vej)Wf zoF_{=ZTd@}1;l+sxAOl{_SSJxu5H)w7=V%@0@6yi(v6^WO2?4WF?5#*(k0y>Ej4s^ zcX#*D-5~7m0=MpcKhOPpzxVxX&fhrsZG+)|&QyIgrlkRiYah`DLgIYP5`M zOqv_PnOfa#plL)T;#HYkUGW=j)#n+OqkeR!Sx?mWrg*;DJR{0T&f$hX%8QqJUaHEXiOC*ic`{;~xYX!C zcP0i``=Pqj=4I^zyMpL0w^gwbcRCx~Vg&>6+nFo=aD<~j%c*RVJosFW4HCj;|T( z1O!R$S7|_PMwNW zC!SO?_G@A*@+Fn&gveC!>tR9zE!B-%%)0F?kLaw!AhF#`>9{LtmkXpIcC<*9T-RNr z^6A781<7|w$GLaxb}Ch9;HOgm!OOCVDVy2d@Nn0C3*Ued<$vn62WA_8flg)Ll!Z@c zAihca3p6HDKQ0XjJe>XlnY>}zU?<$w413~R_Wa*}0T5;G9Y!COD%3%!Wx{2rXHSPk zf1??`T`^tk4+|4;sY!exH8xIFV$+2~@@VoN6gFv!Wv5n+gXi+axnkHWoTWV?W)9QM zyCM%x49-G#2}vBlSs|2r6;y?FBy9~MGh6RMqzBH)I;*KnsJ4kWsbIQ!u#vbunJetW z2;HjGI}1#2esm^2bf&uu8PtEs--7yo*7@v8Wp0Ae$Y%we!^Ff5^ndrs0GA{>uCmn7 zULK!M+kz{iJH50ySZ&R%ajv~{a+>z6neWyO7Rv`mKYW}s)HUhQKSKI zCM#-|n4+k|$(4)f6lF)w0i0X>29`^Emj+^8|95v>^4Hzx6-n!Kbu6wditjl93%gyf z_r-oKIlP}+>+qNH-zn*`g!s>WUhm!h7gvmR*GkU!NHWg;%6!PHLQoZGLwNqTM4H%WsZx=L9h{ctH}0&!JP@u^wuMVXWMuTpb-hYim882`sZhE4^%zY`K9=U&{JqpmR~@SK4diDdtbFGLpPpI= zSmT&ZGObKP*IpKL8gFfGP{ML^A`3?vTS&vWS8)fKNH3_jda{tooLd>DKe0r>j2>Hz zN2F!voY{^N;>Anm>n$5eR`Z_LG{hC~5D~uJtGVn;lt|jhio9BxWqy!)? zYca7PEF-+^YS(Ch{6Pg%^fN|2Co5&*#P8yGq#)R%X;k4hyH^5m)_x~LUI%5D!_JZxAJaI!OWF{VpN%!PDSWb3?^6KT)z^TRIM{xPKJxr&eL7{1p3X`N# zpV=42MR_HuT=+?3At9w1xd-avSW9-_%UXsN$Aq6O;@c%H)&7v25q-QZXq?&OBguZo zcKDGhD=O7MoVy@O*c`BZ<|VVu#Vyn(SgYz^v+UWKE>LilsJ>2w^qWPMXNu0XDDM!o zSSb7Y8v_#^;#A${z(j|D;O4JxIUa!2#~=VwSA^&8DDQo$%VMi5u0%;36$3K5+cu#`hN=^#F9`7CY)ZR5%a=Os7dsui^@Y<6Use;9zSX<~ zfoNZsNgYlcQGrn9(=0w~03lu~@%u5*y}NV`lNl0O_zJjhrgd7*+nJxRPcrg>5TgM< zt9V`0NqaOYlwObSxJ>-Ex69+n(m;gp-XqJPlNp0%wt_zSlaQ)WA+(5>87QXoi?c@@ zNiKC>Yiv9NmevX4e!T!-d`5V4cQde+m**Ep%1BZa#Ipz75*~9y$a1-?)$~*BA;cet zw}s6D$GU3NPIU;6a%W%>+q7jeY9^UXb=B>Nl>KS=JHC(C8Zk-}M!fx+n+^+Z)V9c3Cq9*0Oxb!$5E?(h965R=%4FREZb>Oy?X>MNNPc+uIS84;OH+{dLw)KBN?cqD9eH;ovX;F$e z5b*DzU{nOADb-!8`61;aymvz8Vpf!!tZ(?zk4sf)3MxeC%BKxR75aCTSN=xYNaNEi zL;0wW%C@;=Q}?-qBgXV<&T+cZ_U9cykA$jOQX1{*420PGy5WG7JPde%qv3xJ*y9;J;Y^c6}W@bB{EO@~O^5U%L@7%YbmEQ2y z#MO+jF7uZ1IA^`$*g{#p*|?$FW1!dMNb@1&@TTIyRFI@7hGO@VjC7M?8z{_?*^>7J ze)-y;Hby^2+OcY6sA%3Wbk5*LF$j8q7~f75fm!avnQI%?ztsr~8sascPuGLu;K#6r zR`?-)Yi0Le^MAuMXI2Jp94l@8+a#`$&q7L1!o~>fwZY)UB1Gf2pQb+G^ij%+)|>pukd_kP6qq(NsH6e{&Q}kI0uxko=JWFb!{=YH=ZX>tBTGAOQ_jb-_PKEe-9 zl7xCY(i)P)doVFZXLB=tB#Bbw{PCAQ^;AL372Z?f;bS&M3#wtql3M2_r+(q#ETz7HIvQ=9sO zV29LJ?x z=)>P2wT3uJgdiVdwq;UDl|=QF+lVENjd^025hBiX*GYiDNwCoM^{Bzv zIiPeFv;18`Nz5ACpD-&~1{`*})(GI#o3&90xWl`;f(Gc1E2$E*gfT>O$;Q76Elf6B z+Xqyj!Eu+#@k>Iobe|QIznr#Jp7nNwiw%R(^(Q2Kn=ETvw3*mey-Xf#ELWi$k2y8W zRzY9>Sz@_QVLYkp`@MW-EZX9$R@JA{52S!C`L7nTAa(~kZ0d_?Ff`vHEakF1E)v>x z%r%RE(bDiLd*@M>Q^zNq>>}N~Bit_A)WrO;7hm^`0O|QmtvSs7MC?yHAS=*WH>g0z zGiE8qT1qQeoA2cR0@xG3;!V3yw1*}kRloBxaN1nV(mpZh{=BMbE*yUS-Pd3H*y3L@ zKVRSf7qT1xxxgQY6@cwl&~rKixWT2iE#w~E*j+2yo(&=RT_-jy-?rKK0#ILO22NnK z*zZ;3A-4+*KO$@)a6N!rNr2ou6OjCvQPT!IoxnL2=#_dM?t7Z4>cZ7PJo>$6NDZ9G zylY)qxMOjksl=6mnKUC~c}MevC3+o+92cTFE=51j$*e4D>LX=`00WB(Nl}N1-79pw z1h(J>amk2b&$mu#Go$DHzX3Ym<$~Q-f^;8qhZ1VJ~&XZHe~@6g?_W z%5FCt(3hH9zJ=~E63vM(T}Z#|(*D7njpScQCc+cpG9ixA!Wc zcs2h9cR2u+x@AA7c<>Tw>9eqm)J{OmP6>f|!joC&F%DLQDxDmIAyrsru#*)zaY|cC zi(%(8)VZA5A^i|dcUs$Lqoc*C^~L<8djUK`-hpxB>!tf#cIIm9=;2E2P#=b9KS7n} zkrtv2kEIz^@wEdW7jMwS?JIq%f-H0`h1bQ7tI~LvtydApKh04rCE$PwFo!dh6zZyB zxDKbY?TKx(@NQ*Z{(0klZwznW^|4_Y^DH~5^himDR(VVWtvDk1&gb?C!9N(`DZ$eS zN)>l0zv?Kh25kxiMLdYbS!Lva^w7hpbcYQEdzrB-VRX3Gjmy@ZG%Y9Lep=UGe>i9G z9O0pz-5HHE#;07NXQlB$%ULO&$_(yoDg&06`HvhY-Di4eUi%$&E>2DY9o_`@M~?Cn ze}QD8-VMx)U*_Z*q9t@Z=M|@jVJJ)^L9<+J}N>OxWSlnJajq+EWif1m^SPC-~CyAT|Q6wWb z_C0`h#2J-q)hv~?nMExry)?-hix8ST#`%&Y%oHWuN|l7(rub9O=X))~-S%yaEy8d?z!e3O<~xc{sh4o#!vQo*kYFIJdfMID|8RpwdiqeS>M@*U zT`LSM=JOT!3xpF5STs~m=>A@fmTW!S`3_J7ul{vX-5E8I_^R~Q&1P>TileB7w!QAV zibtw6pD$EGI|eUT=%nw6CfH|=HCa@tMd!s0o#$&@CzHZNx%!VP1r&W+J$~ORP$5hjgsE~B;Wb{Eur$BpA5Hpi2>2EOgx8wetuv%(4NA=lH`@kN-y@+>Yh6m<_AnAgOIE}n1ohdC+pGYXn&RTaYUDP@+SF{=Aq3+Ql_#JQW;7PJy4UdgB#g*d0HG5 z`esDz5$geW9qG_YzVfgyP9oC5Kq@)EK== zG~8vLLYZS;nOtalZ?b1w!BMR`9ZPPHqEl#((gZMTN9QPUG0#WnB;sFxsSzLGUE^g@ z5U>?VEuo=dHAVp(OD)@O{{l&WO4}suI<9r|r#-7Y=Jv=o+1{eJ4av#*RrBPBwO@CbKC@BSQuuO>Ky;*k$ zF`J~R;v<-h+hqvO+l5f&^w{q)g$pm#9z4{$wdXxc{-^_vVPYkna_=oQztOoS_(0{3LMY+1=&r__bTqhPG{~z#K^DcQ2fV;Gk2#Leq5YlXR0v_sM9Z#N7x=?{^YOeuYqgIxcQ!zR+f7ru*gU0WoVVQ=G!q+;Qy5 zPDkXgTiIx39FsO}e=x~+JIA#jm%&{tBB1Sqq%tEvNrtm;e@~B=qivzh_Tbej1^%P>hHSQ*DumRW%E6KBgD5 zR`I2iXE^}F@&kIZ?DFLEIENc5xL81msI+}z&0 zi`aDPy+sJ|!@7UTZ|Y7uuA;FIivTa5$Y<41w7msZIRod9zW$@Wzty4l2=yh8&WA(9 z&&B42v|b^9R*m&pLV!7=2I1FxcQY9m>tIL>R_E6A`crB`B%^HAon)rEMoVt4Bc#CJ zPfgfFqV<)I=5ufwIJ+-9*so%LE8?Z7TArDm0Oz%fCKu%q>Pjw-2ZKIamp$mGXg%i! zJI8I?B&Wwo25B7=o8Oh&*O3{5Wi69VK#}!UHD4a~tH`3aTpa3qU~c$EL`lZV^Qi(q zk1a+M^U+%q&Ipt&@GVhc(rjdW`hsV$V5ChZLx3j?AWTME2+CFqg`uU}MCvCKT0%by zP9@Od0$=E-31C&0HTs||2Kvg%NvABxgex4va#Vq_$CEq8{WpE>DtwT)ug;Ba^BJ-K zbfihDWn&-$@OP`951}~cM}N@*`=#Rf^$Kj=x8ib?{!fx=gJ;{B!(1LltJ*kP?z1^hr&TJ@`jH-IS;Fv0sbW>=Y*5g?@41M;{6t}%y+ zX+Es+1D0~sk8nBm+Sz1pZa)fp_eS1k*HKIp3Hy3Et2!aJ`hN={sf~|)< zaqKxT#P_5G1i#+8I#*>$ZC45;>&;lWdYjY@?LQOxpxW7P9=dL=%5e+F{~9kt*(mps zIzytj-wW!Cg35yUM(D&SI84vgdz+>hQ+V@^RP$jt9|%Jl$uSZ=7{>l8$fzD_n|K z53@gCc{DF1|McnFb_qxyJ^JaLH9j@~R;qAQdxk|wTik%IEuN9YQH?`GHHSgU6(=&4 ztnYk{9d9uYm@6LY(JGw4`-eT9zBKO5ryDc*vZZTHx>mB^<&+U(8fXIaSb%hOt|yuz zAVD>qAcn~Ug+*1}%@=T}!`WPx^o1 z4-@_ue`sqfU~^LVwq8`11KvIQH>dcoz1qYK6iS7a_%G?{_XBwr&2~5%Xe*D4}2)diSIq?%HEFf4RER?y&RgCYLhaOmLzYHzb1bfhC{Q$AwO1?vh(!{1uvj#z0hph-tp?# zx8S9BRyX}QZrl_*PC6-Dr5WLa2b*f*S+jHo6aM35HKReEDO&<)CY>{jh&kJ(*&#){ z!(4)iu)xt8SxyrNI?JnJ!g4-y4)@%6!PNR2n=Ihdbe{*Tf(L&)(uuNqpiw?l9`wV4 zpg?6h65DZ_J2RJVp|W3+$nCfh#9L~cmLq{-ZZpEIFrVXXYa84f-XW8|J9gcF-1xNn zcld084?FYoWe@;+-3v1GTJeB80fE|IU?O}Oh9 zU0SE#D|)z7P8Oi4esBVa4N@o93BYgZLdVAXH>pYQU=ELC;@%^_rG;-2zX8ztZve#m zUjWb?>9DB@e7n$HtO&w6CH!yvW1E~FdyU&v6v_tl6&~F5k7eEgAiMtpfI$Bp7dh>N zw2;gml^_~xk>^J|Qcwf~;;h$QcNyBCMy%PV`Y%QsCBc;NIe8TnVtXILg&*w8o;tZc?rjiv)d$Pr+*X;Zz`G9?Kf(^}?BbsC9S)5tqV z!+o&4zzL66I8<%WiLtoG@TfRhRot{W^W9WK&f(rWD_?mzX;B96Ozf6d^Ai=s1+`Hu zkn-RaKo&2J-@AIY9&Nc;-acL(U0MH4T{G7TroprJ%)h0^5XNRAYW#!tT~Q2-o1kGl zg$+;8HAhlxT7`IZnaOC6D{74N3P^N9@8~+ST4*|b8;Y(gb$_Tn+WN(A*8Czn5$%YC zT(WKj&rTfQRX_2~Bx3u;kp-9=wv{s36bUJw%AnP}NqKUG`s~gGN{A z&lk6dhDM)EKMHiFnZb&_gK89Pt45-RrUqJxv~Lu9*G-v9ytwFKV7AOEcQ% z>h9~Z73Ka|&)P-ua+4sZaUG;)HSoH3_343n4j!aV#rkDCjY$480Zm4c&NQ1ajyxTH z>x7kWAal|J!0og^r_mZP>3X&Isv!N>E$bJsG%T{;`q`jfKUVh#^ciSE zo;f5}&D_4(Q4;aZM~i$c@S(BnyoQDBYKja6ER|MXw$iUt$xi3-23OLsFLH_+mW7Ze z2j$$o^Di zLdQuV-KHM50rQ&BIXyKSnph~?M0!+XO=4tu9a-k_7N>-#f+of!xA^7-AMEumML?ZD zL{d~zs83AQLCc&n25(2bhx2e$qreIc{ltGZhBHU4$kj!22ip`ALr#p;L#h4nIL1m{ zB;6>xA5dj0*WplAtZ@3e>)E{5zcQWNS6u!+*}b6LbE?-iT3jBSu`H4~w)IVw{ooM% zs7iJGVuma;vcS+<0{Jm|4A;X6JVn~ek=y_5aZgf89Dz8ayH8lIe)A@Y!|LIVHn=%*`T_2okK zimjr$+TXoP2`P+v&(7!+{oTOO+n1kZ%duHnU6+3PBmV_5YxXwcf)foc4BsssDaNhL zFg@UuI7MXth^)TAI15$KT4^2ihw3za6hq-`62wy`L3c= zKvBZQ3PSOk(j($re*?L`p}@Fx5NaVl6Dl4D?E5$Wb3rG(I_+K+%(JTt;ul|*pJ<1x z)%6>h=?1xjq|J=a1;Lv>L=#$IOd?q23d`6qM_`oDHY<7QLn$?>p(tmz@3gqxhTDeg z8PUAKhI4qu9QX-Oc*kJLw@D0d)&VbW7MsuUEVmp5zWNMSyT`LjYWBm%W!0N-{L1G^|JA(livs&L@TmIq>dd0gpiBG)$H zY)vl5Nbc^ewh~KG^LoC7kxwRC+*Yr;SZHiS6t$$w$YRp&fXlyGY4zk_v~?rPFHC56 z*V!6Qz-*fPd-izP!t3<#K^}b~lqK_^fZFXMo>x#&q0_838=4nj6DVHwR2K_#KLc7u zNZx=Z8fG>aV|0VMx<;oD47e+5#Q$lbRep|J!0cYSHE~h=X>J%SJo0(t_&8)1Fv`?- z;r{Jab9YdFQ?;<2-_1Eh2yb+Ya)Y|IILhS;JuCyC>Sn{2Ygcdxf3#;i>=UY>uRfbl zRQYs}mk@L(bI)Vl>e^L^v>XvJTK=-1N`MK~Bfo>O5kyV$vbhx6L?6~#h-v=fS<5Qf2@-#Js-&tVFSRY8x$PLYJ}B!%g2gQ$;8(SbCgj7R{;LuKDkP^Fp=s9d|5Yym zGMxD(Tekhh%PRiiWid+c1c8qQ{lL~~6(y>fc1+>ceI1prckTv*$6`%#oMMbp8Kr4R zv@ZKO;Ls~|I0)h?Uyl-%MjIU2)u?{%%D4ddGBkM_H znWp&m0uemdco&ga&>AH*^;>;=j)oFETyCuAbY_y#4j0TawTid2y9R9(`v#@Z%uX0X z?_(^kejRsf^?B6h8kIxQ>#1ED0#)s6rj_{wv5zY#Z5x-Lj7<*eG8@t=sO9tbGV4smScy0*|S;4A8tN{-Q=2g|DP=Y0k%s=AKw@&Ro%P)ZD&4QK+ z65&6~FRoHSHcxzOc@Wo%q^;X3s-P7rR{*7% zkB4(N@Ze4~yQ``TR^#$9Q%*gG%NdjUm2JGdPKbg(h|F`hefmGPC!h!LAfSkRo0<90 zc#4ljL9dEa$qGM?9nEQC37O5OR8Q|nv3Cl}=x%I)(l4ssi5551=scm<@^VZ%o^q0E zYLfuUyI5o;5-o%|ai%y=8>=uOJJ?Ym$3;w3YnQZ`hK+1g7x4_Z-9Fc}_$e=?lAiQ| zbigL$&U{!C34v`^9q=DcsY@!k!ojpXRX8#kle$C$Nj1%~QQ1AYh*X*m`SkTr&J-P( zfG;C#Tjh+k6lrJA7c?vO{Zaxn?fta$5VNv4eCpOI!+8u0y}7RY3s> z?C=E2SM*RMuflR^x&KlLP%0?H8`b23fue}VMpO9m=kw``4D>~gvIGcwFY+f_IRcq!~Xe9Ryg(_Fxw5YGGik3cc2_Gp#SurOODuIZ)DRn~nX%SU}L2SlP1w0);+T#kTIm7g2m{Z1W0R&`~ng{$&)`01^K`5v@J!XWgU zwin)_d00fouY8yrm~~W-a^+>+njV-U*;kWPw63N;>IfWJ?$JL#0iPx_)>dj zs?ctT6e6IiZbuM?2Y35v`$KRZCMrjqtOL>PZPME2k5yeDLv?n7p%Dmlc*{S_ufaUD z7h=YKcJSIq70HDZH>Y?m@Gj~6fRN1Ts?RXJaB34`gKSM@q=Vi*!Ctw_5#~Pdo1XiB zp}+qHg$TMQ%UvQx&uGu!w?)_DVyC}oftmT7_O*ZX5&lQk2+iA-tBT zSt?!c5#z5Nl2`_L*4DH3RULjbK(kb{EgJu|hq{V!SDAJHv|TSaf9T;;`p%t!+;0PM z9`7lpyolOgGL8i8`~`}K7Bwh9C;XKYb1o92R6OSzbA&%sOSGQTT1x9yPe@v3}FMV8B zvZOHgVe@7(zL~R*{`og1kX>STW^*}&W^O;QZsASpkkI<}t@)^FY{}rpIh%fO*Ek=T zCBo($k!oXW*>rTI9XR+}bmD{rh~U6e%-CM0G2UDynksUGounQ~_NDC|DBlyj%{uo6 zI#>+8^8Ky`@v%Ifki2!ET$_13ZRRwft0B&DC1Uqzey&Xv-6>ujrF21$5eAiHOs&xh zD63F8Y^Po#;zb`P*j?D_6Y6~RjsLMZg2&0jF?EYI=)u#ROmop@MOzJSp}#jvrEF-2x25I@5xz02{SU!Bi z#^EwTH{Up_;d3Y8zY|IcTmk>T#X_-R{%JH-H8rOZ#ph>DN$Tqs8mv(}XAD+Og2ugi z=PzU>X+HV0iISAV7wSv9%hgB)t-9q!t0wX{q`1Re)Gw&os{71KJF*4E@zrMG&3M)w zKj!yCxrD9OvA-;sojK)hDPbiNspZ=0=3Aus9@wjXSZZmL%4e4vF&ML9ZWi?!5g)hr zd9YYv5~*n>8D;AXkS)j^9rFxh7bRZZ#KFqA$dIdW$6NHJcq-To?*Dzvi5Enn2Jz+??*s^8010b?@JCtZQ&^P=;j%VLwnATRU>0!E$! zgo+fcm1fC5+oxzK(}arEfD}?iVHbqMe944;0ZZ;RSF<{HIFj!^4OPwRLj*PR;q_j z?pJ!Y5-c8SVg(4go^4A1qZYQ@<#wN!hTG03F@$*%PTQ*C!41PFlikS$xZFyxfps3Rvb!vvW5Z?OO- z4@`Ke-Z}GR=;V33$hw_5i*+bYy7gW}XMG-9yJY}^rtq}{1b8^Njk4)Y$0}uuvtEDu zcB*S`-M*lqEtGp89&BEw@bvSd{IiY=u0H$O49W@x*GM}RoshOSS^7Zi_&N1f4rd%r zFQ$d)<20Da@W{=CSUK6~56`ZxPr<2ZQxbDpT$Lfn5pE6eL-P99t{<{>Zvt2AnP!(t z9X#jrjF+D|E0?}uxX8dZU7)$RT_wP>ZSS)vtwfwQXm5daa`xI=dp8%#Uv!C@U}pov z6uSQhYMQc~qeHP5N!J!)QZ42Kn>JRg`2%is@@!2T%Y_xkD@8y4oRJip(7pVduGV

R8s1e}%=!G&f(kOZz4QiP! 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�bUFYe+UYZDHr`C2WhBVZS9&cy}hZLSWr5 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 literal 0 HcmV?d00001 diff --git a/assets/patterns/zigzags_gloomy.jpg b/assets/patterns/zigzags_gloomy.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c6ccd2a3ea40d5f1bdc5a5592f3cd749b8d55522 GIT binary patch literal 52678 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 get values => [songlinkTransparent, songlink]; } +class $AssetsPatternsGen { + const $AssetsPatternsGen(); + + /// File path: assets/patterns/black_white_visualized.jpg + AssetGenImage get blackWhiteVisualized => + const AssetGenImage('assets/patterns/black_white_visualized.jpg'); + + /// File path: assets/patterns/brazil_carnival.jpg + AssetGenImage get brazilCarnival => + const AssetGenImage('assets/patterns/brazil_carnival.jpg'); + + /// File path: assets/patterns/cotton_balls.jpg + AssetGenImage get cottonBalls => + const AssetGenImage('assets/patterns/cotton_balls.jpg'); + + /// File path: assets/patterns/cute_worms.jpg + AssetGenImage get cuteWorms => + const AssetGenImage('assets/patterns/cute_worms.jpg'); + + /// File path: assets/patterns/flash_cross_axis.jpg + AssetGenImage get flashCrossAxis => + const AssetGenImage('assets/patterns/flash_cross_axis.jpg'); + + /// File path: assets/patterns/memphis_shapes.jpg + AssetGenImage get memphisShapes => + const AssetGenImage('assets/patterns/memphis_shapes.jpg'); + + /// File path: assets/patterns/oval_gloomy.jpg + AssetGenImage get ovalGloomy => + const AssetGenImage('assets/patterns/oval_gloomy.jpg'); + + /// File path: assets/patterns/oval_sunny.jpg + AssetGenImage get ovalSunny => + const AssetGenImage('assets/patterns/oval_sunny.jpg'); + + /// File path: assets/patterns/red_nimbuses.jpg + AssetGenImage get redNimbuses => + const AssetGenImage('assets/patterns/red_nimbuses.jpg'); + + /// File path: assets/patterns/tree_bark.jpg + AssetGenImage get treeBark => + const AssetGenImage('assets/patterns/tree_bark.jpg'); + + /// File path: assets/patterns/vibrant_pentagons.jpg + AssetGenImage get vibrantPentagons => + const AssetGenImage('assets/patterns/vibrant_pentagons.jpg'); + + /// File path: assets/patterns/wiring_pattern.jpg + AssetGenImage get wiringPattern => + const AssetGenImage('assets/patterns/wiring_pattern.jpg'); + + /// File path: assets/patterns/zigzags_gloomy.jpg + AssetGenImage get zigzagsGloomy => + const AssetGenImage('assets/patterns/zigzags_gloomy.jpg'); + + /// File path: assets/patterns/zigzags_sunny.jpg + AssetGenImage get zigzagsSunny => + const AssetGenImage('assets/patterns/zigzags_sunny.jpg'); + + /// List of all assets + List get values => [ + blackWhiteVisualized, + brazilCarnival, + cottonBalls, + cuteWorms, + flashCrossAxis, + memphisShapes, + ovalGloomy, + ovalSunny, + redNimbuses, + treeBark, + vibrantPentagons, + wiringPattern, + zigzagsGloomy, + zigzagsSunny + ]; +} + class $AssetsTutorialGen { const $AssetsTutorialGen(); @@ -67,6 +145,7 @@ class Assets { static const AssetGenImage likedTracks = AssetGenImage('assets/liked-tracks.jpg'); static const $AssetsLogosGen logos = $AssetsLogosGen(); + static const $AssetsPatternsGen patterns = $AssetsPatternsGen(); static const AssetGenImage placeholder = AssetGenImage('assets/placeholder.png'); static const AssetGenImage spotubeHeroBanner = diff --git a/lib/collections/env.dart b/lib/collections/env.dart index eb60851f..eb6c5639 100644 --- a/lib/collections/env.dart +++ b/lib/collections/env.dart @@ -38,6 +38,11 @@ abstract class Env { @EnviedField(varName: "RELEASE_CHANNEL", defaultValue: "nightly") static final String _releaseChannel = _Env._releaseChannel; + @EnviedField(varName: "DISABLE_SPOTIFY_IMAGES", defaultValue: "0") + static final int _disableSpotifyImages = _Env._disableSpotifyImages; + + static bool get disableSpotifyImages => _disableSpotifyImages == 1; + static ReleaseChannel get releaseChannel => _releaseChannel == "stable" ? ReleaseChannel.stable : ReleaseChannel.nightly; diff --git a/lib/components/playbutton_view/playbutton_card.dart b/lib/components/playbutton_view/playbutton_card.dart index 21016d57..05efef38 100644 --- a/lib/components/playbutton_view/playbutton_card.dart +++ b/lib/components/playbutton_view/playbutton_card.dart @@ -11,14 +11,14 @@ class PlaybuttonCard extends StatelessWidget { final void Function()? onAddToQueuePressed; final String? description; - final String imageUrl; + final String? imageUrl; + final Widget? image; final bool isPlaying; final bool isLoading; final String title; final bool isOwner; const PlaybuttonCard({ - required this.imageUrl, required this.isPlaying, required this.isLoading, required this.title, @@ -27,8 +27,13 @@ class PlaybuttonCard extends StatelessWidget { this.onAddToQueuePressed, this.onTap, this.isOwner = false, + this.imageUrl, + this.image, super.key, - }); + }) : assert( + imageUrl != null || image != null, + "imageUrl and image can't be null at the same time", + ); @override Widget build(BuildContext context) { @@ -40,17 +45,27 @@ class PlaybuttonCard extends StatelessWidget { child: CardImage( image: Stack( children: [ - Container( - width: 150 * scale, - height: 150 * scale, - decoration: BoxDecoration( - borderRadius: context.theme.borderRadiusMd, - image: DecorationImage( - image: UniversalImage.imageProvider(imageUrl), - fit: BoxFit.cover, + if (imageUrl != null) + Container( + width: 150 * scale, + height: 150 * scale, + decoration: BoxDecoration( + borderRadius: context.theme.borderRadiusMd, + image: DecorationImage( + image: UniversalImage.imageProvider(imageUrl!), + fit: BoxFit.cover, + ), + ), + ) + else + SizedBox( + width: 150 * scale, + height: 150 * scale, + child: ClipRRect( + borderRadius: context.theme.borderRadiusMd, + child: image!, ), ), - ), StatedWidget.builder( builder: (context, states) { return Positioned( diff --git a/lib/components/playbutton_view/playbutton_tile.dart b/lib/components/playbutton_view/playbutton_tile.dart index 3daaf75c..ec1ca95f 100644 --- a/lib/components/playbutton_view/playbutton_tile.dart +++ b/lib/components/playbutton_view/playbutton_tile.dart @@ -11,14 +11,14 @@ class PlaybuttonTile extends StatelessWidget { final void Function()? onAddToQueuePressed; final String? description; - final String imageUrl; + final String? imageUrl; + final Widget? image; final bool isPlaying; final bool isLoading; final String title; final bool isOwner; const PlaybuttonTile({ - required this.imageUrl, required this.isPlaying, required this.isLoading, required this.title, @@ -27,8 +27,13 @@ class PlaybuttonTile extends StatelessWidget { this.onAddToQueuePressed, this.onTap, this.isOwner = false, + this.imageUrl, + this.image, super.key, - }); + }) : assert( + imageUrl != null || image != null, + "imageUrl and image can't be null at the same time", + ); @override Widget build(BuildContext context) { @@ -36,17 +41,26 @@ class PlaybuttonTile extends StatelessWidget { final scale = context.theme.scaling; return Button( - leading: Container( - width: 50 * scale, - height: 50 * scale, - decoration: BoxDecoration( - borderRadius: context.theme.borderRadiusMd, - image: DecorationImage( - image: UniversalImage.imageProvider(imageUrl), - fit: BoxFit.cover, - ), - ), - ), + leading: imageUrl != null + ? Container( + width: 50 * scale, + height: 50 * scale, + decoration: BoxDecoration( + borderRadius: context.theme.borderRadiusMd, + image: DecorationImage( + image: UniversalImage.imageProvider(imageUrl!), + fit: BoxFit.cover, + ), + ), + ) + : SizedBox( + width: 50 * scale, + height: 50 * scale, + child: ClipRRect( + borderRadius: context.theme.borderRadiusMd, + child: image, + ), + ), style: ButtonVariance.ghost.copyWith( padding: (context, states, value) { return (ButtonVariance.ghost.padding(context, states) as EdgeInsets) diff --git a/lib/components/track_presentation/presentation_top.dart b/lib/components/track_presentation/presentation_top.dart index 59854aaf..8da2f51c 100644 --- a/lib/components/track_presentation/presentation_top.dart +++ b/lib/components/track_presentation/presentation_top.dart @@ -3,6 +3,8 @@ import 'package:flutter/services.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; +import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/env.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/heart_button/heart_button.dart'; import 'package:spotube/components/image/universal_image.dart'; @@ -12,6 +14,7 @@ import 'package:spotube/components/track_presentation/use_is_user_playlist.dart' import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/modules/playlist/playlist_create_dialog.dart'; +import 'package:spotube/provider/spotify/spotify.dart'; class TrackPresentationTopSection extends HookConsumerWidget { const TrackPresentationTopSection({super.key}); @@ -23,6 +26,26 @@ class TrackPresentationTopSection extends HookConsumerWidget { final scale = context.theme.scaling; final isUserPlaylist = useIsUserPlaylist(ref, options.collectionId); + final playlistImage = (options.collection is PlaylistSimple && + (options.collection as PlaylistSimple).owner?.displayName == + "Spotify" && + Env.disableSpotifyImages) + ? ref.watch(playlistImageProvider(options.collectionId)) + : null; + final decorationImage = playlistImage != null + ? DecorationImage( + image: AssetImage(playlistImage.src), + fit: BoxFit.cover, + colorFilter: ColorFilter.mode( + playlistImage.color, + playlistImage.colorBlendMode, + ), + ) + : DecorationImage( + image: UniversalImage.imageProvider(options.image), + fit: BoxFit.cover, + ); + final imageDimension = mediaQuery.mdAndUp ? 200 : 120; final (:isLoading, :isActive, :onPlay, :onShuffle) = @@ -153,10 +176,7 @@ class TrackPresentationTopSection extends HookConsumerWidget { children: [ DecoratedBox( decoration: BoxDecoration( - image: DecorationImage( - image: UniversalImage.imageProvider(options.image), - fit: BoxFit.cover, - ), + image: decorationImage, borderRadius: BorderRadius.circular(45), ), child: OutlinedContainer( @@ -179,11 +199,7 @@ class TrackPresentationTopSection extends HookConsumerWidget { width: imageDimension * scale, decoration: BoxDecoration( borderRadius: context.theme.borderRadiusXl, - image: DecorationImage( - image: - UniversalImage.imageProvider(options.image), - fit: BoxFit.cover, - ), + image: decorationImage, ), ), Flexible( diff --git a/lib/models/spotify/home_feed.dart b/lib/models/spotify/home_feed.dart index e5c2f666..ad764304 100644 --- a/lib/models/spotify/home_feed.dart +++ b/lib/models/spotify/home_feed.dart @@ -29,7 +29,7 @@ class SpotifySectionPlaylist with _$SpotifySectionPlaylist { ..description = description ..collaborative = false ..images = images.map((e) => e.asImage).toList() - ..owner = (User()..displayName = "Spotify") + ..owner = (User()..displayName = owner) ..uri = uri ..type = "playlist"; } diff --git a/lib/modules/home/sections/genres/genre_card_playlist_card.dart b/lib/modules/home/sections/genres/genre_card_playlist_card.dart index bbc42c61..0e2284b3 100644 --- a/lib/modules/home/sections/genres/genre_card_playlist_card.dart +++ b/lib/modules/home/sections/genres/genre_card_playlist_card.dart @@ -1,11 +1,14 @@ import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; -import 'package:spotify/spotify.dart'; +import 'package:spotify/spotify.dart' hide Image; +import 'package:spotube/collections/env.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/extensions/string.dart'; import 'package:spotube/pages/playlist/playlist.dart'; +import 'package:spotube/provider/spotify/spotify.dart'; +import 'package:stroke_text/stroke_text.dart'; class GenreSectionCardPlaylistCard extends HookConsumerWidget { final PlaylistSimple playlist; @@ -58,15 +61,58 @@ class GenreSectionCardPlaylistCard extends HookConsumerWidget { children: [ ClipRRect( borderRadius: theme.borderRadiusSm, - child: UniversalImage( - path: (playlist.images)!.asUrlString( - placeholder: ImagePlaceholder.collection, - index: 1, - ), - fit: BoxFit.cover, - height: 100 * theme.scaling, - width: 100 * theme.scaling, - ), + child: playlist.owner?.displayName == "Spotify" && + Env.disableSpotifyImages + ? Consumer( + builder: (context, ref, _) { + final (:src, :color, :colorBlendMode, :placement) = + ref.watch(playlistImageProvider(playlist.id!)); + return SizedBox( + height: 100 * theme.scaling, + width: 100 * theme.scaling, + child: Stack( + children: [ + Positioned.fill( + child: Image.asset( + src, + color: color, + colorBlendMode: colorBlendMode, + fit: BoxFit.cover, + ), + ), + Positioned.fill( + top: placement == Alignment.topLeft + ? 10 + : null, + left: 10, + bottom: placement == Alignment.bottomLeft + ? 10 + : null, + child: StrokeText( + text: playlist.name!, + strokeColor: Colors.white, + strokeWidth: 3, + textColor: Colors.black, + textStyle: const TextStyle( + fontSize: 16, + fontStyle: FontStyle.italic, + ), + ), + ), + ], + ), + ); + }, + ) + : UniversalImage( + path: (playlist.images)!.asUrlString( + placeholder: ImagePlaceholder.collection, + index: 1, + ), + fit: BoxFit.cover, + height: 100 * theme.scaling, + width: 100 * theme.scaling, + ), ), Text( playlist.name!, diff --git a/lib/modules/playlist/playlist_card.dart b/lib/modules/playlist/playlist_card.dart index 43f2ee4e..c24eb24b 100644 --- a/lib/modules/playlist/playlist_card.dart +++ b/lib/modules/playlist/playlist_card.dart @@ -1,8 +1,10 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; -import 'package:spotify/spotify.dart'; +import 'package:spotify/spotify.dart' hide Offset, Image; +import 'package:spotube/collections/env.dart'; import 'package:spotube/components/dialogs/select_device_dialog.dart'; +import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/components/playbutton_view/playbutton_card.dart'; import 'package:spotube/components/playbutton_view/playbutton_tile.dart'; import 'package:spotube/extensions/context.dart'; @@ -16,6 +18,7 @@ import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:spotube/services/audio_player/audio_player.dart'; import 'package:spotube/utils/service_utils.dart'; +import 'package:stroke_text/stroke_text.dart'; class PlaylistCard extends HookConsumerWidget { final PlaylistSimple playlist; @@ -168,11 +171,52 @@ class PlaylistCard extends HookConsumerWidget { final isOwner = playlist.owner?.id == me.asData?.value.id && me.asData?.value.id != null; + final image = + playlist.owner?.displayName == "Spotify" && Env.disableSpotifyImages + ? Consumer( + builder: (context, ref, child) { + final (:color, :colorBlendMode, :src, :placement) = + ref.watch(playlistImageProvider(playlist.id!)); + + return Stack( + children: [ + Positioned.fill( + child: Image.asset( + src, + color: color, + colorBlendMode: colorBlendMode, + fit: BoxFit.cover, + ), + ), + Positioned.fill( + top: placement == Alignment.topLeft ? 10 : null, + left: 10, + bottom: placement == Alignment.bottomLeft ? 10 : null, + child: StrokeText( + text: playlist.name!, + strokeColor: Colors.white, + strokeWidth: 3, + textColor: Colors.black, + textStyle: const TextStyle( + fontSize: 16, + fontStyle: FontStyle.italic, + ), + ), + ), + ], + ); + }, + ) + : UniversalImage( + path: imageUrl, + fit: BoxFit.cover, + ); + if (_isTile) { return PlaybuttonTile( title: playlist.name!, description: playlist.description, - imageUrl: imageUrl, + image: image, isPlaying: isPlaylistPlaying, isLoading: isLoading, isOwner: isOwner, @@ -185,7 +229,7 @@ class PlaylistCard extends HookConsumerWidget { return PlaybuttonCard( title: playlist.name!, description: playlist.description, - imageUrl: imageUrl, + image: image, isPlaying: isPlaylistPlaying, isLoading: isLoading, isOwner: isOwner, diff --git a/lib/provider/spotify/playlist/playlist.dart b/lib/provider/spotify/playlist/playlist.dart index 0eec3a87..6782fb35 100644 --- a/lib/provider/spotify/playlist/playlist.dart +++ b/lib/provider/spotify/playlist/playlist.dart @@ -104,3 +104,39 @@ final playlistProvider = AsyncNotifierProvider.family( () => PlaylistNotifier(), ); + +final _blendModes = BlendMode.values + .where((e) => switch (e) { + BlendMode.clear || + BlendMode.src || + BlendMode.srcATop || + BlendMode.srcIn || + BlendMode.srcOut || + BlendMode.srcOver || + BlendMode.dstOut || + BlendMode.xor => + false, + _ => true + }) + .toList(); + +typedef PlaylistImageInfo = ({ + Color color, + BlendMode colorBlendMode, + String src, + Alignment placement, +}); + +final playlistImageProvider = Provider.family( + (ref, playlistId) { + final random = Random(); + + return ( + color: Colors.primaries[random.nextInt(Colors.primaries.length)], + colorBlendMode: _blendModes[random.nextInt(_blendModes.length)], + src: Assets + .patterns.values[random.nextInt(Assets.patterns.values.length)].path, + placement: random.nextBool() ? Alignment.topLeft : Alignment.bottomLeft, + ); + }, +); diff --git a/lib/provider/spotify/spotify.dart b/lib/provider/spotify/spotify.dart index dbf3802b..344116cd 100644 --- a/lib/provider/spotify/spotify.dart +++ b/lib/provider/spotify/spotify.dart @@ -1,8 +1,10 @@ library spotify; import 'dart:async'; +import 'dart:math'; import 'package:drift/drift.dart'; +import 'package:spotube/collections/assets.gen.dart'; import 'package:spotube/models/database/database.dart'; import 'package:spotube/provider/authentication/authentication.dart'; import 'package:spotube/provider/database/database.dart'; diff --git a/pubspec.yaml b/pubspec.yaml index 35738548..7cd4cbbd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -172,6 +172,7 @@ flutter: - assets/tutorial/ - assets/logos/ - assets/backgrounds/ + - assets/patterns/ - LICENSE fonts: - family: GeistSans From a8694a7a8bf2bf55903cbb36fe7a3404d80ee35e Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 11 Jan 2025 20:08:04 +0600 Subject: [PATCH 054/112] refactor: blacklist and about page --- lib/modules/home/sections/genres/genres.dart | 1 + lib/pages/settings/about.dart | 108 ++++++++++--------- lib/pages/settings/blacklist.dart | 27 ++--- pubspec.lock | 4 +- pubspec.yaml | 2 +- 5 files changed, 79 insertions(+), 63 deletions(-) diff --git a/lib/modules/home/sections/genres/genres.dart b/lib/modules/home/sections/genres/genres.dart index 5e6fa330..520c1121 100644 --- a/lib/modules/home/sections/genres/genres.dart +++ b/lib/modules/home/sections/genres/genres.dart @@ -55,6 +55,7 @@ class HomeGenresSection extends HookConsumerWidget { return () { timer.cancel(); + controller.dispose(); }; }, []); diff --git a/lib/pages/settings/about.dart b/lib/pages/settings/about.dart index 491cdcf6..79c6692b 100644 --- a/lib/pages/settings/about.dart +++ b/lib/pages/settings/about.dart @@ -1,7 +1,8 @@ -import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/assets.gen.dart'; import 'package:spotube/collections/env.dart'; +import 'package:spotube/components/button/back_button.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/components/links/hyper_link.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; @@ -26,14 +27,16 @@ class AboutSpotube extends HookConsumerWidget { final license = ref.watch(_licenseProvider); final theme = Theme.of(context); - const colon = Text(":"); + const colon = TableCell(child: Text(":")); return Scaffold( - appBar: TitleBar( - leading: const [BackButton()], - title: Text(context.l10n.about_spotube), - ), - body: SingleChildScrollView( + headers: [ + TitleBar( + leading: const [BackButton()], + title: Text(context.l10n.about_spotube), + ) + ], + child: SingleChildScrollView( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), child: Column( @@ -45,76 +48,85 @@ class AboutSpotube extends HookConsumerWidget { Center( child: Column( children: [ - Text( - context.l10n.spotube_description, - style: theme.textTheme.titleLarge, - ), + Text(context.l10n.spotube_description).semiBold().large(), const SizedBox(height: 20), Table( columnWidths: const { - 0: FixedColumnWidth(95), - 1: FixedColumnWidth(10), - 2: IntrinsicColumnWidth(), + 0: FixedTableSize(95), + 1: FixedTableSize(10), + 2: IntrinsicTableSize(), }, - children: [ + defaultRowHeight: const FixedTableSize(40), + rows: [ TableRow( - children: [ - Text(context.l10n.founder), + cells: [ + TableCell(child: Text(context.l10n.founder)), colon, - Hyperlink( - context.l10n.kingkor_roy_tirtho, - "https://github.com/KRTirtho", + TableCell( + child: Hyperlink( + context.l10n.kingkor_roy_tirtho, + "https://github.com/KRTirtho", + ), ) ], ), TableRow( - children: [ - Text(context.l10n.version), + cells: [ + TableCell(child: Text(context.l10n.version)), colon, - Text("v${packageInfo.version}") + TableCell(child: Text("v${packageInfo.version}")) ], ), TableRow( - children: [ - Text(context.l10n.channel), + cells: [ + TableCell(child: Text(context.l10n.channel)), colon, - Text(Env.releaseChannel.name) + TableCell(child: Text(Env.releaseChannel.name)) ], ), TableRow( - children: [ - Text(context.l10n.build_number), + cells: [ + TableCell(child: Text(context.l10n.build_number)), colon, - Text(packageInfo.buildNumber.replaceAll(".", " ")) + TableCell( + child: Text( + packageInfo.buildNumber.replaceAll(".", " ")), + ) ], ), TableRow( - children: [ - Text(context.l10n.repository), + cells: [ + TableCell(child: Text(context.l10n.repository)), colon, - const Hyperlink( - "github.com/KRTirtho/spotube", - "https://github.com/KRTirtho/spotube", + const TableCell( + child: Hyperlink( + "github.com/KRTirtho/spotube", + "https://github.com/KRTirtho/spotube", + ), ), ], ), TableRow( - children: [ - Text(context.l10n.license), + cells: [ + TableCell(child: Text(context.l10n.license)), colon, - const Hyperlink( - "BSD-4-Clause", - "https://raw.githubusercontent.com/KRTirtho/spotube/master/LICENSE", + const TableCell( + child: Hyperlink( + "BSD-4-Clause", + "https://raw.githubusercontent.com/KRTirtho/spotube/master/LICENSE", + ), ), ], ), TableRow( - children: [ - Text(context.l10n.bug_issues), + cells: [ + TableCell(child: Text(context.l10n.bug_issues)), colon, - const Hyperlink( - "github.com/KRTirtho/spotube/issues", - "https://github.com/KRTirtho/spotube/issues", + const TableCell( + child: Hyperlink( + "github.com/KRTirtho/spotube/issues", + "https://github.com/KRTirtho/spotube/issues", + ), ), ], ), @@ -141,12 +153,12 @@ class AboutSpotube extends HookConsumerWidget { Text( context.l10n.made_with, textAlign: TextAlign.center, - style: theme.textTheme.bodySmall, + style: theme.typography.small, ), Text( context.l10n.copyright(DateTime.now().year), textAlign: TextAlign.center, - style: theme.textTheme.bodySmall, + style: theme.typography.small, ), const SizedBox(height: 20), ConstrainedBox( @@ -156,7 +168,7 @@ class AboutSpotube extends HookConsumerWidget { data: (data) { return Text( data, - style: theme.textTheme.bodySmall, + style: theme.typography.small, ); }, loading: () { @@ -167,7 +179,7 @@ class AboutSpotube extends HookConsumerWidget { error: (e, s) { return Text( e.toString(), - style: theme.textTheme.bodySmall, + style: theme.typography.small, ); }, ), diff --git a/lib/pages/settings/blacklist.dart b/lib/pages/settings/blacklist.dart index 57a8b6fe..b525b1b5 100644 --- a/lib/pages/settings/blacklist.dart +++ b/lib/pages/settings/blacklist.dart @@ -1,12 +1,14 @@ -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:collection/collection.dart'; import 'package:fuzzywuzzy/fuzzywuzzy.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/button/back_button.dart'; import 'package:spotube/components/inter_scrollbar/inter_scrollbar.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; +import 'package:spotube/components/ui/button_tile.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/blacklist_provider.dart'; @@ -44,21 +46,21 @@ class BlackListPage extends HookConsumerWidget { ); return Scaffold( - appBar: TitleBar( - title: Text(context.l10n.blacklist), - leading: const [BackButton()], - ), - body: Column( + headers: [ + TitleBar( + title: Text(context.l10n.blacklist), + leading: const [BackButton()], + ) + ], + child: Column( mainAxisSize: MainAxisSize.min, children: [ Padding( padding: const EdgeInsets.all(8.0), child: TextField( onChanged: (value) => searchText.value = value, - decoration: InputDecoration( - hintText: context.l10n.search, - prefixIcon: const Icon(SpotubeIcons.search), - ), + placeholder: Text(context.l10n.search), + leading: const Icon(SpotubeIcons.search), ), ), InterScrollbar( @@ -69,11 +71,12 @@ class BlackListPage extends HookConsumerWidget { itemCount: filteredBlacklist.length, itemBuilder: (context, index) { final item = filteredBlacklist.elementAt(index); - return ListTile( + return ButtonTile( + style: ButtonVariance.ghost, leading: Text("${index + 1}."), title: Text("${item.name} (${item.elementType.name})"), subtitle: Text(item.elementId), - trailing: IconButton( + trailing: IconButton.ghost( icon: Icon(SpotubeIcons.trash, color: Colors.red[400]), onPressed: () { ref diff --git a/pubspec.lock b/pubspec.lock index a43f4f2c..fbcdfd52 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1971,8 +1971,8 @@ packages: dependency: "direct main" description: path: "." - ref: fix-scaffold-footer-safearea - resolved-ref: "8ede34e1e3270ec3839192a7a6453e19cd00f9ab" + ref: d928e73cd734582046c63a3bed99cc42aeab6085 + resolved-ref: d928e73cd734582046c63a3bed99cc42aeab6085 url: "https://github.com/KRTirtho/shadcn_flutter.git" source: git version: "0.0.24" diff --git a/pubspec.yaml b/pubspec.yaml index 7cd4cbbd..7bbf15a1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -105,7 +105,7 @@ dependencies: shadcn_flutter: git: url: https://github.com/KRTirtho/shadcn_flutter.git - ref: fix-scaffold-footer-safearea + ref: d928e73cd734582046c63a3bed99cc42aeab6085 shared_preferences: ^2.2.3 shelf: ^1.4.1 shelf_router: ^1.1.4 From b8ffb9b75f27076060104aedabe0ed15e11bdce0 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 12 Jan 2025 14:16:18 +0600 Subject: [PATCH 055/112] feat: show placeholder images where there is no item or on empty page --- lib/collections/assets.gen.dart | 13 ++ .../fallbacks/anonymous_fallback.dart | 12 +- .../playbutton_view/playbutton_view.dart | 100 +++++++--- .../track_presentation/presentation_list.dart | 27 +++ lib/l10n/app_en.arb | 7 +- lib/modules/getting_started/blur_card.dart | 7 +- lib/modules/home/sections/featured.dart | 17 ++ .../home/sections/genres/genre_card.dart | 29 +-- lib/modules/library/user_albums.dart | 52 +++-- lib/modules/library/user_artists.dart | 107 ++++++---- lib/modules/stats/top/albums.dart | 22 ++- lib/modules/stats/top/artists.dart | 22 ++- lib/modules/stats/top/tracks.dart | 22 ++- lib/pages/album/album.dart | 2 +- .../getting_started/getting_started.dart | 70 +++---- .../getting_started/sections/greeting.dart | 30 +-- .../getting_started/sections/playback.dart | 108 +++++------ .../getting_started/sections/region.dart | 162 +++++++++------- .../getting_started/sections/support.dart | 116 ++++++----- lib/pages/playlist/playlist.dart | 2 +- lib/pages/search/search.dart | 19 +- pubspec.lock | 30 +-- pubspec.yaml | 10 + untranslated_messages.json | 182 +++++++++++++++--- 24 files changed, 765 insertions(+), 403 deletions(-) diff --git a/lib/collections/assets.gen.dart b/lib/collections/assets.gen.dart index 004001f2..98b67c80 100644 --- a/lib/collections/assets.gen.dart +++ b/lib/collections/assets.gen.dart @@ -20,6 +20,17 @@ class $AssetsBackgroundsGen { List get values => [xmasEffect]; } +class $AssetsIllustrationsGen { + const $AssetsIllustrationsGen(); + + /// File path: assets/illustrations/fixing_bugs.png + AssetGenImage get fixingBugs => + const AssetGenImage('assets/illustrations/fixing_bugs.png'); + + /// List of all assets + List get values => [fixingBugs]; +} + class $AssetsLogosGen { const $AssetsLogosGen(); @@ -140,6 +151,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 $AssetsIllustrationsGen illustrations = + $AssetsIllustrationsGen(); static const AssetGenImage invidious = AssetGenImage('assets/invidious.jpg'); static const AssetGenImage jiosaavn = AssetGenImage('assets/jiosaavn.png'); static const AssetGenImage likedTracks = diff --git a/lib/components/fallbacks/anonymous_fallback.dart b/lib/components/fallbacks/anonymous_fallback.dart index cd7a218f..373e0454 100644 --- a/lib/components/fallbacks/anonymous_fallback.dart +++ b/lib/components/fallbacks/anonymous_fallback.dart @@ -1,9 +1,12 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_undraw/flutter_undraw.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/pages/settings/settings.dart'; import 'package:spotube/provider/authentication/authentication.dart'; +import 'package:spotube/utils/platform.dart'; import 'package:spotube/utils/service_utils.dart'; class AnonymousFallback extends ConsumerWidget { @@ -25,9 +28,16 @@ class AnonymousFallback extends ConsumerWidget { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, + spacing: 10, children: [ + Undraw( + illustration: kIsMobile + ? UndrawIllustration.accessDenied + : UndrawIllustration.secureLogin, + height: 200 * context.theme.scaling, + color: context.theme.colorScheme.primary, + ), Text(context.l10n.not_logged_in), - const SizedBox(height: 10), Button.primary( child: Text(context.l10n.login_with_spotify), onPressed: () => ServiceUtils.pushNamed(context, SettingsPage.name), diff --git a/lib/components/playbutton_view/playbutton_view.dart b/lib/components/playbutton_view/playbutton_view.dart index dd8dc371..46e67e25 100644 --- a/lib/components/playbutton_view/playbutton_view.dart +++ b/lib/components/playbutton_view/playbutton_view.dart @@ -1,4 +1,5 @@ import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:flutter_undraw/flutter_undraw.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:skeletonizer/skeletonizer.dart'; @@ -7,6 +8,7 @@ import 'package:spotube/components/playbutton_view/playbutton_card.dart'; import 'package:spotube/components/playbutton_view/playbutton_tile.dart'; import 'package:spotube/components/waypoint.dart'; import 'package:spotube/extensions/constrains.dart'; +import 'package:spotube/extensions/context.dart'; import 'package:very_good_infinite_list/very_good_infinite_list.dart'; const _dummyPlaybuttonCard = PlaybuttonCard( @@ -99,38 +101,59 @@ class PlaybuttonView extends StatelessWidget { const SliverGap(10), // Toggle between grid and list view switch ((isGrid.value, isLoading)) { - (true, _) => SliverGrid.builder( - itemCount: isLoading ? 6 : itemCount + 1, - gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( - maxCrossAxisExtent: 150 * scale, - mainAxisExtent: 225 * scale, - crossAxisSpacing: 12 * scale, - mainAxisSpacing: 12 * scale, - ), - itemBuilder: (context, index) { - if (isLoading) { - return const Skeletonizer( - enabled: true, - child: _dummyPlaybuttonCard, - ); - } - - if (index == itemCount) { - if (!hasMore) return const SizedBox.shrink(); - return Waypoint( - controller: controller, - isGrid: true, - onTouchEdge: onRequestMore, - child: const Skeletonizer( - enabled: true, - child: _dummyPlaybuttonCard, + (true, _) => !isLoading && itemCount == 0 + ? SliverPadding( + padding: const EdgeInsets.symmetric(horizontal: 8), + sliver: SliverToBoxAdapter( + child: Column( + mainAxisSize: MainAxisSize.min, + spacing: 10, + children: [ + Undraw( + height: 200 * context.theme.scaling, + illustration: UndrawIllustration.taken, + color: Theme.of(context).colorScheme.primary, + ), + Text( + context.l10n.nothing_found, + textAlign: TextAlign.center, + ).muted().small() + ], ), - ); - } + ), + ) + : SliverGrid.builder( + itemCount: isLoading ? 6 : itemCount + 1, + gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: 150 * scale, + mainAxisExtent: 225 * scale, + crossAxisSpacing: 12 * scale, + mainAxisSpacing: 12 * scale, + ), + itemBuilder: (context, index) { + if (isLoading) { + return const Skeletonizer( + enabled: true, + child: _dummyPlaybuttonCard, + ); + } - return gridItemBuilder(context, index); - }, - ), + if (index == itemCount) { + if (!hasMore) return const SizedBox.shrink(); + return Waypoint( + controller: controller, + isGrid: true, + onTouchEdge: onRequestMore, + child: const Skeletonizer( + enabled: true, + child: _dummyPlaybuttonCard, + ), + ); + } + + return gridItemBuilder(context, index); + }, + ), (false, true) => Skeletonizer.sliver( enabled: true, child: SliverList( @@ -150,6 +173,23 @@ class PlaybuttonView extends StatelessWidget { onFetchData: onRequestMore, hasReachedMax: !hasMore, isLoading: isLoading, + emptyBuilder: (context) { + return Column( + mainAxisSize: MainAxisSize.min, + spacing: 10, + children: [ + Undraw( + height: 200 * context.theme.scaling, + illustration: UndrawIllustration.taken, + color: Theme.of(context).colorScheme.primary, + ), + Text( + context.l10n.nothing_found, + textAlign: TextAlign.center, + ).muted().small() + ], + ); + }, ), } ], diff --git a/lib/components/track_presentation/presentation_list.dart b/lib/components/track_presentation/presentation_list.dart index 55b4c46d..dda7dffa 100644 --- a/lib/components/track_presentation/presentation_list.dart +++ b/lib/components/track_presentation/presentation_list.dart @@ -1,6 +1,8 @@ import 'package:flutter/services.dart'; +import 'package:flutter_undraw/flutter_undraw.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotube/collections/fake.dart'; import 'package:spotube/components/track_presentation/presentation_props.dart'; @@ -8,6 +10,7 @@ import 'package:spotube/components/track_presentation/presentation_state.dart'; import 'package:spotube/components/track_presentation/use_track_tile_play_callback.dart'; import 'package:spotube/components/track_tile/track_tile.dart'; import 'package:spotube/components/track_presentation/use_is_user_playlist.dart'; +import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:very_good_infinite_list/very_good_infinite_list.dart'; @@ -25,6 +28,30 @@ class PresentationListSection extends HookConsumerWidget { final onTileTap = useTrackTilePlayCallback(ref); + if (state.presentationTracks.isEmpty && !options.pagination.isLoading) { + return SliverToBoxAdapter( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Undraw( + illustration: UndrawIllustration.dreamer, + color: context.theme.colorScheme.primary, + height: 200 * context.theme.scaling, + ), + Text( + isUserPlaylist + ? context.l10n.no_tracks_added_yet + : context.l10n.no_tracks, + textAlign: TextAlign.center, + ).muted().small(), + ], + ), + ), + ); + } + return SliverInfiniteList( isLoading: options.pagination.isLoading, onFetchData: options.pagination.onFetchMore, diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index c95ec54f..9a0f1814 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -409,5 +409,10 @@ "add_all_to_queue": "Add all to queue", "play_all_next": "Play all next", "pause": "Pause", - "view_all": "View all" + "view_all": "View all", + "no_tracks_added_yet": "Looks like you haven't added any tracks yet", + "no_tracks": "Looks like there are no tracks here", + "no_tracks_listened_yet": "Looks like you haven't listened to anything yet", + "not_following_artists": "You're not following any artists", + "no_favorite_albums_yet": "Looks like you haven't added any albums to your favorites yet" } \ No newline at end of file diff --git a/lib/modules/getting_started/blur_card.dart b/lib/modules/getting_started/blur_card.dart index db887013..6434c0a3 100644 --- a/lib/modules/getting_started/blur_card.dart +++ b/lib/modules/getting_started/blur_card.dart @@ -1,7 +1,5 @@ -import 'dart:ui'; - -import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; class BlurCard extends HookConsumerWidget { final Widget child; @@ -18,8 +16,7 @@ class BlurCard extends HookConsumerWidget { clipBehavior: Clip.antiAlias, child: SizedBox( width: double.infinity, - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 20, sigmaY: 20), + child: SurfaceCard( child: Padding( padding: const EdgeInsets.all(16.0), child: child, diff --git a/lib/modules/home/sections/featured.dart b/lib/modules/home/sections/featured.dart index 9ccc8908..a339bd43 100644 --- a/lib/modules/home/sections/featured.dart +++ b/lib/modules/home/sections/featured.dart @@ -1,5 +1,7 @@ +import 'package:flutter_undraw/flutter_undraw.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart'; @@ -15,6 +17,21 @@ class HomeFeaturedSection extends HookConsumerWidget { final featuredPlaylistsNotifier = ref.watch(featuredPlaylistsProvider.notifier); + if (featuredPlaylists.hasError) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Undraw( + illustration: UndrawIllustration.fixingBugs, + height: 200 * context.theme.scaling, + color: context.theme.colorScheme.primary, + ), + Text(context.l10n.something_went_wrong).small().muted(), + const Gap(8), + ], + ); + } + return Skeletonizer( enabled: featuredPlaylists.isLoading, child: HorizontalPlaybuttonCardView( diff --git a/lib/modules/home/sections/genres/genre_card.dart b/lib/modules/home/sections/genres/genre_card.dart index 722e6644..617d7392 100644 --- a/lib/modules/home/sections/genres/genre_card.dart +++ b/lib/modules/home/sections/genres/genre_card.dart @@ -89,23 +89,24 @@ class GenreSectionCard extends HookConsumerWidget { ), ], ), - Expanded( - child: Skeleton.ignore( - child: Skeletonizer( - enabled: playlists?.isLoading ?? false, - child: ListView.separated( - scrollDirection: Axis.horizontal, - itemCount: playlistsData.length, - separatorBuilder: (context, index) => const Gap(12), - itemBuilder: (context, index) { - final playlist = playlistsData.elementAt(index); + if (playlists?.hasError != true) + Expanded( + child: Skeleton.ignore( + child: Skeletonizer( + enabled: playlists?.isLoading ?? false, + child: ListView.separated( + scrollDirection: Axis.horizontal, + itemCount: playlistsData.length, + separatorBuilder: (context, index) => const Gap(12), + itemBuilder: (context, index) { + final playlist = playlistsData.elementAt(index); - return GenreSectionCardPlaylistCard(playlist: playlist); - }, + return GenreSectionCardPlaylistCard(playlist: playlist); + }, + ), ), ), - ), - ) + ) ], ), ), diff --git a/lib/modules/library/user_albums.dart b/lib/modules/library/user_albums.dart index a3f14fba..8d55cf80 100644 --- a/lib/modules/library/user_albums.dart +++ b/lib/modules/library/user_albums.dart @@ -1,9 +1,11 @@ +import 'package:flutter_undraw/flutter_undraw.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart' hide Image; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:collection/collection.dart'; import 'package:fuzzywuzzy/fuzzywuzzy.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/playbutton_view/playbutton_view.dart'; @@ -75,21 +77,45 @@ class UserAlbums extends HookConsumerWidget { ), ), const SliverGap(10), - SliverPadding( - padding: const EdgeInsets.symmetric(horizontal: 8), - sliver: PlaybuttonView( - controller: controller, - itemCount: albums.length, - hasMore: albumsQuery.asData?.value.hasMore == true, - isLoading: albumsQuery.isLoading, - onRequestMore: albumsQueryNotifier.fetchMore, - gridItemBuilder: (context, index) => AlbumCard( - albums[index], + if (albums.isEmpty && + !albumsQuery.isLoading && + searchText.value.isEmpty) + SliverPadding( + padding: const EdgeInsets.symmetric(horizontal: 8), + sliver: SliverToBoxAdapter( + child: Column( + mainAxisSize: MainAxisSize.min, + spacing: 10, + children: [ + Undraw( + height: 200 * context.theme.scaling, + illustration: UndrawIllustration.followMeDrone, + color: Theme.of(context).colorScheme.primary, + ), + Text( + context.l10n.not_following_artists, + textAlign: TextAlign.center, + ).muted().small() + ], + ), + ), + ) + else + SliverPadding( + padding: const EdgeInsets.symmetric(horizontal: 8), + sliver: PlaybuttonView( + controller: controller, + itemCount: albums.length, + hasMore: albumsQuery.asData?.value.hasMore == true, + isLoading: albumsQuery.isLoading, + onRequestMore: albumsQueryNotifier.fetchMore, + gridItemBuilder: (context, index) => AlbumCard( + albums[index], + ), + listItemBuilder: (context, index) => + AlbumCard.tile(albums[index]), ), - listItemBuilder: (context, index) => - AlbumCard.tile(albums[index]), ), - ), const SliverSafeArea(sliver: SliverGap(10)), ], ), diff --git a/lib/modules/library/user_artists.dart b/lib/modules/library/user_artists.dart index 576298ce..fd23f426 100644 --- a/lib/modules/library/user_artists.dart +++ b/lib/modules/library/user_artists.dart @@ -1,9 +1,11 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:collection/collection.dart'; +import 'package:flutter_undraw/flutter_undraw.dart'; import 'package:fuzzywuzzy/fuzzywuzzy.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotube/collections/fake.dart'; @@ -79,45 +81,82 @@ class UserArtists extends HookConsumerWidget { ), ), const SliverGap(10), - SliverLayoutBuilder(builder: (context, constrains) { - return SliverGrid.builder( - itemCount: filteredArtists.isEmpty - ? 6 - : filteredArtists.length + 1, - gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( - maxCrossAxisExtent: 200, - mainAxisExtent: constrains.smAndDown ? 225 : 250, - crossAxisSpacing: 8, - mainAxisSpacing: 8, - ), - itemBuilder: (context, index) { - if (filteredArtists.isNotEmpty && - index == filteredArtists.length) { - if (artistQuery.asData?.value.hasMore != true) { - return const SizedBox.shrink(); + if (filteredArtists.isNotEmpty) + SliverLayoutBuilder(builder: (context, constrains) { + return SliverGrid.builder( + itemCount: filteredArtists.length + 1, + gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: 200, + mainAxisExtent: constrains.smAndDown ? 225 : 250, + crossAxisSpacing: 8, + mainAxisSpacing: 8, + ), + itemBuilder: (context, index) { + if (filteredArtists.isNotEmpty && + index == filteredArtists.length) { + if (artistQuery.asData?.value.hasMore != true) { + return const SizedBox.shrink(); + } + + return Waypoint( + controller: controller, + isGrid: true, + onTouchEdge: artistQueryNotifier.fetchMore, + child: Skeletonizer( + enabled: true, + child: ArtistCard(FakeData.artist), + ), + ); } - return Waypoint( - controller: controller, - isGrid: true, - onTouchEdge: artistQueryNotifier.fetchMore, - child: Skeletonizer( - enabled: true, - child: ArtistCard(FakeData.artist), + return Skeletonizer( + enabled: artistQuery.isLoading, + child: ArtistCard( + filteredArtists.elementAtOrNull(index) ?? + FakeData.artist, ), ); - } - - return Skeletonizer( - enabled: artistQuery.isLoading, - child: ArtistCard( - filteredArtists.elementAtOrNull(index) ?? - FakeData.artist, + }, + ); + }) + else if (filteredArtists.isEmpty && + searchText.value.isEmpty && + !artistQuery.isLoading) + SliverToBoxAdapter( + child: Column( + mainAxisSize: MainAxisSize.min, + spacing: 10, + children: [ + Undraw( + height: 200 * context.theme.scaling, + illustration: UndrawIllustration.followMeDrone, + color: Theme.of(context).colorScheme.primary, ), - ); - }, - ); - }), + Text( + context.l10n.not_following_artists, + textAlign: TextAlign.center, + ).muted().small() + ], + ), + ) + else + SliverToBoxAdapter( + child: Column( + mainAxisSize: MainAxisSize.min, + spacing: 10, + children: [ + Undraw( + height: 200 * context.theme.scaling, + illustration: UndrawIllustration.taken, + color: Theme.of(context).colorScheme.primary, + ), + Text( + context.l10n.nothing_found, + textAlign: TextAlign.center, + ).muted().small() + ], + ), + ), const SliverSafeArea(sliver: SliverGap(10)), ], ), diff --git a/lib/modules/stats/top/albums.dart b/lib/modules/stats/top/albums.dart index e401340e..09bf755c 100644 --- a/lib/modules/stats/top/albums.dart +++ b/lib/modules/stats/top/albums.dart @@ -1,5 +1,7 @@ -import 'package:flutter/material.dart'; +import 'package:flutter_undraw/flutter_undraw.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotube/collections/formatters.dart'; import 'package:spotube/modules/stats/common/album_item.dart'; @@ -31,6 +33,24 @@ class TopAlbums extends HookConsumerWidget { isLoading: topAlbums.isLoading && !topAlbums.isLoadingNextPage, hasReachedMax: topAlbums.asData?.value.hasMore ?? true, itemCount: albumsData.length, + emptyBuilder: (context) => Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Gap(50), + Undraw( + illustration: UndrawIllustration.happyMusic, + color: context.theme.colorScheme.primary, + height: 200 * context.theme.scaling, + ), + Text( + context.l10n.no_tracks_listened_yet, + textAlign: TextAlign.center, + ).muted().small(), + ], + ), + ), itemBuilder: (context, index) { final album = albumsData[index]; return StatsAlbumItem( diff --git a/lib/modules/stats/top/artists.dart b/lib/modules/stats/top/artists.dart index 3e4e098d..c53c34fd 100644 --- a/lib/modules/stats/top/artists.dart +++ b/lib/modules/stats/top/artists.dart @@ -1,6 +1,8 @@ -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:flutter_undraw/flutter_undraw.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotube/collections/formatters.dart'; import 'package:spotube/modules/stats/common/artist_item.dart'; @@ -35,6 +37,24 @@ class TopArtists extends HookConsumerWidget { isLoading: topTracks.isLoading && !topTracks.isLoadingNextPage, hasReachedMax: topTracks.asData?.value.hasMore ?? true, itemCount: artistsData.length, + emptyBuilder: (context) => Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Gap(50), + Undraw( + illustration: UndrawIllustration.happyMusic, + color: context.theme.colorScheme.primary, + height: 200 * context.theme.scaling, + ), + Text( + context.l10n.no_tracks_listened_yet, + textAlign: TextAlign.center, + ).muted().small(), + ], + ), + ), itemBuilder: (context, index) { final artist = artistsData[index]; return StatsArtistItem( diff --git a/lib/modules/stats/top/tracks.dart b/lib/modules/stats/top/tracks.dart index 7fba220d..c4015431 100644 --- a/lib/modules/stats/top/tracks.dart +++ b/lib/modules/stats/top/tracks.dart @@ -1,5 +1,7 @@ -import 'package:flutter/material.dart'; +import 'package:flutter_undraw/flutter_undraw.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotube/collections/formatters.dart'; import 'package:spotube/modules/stats/common/track_item.dart'; @@ -33,6 +35,24 @@ class TopTracks extends HookConsumerWidget { isLoading: topTracks.isLoading && !topTracks.isLoadingNextPage, hasReachedMax: topTracks.asData?.value.hasMore ?? true, itemCount: tracksData.length, + emptyBuilder: (context) => Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Gap(50), + Undraw( + illustration: UndrawIllustration.happyMusic, + color: context.theme.colorScheme.primary, + height: 200 * context.theme.scaling, + ), + Text( + context.l10n.no_tracks_listened_yet, + textAlign: TextAlign.center, + ).muted().small(), + ], + ), + ), itemBuilder: (context, index) { final track = tracksData[index]; return StatsTrackItem( diff --git a/lib/pages/album/album.dart b/lib/pages/album/album.dart index 4a10268b..bc013574 100644 --- a/lib/pages/album/album.dart +++ b/lib/pages/album/album.dart @@ -35,7 +35,7 @@ class AlbumPage extends HookConsumerWidget { tracks: tracks.asData?.value.items ?? [], pagination: PaginationProps( hasNextPage: tracks.asData?.value.hasMore ?? false, - isLoading: tracks.isLoadingNextPage, + isLoading: tracks.isLoading || tracks.isLoadingNextPage, onFetchMore: () async { await tracksNotifier.fetchMore(); }, diff --git a/lib/pages/getting_started/getting_started.dart b/lib/pages/getting_started/getting_started.dart index 6a8141d0..2931a782 100644 --- a/lib/pages/getting_started/getting_started.dart +++ b/lib/pages/getting_started/getting_started.dart @@ -1,6 +1,6 @@ -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/assets.gen.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/extensions/context.dart'; @@ -8,8 +8,6 @@ import 'package:spotube/pages/getting_started/sections/greeting.dart'; import 'package:spotube/pages/getting_started/sections/playback.dart'; import 'package:spotube/pages/getting_started/sections/region.dart'; import 'package:spotube/pages/getting_started/sections/support.dart'; -import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; -import 'package:spotube/themes/theme.dart'; class GettingStarting extends HookConsumerWidget { static const name = "getting_started"; @@ -18,12 +16,6 @@ class GettingStarting extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final preferences = ref.watch(userPreferencesProvider); - final themeData = theme( - preferences.accentColorScheme, - Brightness.dark, - preferences.amoledDarkTheme, - ); final pageController = usePageController(); final onNext = useCallback(() { @@ -40,11 +32,11 @@ class GettingStarting extends HookConsumerWidget { ); }, [pageController]); - return Theme( - data: themeData, - child: Scaffold( - appBar: TitleBar( + return Scaffold( + headers: [ + TitleBar( backgroundColor: Colors.transparent, + surfaceBlur: 0, trailing: [ ListenableBuilder( listenable: pageController, @@ -54,7 +46,7 @@ class GettingStarting extends HookConsumerWidget { child: pageController.hasClients && (pageController.page == 0 || pageController.page == 3) ? const SizedBox() - : TextButton( + : Button.secondary( onPressed: () { pageController.animateToPage( 3, @@ -62,43 +54,33 @@ class GettingStarting extends HookConsumerWidget { curve: Curves.easeInOut, ); }, - child: Text( - context.l10n.skip_this_nonsense, - style: TextStyle( - decoration: TextDecoration.underline, - decorationColor: themeData.colorScheme.primary, - ), - ), + child: Text(context.l10n.skip_this_nonsense), ), ); }, ), ], ), - extendBodyBehindAppBar: true, - body: DecoratedBox( - decoration: BoxDecoration( - image: DecorationImage( - image: Assets.bengaliPatternsBg.provider(), - fit: BoxFit.cover, - colorFilter: const ColorFilter.mode( - Colors.black38, - BlendMode.srcOver, - ), + ], + floatingHeader: true, + child: DecoratedBox( + decoration: BoxDecoration( + image: DecorationImage( + image: Assets.bengaliPatternsBg.provider(), + fit: BoxFit.cover, + ), + ), + child: PageView( + controller: pageController, + children: [ + GettingStartedPageGreetingSection(onNext: onNext), + GettingStartedPageLanguageRegionSection(onNext: onNext), + GettingStartedPagePlaybackSection( + onNext: onNext, + onPrevious: onPrevious, ), - ), - child: PageView( - controller: pageController, - children: [ - GettingStartedPageGreetingSection(onNext: onNext), - GettingStartedPageLanguageRegionSection(onNext: onNext), - GettingStartedPagePlaybackSection( - onNext: onNext, - onPrevious: onPrevious, - ), - const GettingStartedScreenSupportSection(), - ], - ), + const GettingStartedScreenSupportSection(), + ], ), ), ); diff --git a/lib/pages/getting_started/sections/greeting.dart b/lib/pages/getting_started/sections/greeting.dart index 6d649351..4b9c0a89 100644 --- a/lib/pages/getting_started/sections/greeting.dart +++ b/lib/pages/getting_started/sections/greeting.dart @@ -1,10 +1,9 @@ -import 'package:flutter/material.dart'; -import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/assets.gen.dart'; import 'package:spotube/collections/spotube_icons.dart'; -import 'package:spotube/modules/getting_started/blur_card.dart'; import 'package:spotube/extensions/context.dart'; +import 'package:spotube/modules/getting_started/blur_card.dart'; import 'package:spotube/utils/platform.dart'; class GettingStartedPageGreetingSection extends HookConsumerWidget { @@ -13,8 +12,6 @@ class GettingStartedPageGreetingSection extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final ThemeData(:textTheme) = Theme.of(context); - return Center( child: BlurCard( child: Column( @@ -22,30 +19,19 @@ class GettingStartedPageGreetingSection extends HookConsumerWidget { children: [ Assets.spotubeLogoPng.image(height: 200), const Gap(24), - Text( - "Spotube", - style: - textTheme.titleLarge?.copyWith(fontWeight: FontWeight.bold), - ), + const Text("Spotube").semiBold().h4(), const Gap(4), Text( kIsMobile ? context.l10n.freedom_of_music_palm : context.l10n.freedom_of_music, textAlign: TextAlign.center, - style: textTheme.titleMedium?.copyWith( - fontWeight: FontWeight.w300, - fontStyle: FontStyle.italic, - ), - ), + ).light().large().italic(), const Gap(84), - Directionality( - textDirection: TextDirection.rtl, - child: FilledButton.icon( - onPressed: onNext, - icon: const Icon(SpotubeIcons.angleRight), - label: Text(context.l10n.get_started), - ), + Button.primary( + onPressed: onNext, + trailing: const Icon(SpotubeIcons.angleRight), + child: Text(context.l10n.get_started), ), ], ), diff --git a/lib/pages/getting_started/sections/playback.dart b/lib/pages/getting_started/sections/playback.dart index dbf0bda2..bf12d426 100644 --- a/lib/pages/getting_started/sections/playback.dart +++ b/lib/pages/getting_started/sections/playback.dart @@ -1,9 +1,9 @@ -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/assets.gen.dart'; import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/ui/button_tile.dart'; import 'package:spotube/models/database/database.dart'; import 'package:spotube/modules/getting_started/blur_card.dart'; import 'package:spotube/extensions/context.dart'; @@ -14,14 +14,14 @@ final audioSourceToIconMap = { AudioSource.youtube: const Icon( SpotubeIcons.youtube, color: Colors.red, - size: 30, + size: 20, ), - AudioSource.piped: const Icon(SpotubeIcons.piped, size: 30), + AudioSource.piped: const Icon(SpotubeIcons.piped, size: 20), AudioSource.invidious: ClipRRect( - borderRadius: BorderRadius.circular(48), - child: Assets.invidious.image(width: 48, height: 48), + borderRadius: BorderRadius.circular(26), + child: Assets.invidious.image(width: 26, height: 26), ), - AudioSource.jiosaavn: Assets.jiosaavn.image(width: 48, height: 48), + AudioSource.jiosaavn: Assets.jiosaavn.image(width: 20, height: 20), }; class GettingStartedPagePlaybackSection extends HookConsumerWidget { @@ -36,8 +36,6 @@ class GettingStartedPagePlaybackSection extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final ThemeData(:textTheme, :colorScheme, :dividerColor) = - Theme.of(context); final preferences = ref.watch(userPreferencesProvider); final preferencesNotifier = ref.read(userPreferencesProvider.notifier); @@ -62,76 +60,56 @@ class GettingStartedPagePlaybackSection extends HookConsumerWidget { children: [ const Icon(SpotubeIcons.album, size: 16), const Gap(8), - Text(context.l10n.playback, style: textTheme.titleMedium), + Text(context.l10n.playback).semiBold().large(), ], ), const Gap(16), - ListTile( - title: Text( - context.l10n.select_audio_source, - style: textTheme.titleMedium, - ), + Align( + alignment: Alignment.centerLeft, + child: Text(context.l10n.select_audio_source).semiBold().large(), ), const Gap(16), - ToggleButtons( - isSelected: [ - for (final source in AudioSource.values) - preferences.audioSource == source, - ], - onPressed: (index) { - preferencesNotifier.setAudioSource(AudioSource.values[index]); + Select( + value: preferences.audioSource, + onChanged: (value) { + if (value == null) return; + preferencesNotifier.setAudioSource(value); }, - borderRadius: BorderRadius.circular(8), + placeholder: Text(preferences.audioSource.name.capitalize()), + itemBuilder: (context, value) => Row( + mainAxisSize: MainAxisSize.min, + spacing: 6, + children: [ + audioSourceToIconMap[value]!, + Text(value.name.capitalize()), + ], + ), children: [ for (final source in AudioSource.values) - SizedBox.square( - dimension: 84, - child: Column( + SelectItemButton( + value: source, + child: Row( mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, + spacing: 6, children: [ audioSourceToIconMap[source]!, - const Gap(8), - Text( - source.name.capitalize(), - style: textTheme.bodySmall!.copyWith( - color: preferences.audioSource == source - ? colorScheme.primary - : null, - ), - ), + Text(source.name.capitalize()), ], ), ), ], ), - ListTile( - title: Align( - alignment: switch (preferences.audioSource) { - AudioSource.youtube => Alignment.centerLeft, - AudioSource.piped || - AudioSource.invidious => - Alignment.center, - AudioSource.jiosaavn => Alignment.centerRight, - }, - child: Text( - audioSourceToDescription[preferences.audioSource]!, - style: textTheme.bodySmall?.copyWith( - color: dividerColor, - ), - ), - ), - ), const Gap(16), - ListTile( + Text( + audioSourceToDescription[preferences.audioSource]!, + ).small().muted(), + const Gap(16), + ButtonTile( title: Text(context.l10n.endless_playback), subtitle: Text( context.l10n.endless_playback_description, - style: textTheme.bodySmall?.copyWith( - color: dividerColor, - ), - ), - onTap: () { + ).small().muted(), + onPressed: () { preferencesNotifier .setEndlessPlayback(!preferences.endlessPlayback); }, @@ -146,17 +124,17 @@ class GettingStartedPagePlaybackSection extends HookConsumerWidget { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - FilledButton.icon( - icon: const Icon(SpotubeIcons.angleLeft), - label: Text(context.l10n.previous), + Button.secondary( + leading: const Icon(SpotubeIcons.angleLeft), onPressed: onPrevious, + child: Text(context.l10n.previous), ), Directionality( textDirection: TextDirection.rtl, - child: FilledButton.icon( - icon: const Icon(SpotubeIcons.angleRight), - label: Text(context.l10n.next), + child: Button.primary( + leading: const Icon(SpotubeIcons.angleRight), onPressed: onNext, + child: Text(context.l10n.next), ), ), ], diff --git a/lib/pages/getting_started/sections/region.dart b/lib/pages/getting_started/sections/region.dart index 9e31a273..19507fe9 100644 --- a/lib/pages/getting_started/sections/region.dart +++ b/lib/pages/getting_started/sections/region.dart @@ -1,6 +1,6 @@ -import 'package:flutter/material.dart'; -import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:spotify/spotify.dart'; import 'package:spotube/collections/language_codes.dart'; import 'package:spotube/collections/spotify_markets.dart'; import 'package:spotube/collections/spotube_icons.dart'; @@ -16,7 +16,6 @@ class GettingStartedPageLanguageRegionSection extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final ThemeData(:textTheme, :dividerColor) = Theme.of(context); final preferences = ref.watch(userPreferencesProvider); return SafeArea( @@ -32,92 +31,119 @@ class GettingStartedPageLanguageRegionSection extends HookConsumerWidget { size: 16, ), const SizedBox(width: 8), - Text( - context.l10n.language_region, - style: textTheme.titleMedium, - ), + Text(context.l10n.language_region).semiBold(), ], ), - const Gap(48), + const Gap(30), Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ - Text( - context.l10n.choose_your_region, - style: textTheme.titleSmall, - ), + Text(context.l10n.choose_your_region).semiBold(), Text( context.l10n.choose_your_region_description, - style: textTheme.bodySmall?.copyWith( - color: dividerColor, - ), - ), + ).small().muted(), const Gap(16), - DropdownMenu( - initialSelection: preferences.market, - onSelected: (value) { - if (value == null) return; - ref - .read(userPreferencesProvider.notifier) - .setRecommendationMarket(value); - }, - hintText: preferences.market.name, - label: Text(context.l10n.market_place_region), - inputDecorationTheme: - const InputDecorationTheme(isDense: true), - dropdownMenuEntries: [ - for (final market in spotifyMarkets) - DropdownMenuEntry( - value: market.$1, - label: market.$2, - ), - ], + Text(context.l10n.market_place_region).small(), + const Gap(8), + SizedBox( + width: double.infinity, + child: Select( + value: preferences.market, + onChanged: (value) { + if (value == null) return; + ref + .read(userPreferencesProvider.notifier) + .setRecommendationMarket(value); + }, + placeholder: Text(preferences.market.name), + itemBuilder: (context, value) => Text( + spotifyMarkets + .firstWhere((element) => element.$1 == value) + .$2, + ), + searchPlaceholder: Text(context.l10n.search), + searchFilter: (item, query) { + final market = spotifyMarkets + .firstWhere((element) => element.$1 == item) + .$2 + .toLowerCase(); + + return market.contains(query.toLowerCase()) ? 1 : 0; + }, + children: [ + for (final market in spotifyMarkets) + SelectItemButton( + value: market.$1, + child: Text(market.$2), + ), + ], + ), ), const Gap(36), Text( context.l10n.choose_your_language, - style: textTheme.titleSmall, - ), + ).semiBold(), const Gap(16), - DropdownMenu( - initialSelection: preferences.locale, - onSelected: (locale) { - if (locale == null) return; - ref - .read(userPreferencesProvider.notifier) - .setLocale(locale); - }, - hintText: context.l10n.system_default, - label: Text(context.l10n.language), - inputDecorationTheme: - const InputDecorationTheme(isDense: true), - dropdownMenuEntries: [ - DropdownMenuEntry( - value: const Locale("system", "system"), - label: context.l10n.system_default, - ), - for (final locale in L10n.all) - DropdownMenuEntry( - value: locale, - label: LanguageLocals.getDisplayLanguage( - locale.languageCode) - .toString(), + Text(context.l10n.language).small(), + const Gap(8), + SizedBox( + width: double.infinity, + child: Select( + value: preferences.locale, + onChanged: (locale) { + if (locale == null) return; + ref + .read(userPreferencesProvider.notifier) + .setLocale(locale); + }, + placeholder: Text(context.l10n.system_default), + itemBuilder: (context, value) => + value.languageCode == "system" + ? Text(context.l10n.system_default) + : Text( + LanguageLocals.getDisplayLanguage( + value.languageCode) + .toString(), + ), + searchPlaceholder: Text(context.l10n.search), + searchFilter: (locale, query) { + final language = LanguageLocals.getDisplayLanguage( + locale.languageCode) + .toString(); + + return language + .toLowerCase() + .contains(query.toLowerCase()) + ? 1 + : 0; + }, + children: [ + SelectItemButton( + value: const Locale("system", "system"), + child: Text(context.l10n.system_default), ), - ], + for (final locale in L10n.all) + SelectItemButton( + value: locale, + child: Text( + LanguageLocals.getDisplayLanguage( + locale.languageCode) + .toString(), + ), + ), + ], + ), ), ], ), const Gap(48), Align( alignment: Alignment.centerRight, - child: Directionality( - textDirection: TextDirection.rtl, - child: FilledButton.icon( - icon: const Icon(SpotubeIcons.angleRight), - label: Text(context.l10n.next), - onPressed: onNext, - ), + child: Button.primary( + trailing: const Icon(SpotubeIcons.angleRight), + onPressed: onNext, + child: Text(context.l10n.next), ), ), ], diff --git a/lib/pages/getting_started/sections/support.dart b/lib/pages/getting_started/sections/support.dart index f09a585d..640b0b38 100644 --- a/lib/pages/getting_started/sections/support.dart +++ b/lib/pages/getting_started/sections/support.dart @@ -1,7 +1,6 @@ -import 'package:flutter/material.dart'; -import 'package:gap/gap.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/env.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/modules/getting_started/blur_card.dart'; @@ -16,7 +15,6 @@ class GettingStartedScreenSupportSection extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final ThemeData(:textTheme, :colorScheme) = Theme.of(context); final onLogin = useLoginCallback(ref); return Center( @@ -34,9 +32,8 @@ class GettingStartedScreenSupportSection extends HookConsumerWidget { const SizedBox(width: 8), Text( context.l10n.help_project_grow, - style: - textTheme.titleMedium?.copyWith(color: Colors.pink), - ), + style: const TextStyle(color: Colors.pink), + ).semiBold(), ], ), const Gap(16), @@ -46,38 +43,57 @@ class GettingStartedScreenSupportSection extends HookConsumerWidget { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - FilledButton.icon( - icon: const Icon(SpotubeIcons.github), - label: Text(context.l10n.contribute_on_github), - style: FilledButton.styleFrom( - backgroundColor: Colors.black, - foregroundColor: Colors.white, - shape: RoundedRectangleBorder( + Button( + leading: const Icon(SpotubeIcons.github), + style: ButtonVariance.primary.copyWith( + decoration: (context, states, value) { + if (states.isNotEmpty) { + return ButtonVariance.primary + .decoration(context, states); + } + + return BoxDecoration( + color: Colors.black, borderRadius: BorderRadius.circular(8), - ), - ), + ); + }), onPressed: () async { await launchUrlString( "https://github.com/KRTirtho/spotube", mode: LaunchMode.externalApplication, ); }, + child: Text( + context.l10n.contribute_on_github, + style: const TextStyle(color: Colors.white), + ), ), if (!Env.hideDonations) ...[ const Gap(16), - FilledButton.icon( - icon: const Icon(SpotubeIcons.openCollective), - label: Text(context.l10n.donate_on_open_collective), - style: FilledButton.styleFrom( - backgroundColor: const Color(0xff4cb7f6), - foregroundColor: Colors.white, - ), + Button( + leading: const Icon(SpotubeIcons.openCollective), + style: ButtonVariance.primary.copyWith( + decoration: (context, states, value) { + if (states.isNotEmpty) { + return ButtonVariance.primary + .decoration(context, states); + } + + return BoxDecoration( + color: const Color(0xff4cb7f6), + borderRadius: BorderRadius.circular(8), + ); + }), onPressed: () async { await launchUrlString( "https://opencollective.com/spotube", mode: LaunchMode.externalApplication, ); }, + child: Text( + context.l10n.donate_on_open_collective, + style: const TextStyle(color: Colors.white), + ), ), ] ], @@ -91,42 +107,40 @@ class GettingStartedScreenSupportSection extends HookConsumerWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - DecoratedBox( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - gradient: LinearGradient( - colors: [ - colorScheme.primary, - colorScheme.secondary, - ], - ), - ), - child: TextButton.icon( - icon: const Icon(SpotubeIcons.anonymous), - label: Text(context.l10n.browse_anonymously), - style: TextButton.styleFrom( - foregroundColor: Colors.white, - ), - onPressed: () async { - await KVStoreService.setDoneGettingStarted(true); - if (context.mounted) { - context.goNamed(HomePage.name); - } - }, - ), + Button.secondary( + leading: const Icon(SpotubeIcons.anonymous), + onPressed: () async { + await KVStoreService.setDoneGettingStarted(true); + if (context.mounted) { + context.goNamed(HomePage.name); + } + }, + child: Text(context.l10n.browse_anonymously), ), const Gap(16), - FilledButton.icon( - icon: const Icon(SpotubeIcons.spotify), - label: Text(context.l10n.connect_with_spotify), - style: FilledButton.styleFrom( - backgroundColor: const Color(0xff1db954), - foregroundColor: Colors.white, + Button.primary( + leading: const Icon(SpotubeIcons.spotify), + style: ButtonVariance.primary.copyWith( + decoration: (context, states, value) { + if (states.isNotEmpty) { + return ButtonVariance.primary + .decoration(context, states); + } + + return BoxDecoration( + color: const Color(0xff1db954), + borderRadius: BorderRadius.circular(8), + ); + }, ), onPressed: () async { await KVStoreService.setDoneGettingStarted(true); await onLogin(); }, + child: Text( + context.l10n.connect_with_spotify, + style: const TextStyle(color: Colors.white), + ), ), ], ), diff --git a/lib/pages/playlist/playlist.dart b/lib/pages/playlist/playlist.dart index da28c83c..b610b1d4 100644 --- a/lib/pages/playlist/playlist.dart +++ b/lib/pages/playlist/playlist.dart @@ -53,7 +53,7 @@ class PlaylistPage extends HookConsumerWidget { ), pagination: PaginationProps( hasNextPage: tracks.asData?.value.hasMore ?? false, - isLoading: tracks.isLoadingNextPage, + isLoading: tracks.isLoading || tracks.isLoadingNextPage, onFetchMore: tracksNotifier.fetchMore, onRefresh: () async { ref.invalidate(playlistTracksProvider(playlist.id!)); diff --git a/lib/pages/search/search.dart b/lib/pages/search/search.dart index d0f59ce2..efd46ebb 100644 --- a/lib/pages/search/search.dart +++ b/lib/pages/search/search.dart @@ -1,4 +1,5 @@ import 'package:flutter/services.dart'; +import 'package:flutter_undraw/flutter_undraw.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; @@ -159,21 +160,13 @@ class SearchPage extends HookConsumerWidget { SizedBox( height: mediaQuery.height * 0.2, ), - Icon( - SpotubeIcons.web, - size: 120, - color: theme.colorScheme.foreground - .withOpacity(0.7), + Undraw( + illustration: UndrawIllustration.explore, + color: theme.colorScheme.primary, + height: 200 * theme.scaling, ), const SizedBox(height: 20), - Text( - context.l10n.search_to_get_results, - style: theme.typography.h3.copyWith( - fontWeight: FontWeight.w900, - color: theme.colorScheme.foreground - .withOpacity(0.5), - ), - ), + Text(context.l10n.search_to_get_results).large(), ], ), (false, true) => Container( diff --git a/pubspec.lock b/pubspec.lock index fbcdfd52..2666460c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -963,18 +963,26 @@ packages: source: hosted version: "1.1.1" flutter_svg: - dependency: transitive + dependency: "direct overridden" description: name: flutter_svg - sha256: "6ff9fa12892ae074092de2fa6a9938fb21dbabfdaa2ff57dc697ff912fc8d4b2" + sha256: c200fd79c918a40c5cd50ea0877fa13f81bdaf6f0a5d3dbcc2a13e3285d6aa1b url: "https://pub.dev" source: hosted - version: "1.1.6" + version: "2.0.17" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" + flutter_undraw: + dependency: "direct main" + description: + name: flutter_undraw + sha256: "17fe2738231c502171f984c003f6e40979de1a2550ef2debdd29fec27ae006ea" + url: "https://pub.dev" + source: hosted + version: "0.2.0" flutter_web_plugins: dependency: transitive description: flutter @@ -1662,14 +1670,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.1" - path_drawing: - dependency: transitive - description: - name: path_drawing - sha256: bbb1934c0cbb03091af082a6389ca2080345291ef07a5fa6d6e078ba8682f977 - url: "https://pub.dev" - source: hosted - version: "1.0.1" path_parsing: dependency: transitive description: @@ -2525,6 +2525,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.5.1" + vector_graphics: + dependency: transitive + description: + name: vector_graphics + sha256: "27d5fefe86fb9aace4a9f8375b56b3c292b64d8c04510df230f849850d912cb7" + url: "https://pub.dev" + source: hosted + version: "1.1.15" vector_graphics_codec: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 7bbf15a1..657de0c0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -63,6 +63,7 @@ dependencies: flutter_riverpod: ^2.5.1 flutter_secure_storage: ^9.0.0 flutter_sharing_intent: ^1.1.0 + flutter_undraw: ^0.2.0 form_builder_validators: ^11.1.1 form_validator: ^2.1.1 freezed_annotation: ^2.4.1 @@ -163,6 +164,7 @@ dependency_overrides: path: packages/bonsoir_android web: ^1.1.0 meta: 1.16.0 + flutter_svg: ^2.0.17 flutter: generate: true @@ -174,6 +176,14 @@ flutter: - assets/backgrounds/ - assets/patterns/ - LICENSE + - packages/flutter_undraw/assets/undraw/access_denied.svg + - packages/flutter_undraw/assets/undraw/fixing_bugs.svg + - packages/flutter_undraw/assets/undraw/secure_login.svg + - packages/flutter_undraw/assets/undraw/explore.svg + - packages/flutter_undraw/assets/undraw/dreamer.svg + - packages/flutter_undraw/assets/undraw/happy_music.svg + - packages/flutter_undraw/assets/undraw/follow_me_drone.svg + - packages/flutter_undraw/assets/undraw/taken.svg fonts: - family: GeistSans fonts: diff --git a/untranslated_messages.json b/untranslated_messages.json index ddaf9ab0..b00b1fd4 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -9,7 +9,12 @@ "add_all_to_queue", "play_all_next", "pause", - "view_all" + "view_all", + "no_tracks_added_yet", + "no_tracks", + "no_tracks_listened_yet", + "not_following_artists", + "no_favorite_albums_yet" ], "bn": [ @@ -22,7 +27,12 @@ "add_all_to_queue", "play_all_next", "pause", - "view_all" + "view_all", + "no_tracks_added_yet", + "no_tracks", + "no_tracks_listened_yet", + "not_following_artists", + "no_favorite_albums_yet" ], "ca": [ @@ -35,7 +45,12 @@ "add_all_to_queue", "play_all_next", "pause", - "view_all" + "view_all", + "no_tracks_added_yet", + "no_tracks", + "no_tracks_listened_yet", + "not_following_artists", + "no_favorite_albums_yet" ], "cs": [ @@ -48,7 +63,12 @@ "add_all_to_queue", "play_all_next", "pause", - "view_all" + "view_all", + "no_tracks_added_yet", + "no_tracks", + "no_tracks_listened_yet", + "not_following_artists", + "no_favorite_albums_yet" ], "de": [ @@ -61,7 +81,12 @@ "add_all_to_queue", "play_all_next", "pause", - "view_all" + "view_all", + "no_tracks_added_yet", + "no_tracks", + "no_tracks_listened_yet", + "not_following_artists", + "no_favorite_albums_yet" ], "es": [ @@ -74,7 +99,12 @@ "add_all_to_queue", "play_all_next", "pause", - "view_all" + "view_all", + "no_tracks_added_yet", + "no_tracks", + "no_tracks_listened_yet", + "not_following_artists", + "no_favorite_albums_yet" ], "eu": [ @@ -87,7 +117,12 @@ "add_all_to_queue", "play_all_next", "pause", - "view_all" + "view_all", + "no_tracks_added_yet", + "no_tracks", + "no_tracks_listened_yet", + "not_following_artists", + "no_favorite_albums_yet" ], "fa": [ @@ -100,7 +135,12 @@ "add_all_to_queue", "play_all_next", "pause", - "view_all" + "view_all", + "no_tracks_added_yet", + "no_tracks", + "no_tracks_listened_yet", + "not_following_artists", + "no_favorite_albums_yet" ], "fi": [ @@ -113,7 +153,12 @@ "add_all_to_queue", "play_all_next", "pause", - "view_all" + "view_all", + "no_tracks_added_yet", + "no_tracks", + "no_tracks_listened_yet", + "not_following_artists", + "no_favorite_albums_yet" ], "fr": [ @@ -126,7 +171,12 @@ "add_all_to_queue", "play_all_next", "pause", - "view_all" + "view_all", + "no_tracks_added_yet", + "no_tracks", + "no_tracks_listened_yet", + "not_following_artists", + "no_favorite_albums_yet" ], "hi": [ @@ -139,7 +189,12 @@ "add_all_to_queue", "play_all_next", "pause", - "view_all" + "view_all", + "no_tracks_added_yet", + "no_tracks", + "no_tracks_listened_yet", + "not_following_artists", + "no_favorite_albums_yet" ], "id": [ @@ -152,7 +207,12 @@ "add_all_to_queue", "play_all_next", "pause", - "view_all" + "view_all", + "no_tracks_added_yet", + "no_tracks", + "no_tracks_listened_yet", + "not_following_artists", + "no_favorite_albums_yet" ], "it": [ @@ -165,7 +225,12 @@ "add_all_to_queue", "play_all_next", "pause", - "view_all" + "view_all", + "no_tracks_added_yet", + "no_tracks", + "no_tracks_listened_yet", + "not_following_artists", + "no_favorite_albums_yet" ], "ja": [ @@ -178,7 +243,12 @@ "add_all_to_queue", "play_all_next", "pause", - "view_all" + "view_all", + "no_tracks_added_yet", + "no_tracks", + "no_tracks_listened_yet", + "not_following_artists", + "no_favorite_albums_yet" ], "ka": [ @@ -191,7 +261,12 @@ "add_all_to_queue", "play_all_next", "pause", - "view_all" + "view_all", + "no_tracks_added_yet", + "no_tracks", + "no_tracks_listened_yet", + "not_following_artists", + "no_favorite_albums_yet" ], "ko": [ @@ -204,7 +279,12 @@ "add_all_to_queue", "play_all_next", "pause", - "view_all" + "view_all", + "no_tracks_added_yet", + "no_tracks", + "no_tracks_listened_yet", + "not_following_artists", + "no_favorite_albums_yet" ], "ne": [ @@ -217,7 +297,12 @@ "add_all_to_queue", "play_all_next", "pause", - "view_all" + "view_all", + "no_tracks_added_yet", + "no_tracks", + "no_tracks_listened_yet", + "not_following_artists", + "no_favorite_albums_yet" ], "nl": [ @@ -230,7 +315,12 @@ "add_all_to_queue", "play_all_next", "pause", - "view_all" + "view_all", + "no_tracks_added_yet", + "no_tracks", + "no_tracks_listened_yet", + "not_following_artists", + "no_favorite_albums_yet" ], "pl": [ @@ -243,7 +333,12 @@ "add_all_to_queue", "play_all_next", "pause", - "view_all" + "view_all", + "no_tracks_added_yet", + "no_tracks", + "no_tracks_listened_yet", + "not_following_artists", + "no_favorite_albums_yet" ], "pt": [ @@ -256,7 +351,12 @@ "add_all_to_queue", "play_all_next", "pause", - "view_all" + "view_all", + "no_tracks_added_yet", + "no_tracks", + "no_tracks_listened_yet", + "not_following_artists", + "no_favorite_albums_yet" ], "ru": [ @@ -269,7 +369,12 @@ "add_all_to_queue", "play_all_next", "pause", - "view_all" + "view_all", + "no_tracks_added_yet", + "no_tracks", + "no_tracks_listened_yet", + "not_following_artists", + "no_favorite_albums_yet" ], "th": [ @@ -282,7 +387,12 @@ "add_all_to_queue", "play_all_next", "pause", - "view_all" + "view_all", + "no_tracks_added_yet", + "no_tracks", + "no_tracks_listened_yet", + "not_following_artists", + "no_favorite_albums_yet" ], "tr": [ @@ -295,7 +405,12 @@ "add_all_to_queue", "play_all_next", "pause", - "view_all" + "view_all", + "no_tracks_added_yet", + "no_tracks", + "no_tracks_listened_yet", + "not_following_artists", + "no_favorite_albums_yet" ], "uk": [ @@ -308,7 +423,12 @@ "add_all_to_queue", "play_all_next", "pause", - "view_all" + "view_all", + "no_tracks_added_yet", + "no_tracks", + "no_tracks_listened_yet", + "not_following_artists", + "no_favorite_albums_yet" ], "vi": [ @@ -321,7 +441,12 @@ "add_all_to_queue", "play_all_next", "pause", - "view_all" + "view_all", + "no_tracks_added_yet", + "no_tracks", + "no_tracks_listened_yet", + "not_following_artists", + "no_favorite_albums_yet" ], "zh": [ @@ -334,6 +459,11 @@ "add_all_to_queue", "play_all_next", "pause", - "view_all" + "view_all", + "no_tracks_added_yet", + "no_tracks", + "no_tracks_listened_yet", + "not_following_artists", + "no_favorite_albums_yet" ] } From 3649b67869bf14f7cbbf25385c2343e42fc4f92d Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 12 Jan 2025 14:22:54 +0600 Subject: [PATCH 056/112] refactor: use undraw for not_found component --- lib/components/fallbacks/not_found.dart | 39 ++++++++++++------------- lib/modules/player/player_queue.dart | 2 +- lib/pages/library/local_folder.dart | 18 ++++++++++-- pubspec.yaml | 1 + 4 files changed, 35 insertions(+), 25 deletions(-) diff --git a/lib/components/fallbacks/not_found.dart b/lib/components/fallbacks/not_found.dart index d35a4b50..9a994446 100644 --- a/lib/components/fallbacks/not_found.dart +++ b/lib/components/fallbacks/not_found.dart @@ -1,30 +1,27 @@ +import 'package:flutter_undraw/flutter_undraw.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; -import 'package:spotube/collections/assets.gen.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/extensions/context.dart'; class NotFound extends StatelessWidget { - final bool vertical; - const NotFound({super.key, this.vertical = false}); + const NotFound({super.key}); @override Widget build(BuildContext context) { - final widgets = [ - SizedBox( - height: 150, - width: 150, - child: Assets.emptyBox.image(), - ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text(context.l10n.nothing_found).large().semiBold(), - Text( - context.l10n.the_box_is_empty, - ).semiBold(), - ], - ), - ]; - return vertical ? Column(children: widgets) : Row(children: widgets); + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Undraw( + illustration: UndrawIllustration.empty, + height: 200 * context.theme.scaling, + color: context.theme.colorScheme.primary, + ), + const Gap(10), + Text( + context.l10n.nothing_found, + textAlign: TextAlign.center, + ).muted().small() + ], + ); } } diff --git a/lib/modules/player/player_queue.dart b/lib/modules/player/player_queue.dart index a91c883d..fb19f880 100644 --- a/lib/modules/player/player_queue.dart +++ b/lib/modules/player/player_queue.dart @@ -81,7 +81,7 @@ class PlayerQueue extends HookConsumerWidget { ); if (tracks.isEmpty) { - return const NotFound(vertical: true); + return const NotFound(); } return Stack( diff --git a/lib/pages/library/local_folder.dart b/lib/pages/library/local_folder.dart index 23326c68..84873b84 100644 --- a/lib/pages/library/local_folder.dart +++ b/lib/pages/library/local_folder.dart @@ -4,6 +4,7 @@ import 'dart:math'; import 'package:collection/collection.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:flutter_undraw/flutter_undraw.dart'; import 'package:fuzzywuzzy/fuzzywuzzy.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; @@ -320,10 +321,21 @@ class LocalLibraryPage extends HookConsumerWidget { if (!trackSnapshot.isLoading && filteredTracks.isEmpty) { - return const Expanded( - child: Row( + return Expanded( + child: Column( mainAxisAlignment: MainAxisAlignment.center, - children: [NotFound()], + children: [ + Undraw( + illustration: UndrawIllustration.empty, + height: 200 * scale, + color: context.theme.colorScheme.primary, + ), + const Gap(10), + Text( + context.l10n.nothing_found, + textAlign: TextAlign.center, + ).muted().small() + ], ), ); } diff --git a/pubspec.yaml b/pubspec.yaml index 657de0c0..3aaa3395 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -184,6 +184,7 @@ flutter: - packages/flutter_undraw/assets/undraw/happy_music.svg - packages/flutter_undraw/assets/undraw/follow_me_drone.svg - packages/flutter_undraw/assets/undraw/taken.svg + - packages/flutter_undraw/assets/undraw/empty.svg fonts: - family: GeistSans fonts: From 5930c342b5be95c58b2d3884f738b7990abcb46d Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 12 Jan 2025 21:32:33 +0600 Subject: [PATCH 057/112] chore: fix window resizing --- lib/collections/assets.gen.dart | 13 -- lib/components/titlebar/mouse_state.dart | 73 --------- lib/components/titlebar/titlebar.dart | 17 ++- lib/components/titlebar/titlebar_buttons.dart | 144 +++++++++--------- .../titlebar/titlebar_icon_buttons.dart | 95 ++++++------ lib/components/titlebar/window_button.dart | 125 --------------- lib/main.dart | 4 +- lib/pages/home/home.dart | 2 +- lib/pages/library/library.dart | 8 - lib/pages/lyrics/lyrics.dart | 2 + lib/pages/search/search.dart | 3 +- 11 files changed, 132 insertions(+), 354 deletions(-) delete mode 100644 lib/components/titlebar/mouse_state.dart delete mode 100644 lib/components/titlebar/window_button.dart diff --git a/lib/collections/assets.gen.dart b/lib/collections/assets.gen.dart index 98b67c80..004001f2 100644 --- a/lib/collections/assets.gen.dart +++ b/lib/collections/assets.gen.dart @@ -20,17 +20,6 @@ class $AssetsBackgroundsGen { List get values => [xmasEffect]; } -class $AssetsIllustrationsGen { - const $AssetsIllustrationsGen(); - - /// File path: assets/illustrations/fixing_bugs.png - AssetGenImage get fixingBugs => - const AssetGenImage('assets/illustrations/fixing_bugs.png'); - - /// List of all assets - List get values => [fixingBugs]; -} - class $AssetsLogosGen { const $AssetsLogosGen(); @@ -151,8 +140,6 @@ 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 $AssetsIllustrationsGen illustrations = - $AssetsIllustrationsGen(); static const AssetGenImage invidious = AssetGenImage('assets/invidious.jpg'); static const AssetGenImage jiosaavn = AssetGenImage('assets/jiosaavn.png'); static const AssetGenImage likedTracks = diff --git a/lib/components/titlebar/mouse_state.dart b/lib/components/titlebar/mouse_state.dart deleted file mode 100644 index 9af2a8b0..00000000 --- a/lib/components/titlebar/mouse_state.dart +++ /dev/null @@ -1,73 +0,0 @@ -import 'package:flutter/material.dart'; - -typedef MouseStateBuilderCB = Widget Function( - BuildContext context, MouseState mouseState); - -class MouseState { - bool isMouseOver = false; - bool isMouseDown = false; - MouseState(); - @override - String toString() { - return "isMouseDown: $isMouseDown - isMouseOver: $isMouseOver"; - } -} - -T? _ambiguate(T? value) => value; - -class MouseStateBuilder extends StatefulWidget { - final MouseStateBuilderCB builder; - final VoidCallback? onPressed; - const MouseStateBuilder({super.key, required this.builder, this.onPressed}); - @override - // ignore: library_private_types_in_public_api - _MouseStateBuilderState createState() => _MouseStateBuilderState(); -} - -class _MouseStateBuilderState extends State { - late MouseState _mouseState; - _MouseStateBuilderState() { - _mouseState = MouseState(); - } - - @override - Widget build(BuildContext context) { - return MouseRegion( - onEnter: (event) { - setState(() { - _mouseState.isMouseOver = true; - }); - }, - onExit: (event) { - setState(() { - _mouseState.isMouseOver = false; - }); - }, - child: GestureDetector( - onTapDown: (_) { - setState(() { - _mouseState.isMouseDown = true; - }); - }, - onTapCancel: () { - setState(() { - _mouseState.isMouseDown = false; - }); - }, - onTap: () { - setState(() { - _mouseState.isMouseDown = false; - _mouseState.isMouseOver = false; - }); - _ambiguate(WidgetsBinding.instance)!.addPostFrameCallback((_) { - if (widget.onPressed != null) { - widget.onPressed!(); - } - }); - }, - onTapUp: (_) {}, - child: widget.builder(context, _mouseState), - ), - ); - } -} diff --git a/lib/components/titlebar/titlebar.dart b/lib/components/titlebar/titlebar.dart index 215b63ed..5b86f6ad 100644 --- a/lib/components/titlebar/titlebar.dart +++ b/lib/components/titlebar/titlebar.dart @@ -1,6 +1,7 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/components/button/back_button.dart'; import 'package:spotube/components/titlebar/titlebar_buttons.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; @@ -49,7 +50,7 @@ class TitleBar extends HookConsumerWidget implements PreferredSizeWidget { this.height, this.surfaceBlur, this.surfaceOpacity, - this.useSafeArea = true, + this.useSafeArea = false, }); void onDrag(WidgetRef ref) { @@ -66,7 +67,7 @@ class TitleBar extends HookConsumerWidget implements PreferredSizeWidget { final lastClicked = useRef(DateTime.now().millisecondsSinceEpoch); return SizedBox( - height: height ?? 56, + height: height ?? (48 * context.theme.scaling), child: LayoutBuilder( builder: (context, constraints) { final hasFullscreen = @@ -102,18 +103,22 @@ class TitleBar extends HookConsumerWidget implements PreferredSizeWidget { : leading, trailing: [ ...trailing, - WindowTitleBarButtons(foregroundColor: foregroundColor), + Align( + alignment: Alignment.topRight, + child: + WindowTitleBarButtons(foregroundColor: foregroundColor), + ), ], title: title, header: header, subtitle: subtitle, trailingExpanded: trailingExpanded, alignment: alignment, - padding: padding, + padding: padding ?? EdgeInsets.zero, backgroundColor: backgroundColor, leadingGap: leadingGap, trailingGap: trailingGap, - height: height, + height: height ?? (48 * context.theme.scaling), surfaceBlur: surfaceBlur, surfaceOpacity: surfaceOpacity, useSafeArea: useSafeArea, @@ -127,5 +132,5 @@ class TitleBar extends HookConsumerWidget implements PreferredSizeWidget { } @override - Size get preferredSize => Size.fromHeight(height ?? 56.0); + Size get preferredSize => Size.fromHeight(height ?? 48); } diff --git a/lib/components/titlebar/titlebar_buttons.dart b/lib/components/titlebar/titlebar_buttons.dart index 42765d7b..92c2c93d 100644 --- a/lib/components/titlebar/titlebar_buttons.dart +++ b/lib/components/titlebar/titlebar_buttons.dart @@ -2,9 +2,11 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; +import 'package:spotube/components/hover_builder.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/components/titlebar/titlebar_icon_buttons.dart'; -import 'package:spotube/components/titlebar/window_button.dart'; + +import 'package:spotube/hooks/configurators/use_window_listener.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/utils/platform.dart'; import 'package:titlebar_buttons/titlebar_buttons.dart'; @@ -22,12 +24,20 @@ class WindowTitleBarButtons extends HookConsumerWidget { final preferences = ref.watch(userPreferencesProvider); final isMaximized = useState(null); const type = ThemeType.auto; - final scale = context.theme.scaling; Future onClose() async { await windowManager.close(); } + useWindowListener( + onWindowMaximize: () { + isMaximized.value = true; + }, + onWindowUnmaximize: () { + isMaximized.value = false; + }, + ); + useEffect(() { if (kIsDesktop) { windowManager.isMaximized().then((value) { @@ -42,86 +52,68 @@ class WindowTitleBarButtons extends HookConsumerWidget { } if (kIsWindows) { - final theme = Theme.of(context); - final colors = WindowButtonColors( - normal: Colors.transparent, - iconNormal: foregroundColor ?? theme.colorScheme.onSurface, - mouseOver: theme.colorScheme.onSurface.withAlpha(25), - mouseDown: theme.colorScheme.onSurface.withAlpha(51), - iconMouseOver: theme.colorScheme.onSurface, - iconMouseDown: theme.colorScheme.onSurface, - ); - - final closeColors = WindowButtonColors( - normal: Colors.transparent, - iconNormal: foregroundColor ?? theme.colorScheme.onSurface, - mouseOver: Colors.red, - mouseDown: Colors.red[800]!, - iconMouseOver: Colors.white, - iconMouseDown: Colors.black, - ); - - return Transform( - transform: Matrix4.translationValues(18, -12, 0) * scale, - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - MinimizeWindowButton( - onPressed: windowManager.minimize, - colors: colors, + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ShadcnWindowButton( + icon: MinimizeIcon(color: context.theme.colorScheme.foreground), + onPressed: windowManager.minimize, + ), + if (isMaximized.value != true) + ShadcnWindowButton( + icon: MaximizeIcon(color: context.theme.colorScheme.foreground), + onPressed: () { + windowManager.maximize(); + isMaximized.value = true; + }, + ) + else + ShadcnWindowButton( + icon: RestoreIcon(color: context.theme.colorScheme.foreground), + onPressed: () { + windowManager.unmaximize(); + isMaximized.value = false; + }, ), - if (isMaximized.value != true) - MaximizeWindowButton( - colors: colors, - onPressed: () { - windowManager.maximize(); - isMaximized.value = true; - }, - ) - else - RestoreWindowButton( - colors: colors, - onPressed: () { - windowManager.unmaximize(); - isMaximized.value = false; - }, + HoverBuilder(builder: (context, isHovered) { + return ShadcnWindowButton( + icon: CloseIcon( + color: isHovered + ? Colors.white + : context.theme.colorScheme.foreground, ), - CloseWindowButton( - colors: closeColors, onPressed: onClose, - ), - ], - ), + hoverBackgroundColor: const Color(0xFFD32F2F), + ); + }), + ], ); } - return Transform( - transform: Matrix4.translationValues(18, -12, 0) * scale, - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - DecoratedMinimizeButton( - type: type, - onPressed: windowManager.minimize, - ), - DecoratedMaximizeButton( - type: type, - onPressed: () async { - if (await windowManager.isMaximized()) { - await windowManager.unmaximize(); - isMaximized.value = false; - } else { - await windowManager.maximize(); - isMaximized.value = true; - } - }, - ), - DecoratedCloseButton( - type: type, - onPressed: onClose, - ), - ], - ), + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + DecoratedMinimizeButton( + type: type, + onPressed: windowManager.minimize, + ), + DecoratedMaximizeButton( + type: type, + onPressed: () async { + if (await windowManager.isMaximized()) { + await windowManager.unmaximize(); + isMaximized.value = false; + } else { + await windowManager.maximize(); + isMaximized.value = true; + } + }, + ), + DecoratedCloseButton( + type: type, + onPressed: onClose, + ), + ], ); } } diff --git a/lib/components/titlebar/titlebar_icon_buttons.dart b/lib/components/titlebar/titlebar_icon_buttons.dart index 70170262..481a22ce 100644 --- a/lib/components/titlebar/titlebar_icon_buttons.dart +++ b/lib/components/titlebar/titlebar_icon_buttons.dart @@ -1,56 +1,50 @@ import 'dart:math'; -import 'package:flutter/material.dart'; -import 'package:spotube/components/titlebar/window_button.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:spotube/extensions/button_variance.dart'; -class MinimizeWindowButton extends WindowButton { - MinimizeWindowButton( - {super.key, super.colors, super.onPressed, bool? animate}) - : super( - animate: animate ?? false, - iconBuilder: (buttonContext) => - MinimizeIcon(color: buttonContext.iconColor), - ); +class ShadcnWindowButton extends StatelessWidget { + final Widget icon; + final VoidCallback onPressed; + final Color? hoverBackgroundColor; + + const ShadcnWindowButton({ + super.key, + required this.icon, + required this.onPressed, + this.hoverBackgroundColor, + }); + + @override + Widget build(BuildContext context) { + return SizedBox( + width: 45, + height: 32, + child: IconButton( + variance: ButtonVariance.ghost.copyWith( + decoration: (context, states) { + final decoration = ButtonVariance.ghost.decoration(context, states) + as BoxDecoration; + if (hoverBackgroundColor != null && + states.contains(WidgetState.hovered)) { + return decoration.copyWith( + borderRadius: BorderRadius.zero, + color: hoverBackgroundColor, + ); + } + + return decoration.copyWith( + borderRadius: BorderRadius.zero, + ); + }, + ), + icon: icon, + onPressed: onPressed, + ), + ); + } } -class MaximizeWindowButton extends WindowButton { - MaximizeWindowButton( - {super.key, super.colors, super.onPressed, bool? animate}) - : super( - animate: animate ?? false, - iconBuilder: (buttonContext) => - MaximizeIcon(color: buttonContext.iconColor), - ); -} - -class RestoreWindowButton extends WindowButton { - RestoreWindowButton({super.key, super.colors, super.onPressed, bool? animate}) - : super( - animate: animate ?? false, - iconBuilder: (buttonContext) => - RestoreIcon(color: buttonContext.iconColor), - ); -} - -final _defaultCloseButtonColors = WindowButtonColors( - mouseOver: const Color(0xFFD32F2F), - mouseDown: const Color(0xFFB71C1C), - iconNormal: const Color(0xFF805306), - iconMouseOver: const Color(0xFFFFFFFF)); - -class CloseWindowButton extends WindowButton { - CloseWindowButton( - {super.key, WindowButtonColors? colors, super.onPressed, bool? animate}) - : super( - colors: colors ?? _defaultCloseButtonColors, - animate: animate ?? false, - iconBuilder: (buttonContext) => - CloseIcon(color: buttonContext.iconColor), - ); -} - -// Switched to CustomPaint icons by https://github.com/esDotDev - /// Close class CloseIcon extends StatelessWidget { final Color color; @@ -149,8 +143,9 @@ class _AlignedPaint extends StatelessWidget { @override Widget build(BuildContext context) { return Align( - alignment: Alignment.center, - child: CustomPaint(size: const Size(10, 10), painter: painter)); + alignment: Alignment.center, + child: CustomPaint(size: const Size(10, 10), painter: painter), + ); } } diff --git a/lib/components/titlebar/window_button.dart b/lib/components/titlebar/window_button.dart deleted file mode 100644 index fef9d754..00000000 --- a/lib/components/titlebar/window_button.dart +++ /dev/null @@ -1,125 +0,0 @@ -import 'package:shadcn_flutter/shadcn_flutter.dart'; -import 'package:spotube/components/titlebar/mouse_state.dart'; -import 'package:spotube/components/titlebar/titlebar.dart'; - -typedef WindowButtonIconBuilder = Widget Function( - WindowButtonContext buttonContext); -typedef WindowButtonBuilder = Widget Function( - WindowButtonContext buttonContext, Widget icon); - -class WindowButtonContext { - BuildContext context; - MouseState mouseState; - Color? backgroundColor; - Color iconColor; - WindowButtonContext( - {required this.context, - required this.mouseState, - this.backgroundColor, - required this.iconColor}); -} - -class WindowButtonColors { - late Color normal; - late Color mouseOver; - late Color mouseDown; - late Color iconNormal; - late Color iconMouseOver; - late Color iconMouseDown; - WindowButtonColors( - {Color? normal, - Color? mouseOver, - Color? mouseDown, - Color? iconNormal, - Color? iconMouseOver, - Color? iconMouseDown}) { - this.normal = normal ?? _defaultButtonColors.normal; - this.mouseOver = mouseOver ?? _defaultButtonColors.mouseOver; - this.mouseDown = mouseDown ?? _defaultButtonColors.mouseDown; - this.iconNormal = iconNormal ?? _defaultButtonColors.iconNormal; - this.iconMouseOver = iconMouseOver ?? _defaultButtonColors.iconMouseOver; - this.iconMouseDown = iconMouseDown ?? _defaultButtonColors.iconMouseDown; - } -} - -final _defaultButtonColors = WindowButtonColors( - normal: Colors.transparent, - iconNormal: const Color(0xFF805306), - mouseOver: const Color(0xFF404040), - mouseDown: const Color(0xFF202020), - iconMouseOver: const Color(0xFFFFFFFF), - iconMouseDown: const Color(0xFFF0F0F0), -); - -class WindowButton extends StatelessWidget { - final WindowButtonBuilder? builder; - final WindowButtonIconBuilder? iconBuilder; - late final WindowButtonColors colors; - final bool animate; - final EdgeInsets? padding; - final VoidCallback? onPressed; - - WindowButton( - {super.key, - WindowButtonColors? colors, - this.builder, - @required this.iconBuilder, - this.padding, - this.onPressed, - this.animate = false}) { - this.colors = colors ?? _defaultButtonColors; - } - - Color getBackgroundColor(MouseState mouseState) { - if (mouseState.isMouseDown) return colors.mouseDown; - if (mouseState.isMouseOver) return colors.mouseOver; - return colors.normal; - } - - Color getIconColor(MouseState mouseState) { - if (mouseState.isMouseDown) return colors.iconMouseDown; - if (mouseState.isMouseOver) return colors.iconMouseOver; - return colors.iconNormal; - } - - @override - Widget build(BuildContext context) { - if (!kTitlebarVisible) return const SizedBox.shrink(); - - return MouseStateBuilder( - builder: (context, mouseState) { - WindowButtonContext buttonContext = WindowButtonContext( - mouseState: mouseState, - context: context, - backgroundColor: getBackgroundColor(mouseState), - iconColor: getIconColor(mouseState)); - - var icon = (iconBuilder != null) - ? iconBuilder!(buttonContext) - : const SizedBox(); - - var fadeOutColor = - getBackgroundColor(MouseState()..isMouseOver = true).withAlpha(0); - var padding = this.padding ?? const EdgeInsets.all(10); - var animationMs = - mouseState.isMouseOver ? (animate ? 100 : 0) : (animate ? 200 : 0); - Widget iconWithPadding = Padding(padding: padding, child: icon); - iconWithPadding = AnimatedContainer( - curve: Curves.easeOut, - duration: Duration(milliseconds: animationMs), - color: buttonContext.backgroundColor ?? fadeOutColor, - child: iconWithPadding); - var button = - (builder != null) ? builder!(buttonContext, icon) : iconWithPadding; - return SizedBox( - width: 45, - height: 32, - child: button, - ); - }, - onPressed: () { - if (onPressed != null) onPressed!(); - }, - ); - } -} diff --git a/lib/main.dart b/lib/main.dart index 5b20acd8..8025f7cc 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -207,7 +207,9 @@ class Spotube extends HookConsumerWidget { child: child!, ); - if (kIsDesktop && !kIsMacOS) child = DragToResizeArea(child: child); + if (kIsLinux) { + child = DragToResizeArea(child: child); + } return child; }, diff --git a/lib/pages/home/home.dart b/lib/pages/home/home.dart index 78371c4d..1638393b 100644 --- a/lib/pages/home/home.dart +++ b/lib/pages/home/home.dart @@ -36,7 +36,7 @@ class HomePage extends HookConsumerWidget { bottom: false, child: Scaffold( headers: [ - if (kTitlebarVisible) const TitleBar(), + if (kTitlebarVisible) const TitleBar(height: 30), ], child: CustomScrollView( controller: controller, diff --git a/lib/pages/library/library.dart b/lib/pages/library/library.dart index 87b6a6cb..ec896228 100644 --- a/lib/pages/library/library.dart +++ b/lib/pages/library/library.dart @@ -2,8 +2,6 @@ import 'package:flutter/material.dart' show Badge; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; -import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; - import 'package:spotube/modules/library/user_local_tracks.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/modules/library/user_albums.dart'; @@ -19,7 +17,6 @@ class LibraryPage extends HookConsumerWidget { const LibraryPage({super.key}); @override Widget build(BuildContext context, ref) { - final scale = context.theme.scaling; final downloadingCount = ref.watch(downloadManagerProvider).$downloadCount; final index = useState(0); @@ -40,11 +37,6 @@ class LibraryPage extends HookConsumerWidget { child: Scaffold( headers: [ TitleBar( - padding: const EdgeInsets.symmetric( - horizontal: 18, - vertical: 12, - ).copyWith(left: 0) * - scale, child: SingleChildScrollView( scrollDirection: Axis.horizontal, child: TabList( diff --git a/lib/pages/lyrics/lyrics.dart b/lib/pages/lyrics/lyrics.dart index 679ef78e..f61dbbe3 100644 --- a/lib/pages/lyrics/lyrics.dart +++ b/lib/pages/lyrics/lyrics.dart @@ -151,6 +151,8 @@ class LyricsPage extends HookConsumerWidget { ? TitleBar( backgroundColor: Colors.transparent, title: tabbar, + height: 58 * context.theme.scaling, + surfaceBlur: 0, ) : tabbar ], diff --git a/lib/pages/search/search.dart b/lib/pages/search/search.dart index efd46ebb..701c3c5c 100644 --- a/lib/pages/search/search.dart +++ b/lib/pages/search/search.dart @@ -70,7 +70,8 @@ class SearchPage extends HookConsumerWidget { bottom: false, child: Scaffold( headers: [ - if (kTitlebarVisible) const TitleBar(automaticallyImplyLeading: true) + if (kTitlebarVisible) + const TitleBar(automaticallyImplyLeading: true, height: 30) ], child: auth.asData?.value == null ? const AnonymousFallback() From 696875e4b5ab5d8976aa538164dfff54f2eb83de Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 12 Jan 2025 23:21:20 +0600 Subject: [PATCH 058/112] chore: use youtube_explode from github --- lib/provider/audio_player/audio_player.dart | 8 ++++++-- pubspec.lock | 15 ++++++++------- pubspec.yaml | 7 +++++-- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/lib/provider/audio_player/audio_player.dart b/lib/provider/audio_player/audio_player.dart index b4892a0c..170cbb12 100644 --- a/lib/provider/audio_player/audio_player.dart +++ b/lib/provider/audio_player/audio_player.dart @@ -301,7 +301,9 @@ class AudioPlayerNotifier extends Notifier { bool _compareTracks(Track a, Track b) { if ((a is LocalTrack && b is! LocalTrack) || - (a is! LocalTrack && b is LocalTrack)) return false; + (a is! LocalTrack && b is LocalTrack)) { + return false; + } return a is LocalTrack && b is LocalTrack ? (a).path == (b).path @@ -347,7 +349,9 @@ class AudioPlayerNotifier extends Notifier { newIndex < 0 || oldIndex < 0 || newIndex > state.tracks.length - 1 || - oldIndex > state.tracks.length - 1) return; + oldIndex > state.tracks.length - 1) { + return; + } await audioPlayer.moveTrack(oldIndex, newIndex); } diff --git a/pubspec.lock b/pubspec.lock index 2666460c..2fa1d8ab 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -979,10 +979,10 @@ packages: dependency: "direct main" description: name: flutter_undraw - sha256: "17fe2738231c502171f984c003f6e40979de1a2550ef2debdd29fec27ae006ea" + sha256: a38083350fac9e0d44ddde0e53a39f00730498ed4a110f967a38c6fb1a161755 url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.2.1" flutter_web_plugins: dependency: transitive description: flutter @@ -2696,11 +2696,12 @@ packages: youtube_explode_dart: dependency: "direct main" description: - name: youtube_explode_dart - sha256: "51ca5b2c03bf56060143d4f87df90ec3227592d7ae8a8003532533ae019d4291" - url: "https://pub.dev" - source: hosted - version: "2.3.6" + path: "." + ref: e519db65ad0b0a40b12f69285932f9db509da3cf + resolved-ref: e519db65ad0b0a40b12f69285932f9db509da3cf + url: "https://github.com/Hexer10/youtube_explode_dart.git" + source: git + version: "2.3.7" sdks: dart: ">=3.6.0 <4.0.0" flutter: ">=3.27.0" diff --git a/pubspec.yaml b/pubspec.yaml index 3aaa3395..1594abb2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -63,7 +63,7 @@ dependencies: flutter_riverpod: ^2.5.1 flutter_secure_storage: ^9.0.0 flutter_sharing_intent: ^1.1.0 - flutter_undraw: ^0.2.0 + flutter_undraw: ^0.2.1 form_builder_validators: ^11.1.1 form_validator: ^2.1.1 freezed_annotation: ^2.4.1 @@ -134,7 +134,10 @@ dependencies: wikipedia_api: ^0.1.0 win32_registry: ^1.1.5 window_manager: ^0.4.3 - youtube_explode_dart: ^2.3.5 + youtube_explode_dart: + git: + url: https://github.com/Hexer10/youtube_explode_dart.git + ref: e519db65ad0b0a40b12f69285932f9db509da3cf dev_dependencies: build_runner: ^2.4.13 From 6c005592e35edff02c3dc7870ad8293eaced428d Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Thu, 16 Jan 2025 21:13:42 +0600 Subject: [PATCH 059/112] refactor: color scheme support based on shadcn colors --- lib/main.dart | 16 +- lib/modules/home/sections/feed.dart | 21 +- lib/modules/home/sections/genres/genres.dart | 1 - .../settings/color_scheme_picker_dialog.dart | 252 ++++++------------ lib/pages/settings/sections/appearance.dart | 5 +- 5 files changed, 108 insertions(+), 187 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 8025f7cc..af7da1b7 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -26,6 +26,7 @@ import 'package:spotube/hooks/configurators/use_fix_window_stretching.dart'; import 'package:spotube/hooks/configurators/use_get_storage_perms.dart'; import 'package:spotube/hooks/configurators/use_has_touch.dart'; import 'package:spotube/models/database/database.dart'; +import 'package:spotube/modules/settings/color_scheme_picker_dialog.dart'; import 'package:spotube/provider/audio_player/audio_player_streams.dart'; import 'package:spotube/provider/database/database.dart'; import 'package:spotube/provider/glance/glance.dart'; @@ -43,7 +44,6 @@ import 'package:spotube/services/logger/logger.dart'; import 'package:spotube/services/wm_tools/wm_tools.dart'; import 'package:spotube/utils/migrations/sandbox.dart'; import 'package:spotube/utils/platform.dart'; -import 'package:system_theme/system_theme.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_native_splash/flutter_native_splash.dart'; import 'package:flutter_displaymode/flutter_displaymode.dart'; @@ -83,8 +83,6 @@ Future main(List rawArgs) async { await windowManager.setPreventClose(true); } - await SystemTheme.accentColor.load(); - if (!kIsWeb) { MetadataGod.initialize(); } @@ -133,8 +131,8 @@ class Spotube extends HookConsumerWidget { final themeMode = ref.watch(userPreferencesProvider.select((s) => s.themeMode)); final locale = ref.watch(userPreferencesProvider.select((s) => s.locale)); - // final accentMaterialColor = - // ref.watch(userPreferencesProvider.select((s) => s.accentColorScheme)); + final accentMaterialColor = + ref.watch(userPreferencesProvider.select((s) => s.accentColorScheme)); // final isAmoledTheme = // ref.watch(userPreferencesProvider.select((s) => s.amoledDarkTheme)); // final paletteColor = @@ -217,14 +215,18 @@ class Spotube extends HookConsumerWidget { theme: ThemeData( radius: .5, iconTheme: const IconThemeProperties(), - colorScheme: ColorSchemes.lightOrange(), + colorScheme: + colorSchemeMap[accentMaterialColor.name]?.call(ThemeMode.light) ?? + ColorSchemes.lightOrange(), surfaceOpacity: .8, surfaceBlur: 10, ), darkTheme: ThemeData( radius: .5, iconTheme: const IconThemeProperties(), - colorScheme: ColorSchemes.darkOrange(), + colorScheme: + colorSchemeMap[accentMaterialColor.name]?.call(ThemeMode.dark) ?? + ColorSchemes.darkOrange(), surfaceOpacity: .8, surfaceBlur: 10, ), diff --git a/lib/modules/home/sections/feed.dart b/lib/modules/home/sections/feed.dart index bce2ea5b..34a9ee4b 100644 --- a/lib/modules/home/sections/feed.dart +++ b/lib/modules/home/sections/feed.dart @@ -1,6 +1,5 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; -import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/pages/home/feed/feed_section.dart'; @@ -38,18 +37,14 @@ class HomePageFeedSection extends HookConsumerWidget { hasNextPage: false, isLoadingNextPage: false, onFetchMore: () {}, - titleTrailing: Directionality( - textDirection: TextDirection.rtl, - child: Button.link( - leading: const Icon(SpotubeIcons.angleRight), - child: Text(context.l10n.browse_more), - onPressed: () => ServiceUtils.pushNamed( - context, - HomeFeedSectionPage.name, - pathParameters: { - "feedId": section.uri, - }, - ), + titleTrailing: Button.text( + child: Text(context.l10n.browse_all), + onPressed: () => ServiceUtils.pushNamed( + context, + HomeFeedSectionPage.name, + pathParameters: { + "feedId": section.uri, + }, ), ), ); diff --git a/lib/modules/home/sections/genres/genres.dart b/lib/modules/home/sections/genres/genres.dart index 520c1121..5e96f78f 100644 --- a/lib/modules/home/sections/genres/genres.dart +++ b/lib/modules/home/sections/genres/genres.dart @@ -74,7 +74,6 @@ class HomeGenresSection extends HookConsumerWidget { onPressed: () { context.pushNamed(GenrePage.name); }, - trailing: const Icon(SpotubeIcons.angleRight), child: Text( context.l10n.browse_all, ).muted(), diff --git a/lib/modules/settings/color_scheme_picker_dialog.dart b/lib/modules/settings/color_scheme_picker_dialog.dart index f2933505..8092f825 100644 --- a/lib/modules/settings/color_scheme_picker_dialog.dart +++ b/lib/modules/settings/color_scheme_picker_dialog.dart @@ -1,10 +1,11 @@ -import 'package:flutter/material.dart'; +import 'package:collection/collection.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; -import 'package:system_theme/system_theme.dart'; class SpotubeColor extends Color { final String name; @@ -25,23 +26,33 @@ class SpotubeColor extends Color { } final Set colorsMap = { - SpotubeColor(SystemTheme.accentColor.accent.value, name: "System"), - SpotubeColor(Colors.red.value, name: "Red"), - SpotubeColor(Colors.pink.value, name: "Pink"), - SpotubeColor(Colors.purple.value, name: "Purple"), - SpotubeColor(Colors.deepPurple.value, name: "DeepPurple"), - SpotubeColor(Colors.indigo.value, name: "Indigo"), - SpotubeColor(Colors.blue.value, name: "Blue"), - SpotubeColor(Colors.lightBlue.value, name: "LightBlue"), - SpotubeColor(Colors.cyan.value, name: "Cyan"), - SpotubeColor(Colors.teal.value, name: "Teal"), - SpotubeColor(Colors.green.value, name: "Green"), - SpotubeColor(Colors.lightGreen.value, name: "LightGreen"), - SpotubeColor(Colors.yellow.value, name: "Yellow"), - SpotubeColor(Colors.amber.value, name: "Amber"), - SpotubeColor(Colors.orange.value, name: "Orange"), - SpotubeColor(Colors.deepOrange.value, name: "DeepOrange"), - SpotubeColor(Colors.brown.value, name: "Brown"), + SpotubeColor(Colors.slate.value, name: "slate"), + SpotubeColor(Colors.gray.value, name: "gray"), + SpotubeColor(Colors.zinc.value, name: "zinc"), + SpotubeColor(Colors.neutral.value, name: "neutral"), + SpotubeColor(Colors.stone.value, name: "stone"), + SpotubeColor(Colors.red.value, name: "red"), + SpotubeColor(Colors.orange.value, name: "orange"), + SpotubeColor(Colors.yellow.value, name: "yellow"), + SpotubeColor(Colors.green.value, name: "green"), + SpotubeColor(Colors.blue.value, name: "blue"), + SpotubeColor(Colors.violet.value, name: "violet"), + SpotubeColor(Colors.rose.value, name: "rose"), +}; + +final colorSchemeMap = { + "slate": ColorSchemes.slate, + "gray": ColorSchemes.gray, + "zinc": ColorSchemes.zinc, + "neutral": ColorSchemes.neutral, + "stone": ColorSchemes.stone, + "red": ColorSchemes.red, + "orange": ColorSchemes.orange, + "yellow": ColorSchemes.yellow, + "green": ColorSchemes.green, + "blue": ColorSchemes.blue, + "violet": ColorSchemes.violet, + "rose": ColorSchemes.rose, }; class ColorSchemePickerDialog extends HookConsumerWidget { @@ -51,180 +62,93 @@ class ColorSchemePickerDialog extends HookConsumerWidget { Widget build(BuildContext context, ref) { final preferences = ref.watch(userPreferencesProvider); final preferencesNotifier = ref.watch(userPreferencesProvider.notifier); - final scheme = preferences.accentColorScheme; - final active = useState(colorsMap.firstWhere( - (element) { - return scheme.name == element.name; - }, - ).name); - onOk() { - preferencesNotifier.setAccentColorScheme( - colorsMap.firstWhere( - (element) { - return element.name == active.value; - }, - ), - ); - Navigator.pop(context); - } + final scheme = preferences.accentColorScheme; + final active = useState( + colorsMap.firstWhereOrNull( + (element) { + return scheme.name == element.name; + }, + )?.name, + ); return AlertDialog( - title: Text(context.l10n.pick_color_scheme), + title: Text( + context.l10n.pick_color_scheme, + style: TextStyle(color: context.theme.colorScheme.foreground), + ).large(), actions: [ - OutlinedButton( + Button.outline( child: Text(context.l10n.cancel), onPressed: () { Navigator.pop(context); }, ), - FilledButton( - onPressed: onOk, + Button.primary( + onPressed: () { + Navigator.pop(context); + }, child: Text(context.l10n.save), ), ], content: SizedBox( height: 200, width: 400, - child: ListView.separated( - separatorBuilder: (context, index) { - return const SizedBox(height: 10); - }, - itemCount: colorsMap.length, - itemBuilder: (context, index) { - final color = colorsMap.elementAt(index); - return ColorTile( - color: color, - isActive: active.value == color.name, - onPressed: () { - active.value = color.name; - }, - tooltip: color.name, - ); - }, + child: Wrap( + spacing: 8, + runSpacing: 8, + children: colorsMap.map( + (color) { + return ColorChip( + name: color.name, + color: color, + isActive: color.name == active.value, + onPressed: () { + active.value = color.name; + preferencesNotifier.setAccentColorScheme( + colorsMap.firstWhere( + (element) { + return element.name == color.name; + }, + ), + ); + }, + ); + }, + ).toList(), ), ), ); } } -class ColorTile extends StatelessWidget { +class ColorChip extends StatelessWidget { + final String name; final Color color; final bool isActive; - final void Function()? onPressed; - final String? tooltip; - final bool isCompact; - const ColorTile({ - required this.color, - this.isActive = false, - this.onPressed, - this.tooltip = "", - this.isCompact = false, + final VoidCallback onPressed; + const ColorChip({ super.key, + required this.name, + required this.color, + required this.isActive, + required this.onPressed, }); - factory ColorTile.compact({ - required Color color, - bool isActive = false, - void Function()? onPressed, - String? tooltip = "", - Key? key, - }) { - return ColorTile( - color: color, - isActive: isActive, - onPressed: onPressed, - tooltip: tooltip, - isCompact: true, - key: key, - ); - } - @override Widget build(BuildContext context) { - final theme = Theme.of(context); - - final lead = Container( - height: 40, - width: 40, - decoration: BoxDecoration( - border: isActive - ? Border.fromBorderSide( - BorderSide( - color: Color.lerp( - theme.colorScheme.primary, - theme.colorScheme.onPrimary, - 0.5, - )!, - width: 4, - ), - ) - : null, - borderRadius: BorderRadius.circular(15), - color: color, - ), - ); - - if (isCompact) { - return GestureDetector( - onTap: onPressed, - child: lead, - ); - } - - final colorScheme = ColorScheme.fromSeed(seedColor: color); - - final palette = [ - colorScheme.primary, - colorScheme.inversePrimary, - colorScheme.primaryContainer, - colorScheme.secondary, - colorScheme.secondaryContainer, - colorScheme.surface, - colorScheme.surface, - colorScheme.surfaceContainerHighest, - colorScheme.onPrimary, - colorScheme.onSurface, - ]; - - return GestureDetector( - onTap: onPressed, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - lead, - const SizedBox(width: 10), - Text( - tooltip!, - style: theme.textTheme.bodyLarge?.copyWith( - color: theme.colorScheme.primary, - fontWeight: FontWeight.w600, - ), - ), - ], - ), - const SizedBox(height: 10), - Wrap( - alignment: WrapAlignment.start, - spacing: 10, - runSpacing: 10, - children: [ - ...palette.map( - (e) => Container( - height: 20, - width: 20, - decoration: BoxDecoration( - color: e, - borderRadius: BorderRadius.circular(5), - ), - ), - ), - ], - ), - ], + return Chip( + leading: Container( + width: 20, + height: 20, + decoration: BoxDecoration( + color: color, + borderRadius: BorderRadius.circular(10), + ), ), + onPressed: onPressed, + style: isActive ? ButtonVariance.primary : ButtonVariance.outline, + child: Text(name), ); } } diff --git a/lib/pages/settings/sections/appearance.dart b/lib/pages/settings/sections/appearance.dart index aaa2ce8a..55a8f1ef 100644 --- a/lib/pages/settings/sections/appearance.dart +++ b/lib/pages/settings/sections/appearance.dart @@ -94,10 +94,11 @@ class SettingsAppearanceSection extends HookConsumerWidget { horizontal: 15, vertical: 5, ), - trailing: ColorTile.compact( + trailing: ColorChip( color: preferences.accentColorScheme, + name: preferences.accentColorScheme.name, onPressed: pickColorScheme(), - isActive: true, + isActive: false, ), onTap: pickColorScheme(), ), From e470f50e813b4f02c3036d8d800e28fc4970a944 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 19 Jan 2025 19:59:42 +0600 Subject: [PATCH 060/112] chore: remove xmas background from glance widget --- .../oss/krtirtho/spotube/glance/HomePlayerWidget.kt | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/HomePlayerWidget.kt b/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/HomePlayerWidget.kt index 013723c0..a20af959 100644 --- a/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/HomePlayerWidget.kt +++ b/android/app/src/main/kotlin/oss/krtirtho/spotube/glance/HomePlayerWidget.kt @@ -120,16 +120,6 @@ class HomePlayerWidget : GlanceAppWidget() { } , ) { - Image( - provider = FlutterAssetImageProvider( - context, - "assets/backgrounds/xmas-effect.png" - ), - contentDescription = "Background", - modifier = GlanceModifier - .fillMaxSize(), - contentScale = ContentScale.Crop - ) Box( modifier = GlanceModifier .background( From 74a328e52916ba587e03d4e63818bc26f2d98e2d Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 19 Jan 2025 21:00:49 +0600 Subject: [PATCH 061/112] refactor: logs page to shadcn --- lib/l10n/app_en.arb | 3 +- lib/pages/settings/logs.dart | 106 +++++++++++++++---------- lib/pages/settings/sections/about.dart | 32 +++++--- lib/provider/logs/logs_provider.dart | 5 ++ pubspec.yaml | 1 + untranslated_messages.json | 78 ++++++++++++------ 6 files changed, 144 insertions(+), 81 deletions(-) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 9a0f1814..ae7abb01 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -414,5 +414,6 @@ "no_tracks": "Looks like there are no tracks here", "no_tracks_listened_yet": "Looks like you haven't listened to anything yet", "not_following_artists": "You're not following any artists", - "no_favorite_albums_yet": "Looks like you haven't added any albums to your favorites yet" + "no_favorite_albums_yet": "Looks like you haven't added any albums to your favorites yet", + "no_logs_found": "No logs found" } \ No newline at end of file diff --git a/lib/pages/settings/logs.dart b/lib/pages/settings/logs.dart index 0f1260aa..f9439317 100644 --- a/lib/pages/settings/logs.dart +++ b/lib/pages/settings/logs.dart @@ -1,8 +1,11 @@ -import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:flutter_undraw/flutter_undraw.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/button/back_button.dart'; import 'package:spotube/components/inter_scrollbar/inter_scrollbar.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/extensions/context.dart'; @@ -21,54 +24,73 @@ class LogsPage extends HookConsumerWidget { final logsQuery = ref.watch(logsProvider); return Scaffold( - appBar: TitleBar( - title: Text(context.l10n.logs), - leading: const [BackButton()], - trailing: [ - IconButton( - icon: const Icon(SpotubeIcons.clipboard), - iconSize: 16, - onPressed: () async { - final logsSnapshot = await ref.read(logsProvider.future); + headers: [ + TitleBar( + title: Text(context.l10n.logs), + leading: const [BackButton()], + trailing: [ + IconButton.ghost( + icon: const Icon(SpotubeIcons.clipboard, size: 16), + onPressed: () async { + final logsSnapshot = await ref.read(logsProvider.future); - await Clipboard.setData(ClipboardData(text: logsSnapshot)); - if (context.mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(context.l10n.copied_to_clipboard("")), - ), - ); - } - }, - ), - IconButton( - icon: const Icon(SpotubeIcons.trash), - iconSize: 16, - onPressed: () async { - ref.invalidate(logsProvider); + await Clipboard.setData(ClipboardData(text: logsSnapshot)); + if (context.mounted) { + showToast( + context: context, + location: ToastLocation.topRight, + builder: (context, overlay) { + return SurfaceCard( + child: Basic( + title: Text(context.l10n.copied_to_clipboard("")), + ), + ); + }, + ); + } + }, + ), + IconButton.ghost( + icon: const Icon( + SpotubeIcons.trash, + size: 16, + ), + onPressed: () async { + ref.invalidate(logsProvider); - final logsFile = await AppLogger.getLogsPath(); + final logsFile = await AppLogger.getLogsPath(); - await logsFile.writeAsString(""); - }, - ) - ], - ), - body: SafeArea( + await logsFile.writeAsString(""); + }, + ) + ], + ) + ], + child: SafeArea( child: switch (logsQuery) { - AsyncData(:final value) => Card( - child: InterScrollbar( + AsyncData(:final value) => InterScrollbar( + controller: controller, + child: SingleChildScrollView( + padding: const EdgeInsets.all(8.0), controller: controller, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: SingleChildScrollView( - controller: controller, - child: Text(value), - ), - ), + child: Card(child: SelectableText(value)), ), ), - AsyncError(:final error) => Center(child: Text(error.toString())), + AsyncError(:final error) => switch (error) { + StateError() => Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Undraw( + illustration: UndrawIllustration.noData, + height: 200 * context.theme.scaling, + width: 200 * context.theme.scaling, + color: context.theme.colorScheme.primary, + ), + Text(context.l10n.no_logs_found).muted().small(), + ], + ), + _ => Center(child: Text(error.toString())), + }, _ => const Center(child: CircularProgressIndicator()), }, ), diff --git a/lib/pages/settings/sections/about.dart b/lib/pages/settings/sections/about.dart index 5910fc1b..5ed26ee8 100644 --- a/lib/pages/settings/sections/about.dart +++ b/lib/pages/settings/sections/about.dart @@ -1,9 +1,8 @@ import 'package:auto_size_text/auto_size_text.dart'; -import 'package:flutter/material.dart' show FilledButton, ButtonStyle, ListTile; +import 'package:flutter/material.dart' show ListTile; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart' hide ButtonStyle; -import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/collections/env.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/modules/settings/section_card_with_heading.dart'; @@ -44,16 +43,25 @@ class SettingsAboutSection extends HookConsumerWidget { ), ), ), - trailing: (context, update) => FilledButton( - style: ButtonStyle( - backgroundColor: WidgetStatePropertyAll(Colors.red[100]), - foregroundColor: const WidgetStatePropertyAll(Colors.pink), - padding: const WidgetStatePropertyAll(EdgeInsets.all(15)), - shape: WidgetStatePropertyAll( - RoundedRectangleBorder( - borderRadius: context.theme.borderRadiusLg, - ), - ), + trailing: (context, update) => Button( + style: ButtonVariance.primary.copyWith( + decoration: (context, states, value) { + final decoration = ButtonVariance.primary + .decoration(context, states) as BoxDecoration; + + if (states.contains(WidgetState.hovered)) { + return decoration.copyWith(color: Colors.pink[400]); + } else if (states.contains(WidgetState.focused)) { + return decoration.copyWith(color: Colors.pink[300]); + } else if (states.isNotEmpty) { + return decoration; + } + + return decoration.copyWith(color: Colors.pink); + }, + textStyle: (context, states, value) => ButtonVariance.primary + .textStyle(context, states) + .copyWith(color: Colors.white), ), onPressed: () { launchUrlString( diff --git a/lib/provider/logs/logs_provider.dart b/lib/provider/logs/logs_provider.dart index b0e95cae..571d96cc 100644 --- a/lib/provider/logs/logs_provider.dart +++ b/lib/provider/logs/logs_provider.dart @@ -6,6 +6,11 @@ import 'package:spotube/services/logger/logger.dart'; final logsProvider = StreamProvider.autoDispose((ref) async* { final file = await AppLogger.getLogsPath(); final stream = file.openRead().transform(utf8.decoder); + + if (await stream.isEmpty) { + throw StateError('No logs found'); + } + await for (final line in stream) { yield line; } diff --git a/pubspec.yaml b/pubspec.yaml index 1594abb2..3c20981b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -188,6 +188,7 @@ flutter: - packages/flutter_undraw/assets/undraw/follow_me_drone.svg - packages/flutter_undraw/assets/undraw/taken.svg - packages/flutter_undraw/assets/undraw/empty.svg + - packages/flutter_undraw/assets/undraw/no_data.svg fonts: - family: GeistSans fonts: diff --git a/untranslated_messages.json b/untranslated_messages.json index b00b1fd4..810c3125 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -14,7 +14,8 @@ "no_tracks", "no_tracks_listened_yet", "not_following_artists", - "no_favorite_albums_yet" + "no_favorite_albums_yet", + "no_logs_found" ], "bn": [ @@ -32,7 +33,8 @@ "no_tracks", "no_tracks_listened_yet", "not_following_artists", - "no_favorite_albums_yet" + "no_favorite_albums_yet", + "no_logs_found" ], "ca": [ @@ -50,7 +52,8 @@ "no_tracks", "no_tracks_listened_yet", "not_following_artists", - "no_favorite_albums_yet" + "no_favorite_albums_yet", + "no_logs_found" ], "cs": [ @@ -68,7 +71,8 @@ "no_tracks", "no_tracks_listened_yet", "not_following_artists", - "no_favorite_albums_yet" + "no_favorite_albums_yet", + "no_logs_found" ], "de": [ @@ -86,7 +90,8 @@ "no_tracks", "no_tracks_listened_yet", "not_following_artists", - "no_favorite_albums_yet" + "no_favorite_albums_yet", + "no_logs_found" ], "es": [ @@ -104,7 +109,8 @@ "no_tracks", "no_tracks_listened_yet", "not_following_artists", - "no_favorite_albums_yet" + "no_favorite_albums_yet", + "no_logs_found" ], "eu": [ @@ -122,7 +128,8 @@ "no_tracks", "no_tracks_listened_yet", "not_following_artists", - "no_favorite_albums_yet" + "no_favorite_albums_yet", + "no_logs_found" ], "fa": [ @@ -140,7 +147,8 @@ "no_tracks", "no_tracks_listened_yet", "not_following_artists", - "no_favorite_albums_yet" + "no_favorite_albums_yet", + "no_logs_found" ], "fi": [ @@ -158,7 +166,8 @@ "no_tracks", "no_tracks_listened_yet", "not_following_artists", - "no_favorite_albums_yet" + "no_favorite_albums_yet", + "no_logs_found" ], "fr": [ @@ -176,7 +185,8 @@ "no_tracks", "no_tracks_listened_yet", "not_following_artists", - "no_favorite_albums_yet" + "no_favorite_albums_yet", + "no_logs_found" ], "hi": [ @@ -194,7 +204,8 @@ "no_tracks", "no_tracks_listened_yet", "not_following_artists", - "no_favorite_albums_yet" + "no_favorite_albums_yet", + "no_logs_found" ], "id": [ @@ -212,7 +223,8 @@ "no_tracks", "no_tracks_listened_yet", "not_following_artists", - "no_favorite_albums_yet" + "no_favorite_albums_yet", + "no_logs_found" ], "it": [ @@ -230,7 +242,8 @@ "no_tracks", "no_tracks_listened_yet", "not_following_artists", - "no_favorite_albums_yet" + "no_favorite_albums_yet", + "no_logs_found" ], "ja": [ @@ -248,7 +261,8 @@ "no_tracks", "no_tracks_listened_yet", "not_following_artists", - "no_favorite_albums_yet" + "no_favorite_albums_yet", + "no_logs_found" ], "ka": [ @@ -266,7 +280,8 @@ "no_tracks", "no_tracks_listened_yet", "not_following_artists", - "no_favorite_albums_yet" + "no_favorite_albums_yet", + "no_logs_found" ], "ko": [ @@ -284,7 +299,8 @@ "no_tracks", "no_tracks_listened_yet", "not_following_artists", - "no_favorite_albums_yet" + "no_favorite_albums_yet", + "no_logs_found" ], "ne": [ @@ -302,7 +318,8 @@ "no_tracks", "no_tracks_listened_yet", "not_following_artists", - "no_favorite_albums_yet" + "no_favorite_albums_yet", + "no_logs_found" ], "nl": [ @@ -320,7 +337,8 @@ "no_tracks", "no_tracks_listened_yet", "not_following_artists", - "no_favorite_albums_yet" + "no_favorite_albums_yet", + "no_logs_found" ], "pl": [ @@ -338,7 +356,8 @@ "no_tracks", "no_tracks_listened_yet", "not_following_artists", - "no_favorite_albums_yet" + "no_favorite_albums_yet", + "no_logs_found" ], "pt": [ @@ -356,7 +375,8 @@ "no_tracks", "no_tracks_listened_yet", "not_following_artists", - "no_favorite_albums_yet" + "no_favorite_albums_yet", + "no_logs_found" ], "ru": [ @@ -374,7 +394,8 @@ "no_tracks", "no_tracks_listened_yet", "not_following_artists", - "no_favorite_albums_yet" + "no_favorite_albums_yet", + "no_logs_found" ], "th": [ @@ -392,7 +413,8 @@ "no_tracks", "no_tracks_listened_yet", "not_following_artists", - "no_favorite_albums_yet" + "no_favorite_albums_yet", + "no_logs_found" ], "tr": [ @@ -410,7 +432,8 @@ "no_tracks", "no_tracks_listened_yet", "not_following_artists", - "no_favorite_albums_yet" + "no_favorite_albums_yet", + "no_logs_found" ], "uk": [ @@ -428,7 +451,8 @@ "no_tracks", "no_tracks_listened_yet", "not_following_artists", - "no_favorite_albums_yet" + "no_favorite_albums_yet", + "no_logs_found" ], "vi": [ @@ -446,7 +470,8 @@ "no_tracks", "no_tracks_listened_yet", "not_following_artists", - "no_favorite_albums_yet" + "no_favorite_albums_yet", + "no_logs_found" ], "zh": [ @@ -464,6 +489,7 @@ "no_tracks", "no_tracks_listened_yet", "not_following_artists", - "no_favorite_albums_yet" + "no_favorite_albums_yet", + "no_logs_found" ] } From 086107b2cd9ecf0c7e20d1086f813cf3ba855f43 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 20 Jan 2025 13:24:24 +0600 Subject: [PATCH 062/112] refactor: adaptive list tile to use shadcn --- .../adaptive/adaptive_list_tile.dart | 57 +++++++++---------- lib/pages/settings/sections/about.dart | 10 +--- 2 files changed, 30 insertions(+), 37 deletions(-) diff --git a/lib/components/adaptive/adaptive_list_tile.dart b/lib/components/adaptive/adaptive_list_tile.dart index 33df44c1..c6d00bd4 100644 --- a/lib/components/adaptive/adaptive_list_tile.dart +++ b/lib/components/adaptive/adaptive_list_tile.dart @@ -1,5 +1,6 @@ -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:spotube/components/ui/button_tile.dart'; import 'package:spotube/extensions/constrains.dart'; class AdaptiveListTile extends HookWidget { @@ -24,41 +25,39 @@ class AdaptiveListTile extends HookWidget { Widget build(BuildContext context) { final mediaQuery = MediaQuery.of(context); - return ListTile( + return ButtonTile( title: title, subtitle: subtitle, trailing: breakOn ?? mediaQuery.smAndDown ? null : trailing?.call(context, null), leading: leading, - onTap: breakOn ?? mediaQuery.smAndDown - ? () { - onTap?.call(); - showDialog( - context: context, - barrierDismissible: true, - builder: (context) { - return StatefulBuilder(builder: (context, update) { - return AlertDialog( - title: title != null - ? Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - if (leading != null) ...[ - leading!, - const SizedBox(width: 5) - ], - Flexible(child: title!), - ], - ) - : Container(), - content: trailing?.call(context, update), - ); - }); - }, + enabled: breakOn ?? mediaQuery.smAndDown, + onPressed: () { + onTap?.call(); + showDialog( + context: context, + barrierDismissible: true, + builder: (context) { + return StatefulBuilder(builder: (context, update) { + return AlertDialog( + title: title != null + ? Row( + crossAxisAlignment: CrossAxisAlignment.center, + spacing: 5, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (leading != null) leading!, + Flexible(child: title!), + ], + ) + : const SizedBox.shrink(), + content: Center(child: trailing?.call(context, update)), ); - } - : null, + }); + }, + ); + }, ); } } diff --git a/lib/pages/settings/sections/about.dart b/lib/pages/settings/sections/about.dart index 5ed26ee8..7f5d3977 100644 --- a/lib/pages/settings/sections/about.dart +++ b/lib/pages/settings/sections/about.dart @@ -69,14 +69,8 @@ class SettingsAboutSection extends HookConsumerWidget { mode: LaunchMode.externalApplication, ); }, - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - const Icon(SpotubeIcons.heart), - const SizedBox(width: 5), - Text(context.l10n.please_sponsor), - ], - ), + leading: const Icon(SpotubeIcons.heart), + child: Text(context.l10n.please_sponsor), ), ), if (Env.enableUpdateChecker) From 4fead5f504273699f951f9f29a1713f1a6905a65 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 20 Jan 2025 22:04:12 +0600 Subject: [PATCH 063/112] feat: pause playback when no internet connection --- lib/modules/root/use_downloader_dialogs.dart | 46 ++++++ .../root/use_global_subscriptions.dart | 127 +++++++++++++++ lib/pages/root/root_app.dart | 144 +----------------- lib/provider/audio_player/audio_player.dart | 2 +- lib/services/connectivity_adapter.dart | 12 +- .../sourced_track/sources/youtube.dart | 13 +- macos/Flutter/GeneratedPluginRegistrant.swift | 2 + macos/Podfile.lock | 7 + pubspec.lock | 24 +++ pubspec.yaml | 1 + .../flutter/generated_plugin_registrant.cc | 3 + windows/flutter/generated_plugins.cmake | 1 + 12 files changed, 233 insertions(+), 149 deletions(-) create mode 100644 lib/modules/root/use_downloader_dialogs.dart create mode 100644 lib/modules/root/use_global_subscriptions.dart diff --git a/lib/modules/root/use_downloader_dialogs.dart b/lib/modules/root/use_downloader_dialogs.dart new file mode 100644 index 00000000..e2f91043 --- /dev/null +++ b/lib/modules/root/use_downloader_dialogs.dart @@ -0,0 +1,46 @@ +import 'dart:async'; + +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:spotube/components/dialogs/replace_downloaded_dialog.dart'; +import 'package:spotube/provider/download_manager_provider.dart'; + +void useDownloaderDialogs(WidgetRef ref) { + final context = useContext(); + final showingDialogCompleter = useRef(Completer()..complete()); + final downloader = ref.watch(downloadManagerProvider); + + useEffect(() { + downloader.onFileExists = (track) async { + if (!context.mounted) return false; + + if (!showingDialogCompleter.value.isCompleted) { + await showingDialogCompleter.value.future; + } + + final replaceAll = ref.read(replaceDownloadedFileState); + + if (replaceAll != null) return replaceAll; + + showingDialogCompleter.value = Completer(); + + if (context.mounted) { + final result = await showDialog( + context: context, + builder: (context) => ReplaceDownloadedDialog( + track: track, + ), + ) ?? + false; + + showingDialogCompleter.value.complete(); + return result; + } + + // it'll never reach here as root_app is always mounted + return false; + }; + return null; + }, [downloader]); +} diff --git a/lib/modules/root/use_global_subscriptions.dart b/lib/modules/root/use_global_subscriptions.dart new file mode 100644 index 00000000..e0e4dae7 --- /dev/null +++ b/lib/modules/root/use_global_subscriptions.dart @@ -0,0 +1,127 @@ +import 'dart:async'; + +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/extensions/context.dart'; +import 'package:spotube/provider/server/routes/connect.dart'; +import 'package:spotube/services/audio_player/audio_player.dart'; +import 'package:spotube/services/connectivity_adapter.dart'; +import 'package:spotube/utils/service_utils.dart'; + +void useGlobalSubscriptions(WidgetRef ref) { + final context = useContext(); + final theme = Theme.of(context); + final connectRoutes = ref.watch(serverConnectRoutesProvider); + + useEffect(() { + WidgetsBinding.instance.addPostFrameCallback((_) async { + ServiceUtils.checkForUpdates(context, ref); + }); + + StreamSubscription? audioPlayerSubscription; + bool pausedByStream = false; + + final subscriptions = [ + ConnectionCheckerService.instance.onConnectivityChanged + .listen((connected) async { + audioPlayerSubscription?.cancel(); + + /// Pausing or resuming based on connectivity to avoid MPV skipping + /// audio while retrying to connect + if (audioPlayer.currentIndex >= 0) { + if (connected && audioPlayer.isPaused && pausedByStream) { + await audioPlayer.resume(); + pausedByStream = false; + } else if (!connected && audioPlayer.isPlaying) { + if ((audioPlayer.bufferedPosition - const Duration(seconds: 1)) <= + audioPlayer.position) { + await audioPlayer.pause(); + pausedByStream = true; + } else { + audioPlayerSubscription = + audioPlayer.positionStream.listen((position) async { + if (ConnectionCheckerService.instance.isConnectedSync) return; + + final bufferedPosition = + audioPlayer.bufferedPosition - const Duration(seconds: 1); + final duration = + audioPlayer.duration - const Duration(seconds: 1); + + if (bufferedPosition <= position || position >= duration) { + audioPlayer.pause(); + pausedByStream = true; + } + }); + } + } + } + + // Show notification for connection related issues + if (!context.mounted) return; + + showToast( + context: context, + location: ToastLocation.bottomCenter, + builder: (context, overlay) { + if (connected) { + return SurfaceCard( + child: Basic( + leading: const Icon(SpotubeIcons.wifi), + title: Text(context.l10n.connection_restored), + ), + ); + } + + return SurfaceCard( + fillColor: theme.colorScheme.destructive, + filled: true, + child: Basic( + leading: Icon( + SpotubeIcons.noWifi, + color: theme.colorScheme.destructiveForeground, + ), + trailing: Text( + context.l10n.you_are_offline, + style: TextStyle( + color: theme.colorScheme.destructiveForeground, + ), + ), + ), + ); + }, + ); + }), + connectRoutes.connectClientStream.listen((clientOrigin) { + if (!context.mounted) return; + showToast( + context: context, + location: ToastLocation.topRight, + builder: (context, overlay) { + return SurfaceCard( + fillColor: Colors.yellow[600], + filled: true, + child: Basic( + leading: const Icon( + SpotubeIcons.error, + color: Colors.black, + ), + title: Text( + context.l10n.connect_client_alert(clientOrigin), + style: const TextStyle(color: Colors.black), + ), + ), + ); + }, + ); + }) + ]; + + return () { + for (final subscription in subscriptions) { + subscription.cancel(); + } + }; + }, []); +} diff --git a/lib/pages/root/root_app.dart b/lib/pages/root/root_app.dart index cdb56910..2a1bf088 100644 --- a/lib/pages/root/root_app.dart +++ b/lib/pages/root/root_app.dart @@ -1,26 +1,20 @@ -import 'dart:async'; - import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/side_bar_tiles.dart'; -import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/framework/app_pop_scope.dart'; -import 'package:spotube/components/dialogs/replace_downloaded_dialog.dart'; import 'package:spotube/modules/root/bottom_player.dart'; import 'package:spotube/modules/root/sidebar.dart'; import 'package:spotube/modules/root/spotube_navigation_bar.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/hooks/configurators/use_endless_playback.dart'; +import 'package:spotube/modules/root/use_downloader_dialogs.dart'; +import 'package:spotube/modules/root/use_global_subscriptions.dart'; import 'package:spotube/pages/home/home.dart'; -import 'package:spotube/provider/download_manager_provider.dart'; import 'package:spotube/provider/glance/glance.dart'; -import 'package:spotube/provider/server/routes/connect.dart'; -import 'package:spotube/services/connectivity_adapter.dart'; import 'package:spotube/utils/platform.dart'; -import 'package:spotube/utils/service_utils.dart'; class RootApp extends HookConsumerWidget { final Widget child; @@ -31,138 +25,14 @@ class RootApp extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final theme = Theme.of(context); - - final showingDialogCompleter = useRef(Completer()..complete()); - final downloader = ref.watch(downloadManagerProvider); - - final connectRoutes = ref.watch(serverConnectRoutesProvider); - - ref.listen(glanceProvider, (_, __) {}); - - useEffect(() { - WidgetsBinding.instance.addPostFrameCallback((_) async { - ServiceUtils.checkForUpdates(context, ref); - }); - - final subscriptions = [ - ConnectionCheckerService.instance.onConnectivityChanged - .listen((status) { - if (!context.mounted) return; - if (status) { - showToast( - context: context, - builder: (context, overlay) { - return SurfaceCard( - fillColor: theme.colorScheme.primary, - child: Row( - children: [ - Icon( - SpotubeIcons.wifi, - color: theme.colorScheme.primaryForeground, - ), - const SizedBox(width: 10), - Text(context.l10n.connection_restored), - ], - ), - ); - }, - ); - } else { - showToast( - context: context, - builder: (context, overlay) { - return SurfaceCard( - fillColor: theme.colorScheme.destructive, - child: Row( - children: [ - Icon( - SpotubeIcons.noWifi, - color: theme.colorScheme.destructiveForeground, - ), - const SizedBox(width: 10), - Text(context.l10n.you_are_offline), - ], - ), - ); - }, - ); - } - }), - connectRoutes.connectClientStream.listen((clientOrigin) { - if (!context.mounted) return; - showToast( - context: context, - builder: (context, overlay) { - return SurfaceCard( - fillColor: Colors.yellow[600], - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - const Icon( - SpotubeIcons.error, - color: Colors.black, - ), - const SizedBox(width: 10), - Text( - context.l10n.connect_client_alert(clientOrigin), - style: const TextStyle(color: Colors.black), - ), - ], - ), - ); - }, - ); - }) - ]; - - return () { - for (final subscription in subscriptions) { - subscription.cancel(); - } - }; - }, []); - - useEffect(() { - downloader.onFileExists = (track) async { - if (!context.mounted) return false; - - if (!showingDialogCompleter.value.isCompleted) { - await showingDialogCompleter.value.future; - } - - final replaceAll = ref.read(replaceDownloadedFileState); - - if (replaceAll != null) return replaceAll; - - showingDialogCompleter.value = Completer(); - - if (context.mounted) { - final result = await showDialog( - context: context, - builder: (context) => ReplaceDownloadedDialog( - track: track, - ), - ) ?? - false; - - showingDialogCompleter.value.complete(); - return result; - } - - // it'll never reach here as root_app is always mounted - return false; - }; - return null; - }, [downloader]); - - // checks for latest version of the application - - useEndlessPlayback(ref); - final backgroundColor = Theme.of(context).colorScheme.background; final brightness = Theme.of(context).brightness; + ref.listen(glanceProvider, (_, __) {}); + useGlobalSubscriptions(ref); + useDownloaderDialogs(ref); + useEndlessPlayback(ref); + useEffect(() { SystemChrome.setSystemUIOverlayStyle( SystemUiOverlayStyle( diff --git a/lib/provider/audio_player/audio_player.dart b/lib/provider/audio_player/audio_player.dart index 170cbb12..aa93bd4f 100644 --- a/lib/provider/audio_player/audio_player.dart +++ b/lib/provider/audio_player/audio_player.dart @@ -45,7 +45,7 @@ class AudioPlayerNotifier extends Notifier { var playlist = await database.select(database.playlistTable).getSingleOrNull(); - var medias = await database.select(database.playlistMediaTable).get(); + final medias = await database.select(database.playlistMediaTable).get(); if (playlist == null) { await database.into(database.playlistTable).insert( diff --git a/lib/services/connectivity_adapter.dart b/lib/services/connectivity_adapter.dart index 86765671..478890df 100644 --- a/lib/services/connectivity_adapter.dart +++ b/lib/services/connectivity_adapter.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'dart:io'; +import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:dio/dio.dart'; import 'package:flutter/widgets.dart'; import 'package:spotube/services/logger/logger.dart'; @@ -34,6 +35,10 @@ class ConnectionCheckerService with WidgetsBindingObserver { AppLogger.reportError(e, stack); } }); + + Connectivity().onConnectivityChanged.listen((event) async { + await isConnected; + }); } @override @@ -77,8 +82,9 @@ class ConnectionCheckerService with WidgetsBindingObserver { } return interfaces.any( - (interface) => - vpnNames.any((name) => interface.name.toLowerCase().contains(name)), + (interface) => vpnNames.any( + (name) => interface.name.toLowerCase().contains(name), + ), ); } @@ -109,10 +115,10 @@ class ConnectionCheckerService with WidgetsBindingObserver { Future get isConnected async { final connected = await _isConnected(); - isConnectedSync = connected; if (connected != isConnectedSync /*previous value*/) { _connectionStreamController.add(connected); } + isConnectedSync = connected; return connected; } diff --git a/lib/services/sourced_track/sources/youtube.dart b/lib/services/sourced_track/sources/youtube.dart index 0b5ee71b..1bafb705 100644 --- a/lib/services/sourced_track/sources/youtube.dart +++ b/lib/services/sourced_track/sources/youtube.dart @@ -82,14 +82,11 @@ class YoutubeSourcedTrack extends SourcedTrack { ); } final item = await youtubeClient.videos.get(cachedSource.sourceId); - final manifest = await youtubeClient.videos.streamsClient - .getManifest( - cachedSource.sourceId, - ) - .timeout( - const Duration(seconds: 5), - onTimeout: () => throw ClientException("Timeout"), - ); + final manifest = await youtubeClient.videos.streamsClient.getManifest( + cachedSource.sourceId, + requireWatchPage: false, + ytClients: [YoutubeApiClient.tv], + ); return YoutubeSourcedTrack( ref: ref, siblings: [], diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 608a854e..b92d7882 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -9,6 +9,7 @@ import app_links import audio_service import audio_session import bonsoir_darwin +import connectivity_plus import desktop_webview_window import device_info_plus import file_selector_macos @@ -33,6 +34,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { AudioServicePlugin.register(with: registry.registrar(forPlugin: "AudioServicePlugin")) AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin")) SwiftBonsoirPlugin.register(with: registry.registrar(forPlugin: "SwiftBonsoirPlugin")) + ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin")) DesktopWebviewWindowPlugin.register(with: registry.registrar(forPlugin: "DesktopWebviewWindowPlugin")) DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) diff --git a/macos/Podfile.lock b/macos/Podfile.lock index bdf530f1..44da1f81 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -8,6 +8,9 @@ PODS: - bonsoir_darwin (0.0.1): - Flutter - FlutterMacOS + - connectivity_plus (0.0.1): + - Flutter + - FlutterMacOS - desktop_webview_window (0.0.1): - FlutterMacOS - device_info_plus (0.0.1): @@ -79,6 +82,7 @@ DEPENDENCIES: - audio_service (from `Flutter/ephemeral/.symlinks/plugins/audio_service/macos`) - audio_session (from `Flutter/ephemeral/.symlinks/plugins/audio_session/macos`) - bonsoir_darwin (from `Flutter/ephemeral/.symlinks/plugins/bonsoir_darwin/darwin`) + - connectivity_plus (from `Flutter/ephemeral/.symlinks/plugins/connectivity_plus/darwin`) - desktop_webview_window (from `Flutter/ephemeral/.symlinks/plugins/desktop_webview_window/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`) @@ -116,6 +120,8 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral/.symlinks/plugins/audio_session/macos bonsoir_darwin: :path: Flutter/ephemeral/.symlinks/plugins/bonsoir_darwin/darwin + connectivity_plus: + :path: Flutter/ephemeral/.symlinks/plugins/connectivity_plus/darwin desktop_webview_window: :path: Flutter/ephemeral/.symlinks/plugins/desktop_webview_window/macos device_info_plus: @@ -166,6 +172,7 @@ SPEC CHECKSUMS: audio_service: b88ff778e0e3915efd4cd1a5ad6f0beef0c950a9 audio_session: dea1f41890dbf1718f04a56f1d6150fd50039b72 bonsoir_darwin: e3b8526c42ca46a885142df84229131dfabea842 + connectivity_plus: 18382e7311ba19efcaee94442b23b32507b20695 desktop_webview_window: 89bb3d691f4c80314a10be312f4cd35db93a9d5a device_info_plus: 1b14eed9bf95428983aed283a8d51cce3d8c4215 file_selector_macos: cc3858c981fe6889f364731200d6232dac1d812d diff --git a/pubspec.lock b/pubspec.lock index 2fa1d8ab..09bc1361 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -375,6 +375,22 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.0" + connectivity_plus: + dependency: "direct main" + description: + name: connectivity_plus + sha256: "8a68739d3ee113e51ad35583fdf9ab82c55d09d693d3c39da1aebab87c938412" + url: "https://pub.dev" + source: hosted + version: "6.1.2" + connectivity_plus_platform_interface: + dependency: transitive + description: + name: connectivity_plus_platform_interface + sha256: "42657c1715d48b167930d5f34d00222ac100475f73d10162ddf43e714932f204" + url: "https://pub.dev" + source: hosted + version: "2.0.1" convert: dependency: transitive description: @@ -1542,6 +1558,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.6" + nm: + dependency: transitive + description: + name: nm + sha256: "2c9aae4127bdc8993206464fcc063611e0e36e72018696cd9631023a31b24254" + url: "https://pub.dev" + source: hosted + version: "0.5.0" node_preamble: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 3c20981b..b9e44021 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -23,6 +23,7 @@ dependencies: bonsoir: ^5.1.10 cached_network_image: ^3.3.1 collection: ^1.18.0 + connectivity_plus: ^6.1.2 desktop_webview_window: git: path: packages/desktop_webview_window diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 42fa2129..d1bee122 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -27,6 +28,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("AppLinksPluginCApi")); BonsoirWindowsPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("BonsoirWindowsPluginCApi")); + ConnectivityPlusWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin")); DesktopWebviewWindowPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("DesktopWebviewWindowPlugin")); FileSelectorWindowsRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index cf14ec52..32c8a634 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -5,6 +5,7 @@ list(APPEND FLUTTER_PLUGIN_LIST app_links bonsoir_windows + connectivity_plus desktop_webview_window file_selector_windows flutter_inappwebview_windows From 2411f468777fa91aa5a868563cb75b6fe1cfd00f Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Tue, 21 Jan 2025 10:15:06 +0600 Subject: [PATCH 064/112] fix: youtube video unplayable issue and use more ytClients --- lib/services/connectivity_adapter.dart | 3 +- lib/services/logger/logger.dart | 34 +++++++++++++++++++ .../sourced_track/sources/youtube.dart | 24 +++++++++---- pubspec.lock | 2 +- pubspec.yaml | 1 + 5 files changed, 56 insertions(+), 8 deletions(-) diff --git a/lib/services/connectivity_adapter.dart b/lib/services/connectivity_adapter.dart index 478890df..f6b760c8 100644 --- a/lib/services/connectivity_adapter.dart +++ b/lib/services/connectivity_adapter.dart @@ -20,6 +20,7 @@ class ConnectionCheckerService with WidgetsBindingObserver { onConnectivityChanged.listen((connected) { try { if (!connected && timer == null) { + // check every 30 seconds if we are connected when we are not connected timer = Timer.periodic(const Duration(seconds: 30), (timer) async { if (WidgetsBinding.instance.lifecycleState == AppLifecycleState.paused) { @@ -111,7 +112,7 @@ class ConnectionCheckerService with WidgetsBindingObserver { await isVpnActive(); // when VPN is active that means we are connected } - bool isConnectedSync = false; + bool isConnectedSync = true; Future get isConnected async { final connected = await _isConnected(); diff --git a/lib/services/logger/logger.dart b/lib/services/logger/logger.dart index 1df7b5aa..46fc6de5 100644 --- a/lib/services/logger/logger.dart +++ b/lib/services/logger/logger.dart @@ -9,6 +9,20 @@ import 'package:logger/logger.dart'; import 'package:path/path.dart'; import 'package:path_provider/path_provider.dart'; import 'package:spotube/utils/platform.dart'; +import 'package:logging/logging.dart' as logging; + +final _loggingToLoggerLevel = { + logging.Level.ALL: Level.all, + logging.Level.FINEST: Level.trace, + logging.Level.FINER: Level.debug, + logging.Level.FINE: Level.info, + logging.Level.CONFIG: Level.info, + logging.Level.INFO: Level.info, + logging.Level.WARNING: Level.warning, + logging.Level.SEVERE: Level.error, + logging.Level.SHOUT: Level.fatal, + logging.Level.OFF: Level.off, +}; class AppLogger { static late final Logger log; @@ -20,6 +34,24 @@ class AppLogger { ); } + static void _initInternalPackageLoggers() { + if (!kDebugMode) return; + logging.hierarchicalLoggingEnabled = true; + logging.Logger('YoutubeExplode.StreamsClient') + ..level = logging.Level.ALL + ..onRecord.listen( + (record) { + log.log( + _loggingToLoggerLevel[record.level] ?? Level.info, + record.message, + error: record.error, + stackTrace: record.stackTrace, + time: record.time, + ); + }, + ); + } + static R? runZoned(R Function() body) { return runZonedGuarded( () { @@ -46,6 +78,8 @@ class AppLogger { ); } + _initInternalPackageLoggers(); + getLogsPath().then((value) => logFile = value); return body(); diff --git a/lib/services/sourced_track/sources/youtube.dart b/lib/services/sourced_track/sources/youtube.dart index 1bafb705..fa13a25d 100644 --- a/lib/services/sourced_track/sources/youtube.dart +++ b/lib/services/sourced_track/sources/youtube.dart @@ -85,7 +85,13 @@ class YoutubeSourcedTrack extends SourcedTrack { final manifest = await youtubeClient.videos.streamsClient.getManifest( cachedSource.sourceId, requireWatchPage: false, - ytClients: [YoutubeApiClient.tv], + ytClients: [ + YoutubeApiClient.mediaConnect, + YoutubeApiClient.ios, + YoutubeApiClient.android, + YoutubeApiClient.mweb, + YoutubeApiClient.tv, + ], ); return YoutubeSourcedTrack( ref: ref, @@ -138,11 +144,17 @@ class YoutubeSourcedTrack extends SourcedTrack { ) async { SourceMap? sourceMap; if (index == 0) { - final manifest = - await youtubeClient.videos.streamsClient.getManifest(item.id).timeout( - const Duration(seconds: 5), - onTimeout: () => throw ClientException("Timeout"), - ); + final manifest = await youtubeClient.videos.streamsClient.getManifest( + item.id, + requireWatchPage: false, + ytClients: [ + YoutubeApiClient.mediaConnect, + YoutubeApiClient.ios, + YoutubeApiClient.android, + YoutubeApiClient.mweb, + YoutubeApiClient.tv, + ], + ); sourceMap = toSourceMap(manifest); } diff --git a/pubspec.lock b/pubspec.lock index 09bc1361..1a35f9c9 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1423,7 +1423,7 @@ packages: source: hosted version: "2.5.0" logging: - dependency: transitive + dependency: "direct main" description: name: logging sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 diff --git a/pubspec.yaml b/pubspec.yaml index b9e44021..ed0d7ce5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -86,6 +86,7 @@ dependencies: json_annotation: ^4.8.1 local_notifier: ^0.1.6 logger: ^2.0.2 + logging: ^1.3.0 lrc: ^1.0.2 media_kit: ^1.1.10+1 media_kit_libs_audio: ^1.0.4 From 6e357230ac87c621c7823168b3db09ba171a5350 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Thu, 23 Jan 2025 20:34:04 +0600 Subject: [PATCH 065/112] refactor: use expanded sidebar tiles for library --- .vscode/launch.json | 11 ++ lib/collections/intents.dart | 31 +++++- lib/collections/routes.dart | 105 ++++++++++++------ lib/collections/side_bar_tiles.dart | 40 +++++-- lib/collections/spotube_icons.dart | 2 + .../presentation_state.dart | 2 +- .../sort_tracks_dropdown.dart | 2 +- lib/main.dart | 24 +++- lib/modules/connect/connect_device.dart | 12 ++ lib/modules/root/sidebar.dart | 99 +++++++++++++---- .../getting_started/getting_started.dart | 55 ++++----- lib/pages/library/library.dart | 92 +++++++-------- lib/pages/library/local_folder.dart | 3 +- .../library/user_albums.dart | 5 +- .../library/user_artists.dart | 5 +- .../library/user_downloads.dart | 5 +- .../library/user_local_tracks.dart | 5 +- .../library/user_playlists.dart | 5 +- lib/pages/lyrics/lyrics.dart | 86 ++++++-------- lib/utils/service_utils.dart | 2 +- macos/Podfile.lock | 52 ++++----- 21 files changed, 403 insertions(+), 240 deletions(-) rename lib/{modules => pages}/library/user_albums.dart (97%) rename lib/{modules => pages}/library/user_artists.dart (98%) rename lib/{modules => pages}/library/user_downloads.dart (92%) rename lib/{modules => pages}/library/user_local_tracks.dart (96%) rename lib/{modules => pages}/library/user_playlists.dart (97%) diff --git a/.vscode/launch.json b/.vscode/launch.json index 7a1e8b9b..deabf1d3 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -30,6 +30,17 @@ "request": "launch", "program": "lib/main.dart", "flutterMode": "release" + }, + { + "name": "spotube (mobile) (release)", + "type": "dart", + "request": "launch", + "program": "lib/main.dart", + "flutterMode": "release", + "args": [ + "--flavor", + "dev" + ] } ], "compounds": [] diff --git a/lib/collections/intents.dart b/lib/collections/intents.dart index 4f446831..1ec62812 100644 --- a/lib/collections/intents.dart +++ b/lib/collections/intents.dart @@ -7,7 +7,11 @@ import 'package:go_router/go_router.dart'; import 'package:spotube/collections/routes.dart'; import 'package:spotube/modules/player/player_controls.dart'; import 'package:spotube/pages/home/home.dart'; -import 'package:spotube/pages/library/library.dart'; +import 'package:spotube/pages/library/user_albums.dart'; +import 'package:spotube/pages/library/user_artists.dart'; +import 'package:spotube/pages/library/user_downloads.dart'; +import 'package:spotube/pages/library/user_local_tracks.dart'; +import 'package:spotube/pages/library/user_playlists.dart'; import 'package:spotube/pages/lyrics/lyrics.dart'; import 'package:spotube/pages/search/search.dart'; import 'package:spotube/provider/audio_player/querying_track_info.dart'; @@ -52,8 +56,13 @@ class NavigationAction extends Action { enum HomeTabs { browse, search, - library, + lyrics, + userPlaylists, + userArtists, + userAlbums, + userLocalLibrary, + userDownloads, } class HomeTabIntent extends Intent { @@ -73,12 +82,24 @@ class HomeTabAction extends Action { case HomeTabs.search: router.goNamed(SearchPage.name); break; - case HomeTabs.library: - router.goNamed(LibraryPage.name); - break; case HomeTabs.lyrics: router.goNamed(LyricsPage.name); break; + case HomeTabs.userPlaylists: + router.goNamed(UserPlaylistsPage.name); + break; + case HomeTabs.userArtists: + router.goNamed(UserArtistsPage.name); + break; + case HomeTabs.userAlbums: + router.goNamed(UserAlbumsPage.name); + break; + case HomeTabs.userLocalLibrary: + router.goNamed(UserLocalLibraryPage.name); + break; + case HomeTabs.userDownloads: + router.goNamed(UserDownloadsPage.name); + break; } return null; } diff --git a/lib/collections/routes.dart b/lib/collections/routes.dart index a0380e29..25cf995c 100644 --- a/lib/collections/routes.dart +++ b/lib/collections/routes.dart @@ -16,6 +16,11 @@ import 'package:spotube/pages/lastfm_login/lastfm_login.dart'; import 'package:spotube/pages/library/local_folder.dart'; import 'package:spotube/pages/library/playlist_generate/playlist_generate.dart'; import 'package:spotube/pages/library/playlist_generate/playlist_generate_result.dart'; +import 'package:spotube/pages/library/user_albums.dart'; +import 'package:spotube/pages/library/user_artists.dart'; +import 'package:spotube/pages/library/user_downloads.dart'; +import 'package:spotube/pages/library/user_local_tracks.dart'; +import 'package:spotube/pages/library/user_playlists.dart'; import 'package:spotube/pages/lyrics/mini_lyrics.dart'; import 'package:spotube/pages/playlist/liked_playlist.dart'; import 'package:spotube/pages/playlist/playlist.dart'; @@ -99,45 +104,73 @@ final routerProvider = Provider((ref) { pageBuilder: (context, state) => const SpotubePage(child: SearchPage()), ), + ShellRoute( + pageBuilder: (context, state, child) => + SpotubePage(child: LibraryPage(child: child)), + routes: [ + GoRoute( + path: "/library/playlists", + name: UserPlaylistsPage.name, + pageBuilder: (context, state) => + const SpotubePage(child: UserPlaylistsPage()), + ), + GoRoute( + path: "/library/artists", + name: UserArtistsPage.name, + pageBuilder: (context, state) => + const SpotubePage(child: UserArtistsPage()), + ), + GoRoute( + path: "/library/album", + name: UserAlbumsPage.name, + pageBuilder: (context, state) => + const SpotubePage(child: UserAlbumsPage()), + ), + GoRoute( + path: "/library/local", + name: UserLocalLibraryPage.name, + pageBuilder: (context, state) => + const SpotubePage(child: UserLocalLibraryPage()), + ), + GoRoute( + path: "/library/downloads", + name: UserDownloadsPage.name, + pageBuilder: (context, state) => + const SpotubePage(child: UserDownloadsPage()), + ), + ], + ), GoRoute( - path: "/library", - name: LibraryPage.name, - pageBuilder: (context, state) => - const SpotubePage(child: LibraryPage()), - routes: [ - GoRoute( - path: "generate", - name: PlaylistGeneratorPage.name, - pageBuilder: (context, state) => - const SpotubePage(child: PlaylistGeneratorPage()), - routes: [ - GoRoute( - path: "result", - name: PlaylistGenerateResultPage.name, - pageBuilder: (context, state) => SpotubePage( - child: PlaylistGenerateResultPage( - state: state.extra as GeneratePlaylistProviderInput, - ), - ), - ) - ], + path: "/library/generate", + name: PlaylistGeneratorPage.name, + pageBuilder: (context, state) => + const SpotubePage(child: PlaylistGeneratorPage()), + routes: [ + GoRoute( + path: "result", + name: PlaylistGenerateResultPage.name, + pageBuilder: (context, state) => SpotubePage( + child: PlaylistGenerateResultPage( + state: state.extra as GeneratePlaylistProviderInput, + ), ), - GoRoute( - path: "local", - name: LocalLibraryPage.name, - pageBuilder: (context, state) { - assert(state.extra is String); - return SpotubePage( - child: LocalLibraryPage( - state.extra as String, - isDownloads: - state.uri.queryParameters["downloads"] != null, - isCache: state.uri.queryParameters["cache"] != null, - ), - ); - }, + ) + ], + ), + GoRoute( + path: "/library/local", + name: LocalLibraryPage.name, + pageBuilder: (context, state) { + assert(state.extra is String); + return SpotubePage( + child: LocalLibraryPage( + state.extra as String, + isDownloads: state.uri.queryParameters["downloads"] != null, + isCache: state.uri.queryParameters["cache"] != null, ), - ]), + ); + }, + ), GoRoute( path: "/lyrics", name: LyricsPage.name, diff --git a/lib/collections/side_bar_tiles.dart b/lib/collections/side_bar_tiles.dart index 4f23c049..26396e39 100644 --- a/lib/collections/side_bar_tiles.dart +++ b/lib/collections/side_bar_tiles.dart @@ -2,7 +2,10 @@ import 'package:flutter/material.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:spotube/pages/home/home.dart'; -import 'package:spotube/pages/library/library.dart'; +import 'package:spotube/pages/library/user_albums.dart'; +import 'package:spotube/pages/library/user_artists.dart'; +import 'package:spotube/pages/library/user_local_tracks.dart'; +import 'package:spotube/pages/library/user_playlists.dart'; import 'package:spotube/pages/lyrics/lyrics.dart'; import 'package:spotube/pages/search/search.dart'; import 'package:spotube/pages/stats/stats.dart'; @@ -34,12 +37,6 @@ List getSidebarTileList(AppLocalizations l10n) => [ icon: SpotubeIcons.search, title: l10n.search, ), - SideBarTiles( - id: "library", - name: LibraryPage.name, - icon: SpotubeIcons.library, - title: l10n.library, - ), SideBarTiles( id: "lyrics", name: LyricsPage.name, @@ -54,6 +51,33 @@ List getSidebarTileList(AppLocalizations l10n) => [ ), ]; +List getSidebarLibraryTileList(AppLocalizations l10n) => [ + SideBarTiles( + id: "playlists", + title: l10n.playlists, + name: UserPlaylistsPage.name, + icon: SpotubeIcons.playlist, + ), + SideBarTiles( + id: "artists", + title: l10n.artists, + name: UserArtistsPage.name, + icon: SpotubeIcons.artist, + ), + SideBarTiles( + id: "albums", + title: l10n.albums, + name: UserAlbumsPage.name, + icon: SpotubeIcons.album, + ), + SideBarTiles( + id: "local_library", + title: l10n.local_library, + name: UserLocalLibraryPage.name, + icon: SpotubeIcons.device, + ), + ]; + List getNavbarTileList(AppLocalizations l10n) => [ SideBarTiles( id: "browse", @@ -69,7 +93,7 @@ List getNavbarTileList(AppLocalizations l10n) => [ ), SideBarTiles( id: "library", - name: LibraryPage.name, + name: UserPlaylistsPage.name, icon: SpotubeIcons.library, title: l10n.library, ), diff --git a/lib/collections/spotube_icons.dart b/lib/collections/spotube_icons.dart index 9239875e..56192d18 100644 --- a/lib/collections/spotube_icons.dart +++ b/lib/collections/spotube_icons.dart @@ -37,6 +37,7 @@ abstract class SpotubeIcons { static const share = FeatherIcons.share2; static const playlistAdd = Icons.playlist_add_rounded; static const playlistRemove = Icons.playlist_remove_rounded; + static const playlist = Icons.playlist_play_rounded; static const trash = FeatherIcons.trash2; static const clock = FeatherIcons.clock; static const lyrics = Icons.lyrics_rounded; @@ -132,4 +133,5 @@ abstract class SpotubeIcons { static const radioUnchecked = Icons.radio_button_off_rounded; static const grid = FeatherIcons.grid; static const list = FeatherIcons.list; + static const device = FeatherIcons.smartphone; } diff --git a/lib/components/track_presentation/presentation_state.dart b/lib/components/track_presentation/presentation_state.dart index 11ca9809..91adbfcd 100644 --- a/lib/components/track_presentation/presentation_state.dart +++ b/lib/components/track_presentation/presentation_state.dart @@ -2,7 +2,7 @@ import 'package:collection/collection.dart'; import 'package:fuzzywuzzy/fuzzywuzzy.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; -import 'package:spotube/modules/library/user_local_tracks.dart'; +import 'package:spotube/pages/library/user_local_tracks.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:spotube/utils/service_utils.dart'; diff --git a/lib/components/track_presentation/sort_tracks_dropdown.dart b/lib/components/track_presentation/sort_tracks_dropdown.dart index 543bacb3..ecab615f 100644 --- a/lib/components/track_presentation/sort_tracks_dropdown.dart +++ b/lib/components/track_presentation/sort_tracks_dropdown.dart @@ -1,6 +1,6 @@ import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/spotube_icons.dart'; -import 'package:spotube/modules/library/user_local_tracks.dart'; +import 'package:spotube/pages/library/user_local_tracks.dart'; import 'package:spotube/components/adaptive/adaptive_pop_sheet_list.dart'; import 'package:spotube/extensions/context.dart'; diff --git a/lib/main.dart b/lib/main.dart index af7da1b7..bbf161c5 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -264,12 +264,32 @@ class Spotube extends HookConsumerWidget { LogicalKeyboardKey.digit3, LogicalKeyboardKey.control, LogicalKeyboardKey.shift, - ): HomeTabIntent(ref, tab: HomeTabs.library), + ): HomeTabIntent(ref, tab: HomeTabs.lyrics), LogicalKeySet( LogicalKeyboardKey.digit4, LogicalKeyboardKey.control, LogicalKeyboardKey.shift, - ): HomeTabIntent(ref, tab: HomeTabs.lyrics), + ): HomeTabIntent(ref, tab: HomeTabs.userPlaylists), + LogicalKeySet( + LogicalKeyboardKey.digit5, + LogicalKeyboardKey.control, + LogicalKeyboardKey.shift, + ): HomeTabIntent(ref, tab: HomeTabs.userArtists), + LogicalKeySet( + LogicalKeyboardKey.digit6, + LogicalKeyboardKey.control, + LogicalKeyboardKey.shift, + ): HomeTabIntent(ref, tab: HomeTabs.userAlbums), + LogicalKeySet( + LogicalKeyboardKey.digit7, + LogicalKeyboardKey.control, + LogicalKeyboardKey.shift, + ): HomeTabIntent(ref, tab: HomeTabs.userLocalLibrary), + LogicalKeySet( + LogicalKeyboardKey.digit8, + LogicalKeyboardKey.control, + LogicalKeyboardKey.shift, + ): HomeTabIntent(ref, tab: HomeTabs.userDownloads), LogicalKeySet( LogicalKeyboardKey.keyW, LogicalKeyboardKey.control, diff --git a/lib/modules/connect/connect_device.dart b/lib/modules/connect/connect_device.dart index be9826a3..a285284c 100644 --- a/lib/modules/connect/connect_device.dart +++ b/lib/modules/connect/connect_device.dart @@ -1,6 +1,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/pages/connect/connect.dart'; import 'package:spotube/provider/connect/clients.dart'; @@ -19,6 +20,17 @@ class ConnectDeviceButton extends HookConsumerWidget { connectClients.asData?.value.services.isNotEmpty == true; if (_sidebar) { + final mediaQuery = MediaQuery.sizeOf(context); + + if (mediaQuery.mdAndDown) { + return IconButton.ghost( + icon: const Icon(SpotubeIcons.speaker), + onPressed: () { + ServiceUtils.pushNamed(context, ConnectPage.name); + }, + ); + } + return SizedBox( width: double.infinity, child: Button.primary( diff --git a/lib/modules/root/sidebar.dart b/lib/modules/root/sidebar.dart index 9a92a1cb..1d5d9da0 100644 --- a/lib/modules/root/sidebar.dart +++ b/lib/modules/root/sidebar.dart @@ -3,7 +3,6 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; -import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/collections/assets.gen.dart'; import 'package:spotube/collections/side_bar_tiles.dart'; @@ -14,6 +13,7 @@ import 'package:spotube/models/database/database.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/modules/connect/connect_device.dart'; +import 'package:spotube/pages/library/user_downloads.dart'; import 'package:spotube/pages/profile/profile.dart'; import 'package:spotube/pages/settings/settings.dart'; import 'package:spotube/provider/authentication/authentication.dart'; @@ -47,8 +47,6 @@ class Sidebar extends HookConsumerWidget { final routerState = GoRouterState.of(context); final mediaQuery = MediaQuery.of(context); - final downloadCount = ref.watch(downloadManagerProvider).$downloadCount; - final layoutMode = ref.watch(userPreferencesProvider.select((s) => s.layoutMode)); @@ -57,7 +55,14 @@ class Sidebar extends HookConsumerWidget { [context.l10n], ); - final selectedIndex = sidebarTileList.indexWhere( + final sidebarLibraryTileList = useMemoized( + () => getSidebarLibraryTileList(context.l10n), + [context.l10n], + ); + + final tileList = [...sidebarTileList, ...sidebarLibraryTileList]; + + final selectedIndex = tileList.indexWhere( (e) => routerState.namedLocation(e.name) == routerState.matchedLocation, ); @@ -73,16 +78,8 @@ class Sidebar extends HookConsumerWidget { for (final tile in sidebarTileList) NavigationButton( label: mediaQuery.lgAndUp ? Text(tile.title) : null, - child: Badge( - backgroundColor: context.theme.colorScheme.primary, - isLabelVisible: tile.title == "Library" && downloadCount > 0, - label: Text( - downloadCount.toString(), - style: TextStyle( - color: context.theme.colorScheme.primaryForeground, - fontSize: 10, - ), - ), + child: Tooltip( + tooltip: TooltipContainer(child: Text(tile.title)), child: Icon(tile.icon), ), onChanged: (value) { @@ -91,6 +88,22 @@ class Sidebar extends HookConsumerWidget { } }, ), + const NavigationDivider(), + if (mediaQuery.lgAndUp) + NavigationLabel(child: Text(context.l10n.library)), + for (final tile in sidebarLibraryTileList) + NavigationButton( + label: mediaQuery.lgAndUp ? Text(tile.title) : null, + onChanged: (value) { + if (value) { + context.goNamed(tile.name); + } + }, + child: Tooltip( + tooltip: TooltipContainer(child: Text(tile.title)), + child: Icon(tile.icon), + ), + ), ]; return Row( @@ -103,7 +116,7 @@ class Sidebar extends HookConsumerWidget { ? NavigationSidebar( index: selectedIndex, onSelected: (index) { - final tile = sidebarTileList[index]; + final tile = tileList[index]; context.goNamed(tile.name); }, children: navigationButtons, @@ -112,7 +125,7 @@ class Sidebar extends HookConsumerWidget { alignment: NavigationRailAlignment.start, index: selectedIndex, onSelected: (index) { - final tile = sidebarTileList[index]; + final tile = tileList[index]; context.goNamed(tile.name); }, children: navigationButtons, @@ -138,8 +151,10 @@ class SidebarFooter extends HookConsumerWidget implements NavigationBarItem { Widget build(BuildContext context, ref) { final theme = Theme.of(context); final mediaQuery = MediaQuery.of(context); - final me = ref.watch(meProvider); - final data = me.asData?.value; + final routerState = GoRouterState.of(context); + final downloadCount = ref.watch(downloadManagerProvider).$downloadCount; + final userSnapshot = ref.watch(meProvider); + final data = userSnapshot.asData?.value; final avatarImg = (data?.images).asUrlString( index: (data?.images?.length ?? 1) - 1, @@ -149,10 +164,30 @@ class SidebarFooter extends HookConsumerWidget implements NavigationBarItem { final auth = ref.watch(authenticationProvider); if (mediaQuery.mdAndDown) { - return IconButton( - variance: ButtonVariance.ghost, - icon: const Icon(SpotubeIcons.settings), - onPressed: () => ServiceUtils.navigateNamed(context, SettingsPage.name), + return Column( + mainAxisSize: MainAxisSize.min, + spacing: 10, + children: [ + Badge( + isLabelVisible: downloadCount > 0, + label: Text(downloadCount.toString()), + child: IconButton( + variance: routerState.topRoute?.name == UserDownloadsPage.name + ? ButtonVariance.secondary + : ButtonVariance.ghost, + icon: const Icon(SpotubeIcons.download), + onPressed: () => + ServiceUtils.navigateNamed(context, UserDownloadsPage.name), + ), + ), + const ConnectDeviceButton.sidebar(), + IconButton( + variance: ButtonVariance.ghost, + icon: const Icon(SpotubeIcons.settings), + onPressed: () => + ServiceUtils.navigateNamed(context, SettingsPage.name), + ), + ], ); } @@ -161,9 +196,27 @@ class SidebarFooter extends HookConsumerWidget implements NavigationBarItem { width: 180, child: Column( mainAxisSize: MainAxisSize.min, + spacing: 10, children: [ + SizedBox( + width: double.infinity, + child: Button( + style: routerState.topRoute?.name == UserDownloadsPage.name + ? ButtonVariance.secondary + : ButtonVariance.outline, + onPressed: () { + ServiceUtils.navigateNamed(context, UserDownloadsPage.name); + }, + leading: const Icon(SpotubeIcons.download), + trailing: downloadCount > 0 + ? PrimaryBadge( + child: Text(downloadCount.toString()), + ) + : null, + child: Text(context.l10n.downloads), + ), + ), const ConnectDeviceButton.sidebar(), - const Gap(10), Row( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.spaceBetween, diff --git a/lib/pages/getting_started/getting_started.dart b/lib/pages/getting_started/getting_started.dart index 2931a782..f710bd8f 100644 --- a/lib/pages/getting_started/getting_started.dart +++ b/lib/pages/getting_started/getting_started.dart @@ -34,32 +34,35 @@ class GettingStarting extends HookConsumerWidget { return Scaffold( headers: [ - TitleBar( - backgroundColor: Colors.transparent, - surfaceBlur: 0, - trailing: [ - ListenableBuilder( - listenable: pageController, - builder: (context, _) { - return AnimatedSwitcher( - duration: const Duration(milliseconds: 300), - child: pageController.hasClients && - (pageController.page == 0 || pageController.page == 3) - ? const SizedBox() - : Button.secondary( - onPressed: () { - pageController.animateToPage( - 3, - duration: const Duration(milliseconds: 300), - curve: Curves.easeInOut, - ); - }, - child: Text(context.l10n.skip_this_nonsense), - ), - ); - }, - ), - ], + SafeArea( + child: TitleBar( + backgroundColor: Colors.transparent, + surfaceBlur: 0, + trailing: [ + ListenableBuilder( + listenable: pageController, + builder: (context, _) { + return AnimatedSwitcher( + duration: const Duration(milliseconds: 300), + child: pageController.hasClients && + (pageController.page == 0 || + pageController.page == 3) + ? const SizedBox() + : Button.secondary( + onPressed: () { + pageController.animateToPage( + 3, + duration: const Duration(milliseconds: 300), + curve: Curves.easeInOut, + ); + }, + child: Text(context.l10n.skip_this_nonsense), + ), + ); + }, + ), + ], + ), ), ], floatingHeader: true, diff --git a/lib/pages/library/library.dart b/lib/pages/library/library.dart index ec896228..7ae5a0e4 100644 --- a/lib/pages/library/library.dart +++ b/lib/pages/library/library.dart @@ -1,71 +1,63 @@ import 'package:flutter/material.dart' show Badge; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; -import 'package:spotube/modules/library/user_local_tracks.dart'; +import 'package:spotube/collections/side_bar_tiles.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; -import 'package:spotube/modules/library/user_albums.dart'; -import 'package:spotube/modules/library/user_artists.dart'; -import 'package:spotube/modules/library/user_downloads.dart'; -import 'package:spotube/modules/library/user_playlists.dart'; +import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/download_manager_provider.dart'; class LibraryPage extends HookConsumerWidget { - static const name = "library"; + final Widget child; + const LibraryPage({super.key, required this.child}); - const LibraryPage({super.key}); @override Widget build(BuildContext context, ref) { final downloadingCount = ref.watch(downloadManagerProvider).$downloadCount; - final index = useState(0); - - final children = [ - Text(context.l10n.playlists), - Text(context.l10n.local_tab), - Badge( - isLabelVisible: downloadingCount > 0, - label: Text(downloadingCount.toString()), - child: Text(context.l10n.downloads), - ), - Text(context.l10n.artists), - Text(context.l10n.albums), - ]; + final routerState = GoRouterState.of(context); + final sidebarLibraryTileList = useMemoized( + () => getSidebarLibraryTileList(context.l10n), + [context.l10n], + ); + final index = sidebarLibraryTileList.indexWhere( + (e) => routerState.namedLocation(e.name) == routerState.matchedLocation, + ); return SafeArea( bottom: false, - child: Scaffold( - headers: [ - TitleBar( - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: TabList( - index: index.value, - children: [ - for (final child in children) - TabButton( - child: child, - onPressed: () { - index.value = children.indexOf(child); - }, - ), - ], + child: LayoutBuilder(builder: (context, constraints) { + return Scaffold( + headers: [ + if (constraints.smAndDown) + TitleBar( + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: TabList( + index: index, + children: [ + for (final tile in sidebarLibraryTileList) + TabButton( + child: Badge( + isLabelVisible: + tile.id == 'downloads' && downloadingCount > 0, + label: Text(downloadingCount.toString()), + child: Text(tile.title), + ), + onPressed: () { + context.goNamed(tile.name); + }, + ), + ], + ), + ), ), - ), - ), - const Gap(10), - ], - child: IndexedStack( - index: index.value, - children: const [ - UserPlaylists(), - UserLocalTracks(), - UserDownloads(), - UserArtists(), - UserAlbums(), + const Gap(10), ], - ), - ), + child: child, + ); + }), ); } } diff --git a/lib/pages/library/local_folder.dart b/lib/pages/library/local_folder.dart index 84873b84..b8cdd096 100644 --- a/lib/pages/library/local_folder.dart +++ b/lib/pages/library/local_folder.dart @@ -16,9 +16,8 @@ import 'package:spotube/components/button/back_button.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/string.dart'; import 'package:spotube/modules/library/local_folder/cache_export_dialog.dart'; -import 'package:spotube/modules/library/user_local_tracks.dart'; +import 'package:spotube/pages/library/user_local_tracks.dart'; import 'package:spotube/components/expandable_search/expandable_search.dart'; -import 'package:spotube/components/fallbacks/not_found.dart'; import 'package:spotube/components/inter_scrollbar/inter_scrollbar.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/components/track_presentation/sort_tracks_dropdown.dart'; diff --git a/lib/modules/library/user_albums.dart b/lib/pages/library/user_albums.dart similarity index 97% rename from lib/modules/library/user_albums.dart rename to lib/pages/library/user_albums.dart index 8d55cf80..861d1705 100644 --- a/lib/modules/library/user_albums.dart +++ b/lib/pages/library/user_albums.dart @@ -16,8 +16,9 @@ import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/authentication/authentication.dart'; import 'package:spotube/provider/spotify/spotify.dart'; -class UserAlbums extends HookConsumerWidget { - const UserAlbums({super.key}); +class UserAlbumsPage extends HookConsumerWidget { + static const name = 'user_albums'; + const UserAlbumsPage({super.key}); @override Widget build(BuildContext context, ref) { diff --git a/lib/modules/library/user_artists.dart b/lib/pages/library/user_artists.dart similarity index 98% rename from lib/modules/library/user_artists.dart rename to lib/pages/library/user_artists.dart index fd23f426..aacf4102 100644 --- a/lib/modules/library/user_artists.dart +++ b/lib/pages/library/user_artists.dart @@ -19,8 +19,9 @@ import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/authentication/authentication.dart'; import 'package:spotube/provider/spotify/spotify.dart'; -class UserArtists extends HookConsumerWidget { - const UserArtists({super.key}); +class UserArtistsPage extends HookConsumerWidget { + static const name = 'user_artists'; + const UserArtistsPage({super.key}); @override Widget build(BuildContext context, ref) { diff --git a/lib/modules/library/user_downloads.dart b/lib/pages/library/user_downloads.dart similarity index 92% rename from lib/modules/library/user_downloads.dart rename to lib/pages/library/user_downloads.dart index 5db30342..871e21ab 100644 --- a/lib/modules/library/user_downloads.dart +++ b/lib/pages/library/user_downloads.dart @@ -6,8 +6,9 @@ import 'package:spotube/modules/library/user_downloads/download_item.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/download_manager_provider.dart'; -class UserDownloads extends HookConsumerWidget { - const UserDownloads({super.key}); +class UserDownloadsPage extends HookConsumerWidget { + static const name = 'user_downloads'; + const UserDownloadsPage({super.key}); @override Widget build(BuildContext context, ref) { diff --git a/lib/modules/library/user_local_tracks.dart b/lib/pages/library/user_local_tracks.dart similarity index 96% rename from lib/modules/library/user_local_tracks.dart rename to lib/pages/library/user_local_tracks.dart index 86b36dfb..66c011e5 100644 --- a/lib/modules/library/user_local_tracks.dart +++ b/lib/pages/library/user_local_tracks.dart @@ -24,8 +24,9 @@ enum SortBy { album, } -class UserLocalTracks extends HookConsumerWidget { - const UserLocalTracks({super.key}); +class UserLocalLibraryPage extends HookConsumerWidget { + static const name = 'user_local_library'; + const UserLocalLibraryPage({super.key}); @override Widget build(BuildContext context, ref) { diff --git a/lib/modules/library/user_playlists.dart b/lib/pages/library/user_playlists.dart similarity index 97% rename from lib/modules/library/user_playlists.dart rename to lib/pages/library/user_playlists.dart index 06f08ab6..a4711e1b 100644 --- a/lib/modules/library/user_playlists.dart +++ b/lib/pages/library/user_playlists.dart @@ -20,8 +20,9 @@ import 'package:spotube/provider/spotify/spotify.dart'; import 'package:spotube/utils/platform.dart'; import 'package:spotube/utils/service_utils.dart'; -class UserPlaylists extends HookConsumerWidget { - const UserPlaylists({super.key}); +class UserPlaylistsPage extends HookConsumerWidget { + static const name = 'user_playlists'; + const UserPlaylistsPage({super.key}); @override Widget build(BuildContext context, ref) { diff --git a/lib/pages/lyrics/lyrics.dart b/lib/pages/lyrics/lyrics.dart index f61dbbe3..85798eda 100644 --- a/lib/pages/lyrics/lyrics.dart +++ b/lib/pages/lyrics/lyrics.dart @@ -8,7 +8,6 @@ import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; -import 'package:spotube/hooks/utils/use_custom_status_bar_color.dart'; import 'package:spotube/hooks/utils/use_palette_color.dart'; import 'package:spotube/pages/lyrics/plain_lyrics.dart'; import 'package:spotube/pages/lyrics/synced_lyrics.dart'; @@ -33,15 +32,8 @@ class LyricsPage extends HookConsumerWidget { [playlist.activeTrack?.album?.images], ); final palette = usePaletteColor(albumArt, ref); - final route = ModalRoute.of(context); final selectedIndex = useState(0); - final resetStatusBar = useCustomStatusBarColor( - palette.color, - route?.isCurrent ?? false, - noSetBGColor: true, - ); - Widget tabbar = Padding( padding: const EdgeInsets.all(10), child: isModal @@ -93,51 +85,47 @@ class LyricsPage extends HookConsumerWidget { ); if (isModal) { - return PopScope( - canPop: true, - onPopInvokedWithResult: (_, __) => resetStatusBar(), - child: SafeArea( - bottom: false, - child: SurfaceCard( - surfaceBlur: context.theme.surfaceBlur, - surfaceOpacity: context.theme.surfaceOpacity, - padding: EdgeInsets.zero, - borderRadius: BorderRadius.zero, - borderWidth: 0, - child: Column( - children: [ - const SizedBox(height: 5), - Container( - height: 7, - width: 150, - decoration: BoxDecoration( - color: palette.titleTextColor, - borderRadius: BorderRadius.circular(10), - ), + return SafeArea( + bottom: false, + child: SurfaceCard( + surfaceBlur: context.theme.surfaceBlur, + surfaceOpacity: context.theme.surfaceOpacity, + padding: EdgeInsets.zero, + borderRadius: BorderRadius.zero, + borderWidth: 0, + child: Column( + children: [ + const SizedBox(height: 20), + Container( + height: 7, + width: 150, + decoration: BoxDecoration( + color: palette.titleTextColor, + borderRadius: BorderRadius.circular(10), ), - Row( + ), + Row( + children: [ + Expanded( + child: tabbar, + ), + IconButton.ghost( + icon: const Icon(SpotubeIcons.minimize), + onPressed: () => Navigator.of(context).pop(), + ), + const SizedBox(width: 5), + ], + ), + Expanded( + child: IndexedStack( + index: selectedIndex.value, children: [ - Expanded( - child: tabbar, - ), - IconButton.ghost( - icon: const Icon(SpotubeIcons.minimize), - onPressed: () => Navigator.of(context).pop(), - ), - const SizedBox(width: 5), + SyncedLyrics(palette: palette, isModal: isModal), + PlainLyrics(palette: palette, isModal: isModal), ], ), - Expanded( - child: IndexedStack( - index: selectedIndex.value, - children: [ - SyncedLyrics(palette: palette, isModal: isModal), - PlainLyrics(palette: palette, isModal: isModal), - ], - ), - ), - ], - ), + ), + ], ), ), ); diff --git a/lib/utils/service_utils.dart b/lib/utils/service_utils.dart index 2abb98ef..bc57dd4a 100644 --- a/lib/utils/service_utils.dart +++ b/lib/utils/service_utils.dart @@ -6,7 +6,7 @@ import 'package:go_router/go_router.dart'; import 'package:html/dom.dart' hide Text; import 'package:shadcn_flutter/shadcn_flutter.dart' hide Element; import 'package:spotify/spotify.dart'; -import 'package:spotube/modules/library/user_local_tracks.dart'; +import 'package:spotube/pages/library/user_local_tracks.dart'; import 'package:spotube/modules/root/update_dialog.dart'; import 'package:spotube/models/lyrics.dart'; diff --git a/macos/Podfile.lock b/macos/Podfile.lock index 44da1f81..95feb26d 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -168,35 +168,35 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos SPEC CHECKSUMS: - app_links: 10e0a0ab602ffaf34d142cd4862f29d34b303b2a - audio_service: b88ff778e0e3915efd4cd1a5ad6f0beef0c950a9 - audio_session: dea1f41890dbf1718f04a56f1d6150fd50039b72 - bonsoir_darwin: e3b8526c42ca46a885142df84229131dfabea842 - connectivity_plus: 18382e7311ba19efcaee94442b23b32507b20695 - desktop_webview_window: 89bb3d691f4c80314a10be312f4cd35db93a9d5a - device_info_plus: 1b14eed9bf95428983aed283a8d51cce3d8c4215 - file_selector_macos: cc3858c981fe6889f364731200d6232dac1d812d - flutter_discord_rpc: 67a7c10ea24d9d3bf35d01af643f48fbcfa7c24f - flutter_inappwebview_macos: bdf207b8f4ebd58e86ae06cd96b147de99a67c9b - flutter_secure_storage_macos: 59459653abe1adb92abbc8ea747d79f8d19866c9 + app_links: 9028728e32c83a0831d9db8cf91c526d16cc5468 + audio_service: 0d9e4e25347bb3efb768f3b9f005911a81e587a7 + audio_session: 48ab6500f7a5e7c64363e206565a5dfe5a0c1441 + bonsoir_darwin: 29c7ccf356646118844721f36e1de4b61f6cbd0e + connectivity_plus: 2256d3e20624a7749ed21653aafe291a46446fee + desktop_webview_window: 2f0cdefecc06e21208a51589bd3d1580a87a703c + device_info_plus: 4fb280989f669696856f8b129e4a5e3cd6c48f76 + file_selector_macos: 6280b52b459ae6c590af5d78fc35c7267a3c4b31 + flutter_discord_rpc: 90614fcca26f3cebfd33263557ea7875936d184b + flutter_inappwebview_macos: c2d68649f9f8f1831bfcd98d73fd6256366d9d1d + flutter_secure_storage_macos: b2d62a774c23b060f0b99d0173b0b36abb4a8632 FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 - local_notifier: e9506bc66fc70311e8bc7291fb70f743c081e4ff - media_kit_libs_macos_audio: 3871782a4f3f84c77f04d7666c87800a781c24da - media_kit_native_event_loop: 7321675377cb9ae8596a29bddf3a3d2b5e8792c5 - metadata_god: 829f61208b44ac1173e7cd32ab740d8776be5435 - open_file_mac: 0e554648e2a87ce59e9438e3e5ca3e552e90d89a + local_notifier: ebf072651e35ae5e47280ad52e2707375cb2ae4e + media_kit_libs_macos_audio: 06f3cf88d6d89c7c3c87eae57689d1c6adb335b2 + media_kit_native_event_loop: a5833d1e4d5bedb6f691e9909fa57f15f436f2c8 + metadata_god: 8029e6ff4b1400ae4f13c38d2c478e8633f0e58b + open_file_mac: 01874b6d6a2c1485ac9b126d7105b99102dea2cf OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94 - package_info_plus: fa739dd842b393193c5ca93c26798dff6e3d0e0c - path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 - screen_retriever_macos: 776e0fa5d42c6163d2bf772d22478df4b302b161 - shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 - sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d + package_info_plus: a8a591e70e87ce97ce5d21b2594f69cea9e0312f + path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 + screen_retriever_macos: 452e51764a9e1cdb74b3c541238795849f21557f + shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7 + sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0 sqlite3: 7559e33dae4c78538df563795af3a86fc887ee71 - sqlite3_flutter_libs: 1b4e98da20ebd4e9b1240269b78cdcf492dbe9f3 - system_theme: c7b9f6659a5caa26c9bc2284da096781e9a6fcbc - tray_manager: 9064e219c56d75c476e46b9a21182087930baf90 - url_launcher_macos: c82c93949963e55b228a30115bd219499a6fe404 - window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8 + sqlite3_flutter_libs: f0b59f6bb2a18597d0796558725007e5a7428397 + system_theme: ed74293ad07d3a05e3e2d0059ff342360346f1a0 + tray_manager: a104b5c81b578d83f3c3d0f40a997c8b10810166 + url_launcher_macos: 0fba8ddabfc33ce0a9afe7c5fef5aab3d8d2d673 + window_manager: 1d01fa7ac65a6e6f83b965471b1a7fdd3f06166c PODFILE CHECKSUM: 0d3963a09fc94f580682bd88480486da345dc3f0 From 082f7110187778b0f9920a885b2c847414b3068e Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Thu, 23 Jan 2025 20:39:04 +0600 Subject: [PATCH 066/112] chore: use angle --- lib/modules/home/sections/genres/genres.dart | 40 ++++++-------------- 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/lib/modules/home/sections/genres/genres.dart b/lib/modules/home/sections/genres/genres.dart index 5e96f78f..881003aa 100644 --- a/lib/modules/home/sections/genres/genres.dart +++ b/lib/modules/home/sections/genres/genres.dart @@ -111,21 +111,13 @@ class HomeGenresSection extends HookConsumerWidget { left: 0, child: Container( height: 280 * theme.scaling, - width: (mediaQuery.mdAndUp ? 80 : 50) * theme.scaling, - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.centerLeft, - end: Alignment.centerRight, - colors: [ - theme.colorScheme.background.withAlpha(255), - theme.colorScheme.background.withAlpha(0), - ], - ), - ), + width: (mediaQuery.mdAndUp ? 60 : 40) * theme.scaling, alignment: Alignment.center, - child: IconButton.ghost( - size: - mediaQuery.mdAndUp ? ButtonSize.normal : ButtonSize.small, + child: IconButton.secondary( + shape: ButtonShape.circle, + size: mediaQuery.mdAndUp + ? const ButtonSize(1.3) + : ButtonSize.normal, icon: const Icon(SpotubeIcons.angleLeft), onPressed: () { controller.animatePrevious( @@ -140,21 +132,13 @@ class HomeGenresSection extends HookConsumerWidget { right: 0, child: Container( height: 280 * theme.scaling, - width: (mediaQuery.mdAndUp ? 80 : 50) * theme.scaling, - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.centerLeft, - end: Alignment.centerRight, - colors: [ - theme.colorScheme.background.withAlpha(0), - theme.colorScheme.background.withAlpha(255), - ], - ), - ), + width: (mediaQuery.mdAndUp ? 60 : 40) * theme.scaling, alignment: Alignment.center, - child: IconButton.ghost( - size: - mediaQuery.mdAndUp ? ButtonSize.normal : ButtonSize.small, + child: IconButton.secondary( + shape: ButtonShape.circle, + size: mediaQuery.mdAndUp + ? const ButtonSize(1.3) + : ButtonSize.normal, icon: const Icon(SpotubeIcons.angleRight), onPressed: () { controller.animateNext( From 768bab8bbbf2f7667a80c16cb69a44dbc7ceacd2 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Thu, 23 Jan 2025 21:11:59 +0600 Subject: [PATCH 067/112] chore: settings popup menu constraints --- lib/components/adaptive/adaptive_select_tile.dart | 7 +++++++ lib/pages/settings/sections/playback.dart | 2 ++ 2 files changed, 9 insertions(+) diff --git a/lib/components/adaptive/adaptive_select_tile.dart b/lib/components/adaptive/adaptive_select_tile.dart index 40308711..2e2e7041 100644 --- a/lib/components/adaptive/adaptive_select_tile.dart +++ b/lib/components/adaptive/adaptive_select_tile.dart @@ -23,6 +23,9 @@ class AdaptiveSelectTile extends HookWidget { final bool? breakLayout; + final BoxConstraints? popupConstraints; + final PopoverConstraint? popupWidthConstraint; + const AdaptiveSelectTile({ required this.title, required this.value, @@ -34,6 +37,8 @@ class AdaptiveSelectTile extends HookWidget { this.breakLayout, this.showValueWhenUnfolded = true, super.key, + this.popupConstraints, + this.popupWidthConstraint, }); @override @@ -47,6 +52,8 @@ class AdaptiveSelectTile extends HookWidget { }, value: value, onChanged: onChanged, + popupConstraints: popupConstraints ?? const BoxConstraints(maxWidth: 200), + popupWidthConstraint: popupWidthConstraint ?? PopoverConstraint.flexible, children: options, ); diff --git a/lib/pages/settings/sections/playback.dart b/lib/pages/settings/sections/playback.dart index 6888e3a9..be3fc15b 100644 --- a/lib/pages/settings/sections/playback.dart +++ b/lib/pages/settings/sections/playback.dart @@ -281,6 +281,7 @@ class SettingsPlaybackSection extends HookConsumerWidget { ), if (preferences.audioSource != AudioSource.jiosaavn) ...[ AdaptiveSelectTile( + popupConstraints: const BoxConstraints(maxWidth: 300), secondary: const Icon(SpotubeIcons.stream), title: Text(context.l10n.streaming_music_codec), value: preferences.streamMusicCodec, @@ -300,6 +301,7 @@ class SettingsPlaybackSection extends HookConsumerWidget { }, ), AdaptiveSelectTile( + popupConstraints: const BoxConstraints(maxWidth: 300), secondary: const Icon(SpotubeIcons.file), title: Text(context.l10n.download_music_codec), value: preferences.downloadMusicCodec, From 0aee8b339919979e5df6c23d5808ab048728c1f8 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Thu, 23 Jan 2025 21:16:40 +0600 Subject: [PATCH 068/112] cd: use upload-artifact v4 --- .github/workflows/spotube-release-binary.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index eb251d2a..fb64d55a 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -125,7 +125,7 @@ jobs: CHANNEL: ${{inputs.channel}} DOTENV: ${{secrets.DOTENV_RELEASE}} - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: if-no-files-found: error name: Spotube-Release-Binaries @@ -143,7 +143,7 @@ jobs: - build_platform steps: - uses: actions/checkout@v4 - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: Spotube-Release-Binaries path: ./Spotube-Release-Binaries @@ -162,7 +162,7 @@ jobs: run: | echo "PUBSPEC_VERSION=$(grep -oP 'version:\s*\K[^+]+(?=\+)' pubspec.yaml)" >> $GITHUB_ENV - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: if-no-files-found: error name: Spotube-Release-Binaries From 343198a7e8ff19f45b537e005a010f7d06bf6c46 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 24 Jan 2025 09:55:09 +0600 Subject: [PATCH 069/112] cd: use individual artifacts --- .github/workflows/spotube-release-binary.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index fb64d55a..1e07d938 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -128,7 +128,6 @@ jobs: - uses: actions/upload-artifact@v4 with: if-no-files-found: error - name: Spotube-Release-Binaries path: ${{matrix.files}} - name: Debug With SSH When fails @@ -145,7 +144,6 @@ jobs: - uses: actions/checkout@v4 - uses: actions/download-artifact@v4 with: - name: Spotube-Release-Binaries path: ./Spotube-Release-Binaries - name: Install dependencies From becba8956f97b50d0b9d01bdb0863ef87af97c51 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 24 Jan 2025 10:15:24 +0600 Subject: [PATCH 070/112] cd: artifact name need to be specified --- .github/workflows/spotube-release-binary.yml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index 1e07d938..a4afcab3 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -107,7 +107,7 @@ jobs: echo '${{ secrets.KEYSTORE }}' | base64 --decode > android/app/upload-keystore.jks echo '${{ secrets.KEY_PROPERTIES }}' > android/key.properties - - name: Unessary hosted tools + - name: Uncessary hosted tools if: ${{matrix.platform == 'linux_arm'}} uses: jlumbroso/free-disk-space@main with: @@ -128,6 +128,7 @@ jobs: - uses: actions/upload-artifact@v4 with: if-no-files-found: error + name: ${{matrix.platform}} path: ${{matrix.files}} - name: Debug With SSH When fails @@ -163,7 +164,7 @@ jobs: - uses: actions/upload-artifact@v4 with: if-no-files-found: error - name: Spotube-Release-Binaries + name: sums path: | RELEASE.md5sum RELEASE.sha256sum @@ -196,3 +197,10 @@ jobs: Nightly release includes newest features but may contain bugs It is preferred to use the stable version unless you know what you're doing + + - name: Debug With SSH When fails + if: ${{ failure() && inputs.debug && inputs.channel == 'nightly' }} + uses: mxschmitt/action-tmate@v3 + with: + limit-access-to-actor: true + From 85ebaf69de09e8c96629faeca799e4d331f5f260 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 24 Jan 2025 11:15:48 +0600 Subject: [PATCH 071/112] cd: use new hosted github runners --- .github/workflows/spotube-release-binary.yml | 32 ++++-------- cli/commands/build.dart | 8 ++- cli/commands/build/common.dart | 2 + cli/commands/build/linux.dart | 55 ++++++++++++-------- cli/commands/build/linux_arm.dart | 37 ------------- cli/commands/install-dependencies.dart | 15 +++--- 6 files changed, 58 insertions(+), 91 deletions(-) delete mode 100644 cli/commands/build/linux_arm.dart diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index a4afcab3..410cb835 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -33,31 +33,37 @@ jobs: include: - os: ubuntu-latest platform: linux + arch: x86 files: | dist/Spotube-linux-x86_64.deb dist/Spotube-linux-x86_64.rpm dist/spotube-linux-*-x86_64.tar.xz - - os: ubuntu-latest - platform: linux_arm + - os: ubuntu-22.04-arm + platform: linux + arch: arm64 files: | dist/Spotube-linux-aarch64.deb dist/spotube-linux-*-aarch64.tar.xz - os: ubuntu-latest platform: android + arch: all files: | build/Spotube-android-all-arch.apk build/Spotube-playstore-all-arch.aab - os: windows-latest platform: windows + arch: x86 files: | dist/Spotube-windows-x86_64.nupkg dist/Spotube-windows-x86_64-setup.exe - os: macos-latest platform: ios + arch: all files: | Spotube-iOS.ipa - os: macos-14 platform: macos + arch: all files: | build/Spotube-macos-universal.dmg build/Spotube-macos-universal.pkg @@ -78,14 +84,8 @@ jobs: java-version: '17' cache: 'gradle' check-latest: true - - name: Set up QEMU - if: ${{matrix.platform == 'linux_arm'}} - uses: docker/setup-qemu-action@v3 - - name: Set up Docker Buildx - if: ${{matrix.platform == 'linux_arm'}} - uses: docker/setup-buildx-action@v3 + - name: Setup Rust toolchain - if: ${{matrix.platform != 'linux_arm'}} uses: dtolnay/rust-toolchain@stable with: toolchain: stable @@ -107,20 +107,8 @@ jobs: echo '${{ secrets.KEYSTORE }}' | base64 --decode > android/app/upload-keystore.jks echo '${{ secrets.KEY_PROPERTIES }}' > android/key.properties - - name: Uncessary hosted tools - if: ${{matrix.platform == 'linux_arm'}} - uses: jlumbroso/free-disk-space@main - with: - tool-cache: false - swap-storage: false - android: true - dotnet: true - haskell: true - large-packages: true - docker-images: true - - name: Build ${{matrix.platform}} binaries - run: dart cli/cli.dart build ${{matrix.platform}} + run: dart cli/cli.dart build --arch=${{matrix.arch}} ${{matrix.platform}} env: CHANNEL: ${{inputs.channel}} DOTENV: ${{secrets.DOTENV_RELEASE}} diff --git a/cli/commands/build.dart b/cli/commands/build.dart index fdf35a95..e0c254ff 100644 --- a/cli/commands/build.dart +++ b/cli/commands/build.dart @@ -3,7 +3,6 @@ import 'package:args/command_runner.dart'; import 'build/android.dart'; import 'build/ios.dart'; import 'build/linux.dart'; -import 'build/linux_arm.dart'; import 'build/macos.dart'; import 'build/windows.dart'; @@ -18,8 +17,13 @@ class BuildCommand extends Command { addSubcommand(AndroidBuildCommand()); addSubcommand(IosBuildCommand()); addSubcommand(LinuxBuildCommand()); - addSubcommand(LinuxArmBuildCommand()); addSubcommand(MacosBuildCommand()); addSubcommand(WindowsBuildCommand()); + argParser.addOption( + "arch", + abbr: "a", + defaultsTo: "x86", + allowed: ["x86", "arm64", "all"], + ); } } diff --git a/cli/commands/build/common.dart b/cli/commands/build/common.dart index 4c7e3e51..f6f6ad50 100644 --- a/cli/commands/build/common.dart +++ b/cli/commands/build/common.dart @@ -63,4 +63,6 @@ mixin BuildCommandCommonSteps on Command { """, ); } + + String get architecture => argResults?.option("arch") as String; } diff --git a/cli/commands/build/linux.dart b/cli/commands/build/linux.dart index a218720c..f61ffbce 100644 --- a/cli/commands/build/linux.dart +++ b/cli/commands/build/linux.dart @@ -37,23 +37,32 @@ class LinuxBuildCommand extends Command with BuildCommandCommonSteps { await bootstrap(); await shell.run( - """ - flutter_distributor package --platform=linux --targets=deb - flutter_distributor package --platform=linux --targets=rpm - """, + "flutter_distributor package --platform=linux --targets=deb", ); + if (architecture == "x86") { + await shell.run( + "flutter_distributor package --platform=linux --targets=rpm", + ); + } + final tempDir = join(Directory.systemTemp.path, "spotube-tar"); - final bundleDirPath = - join(cwd.path, "build", "linux", "x64", "release", "bundle"); + final bundleDirPath = join( + cwd.path, + "build", + "linux", + architecture == "x86" ? "x64" : architecture, + "release", + "bundle", + ); final tarFile = File(join( cwd.path, "dist", "spotube-linux-" "${CliEnv.channel == BuildChannel.nightly ? "nightly" : versionWithoutBuildNumber}" - "-x86_64.tar.xz", + "-${architecture == "x86" ? "x86_64" : "aarch64"}.tar.xz", )); await copyPath(bundleDirPath, tempDir); @@ -81,25 +90,27 @@ class LinuxBuildCommand extends Command with BuildCommandCommonSteps { "spotube-${pubspec.version}-linux.deb", ), ); - - final ogRpm = File( - join( - cwd.path, - "dist", - pubspec.version.toString(), - "spotube-${pubspec.version}-linux.rpm", - ), - ); - await ogDeb.copy( join(cwd.path, "dist", "Spotube-linux-x86_64.deb"), ); - await ogRpm.copy( - join(cwd.path, "dist", "Spotube-linux-x86_64.rpm"), - ); - await ogDeb.delete(); - await ogRpm.delete(); + + if (architecture == "x86") { + final ogRpm = File( + join( + cwd.path, + "dist", + pubspec.version.toString(), + "spotube-${pubspec.version}-linux.rpm", + ), + ); + + await ogRpm.copy( + join(cwd.path, "dist", "Spotube-linux-x86_64.rpm"), + ); + + await ogRpm.delete(); + } stdout.writeln("✅ Linux building done"); } diff --git a/cli/commands/build/linux_arm.dart b/cli/commands/build/linux_arm.dart deleted file mode 100644 index a09f0980..00000000 --- a/cli/commands/build/linux_arm.dart +++ /dev/null @@ -1,37 +0,0 @@ -import 'dart:async'; - -import 'package:args/command_runner.dart'; -import 'package:path/path.dart'; - -import '../../core/env.dart'; -import 'common.dart'; - -class LinuxArmBuildCommand extends Command with BuildCommandCommonSteps { - @override - String get description => "Build Linux Arm"; - - @override - String get name => "linux_arm"; - - @override - FutureOr? run() async { - await bootstrap(); - - await shell.run( - "docker buildx build --platform=linux/arm64 " - "-f ${join(cwd.path, ".github", "Dockerfile")} ${cwd.path} " - "--build-arg FLUTTER_VERSION=${CliEnv.flutterVersion} " - "--build-arg BUILD_VERSION=${CliEnv.channel == BuildChannel.nightly ? "nightly" : versionWithoutBuildNumber} " - "-t krtirtho/spotube_linux_arm:latest " - "--load", - ); - - await shell.run( - """ - docker images ls - docker create --name spotube_linux_arm krtirtho/spotube_linux_arm:latest - docker cp spotube_linux_arm:/app/dist/ dist/ - """, - ); - } -} diff --git a/cli/commands/install-dependencies.dart b/cli/commands/install-dependencies.dart index dc519cc6..e26b8078 100644 --- a/cli/commands/install-dependencies.dart +++ b/cli/commands/install-dependencies.dart @@ -24,6 +24,13 @@ class InstallDependenciesCommand extends Command { ], mandatory: true, ); + + argParser.addOption( + "arch", + abbr: "a", + allowed: ["x86", "arm64", "all"], + defaultsTo: "x86", + ); } @override @@ -41,14 +48,6 @@ class InstallDependenciesCommand extends Command { """, ); break; - case "linux_arm": - await shell.run( - """ - sudo apt-get update -y - sudo apt-get install -y pkg-config make python3-pip python3-setuptools - """, - ); - break; case "macos": await shell.run( """ From 1937b1b8401a9473ea3d41caf86ba2287299d499 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 24 Jan 2025 11:31:01 +0600 Subject: [PATCH 072/112] cd: use default caching key --- .github/workflows/spotube-release-binary.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index 410cb835..9d2f2441 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -73,7 +73,6 @@ jobs: - uses: subosito/flutter-action@v2.12.0 with: cache: true - cache-key: ${{ runner.os }}-flutter-${{ hashFiles('**/pubspec.yaml') }} flutter-version: ${{ env.FLUTTER_VERSION }} channel: ${{ env.FLUTTER_CHANNEL }} - name: Setup Java From b7bb35d299c3e4e0c2c2e00b114cd5d5ed026d8d Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 24 Jan 2025 11:32:41 +0600 Subject: [PATCH 073/112] cd: upgrade flutter action --- .github/workflows/spotube-release-binary.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index 9d2f2441..b0096517 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -70,7 +70,7 @@ jobs: runs-on: ${{matrix.os}} steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v2.12.0 + - uses: subosito/flutter-action@v2 with: cache: true flutter-version: ${{ env.FLUTTER_VERSION }} From 15773e1ce7105d608a289b64133b3e18055ddab7 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 24 Jan 2025 11:44:22 +0600 Subject: [PATCH 074/112] cd: use alternative flutter action setup action --- .github/workflows/spotube-release-binary.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index b0096517..68fc6a60 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -70,10 +70,9 @@ jobs: runs-on: ${{matrix.os}} steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v2 + - uses: flutter-actions/setup-flutter@v4 with: - cache: true - flutter-version: ${{ env.FLUTTER_VERSION }} + version: ${{ env.FLUTTER_VERSION }} channel: ${{ env.FLUTTER_CHANNEL }} - name: Setup Java if: ${{matrix.platform == 'android'}} From ed1f4ad6f522863c5635212b8f56ea41bc307de9 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 24 Jan 2025 12:08:01 +0600 Subject: [PATCH 075/112] cd: use cache less Flutter SDK --- .github/workflows/spotube-release-binary.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index 68fc6a60..4e8c9ac7 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -70,10 +70,12 @@ jobs: runs-on: ${{matrix.os}} steps: - uses: actions/checkout@v4 - - uses: flutter-actions/setup-flutter@v4 + - uses: subosito/flutter-action@v2 with: - version: ${{ env.FLUTTER_VERSION }} + flutter-version: ${{ env.FLUTTER_VERSION }} channel: ${{ env.FLUTTER_CHANNEL }} + cache: false + - name: Setup Java if: ${{matrix.platform == 'android'}} uses: actions/setup-java@v4 From 219ae9dcb3d57e0324d48790f82f498636e2807f Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 24 Jan 2025 12:15:30 +0600 Subject: [PATCH 076/112] cd: use git source for flutter action --- .github/workflows/spotube-release-binary.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index 4e8c9ac7..30e9dd2c 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -70,11 +70,12 @@ jobs: runs-on: ${{matrix.os}} steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v2 + - uses: subosito/flutter-action@v2.18.0 with: flutter-version: ${{ env.FLUTTER_VERSION }} channel: ${{ env.FLUTTER_CHANNEL }} cache: false + git-source: https://github.com/flutter/flutter.git - name: Setup Java if: ${{matrix.platform == 'android'}} From b2b38a919184325f56d4a9b4c539f657ab0b5c13 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 24 Jan 2025 12:18:33 +0600 Subject: [PATCH 077/112] cd: use git source for flutter action --- .github/workflows/spotube-release-binary.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index 30e9dd2c..f146ae9a 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -21,7 +21,7 @@ on: env: FLUTTER_VERSION: 3.28.0-0.1.pre - FLUTTER_CHANNEL: beta + FLUTTER_CHANNEL: master permissions: contents: write From ee95b3b26a37ed9255ee46b300f0fb40b03fcf09 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 24 Jan 2025 12:32:01 +0600 Subject: [PATCH 078/112] chore: fix build cli argument access --- cli/commands/build/common.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/commands/build/common.dart b/cli/commands/build/common.dart index f6f6ad50..30906b3c 100644 --- a/cli/commands/build/common.dart +++ b/cli/commands/build/common.dart @@ -64,5 +64,5 @@ mixin BuildCommandCommonSteps on Command { ); } - String get architecture => argResults?.option("arch") as String; + String get architecture => parent?.argResults?.option("arch") as String; } From e05645c46e68e481a172f1b4b83b3e046aeb72ca Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 24 Jan 2025 12:43:44 +0600 Subject: [PATCH 079/112] cd: enable caching for Flutter SDK in release workflow --- .github/workflows/spotube-release-binary.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index f146ae9a..7b9ffe72 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -74,7 +74,7 @@ jobs: with: flutter-version: ${{ env.FLUTTER_VERSION }} channel: ${{ env.FLUTTER_CHANNEL }} - cache: false + cache: true git-source: https://github.com/flutter/flutter.git - name: Setup Java @@ -117,7 +117,7 @@ jobs: - uses: actions/upload-artifact@v4 with: if-no-files-found: error - name: ${{matrix.platform}} + name: ${{matrix.platform}}-${{matrix.arch}} path: ${{matrix.files}} - name: Debug With SSH When fails From 697ba1ed7b9dad734a305b0fc7e0f412e9249f00 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 24 Jan 2025 13:27:20 +0600 Subject: [PATCH 080/112] cd: sha and md5 sum error --- .github/workflows/spotube-release-binary.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index 7b9ffe72..19011967 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -142,8 +142,9 @@ jobs: - name: Generate Checksums run: | tree . - md5sum Spotube-Release-Binaries/* >> RELEASE.md5sum - sha256sum Spotube-Release-Binaries/* >> RELEASE.sha256sum + find Spotube-Release-Binaries -type f -exec md5sum {} \; >> RELEASE.md5sum + find Spotube-Release-Binaries -type f -exec sha256sum {} \; >> RELEASE.sha256sum + sed -i 's|Spotube-Release-Binaries/.*/\([^/]*\)$|\1|' RELEASE.sha256sum RELEASE.md5sum sed -i 's|Spotube-Release-Binaries/||' RELEASE.sha256sum RELEASE.md5sum - name: Extract pubspec version From 8c0a47374da809a7c03fa34efa6badfdae7b0131 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 24 Jan 2025 13:55:57 +0600 Subject: [PATCH 081/112] cd: artifact nested directory glob --- .github/workflows/spotube-release-binary.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index 19011967..e8651c07 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -169,7 +169,7 @@ jobs: omitNameDuringUpdate: true omitPrereleaseDuringUpdate: true allowUpdates: true - artifacts: Spotube-Release-Binaries/*,RELEASE.sha256sum,RELEASE.md5sum + artifacts: Spotube-Release-Binaries/**/*,RELEASE.sha256sum,RELEASE.md5sum - name: Upload Release Binaries (nightly) if: ${{ !inputs.dry_run && inputs.channel == 'nightly' }} @@ -181,7 +181,7 @@ jobs: omitNameDuringUpdate: true omitPrereleaseDuringUpdate: true allowUpdates: true - artifacts: Spotube-Release-Binaries/*,RELEASE.sha256sum,RELEASE.md5sum + artifacts: Spotube-Release-Binaries/**/*,RELEASE.sha256sum,RELEASE.md5sum body: | Build Number: ${{github.run_number}} From 75e189344e1d6b1e288c8178d1f7069cec21e834 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 24 Jan 2025 14:19:44 +0600 Subject: [PATCH 082/112] cd: update workflow and build command for Ubuntu 22.04 compatibility --- .github/workflows/spotube-release-binary.yml | 6 +++--- cli/commands/build/linux.dart | 12 ++++++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index e8651c07..fa736f27 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -31,7 +31,7 @@ jobs: strategy: matrix: include: - - os: ubuntu-latest + - os: ubuntu-22.04 platform: linux arch: x86 files: | @@ -44,7 +44,7 @@ jobs: files: | dist/Spotube-linux-aarch64.deb dist/spotube-linux-*-aarch64.tar.xz - - os: ubuntu-latest + - os: ubuntu-22.04 platform: android arch: all files: | @@ -127,7 +127,7 @@ jobs: limit-access-to-actor: true upload: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 needs: - build_platform steps: diff --git a/cli/commands/build/linux.dart b/cli/commands/build/linux.dart index f61ffbce..3fd8a0b9 100644 --- a/cli/commands/build/linux.dart +++ b/cli/commands/build/linux.dart @@ -47,7 +47,7 @@ class LinuxBuildCommand extends Command with BuildCommandCommonSteps { } final tempDir = join(Directory.systemTemp.path, "spotube-tar"); - + final bundleArchName = architecture == "x86" ? "x86_64" : "aarch64"; final bundleDirPath = join( cwd.path, "build", @@ -62,7 +62,7 @@ class LinuxBuildCommand extends Command with BuildCommandCommonSteps { "dist", "spotube-linux-" "${CliEnv.channel == BuildChannel.nightly ? "nightly" : versionWithoutBuildNumber}" - "-${architecture == "x86" ? "x86_64" : "aarch64"}.tar.xz", + "-$bundleArchName.tar.xz", )); await copyPath(bundleDirPath, tempDir); @@ -91,7 +91,11 @@ class LinuxBuildCommand extends Command with BuildCommandCommonSteps { ), ); await ogDeb.copy( - join(cwd.path, "dist", "Spotube-linux-x86_64.deb"), + join( + cwd.path, + "dist", + "Spotube-linux-$bundleArchName.deb", + ), ); await ogDeb.delete(); @@ -106,7 +110,7 @@ class LinuxBuildCommand extends Command with BuildCommandCommonSteps { ); await ogRpm.copy( - join(cwd.path, "dist", "Spotube-linux-x86_64.rpm"), + join(cwd.path, "dist", "Spotube-linux-$bundleArchName.rpm"), ); await ogRpm.delete(); From 4e8a50ec58ebd3aba51f043ab629de52b41cc2b4 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 26 Jan 2025 22:05:24 +0600 Subject: [PATCH 083/112] chore: fix logs not showing up and nightly crashing on track change on android --- .vscode/launch.json | 2 +- .../res/drawable/ic_launcher_monochrome.xml | 27 ++++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 11 +- lib/pages/settings/logs.dart | 123 +++++++++--------- lib/provider/logs/logs_provider.dart | 8 +- .../audio_services/audio_services.dart | 11 +- pubspec.lock | 48 +++---- 7 files changed, 132 insertions(+), 98 deletions(-) create mode 100644 android/app/src/nightly/res/drawable/ic_launcher_monochrome.xml diff --git a/.vscode/launch.json b/.vscode/launch.json index deabf1d3..df4131e5 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -14,7 +14,7 @@ "program": "lib/main.dart", "args": [ "--flavor", - "dev" + "nightly" ] }, { diff --git a/android/app/src/nightly/res/drawable/ic_launcher_monochrome.xml b/android/app/src/nightly/res/drawable/ic_launcher_monochrome.xml new file mode 100644 index 00000000..8aae0e6c --- /dev/null +++ b/android/app/src/nightly/res/drawable/ic_launcher_monochrome.xml @@ -0,0 +1,27 @@ + + + + + diff --git a/android/app/src/nightly/res/mipmap-anydpi-v26/ic_launcher.xml b/android/app/src/nightly/res/mipmap-anydpi-v26/ic_launcher.xml index c79c58a3..83e651db 100644 --- a/android/app/src/nightly/res/mipmap-anydpi-v26/ic_launcher.xml +++ b/android/app/src/nightly/res/mipmap-anydpi-v26/ic_launcher.xml @@ -1,9 +1,6 @@ - - - - - + + + + \ No newline at end of file diff --git a/lib/pages/settings/logs.dart b/lib/pages/settings/logs.dart index f9439317..3a4f7715 100644 --- a/lib/pages/settings/logs.dart +++ b/lib/pages/settings/logs.dart @@ -25,75 +25,76 @@ class LogsPage extends HookConsumerWidget { return Scaffold( headers: [ - TitleBar( - title: Text(context.l10n.logs), - leading: const [BackButton()], - trailing: [ - IconButton.ghost( - icon: const Icon(SpotubeIcons.clipboard, size: 16), - onPressed: () async { - final logsSnapshot = await ref.read(logsProvider.future); + SafeArea( + bottom: false, + child: TitleBar( + title: Text(context.l10n.logs), + leading: const [BackButton()], + trailing: [ + IconButton.ghost( + icon: const Icon(SpotubeIcons.clipboard, size: 16), + onPressed: () async { + final logsSnapshot = await ref.read(logsProvider.future); - await Clipboard.setData(ClipboardData(text: logsSnapshot)); - if (context.mounted) { - showToast( - context: context, - location: ToastLocation.topRight, - builder: (context, overlay) { - return SurfaceCard( - child: Basic( - title: Text(context.l10n.copied_to_clipboard("")), - ), - ); - }, - ); - } - }, - ), - IconButton.ghost( - icon: const Icon( - SpotubeIcons.trash, - size: 16, + await Clipboard.setData(ClipboardData(text: logsSnapshot)); + if (context.mounted) { + showToast( + context: context, + location: ToastLocation.topRight, + builder: (context, overlay) { + return SurfaceCard( + child: Basic( + title: Text(context.l10n.copied_to_clipboard("")), + ), + ); + }, + ); + } + }, ), - onPressed: () async { - ref.invalidate(logsProvider); + IconButton.ghost( + icon: const Icon( + SpotubeIcons.trash, + size: 16, + ), + onPressed: () async { + ref.invalidate(logsProvider); - final logsFile = await AppLogger.getLogsPath(); + final logsFile = await AppLogger.getLogsPath(); - await logsFile.writeAsString(""); - }, - ) - ], + await logsFile.writeAsString(""); + }, + ) + ], + ), ) ], - child: SafeArea( - child: switch (logsQuery) { - AsyncData(:final value) => InterScrollbar( + child: switch (logsQuery) { + AsyncData(:final value) => InterScrollbar( + controller: controller, + child: SingleChildScrollView( + padding: const EdgeInsets.all(8.0), controller: controller, - child: SingleChildScrollView( - padding: const EdgeInsets.all(8.0), - controller: controller, - child: Card(child: SelectableText(value)), - ), + child: Card(child: SelectableText(value)), ), - AsyncError(:final error) => switch (error) { - StateError() => Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Undraw( - illustration: UndrawIllustration.noData, - height: 200 * context.theme.scaling, - width: 200 * context.theme.scaling, - color: context.theme.colorScheme.primary, - ), - Text(context.l10n.no_logs_found).muted().small(), - ], - ), - _ => Center(child: Text(error.toString())), - }, - _ => const Center(child: CircularProgressIndicator()), - }, - ), + ), + AsyncError(:final error) => switch (error) { + StateError() => Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Undraw( + illustration: UndrawIllustration.noData, + height: 200 * context.theme.scaling, + width: 200 * context.theme.scaling, + color: context.theme.colorScheme.primary, + ), + Text(context.l10n.no_logs_found).muted().small(), + ], + ), + _ => Center(child: Text(error.toString())), + }, + _ => const Center(child: CircularProgressIndicator()), + }, ); } } diff --git a/lib/provider/logs/logs_provider.dart b/lib/provider/logs/logs_provider.dart index 571d96cc..d39059ac 100644 --- a/lib/provider/logs/logs_provider.dart +++ b/lib/provider/logs/logs_provider.dart @@ -5,12 +5,14 @@ import 'package:spotube/services/logger/logger.dart'; final logsProvider = StreamProvider.autoDispose((ref) async* { final file = await AppLogger.getLogsPath(); - final stream = file.openRead().transform(utf8.decoder); + // Check if file is empty or non-existent - if (await stream.isEmpty) { - throw StateError('No logs found'); + if (await file.length() == 0) { + throw StateError("Logs file is empty or non-existent"); } + final stream = file.openRead().transform(utf8.decoder); + await for (final line in stream) { yield line; } diff --git a/lib/services/audio_services/audio_services.dart b/lib/services/audio_services/audio_services.dart index 0b1843c4..6433707d 100644 --- a/lib/services/audio_services/audio_services.dart +++ b/lib/services/audio_services/audio_services.dart @@ -2,6 +2,7 @@ import 'package:audio_service/audio_service.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/env.dart'; import 'package:spotube/extensions/artist_simple.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; @@ -27,8 +28,14 @@ class AudioServices with WidgetsBindingObserver { ? await AudioService.init( builder: () => MobileAudioService(playback), config: AudioServiceConfig( - androidNotificationChannelId: - kIsLinux ? 'spotube' : 'com.krtirtho.Spotube', + androidNotificationChannelId: switch (( + kIsLinux, + Env.releaseChannel + )) { + (true, _) => "spotube", + (_, ReleaseChannel.stable) => "com.krtirtho.Spotube", + (_, ReleaseChannel.nightly) => "com.krtirtho.Spotube.nightly", + }, androidNotificationChannelName: 'Spotube', androidNotificationOngoing: false, androidStopForegroundOnPause: false, diff --git a/pubspec.lock b/pubspec.lock index 1a35f9c9..1e9d9265 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -98,10 +98,10 @@ packages: dependency: "direct main" description: name: async - sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" url: "https://pub.dev" source: hosted - version: "2.12.0" + version: "2.11.0" audio_service: dependency: "direct main" description: @@ -203,10 +203,10 @@ packages: dependency: transitive description: name: boolean_selector - sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.1" build: dependency: transitive description: @@ -347,10 +347,10 @@ packages: dependency: transitive description: name: clock - sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.1.1" code_builder: dependency: transitive description: @@ -614,10 +614,10 @@ packages: dependency: transitive description: name: fake_async - sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.3.1" ffi: dependency: transitive description: @@ -630,10 +630,10 @@ packages: dependency: transitive description: name: file - sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" url: "https://pub.dev" source: hosted - version: "7.0.1" + version: "7.0.0" file_picker: dependency: "direct main" description: @@ -1370,18 +1370,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec + sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" url: "https://pub.dev" source: hosted - version: "10.0.8" + version: "10.0.7" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" url: "https://pub.dev" source: hosted - version: "3.0.9" + version: "3.0.8" leak_tracker_testing: dependency: transitive description: @@ -1690,10 +1690,10 @@ packages: dependency: "direct main" description: name: path - sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.9.0" path_parsing: dependency: transitive description: @@ -1826,10 +1826,10 @@ packages: dependency: transitive description: name: platform - sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" + sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" url: "https://pub.dev" source: hosted - version: "3.1.6" + version: "3.1.5" plugin_platform_interface: dependency: transitive description: @@ -1866,10 +1866,10 @@ packages: dependency: transitive description: name: process - sha256: "107d8be718f120bbba9dcd1e95e3bd325b1b4a4f07db64154635ba03f2567a0d" + sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32" url: "https://pub.dev" source: hosted - version: "5.0.3" + version: "5.0.2" process_run: dependency: "direct dev" description: @@ -2305,10 +2305,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "0bd04f5bb74fcd6ff0606a888a30e917af9bd52820b178eaa464beb11dca84b6" + sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.3.0" stroke_text: dependency: "direct main" description: @@ -2609,10 +2609,10 @@ packages: dependency: transitive description: name: vm_service - sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" + sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b url: "https://pub.dev" source: hosted - version: "14.3.1" + version: "14.3.0" watcher: dependency: transitive description: From 4c3718467d2037caea3c85ccd273f3b3e4ef093b Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 26 Jan 2025 22:36:11 +0600 Subject: [PATCH 084/112] chore: local library not working --- .fvm/fvm_config.json | 2 +- .fvmrc | 2 +- .github/workflows/spotube-release-binary.yml | 2 +- .vscode/launch.json | 2 +- .vscode/settings.json | 2 +- lib/collections/intents.dart | 2 +- lib/collections/routes.dart | 45 ++++++++++--------- lib/collections/side_bar_tiles.dart | 2 +- .../presentation_state.dart | 2 +- .../sort_tracks_dropdown.dart | 2 +- .../local_folder/local_folder_item.dart | 4 +- lib/pages/library/library.dart | 12 ++++- .../{ => user_local_tracks}/local_folder.dart | 2 +- .../user_local_tracks.dart | 0 lib/utils/service_utils.dart | 2 +- 15 files changed, 48 insertions(+), 35 deletions(-) rename lib/pages/library/{ => user_local_tracks}/local_folder.dart (99%) rename lib/pages/library/{ => user_local_tracks}/user_local_tracks.dart (100%) diff --git a/.fvm/fvm_config.json b/.fvm/fvm_config.json index 7572d05e..c0b314bc 100644 --- a/.fvm/fvm_config.json +++ b/.fvm/fvm_config.json @@ -1,3 +1,3 @@ { - "flutterSdkVersion": "3.28.0-0.1.pre" + "flutterSdkVersion": "3.27.3" } \ No newline at end of file diff --git a/.fvmrc b/.fvmrc index 089fa312..74c2c15a 100644 --- a/.fvmrc +++ b/.fvmrc @@ -1,4 +1,4 @@ { - "flutter": "3.28.0-0.1.pre", + "flutter": "3.27.3", "flavors": {} } \ No newline at end of file diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index fa736f27..5cfa5b6e 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -20,7 +20,7 @@ on: description: Dry run without uploading to release env: - FLUTTER_VERSION: 3.28.0-0.1.pre + FLUTTER_VERSION: 3.27.3 FLUTTER_CHANNEL: master permissions: diff --git a/.vscode/launch.json b/.vscode/launch.json index df4131e5..deabf1d3 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -14,7 +14,7 @@ "program": "lib/main.dart", "args": [ "--flavor", - "nightly" + "dev" ] }, { diff --git a/.vscode/settings.json b/.vscode/settings.json index a5548411..ac8518d1 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -28,5 +28,5 @@ "README.md": "LICENSE,CODE_OF_CONDUCT.md,CONTRIBUTING.md,SECURITY.md,CONTRIBUTION.md,CHANGELOG.md,PRIVACY_POLICY.md", "*.dart": "${capture}.g.dart,${capture}.freezed.dart" }, - "dart.flutterSdkPath": ".fvm/versions/3.28.0-0.1.pre" + "dart.flutterSdkPath": ".fvm/versions/3.27.3" } \ No newline at end of file diff --git a/lib/collections/intents.dart b/lib/collections/intents.dart index 1ec62812..d0a0c8b6 100644 --- a/lib/collections/intents.dart +++ b/lib/collections/intents.dart @@ -10,7 +10,7 @@ import 'package:spotube/pages/home/home.dart'; import 'package:spotube/pages/library/user_albums.dart'; import 'package:spotube/pages/library/user_artists.dart'; import 'package:spotube/pages/library/user_downloads.dart'; -import 'package:spotube/pages/library/user_local_tracks.dart'; +import 'package:spotube/pages/library/user_local_tracks/user_local_tracks.dart'; import 'package:spotube/pages/library/user_playlists.dart'; import 'package:spotube/pages/lyrics/lyrics.dart'; import 'package:spotube/pages/search/search.dart'; diff --git a/lib/collections/routes.dart b/lib/collections/routes.dart index 25cf995c..4cd869cd 100644 --- a/lib/collections/routes.dart +++ b/lib/collections/routes.dart @@ -13,13 +13,13 @@ import 'package:spotube/pages/home/genres/genre_playlists.dart'; import 'package:spotube/pages/home/genres/genres.dart'; import 'package:spotube/pages/home/home.dart'; import 'package:spotube/pages/lastfm_login/lastfm_login.dart'; -import 'package:spotube/pages/library/local_folder.dart'; +import 'package:spotube/pages/library/user_local_tracks/local_folder.dart'; import 'package:spotube/pages/library/playlist_generate/playlist_generate.dart'; import 'package:spotube/pages/library/playlist_generate/playlist_generate_result.dart'; import 'package:spotube/pages/library/user_albums.dart'; import 'package:spotube/pages/library/user_artists.dart'; import 'package:spotube/pages/library/user_downloads.dart'; -import 'package:spotube/pages/library/user_local_tracks.dart'; +import 'package:spotube/pages/library/user_local_tracks/user_local_tracks.dart'; import 'package:spotube/pages/library/user_playlists.dart'; import 'package:spotube/pages/lyrics/mini_lyrics.dart'; import 'package:spotube/pages/playlist/liked_playlist.dart'; @@ -127,11 +127,28 @@ final routerProvider = Provider((ref) { const SpotubePage(child: UserAlbumsPage()), ), GoRoute( - path: "/library/local", - name: UserLocalLibraryPage.name, - pageBuilder: (context, state) => - const SpotubePage(child: UserLocalLibraryPage()), - ), + path: "/library/local", + name: UserLocalLibraryPage.name, + pageBuilder: (context, state) => + const SpotubePage(child: UserLocalLibraryPage()), + routes: [ + GoRoute( + path: "folder", + name: LocalLibraryPage.name, + parentNavigatorKey: shellRouteNavigatorKey, + pageBuilder: (context, state) { + assert(state.extra is String); + return SpotubePage( + child: LocalLibraryPage( + state.extra as String, + isDownloads: + state.uri.queryParameters["downloads"] != null, + isCache: state.uri.queryParameters["cache"] != null, + ), + ); + }, + ), + ]), GoRoute( path: "/library/downloads", name: UserDownloadsPage.name, @@ -157,20 +174,6 @@ final routerProvider = Provider((ref) { ) ], ), - GoRoute( - path: "/library/local", - name: LocalLibraryPage.name, - pageBuilder: (context, state) { - assert(state.extra is String); - return SpotubePage( - child: LocalLibraryPage( - state.extra as String, - isDownloads: state.uri.queryParameters["downloads"] != null, - isCache: state.uri.queryParameters["cache"] != null, - ), - ); - }, - ), GoRoute( path: "/lyrics", name: LyricsPage.name, diff --git a/lib/collections/side_bar_tiles.dart b/lib/collections/side_bar_tiles.dart index 26396e39..f84bd158 100644 --- a/lib/collections/side_bar_tiles.dart +++ b/lib/collections/side_bar_tiles.dart @@ -4,7 +4,7 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:spotube/pages/home/home.dart'; import 'package:spotube/pages/library/user_albums.dart'; import 'package:spotube/pages/library/user_artists.dart'; -import 'package:spotube/pages/library/user_local_tracks.dart'; +import 'package:spotube/pages/library/user_local_tracks/user_local_tracks.dart'; import 'package:spotube/pages/library/user_playlists.dart'; import 'package:spotube/pages/lyrics/lyrics.dart'; import 'package:spotube/pages/search/search.dart'; diff --git a/lib/components/track_presentation/presentation_state.dart b/lib/components/track_presentation/presentation_state.dart index 91adbfcd..2ae0b451 100644 --- a/lib/components/track_presentation/presentation_state.dart +++ b/lib/components/track_presentation/presentation_state.dart @@ -2,7 +2,7 @@ import 'package:collection/collection.dart'; import 'package:fuzzywuzzy/fuzzywuzzy.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; -import 'package:spotube/pages/library/user_local_tracks.dart'; +import 'package:spotube/pages/library/user_local_tracks/user_local_tracks.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:spotube/utils/service_utils.dart'; diff --git a/lib/components/track_presentation/sort_tracks_dropdown.dart b/lib/components/track_presentation/sort_tracks_dropdown.dart index ecab615f..54990503 100644 --- a/lib/components/track_presentation/sort_tracks_dropdown.dart +++ b/lib/components/track_presentation/sort_tracks_dropdown.dart @@ -1,6 +1,6 @@ import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/spotube_icons.dart'; -import 'package:spotube/pages/library/user_local_tracks.dart'; +import 'package:spotube/pages/library/user_local_tracks/user_local_tracks.dart'; import 'package:spotube/components/adaptive/adaptive_pop_sheet_list.dart'; import 'package:spotube/extensions/context.dart'; diff --git a/lib/modules/library/local_folder/local_folder_item.dart b/lib/modules/library/local_folder/local_folder_item.dart index 20845ef7..149657cc 100644 --- a/lib/modules/library/local_folder/local_folder_item.dart +++ b/lib/modules/library/local_folder/local_folder_item.dart @@ -12,7 +12,7 @@ import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/extensions/string.dart'; -import 'package:spotube/pages/library/local_folder.dart'; +import 'package:spotube/pages/library/user_local_tracks/local_folder.dart'; import 'package:spotube/provider/local_tracks/local_tracks_provider.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; @@ -59,7 +59,7 @@ class LocalFolderItem extends HookConsumerWidget { return Button( onPressed: () { - context.goNamed( + context.pushNamed( LocalLibraryPage.name, queryParameters: { if (isDownloadFolder) "downloads": "true", diff --git a/lib/pages/library/library.dart b/lib/pages/library/library.dart index 7ae5a0e4..6677a3b6 100644 --- a/lib/pages/library/library.dart +++ b/lib/pages/library/library.dart @@ -4,9 +4,11 @@ import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/side_bar_tiles.dart'; +import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; +import 'package:spotube/pages/library/user_downloads.dart'; import 'package:spotube/provider/download_manager_provider.dart'; class LibraryPage extends HookConsumerWidget { @@ -18,7 +20,15 @@ class LibraryPage extends HookConsumerWidget { final downloadingCount = ref.watch(downloadManagerProvider).$downloadCount; final routerState = GoRouterState.of(context); final sidebarLibraryTileList = useMemoized( - () => getSidebarLibraryTileList(context.l10n), + () => [ + ...getSidebarLibraryTileList(context.l10n), + SideBarTiles( + id: "downloads", + title: context.l10n.downloads, + name: UserDownloadsPage.name, + icon: SpotubeIcons.download, + ), + ], [context.l10n], ); final index = sidebarLibraryTileList.indexWhere( diff --git a/lib/pages/library/local_folder.dart b/lib/pages/library/user_local_tracks/local_folder.dart similarity index 99% rename from lib/pages/library/local_folder.dart rename to lib/pages/library/user_local_tracks/local_folder.dart index b8cdd096..5282894a 100644 --- a/lib/pages/library/local_folder.dart +++ b/lib/pages/library/user_local_tracks/local_folder.dart @@ -16,7 +16,7 @@ import 'package:spotube/components/button/back_button.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/string.dart'; import 'package:spotube/modules/library/local_folder/cache_export_dialog.dart'; -import 'package:spotube/pages/library/user_local_tracks.dart'; +import 'package:spotube/pages/library/user_local_tracks/user_local_tracks.dart'; import 'package:spotube/components/expandable_search/expandable_search.dart'; import 'package:spotube/components/inter_scrollbar/inter_scrollbar.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; diff --git a/lib/pages/library/user_local_tracks.dart b/lib/pages/library/user_local_tracks/user_local_tracks.dart similarity index 100% rename from lib/pages/library/user_local_tracks.dart rename to lib/pages/library/user_local_tracks/user_local_tracks.dart diff --git a/lib/utils/service_utils.dart b/lib/utils/service_utils.dart index bc57dd4a..c89866b4 100644 --- a/lib/utils/service_utils.dart +++ b/lib/utils/service_utils.dart @@ -6,7 +6,7 @@ import 'package:go_router/go_router.dart'; import 'package:html/dom.dart' hide Text; import 'package:shadcn_flutter/shadcn_flutter.dart' hide Element; import 'package:spotify/spotify.dart'; -import 'package:spotube/pages/library/user_local_tracks.dart'; +import 'package:spotube/pages/library/user_local_tracks/user_local_tracks.dart'; import 'package:spotube/modules/root/update_dialog.dart'; import 'package:spotube/models/lyrics.dart'; From 5c6cb770a8c94fe54c09a661aabd8e50b711ff7e Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Tue, 28 Jan 2025 21:07:02 +0600 Subject: [PATCH 085/112] chore: fix where loading images not working --- .../presentation_state.dart | 58 ++++++++++++------- lib/modules/home/sections/genres/genres.dart | 27 --------- lib/pages/library/user_artists.dart | 2 +- lib/pages/playlist/liked_playlist.dart | 2 +- 4 files changed, 39 insertions(+), 50 deletions(-) diff --git a/lib/components/track_presentation/presentation_state.dart b/lib/components/track_presentation/presentation_state.dart index 2ae0b451..d3428861 100644 --- a/lib/components/track_presentation/presentation_state.dart +++ b/lib/components/track_presentation/presentation_state.dart @@ -34,25 +34,38 @@ class PresentationStateNotifier extends AutoDisposeFamilyNotifier { @override PresentationState build(collection) { - final isPlaylist = arg is PlaylistSimple; - - if ((isPlaylist && (arg as PlaylistSimple).id != "user-liked-tracks") || - arg is AlbumSimple) { - ref.listen( - isPlaylist - ? playlistTracksProvider((arg as PlaylistSimple).id!) - : albumTracksProvider((arg as AlbumSimple)), - (previous, next) { - next.whenData((value) { - state = state.copyWith( - presentationTracks: ServiceUtils.sortTracks( - value.items, - state.sortBy, - ), - ); - }); - }, - ); + if (arg case PlaylistSimple() || AlbumSimple()) { + if (isSavedTrackPlaylist) { + ref.listen( + likedTracksProvider, + (previous, next) { + next.whenData((value) { + state = state.copyWith( + presentationTracks: ServiceUtils.sortTracks( + value, + state.sortBy, + ), + ); + }); + }, + ); + } else { + ref.listen( + arg is PlaylistSimple + ? playlistTracksProvider((arg as PlaylistSimple).id!) + : albumTracksProvider((arg as AlbumSimple)), + (previous, next) { + next.whenData((value) { + state = state.copyWith( + presentationTracks: ServiceUtils.sortTracks( + value.items, + state.sortBy, + ), + ); + }); + }, + ); + } } return PresentationState( @@ -62,6 +75,10 @@ class PresentationStateNotifier ); } + bool get isSavedTrackPlaylist => + arg is PlaylistSimple && + (arg as PlaylistSimple).id == "user-liked-tracks"; + List get tracks { assert( arg is PlaylistSimple || arg is AlbumSimple, @@ -69,8 +86,7 @@ class PresentationStateNotifier ); final isPlaylist = arg is PlaylistSimple; - final isSavedTrackPlaylist = - isPlaylist && (arg as PlaylistSimple).id == "user-liked-tracks"; + final tracks = switch ((isPlaylist, isSavedTrackPlaylist)) { (true, true) => ref.read(likedTracksProvider).asData?.value, (true, false) => ref diff --git a/lib/modules/home/sections/genres/genres.dart b/lib/modules/home/sections/genres/genres.dart index 881003aa..64a6be1c 100644 --- a/lib/modules/home/sections/genres/genres.dart +++ b/lib/modules/home/sections/genres/genres.dart @@ -1,5 +1,3 @@ -import 'dart:async'; - import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; @@ -35,29 +33,6 @@ class HomeGenresSection extends HookConsumerWidget { [categoriesQuery.asData?.value], ); final controller = useMemoized(() => CarouselController(), []); - final interactedRef = useRef(false); - - useEffect(() { - int times = 0; - final timer = Timer.periodic( - const Duration(seconds: 5), - (timer) { - if (times > 5 || interactedRef.value) { - timer.cancel(); - return; - } - controller.animateNext( - const Duration(seconds: 2), - ); - times++; - }, - ); - - return () { - timer.cancel(); - controller.dispose(); - }; - }, []); return SliverList.list( children: [ @@ -123,7 +98,6 @@ class HomeGenresSection extends HookConsumerWidget { controller.animatePrevious( const Duration(seconds: 1), ); - interactedRef.value = true; }, ), ), @@ -144,7 +118,6 @@ class HomeGenresSection extends HookConsumerWidget { controller.animateNext( const Duration(seconds: 1), ); - interactedRef.value = true; }, ), ), diff --git a/lib/pages/library/user_artists.dart b/lib/pages/library/user_artists.dart index aacf4102..6ce715ad 100644 --- a/lib/pages/library/user_artists.dart +++ b/lib/pages/library/user_artists.dart @@ -82,7 +82,7 @@ class UserArtistsPage extends HookConsumerWidget { ), ), const SliverGap(10), - if (filteredArtists.isNotEmpty) + if (filteredArtists.isNotEmpty || artistQuery.isLoading) SliverLayoutBuilder(builder: (context, constrains) { return SliverGrid.builder( itemCount: filteredArtists.length + 1, diff --git a/lib/pages/playlist/liked_playlist.dart b/lib/pages/playlist/liked_playlist.dart index 3b4455d5..95107a8c 100644 --- a/lib/pages/playlist/liked_playlist.dart +++ b/lib/pages/playlist/liked_playlist.dart @@ -26,7 +26,7 @@ class LikedPlaylistPage extends HookConsumerWidget { image: "assets/liked-tracks.jpg", pagination: PaginationProps( hasNextPage: false, - isLoading: false, + isLoading: likedTracks.isLoading, onFetchMore: () {}, onFetchAll: () async { return tracks.toList(); From 42158a99ff1f528eb9e2e7f1c8394afe6be92f46 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Tue, 28 Jan 2025 21:23:57 +0600 Subject: [PATCH 086/112] refactor: use shadcn for mini lyrics window --- lib/modules/player/sibling_tracks_sheet.dart | 7 +- lib/pages/lyrics/mini_lyrics.dart | 308 ++++++++++--------- 2 files changed, 164 insertions(+), 151 deletions(-) diff --git a/lib/modules/player/sibling_tracks_sheet.dart b/lib/modules/player/sibling_tracks_sheet.dart index 14773156..6f9763b6 100644 --- a/lib/modules/player/sibling_tracks_sheet.dart +++ b/lib/modules/player/sibling_tracks_sheet.dart @@ -10,6 +10,7 @@ import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/components/inter_scrollbar/inter_scrollbar.dart'; import 'package:spotube/components/ui/button_tile.dart'; import 'package:spotube/extensions/artist_simple.dart'; +import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/duration.dart'; import 'package:spotube/hooks/utils/use_debounce.dart'; @@ -193,7 +194,11 @@ class SiblingTracksSheet extends HookConsumerWidget { if (!isFetchingActiveTrack && sourceInfo.id != (activeTrack as SourcedTrack).sourceInfo.id) { activeTrackNotifier.swapSibling(sourceInfo); - closeDrawer(context); + if (MediaQuery.sizeOf(context).mdAndUp) { + closeOverlay(context); + } else { + closeDrawer(context); + } } }, ); diff --git a/lib/pages/lyrics/mini_lyrics.dart b/lib/pages/lyrics/mini_lyrics.dart index 8f6ec1fc..9fd54ad6 100644 --- a/lib/pages/lyrics/mini_lyrics.dart +++ b/lib/pages/lyrics/mini_lyrics.dart @@ -1,13 +1,12 @@ -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:gap/gap.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:palette_generator/palette_generator.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/modules/player/player_controls.dart'; import 'package:spotube/modules/player/player_queue.dart'; -import 'package:spotube/modules/root/sidebar.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/hooks/utils/use_force_update.dart'; import 'package:spotube/pages/lyrics/plain_lyrics.dart'; @@ -30,6 +29,8 @@ class MiniLyricsPage extends HookConsumerWidget { final playlistQueue = ref.watch(audioPlayerProvider); + final index = useState(0); + final areaActive = useState(false); final hoverMode = useState(true); final showLyrics = useState(true); @@ -43,8 +44,6 @@ class MiniLyricsPage extends HookConsumerWidget { return null; }, []); - - return MouseRegion( onEnter: !hoverMode.value ? null @@ -56,12 +55,11 @@ class MiniLyricsPage extends HookConsumerWidget { : (event) { areaActive.value = false; }, - child: DefaultTabController( - length: 2, - child: Scaffold( - backgroundColor: theme.colorScheme.surface.withOpacity(0.4), - appBar: PreferredSize( - preferredSize: const Size.fromHeight(60), + child: Scaffold( + backgroundColor: theme.colorScheme.background.withOpacity(0.4), + headers: [ + Padding( + padding: const EdgeInsets.all(8.0), child: AnimatedCrossFade( duration: const Duration(milliseconds: 200), crossFadeState: areaActive.value @@ -70,91 +68,90 @@ class MiniLyricsPage extends HookConsumerWidget { secondChild: const SizedBox(), firstChild: DragToMoveArea( child: Row( + spacing: 2, children: [ const Gap(10), - if (!kIsMacOS) - SizedBox( - height: 30, - width: 30, - child: Sidebar.brandLogo(), - ), - const Spacer(), + if (kIsMacOS) const SizedBox(width: 65), if (showLyrics.value) - SizedBox( - height: 30, - child: TabBar( - tabs: [ - Tab(text: context.l10n.synced), - Tab(text: context.l10n.plain), - ], - isScrollable: true, - ), + Tabs( + index: index.value, + onChanged: (i) { + index.value = i; + }, + tabs: [ + Text(context.l10n.synced), + Text(context.l10n.plain), + ], ), const Spacer(), - IconButton( - tooltip: context.l10n.lyrics, - icon: showLyrics.value - ? const Icon(SpotubeIcons.lyrics) - : const Icon(SpotubeIcons.lyricsOff), - style: ButtonStyle( - foregroundColor: showLyrics.value - ? WidgetStateProperty.all(theme.colorScheme.primary) - : null, - ), - onPressed: () async { - showLyrics.value = !showLyrics.value; - areaActive.value = true; - hoverMode.value = false; + Tooltip( + tooltip: + TooltipContainer(child: Text(context.l10n.lyrics)), + child: IconButton( + variance: showLyrics.value + ? ButtonVariance.secondary + : ButtonVariance.ghost, + icon: showLyrics.value + ? const Icon(SpotubeIcons.lyrics) + : const Icon(SpotubeIcons.lyricsOff), + onPressed: () async { + showLyrics.value = !showLyrics.value; + areaActive.value = true; + hoverMode.value = false; - if (kIsDesktop) { - await windowManager.setSize( - showLyrics.value - ? const Size(400, 500) - : const Size(400, 150), - ); - } - }, - ), - IconButton( - tooltip: context.l10n.show_hide_ui_on_hover, - icon: hoverMode.value - ? const Icon(SpotubeIcons.hoverOn) - : const Icon(SpotubeIcons.hoverOff), - style: ButtonStyle( - foregroundColor: hoverMode.value - ? WidgetStateProperty.all(theme.colorScheme.primary) - : null, + if (kIsDesktop) { + await windowManager.setSize( + showLyrics.value + ? const Size(400, 500) + : const Size(400, 150), + ); + } + }, + ), + ), + Tooltip( + tooltip: TooltipContainer( + child: Text(context.l10n.show_hide_ui_on_hover), + ), + child: IconButton( + variance: hoverMode.value + ? ButtonVariance.secondary + : ButtonVariance.ghost, + icon: hoverMode.value + ? const Icon(SpotubeIcons.hoverOn) + : const Icon(SpotubeIcons.hoverOff), + onPressed: () async { + areaActive.value = true; + hoverMode.value = !hoverMode.value; + }, ), - onPressed: () async { - areaActive.value = true; - hoverMode.value = !hoverMode.value; - }, ), if (kIsDesktop) FutureBuilder( future: windowManager.isAlwaysOnTop(), builder: (context, snapshot) { - return IconButton( - tooltip: context.l10n.always_on_top, - icon: Icon( - snapshot.data == true - ? SpotubeIcons.pinOn - : SpotubeIcons.pinOff, + return Tooltip( + tooltip: TooltipContainer( + child: Text(context.l10n.always_on_top), ), - style: ButtonStyle( - foregroundColor: snapshot.data == true - ? WidgetStateProperty.all( - theme.colorScheme.primary) - : null, + child: IconButton( + variance: snapshot.data == true + ? ButtonVariance.secondary + : ButtonVariance.ghost, + icon: Icon( + snapshot.data == true + ? SpotubeIcons.pinOn + : SpotubeIcons.pinOff, + ), + onPressed: snapshot.data == null + ? null + : () async { + await windowManager.setAlwaysOnTop( + snapshot.data == true ? false : true, + ); + update(); + }, ), - onPressed: snapshot.data == null - ? null - : () async { - await windowManager.setAlwaysOnTop( - snapshot.data == true ? false : true, - ); - update(); - }, ); }, ), @@ -163,79 +160,90 @@ class MiniLyricsPage extends HookConsumerWidget { ), ), ), - body: Column( - children: [ - if (playlistQueue.activeTrack != null) - Text( - playlistQueue.activeTrack!.name!, - style: theme.textTheme.titleMedium, - ), - if (showLyrics.value) - Expanded( - child: TabBarView( - children: [ - SyncedLyrics( - palette: PaletteColor(theme.colorScheme.surface, 0), - isModal: true, - defaultTextZoom: 65, - ), - PlainLyrics( - palette: PaletteColor(theme.colorScheme.surface, 0), - isModal: true, - defaultTextZoom: 65, - ), - ], - ), - ) - else - const Gap(20), - AnimatedCrossFade( - crossFadeState: areaActive.value - ? CrossFadeState.showFirst - : CrossFadeState.showSecond, - duration: const Duration(milliseconds: 200), - secondChild: const SizedBox(), - firstChild: Row( + ], + child: Column( + children: [ + if (playlistQueue.activeTrack != null) + Text(playlistQueue.activeTrack!.name!).semiBold(), + if (showLyrics.value) + Expanded( + child: IndexedStack( + index: index.value, children: [ - IconButton( + SyncedLyrics( + palette: PaletteColor(theme.colorScheme.background, 0), + isModal: true, + defaultTextZoom: 65, + ), + PlainLyrics( + palette: PaletteColor(theme.colorScheme.background, 0), + isModal: true, + defaultTextZoom: 65, + ), + ], + ), + ) + else + const Gap(20), + AnimatedCrossFade( + crossFadeState: areaActive.value + ? CrossFadeState.showFirst + : CrossFadeState.showSecond, + duration: const Duration(milliseconds: 200), + secondChild: const SizedBox(), + firstChild: Row( + children: [ + Tooltip( + tooltip: TooltipContainer( + child: Text(context.l10n.queue), + ), + child: IconButton.ghost( icon: const Icon(SpotubeIcons.queue), - tooltip: context.l10n.queue, onPressed: playlistQueue.activeTrack != null ? () { - showModalBottomSheet( + openDrawer( context: context, - isDismissible: true, - enableDrag: true, - isScrollControlled: true, - backgroundColor: Colors.black12, - barrierColor: Colors.black12, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ), - constraints: BoxConstraints( - maxHeight: - MediaQuery.of(context).size.height * .7, - ), - builder: (context) { - return Consumer(builder: (context, ref, _) { - final playlist = - ref.watch(audioPlayerProvider); - - return PlayerQueue.fromAudioPlayerNotifier( - floating: true, - playlist: playlist, - notifier: ref - .read(audioPlayerProvider.notifier), + barrierDismissible: true, + draggable: true, + barrierColor: Colors.black.withAlpha(100), + borderRadius: BorderRadius.circular(10), + transformBackdrop: false, + position: OverlayPosition.bottom, + surfaceBlur: context.theme.surfaceBlur, + surfaceOpacity: 0.7, + expands: true, + builder: (context) => Consumer( + builder: (context, ref, _) { + final playlist = ref.watch( + audioPlayerProvider, ); - }); - }, + final playlistNotifier = + ref.read(audioPlayerProvider.notifier); + return ConstrainedBox( + constraints: BoxConstraints( + maxHeight: + MediaQuery.of(context).size.height * + 0.8, + ), + child: + PlayerQueue.fromAudioPlayerNotifier( + floating: false, + playlist: playlist, + notifier: playlistNotifier, + ), + ); + }, + ), ); } : null, ), - const Flexible(child: PlayerControls(compact: true)), - IconButton( - tooltip: context.l10n.exit_mini_player, + ), + const Flexible(child: PlayerControls(compact: true)), + Tooltip( + tooltip: TooltipContainer( + child: Text(context.l10n.exit_mini_player)), + child: IconButton.ghost( icon: const Icon(SpotubeIcons.maximize), onPressed: () async { if (!kIsDesktop) return; @@ -262,11 +270,11 @@ class MiniLyricsPage extends HookConsumerWidget { } }, ), - ], - ), - ) - ], - ), + ), + ], + ), + ) + ], ), ), ); From ada0ca14727fad4dd98a8fb0b1e1f5a6cd7987ac Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Tue, 28 Jan 2025 21:42:16 +0600 Subject: [PATCH 087/112] chore: remove obsolete appearance customization --- lib/main.dart | 17 ---- lib/pages/settings/sections/appearance.dart | 32 +++---- .../audio_player/audio_player_streams.dart | 28 ------ lib/provider/palette_provider.dart | 4 - .../user_preferences_provider.dart | 12 ++- lib/themes/theme.dart | 86 ------------------- 6 files changed, 21 insertions(+), 158 deletions(-) delete mode 100644 lib/provider/palette_provider.dart delete mode 100644 lib/themes/theme.dart diff --git a/lib/main.dart b/lib/main.dart index bbf161c5..e0b6e370 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -133,10 +133,6 @@ class Spotube extends HookConsumerWidget { final locale = ref.watch(userPreferencesProvider.select((s) => s.locale)); final accentMaterialColor = ref.watch(userPreferencesProvider.select((s) => s.accentColorScheme)); - // final isAmoledTheme = - // ref.watch(userPreferencesProvider.select((s) => s.amoledDarkTheme)); - // final paletteColor = - // ref.watch(paletteProvider.select((s) => s?.dominantColor?.color)); final router = ref.watch(routerProvider); final hasTouchSupport = useHasTouch(); @@ -166,19 +162,6 @@ class Spotube extends HookConsumerWidget { }; }, []); - // final lightTheme = useMemoized( - // () => theme(paletteColor ?? accentMaterialColor, Brightness.light, false), - // [paletteColor, accentMaterialColor], - // ); - // final darkTheme = useMemoized( - // () => theme( - // paletteColor ?? accentMaterialColor, - // Brightness.dark, - // isAmoledTheme, - // ), - // [paletteColor, accentMaterialColor, isAmoledTheme], - // ); - return ShadcnApp.router( supportedLocales: L10n.all, locale: locale.languageCode == "system" ? null : locale, diff --git a/lib/pages/settings/sections/appearance.dart b/lib/pages/settings/sections/appearance.dart index 55a8f1ef..88f39a25 100644 --- a/lib/pages/settings/sections/appearance.dart +++ b/lib/pages/settings/sections/appearance.dart @@ -79,14 +79,14 @@ class SettingsAppearanceSection extends HookConsumerWidget { } }, ), - ListTile( - leading: const Icon(SpotubeIcons.amoled), - title: Text(context.l10n.use_amoled_mode), - subtitle: Text(context.l10n.pitch_dark_theme), - trailing: Switch( - value: preferences.amoledDarkTheme, - onChanged: preferencesNotifier.setAmoledDarkTheme, - )), + // ListTile( + // leading: const Icon(SpotubeIcons.amoled), + // title: Text(context.l10n.use_amoled_mode), + // subtitle: Text(context.l10n.pitch_dark_theme), + // trailing: Switch( + // value: preferences.amoledDarkTheme, + // onChanged: preferencesNotifier.setAmoledDarkTheme, + // )), ListTile( leading: const Icon(SpotubeIcons.palette), title: Text(context.l10n.accent_color), @@ -102,14 +102,14 @@ class SettingsAppearanceSection extends HookConsumerWidget { ), onTap: pickColorScheme(), ), - ListTile( - leading: const Icon(SpotubeIcons.colorSync), - title: Text(context.l10n.sync_album_color), - subtitle: Text(context.l10n.sync_album_color_description), - trailing: Switch( - value: preferences.albumColorSync, - onChanged: preferencesNotifier.setAlbumColorSync, - )), + // ListTile( + // leading: const Icon(SpotubeIcons.colorSync), + // title: Text(context.l10n.sync_album_color), + // subtitle: Text(context.l10n.sync_album_color_description), + // trailing: Switch( + // value: preferences.albumColorSync, + // onChanged: preferencesNotifier.setAlbumColorSync, + // )), ]; if (isGettingStarted) { diff --git a/lib/provider/audio_player/audio_player_streams.dart b/lib/provider/audio_player/audio_player_streams.dart index e52b6109..880f643f 100644 --- a/lib/provider/audio_player/audio_player_streams.dart +++ b/lib/provider/audio_player/audio_player_streams.dart @@ -1,15 +1,11 @@ import 'dart:async'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:palette_generator/palette_generator.dart'; -import 'package:spotube/components/image/universal_image.dart'; -import 'package:spotube/extensions/image.dart'; import 'package:spotube/models/local_track.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/provider/audio_player/state.dart'; import 'package:spotube/provider/discord_provider.dart'; import 'package:spotube/provider/history/history.dart'; -import 'package:spotube/provider/palette_provider.dart'; import 'package:spotube/provider/skip_segments/skip_segments.dart'; import 'package:spotube/provider/scrobbler/scrobbler.dart'; import 'package:spotube/provider/server/sourced_track.dart'; @@ -48,36 +44,12 @@ class AudioPlayerStreamListeners { PlaybackHistoryActions get history => ref.read(playbackHistoryActionsProvider); - Future updatePalette() async { - final palette = ref.read(paletteProvider); - if (!preferences.albumColorSync) { - if (palette != null) ref.read(paletteProvider.notifier).state = null; - return; - } - return Future.microtask(() async { - final activeTrack = ref.read(audioPlayerProvider).activeTrack; - if (activeTrack == null) return; - - final palette = await PaletteGenerator.fromImageProvider( - UniversalImage.imageProvider( - (activeTrack.album?.images).asUrlString( - placeholder: ImagePlaceholder.albumArt, - ), - height: 50, - width: 50, - ), - ); - ref.read(paletteProvider.notifier).state = palette; - }); - } - StreamSubscription subscribeToPlaylist() { return audioPlayer.playlistStream.listen((mpvPlaylist) { try { if (audioPlayerState.activeTrack == null) return; notificationService.addTrack(audioPlayerState.activeTrack!); discord.updatePresence(audioPlayerState.activeTrack!); - updatePalette(); } catch (e, stack) { AppLogger.reportError(e, stack); } diff --git a/lib/provider/palette_provider.dart b/lib/provider/palette_provider.dart deleted file mode 100644 index 8f0e9e29..00000000 --- a/lib/provider/palette_provider.dart +++ /dev/null @@ -1,4 +0,0 @@ -import 'package:palette_generator/palette_generator.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; - -final paletteProvider = StateProvider((ref) => null); diff --git a/lib/provider/user_preferences/user_preferences_provider.dart b/lib/provider/user_preferences/user_preferences_provider.dart index 0f9efce1..eeb712e1 100644 --- a/lib/provider/user_preferences/user_preferences_provider.dart +++ b/lib/provider/user_preferences/user_preferences_provider.dart @@ -7,9 +7,7 @@ import 'package:shadcn_flutter/shadcn_flutter.dart' hide join; import 'package:spotify/spotify.dart'; import 'package:spotube/models/database/database.dart'; import 'package:spotube/modules/settings/color_scheme_picker_dialog.dart'; -import 'package:spotube/provider/audio_player/audio_player_streams.dart'; import 'package:spotube/provider/database/database.dart'; -import 'package:spotube/provider/palette_provider.dart'; import 'package:spotube/services/audio_player/audio_player.dart'; import 'package:spotube/services/logger/logger.dart'; import 'package:spotube/services/sourced_track/enums.dart'; @@ -144,11 +142,11 @@ class UserPreferencesNotifier extends Notifier { void setAlbumColorSync(bool sync) { setData(PreferencesTableCompanion(albumColorSync: Value(sync))); - if (!sync) { - ref.read(paletteProvider.notifier).state = null; - } else { - ref.read(audioPlayerStreamListenersProvider).updatePalette(); - } + // if (!sync) { + // ref.read(paletteProvider.notifier).state = null; + // } else { + // ref.read(audioPlayerStreamListenersProvider).updatePalette(); + // } } void setCheckUpdate(bool check) { diff --git a/lib/themes/theme.dart b/lib/themes/theme.dart deleted file mode 100644 index 485e5af7..00000000 --- a/lib/themes/theme.dart +++ /dev/null @@ -1,86 +0,0 @@ -import 'package:flutter/material.dart'; - -ThemeData theme(Color seed, Brightness brightness, bool isAmoled) { - final scheme = ColorScheme.fromSeed( - seedColor: seed, - shadow: Colors.black12, - surface: isAmoled ? Colors.black : null, - brightness: brightness, - ); - return ThemeData( - useMaterial3: true, - colorScheme: scheme, - listTileTheme: ListTileThemeData( - horizontalTitleGap: 5, - iconColor: scheme.onSurface, - ), - appBarTheme: const AppBarTheme( - surfaceTintColor: Colors.transparent, - scrolledUnderElevation: 0, - shadowColor: Colors.transparent, - elevation: 0, - ), - inputDecorationTheme: InputDecorationTheme( - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(15), - ), - ), - iconTheme: IconThemeData(size: 16, color: scheme.onSurface), - navigationBarTheme: const NavigationBarThemeData( - labelBehavior: NavigationDestinationLabelBehavior.alwaysHide, - height: 50, - iconTheme: WidgetStatePropertyAll( - IconThemeData(size: 18), - ), - ), - tabBarTheme: TabBarTheme( - indicatorSize: TabBarIndicatorSize.tab, - labelStyle: const TextStyle(fontWeight: FontWeight.w600), - labelColor: scheme.primary, - dividerColor: Colors.transparent, - indicator: BoxDecoration( - color: scheme.secondaryContainer, - borderRadius: BorderRadius.circular(15), - ), - ), - popupMenuTheme: PopupMenuThemeData( - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)), - color: scheme.surface, - elevation: 4, - labelTextStyle: WidgetStatePropertyAll( - TextStyle(color: scheme.onSurface), - ), - ), - snackBarTheme: SnackBarThemeData( - behavior: SnackBarBehavior.floating, - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)), - backgroundColor: scheme.onSurface, - contentTextStyle: TextStyle(color: scheme.surface), - ), - sliderTheme: SliderThemeData(overlayShape: SliderComponentShape.noOverlay), - searchBarTheme: SearchBarThemeData( - textStyle: const WidgetStatePropertyAll(TextStyle(fontSize: 15)), - constraints: const BoxConstraints(maxWidth: double.infinity), - padding: const WidgetStatePropertyAll(EdgeInsets.all(8)), - backgroundColor: WidgetStatePropertyAll( - Color.lerp( - scheme.surfaceContainerHighest, - scheme.surface, - brightness == Brightness.light ? .9 : .7, - ), - ), - elevation: const WidgetStatePropertyAll(0), - shape: WidgetStatePropertyAll( - RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ), - ), - ), - scrollbarTheme: const ScrollbarThemeData( - thickness: WidgetStatePropertyAll(14), - ), - checkboxTheme: CheckboxThemeData( - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), - ), - ); -} From e0760e62504de1ab28495ee7fe9cfbd630a2dd37 Mon Sep 17 00:00:00 2001 From: KRTirtho Date: Thu, 30 Jan 2025 20:36:52 +0600 Subject: [PATCH 088/112] chore: fix linux resizing blocking scrollbar --- .env.example | 1 + lib/main.dart | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.env.example b/.env.example index 888cbe6b..35c5d563 100644 --- a/.env.example +++ b/.env.example @@ -14,3 +14,4 @@ LASTFM_API_SECRET=$LASTFM_API_SECRET RELEASE_CHANNEL=$RELEASE_CHANNEL HIDE_DONATIONS=$HIDE_DONATIONS +DISABLE_SPOTIFY_IMAGES=$DISABLE_SPOTIFY_IMAGES diff --git a/lib/main.dart b/lib/main.dart index e0b6e370..3994fd50 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -189,7 +189,10 @@ class Spotube extends HookConsumerWidget { ); if (kIsLinux) { - child = DragToResizeArea(child: child); + child = DragToResizeArea( + resizeEdgeSize: 2.5, + child: child, + ); } return child; From 2ea807077151ab913632f37bbe67d7132dbf8e61 Mon Sep 17 00:00:00 2001 From: Malik Miran <76216906+malikmiran@users.noreply.github.com> Date: Thu, 30 Jan 2025 20:50:50 +0600 Subject: [PATCH 089/112] fix(ios): downloads not working due to permission errors (#2180) * Update AppDelegate.swift store the Documents directory path which the app can then use for downloads instead of trying to create a Downloads directory * Update Info.plist should resolve the permission issues because using Documents directory instead of trying to create a Downloads directory. --------- Co-authored-by: Kingkor Roy Tirtho --- ios/Runner/AppDelegate.swift | 7 ++++++- ios/Runner/Info.plist | 8 +++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index b6363034..f512ac86 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -1,12 +1,17 @@ import UIKit import Flutter -@main +@UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { + // Add this to get Documents directory path + if let documentsPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first?.path { + UserDefaults.standard.set(documentsPath, forKey: "download_path") + } + GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index ffd511a4..91b7ad94 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -72,5 +72,11 @@ _spotube._tcp + UIFileSharingEnabled + + LSSupportsOpeningDocumentsInPlace + + UISupportsDocumentBrowser + - \ No newline at end of file + From 6cf4ca91793b95f0ec3393f3e7c4a7d0e2197f57 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Thu, 30 Jan 2025 21:44:07 +0600 Subject: [PATCH 090/112] chore: use shadcn in all places that's using material --- lib/collections/env.dart | 4 +-- lib/collections/gradients.dart | 2 +- lib/collections/side_bar_tiles.dart | 2 +- lib/collections/spotube_icons.dart | 2 +- lib/components/animated_gradient.dart | 2 +- lib/components/framework/app_pop_scope.dart | 2 +- .../inter_scrollbar/inter_scrollbar.dart | 2 +- lib/components/links/artist_link.dart | 2 +- lib/components/links/hyper_link.dart | 2 +- lib/components/links/link_text.dart | 2 +- lib/components/shimmers/shimmer_lyrics.dart | 2 +- lib/components/spotube_page_route.dart | 2 +- lib/components/titlebar/titlebar_buttons.dart | 2 +- lib/extensions/color.dart | 2 +- lib/extensions/context.dart | 2 +- lib/extensions/theme.dart | 34 ------------------- .../use_fix_window_stretching.dart | 2 +- lib/hooks/configurators/use_has_touch.dart | 2 +- .../use_auto_scroll_controller.dart | 2 +- lib/hooks/controllers/use_package_info.dart | 2 +- lib/hooks/utils/use_breakpoint_value.dart | 2 +- lib/hooks/utils/use_brightness_value.dart | 3 +- .../utils/use_custom_status_bar_color.dart | 4 +-- lib/hooks/utils/use_palette_color.dart | 5 +-- lib/l10n/l10n.dart | 2 +- lib/models/database/database.steps.dart | 2 +- lib/modules/player/player_track_details.dart | 6 ++-- lib/pages/artist/section/footer.dart | 14 ++++---- lib/pages/artist/section/related_artists.dart | 2 +- .../mobile_login/hooks/login_callback.dart | 5 +-- lib/pages/mobile_login/mobile_login.dart | 19 ++++++----- .../no_webview_runtime_dialog.dart | 15 +++++--- lib/provider/spotify/spotify.dart | 2 +- .../audio_services/audio_services.dart | 2 +- lib/services/logger/logger.dart | 2 +- lib/services/wm_tools/wm_tools.dart | 2 +- 36 files changed, 70 insertions(+), 91 deletions(-) delete mode 100644 lib/extensions/theme.dart diff --git a/lib/collections/env.dart b/lib/collections/env.dart index eb6c5639..feb2a2db 100644 --- a/lib/collections/env.dart +++ b/lib/collections/env.dart @@ -39,9 +39,9 @@ abstract class Env { static final String _releaseChannel = _Env._releaseChannel; @EnviedField(varName: "DISABLE_SPOTIFY_IMAGES", defaultValue: "0") - static final int _disableSpotifyImages = _Env._disableSpotifyImages; + static final String _disableSpotifyImages = _Env._disableSpotifyImages; - static bool get disableSpotifyImages => _disableSpotifyImages == 1; + static bool get disableSpotifyImages => _disableSpotifyImages == "1"; static ReleaseChannel get releaseChannel => _releaseChannel == "stable" ? ReleaseChannel.stable diff --git a/lib/collections/gradients.dart b/lib/collections/gradients.dart index e861dde7..a7936ee2 100644 --- a/lib/collections/gradients.dart +++ b/lib/collections/gradients.dart @@ -1,4 +1,4 @@ -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; const gradients = [ LinearGradient(colors: [ diff --git a/lib/collections/side_bar_tiles.dart b/lib/collections/side_bar_tiles.dart index f84bd158..f12517bb 100644 --- a/lib/collections/side_bar_tiles.dart +++ b/lib/collections/side_bar_tiles.dart @@ -1,4 +1,4 @@ -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:spotube/pages/home/home.dart'; diff --git a/lib/collections/spotube_icons.dart b/lib/collections/spotube_icons.dart index 56192d18..b5fbe5e8 100644 --- a/lib/collections/spotube_icons.dart +++ b/lib/collections/spotube_icons.dart @@ -1,5 +1,5 @@ import 'package:fluentui_system_icons/fluentui_system_icons.dart'; -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:flutter_feather_icons/flutter_feather_icons.dart'; import 'package:simple_icons/simple_icons.dart'; diff --git a/lib/components/animated_gradient.dart b/lib/components/animated_gradient.dart index aaba2ff9..a9d4ef2b 100644 --- a/lib/components/animated_gradient.dart +++ b/lib/components/animated_gradient.dart @@ -1,4 +1,4 @@ -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; class AnimateGradient extends HookWidget { diff --git a/lib/components/framework/app_pop_scope.dart b/lib/components/framework/app_pop_scope.dart index b8e35767..fe923958 100644 --- a/lib/components/framework/app_pop_scope.dart +++ b/lib/components/framework/app_pop_scope.dart @@ -1,6 +1,6 @@ import 'dart:io'; -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; /// A temporary workaround for [WillPopScope] and [PopScope] not working in GoRouter /// https://github.com/flutter/flutter/issues/140869#issuecomment-2247181468 diff --git a/lib/components/inter_scrollbar/inter_scrollbar.dart b/lib/components/inter_scrollbar/inter_scrollbar.dart index 8a86b643..415ba6da 100644 --- a/lib/components/inter_scrollbar/inter_scrollbar.dart +++ b/lib/components/inter_scrollbar/inter_scrollbar.dart @@ -1,5 +1,5 @@ import 'package:draggable_scrollbar/draggable_scrollbar.dart'; -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:spotube/utils/platform.dart'; diff --git a/lib/components/links/artist_link.dart b/lib/components/links/artist_link.dart index 9f06f1b3..c6ea5c14 100644 --- a/lib/components/links/artist_link.dart +++ b/lib/components/links/artist_link.dart @@ -1,4 +1,4 @@ -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/links/anchor_button.dart'; import 'package:spotube/extensions/context.dart'; diff --git a/lib/components/links/hyper_link.dart b/lib/components/links/hyper_link.dart index 32d715e0..647edaca 100644 --- a/lib/components/links/hyper_link.dart +++ b/lib/components/links/hyper_link.dart @@ -1,4 +1,4 @@ -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/components/links/anchor_button.dart'; import 'package:url_launcher/url_launcher_string.dart'; diff --git a/lib/components/links/link_text.dart b/lib/components/links/link_text.dart index 0cab71d0..a54c8b9f 100644 --- a/lib/components/links/link_text.dart +++ b/lib/components/links/link_text.dart @@ -1,4 +1,4 @@ -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/components/links/anchor_button.dart'; import 'package:spotube/utils/service_utils.dart'; diff --git a/lib/components/shimmers/shimmer_lyrics.dart b/lib/components/shimmers/shimmer_lyrics.dart index 03816202..f8d29722 100644 --- a/lib/components/shimmers/shimmer_lyrics.dart +++ b/lib/components/shimmers/shimmer_lyrics.dart @@ -1,4 +1,4 @@ -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:gap/gap.dart'; diff --git a/lib/components/spotube_page_route.dart b/lib/components/spotube_page_route.dart index 22e4d2f1..6d152dd5 100644 --- a/lib/components/spotube_page_route.dart +++ b/lib/components/spotube_page_route.dart @@ -1,4 +1,4 @@ -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:go_router/go_router.dart'; class SpotubePage extends MaterialPage { diff --git a/lib/components/titlebar/titlebar_buttons.dart b/lib/components/titlebar/titlebar_buttons.dart index 92c2c93d..30d88508 100644 --- a/lib/components/titlebar/titlebar_buttons.dart +++ b/lib/components/titlebar/titlebar_buttons.dart @@ -1,4 +1,4 @@ -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; diff --git a/lib/extensions/color.dart b/lib/extensions/color.dart index 68cd8ef7..bc7d65a2 100644 --- a/lib/extensions/color.dart +++ b/lib/extensions/color.dart @@ -1,4 +1,4 @@ -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; extension ColorAlterer on Color { Color darken(double amount) { diff --git a/lib/extensions/context.dart b/lib/extensions/context.dart index 9ca1e237..f6c5915c 100644 --- a/lib/extensions/context.dart +++ b/lib/extensions/context.dart @@ -1,4 +1,4 @@ -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; extension AppLocale on BuildContext { diff --git a/lib/extensions/theme.dart b/lib/extensions/theme.dart deleted file mode 100644 index 22a1ce84..00000000 --- a/lib/extensions/theme.dart +++ /dev/null @@ -1,34 +0,0 @@ -import 'package:flutter/material.dart'; - -class ShimmerColorTheme extends ThemeExtension { - final Color? shimmerColor; - final Color? shimmerBackgroundColor; - - ShimmerColorTheme({ - this.shimmerBackgroundColor, - this.shimmerColor, - }); - - @override - ThemeExtension copyWith( - {Color? shimmerColor, Color? shimmerBackgroundColor}) { - return ShimmerColorTheme( - shimmerBackgroundColor: - shimmerBackgroundColor ?? this.shimmerBackgroundColor, - shimmerColor: shimmerColor ?? this.shimmerColor, - ); - } - - @override - ThemeExtension lerp( - ThemeExtension? other, double t) { - if (other is! ShimmerColorTheme) { - return this; - } - return ShimmerColorTheme( - shimmerBackgroundColor: - Color.lerp(shimmerBackgroundColor, other.shimmerBackgroundColor, t), - shimmerColor: Color.lerp(shimmerColor, other.shimmerColor, t), - ); - } -} diff --git a/lib/hooks/configurators/use_fix_window_stretching.dart b/lib/hooks/configurators/use_fix_window_stretching.dart index a6603d59..b94098ab 100644 --- a/lib/hooks/configurators/use_fix_window_stretching.dart +++ b/lib/hooks/configurators/use_fix_window_stretching.dart @@ -1,4 +1,4 @@ -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:spotube/utils/platform.dart'; import 'package:window_manager/window_manager.dart'; diff --git a/lib/hooks/configurators/use_has_touch.dart b/lib/hooks/configurators/use_has_touch.dart index 75353f27..5ce309b8 100644 --- a/lib/hooks/configurators/use_has_touch.dart +++ b/lib/hooks/configurators/use_has_touch.dart @@ -1,5 +1,5 @@ import 'package:flutter/gestures.dart'; -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:spotube/utils/platform.dart'; diff --git a/lib/hooks/controllers/use_auto_scroll_controller.dart b/lib/hooks/controllers/use_auto_scroll_controller.dart index 0c7119e4..befc4351 100644 --- a/lib/hooks/controllers/use_auto_scroll_controller.dart +++ b/lib/hooks/controllers/use_auto_scroll_controller.dart @@ -1,4 +1,4 @@ -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:scroll_to_index/scroll_to_index.dart'; diff --git a/lib/hooks/controllers/use_package_info.dart b/lib/hooks/controllers/use_package_info.dart index b3c05665..07b53af6 100644 --- a/lib/hooks/controllers/use_package_info.dart +++ b/lib/hooks/controllers/use_package_info.dart @@ -1,4 +1,4 @@ -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:package_info_plus/package_info_plus.dart'; diff --git a/lib/hooks/utils/use_breakpoint_value.dart b/lib/hooks/utils/use_breakpoint_value.dart index b2592124..74b2f860 100644 --- a/lib/hooks/utils/use_breakpoint_value.dart +++ b/lib/hooks/utils/use_breakpoint_value.dart @@ -1,4 +1,4 @@ -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:spotube/extensions/constrains.dart'; diff --git a/lib/hooks/utils/use_brightness_value.dart b/lib/hooks/utils/use_brightness_value.dart index d3823b2f..64e3f27c 100644 --- a/lib/hooks/utils/use_brightness_value.dart +++ b/lib/hooks/utils/use_brightness_value.dart @@ -1,4 +1,5 @@ -import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; T useBrightnessValue( diff --git a/lib/hooks/utils/use_custom_status_bar_color.dart b/lib/hooks/utils/use_custom_status_bar_color.dart index 8afc6a59..f34ae7a8 100644 --- a/lib/hooks/utils/use_custom_status_bar_color.dart +++ b/lib/hooks/utils/use_custom_status_bar_color.dart @@ -1,4 +1,4 @@ -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; @@ -9,7 +9,7 @@ VoidCallback useCustomStatusBarColor( bool? automaticSystemUiAdjustment, }) { final context = useContext(); - final backgroundColor = Theme.of(context).scaffoldBackgroundColor; + final backgroundColor = Theme.of(context).colorScheme.background; // ignore: invalid_use_of_visible_for_testing_member final previousState = SystemChrome.latestStyle; diff --git a/lib/hooks/utils/use_palette_color.dart b/lib/hooks/utils/use_palette_color.dart index 64994d2b..c70bcf72 100644 --- a/lib/hooks/utils/use_palette_color.dart +++ b/lib/hooks/utils/use_palette_color.dart @@ -1,4 +1,5 @@ -import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:palette_generator/palette_generator.dart'; @@ -6,7 +7,7 @@ import 'package:spotube/components/image/universal_image.dart'; final _paletteColorState = StateProvider( (ref) { - return PaletteColor(Colors.grey[300]!, 0); + return PaletteColor(Colors.gray[300], 0); }, ); diff --git a/lib/l10n/l10n.dart b/lib/l10n/l10n.dart index ebdc4b61..2dba8370 100644 --- a/lib/l10n/l10n.dart +++ b/lib/l10n/l10n.dart @@ -16,7 +16,7 @@ library l10n; -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; class L10n { static final all = [ diff --git a/lib/models/database/database.steps.dart b/lib/models/database/database.steps.dart index 11a564c6..25bf6ad9 100644 --- a/lib/models/database/database.steps.dart +++ b/lib/models/database/database.steps.dart @@ -2,7 +2,7 @@ import 'package:drift/internal/versioned_schema.dart' as i0; import 'package:drift/drift.dart' as i1; import 'package:drift/drift.dart'; // ignore_for_file: type=lint,unused_import -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/models/database/database.dart'; import 'package:spotube/services/sourced_track/enums.dart'; diff --git a/lib/modules/player/player_track_details.dart b/lib/modules/player/player_track_details.dart index 8d3b99fa..5c13f3e8 100644 --- a/lib/modules/player/player_track_details.dart +++ b/lib/modules/player/player_track_details.dart @@ -1,4 +1,4 @@ -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; @@ -53,14 +53,14 @@ class PlayerTrackDetails extends HookConsumerWidget { "/track/${playback.activeTrack?.id}", push: true, overflow: TextOverflow.ellipsis, - style: theme.textTheme.bodyMedium!.copyWith( + style: theme.typography.normal.copyWith( color: color, ), ), Text( playback.activeTrack?.artists?.asString() ?? "", overflow: TextOverflow.ellipsis, - style: theme.textTheme.bodySmall!.copyWith(color: color), + style: theme.typography.small.copyWith(color: color), ) ], ), diff --git a/lib/pages/artist/section/footer.dart b/lib/pages/artist/section/footer.dart index 61d9d100..0fe2ab68 100644 --- a/lib/pages/artist/section/footer.dart +++ b/lib/pages/artist/section/footer.dart @@ -1,5 +1,5 @@ import 'package:flutter/gestures.dart'; -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/collections/spotube_icons.dart'; @@ -16,7 +16,7 @@ class ArtistPageFooter extends ConsumerWidget { @override Widget build(BuildContext context, ref) { - final ThemeData(:textTheme) = Theme.of(context); + final ThemeData(:typography) = Theme.of(context); final mediaQuery = MediaQuery.of(context); final artistImage = artist.images.asUrlString( @@ -50,7 +50,7 @@ class ArtistPageFooter extends ConsumerWidget { alignment: Alignment.center, child: RichText( text: TextSpan( - style: textTheme.bodyLarge?.copyWith( + style: typography.semiBold.copyWith( color: Colors.white, ), children: [ @@ -64,7 +64,7 @@ class ArtistPageFooter extends ConsumerWidget { ), TextSpan( text: " Wikipedia", - style: textTheme.titleLarge?.copyWith( + style: typography.large.copyWith( color: Colors.white, ), ), @@ -74,10 +74,10 @@ class ArtistPageFooter extends ConsumerWidget { ), TextSpan( text: '\n...read more at wikipedia', - style: textTheme.bodyLarge?.copyWith( - color: Colors.lightBlue[300], + style: typography.semiBold.copyWith( + color: Colors.sky[300], decoration: TextDecoration.underline, - decorationColor: Colors.lightBlue[300], + decorationColor: Colors.sky[300], ), recognizer: TapGestureRecognizer() ..onTap = () async { diff --git a/lib/pages/artist/section/related_artists.dart b/lib/pages/artist/section/related_artists.dart index 066f73fd..2db9ca94 100644 --- a/lib/pages/artist/section/related_artists.dart +++ b/lib/pages/artist/section/related_artists.dart @@ -1,4 +1,4 @@ -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotube/modules/artist/artist_card.dart'; import 'package:spotube/provider/spotify/spotify.dart'; diff --git a/lib/pages/mobile_login/hooks/login_callback.dart b/lib/pages/mobile_login/hooks/login_callback.dart index 07c0210a..9979f4a5 100644 --- a/lib/pages/mobile_login/hooks/login_callback.dart +++ b/lib/pages/mobile_login/hooks/login_callback.dart @@ -1,7 +1,7 @@ import 'dart:io'; import 'package:desktop_webview_window/desktop_webview_window.dart'; -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart' hide join; import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:go_router/go_router.dart'; @@ -28,7 +28,8 @@ Future Function() useLoginCallback(WidgetRef ref) { final exp = RegExp(r"https:\/\/accounts.spotify.com\/.+\/status"); final applicationSupportDir = await getApplicationSupportDirectory(); final userDataFolder = Directory( - join(applicationSupportDir.path, "webview_window_Webview2")); + join(applicationSupportDir.path, "webview_window_Webview2"), + ); if (!await userDataFolder.exists()) { await userDataFolder.create(); diff --git a/lib/pages/mobile_login/mobile_login.dart b/lib/pages/mobile_login/mobile_login.dart index fa818dc8..e2191586 100644 --- a/lib/pages/mobile_login/mobile_login.dart +++ b/lib/pages/mobile_login/mobile_login.dart @@ -1,7 +1,8 @@ -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotube/components/button/back_button.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/provider/authentication/authentication.dart'; @@ -17,19 +18,21 @@ class WebViewLogin extends HookConsumerWidget { if (kIsDesktop) { const Scaffold( - body: Center( + child: Center( child: Text('This feature is not available on desktop'), ), ); } return Scaffold( - appBar: const TitleBar( - leading: [BackButton(color: Colors.white)], - backgroundColor: Colors.transparent, - ), - extendBodyBehindAppBar: true, - body: InAppWebView( + headers: const [ + TitleBar( + leading: [BackButton(color: Colors.white)], + backgroundColor: Colors.transparent, + ), + ], + floatingHeader: true, + child: InAppWebView( initialSettings: InAppWebViewSettings( userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 safari/537.36", diff --git a/lib/pages/mobile_login/no_webview_runtime_dialog.dart b/lib/pages/mobile_login/no_webview_runtime_dialog.dart index a6cc5ffb..b0919e5c 100644 --- a/lib/pages/mobile_login/no_webview_runtime_dialog.dart +++ b/lib/pages/mobile_login/no_webview_runtime_dialog.dart @@ -1,4 +1,4 @@ -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/extensions/context.dart'; import 'package:url_launcher/url_launcher_string.dart'; @@ -19,7 +19,7 @@ class NoWebviewRuntimeDialog extends StatelessWidget { }, child: Text(context.l10n.cancel), ), - FilledButton( + Button.primary( onPressed: () async { final url = switch (platform) { TargetPlatform.windows => @@ -30,8 +30,15 @@ class NoWebviewRuntimeDialog extends StatelessWidget { _ => "", }; if (url.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Unsupported platform')), + showToast( + context: context, + builder: (context, overlay) { + return const SurfaceCard( + child: Basic( + title: Text('Unsupported platform'), + ), + ); + }, ); } diff --git a/lib/provider/spotify/spotify.dart b/lib/provider/spotify/spotify.dart index 344116cd..d43e34cd 100644 --- a/lib/provider/spotify/spotify.dart +++ b/lib/provider/spotify/spotify.dart @@ -11,7 +11,7 @@ import 'package:spotube/provider/database/database.dart'; import 'package:spotube/services/logger/logger.dart'; import 'package:collection/collection.dart'; import 'package:dio/dio.dart'; -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:intl/intl.dart'; import 'package:lrc/lrc.dart'; import 'package:package_info_plus/package_info_plus.dart'; diff --git a/lib/services/audio_services/audio_services.dart b/lib/services/audio_services/audio_services.dart index 6433707d..060a7f41 100644 --- a/lib/services/audio_services/audio_services.dart +++ b/lib/services/audio_services/audio_services.dart @@ -1,5 +1,5 @@ import 'package:audio_service/audio_service.dart'; -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/collections/env.dart'; diff --git a/lib/services/logger/logger.dart b/lib/services/logger/logger.dart index 46fc6de5..d1595930 100644 --- a/lib/services/logger/logger.dart +++ b/lib/services/logger/logger.dart @@ -3,7 +3,7 @@ import 'dart:io'; import 'dart:isolate'; import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart' hide join; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:logger/logger.dart'; import 'package:path/path.dart'; diff --git a/lib/services/wm_tools/wm_tools.dart b/lib/services/wm_tools/wm_tools.dart index 920e09b5..f60b4ac9 100644 --- a/lib/services/wm_tools/wm_tools.dart +++ b/lib/services/wm_tools/wm_tools.dart @@ -1,4 +1,4 @@ -import 'package:flutter/material.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/services/kv_store/kv_store.dart'; import 'package:spotube/utils/platform.dart'; import 'package:window_manager/window_manager.dart'; From 003767738357248b4dc5df47573fd5d7c9982d11 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 31 Jan 2025 21:07:51 +0600 Subject: [PATCH 091/112] refactor: migrate to auto_route from go_router --- build.yaml | 10 + lib/collections/intents.dart | 36 +- lib/collections/routes.dart | 561 +++----- lib/collections/routes.gr.dart | 1143 +++++++++++++++++ lib/collections/side_bar_tiles.dart | 38 +- .../dialogs/track_details_dialog.dart | 4 +- .../fallbacks/anonymous_fallback.dart | 6 +- lib/components/links/artist_link.dart | 13 +- lib/components/links/link_text.dart | 10 +- lib/components/spotube_page_route.dart | 37 +- lib/components/track_tile/track_options.dart | 20 +- lib/components/track_tile/track_tile.dart | 29 +- lib/hooks/configurators/use_deep_linking.dart | 32 +- lib/main.dart | 24 +- lib/modules/album/album_card.dart | 13 +- lib/modules/artist/artist_card.dart | 12 +- lib/modules/connect/connect_device.dart | 12 +- lib/modules/home/sections/feed.dart | 14 +- .../home/sections/friends/friend_item.dart | 40 +- .../home/sections/genres/genre_card.dart | 13 +- .../genres/genre_card_playlist_card.dart | 12 +- lib/modules/home/sections/genres/genres.dart | 7 +- .../local_folder/local_folder_item.dart | 17 +- .../library/user_downloads/download_item.dart | 14 +- lib/modules/player/player.dart | 17 +- lib/modules/player/player_track_details.dart | 20 +- lib/modules/playlist/playlist_card.dart | 13 +- .../playlist/playlist_create_dialog.dart | 4 +- lib/modules/root/bottom_player.dart | 8 +- lib/modules/root/sidebar.dart | 270 ---- lib/modules/root/sidebar/sidebar.dart | 132 ++ lib/modules/root/sidebar/sidebar_footer.dart | 140 ++ lib/modules/root/spotube_navigation_bar.dart | 36 +- lib/modules/stats/common/album_item.dart | 20 +- lib/modules/stats/common/artist_item.dart | 10 +- lib/modules/stats/common/playlist_item.dart | 11 +- lib/modules/stats/common/track_item.dart | 22 +- lib/modules/stats/summary/summary.dart | 21 +- lib/modules/stats/top/top.dart | 1 + lib/pages/album/album.dart | 4 + lib/pages/artist/artist.dart | 7 +- lib/pages/connect/connect.dart | 10 +- lib/pages/connect/control/control.dart | 26 +- .../getting_started/getting_started.dart | 6 +- .../getting_started/sections/support.dart | 6 +- lib/pages/home/feed/feed_section.dart | 7 +- lib/pages/home/genres/genre_playlists.dart | 14 +- lib/pages/home/genres/genres.dart | 17 +- lib/pages/home/home.dart | 7 +- lib/pages/lastfm_login/lastfm_login.dart | 8 +- lib/pages/library/library.dart | 18 +- .../playlist_generate/playlist_generate.dart | 12 +- .../playlist_generate_result.dart | 21 +- lib/pages/library/user_albums.dart | 2 + lib/pages/library/user_artists.dart | 2 + lib/pages/library/user_downloads.dart | 2 + .../user_local_tracks/local_folder.dart | 2 + .../user_local_tracks/user_local_tracks.dart | 2 + lib/pages/library/user_playlists.dart | 10 +- lib/pages/lyrics/lyrics.dart | 2 + lib/pages/lyrics/mini_lyrics.dart | 7 +- .../mobile_login/hooks/login_callback.dart | 11 +- lib/pages/mobile_login/mobile_login.dart | 11 +- lib/pages/playlist/liked_playlist.dart | 2 + lib/pages/playlist/playlist.dart | 4 + lib/pages/profile/profile.dart | 2 + lib/pages/root/root_app.dart | 31 +- lib/pages/search/search.dart | 2 + lib/pages/settings/about.dart | 6 +- lib/pages/settings/blacklist.dart | 2 + lib/pages/settings/logs.dart | 2 + lib/pages/settings/sections/about.dart | 6 +- lib/pages/settings/sections/accounts.dart | 13 +- lib/pages/settings/sections/developers.dart | 6 +- lib/pages/settings/sections/playback.dart | 5 +- lib/pages/settings/settings.dart | 2 + lib/pages/stats/albums/albums.dart | 2 + lib/pages/stats/artists/artists.dart | 2 + lib/pages/stats/fees/fees.dart | 2 + lib/pages/stats/minutes/minutes.dart | 2 + lib/pages/stats/playlists/playlists.dart | 2 + lib/pages/stats/stats.dart | 2 + lib/pages/stats/streams/streams.dart | 2 + lib/pages/track/track.dart | 12 +- lib/utils/service_utils.dart | 67 +- pubspec.lock | 24 +- pubspec.yaml | 3 +- 87 files changed, 2086 insertions(+), 1173 deletions(-) create mode 100644 lib/collections/routes.gr.dart delete mode 100644 lib/modules/root/sidebar.dart create mode 100644 lib/modules/root/sidebar/sidebar.dart create mode 100644 lib/modules/root/sidebar/sidebar_footer.dart diff --git a/build.yaml b/build.yaml index 17d5bc50..76771f22 100644 --- a/build.yaml +++ b/build.yaml @@ -4,6 +4,16 @@ targets: exclude: - bin/*.dart builders: + auto_route_generator:auto_route_generator: # this for @RoutePage + options: + enable_cached_builds: true + generate_for: + - lib/pages/**/*.dart + auto_route_generator:auto_router_generator: # this for @AutoRouterConfig + options: + enable_cached_builds: true + generate_for: + - lib/collections/routes.dart json_serializable: options: any_map: true diff --git a/lib/collections/intents.dart b/lib/collections/intents.dart index d0a0c8b6..e4e3fa07 100644 --- a/lib/collections/intents.dart +++ b/lib/collections/intents.dart @@ -3,17 +3,9 @@ import 'dart:io'; import 'package:flutter/cupertino.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:go_router/go_router.dart'; import 'package:spotube/collections/routes.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/modules/player/player_controls.dart'; -import 'package:spotube/pages/home/home.dart'; -import 'package:spotube/pages/library/user_albums.dart'; -import 'package:spotube/pages/library/user_artists.dart'; -import 'package:spotube/pages/library/user_downloads.dart'; -import 'package:spotube/pages/library/user_local_tracks/user_local_tracks.dart'; -import 'package:spotube/pages/library/user_playlists.dart'; -import 'package:spotube/pages/lyrics/lyrics.dart'; -import 'package:spotube/pages/search/search.dart'; import 'package:spotube/provider/audio_player/querying_track_info.dart'; import 'package:spotube/services/audio_player/audio_player.dart'; import 'package:spotube/utils/platform.dart'; @@ -40,7 +32,7 @@ class PlayPauseAction extends Action { } class NavigationIntent extends Intent { - final GoRouter router; + final AppRouter router; final String path; const NavigationIntent(this.router, this.path); } @@ -48,7 +40,7 @@ class NavigationIntent extends Intent { class NavigationAction extends Action { @override invoke(intent) { - intent.router.go(intent.path); + intent.router.navigateNamed(intent.path); return null; } } @@ -66,39 +58,39 @@ enum HomeTabs { } class HomeTabIntent extends Intent { - final WidgetRef ref; + final AppRouter router; final HomeTabs tab; - const HomeTabIntent(this.ref, {required this.tab}); + const HomeTabIntent(this.router, {required this.tab}); } class HomeTabAction extends Action { @override invoke(intent) { - final router = intent.ref.read(routerProvider); + final router = intent.router; switch (intent.tab) { case HomeTabs.browse: - router.goNamed(HomePage.name); + router.navigate(const HomeRoute()); break; case HomeTabs.search: - router.goNamed(SearchPage.name); + router.navigate(const SearchRoute()); break; case HomeTabs.lyrics: - router.goNamed(LyricsPage.name); + router.navigate(LyricsRoute()); break; case HomeTabs.userPlaylists: - router.goNamed(UserPlaylistsPage.name); + router.navigate(const UserPlaylistsRoute()); break; case HomeTabs.userArtists: - router.goNamed(UserArtistsPage.name); + router.navigate(const UserArtistsRoute()); break; case HomeTabs.userAlbums: - router.goNamed(UserAlbumsPage.name); + router.navigate(const UserAlbumsRoute()); break; case HomeTabs.userLocalLibrary: - router.goNamed(UserLocalLibraryPage.name); + router.navigate(const UserLocalLibraryRoute()); break; case HomeTabs.userDownloads: - router.goNamed(UserDownloadsPage.name); + router.navigate(const UserDownloadsRoute()); break; } return null; diff --git a/lib/collections/routes.dart b/lib/collections/routes.dart index 4cd869cd..367e6eb8 100644 --- a/lib/collections/routes.dart +++ b/lib/collections/routes.dart @@ -1,365 +1,216 @@ -import 'package:flutter/foundation.dart' hide Category; -import 'package:flutter/widgets.dart'; -import 'package:go_router/go_router.dart'; +import 'package:auto_route/auto_route.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:spotify/spotify.dart' hide Search; -import 'package:spotube/models/spotify/recommendation_seeds.dart'; -import 'package:spotube/pages/album/album.dart'; -import 'package:spotube/pages/connect/connect.dart'; -import 'package:spotube/pages/connect/control/control.dart'; -import 'package:spotube/pages/getting_started/getting_started.dart'; -import 'package:spotube/pages/home/feed/feed_section.dart'; -import 'package:spotube/pages/home/genres/genre_playlists.dart'; -import 'package:spotube/pages/home/genres/genres.dart'; -import 'package:spotube/pages/home/home.dart'; -import 'package:spotube/pages/lastfm_login/lastfm_login.dart'; -import 'package:spotube/pages/library/user_local_tracks/local_folder.dart'; -import 'package:spotube/pages/library/playlist_generate/playlist_generate.dart'; -import 'package:spotube/pages/library/playlist_generate/playlist_generate_result.dart'; -import 'package:spotube/pages/library/user_albums.dart'; -import 'package:spotube/pages/library/user_artists.dart'; -import 'package:spotube/pages/library/user_downloads.dart'; -import 'package:spotube/pages/library/user_local_tracks/user_local_tracks.dart'; -import 'package:spotube/pages/library/user_playlists.dart'; -import 'package:spotube/pages/lyrics/mini_lyrics.dart'; -import 'package:spotube/pages/playlist/liked_playlist.dart'; -import 'package:spotube/pages/playlist/playlist.dart'; -import 'package:spotube/pages/profile/profile.dart'; -import 'package:spotube/pages/search/search.dart'; -import 'package:spotube/pages/settings/blacklist.dart'; -import 'package:spotube/pages/settings/about.dart'; -import 'package:spotube/pages/settings/logs.dart'; -import 'package:spotube/pages/stats/albums/albums.dart'; -import 'package:spotube/pages/stats/artists/artists.dart'; -import 'package:spotube/pages/stats/fees/fees.dart'; -import 'package:spotube/pages/stats/minutes/minutes.dart'; -import 'package:spotube/pages/stats/playlists/playlists.dart'; -import 'package:spotube/pages/stats/stats.dart'; -import 'package:spotube/pages/stats/streams/streams.dart'; -import 'package:spotube/pages/track/track.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/provider/authentication/authentication.dart'; import 'package:spotube/services/kv_store/kv_store.dart'; -import 'package:spotube/components/spotube_page_route.dart'; -import 'package:spotube/pages/artist/artist.dart'; -import 'package:spotube/pages/library/library.dart'; -import 'package:spotube/pages/lyrics/lyrics.dart'; -import 'package:spotube/pages/root/root_app.dart'; -import 'package:spotube/pages/settings/settings.dart'; -import 'package:spotube/pages/mobile_login/mobile_login.dart'; final rootNavigatorKey = GlobalKey(); -final shellRouteNavigatorKey = GlobalKey(); -final routerProvider = Provider((ref) { - return GoRouter( - navigatorKey: rootNavigatorKey, - routes: [ - ShellRoute( - navigatorKey: shellRouteNavigatorKey, - builder: (context, state, child) => RootApp(child: child), - routes: [ - GoRoute( - path: "/", - name: HomePage.name, - redirect: (context, state) async { - final auth = await ref.read(authenticationProvider.future); - if (auth == null && !KVStoreService.doneGettingStarted) { - return "/getting-started"; - } +@AutoRouterConfig(replaceInRouteName: 'Screen|Page,Route') +class AppRouter extends RootStackRouter { + final WidgetRef ref; - return null; - }, - pageBuilder: (context, state) => - const SpotubePage(child: HomePage()), - routes: [ - GoRoute( - path: "genres", - name: GenrePage.name, - pageBuilder: (context, state) => - const SpotubePage(child: GenrePage()), - ), - GoRoute( - path: "genre/:categoryId", - name: GenrePlaylistsPage.name, - pageBuilder: (context, state) => SpotubePage( - child: GenrePlaylistsPage( - category: state.extra as Category, - ), - ), - ), - GoRoute( - path: "feeds/:feedId", - name: HomeFeedSectionPage.name, - pageBuilder: (context, state) => SpotubePage( - child: HomeFeedSectionPage( - sectionUri: state.pathParameters["feedId"] as String, - ), - ), - ) - ], - ), - GoRoute( - path: "/search", - name: SearchPage.name, - pageBuilder: (context, state) => - const SpotubePage(child: SearchPage()), - ), - ShellRoute( - pageBuilder: (context, state, child) => - SpotubePage(child: LibraryPage(child: child)), - routes: [ - GoRoute( - path: "/library/playlists", - name: UserPlaylistsPage.name, - pageBuilder: (context, state) => - const SpotubePage(child: UserPlaylistsPage()), - ), - GoRoute( - path: "/library/artists", - name: UserArtistsPage.name, - pageBuilder: (context, state) => - const SpotubePage(child: UserArtistsPage()), - ), - GoRoute( - path: "/library/album", - name: UserAlbumsPage.name, - pageBuilder: (context, state) => - const SpotubePage(child: UserAlbumsPage()), - ), - GoRoute( - path: "/library/local", - name: UserLocalLibraryPage.name, - pageBuilder: (context, state) => - const SpotubePage(child: UserLocalLibraryPage()), - routes: [ - GoRoute( - path: "folder", - name: LocalLibraryPage.name, - parentNavigatorKey: shellRouteNavigatorKey, - pageBuilder: (context, state) { - assert(state.extra is String); - return SpotubePage( - child: LocalLibraryPage( - state.extra as String, - isDownloads: - state.uri.queryParameters["downloads"] != null, - isCache: state.uri.queryParameters["cache"] != null, - ), - ); - }, - ), - ]), - GoRoute( - path: "/library/downloads", - name: UserDownloadsPage.name, - pageBuilder: (context, state) => - const SpotubePage(child: UserDownloadsPage()), - ), - ], - ), - GoRoute( - path: "/library/generate", - name: PlaylistGeneratorPage.name, - pageBuilder: (context, state) => - const SpotubePage(child: PlaylistGeneratorPage()), - routes: [ - GoRoute( - path: "result", - name: PlaylistGenerateResultPage.name, - pageBuilder: (context, state) => SpotubePage( - child: PlaylistGenerateResultPage( - state: state.extra as GeneratePlaylistProviderInput, - ), - ), - ) - ], - ), - GoRoute( - path: "/lyrics", - name: LyricsPage.name, - pageBuilder: (context, state) => - const SpotubePage(child: LyricsPage()), - ), - GoRoute( - path: "/settings", - name: SettingsPage.name, - pageBuilder: (context, state) => const SpotubePage( - child: SettingsPage(), - ), - routes: [ - GoRoute( - path: "blacklist", - name: BlackListPage.name, - pageBuilder: (context, state) => SpotubeSlidePage( - child: const BlackListPage(), - ), - ), - if (!kIsWeb) - GoRoute( - path: "logs", - name: LogsPage.name, - pageBuilder: (context, state) => SpotubeSlidePage( - child: const LogsPage(), - ), - ), - GoRoute( - path: "about", - name: AboutSpotube.name, - pageBuilder: (context, state) => SpotubeSlidePage( - child: const AboutSpotube(), - ), - ), - ], - ), - GoRoute( - path: "/album/:id", - name: AlbumPage.name, - pageBuilder: (context, state) { - assert(state.extra is AlbumSimple); - return SpotubePage( - child: AlbumPage(album: state.extra as AlbumSimple), - ); - }, - ), - GoRoute( - path: "/artist/:id", - name: ArtistPage.name, - pageBuilder: (context, state) { - assert(state.pathParameters["id"] != null); - return SpotubePage( - child: ArtistPage(state.pathParameters["id"]!)); - }, - ), - GoRoute( - path: "/playlist/:id", - name: PlaylistPage.name, - pageBuilder: (context, state) { - assert(state.extra is PlaylistSimple); - return SpotubePage( - child: state.pathParameters["id"] == "user-liked-tracks" - ? LikedPlaylistPage(playlist: state.extra as PlaylistSimple) - : PlaylistPage(playlist: state.extra as PlaylistSimple), - ); - }, - ), - GoRoute( - path: "/track/:id", - name: TrackPage.name, - pageBuilder: (context, state) { - final id = state.pathParameters["id"]!; - return SpotubePage( - child: TrackPage(trackId: id), - ); - }, - ), - GoRoute( - path: "/connect", - name: ConnectPage.name, - pageBuilder: (context, state) => const SpotubePage( - child: ConnectPage(), - ), - routes: [ - GoRoute( - path: "control", - name: ConnectControlPage.name, - pageBuilder: (context, state) { - return const SpotubePage( - child: ConnectControlPage(), - ); - }, - ) - ], - ), - GoRoute( - path: "/profile", - name: ProfilePage.name, - pageBuilder: (context, state) => - const SpotubePage(child: ProfilePage()), - ), - GoRoute( - path: "/stats", - name: StatsPage.name, - pageBuilder: (context, state) => const SpotubePage( - child: StatsPage(), - ), - routes: [ - GoRoute( - path: "minutes", - name: StatsMinutesPage.name, - pageBuilder: (context, state) => const SpotubePage( - child: StatsMinutesPage(), - ), - ), - GoRoute( - path: "streams", - name: StatsStreamsPage.name, - pageBuilder: (context, state) => const SpotubePage( - child: StatsStreamsPage(), - ), - ), - GoRoute( - path: "fees", - name: StatsStreamFeesPage.name, - pageBuilder: (context, state) => const SpotubePage( - child: StatsStreamFeesPage(), - ), - ), - GoRoute( - path: "artists", - name: StatsArtistsPage.name, - pageBuilder: (context, state) => const SpotubePage( - child: StatsArtistsPage(), - ), - ), - GoRoute( - path: "albums", - name: StatsAlbumsPage.name, - pageBuilder: (context, state) => const SpotubePage( - child: StatsAlbumsPage(), - ), - ), - GoRoute( - path: "playlists", - name: StatsPlaylistsPage.name, - pageBuilder: (context, state) => const SpotubePage( - child: StatsPlaylistsPage(), - ), - ), - ], - ) - ], - ), - GoRoute( - path: "/mini-player", - name: MiniLyricsPage.name, - parentNavigatorKey: rootNavigatorKey, - pageBuilder: (context, state) => SpotubePage( - child: MiniLyricsPage(prevSize: state.extra as Size), + AppRouter(this.ref) : super(navigatorKey: rootNavigatorKey); + + @override + List get guards => [ + AutoRouteGuardCallback( + (resolver, router) async { + final auth = await ref.read(authenticationProvider.future); + + if (auth == null && !KVStoreService.doneGettingStarted) { + resolver.redirect(const GettingStartedRoute()); + } else { + resolver.next(true); + } + }, ), - ), - GoRoute( - path: "/getting-started", - name: GettingStarting.name, - parentNavigatorKey: rootNavigatorKey, - pageBuilder: (context, state) => const SpotubePage( - child: GettingStarting(), + ]; + + @override + List get routes => [ + AutoRoute( + page: RootAppRoute.page, + path: "/", + initial: true, + children: [ + AutoRoute( + path: "browse", + page: HomeRoute.page, + initial: true, + ), + AutoRoute( + path: "home/genres", + page: GenreRoute.page, + ), + AutoRoute( + path: "home/genre/:categoryId", + page: GenrePlaylistsRoute.page, + ), + AutoRoute( + path: "home/feeds/:feedId", + page: HomeFeedSectionRoute.page, + ), + AutoRoute( + path: "search", + page: SearchRoute.page, + ), + AutoRoute( + path: "library", + page: LibraryRoute.page, + children: [ + AutoRoute( + path: "playlists", + page: UserPlaylistsRoute.page, + ), + AutoRoute( + path: "artists", + page: UserArtistsRoute.page, + ), + AutoRoute( + path: "album", + page: UserAlbumsRoute.page, + ), + AutoRoute( + path: "local", + page: UserLocalLibraryRoute.page, + ), + AutoRoute( + path: "local/folder", + page: LocalLibraryRoute.page, + // parentNavigatorKey: shellRouteNavigatorKey, + ), + AutoRoute( + path: "downloads", + page: UserDownloadsRoute.page, + ), + ], + ), + AutoRoute( + path: "library/generate", + page: PlaylistGeneratorRoute.page, + ), + AutoRoute( + path: "library/generate/result", + page: PlaylistGenerateResultRoute.page, + ), + AutoRoute( + path: "lyrics", + page: LyricsRoute.page, + ), + AutoRoute( + path: "settings", + page: SettingsRoute.page, + ), + AutoRoute( + path: "settings/blacklist", + page: BlackListRoute.page, + ), + if (!kIsWeb) + AutoRoute( + path: "settings/logs", + page: LogsRoute.page, + ), + AutoRoute( + path: "settings/about", + page: AboutSpotubeRoute.page, + ), + AutoRoute( + path: "album/:id", + page: AlbumRoute.page, + ), + AutoRoute( + path: "artist/:id", + page: ArtistRoute.page, + ), + AutoRoute( + path: "liked-tracks", + page: LikedPlaylistRoute.page, + ), + AutoRoute( + path: "playlist/:id", + page: PlaylistRoute.page, + guards: [ + AutoRouteGuard.redirect( + (resolver) { + final PlaylistRouteArgs(:id, :playlist) = + resolver.route.args as PlaylistRouteArgs; + if (id == "user-liked-tracks") { + return LikedPlaylistRoute(playlist: playlist); + } + + return null; + }, + ), + ], + ), + AutoRoute( + path: "track/:id", + page: TrackRoute.page, + ), + AutoRoute( + path: "connect", + page: ConnectRoute.page, + ), + AutoRoute( + path: "connect/control", + page: ConnectControlRoute.page, + ), + AutoRoute( + path: "profile", + page: ProfileRoute.page, + ), + AutoRoute( + path: "stats", + page: StatsRoute.page, + ), + AutoRoute( + path: "stats/minutes", + page: StatsMinutesRoute.page, + ), + AutoRoute( + path: "stats/streams", + page: StatsStreamsRoute.page, + ), + AutoRoute( + path: "stats/fees", + page: StatsStreamFeesRoute.page, + ), + AutoRoute( + path: "stats/artists", + page: StatsArtistsRoute.page, + ), + AutoRoute( + path: "stats/albums", + page: StatsAlbumsRoute.page, + ), + AutoRoute( + path: "stats/playlists", + page: StatsPlaylistsRoute.page, + ), + ], ), - ), - GoRoute( - path: "/login", - name: WebViewLogin.name, - parentNavigatorKey: rootNavigatorKey, - pageBuilder: (context, state) => const SpotubePage( - child: WebViewLogin(), + AutoRoute( + path: "/mini-player", + page: MiniLyricsRoute.page, + // parentNavigatorKey: rootNavigatorKey, ), - ), - GoRoute( - path: "/lastfm-login", - name: LastFMLoginPage.name, - parentNavigatorKey: rootNavigatorKey, - pageBuilder: (context, state) => - const SpotubePage(child: LastFMLoginPage()), - ), - ], - ); -}); + AutoRoute( + path: "/getting-started", + page: GettingStartedRoute.page, + // parentNavigatorKey: rootNavigatorKey, + ), + AutoRoute( + path: "/login", + page: WebViewLoginRoute.page, + // parentNavigatorKey: rootNavigatorKey, + ), + AutoRoute( + path: "/lastfm-login", + page: LastFMLoginRoute.page, + // parentNavigatorKey: rootNavigatorKey, + ), + ]; +} diff --git a/lib/collections/routes.gr.dart b/lib/collections/routes.gr.dart new file mode 100644 index 00000000..4572a23d --- /dev/null +++ b/lib/collections/routes.gr.dart @@ -0,0 +1,1143 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +// ************************************************************************** +// AutoRouterGenerator +// ************************************************************************** + +// ignore_for_file: type=lint +// coverage:ignore-file + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'package:auto_route/auto_route.dart' as _i40; +import 'package:flutter/material.dart' as _i43; +import 'package:flutter/widgets.dart' as _i44; +import 'package:shadcn_flutter/shadcn_flutter.dart' as _i41; +import 'package:spotify/spotify.dart' as _i42; +import 'package:spotube/models/spotify/recommendation_seeds.dart' as _i45; +import 'package:spotube/pages/album/album.dart' as _i2; +import 'package:spotube/pages/artist/artist.dart' as _i3; +import 'package:spotube/pages/connect/connect.dart' as _i6; +import 'package:spotube/pages/connect/control/control.dart' as _i5; +import 'package:spotube/pages/getting_started/getting_started.dart' as _i9; +import 'package:spotube/pages/home/feed/feed_section.dart' as _i10; +import 'package:spotube/pages/home/genres/genre_playlists.dart' as _i8; +import 'package:spotube/pages/home/genres/genres.dart' as _i7; +import 'package:spotube/pages/home/home.dart' as _i11; +import 'package:spotube/pages/lastfm_login/lastfm_login.dart' as _i12; +import 'package:spotube/pages/library/library.dart' as _i13; +import 'package:spotube/pages/library/playlist_generate/playlist_generate.dart' + as _i20; +import 'package:spotube/pages/library/playlist_generate/playlist_generate_result.dart' + as _i19; +import 'package:spotube/pages/library/user_albums.dart' as _i34; +import 'package:spotube/pages/library/user_artists.dart' as _i35; +import 'package:spotube/pages/library/user_downloads.dart' as _i36; +import 'package:spotube/pages/library/user_local_tracks/local_folder.dart' + as _i15; +import 'package:spotube/pages/library/user_local_tracks/user_local_tracks.dart' + as _i37; +import 'package:spotube/pages/library/user_playlists.dart' as _i38; +import 'package:spotube/pages/lyrics/lyrics.dart' as _i17; +import 'package:spotube/pages/lyrics/mini_lyrics.dart' as _i18; +import 'package:spotube/pages/mobile_login/mobile_login.dart' as _i39; +import 'package:spotube/pages/playlist/liked_playlist.dart' as _i14; +import 'package:spotube/pages/playlist/playlist.dart' as _i21; +import 'package:spotube/pages/profile/profile.dart' as _i22; +import 'package:spotube/pages/root/root_app.dart' as _i23; +import 'package:spotube/pages/search/search.dart' as _i24; +import 'package:spotube/pages/settings/about.dart' as _i1; +import 'package:spotube/pages/settings/blacklist.dart' as _i4; +import 'package:spotube/pages/settings/logs.dart' as _i16; +import 'package:spotube/pages/settings/settings.dart' as _i25; +import 'package:spotube/pages/stats/albums/albums.dart' as _i26; +import 'package:spotube/pages/stats/artists/artists.dart' as _i27; +import 'package:spotube/pages/stats/fees/fees.dart' as _i31; +import 'package:spotube/pages/stats/minutes/minutes.dart' as _i28; +import 'package:spotube/pages/stats/playlists/playlists.dart' as _i30; +import 'package:spotube/pages/stats/stats.dart' as _i29; +import 'package:spotube/pages/stats/streams/streams.dart' as _i32; +import 'package:spotube/pages/track/track.dart' as _i33; + +/// generated route for +/// [_i1.AboutSpotubePage] +class AboutSpotubeRoute extends _i40.PageRouteInfo { + const AboutSpotubeRoute({List<_i40.PageRouteInfo>? children}) + : super( + AboutSpotubeRoute.name, + initialChildren: children, + ); + + static const String name = 'AboutSpotubeRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i1.AboutSpotubePage(); + }, + ); +} + +/// generated route for +/// [_i2.AlbumPage] +class AlbumRoute extends _i40.PageRouteInfo { + AlbumRoute({ + _i41.Key? key, + required String id, + required _i42.AlbumSimple album, + List<_i40.PageRouteInfo>? children, + }) : super( + AlbumRoute.name, + args: AlbumRouteArgs( + key: key, + id: id, + album: album, + ), + rawPathParams: {'id': id}, + initialChildren: children, + ); + + static const String name = 'AlbumRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + final args = data.argsAs(); + return _i2.AlbumPage( + key: args.key, + id: args.id, + album: args.album, + ); + }, + ); +} + +class AlbumRouteArgs { + const AlbumRouteArgs({ + this.key, + required this.id, + required this.album, + }); + + final _i41.Key? key; + + final String id; + + final _i42.AlbumSimple album; + + @override + String toString() { + return 'AlbumRouteArgs{key: $key, id: $id, album: $album}'; + } +} + +/// generated route for +/// [_i3.ArtistPage] +class ArtistRoute extends _i40.PageRouteInfo { + ArtistRoute({ + required String artistId, + _i41.Key? key, + List<_i40.PageRouteInfo>? children, + }) : super( + ArtistRoute.name, + args: ArtistRouteArgs( + artistId: artistId, + key: key, + ), + rawPathParams: {'id': artistId}, + initialChildren: children, + ); + + static const String name = 'ArtistRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + final pathParams = data.inheritedPathParams; + final args = data.argsAs( + orElse: () => ArtistRouteArgs(artistId: pathParams.getString('id'))); + return _i3.ArtistPage( + args.artistId, + key: args.key, + ); + }, + ); +} + +class ArtistRouteArgs { + const ArtistRouteArgs({ + required this.artistId, + this.key, + }); + + final String artistId; + + final _i41.Key? key; + + @override + String toString() { + return 'ArtistRouteArgs{artistId: $artistId, key: $key}'; + } +} + +/// generated route for +/// [_i4.BlackListPage] +class BlackListRoute extends _i40.PageRouteInfo { + const BlackListRoute({List<_i40.PageRouteInfo>? children}) + : super( + BlackListRoute.name, + initialChildren: children, + ); + + static const String name = 'BlackListRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i4.BlackListPage(); + }, + ); +} + +/// generated route for +/// [_i5.ConnectControlPage] +class ConnectControlRoute extends _i40.PageRouteInfo { + const ConnectControlRoute({List<_i40.PageRouteInfo>? children}) + : super( + ConnectControlRoute.name, + initialChildren: children, + ); + + static const String name = 'ConnectControlRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i5.ConnectControlPage(); + }, + ); +} + +/// generated route for +/// [_i6.ConnectPage] +class ConnectRoute extends _i40.PageRouteInfo { + const ConnectRoute({List<_i40.PageRouteInfo>? children}) + : super( + ConnectRoute.name, + initialChildren: children, + ); + + static const String name = 'ConnectRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i6.ConnectPage(); + }, + ); +} + +/// generated route for +/// [_i7.GenrePage] +class GenreRoute extends _i40.PageRouteInfo { + const GenreRoute({List<_i40.PageRouteInfo>? children}) + : super( + GenreRoute.name, + initialChildren: children, + ); + + static const String name = 'GenreRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i7.GenrePage(); + }, + ); +} + +/// generated route for +/// [_i8.GenrePlaylistsPage] +class GenrePlaylistsRoute extends _i40.PageRouteInfo { + GenrePlaylistsRoute({ + _i43.Key? key, + required String id, + required _i42.Category category, + List<_i40.PageRouteInfo>? children, + }) : super( + GenrePlaylistsRoute.name, + args: GenrePlaylistsRouteArgs( + key: key, + id: id, + category: category, + ), + rawPathParams: {'categoryId': id}, + initialChildren: children, + ); + + static const String name = 'GenrePlaylistsRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + final args = data.argsAs(); + return _i8.GenrePlaylistsPage( + key: args.key, + id: args.id, + category: args.category, + ); + }, + ); +} + +class GenrePlaylistsRouteArgs { + const GenrePlaylistsRouteArgs({ + this.key, + required this.id, + required this.category, + }); + + final _i43.Key? key; + + final String id; + + final _i42.Category category; + + @override + String toString() { + return 'GenrePlaylistsRouteArgs{key: $key, id: $id, category: $category}'; + } +} + +/// generated route for +/// [_i9.GettingStartedPage] +class GettingStartedRoute extends _i40.PageRouteInfo { + const GettingStartedRoute({List<_i40.PageRouteInfo>? children}) + : super( + GettingStartedRoute.name, + initialChildren: children, + ); + + static const String name = 'GettingStartedRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i9.GettingStartedPage(); + }, + ); +} + +/// generated route for +/// [_i10.HomeFeedSectionPage] +class HomeFeedSectionRoute + extends _i40.PageRouteInfo { + HomeFeedSectionRoute({ + _i41.Key? key, + required String sectionUri, + List<_i40.PageRouteInfo>? children, + }) : super( + HomeFeedSectionRoute.name, + args: HomeFeedSectionRouteArgs( + key: key, + sectionUri: sectionUri, + ), + rawPathParams: {'feedId': sectionUri}, + initialChildren: children, + ); + + static const String name = 'HomeFeedSectionRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + final pathParams = data.inheritedPathParams; + final args = data.argsAs( + orElse: () => HomeFeedSectionRouteArgs( + sectionUri: pathParams.getString('feedId'))); + return _i10.HomeFeedSectionPage( + key: args.key, + sectionUri: args.sectionUri, + ); + }, + ); +} + +class HomeFeedSectionRouteArgs { + const HomeFeedSectionRouteArgs({ + this.key, + required this.sectionUri, + }); + + final _i41.Key? key; + + final String sectionUri; + + @override + String toString() { + return 'HomeFeedSectionRouteArgs{key: $key, sectionUri: $sectionUri}'; + } +} + +/// generated route for +/// [_i11.HomePage] +class HomeRoute extends _i40.PageRouteInfo { + const HomeRoute({List<_i40.PageRouteInfo>? children}) + : super( + HomeRoute.name, + initialChildren: children, + ); + + static const String name = 'HomeRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i11.HomePage(); + }, + ); +} + +/// generated route for +/// [_i12.LastFMLoginPage] +class LastFMLoginRoute extends _i40.PageRouteInfo { + const LastFMLoginRoute({List<_i40.PageRouteInfo>? children}) + : super( + LastFMLoginRoute.name, + initialChildren: children, + ); + + static const String name = 'LastFMLoginRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i12.LastFMLoginPage(); + }, + ); +} + +/// generated route for +/// [_i13.LibraryPage] +class LibraryRoute extends _i40.PageRouteInfo { + const LibraryRoute({List<_i40.PageRouteInfo>? children}) + : super( + LibraryRoute.name, + initialChildren: children, + ); + + static const String name = 'LibraryRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i13.LibraryPage(); + }, + ); +} + +/// generated route for +/// [_i14.LikedPlaylistPage] +class LikedPlaylistRoute extends _i40.PageRouteInfo { + LikedPlaylistRoute({ + _i44.Key? key, + required _i42.PlaylistSimple playlist, + List<_i40.PageRouteInfo>? children, + }) : super( + LikedPlaylistRoute.name, + args: LikedPlaylistRouteArgs( + key: key, + playlist: playlist, + ), + initialChildren: children, + ); + + static const String name = 'LikedPlaylistRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + final args = data.argsAs(); + return _i14.LikedPlaylistPage( + key: args.key, + playlist: args.playlist, + ); + }, + ); +} + +class LikedPlaylistRouteArgs { + const LikedPlaylistRouteArgs({ + this.key, + required this.playlist, + }); + + final _i44.Key? key; + + final _i42.PlaylistSimple playlist; + + @override + String toString() { + return 'LikedPlaylistRouteArgs{key: $key, playlist: $playlist}'; + } +} + +/// generated route for +/// [_i15.LocalLibraryPage] +class LocalLibraryRoute extends _i40.PageRouteInfo { + LocalLibraryRoute({ + required String location, + _i41.Key? key, + bool isDownloads = false, + bool isCache = false, + List<_i40.PageRouteInfo>? children, + }) : super( + LocalLibraryRoute.name, + args: LocalLibraryRouteArgs( + location: location, + key: key, + isDownloads: isDownloads, + isCache: isCache, + ), + initialChildren: children, + ); + + static const String name = 'LocalLibraryRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + final args = data.argsAs(); + return _i15.LocalLibraryPage( + args.location, + key: args.key, + isDownloads: args.isDownloads, + isCache: args.isCache, + ); + }, + ); +} + +class LocalLibraryRouteArgs { + const LocalLibraryRouteArgs({ + required this.location, + this.key, + this.isDownloads = false, + this.isCache = false, + }); + + final String location; + + final _i41.Key? key; + + final bool isDownloads; + + final bool isCache; + + @override + String toString() { + return 'LocalLibraryRouteArgs{location: $location, key: $key, isDownloads: $isDownloads, isCache: $isCache}'; + } +} + +/// generated route for +/// [_i16.LogsPage] +class LogsRoute extends _i40.PageRouteInfo { + const LogsRoute({List<_i40.PageRouteInfo>? children}) + : super( + LogsRoute.name, + initialChildren: children, + ); + + static const String name = 'LogsRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i16.LogsPage(); + }, + ); +} + +/// generated route for +/// [_i17.LyricsPage] +class LyricsRoute extends _i40.PageRouteInfo { + LyricsRoute({ + _i41.Key? key, + bool isModal = false, + List<_i40.PageRouteInfo>? children, + }) : super( + LyricsRoute.name, + args: LyricsRouteArgs( + key: key, + isModal: isModal, + ), + initialChildren: children, + ); + + static const String name = 'LyricsRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + final args = + data.argsAs(orElse: () => const LyricsRouteArgs()); + return _i17.LyricsPage( + key: args.key, + isModal: args.isModal, + ); + }, + ); +} + +class LyricsRouteArgs { + const LyricsRouteArgs({ + this.key, + this.isModal = false, + }); + + final _i41.Key? key; + + final bool isModal; + + @override + String toString() { + return 'LyricsRouteArgs{key: $key, isModal: $isModal}'; + } +} + +/// generated route for +/// [_i18.MiniLyricsPage] +class MiniLyricsRoute extends _i40.PageRouteInfo { + MiniLyricsRoute({ + _i41.Key? key, + required _i41.Size prevSize, + List<_i40.PageRouteInfo>? children, + }) : super( + MiniLyricsRoute.name, + args: MiniLyricsRouteArgs( + key: key, + prevSize: prevSize, + ), + initialChildren: children, + ); + + static const String name = 'MiniLyricsRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + final args = data.argsAs(); + return _i18.MiniLyricsPage( + key: args.key, + prevSize: args.prevSize, + ); + }, + ); +} + +class MiniLyricsRouteArgs { + const MiniLyricsRouteArgs({ + this.key, + required this.prevSize, + }); + + final _i41.Key? key; + + final _i41.Size prevSize; + + @override + String toString() { + return 'MiniLyricsRouteArgs{key: $key, prevSize: $prevSize}'; + } +} + +/// generated route for +/// [_i19.PlaylistGenerateResultPage] +class PlaylistGenerateResultRoute + extends _i40.PageRouteInfo { + PlaylistGenerateResultRoute({ + _i41.Key? key, + required _i45.GeneratePlaylistProviderInput state, + List<_i40.PageRouteInfo>? children, + }) : super( + PlaylistGenerateResultRoute.name, + args: PlaylistGenerateResultRouteArgs( + key: key, + state: state, + ), + initialChildren: children, + ); + + static const String name = 'PlaylistGenerateResultRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + final args = data.argsAs(); + return _i19.PlaylistGenerateResultPage( + key: args.key, + state: args.state, + ); + }, + ); +} + +class PlaylistGenerateResultRouteArgs { + const PlaylistGenerateResultRouteArgs({ + this.key, + required this.state, + }); + + final _i41.Key? key; + + final _i45.GeneratePlaylistProviderInput state; + + @override + String toString() { + return 'PlaylistGenerateResultRouteArgs{key: $key, state: $state}'; + } +} + +/// generated route for +/// [_i20.PlaylistGeneratorPage] +class PlaylistGeneratorRoute extends _i40.PageRouteInfo { + const PlaylistGeneratorRoute({List<_i40.PageRouteInfo>? children}) + : super( + PlaylistGeneratorRoute.name, + initialChildren: children, + ); + + static const String name = 'PlaylistGeneratorRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i20.PlaylistGeneratorPage(); + }, + ); +} + +/// generated route for +/// [_i21.PlaylistPage] +class PlaylistRoute extends _i40.PageRouteInfo { + PlaylistRoute({ + _i43.Key? key, + required String id, + required _i42.PlaylistSimple playlist, + List<_i40.PageRouteInfo>? children, + }) : super( + PlaylistRoute.name, + args: PlaylistRouteArgs( + key: key, + id: id, + playlist: playlist, + ), + rawPathParams: {'id': id}, + initialChildren: children, + ); + + static const String name = 'PlaylistRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + final args = data.argsAs(); + return _i21.PlaylistPage( + key: args.key, + id: args.id, + playlist: args.playlist, + ); + }, + ); +} + +class PlaylistRouteArgs { + const PlaylistRouteArgs({ + this.key, + required this.id, + required this.playlist, + }); + + final _i43.Key? key; + + final String id; + + final _i42.PlaylistSimple playlist; + + @override + String toString() { + return 'PlaylistRouteArgs{key: $key, id: $id, playlist: $playlist}'; + } +} + +/// generated route for +/// [_i22.ProfilePage] +class ProfileRoute extends _i40.PageRouteInfo { + const ProfileRoute({List<_i40.PageRouteInfo>? children}) + : super( + ProfileRoute.name, + initialChildren: children, + ); + + static const String name = 'ProfileRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i22.ProfilePage(); + }, + ); +} + +/// generated route for +/// [_i23.RootAppPage] +class RootAppRoute extends _i40.PageRouteInfo { + const RootAppRoute({List<_i40.PageRouteInfo>? children}) + : super( + RootAppRoute.name, + initialChildren: children, + ); + + static const String name = 'RootAppRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i23.RootAppPage(); + }, + ); +} + +/// generated route for +/// [_i24.SearchPage] +class SearchRoute extends _i40.PageRouteInfo { + const SearchRoute({List<_i40.PageRouteInfo>? children}) + : super( + SearchRoute.name, + initialChildren: children, + ); + + static const String name = 'SearchRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i24.SearchPage(); + }, + ); +} + +/// generated route for +/// [_i25.SettingsPage] +class SettingsRoute extends _i40.PageRouteInfo { + const SettingsRoute({List<_i40.PageRouteInfo>? children}) + : super( + SettingsRoute.name, + initialChildren: children, + ); + + static const String name = 'SettingsRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i25.SettingsPage(); + }, + ); +} + +/// generated route for +/// [_i26.StatsAlbumsPage] +class StatsAlbumsRoute extends _i40.PageRouteInfo { + const StatsAlbumsRoute({List<_i40.PageRouteInfo>? children}) + : super( + StatsAlbumsRoute.name, + initialChildren: children, + ); + + static const String name = 'StatsAlbumsRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i26.StatsAlbumsPage(); + }, + ); +} + +/// generated route for +/// [_i27.StatsArtistsPage] +class StatsArtistsRoute extends _i40.PageRouteInfo { + const StatsArtistsRoute({List<_i40.PageRouteInfo>? children}) + : super( + StatsArtistsRoute.name, + initialChildren: children, + ); + + static const String name = 'StatsArtistsRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i27.StatsArtistsPage(); + }, + ); +} + +/// generated route for +/// [_i28.StatsMinutesPage] +class StatsMinutesRoute extends _i40.PageRouteInfo { + const StatsMinutesRoute({List<_i40.PageRouteInfo>? children}) + : super( + StatsMinutesRoute.name, + initialChildren: children, + ); + + static const String name = 'StatsMinutesRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i28.StatsMinutesPage(); + }, + ); +} + +/// generated route for +/// [_i29.StatsPage] +class StatsRoute extends _i40.PageRouteInfo { + const StatsRoute({List<_i40.PageRouteInfo>? children}) + : super( + StatsRoute.name, + initialChildren: children, + ); + + static const String name = 'StatsRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i29.StatsPage(); + }, + ); +} + +/// generated route for +/// [_i30.StatsPlaylistsPage] +class StatsPlaylistsRoute extends _i40.PageRouteInfo { + const StatsPlaylistsRoute({List<_i40.PageRouteInfo>? children}) + : super( + StatsPlaylistsRoute.name, + initialChildren: children, + ); + + static const String name = 'StatsPlaylistsRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i30.StatsPlaylistsPage(); + }, + ); +} + +/// generated route for +/// [_i31.StatsStreamFeesPage] +class StatsStreamFeesRoute extends _i40.PageRouteInfo { + const StatsStreamFeesRoute({List<_i40.PageRouteInfo>? children}) + : super( + StatsStreamFeesRoute.name, + initialChildren: children, + ); + + static const String name = 'StatsStreamFeesRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i31.StatsStreamFeesPage(); + }, + ); +} + +/// generated route for +/// [_i32.StatsStreamsPage] +class StatsStreamsRoute extends _i40.PageRouteInfo { + const StatsStreamsRoute({List<_i40.PageRouteInfo>? children}) + : super( + StatsStreamsRoute.name, + initialChildren: children, + ); + + static const String name = 'StatsStreamsRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i32.StatsStreamsPage(); + }, + ); +} + +/// generated route for +/// [_i33.TrackPage] +class TrackRoute extends _i40.PageRouteInfo { + TrackRoute({ + _i41.Key? key, + required String trackId, + List<_i40.PageRouteInfo>? children, + }) : super( + TrackRoute.name, + args: TrackRouteArgs( + key: key, + trackId: trackId, + ), + rawPathParams: {'id': trackId}, + initialChildren: children, + ); + + static const String name = 'TrackRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + final pathParams = data.inheritedPathParams; + final args = data.argsAs( + orElse: () => TrackRouteArgs(trackId: pathParams.getString('id'))); + return _i33.TrackPage( + key: args.key, + trackId: args.trackId, + ); + }, + ); +} + +class TrackRouteArgs { + const TrackRouteArgs({ + this.key, + required this.trackId, + }); + + final _i41.Key? key; + + final String trackId; + + @override + String toString() { + return 'TrackRouteArgs{key: $key, trackId: $trackId}'; + } +} + +/// generated route for +/// [_i34.UserAlbumsPage] +class UserAlbumsRoute extends _i40.PageRouteInfo { + const UserAlbumsRoute({List<_i40.PageRouteInfo>? children}) + : super( + UserAlbumsRoute.name, + initialChildren: children, + ); + + static const String name = 'UserAlbumsRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i34.UserAlbumsPage(); + }, + ); +} + +/// generated route for +/// [_i35.UserArtistsPage] +class UserArtistsRoute extends _i40.PageRouteInfo { + const UserArtistsRoute({List<_i40.PageRouteInfo>? children}) + : super( + UserArtistsRoute.name, + initialChildren: children, + ); + + static const String name = 'UserArtistsRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i35.UserArtistsPage(); + }, + ); +} + +/// generated route for +/// [_i36.UserDownloadsPage] +class UserDownloadsRoute extends _i40.PageRouteInfo { + const UserDownloadsRoute({List<_i40.PageRouteInfo>? children}) + : super( + UserDownloadsRoute.name, + initialChildren: children, + ); + + static const String name = 'UserDownloadsRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i36.UserDownloadsPage(); + }, + ); +} + +/// generated route for +/// [_i37.UserLocalLibraryPage] +class UserLocalLibraryRoute extends _i40.PageRouteInfo { + const UserLocalLibraryRoute({List<_i40.PageRouteInfo>? children}) + : super( + UserLocalLibraryRoute.name, + initialChildren: children, + ); + + static const String name = 'UserLocalLibraryRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i37.UserLocalLibraryPage(); + }, + ); +} + +/// generated route for +/// [_i38.UserPlaylistsPage] +class UserPlaylistsRoute extends _i40.PageRouteInfo { + const UserPlaylistsRoute({List<_i40.PageRouteInfo>? children}) + : super( + UserPlaylistsRoute.name, + initialChildren: children, + ); + + static const String name = 'UserPlaylistsRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i38.UserPlaylistsPage(); + }, + ); +} + +/// generated route for +/// [_i39.WebViewLoginPage] +class WebViewLoginRoute extends _i40.PageRouteInfo { + const WebViewLoginRoute({List<_i40.PageRouteInfo>? children}) + : super( + WebViewLoginRoute.name, + initialChildren: children, + ); + + static const String name = 'WebViewLoginRoute'; + + static _i40.PageInfo page = _i40.PageInfo( + name, + builder: (data) { + return const _i39.WebViewLoginPage(); + }, + ); +} diff --git a/lib/collections/side_bar_tiles.dart b/lib/collections/side_bar_tiles.dart index f12517bb..c74d18c7 100644 --- a/lib/collections/side_bar_tiles.dart +++ b/lib/collections/side_bar_tiles.dart @@ -1,51 +1,45 @@ +import 'package:auto_route/auto_route.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -import 'package:spotube/pages/home/home.dart'; -import 'package:spotube/pages/library/user_albums.dart'; -import 'package:spotube/pages/library/user_artists.dart'; -import 'package:spotube/pages/library/user_local_tracks/user_local_tracks.dart'; -import 'package:spotube/pages/library/user_playlists.dart'; -import 'package:spotube/pages/lyrics/lyrics.dart'; -import 'package:spotube/pages/search/search.dart'; -import 'package:spotube/pages/stats/stats.dart'; class SideBarTiles { final IconData icon; final String title; final String id; - final String name; + final PageRouteInfo route; SideBarTiles({ required this.icon, required this.title, required this.id, - required this.name, + required this.route, }); } List getSidebarTileList(AppLocalizations l10n) => [ SideBarTiles( id: "browse", - name: HomePage.name, + route: const HomeRoute(), icon: SpotubeIcons.home, title: l10n.browse, ), SideBarTiles( id: "search", - name: SearchPage.name, + route: const SearchRoute(), icon: SpotubeIcons.search, title: l10n.search, ), SideBarTiles( id: "lyrics", - name: LyricsPage.name, + route: LyricsRoute(), icon: SpotubeIcons.music, title: l10n.lyrics, ), SideBarTiles( id: "stats", - name: StatsPage.name, + route: const StatsRoute(), icon: SpotubeIcons.chart, title: l10n.stats, ), @@ -55,25 +49,25 @@ List getSidebarLibraryTileList(AppLocalizations l10n) => [ SideBarTiles( id: "playlists", title: l10n.playlists, - name: UserPlaylistsPage.name, + route: const UserPlaylistsRoute(), icon: SpotubeIcons.playlist, ), SideBarTiles( id: "artists", title: l10n.artists, - name: UserArtistsPage.name, + route: const UserArtistsRoute(), icon: SpotubeIcons.artist, ), SideBarTiles( id: "albums", title: l10n.albums, - name: UserAlbumsPage.name, + route: const UserAlbumsRoute(), icon: SpotubeIcons.album, ), SideBarTiles( id: "local_library", title: l10n.local_library, - name: UserLocalLibraryPage.name, + route: const UserLocalLibraryRoute(), icon: SpotubeIcons.device, ), ]; @@ -81,25 +75,25 @@ List getSidebarLibraryTileList(AppLocalizations l10n) => [ List getNavbarTileList(AppLocalizations l10n) => [ SideBarTiles( id: "browse", - name: HomePage.name, + route: const HomeRoute(), icon: SpotubeIcons.home, title: l10n.browse, ), SideBarTiles( id: "search", - name: SearchPage.name, + route: const SearchRoute(), icon: SpotubeIcons.search, title: l10n.search, ), SideBarTiles( id: "library", - name: UserPlaylistsPage.name, + route: const UserPlaylistsRoute(), icon: SpotubeIcons.library, title: l10n.library, ), SideBarTiles( id: "stats", - name: StatsPage.name, + route: const StatsRoute(), icon: SpotubeIcons.chart, title: l10n.stats, ), diff --git a/lib/components/dialogs/track_details_dialog.dart b/lib/components/dialogs/track_details_dialog.dart index 1296ae0e..bfb4a318 100644 --- a/lib/components/dialogs/track_details_dialog.dart +++ b/lib/components/dialogs/track_details_dialog.dart @@ -1,6 +1,7 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/links/artist_link.dart'; import 'package:spotube/components/links/hyper_link.dart'; @@ -32,8 +33,7 @@ class TrackDetailsDialog extends HookWidget { ), context.l10n.album: LinkText( track.album!.name!, - "/album/${track.album?.id}", - extra: track.album, + AlbumRoute(album: track.album!, id: track.album!.id!), overflow: TextOverflow.ellipsis, style: const TextStyle(color: Colors.blue), ), diff --git a/lib/components/fallbacks/anonymous_fallback.dart b/lib/components/fallbacks/anonymous_fallback.dart index 373e0454..714a0df5 100644 --- a/lib/components/fallbacks/anonymous_fallback.dart +++ b/lib/components/fallbacks/anonymous_fallback.dart @@ -1,13 +1,13 @@ +import 'package:auto_route/auto_route.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_undraw/flutter_undraw.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/pages/settings/settings.dart'; import 'package:spotube/provider/authentication/authentication.dart'; import 'package:spotube/utils/platform.dart'; -import 'package:spotube/utils/service_utils.dart'; class AnonymousFallback extends ConsumerWidget { final Widget? child; @@ -40,7 +40,7 @@ class AnonymousFallback extends ConsumerWidget { Text(context.l10n.not_logged_in), Button.primary( child: Text(context.l10n.login_with_spotify), - onPressed: () => ServiceUtils.pushNamed(context, SettingsPage.name), + onPressed: () => context.pushRoute(const SettingsRoute()), ) ], ), diff --git a/lib/components/links/artist_link.dart b/lib/components/links/artist_link.dart index c6ea5c14..cdd7f659 100644 --- a/lib/components/links/artist_link.dart +++ b/lib/components/links/artist_link.dart @@ -1,9 +1,9 @@ +import 'package:auto_route/auto_route.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/components/links/anchor_button.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/pages/artist/artist.dart'; -import 'package:spotube/utils/service_utils.dart'; class ArtistLink extends StatelessWidget { final List artists; @@ -49,13 +49,8 @@ class ArtistLink extends StatelessWidget { if (onRouteChange != null) { onRouteChange?.call("/artist/${artist.value.id}"); } else { - ServiceUtils.pushNamed( - context, - ArtistPage.name, - pathParameters: { - "id": artist.value.id!, - }, - ); + context + .pushRoute(ArtistRoute(artistId: artist.value.id!)); } }, overflow: TextOverflow.ellipsis, diff --git a/lib/components/links/link_text.dart b/lib/components/links/link_text.dart index a54c8b9f..f21aa032 100644 --- a/lib/components/links/link_text.dart +++ b/lib/components/links/link_text.dart @@ -1,15 +1,14 @@ +import 'package:auto_route/auto_route.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/components/links/anchor_button.dart'; -import 'package:spotube/utils/service_utils.dart'; class LinkText extends StatelessWidget { final String text; final TextStyle style; final TextAlign? textAlign; final TextOverflow? overflow; - final String route; + final PageRouteInfo route; final int? maxLines; - final T? extra; final bool push; const LinkText( @@ -17,7 +16,6 @@ class LinkText extends StatelessWidget { this.route, { super.key, this.textAlign, - this.extra, this.overflow, this.style = const TextStyle(), this.maxLines, @@ -30,9 +28,9 @@ class LinkText extends StatelessWidget { text, onTap: () { if (push) { - ServiceUtils.push(context, route, extra: extra); + context.pushRoute(route); } else { - ServiceUtils.navigate(context, route, extra: extra); + context.navigateTo(route); } }, key: key, diff --git a/lib/components/spotube_page_route.dart b/lib/components/spotube_page_route.dart index 6d152dd5..cff32975 100644 --- a/lib/components/spotube_page_route.dart +++ b/lib/components/spotube_page_route.dart @@ -1,25 +1,24 @@ import 'package:shadcn_flutter/shadcn_flutter.dart'; -import 'package:go_router/go_router.dart'; class SpotubePage extends MaterialPage { const SpotubePage({required super.child}); } -class SpotubeSlidePage extends CustomTransitionPage { - SpotubeSlidePage({ - required super.child, - super.key, - }) : super( - reverseTransitionDuration: const Duration(milliseconds: 150), - transitionDuration: const Duration(milliseconds: 150), - transitionsBuilder: (context, animation, secondaryAnimation, child) { - return SlideTransition( - position: Tween( - begin: const Offset(1, 0), - end: Offset.zero, - ).animate(animation), - child: child, - ); - }, - ); -} +// class SpotubeSlidePage extends CustomTransitionPage { +// SpotubeSlidePage({ +// required super.child, +// super.key, +// }) : super( +// reverseTransitionDuration: const Duration(milliseconds: 150), +// transitionDuration: const Duration(milliseconds: 150), +// transitionsBuilder: (context, animation, secondaryAnimation, child) { +// return SlideTransition( +// position: Tween( +// begin: const Offset(1, 0), +// end: Offset.zero, +// ).animate(animation), +// child: child, +// ); +// }, +// ); +// } diff --git a/lib/components/track_tile/track_options.dart b/lib/components/track_tile/track_options.dart index 14514cde..66cee95f 100644 --- a/lib/components/track_tile/track_options.dart +++ b/lib/components/track_tile/track_options.dart @@ -1,14 +1,16 @@ import 'dart:io'; +import 'package:auto_route/auto_route.dart'; import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; + import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotify/spotify.dart' hide Offset; import 'package:spotube/collections/assets.gen.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/adaptive/adaptive_pop_sheet_list.dart'; import 'package:spotube/components/dialogs/playlist_add_track_dialog.dart'; @@ -22,7 +24,6 @@ import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/models/database/database.dart'; import 'package:spotube/models/local_track.dart'; -import 'package:spotube/pages/track/track.dart'; import 'package:spotube/provider/authentication/authentication.dart'; import 'package:spotube/provider/blacklist_provider.dart'; import 'package:spotube/provider/download_manager_provider.dart'; @@ -30,7 +31,6 @@ import 'package:spotube/provider/local_tracks/local_tracks_provider.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:spotube/provider/spotify_provider.dart'; -import 'package:spotube/utils/service_utils.dart'; import 'package:url_launcher/url_launcher_string.dart'; @@ -166,7 +166,6 @@ class TrackOptions extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { final mediaQuery = MediaQuery.of(context); - final router = GoRouter.of(context); final ThemeData(:colorScheme) = Theme.of(context); final playlist = ref.watch(audioPlayerProvider); @@ -211,9 +210,8 @@ class TrackOptions extends HookConsumerWidget { onSelected: (value) async { switch (value) { case TrackOptionValue.album: - await router.push( - '/album/${track.album!.id}', - extra: track.album!, + await context.pushRoute( + AlbumRoute(id: track.album!.id!, album: track.album!), ); break; case TrackOptionValue.delete: @@ -347,12 +345,8 @@ class TrackOptions extends HookConsumerWidget { alignment: Alignment.centerLeft, child: ArtistLink( artists: track.artists!, - onOverflowArtistClick: () => ServiceUtils.pushNamed( - context, - TrackPage.name, - pathParameters: { - "id": track.id!, - }, + onOverflowArtistClick: () => context.pushRoute( + TrackRoute(trackId: track.id!), ), ), ), diff --git a/lib/components/track_tile/track_tile.dart b/lib/components/track_tile/track_tile.dart index 0ca14979..71aad728 100644 --- a/lib/components/track_tile/track_tile.dart +++ b/lib/components/track_tile/track_tile.dart @@ -1,13 +1,14 @@ import 'dart:async'; +import 'package:auto_route/auto_route.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/hover_builder.dart'; import 'package:spotube/components/image/universal_image.dart'; @@ -21,12 +22,10 @@ import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/duration.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/models/local_track.dart'; -import 'package:spotube/pages/track/track.dart'; import 'package:spotube/provider/audio_player/querying_track_info.dart'; import 'package:spotube/provider/audio_player/state.dart'; import 'package:spotube/provider/blacklist_provider.dart'; import 'package:spotube/utils/platform.dart'; -import 'package:spotube/utils/service_utils.dart'; class TrackTile extends HookConsumerWidget { /// [index] will not be shown if null @@ -234,12 +233,8 @@ class TrackTile extends HookConsumerWidget { padding: (context, states) => EdgeInsets.zero, ), onPressed: () { - context.pushNamed( - TrackPage.name, - pathParameters: { - "id": track.id!, - }, - ); + context + .pushRoute(TrackRoute(trackId: track.id!)); }, child: Text( track.name!, @@ -266,8 +261,8 @@ class TrackTile extends HookConsumerWidget { alignment: Alignment.centerLeft, child: LinkText( track.album!.name!, - "/album/${track.album?.id}", - extra: track.album, + AlbumRoute( + album: track.album!, id: track.album!.id!), push: true, overflow: TextOverflow.ellipsis, ), @@ -288,13 +283,11 @@ class TrackTile extends HookConsumerWidget { constraints: const BoxConstraints(maxHeight: 40), child: ArtistLink( artists: track.artists ?? [], - onOverflowArtistClick: () => ServiceUtils.pushNamed( - context, - TrackPage.name, - pathParameters: { - "id": track.id!, - }, - ), + onOverflowArtistClick: () { + context.pushRoute( + TrackRoute(trackId: track.id!), + ); + }, ), ), ), diff --git a/lib/hooks/configurators/use_deep_linking.dart b/lib/hooks/configurators/use_deep_linking.dart index ec6d8516..045fe016 100644 --- a/lib/hooks/configurators/use_deep_linking.dart +++ b/lib/hooks/configurators/use_deep_linking.dart @@ -4,6 +4,7 @@ import 'package:app_links/app_links.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotube/collections/routes.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/provider/spotify_provider.dart'; import 'package:flutter_sharing_intent/flutter_sharing_intent.dart'; import 'package:flutter_sharing_intent/model/sharing_file.dart'; @@ -13,10 +14,9 @@ import 'package:spotube/utils/platform.dart'; final appLinks = AppLinks(); final linkStream = appLinks.stringLinkStream.asBroadcastStream(); -void useDeepLinking(WidgetRef ref) { +void useDeepLinking(WidgetRef ref, AppRouter router) { // single instance no worries final spotify = ref.watch(spotifyProvider); - final router = ref.watch(routerProvider); useEffect(() { void uriListener(List files) async { @@ -27,24 +27,20 @@ void useDeepLinking(WidgetRef ref) { switch (url.pathSegments.first) { case "album": + final album = await spotify.albums.get(url.pathSegments.last); router.push( - "/album/${url.pathSegments.last}", - extra: await spotify.albums.get(url.pathSegments.last), + AlbumRoute(id: album.id!, album: album), ); break; case "artist": - router.push("/artist/${url.pathSegments.last}"); + router.push(ArtistRoute(artistId: url.pathSegments.last)); break; case "playlist": - router.push( - "/playlist/${url.pathSegments.last}", - extra: await spotify.playlists.get(url.pathSegments.last), - ); + final playlist = await spotify.playlists.get(url.pathSegments.last); + router.push(PlaylistRoute(id: playlist.id!, playlist: playlist)); break; case "track": - router.push( - "/track/${url.pathSegments.last}", - ); + router.push(TrackRoute(trackId: url.pathSegments.last)); break; default: break; @@ -68,21 +64,21 @@ void useDeepLinking(WidgetRef ref) { switch (startSegment) { case "spotify:album": + final album = await spotify.albums.get(endSegment); await router.push( - "/album/$endSegment", - extra: await spotify.albums.get(endSegment), + AlbumRoute(id: album.id!, album: album), ); break; case "spotify:artist": - await router.push("/artist/$endSegment"); + await router.push(ArtistRoute(artistId: endSegment)); break; case "spotify:track": - await router.push("/track/$endSegment"); + await router.push(TrackRoute(trackId: endSegment)); break; case "spotify:playlist": + final playlist = await spotify.playlists.get(endSegment); await router.push( - "/playlist/$endSegment", - extra: await spotify.playlists.get(endSegment), + PlaylistRoute(id: playlist.id!, playlist: playlist), ); break; default: diff --git a/lib/main.dart b/lib/main.dart index 3994fd50..016c0fea 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -17,8 +17,8 @@ import 'package:metadata_god/metadata_god.dart'; import 'package:smtc_windows/smtc_windows.dart'; import 'package:spotube/collections/env.dart'; import 'package:spotube/collections/initializers.dart'; -import 'package:spotube/collections/routes.dart'; import 'package:spotube/collections/intents.dart'; +import 'package:spotube/collections/routes.dart'; import 'package:spotube/hooks/configurators/use_close_behavior.dart'; import 'package:spotube/hooks/configurators/use_deep_linking.dart'; import 'package:spotube/hooks/configurators/use_disable_battery_optimizations.dart'; @@ -133,7 +133,7 @@ class Spotube extends HookConsumerWidget { final locale = ref.watch(userPreferencesProvider.select((s) => s.locale)); final accentMaterialColor = ref.watch(userPreferencesProvider.select((s) => s.accentColorScheme)); - final router = ref.watch(routerProvider); + final router = useMemoized(() => AppRouter(ref), []); final hasTouchSupport = useHasTouch(); ref.listen(audioPlayerStreamListenersProvider, (_, __) {}); @@ -144,7 +144,7 @@ class Spotube extends HookConsumerWidget { useFixWindowStretching(); useDisableBatteryOptimizations(); - useDeepLinking(ref); + useDeepLinking(ref, router); useCloseBehavior(ref); useGetStoragePermissions(ref); @@ -171,7 +171,7 @@ class Spotube extends HookConsumerWidget { GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ], - routerConfig: router, + routerConfig: router.config(), debugShowCheckedModeBanner: false, title: 'Spotube', builder: (context, child) { @@ -240,42 +240,42 @@ class Spotube extends HookConsumerWidget { LogicalKeyboardKey.digit1, LogicalKeyboardKey.control, LogicalKeyboardKey.shift, - ): HomeTabIntent(ref, tab: HomeTabs.browse), + ): HomeTabIntent(router, tab: HomeTabs.browse), LogicalKeySet( LogicalKeyboardKey.digit2, LogicalKeyboardKey.control, LogicalKeyboardKey.shift, - ): HomeTabIntent(ref, tab: HomeTabs.search), + ): HomeTabIntent(router, tab: HomeTabs.search), LogicalKeySet( LogicalKeyboardKey.digit3, LogicalKeyboardKey.control, LogicalKeyboardKey.shift, - ): HomeTabIntent(ref, tab: HomeTabs.lyrics), + ): HomeTabIntent(router, tab: HomeTabs.lyrics), LogicalKeySet( LogicalKeyboardKey.digit4, LogicalKeyboardKey.control, LogicalKeyboardKey.shift, - ): HomeTabIntent(ref, tab: HomeTabs.userPlaylists), + ): HomeTabIntent(router, tab: HomeTabs.userPlaylists), LogicalKeySet( LogicalKeyboardKey.digit5, LogicalKeyboardKey.control, LogicalKeyboardKey.shift, - ): HomeTabIntent(ref, tab: HomeTabs.userArtists), + ): HomeTabIntent(router, tab: HomeTabs.userArtists), LogicalKeySet( LogicalKeyboardKey.digit6, LogicalKeyboardKey.control, LogicalKeyboardKey.shift, - ): HomeTabIntent(ref, tab: HomeTabs.userAlbums), + ): HomeTabIntent(router, tab: HomeTabs.userAlbums), LogicalKeySet( LogicalKeyboardKey.digit7, LogicalKeyboardKey.control, LogicalKeyboardKey.shift, - ): HomeTabIntent(ref, tab: HomeTabs.userLocalLibrary), + ): HomeTabIntent(router, tab: HomeTabs.userLocalLibrary), LogicalKeySet( LogicalKeyboardKey.digit8, LogicalKeyboardKey.control, LogicalKeyboardKey.shift, - ): HomeTabIntent(ref, tab: HomeTabs.userDownloads), + ): HomeTabIntent(router, tab: HomeTabs.userDownloads), LogicalKeySet( LogicalKeyboardKey.keyW, LogicalKeyboardKey.control, diff --git a/lib/modules/album/album_card.dart b/lib/modules/album/album_card.dart index 2efacbfd..a35bd53d 100644 --- a/lib/modules/album/album_card.dart +++ b/lib/modules/album/album_card.dart @@ -1,7 +1,9 @@ +import 'package:auto_route/auto_route.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/components/dialogs/select_device_dialog.dart'; import 'package:spotube/components/playbutton_view/playbutton_card.dart'; import 'package:spotube/components/playbutton_view/playbutton_tile.dart'; @@ -10,14 +12,12 @@ import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/extensions/track.dart'; import 'package:spotube/models/connect/connect.dart'; -import 'package:spotube/pages/album/album.dart'; import 'package:spotube/provider/audio_player/querying_track_info.dart'; import 'package:spotube/provider/connect/connect.dart'; import 'package:spotube/provider/history/history.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:spotube/services/audio_player/audio_player.dart'; -import 'package:spotube/utils/service_utils.dart'; extension FormattedAlbumType on AlbumType { String get formatted => name.replaceFirst(name[0], name[0].toUpperCase()); @@ -69,14 +69,7 @@ class AlbumCard extends HookConsumerWidget { "${album.albumType?.formatted} • ${album.artists?.asString() ?? ""}"; void onTap() { - ServiceUtils.pushNamed( - context, - AlbumPage.name, - pathParameters: { - "id": album.id!, - }, - extra: album, - ); + context.pushRoute(AlbumRoute(id: album.id!, album: album)); } void onPlaybuttonPressed() async { diff --git a/lib/modules/artist/artist_card.dart b/lib/modules/artist/artist_card.dart index 57c955c7..28ae6315 100644 --- a/lib/modules/artist/artist_card.dart +++ b/lib/modules/artist/artist_card.dart @@ -1,16 +1,16 @@ +import 'package:auto_route/auto_route.dart'; import 'package:auto_size_text/auto_size_text.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; -import 'package:spotube/pages/artist/artist.dart'; import 'package:spotube/provider/blacklist_provider.dart'; -import 'package:spotube/utils/service_utils.dart'; class ArtistCard extends HookConsumerWidget { final Artist artist; @@ -36,13 +36,7 @@ class ArtistCard extends HookConsumerWidget { width: 180, child: Button.card( onPressed: () { - ServiceUtils.pushNamed( - context, - ArtistPage.name, - pathParameters: { - "id": artist.id!, - }, - ); + context.pushRoute(ArtistRoute(artistId: artist.id!)); }, child: Column( children: [ diff --git a/lib/modules/connect/connect_device.dart b/lib/modules/connect/connect_device.dart index a285284c..df2539a2 100644 --- a/lib/modules/connect/connect_device.dart +++ b/lib/modules/connect/connect_device.dart @@ -1,11 +1,11 @@ +import 'package:auto_route/auto_route.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/pages/connect/connect.dart'; import 'package:spotube/provider/connect/clients.dart'; -import 'package:spotube/utils/service_utils.dart'; class ConnectDeviceButton extends HookConsumerWidget { final bool _sidebar; @@ -26,7 +26,7 @@ class ConnectDeviceButton extends HookConsumerWidget { return IconButton.ghost( icon: const Icon(SpotubeIcons.speaker), onPressed: () { - ServiceUtils.pushNamed(context, ConnectPage.name); + context.pushRoute(const ConnectRoute()); }, ); } @@ -35,7 +35,7 @@ class ConnectDeviceButton extends HookConsumerWidget { width: double.infinity, child: Button.primary( onPressed: () { - ServiceUtils.pushNamed(context, ConnectPage.name); + context.pushRoute(const ConnectRoute()); }, trailing: const Icon(SpotubeIcons.speaker), child: Text( @@ -50,7 +50,7 @@ class ConnectDeviceButton extends HookConsumerWidget { children: [ SecondaryBadge( onPressed: () { - ServiceUtils.pushNamed(context, ConnectPage.name); + context.pushRoute(const ConnectRoute()); }, style: const ButtonStyle.secondary(size: ButtonSize(.8)), leading: connectClients.asData?.value.resolvedService != null @@ -70,7 +70,7 @@ class ConnectDeviceButton extends HookConsumerWidget { IconButton.primary( icon: const Icon(SpotubeIcons.speaker), onPressed: () { - ServiceUtils.pushNamed(context, ConnectPage.name); + context.pushRoute(const ConnectRoute()); }, ) ], diff --git a/lib/modules/home/sections/feed.dart b/lib/modules/home/sections/feed.dart index 34a9ee4b..e423b08c 100644 --- a/lib/modules/home/sections/feed.dart +++ b/lib/modules/home/sections/feed.dart @@ -1,10 +1,10 @@ +import 'package:auto_route/auto_route.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/pages/home/feed/feed_section.dart'; import 'package:spotube/provider/spotify/views/home.dart'; -import 'package:spotube/utils/service_utils.dart'; class HomePageFeedSection extends HookConsumerWidget { const HomePageFeedSection({super.key}); @@ -39,13 +39,9 @@ class HomePageFeedSection extends HookConsumerWidget { onFetchMore: () {}, titleTrailing: Button.text( child: Text(context.l10n.browse_all), - onPressed: () => ServiceUtils.pushNamed( - context, - HomeFeedSectionPage.name, - pathParameters: { - "feedId": section.uri, - }, - ), + onPressed: () { + context.pushRoute(HomeFeedSectionRoute(sectionUri: section.uri)); + }, ), ); }, diff --git a/lib/modules/home/sections/friends/friend_item.dart b/lib/modules/home/sections/friends/friend_item.dart index 94feb5cd..216cc607 100644 --- a/lib/modules/home/sections/friends/friend_item.dart +++ b/lib/modules/home/sections/friends/friend_item.dart @@ -1,14 +1,13 @@ +import 'package:auto_route/auto_route.dart'; import 'package:flutter/gestures.dart'; -import 'package:go_router/go_router.dart'; + import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/models/spotify_friends.dart'; -import 'package:spotube/pages/album/album.dart'; -import 'package:spotube/pages/artist/artist.dart'; -import 'package:spotube/pages/track/track.dart'; import 'package:spotube/provider/spotify_provider.dart'; class FriendItem extends HookConsumerWidget { @@ -50,9 +49,8 @@ class FriendItem extends HookConsumerWidget { text: friend.track.name, recognizer: TapGestureRecognizer() ..onTap = () { - context.pushNamed(TrackPage.name, pathParameters: { - "id": friend.track.id, - }); + context + .pushRoute(TrackRoute(trackId: friend.track.id)); }, ), const TextSpan(text: " • "), @@ -66,12 +64,8 @@ class FriendItem extends HookConsumerWidget { text: " ${friend.track.artist.name}", recognizer: TapGestureRecognizer() ..onTap = () { - context.pushNamed( - ArtistPage.name, - pathParameters: { - "id": friend.track.artist.id, - }, - extra: friend.track.artist, + context.pushRoute( + ArtistRoute(artistId: friend.track.artist.id), ); }, ), @@ -80,13 +74,13 @@ class FriendItem extends HookConsumerWidget { text: friend.track.context.name, recognizer: TapGestureRecognizer() ..onTap = () async { - context.push( + context.router.pushNamed( "/${friend.track.context.path}", - extra: - !friend.track.context.path.startsWith("album") - ? null - : await spotify.albums - .get(friend.track.context.id), + // extra: + // !friend.track.context.path.startsWith("album") + // ? null + // : await spotify.albums + // .get(friend.track.context.id), ); }, ), @@ -104,12 +98,8 @@ class FriendItem extends HookConsumerWidget { final album = await spotify.albums.get(friend.track.album.id); if (context.mounted) { - context.pushNamed( - AlbumPage.name, - pathParameters: { - "id": friend.track.album.id, - }, - extra: album, + context.pushRoute( + AlbumRoute(id: album.id!, album: album), ); } }, diff --git a/lib/modules/home/sections/genres/genre_card.dart b/lib/modules/home/sections/genres/genre_card.dart index 617d7392..8371e553 100644 --- a/lib/modules/home/sections/genres/genre_card.dart +++ b/lib/modules/home/sections/genres/genre_card.dart @@ -1,17 +1,17 @@ import 'dart:math'; import 'dart:ui'; -import 'package:go_router/go_router.dart'; +import 'package:auto_route/auto_route.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotify/spotify.dart' hide Offset; import 'package:spotube/collections/fake.dart'; import 'package:spotube/collections/gradients.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/modules/home/sections/genres/genre_card_playlist_card.dart'; -import 'package:spotube/pages/home/genres/genre_playlists.dart'; import 'package:spotube/provider/spotify/spotify.dart'; final random = Random(); @@ -76,10 +76,11 @@ class GenreSectionCard extends HookConsumerWidget { ).h3(), Button.link( onPressed: () { - context.pushNamed( - GenrePlaylistsPage.name, - pathParameters: {'categoryId': category.id!}, - extra: category, + context.router.push( + GenrePlaylistsRoute( + id: category.id!, + category: category, + ), ); }, child: Text( diff --git a/lib/modules/home/sections/genres/genre_card_playlist_card.dart b/lib/modules/home/sections/genres/genre_card_playlist_card.dart index 0e2284b3..e5770efa 100644 --- a/lib/modules/home/sections/genres/genre_card_playlist_card.dart +++ b/lib/modules/home/sections/genres/genre_card_playlist_card.dart @@ -1,12 +1,12 @@ -import 'package:go_router/go_router.dart'; +import 'package:auto_route/auto_route.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart' hide Image; import 'package:spotube/collections/env.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/extensions/string.dart'; -import 'package:spotube/pages/playlist/playlist.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:stroke_text/stroke_text.dart'; @@ -47,12 +47,8 @@ class GenreSectionCardPlaylistCard extends HookConsumerWidget { }, ), onPressed: () { - context.pushNamed( - PlaylistPage.name, - pathParameters: { - "id": playlist.id!, - }, - extra: playlist, + context.pushRoute( + PlaylistRoute(id: playlist.id!, playlist: playlist), ); }, child: Column( diff --git a/lib/modules/home/sections/genres/genres.dart b/lib/modules/home/sections/genres/genres.dart index 64a6be1c..507985c2 100644 --- a/lib/modules/home/sections/genres/genres.dart +++ b/lib/modules/home/sections/genres/genres.dart @@ -1,15 +1,16 @@ +import 'package:auto_route/auto_route.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; + import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotube/collections/fake.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/modules/home/sections/genres/genre_card.dart'; -import 'package:spotube/pages/home/genres/genres.dart'; import 'package:spotube/provider/spotify/spotify.dart'; class HomeGenresSection extends HookConsumerWidget { @@ -47,7 +48,7 @@ class HomeGenresSection extends HookConsumerWidget { ), Button.link( onPressed: () { - context.pushNamed(GenrePage.name); + context.pushRoute(const GenreRoute()); }, child: Text( context.l10n.browse_all, diff --git a/lib/modules/library/local_folder/local_folder_item.dart b/lib/modules/library/local_folder/local_folder_item.dart index 149657cc..15355d8f 100644 --- a/lib/modules/library/local_folder/local_folder_item.dart +++ b/lib/modules/library/local_folder/local_folder_item.dart @@ -1,18 +1,18 @@ import 'dart:math'; +import 'package:auto_route/auto_route.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:path/path.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/extensions/string.dart'; -import 'package:spotube/pages/library/user_local_tracks/local_folder.dart'; import 'package:spotube/provider/local_tracks/local_tracks_provider.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; @@ -59,13 +59,12 @@ class LocalFolderItem extends HookConsumerWidget { return Button( onPressed: () { - context.pushNamed( - LocalLibraryPage.name, - queryParameters: { - if (isDownloadFolder) "downloads": "true", - if (isCacheFolder) "cache": "true", - }, - extra: folder, + context.pushRoute( + LocalLibraryRoute( + location: folder, + isCache: isCacheFolder, + isDownloads: isDownloadFolder, + ), ); }, style: ButtonVariance.card.copyWith( diff --git a/lib/modules/library/user_downloads/download_item.dart b/lib/modules/library/user_downloads/download_item.dart index 4b104ed1..11c86810 100644 --- a/lib/modules/library/user_downloads/download_item.dart +++ b/lib/modules/library/user_downloads/download_item.dart @@ -1,18 +1,18 @@ +import 'package:auto_route/auto_route.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/components/links/artist_link.dart'; import 'package:spotube/components/ui/button_tile.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; -import 'package:spotube/pages/track/track.dart'; import 'package:spotube/provider/download_manager_provider.dart'; import 'package:spotube/services/download_manager/download_status.dart'; import 'package:spotube/services/sourced_track/sourced_track.dart'; -import 'package:spotube/utils/service_utils.dart'; class DownloadItem extends HookConsumerWidget { final Track track; @@ -66,13 +66,9 @@ class DownloadItem extends HookConsumerWidget { subtitle: ArtistLink( artists: track.artists ?? [], mainAxisAlignment: WrapAlignment.start, - onOverflowArtistClick: () => ServiceUtils.pushNamed( - context, - TrackPage.name, - pathParameters: { - "id": track.id!, - }, - ), + onOverflowArtistClick: () { + context.pushRoute(TrackRoute(trackId: track.id!)); + }, ), trailing: isQueryingSourceInfo ? Text(context.l10n.querying_info).small() diff --git a/lib/modules/player/player.dart b/lib/modules/player/player.dart index 16ee6c72..2f43cbee 100644 --- a/lib/modules/player/player.dart +++ b/lib/modules/player/player.dart @@ -1,13 +1,14 @@ +import 'package:auto_route/auto_route.dart'; import 'package:auto_size_text/auto_size_text.dart'; import 'package:flutter/material.dart' show showModalBottomSheet; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:sliding_up_panel/sliding_up_panel.dart'; import 'package:spotube/collections/assets.gen.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/framework/app_pop_scope.dart'; import 'package:spotube/modules/player/player_actions.dart'; @@ -25,13 +26,11 @@ import 'package:spotube/extensions/image.dart'; import 'package:spotube/models/local_track.dart'; import 'package:spotube/modules/root/spotube_navigation_bar.dart'; import 'package:spotube/pages/lyrics/lyrics.dart'; -import 'package:spotube/pages/track/track.dart'; import 'package:spotube/provider/authentication/authentication.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/provider/server/active_sourced_track.dart'; import 'package:spotube/provider/volume_provider.dart'; import 'package:spotube/services/sourced_track/sources/youtube.dart'; -import 'package:spotube/utils/service_utils.dart'; import 'package:url_launcher/url_launcher_string.dart'; @@ -94,7 +93,7 @@ class PlayerView extends HookConsumerWidget { }, [panelController.isAttached && panelController.isPanelOpen]); return AppPopScope( - canPop: context.canPop(), + canPop: context.watchRouter.canPop(), onPopInvoked: (didPop) async { await panelController.close(); }, @@ -210,14 +209,10 @@ class PlayerView extends HookConsumerWidget { .copyWith(fontWeight: FontWeight.bold), onRouteChange: (route) { panelController.close(); - GoRouter.of(context).push(route); + context.router.pushNamed(route); }, - onOverflowArtistClick: () => ServiceUtils.pushNamed( - context, - TrackPage.name, - pathParameters: { - "id": currentTrack!.id!, - }, + onOverflowArtistClick: () => context.pushRoute( + TrackRoute(trackId: currentTrack!.id!), ), ), ], diff --git a/lib/modules/player/player_track_details.dart b/lib/modules/player/player_track_details.dart index 5c13f3e8..345a19db 100644 --- a/lib/modules/player/player_track_details.dart +++ b/lib/modules/player/player_track_details.dart @@ -1,17 +1,18 @@ +import 'package:auto_route/auto_route.dart'; + import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/collections/assets.gen.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/components/links/artist_link.dart'; import 'package:spotube/components/links/link_text.dart'; import 'package:spotube/extensions/artist_simple.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/image.dart'; -import 'package:spotube/pages/track/track.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; -import 'package:spotube/utils/service_utils.dart'; class PlayerTrackDetails extends HookConsumerWidget { final Color? color; @@ -50,7 +51,7 @@ class PlayerTrackDetails extends HookConsumerWidget { const SizedBox(height: 4), LinkText( playback.activeTrack?.name ?? "", - "/track/${playback.activeTrack?.id}", + TrackRoute(trackId: playback.activeTrack?.id ?? ""), push: true, overflow: TextOverflow.ellipsis, style: theme.typography.normal.copyWith( @@ -72,7 +73,7 @@ class PlayerTrackDetails extends HookConsumerWidget { children: [ LinkText( playback.activeTrack?.name ?? "", - "/track/${playback.activeTrack?.id}", + TrackRoute(trackId: playback.activeTrack?.id ?? ""), push: true, overflow: TextOverflow.ellipsis, style: TextStyle(fontWeight: FontWeight.bold, color: color), @@ -80,15 +81,10 @@ class PlayerTrackDetails extends HookConsumerWidget { ArtistLink( artists: playback.activeTrack?.artists ?? [], onRouteChange: (route) { - ServiceUtils.push(context, route); + context.router.pushNamed(route); }, - onOverflowArtistClick: () => ServiceUtils.pushNamed( - context, - TrackPage.name, - pathParameters: { - "id": track!.id!, - }, - ), + onOverflowArtistClick: () => + context.pushRoute(TrackRoute(trackId: track!.id!)), ) ], ), diff --git a/lib/modules/playlist/playlist_card.dart b/lib/modules/playlist/playlist_card.dart index c24eb24b..1bbcf56f 100644 --- a/lib/modules/playlist/playlist_card.dart +++ b/lib/modules/playlist/playlist_card.dart @@ -1,8 +1,10 @@ +import 'package:auto_route/auto_route.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart' hide Offset, Image; import 'package:spotube/collections/env.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/components/dialogs/select_device_dialog.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/components/playbutton_view/playbutton_card.dart'; @@ -10,14 +12,12 @@ import 'package:spotube/components/playbutton_view/playbutton_tile.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/models/connect/connect.dart'; -import 'package:spotube/pages/playlist/playlist.dart'; import 'package:spotube/provider/audio_player/querying_track_info.dart'; import 'package:spotube/provider/connect/connect.dart'; import 'package:spotube/provider/history/history.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:spotube/services/audio_player/audio_player.dart'; -import 'package:spotube/utils/service_utils.dart'; import 'package:stroke_text/stroke_text.dart'; class PlaylistCard extends HookConsumerWidget { @@ -73,14 +73,7 @@ class PlaylistCard extends HookConsumerWidget { } void onTap() { - ServiceUtils.pushNamed( - context, - PlaylistPage.name, - pathParameters: { - "id": playlist.id!, - }, - extra: playlist, - ); + context.pushRoute(PlaylistRoute(id: playlist.id!, playlist: playlist)); } void onPlaybuttonPressed() async { diff --git a/lib/modules/playlist/playlist_create_dialog.dart b/lib/modules/playlist/playlist_create_dialog.dart index 55e7ce77..9619b2ee 100644 --- a/lib/modules/playlist/playlist_create_dialog.dart +++ b/lib/modules/playlist/playlist_create_dialog.dart @@ -1,11 +1,11 @@ import 'dart:convert'; import 'dart:io'; +import 'package:auto_route/auto_route.dart'; import 'package:collection/collection.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:form_builder_validators/form_builder_validators.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:image_picker/image_picker.dart'; import 'package:path/path.dart'; @@ -105,7 +105,7 @@ class PlaylistCreateDialog extends HookConsumerWidget { isSubmitting.value = false; if (context.mounted && !ref.read(playlistProvider(playlistId ?? "")).hasError) { - context.pop(); + context.router.maybePop(); } } } diff --git a/lib/modules/root/bottom_player.dart b/lib/modules/root/bottom_player.dart index fc581377..18b4c221 100644 --- a/lib/modules/root/bottom_player.dart +++ b/lib/modules/root/bottom_player.dart @@ -1,10 +1,11 @@ +import 'package:auto_route/auto_route.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/collections/assets.gen.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/models/database/database.dart'; import 'package:spotube/modules/player/player_actions.dart'; @@ -96,9 +97,8 @@ class BottomPlayer extends HookConsumerWidget { const Duration(milliseconds: 100), () async { if (context.mounted) { - context.go( - '/mini-player', - extra: prevSize, + context.navigateTo( + MiniLyricsRoute(prevSize: prevSize), ); } }, diff --git a/lib/modules/root/sidebar.dart b/lib/modules/root/sidebar.dart deleted file mode 100644 index 1d5d9da0..00000000 --- a/lib/modules/root/sidebar.dart +++ /dev/null @@ -1,270 +0,0 @@ -import 'package:flutter/material.dart' show Badge; -import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:shadcn_flutter/shadcn_flutter.dart'; - -import 'package:spotube/collections/assets.gen.dart'; -import 'package:spotube/collections/side_bar_tiles.dart'; -import 'package:spotube/collections/spotube_icons.dart'; -import 'package:spotube/components/image/universal_image.dart'; -import 'package:spotube/extensions/image.dart'; -import 'package:spotube/models/database/database.dart'; -import 'package:spotube/extensions/constrains.dart'; -import 'package:spotube/extensions/context.dart'; -import 'package:spotube/modules/connect/connect_device.dart'; -import 'package:spotube/pages/library/user_downloads.dart'; -import 'package:spotube/pages/profile/profile.dart'; -import 'package:spotube/pages/settings/settings.dart'; -import 'package:spotube/provider/authentication/authentication.dart'; -import 'package:spotube/provider/download_manager_provider.dart'; -import 'package:spotube/provider/spotify/spotify.dart'; - -import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; - -import 'package:spotube/utils/service_utils.dart'; - -class Sidebar extends HookConsumerWidget { - final Widget child; - - const Sidebar({ - required this.child, - super.key, - }); - - static Widget brandLogo() { - return Container( - decoration: BoxDecoration( - color: Colors.black, - borderRadius: BorderRadius.circular(50), - ), - child: Assets.spotubeLogoPng.image(height: 50), - ); - } - - @override - Widget build(BuildContext context, WidgetRef ref) { - final routerState = GoRouterState.of(context); - final mediaQuery = MediaQuery.of(context); - - final layoutMode = - ref.watch(userPreferencesProvider.select((s) => s.layoutMode)); - - final sidebarTileList = useMemoized( - () => getSidebarTileList(context.l10n), - [context.l10n], - ); - - final sidebarLibraryTileList = useMemoized( - () => getSidebarLibraryTileList(context.l10n), - [context.l10n], - ); - - final tileList = [...sidebarTileList, ...sidebarLibraryTileList]; - - final selectedIndex = tileList.indexWhere( - (e) => routerState.namedLocation(e.name) == routerState.matchedLocation, - ); - - if (layoutMode == LayoutMode.compact || - (mediaQuery.smAndDown && layoutMode == LayoutMode.adaptive)) { - return Scaffold(child: child); - } - - final navigationButtons = [ - NavigationLabel( - child: mediaQuery.lgAndUp ? const Text("Spotube") : const Text(""), - ), - for (final tile in sidebarTileList) - NavigationButton( - label: mediaQuery.lgAndUp ? Text(tile.title) : null, - child: Tooltip( - tooltip: TooltipContainer(child: Text(tile.title)), - child: Icon(tile.icon), - ), - onChanged: (value) { - if (value) { - context.goNamed(tile.name); - } - }, - ), - const NavigationDivider(), - if (mediaQuery.lgAndUp) - NavigationLabel(child: Text(context.l10n.library)), - for (final tile in sidebarLibraryTileList) - NavigationButton( - label: mediaQuery.lgAndUp ? Text(tile.title) : null, - onChanged: (value) { - if (value) { - context.goNamed(tile.name); - } - }, - child: Tooltip( - tooltip: TooltipContainer(child: Text(tile.title)), - child: Icon(tile.icon), - ), - ), - ]; - - return Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Column( - children: [ - Expanded( - child: mediaQuery.lgAndUp - ? NavigationSidebar( - index: selectedIndex, - onSelected: (index) { - final tile = tileList[index]; - context.goNamed(tile.name); - }, - children: navigationButtons, - ) - : NavigationRail( - alignment: NavigationRailAlignment.start, - index: selectedIndex, - onSelected: (index) { - final tile = tileList[index]; - context.goNamed(tile.name); - }, - children: navigationButtons, - ), - ), - const SidebarFooter(), - if (mediaQuery.lgAndUp) const Gap(130) else const Gap(65), - ], - ), - const VerticalDivider(), - Expanded(child: child), - ], - ); - } -} - -class SidebarFooter extends HookConsumerWidget implements NavigationBarItem { - const SidebarFooter({ - super.key, - }); - - @override - Widget build(BuildContext context, ref) { - final theme = Theme.of(context); - final mediaQuery = MediaQuery.of(context); - final routerState = GoRouterState.of(context); - final downloadCount = ref.watch(downloadManagerProvider).$downloadCount; - final userSnapshot = ref.watch(meProvider); - final data = userSnapshot.asData?.value; - - final avatarImg = (data?.images).asUrlString( - index: (data?.images?.length ?? 1) - 1, - placeholder: ImagePlaceholder.artist, - ); - - final auth = ref.watch(authenticationProvider); - - if (mediaQuery.mdAndDown) { - return Column( - mainAxisSize: MainAxisSize.min, - spacing: 10, - children: [ - Badge( - isLabelVisible: downloadCount > 0, - label: Text(downloadCount.toString()), - child: IconButton( - variance: routerState.topRoute?.name == UserDownloadsPage.name - ? ButtonVariance.secondary - : ButtonVariance.ghost, - icon: const Icon(SpotubeIcons.download), - onPressed: () => - ServiceUtils.navigateNamed(context, UserDownloadsPage.name), - ), - ), - const ConnectDeviceButton.sidebar(), - IconButton( - variance: ButtonVariance.ghost, - icon: const Icon(SpotubeIcons.settings), - onPressed: () => - ServiceUtils.navigateNamed(context, SettingsPage.name), - ), - ], - ); - } - - return Container( - padding: const EdgeInsets.only(left: 12), - width: 180, - child: Column( - mainAxisSize: MainAxisSize.min, - spacing: 10, - children: [ - SizedBox( - width: double.infinity, - child: Button( - style: routerState.topRoute?.name == UserDownloadsPage.name - ? ButtonVariance.secondary - : ButtonVariance.outline, - onPressed: () { - ServiceUtils.navigateNamed(context, UserDownloadsPage.name); - }, - leading: const Icon(SpotubeIcons.download), - trailing: downloadCount > 0 - ? PrimaryBadge( - child: Text(downloadCount.toString()), - ) - : null, - child: Text(context.l10n.downloads), - ), - ), - const ConnectDeviceButton.sidebar(), - Row( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - if (auth.asData?.value != null && data == null) - const CircularProgressIndicator() - else if (data != null) - Flexible( - child: GestureDetector( - onTap: () { - ServiceUtils.pushNamed(context, ProfilePage.name); - }, - child: Row( - children: [ - Avatar( - initials: - Avatar.getInitials(data.displayName ?? "User"), - provider: UniversalImage.imageProvider(avatarImg), - ), - const SizedBox(width: 10), - Flexible( - child: Text( - data.displayName ?? context.l10n.guest, - maxLines: 1, - softWrap: false, - overflow: TextOverflow.fade, - style: theme.typography.normal - .copyWith(fontWeight: FontWeight.bold), - ), - ), - ], - ), - ), - ), - IconButton( - variance: ButtonVariance.ghost, - icon: const Icon(SpotubeIcons.settings), - onPressed: () { - ServiceUtils.pushNamed(context, SettingsPage.name); - }, - ), - ], - ), - ], - ), - ); - } - - @override - bool get selectable => false; -} diff --git a/lib/modules/root/sidebar/sidebar.dart b/lib/modules/root/sidebar/sidebar.dart new file mode 100644 index 00000000..2bfb8687 --- /dev/null +++ b/lib/modules/root/sidebar/sidebar.dart @@ -0,0 +1,132 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; + +import 'package:spotube/collections/assets.gen.dart'; +import 'package:spotube/collections/side_bar_tiles.dart'; +import 'package:spotube/models/database/database.dart'; +import 'package:spotube/extensions/constrains.dart'; +import 'package:spotube/extensions/context.dart'; +import 'package:spotube/modules/root/sidebar/sidebar_footer.dart'; + +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; + +class Sidebar extends HookConsumerWidget { + final Widget child; + + const Sidebar({ + required this.child, + super.key, + }); + + static Widget brandLogo() { + return Container( + decoration: BoxDecoration( + color: Colors.black, + borderRadius: BorderRadius.circular(50), + ), + child: Assets.spotubeLogoPng.image(height: 50), + ); + } + + @override + Widget build(BuildContext context, WidgetRef ref) { + final mediaQuery = MediaQuery.of(context); + + final layoutMode = + ref.watch(userPreferencesProvider.select((s) => s.layoutMode)); + + final sidebarTileList = useMemoized( + () => getSidebarTileList(context.l10n), + [context.l10n], + ); + + final sidebarLibraryTileList = useMemoized( + () => getSidebarLibraryTileList(context.l10n), + [context.l10n], + ); + + final tileList = [...sidebarTileList, ...sidebarLibraryTileList]; + + final router = context.watchRouter; + + final selectedIndex = tileList.indexWhere( + (e) => router.topRoute.name == e.route.routeName, + ); + + if (layoutMode == LayoutMode.compact || + (mediaQuery.smAndDown && layoutMode == LayoutMode.adaptive)) { + return Scaffold(child: child); + } + + final navigationButtons = [ + NavigationLabel( + child: mediaQuery.lgAndUp ? const Text("Spotube") : const Text(""), + ), + for (final tile in sidebarTileList) + NavigationButton( + label: mediaQuery.lgAndUp ? Text(tile.title) : null, + child: Tooltip( + tooltip: TooltipContainer(child: Text(tile.title)), + child: Icon(tile.icon), + ), + onChanged: (value) { + if (value) { + context.navigateTo(tile.route); + } + }, + ), + const NavigationDivider(), + if (mediaQuery.lgAndUp) + NavigationLabel(child: Text(context.l10n.library)), + for (final tile in sidebarLibraryTileList) + NavigationButton( + label: mediaQuery.lgAndUp ? Text(tile.title) : null, + onChanged: (value) { + if (value) { + context.navigateTo(tile.route); + } + }, + child: Tooltip( + tooltip: TooltipContainer(child: Text(tile.title)), + child: Icon(tile.icon), + ), + ), + ]; + + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Column( + children: [ + Expanded( + child: mediaQuery.lgAndUp + ? NavigationSidebar( + index: selectedIndex, + onSelected: (index) { + final tile = tileList[index]; + context.navigateTo(tile.route); + }, + children: navigationButtons, + ) + : NavigationRail( + alignment: NavigationRailAlignment.start, + index: selectedIndex, + onSelected: (index) { + final tile = tileList[index]; + context.navigateTo(tile.route); + }, + children: navigationButtons, + ), + ), + const SidebarFooter(), + if (mediaQuery.lgAndUp) const Gap(130) else const Gap(65), + ], + ), + const VerticalDivider(), + Expanded(child: child), + ], + ); + } +} diff --git a/lib/modules/root/sidebar/sidebar_footer.dart b/lib/modules/root/sidebar/sidebar_footer.dart new file mode 100644 index 00000000..73916f50 --- /dev/null +++ b/lib/modules/root/sidebar/sidebar_footer.dart @@ -0,0 +1,140 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:flutter/material.dart' show Badge; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; + +import 'package:spotube/collections/routes.gr.dart'; +import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/image/universal_image.dart'; +import 'package:spotube/extensions/image.dart'; +import 'package:spotube/extensions/constrains.dart'; +import 'package:spotube/extensions/context.dart'; +import 'package:spotube/modules/connect/connect_device.dart'; +import 'package:spotube/provider/authentication/authentication.dart'; +import 'package:spotube/provider/download_manager_provider.dart'; +import 'package:spotube/provider/spotify/spotify.dart'; + +class SidebarFooter extends HookConsumerWidget implements NavigationBarItem { + const SidebarFooter({ + super.key, + }); + + @override + Widget build(BuildContext context, ref) { + final theme = Theme.of(context); + final router = AutoRouter.of(context, watch: true); + final mediaQuery = MediaQuery.of(context); + final downloadCount = ref.watch(downloadManagerProvider).$downloadCount; + final userSnapshot = ref.watch(meProvider); + final data = userSnapshot.asData?.value; + + final avatarImg = (data?.images).asUrlString( + index: (data?.images?.length ?? 1) - 1, + placeholder: ImagePlaceholder.artist, + ); + + final auth = ref.watch(authenticationProvider); + + if (mediaQuery.mdAndDown) { + return Column( + mainAxisSize: MainAxisSize.min, + spacing: 10, + children: [ + Badge( + isLabelVisible: downloadCount > 0, + label: Text(downloadCount.toString()), + child: IconButton( + variance: router.topRoute.name == UserDownloadsRoute.name + ? ButtonVariance.secondary + : ButtonVariance.ghost, + icon: const Icon(SpotubeIcons.download), + onPressed: () => context.navigateTo(const UserDownloadsRoute()), + ), + ), + const ConnectDeviceButton.sidebar(), + IconButton( + variance: ButtonVariance.ghost, + icon: const Icon(SpotubeIcons.settings), + onPressed: () => context.navigateTo(const SettingsRoute()), + ), + ], + ); + } + + return Container( + padding: const EdgeInsets.only(left: 12), + width: 180, + child: Column( + mainAxisSize: MainAxisSize.min, + spacing: 10, + children: [ + SizedBox( + width: double.infinity, + child: Button( + style: router.topRoute.name == UserDownloadsRoute.name + ? ButtonVariance.secondary + : ButtonVariance.outline, + onPressed: () { + context.navigateTo(const UserDownloadsRoute()); + }, + leading: const Icon(SpotubeIcons.download), + trailing: downloadCount > 0 + ? PrimaryBadge( + child: Text(downloadCount.toString()), + ) + : null, + child: Text(context.l10n.downloads), + ), + ), + const ConnectDeviceButton.sidebar(), + Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + if (auth.asData?.value != null && data == null) + const CircularProgressIndicator() + else if (data != null) + Flexible( + child: GestureDetector( + onTap: () { + context.pushRoute(const ProfileRoute()); + }, + child: Row( + children: [ + Avatar( + initials: + Avatar.getInitials(data.displayName ?? "User"), + provider: UniversalImage.imageProvider(avatarImg), + ), + const SizedBox(width: 10), + Flexible( + child: Text( + data.displayName ?? context.l10n.guest, + maxLines: 1, + softWrap: false, + overflow: TextOverflow.fade, + style: theme.typography.normal + .copyWith(fontWeight: FontWeight.bold), + ), + ), + ], + ), + ), + ), + IconButton( + variance: ButtonVariance.ghost, + icon: const Icon(SpotubeIcons.settings), + onPressed: () { + context.pushRoute(const SettingsRoute()); + }, + ), + ], + ), + ], + ), + ); + } + + @override + bool get selectable => false; +} diff --git a/lib/modules/root/spotube_navigation_bar.dart b/lib/modules/root/spotube_navigation_bar.dart index c19b3a40..cd717833 100644 --- a/lib/modules/root/spotube_navigation_bar.dart +++ b/lib/modules/root/spotube_navigation_bar.dart @@ -1,9 +1,12 @@ +import 'dart:math'; + +import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart' show Badge; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/side_bar_tiles.dart'; import 'package:spotube/extensions/constrains.dart'; @@ -12,8 +15,6 @@ import 'package:spotube/models/database/database.dart'; import 'package:spotube/provider/download_manager_provider.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; -import 'package:spotube/utils/service_utils.dart'; - final navigationPanelHeight = StateProvider((ref) => 50); class SpotubeNavigationBar extends HookConsumerWidget { @@ -23,10 +24,9 @@ class SpotubeNavigationBar extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final routerState = GoRouterState.of(context); + final mediaQuery = MediaQuery.of(context); final downloadCount = ref.watch(downloadManagerProvider).$downloadCount; - final mediaQuery = MediaQuery.of(context); final layoutMode = ref.watch(userPreferencesProvider.select((s) => s.layoutMode)); @@ -35,15 +35,25 @@ class SpotubeNavigationBar extends HookConsumerWidget { [context.l10n], ); + final libraryTiles = useMemoized( + () => getSidebarLibraryTileList(context.l10n) + .map((e) => e.route.routeName) + .toList(), + [context.l10n], + ); + final panelHeight = ref.watch(navigationPanelHeight); - final selectedIndex = useMemoized(() { - final index = navbarTileList.indexWhere( - (e) => routerState.namedLocation(e.name) == routerState.matchedLocation, - ); - - return index == -1 ? 0 : index; - }, [navbarTileList, routerState.matchedLocation]); + final router = context.watchRouter; + final selectedIndex = max( + 0, + navbarTileList.indexWhere( + (e) => + router.topRoute.name == e.route.routeName || + (libraryTiles.contains(router.topRoute.name) && + e.route.routeName == LibraryRoute.name), + ), + ); if (layoutMode == LayoutMode.extended || (mediaQuery.mdAndUp && layoutMode == LayoutMode.adaptive) || @@ -63,7 +73,7 @@ class SpotubeNavigationBar extends HookConsumerWidget { surfaceBlur: context.theme.surfaceBlur, surfaceOpacity: context.theme.surfaceOpacity, onSelected: (i) { - ServiceUtils.navigateNamed(context, navbarTileList[i].name); + context.navigateTo(navbarTileList[i].route); }, children: [ for (final tile in navbarTileList) diff --git a/lib/modules/stats/common/album_item.dart b/lib/modules/stats/common/album_item.dart index 0920baae..3105eb17 100644 --- a/lib/modules/stats/common/album_item.dart +++ b/lib/modules/stats/common/album_item.dart @@ -1,12 +1,12 @@ +import 'package:auto_route/auto_route.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/components/ui/button_tile.dart'; import 'package:spotube/modules/album/album_card.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/components/links/artist_link.dart'; import 'package:spotube/extensions/image.dart'; -import 'package:spotube/pages/album/album.dart'; -import 'package:spotube/utils/service_utils.dart'; class StatsAlbumItem extends StatelessWidget { final AlbumSimple album; @@ -36,25 +36,15 @@ class StatsAlbumItem extends StatelessWidget { child: ArtistLink( artists: album.artists ?? [], mainAxisAlignment: WrapAlignment.start, - onOverflowArtistClick: () => ServiceUtils.pushNamed( - context, - AlbumPage.name, - pathParameters: { - "id": album.id!, - }, - ), + onOverflowArtistClick: () => + context.pushRoute(AlbumRoute(id: album.id!, album: album)), ), ), ], ), trailing: info, onPressed: () { - ServiceUtils.pushNamed( - context, - AlbumPage.name, - pathParameters: {"id": album.id!}, - extra: album, - ); + context.pushRoute(AlbumRoute(id: album.id!, album: album)); }, ); } diff --git a/lib/modules/stats/common/artist_item.dart b/lib/modules/stats/common/artist_item.dart index 26691ba4..13e19777 100644 --- a/lib/modules/stats/common/artist_item.dart +++ b/lib/modules/stats/common/artist_item.dart @@ -1,10 +1,10 @@ +import 'package:auto_route/auto_route.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/components/ui/button_tile.dart'; import 'package:spotube/extensions/image.dart'; -import 'package:spotube/pages/artist/artist.dart'; -import 'package:spotube/utils/service_utils.dart'; class StatsArtistItem extends StatelessWidget { final Artist artist; @@ -30,11 +30,7 @@ class StatsArtistItem extends StatelessWidget { ), trailing: info, onPressed: () { - ServiceUtils.pushNamed( - context, - ArtistPage.name, - pathParameters: {"id": artist.id!}, - ); + context.pushRoute(ArtistRoute(artistId: artist.id!)); }, ); } diff --git a/lib/modules/stats/common/playlist_item.dart b/lib/modules/stats/common/playlist_item.dart index 3859db6b..744fef04 100644 --- a/lib/modules/stats/common/playlist_item.dart +++ b/lib/modules/stats/common/playlist_item.dart @@ -1,11 +1,11 @@ +import 'package:auto_route/auto_route.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/components/ui/button_tile.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/extensions/string.dart'; -import 'package:spotube/pages/playlist/playlist.dart'; -import 'package:spotube/utils/service_utils.dart'; class StatsPlaylistItem extends StatelessWidget { final PlaylistSimple playlist; @@ -35,12 +35,7 @@ class StatsPlaylistItem extends StatelessWidget { ), trailing: info, onPressed: () { - ServiceUtils.pushNamed( - context, - PlaylistPage.name, - pathParameters: {"id": playlist.id!}, - extra: playlist, - ); + context.pushRoute(PlaylistRoute(id: playlist.id!, playlist: playlist)); }, ); } diff --git a/lib/modules/stats/common/track_item.dart b/lib/modules/stats/common/track_item.dart index 8f0f5b8d..640c2b0b 100644 --- a/lib/modules/stats/common/track_item.dart +++ b/lib/modules/stats/common/track_item.dart @@ -1,11 +1,11 @@ +import 'package:auto_route/auto_route.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/components/links/artist_link.dart'; import 'package:spotube/components/ui/button_tile.dart'; import 'package:spotube/extensions/image.dart'; -import 'package:spotube/pages/track/track.dart'; -import 'package:spotube/utils/service_utils.dart'; class StatsTrackItem extends StatelessWidget { final Track track; @@ -34,23 +34,13 @@ class StatsTrackItem extends StatelessWidget { subtitle: ArtistLink( artists: track.artists!, mainAxisAlignment: WrapAlignment.start, - onOverflowArtistClick: () => ServiceUtils.pushNamed( - context, - TrackPage.name, - pathParameters: { - "id": track.id!, - }, - ), + onOverflowArtistClick: () { + context.pushRoute(TrackRoute(trackId: track.id!)); + }, ), trailing: info, onPressed: () { - ServiceUtils.pushNamed( - context, - TrackPage.name, - pathParameters: { - "id": track.id!, - }, - ); + context.pushRoute(TrackRoute(trackId: track.id!)); }, ); } diff --git a/lib/modules/stats/summary/summary.dart b/lib/modules/stats/summary/summary.dart index 351b0264..6966da97 100644 --- a/lib/modules/stats/summary/summary.dart +++ b/lib/modules/stats/summary/summary.dart @@ -1,19 +1,14 @@ +import 'package:auto_route/auto_route.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotube/collections/fake.dart'; import 'package:spotube/collections/formatters.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/modules/stats/summary/summary_card.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/pages/stats/albums/albums.dart'; -import 'package:spotube/pages/stats/artists/artists.dart'; -import 'package:spotube/pages/stats/fees/fees.dart'; -import 'package:spotube/pages/stats/minutes/minutes.dart'; -import 'package:spotube/pages/stats/playlists/playlists.dart'; -import 'package:spotube/pages/stats/streams/streams.dart'; import 'package:spotube/provider/history/summary.dart'; -import 'package:spotube/utils/service_utils.dart'; class StatsPageSummarySection extends HookConsumerWidget { const StatsPageSummarySection({super.key}); @@ -50,7 +45,7 @@ class StatsPageSummarySection extends HookConsumerWidget { description: context.l10n.summary_listened_to_music, color: Colors.indigo, onTap: () { - ServiceUtils.pushNamed(context, StatsMinutesPage.name); + context.pushRoute(const StatsMinutesRoute()); }, ), SummaryCard( @@ -59,7 +54,7 @@ class StatsPageSummarySection extends HookConsumerWidget { description: context.l10n.summary_streamed_overall, color: Colors.blue, onTap: () { - ServiceUtils.pushNamed(context, StatsStreamsPage.name); + context.pushRoute(const StatsStreamsRoute()); }, ), SummaryCard.unformatted( @@ -68,7 +63,7 @@ class StatsPageSummarySection extends HookConsumerWidget { description: context.l10n.summary_owed_to_artists, color: Colors.green, onTap: () { - ServiceUtils.pushNamed(context, StatsStreamFeesPage.name); + context.pushRoute(const StatsStreamsRoute()); }, ), SummaryCard( @@ -77,7 +72,7 @@ class StatsPageSummarySection extends HookConsumerWidget { description: context.l10n.summary_music_reached_you, color: Colors.yellow, onTap: () { - ServiceUtils.pushNamed(context, StatsArtistsPage.name); + context.pushRoute(const StatsArtistsRoute()); }, ), SummaryCard( @@ -86,7 +81,7 @@ class StatsPageSummarySection extends HookConsumerWidget { description: context.l10n.summary_got_your_love, color: Colors.pink, onTap: () { - ServiceUtils.pushNamed(context, StatsAlbumsPage.name); + context.pushRoute(const StatsAlbumsRoute()); }, ), SummaryCard( @@ -95,7 +90,7 @@ class StatsPageSummarySection extends HookConsumerWidget { description: context.l10n.summary_were_on_repeat, color: Colors.teal, onTap: () { - ServiceUtils.pushNamed(context, StatsPlaylistsPage.name); + context.pushRoute(const StatsPlaylistsRoute()); }, ), ]), diff --git a/lib/modules/stats/top/top.dart b/lib/modules/stats/top/top.dart index 8e9134c7..1df2b7e9 100644 --- a/lib/modules/stats/top/top.dart +++ b/lib/modules/stats/top/top.dart @@ -56,6 +56,7 @@ class StatsPageTopSection extends HookConsumerWidget { floating: true, elevation: 0, backgroundColor: context.theme.colorScheme.background, + automaticallyImplyLeading: false, flexibleSpace: Padding( padding: const EdgeInsets.all(8.0), child: Row( diff --git a/lib/pages/album/album.dart b/lib/pages/album/album.dart index bc013574..5d19f5ed 100644 --- a/lib/pages/album/album.dart +++ b/lib/pages/album/album.dart @@ -1,3 +1,4 @@ +import 'package:auto_route/auto_route.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; @@ -7,12 +8,15 @@ import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/provider/spotify/spotify.dart'; +@RoutePage() class AlbumPage extends HookConsumerWidget { static const name = "album"; final AlbumSimple album; + final String id; const AlbumPage({ super.key, + @PathParam("id") required this.id, required this.album, }); diff --git a/lib/pages/artist/artist.dart b/lib/pages/artist/artist.dart index 5565d897..67db398d 100644 --- a/lib/pages/artist/artist.dart +++ b/lib/pages/artist/artist.dart @@ -13,12 +13,17 @@ import 'package:spotube/pages/artist/section/header.dart'; import 'package:spotube/pages/artist/section/related_artists.dart'; import 'package:spotube/pages/artist/section/top_tracks.dart'; import 'package:spotube/provider/spotify/spotify.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class ArtistPage extends HookConsumerWidget { static const name = "artist"; final String artistId; - const ArtistPage(this.artistId, {super.key}); + const ArtistPage( + @PathParam("id") this.artistId, { + super.key, + }); @override Widget build(BuildContext context, ref) { diff --git a/lib/pages/connect/connect.dart b/lib/pages/connect/connect.dart index 55c72026..20b6d0da 100644 --- a/lib/pages/connect/connect.dart +++ b/lib/pages/connect/connect.dart @@ -1,14 +1,15 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/ui/button_tile.dart'; import 'package:spotube/modules/connect/local_devices.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/pages/connect/control/control.dart'; import 'package:spotube/provider/connect/clients.dart'; -import 'package:spotube/utils/service_utils.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class ConnectPage extends HookConsumerWidget { static const name = "connect"; @@ -71,10 +72,7 @@ class ConnectPage extends HookConsumerWidget { : null, onPressed: () { if (selected) { - ServiceUtils.pushNamed( - context, - ConnectControlPage.name, - ); + context.pushRoute(const ConnectControlRoute()); } else { connectClientsNotifier.resolveService(device); } diff --git a/lib/pages/connect/control/control.dart b/lib/pages/connect/control/control.dart index afe68b16..504d670c 100644 --- a/lib/pages/connect/control/control.dart +++ b/lib/pages/connect/control/control.dart @@ -1,7 +1,8 @@ -import 'package:go_router/go_router.dart'; +import 'package:auto_route/auto_route.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/modules/player/player_queue.dart'; import 'package:spotube/modules/player/volume_slider.dart'; @@ -13,11 +14,9 @@ import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/duration.dart'; import 'package:spotube/extensions/image.dart'; -import 'package:spotube/pages/track/track.dart'; import 'package:spotube/provider/connect/clients.dart'; import 'package:spotube/provider/connect/connect.dart'; import 'package:media_kit/media_kit.dart' hide Track; -import 'package:spotube/utils/service_utils.dart'; class RemotePlayerQueue extends ConsumerWidget { const RemotePlayerQueue({super.key}); @@ -46,6 +45,7 @@ class RemotePlayerQueue extends ConsumerWidget { } } +@RoutePage() class ConnectControlPage extends HookConsumerWidget { static const name = "connect_control"; @@ -65,7 +65,7 @@ class ConnectControlPage extends HookConsumerWidget { ref.listen(connectClientsProvider, (prev, next) { if (next.asData?.value.resolvedService == null) { - context.pop(); + context.back(); } }); @@ -115,12 +115,9 @@ class ConnectControlPage extends HookConsumerWidget { style: typography.h4, onTap: () { if (playlist.activeTrack == null) return; - ServiceUtils.pushNamed( - context, - TrackPage.name, - pathParameters: { - "id": playlist.activeTrack!.id!, - }, + context.pushRoute( + TrackRoute( + trackId: playlist.activeTrack!.id!), ); }, ), @@ -130,13 +127,8 @@ class ConnectControlPage extends HookConsumerWidget { artists: playlist.activeTrack?.artists ?? [], textStyle: typography.normal, mainAxisAlignment: WrapAlignment.start, - onOverflowArtistClick: () => - ServiceUtils.pushNamed( - context, - TrackPage.name, - pathParameters: { - "id": playlist.activeTrack!.id!, - }, + onOverflowArtistClick: () => context.pushRoute( + TrackRoute(trackId: playlist.activeTrack!.id!), ), ), ), diff --git a/lib/pages/getting_started/getting_started.dart b/lib/pages/getting_started/getting_started.dart index f710bd8f..a576ed09 100644 --- a/lib/pages/getting_started/getting_started.dart +++ b/lib/pages/getting_started/getting_started.dart @@ -8,11 +8,13 @@ import 'package:spotube/pages/getting_started/sections/greeting.dart'; import 'package:spotube/pages/getting_started/sections/playback.dart'; import 'package:spotube/pages/getting_started/sections/region.dart'; import 'package:spotube/pages/getting_started/sections/support.dart'; +import 'package:auto_route/auto_route.dart'; -class GettingStarting extends HookConsumerWidget { +@RoutePage() +class GettingStartedPage extends HookConsumerWidget { static const name = "getting_started"; - const GettingStarting({super.key}); + const GettingStartedPage({super.key}); @override Widget build(BuildContext context, ref) { diff --git a/lib/pages/getting_started/sections/support.dart b/lib/pages/getting_started/sections/support.dart index 640b0b38..9559d28d 100644 --- a/lib/pages/getting_started/sections/support.dart +++ b/lib/pages/getting_started/sections/support.dart @@ -1,11 +1,11 @@ -import 'package:go_router/go_router.dart'; +import 'package:auto_route/auto_route.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/env.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/modules/getting_started/blur_card.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/pages/home/home.dart'; import 'package:spotube/pages/mobile_login/hooks/login_callback.dart'; import 'package:spotube/services/kv_store/kv_store.dart'; import 'package:url_launcher/url_launcher_string.dart'; @@ -112,7 +112,7 @@ class GettingStartedScreenSupportSection extends HookConsumerWidget { onPressed: () async { await KVStoreService.setDoneGettingStarted(true); if (context.mounted) { - context.goNamed(HomePage.name); + context.navigateTo(const HomeRoute()); } }, child: Text(context.l10n.browse_anonymously), diff --git a/lib/pages/home/feed/feed_section.dart b/lib/pages/home/feed/feed_section.dart index 38d0887c..eff70808 100644 --- a/lib/pages/home/feed/feed_section.dart +++ b/lib/pages/home/feed/feed_section.dart @@ -1,3 +1,4 @@ +import 'package:auto_route/auto_route.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; @@ -10,11 +11,15 @@ import 'package:spotube/modules/playlist/playlist_card.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/provider/spotify/views/home_section.dart'; +@RoutePage() class HomeFeedSectionPage extends HookConsumerWidget { static const name = "home_feed_section"; final String sectionUri; - const HomeFeedSectionPage({super.key, required this.sectionUri}); + const HomeFeedSectionPage({ + super.key, + @PathParam("feedId") required this.sectionUri, + }); @override Widget build(BuildContext context, ref) { diff --git a/lib/pages/home/genres/genre_playlists.dart b/lib/pages/home/genres/genre_playlists.dart index ebfc4450..a3e38309 100644 --- a/lib/pages/home/genres/genre_playlists.dart +++ b/lib/pages/home/genres/genre_playlists.dart @@ -1,12 +1,12 @@ import 'package:flutter/material.dart' show CollapseMode, FlexibleSpaceBar; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotify/spotify.dart' hide Offset; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/components/button/back_button.dart'; import 'package:spotube/components/playbutton_view/playbutton_view.dart'; import 'package:spotube/hooks/utils/use_custom_status_bar_color.dart'; @@ -16,12 +16,19 @@ import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:spotube/utils/platform.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class GenrePlaylistsPage extends HookConsumerWidget { static const name = "genre_playlists"; final Category category; - const GenrePlaylistsPage({super.key, required this.category}); + final String id; + const GenrePlaylistsPage({ + super.key, + @PathParam("categoryId") required this.id, + required this.category, + }); @override Widget build(BuildContext context, ref) { @@ -30,11 +37,10 @@ class GenrePlaylistsPage extends HookConsumerWidget { final playlistsNotifier = ref.read(categoryPlaylistsProvider(category.id!).notifier); final scrollController = useScrollController(); - final routeName = GoRouterState.of(context).name; useCustomStatusBarColor( Colors.black, - routeName == GenrePlaylistsPage.name, + context.watchRouter.topRoute.name == GenrePlaylistsRoute.name, noSetBGColor: true, automaticSystemUiAdjustment: false, ); diff --git a/lib/pages/home/genres/genres.dart b/lib/pages/home/genres/genres.dart index 062852e8..1bdb3782 100644 --- a/lib/pages/home/genres/genres.dart +++ b/lib/pages/home/genres/genres.dart @@ -3,17 +3,19 @@ import 'dart:math'; import 'package:auto_size_text/auto_size_text.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; + import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/collections/gradients.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/pages/home/genres/genre_playlists.dart'; import 'package:spotube/provider/spotify/spotify.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class GenrePage extends HookConsumerWidget { static const name = "genre"; const GenrePage({super.key}); @@ -49,12 +51,11 @@ class GenrePage extends HookConsumerWidget { final gradient = gradients[Random().nextInt(gradients.length)]; return CardImage( onPressed: () { - context.pushNamed( - GenrePlaylistsPage.name, - pathParameters: { - "categoryId": category.id!, - }, - extra: category, + context.pushRoute( + GenrePlaylistsRoute( + id: category.id!, + category: category, + ), ); }, image: Stack( diff --git a/lib/pages/home/home.dart b/lib/pages/home/home.dart index 1638393b..9bcba29e 100644 --- a/lib/pages/home/home.dart +++ b/lib/pages/home/home.dart @@ -1,9 +1,11 @@ +import 'package:auto_route/auto_route.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotube/collections/assets.gen.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/models/database/database.dart'; import 'package:spotube/modules/connect/connect_device.dart'; @@ -16,11 +18,10 @@ import 'package:spotube/modules/home/sections/new_releases.dart'; import 'package:spotube/modules/home/sections/recent.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/extensions/constrains.dart'; -import 'package:spotube/pages/settings/settings.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/utils/platform.dart'; -import 'package:spotube/utils/service_utils.dart'; +@RoutePage() class HomePage extends HookConsumerWidget { static const name = "home"; const HomePage({super.key}); @@ -53,7 +54,7 @@ class HomePage extends HookConsumerWidget { IconButton.ghost( icon: const Icon(SpotubeIcons.settings, size: 20), onPressed: () { - ServiceUtils.pushNamed(context, SettingsPage.name); + context.pushRoute(const SettingsRoute()); }, ), const Gap(10), diff --git a/lib/pages/lastfm_login/lastfm_login.dart b/lib/pages/lastfm_login/lastfm_login.dart index 89b8270a..6b741f4d 100644 --- a/lib/pages/lastfm_login/lastfm_login.dart +++ b/lib/pages/lastfm_login/lastfm_login.dart @@ -1,6 +1,5 @@ import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/spotube_icons.dart'; @@ -9,14 +8,15 @@ import 'package:spotube/components/dialogs/prompt_dialog.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/scrobbler/scrobbler.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class LastFMLoginPage extends HookConsumerWidget { static const name = "lastfm_login"; const LastFMLoginPage({super.key}); @override Widget build(BuildContext context, ref) { - final router = GoRouter.of(context); final scrobblerNotifier = ref.read(scrobblerProvider.notifier); final usernameKey = @@ -53,7 +53,9 @@ class LastFMLoginPage extends HookConsumerWidget { values[usernameKey].trim(), values[passwordKey], ); - router.pop(); + if (context.mounted) { + context.back(); + } } catch (e) { if (context.mounted) { showPromptDialog( diff --git a/lib/pages/library/library.dart b/lib/pages/library/library.dart index 6677a3b6..91353aed 100644 --- a/lib/pages/library/library.dart +++ b/lib/pages/library/library.dart @@ -1,38 +1,38 @@ +import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart' show Badge; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/side_bar_tiles.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/pages/library/user_downloads.dart'; import 'package:spotube/provider/download_manager_provider.dart'; +@RoutePage() class LibraryPage extends HookConsumerWidget { - final Widget child; - const LibraryPage({super.key, required this.child}); + const LibraryPage({super.key}); @override Widget build(BuildContext context, ref) { final downloadingCount = ref.watch(downloadManagerProvider).$downloadCount; - final routerState = GoRouterState.of(context); + final router = context.watchRouter; final sidebarLibraryTileList = useMemoized( () => [ ...getSidebarLibraryTileList(context.l10n), SideBarTiles( id: "downloads", title: context.l10n.downloads, - name: UserDownloadsPage.name, + route: const UserDownloadsRoute(), icon: SpotubeIcons.download, ), ], [context.l10n], ); final index = sidebarLibraryTileList.indexWhere( - (e) => routerState.namedLocation(e.name) == routerState.matchedLocation, + (e) => router.topRoute.name == e.route.routeName, ); return SafeArea( @@ -56,7 +56,7 @@ class LibraryPage extends HookConsumerWidget { child: Text(tile.title), ), onPressed: () { - context.goNamed(tile.name); + context.navigateTo(tile.route); }, ), ], @@ -65,7 +65,7 @@ class LibraryPage extends HookConsumerWidget { ), const Gap(10), ], - child: child, + child: const AutoRouter(), ); }), ); diff --git a/lib/pages/library/playlist_generate/playlist_generate.dart b/lib/pages/library/playlist_generate/playlist_generate.dart index 2b1e7512..29bfb360 100644 --- a/lib/pages/library/playlist_generate/playlist_generate.dart +++ b/lib/pages/library/playlist_generate/playlist_generate.dart @@ -1,10 +1,11 @@ import 'package:collection/collection.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; + import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotify_markets.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/button/back_button.dart'; @@ -23,9 +24,11 @@ import 'package:spotube/models/spotify/recommendation_seeds.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:spotube/provider/spotify_provider.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; +import 'package:auto_route/auto_route.dart'; const RecommendationAttribute zeroValues = (min: 0, target: 0, max: 0); +@RoutePage() class PlaylistGeneratorPage extends HookConsumerWidget { static const name = "playlist_generator"; @@ -660,9 +663,10 @@ class PlaylistGeneratorPage extends HookConsumerWidget { min: min.value, target: target.value, ); - GoRouter.of(context).push( - "/library/generate/result", - extra: routeState, + context.pushRoute( + PlaylistGenerateResultRoute( + state: routeState, + ), ); }, child: Text(context.l10n.generate), diff --git a/lib/pages/library/playlist_generate/playlist_generate_result.dart b/lib/pages/library/playlist_generate/playlist_generate_result.dart index 87d6fdc9..4c350366 100644 --- a/lib/pages/library/playlist_generate/playlist_generate_result.dart +++ b/lib/pages/library/playlist_generate/playlist_generate_result.dart @@ -1,8 +1,10 @@ +import 'package:auto_route/auto_route.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; + import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/button/back_button.dart'; import 'package:spotube/modules/library/playlist_generate/simple_track_tile.dart'; @@ -11,10 +13,10 @@ import 'package:spotube/components/dialogs/playlist_add_track_dialog.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/models/spotify/recommendation_seeds.dart'; -import 'package:spotube/pages/playlist/playlist.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/provider/spotify/spotify.dart'; +@RoutePage() class PlaylistGenerateResultPage extends HookConsumerWidget { static const name = "playlist_generate_result"; @@ -27,8 +29,6 @@ class PlaylistGenerateResultPage extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final router = GoRouter.of(context); - final playlistNotifier = ref.watch(audioPlayerProvider.notifier); final generatedPlaylist = ref.watch(generatePlaylistProvider(state)); @@ -134,13 +134,12 @@ class PlaylistGenerateResultPage extends HookConsumerWidget { ), ); - if (playlist != null) { - router.goNamed( - PlaylistPage.name, - pathParameters: { - "id": playlist.id!, - }, - extra: playlist, + if (playlist != null && context.mounted) { + context.navigateTo( + PlaylistRoute( + id: playlist.id!, + playlist: playlist, + ), ); } }, diff --git a/lib/pages/library/user_albums.dart b/lib/pages/library/user_albums.dart index 861d1705..e11c6c8b 100644 --- a/lib/pages/library/user_albums.dart +++ b/lib/pages/library/user_albums.dart @@ -15,7 +15,9 @@ import 'package:spotube/components/fallbacks/anonymous_fallback.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/authentication/authentication.dart'; import 'package:spotube/provider/spotify/spotify.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class UserAlbumsPage extends HookConsumerWidget { static const name = 'user_albums'; const UserAlbumsPage({super.key}); diff --git a/lib/pages/library/user_artists.dart b/lib/pages/library/user_artists.dart index 6ce715ad..f55f4587 100644 --- a/lib/pages/library/user_artists.dart +++ b/lib/pages/library/user_artists.dart @@ -18,7 +18,9 @@ import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/authentication/authentication.dart'; import 'package:spotube/provider/spotify/spotify.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class UserArtistsPage extends HookConsumerWidget { static const name = 'user_artists'; const UserArtistsPage({super.key}); diff --git a/lib/pages/library/user_downloads.dart b/lib/pages/library/user_downloads.dart index 871e21ab..1d8f560a 100644 --- a/lib/pages/library/user_downloads.dart +++ b/lib/pages/library/user_downloads.dart @@ -5,7 +5,9 @@ import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/modules/library/user_downloads/download_item.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/download_manager_provider.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class UserDownloadsPage extends HookConsumerWidget { static const name = 'user_downloads'; const UserDownloadsPage({super.key}); diff --git a/lib/pages/library/user_local_tracks/local_folder.dart b/lib/pages/library/user_local_tracks/local_folder.dart index 5282894a..028d4e69 100644 --- a/lib/pages/library/user_local_tracks/local_folder.dart +++ b/lib/pages/library/user_local_tracks/local_folder.dart @@ -29,7 +29,9 @@ import 'package:spotube/provider/local_tracks/local_tracks_provider.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/utils/service_utils.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class LocalLibraryPage extends HookConsumerWidget { static const name = "local_library_page"; diff --git a/lib/pages/library/user_local_tracks/user_local_tracks.dart b/lib/pages/library/user_local_tracks/user_local_tracks.dart index 66c011e5..67e02b0b 100644 --- a/lib/pages/library/user_local_tracks/user_local_tracks.dart +++ b/lib/pages/library/user_local_tracks/user_local_tracks.dart @@ -1,3 +1,4 @@ +import 'package:auto_route/auto_route.dart'; import 'package:file_picker/file_picker.dart'; import 'package:file_selector/file_selector.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; @@ -24,6 +25,7 @@ enum SortBy { album, } +@RoutePage() class UserLocalLibraryPage extends HookConsumerWidget { static const name = 'user_local_library'; const UserLocalLibraryPage({super.key}); diff --git a/lib/pages/library/user_playlists.dart b/lib/pages/library/user_playlists.dart index a4711e1b..76a01e18 100644 --- a/lib/pages/library/user_playlists.dart +++ b/lib/pages/library/user_playlists.dart @@ -7,6 +7,7 @@ import 'package:shadcn_flutter/shadcn_flutter.dart' hide Image; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/playbutton_view/playbutton_view.dart'; import 'package:spotube/modules/playlist/playlist_create_dialog.dart'; @@ -14,12 +15,12 @@ import 'package:spotube/components/inter_scrollbar/inter_scrollbar.dart'; import 'package:spotube/components/fallbacks/anonymous_fallback.dart'; import 'package:spotube/modules/playlist/playlist_card.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/pages/library/playlist_generate/playlist_generate.dart'; import 'package:spotube/provider/authentication/authentication.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:spotube/utils/platform.dart'; -import 'package:spotube/utils/service_utils.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class UserPlaylistsPage extends HookConsumerWidget { static const name = 'user_playlists'; const UserPlaylistsPage({super.key}); @@ -113,10 +114,7 @@ class UserPlaylistsPage extends HookConsumerWidget { leading: const Icon(SpotubeIcons.magic), child: Text(context.l10n.generate), onPressed: () { - ServiceUtils.pushNamed( - context, - PlaylistGeneratorPage.name, - ); + context.pushRoute(const PlaylistGeneratorRoute()); }, ), const Gap(10), diff --git a/lib/pages/lyrics/lyrics.dart b/lib/pages/lyrics/lyrics.dart index 85798eda..ab8782a8 100644 --- a/lib/pages/lyrics/lyrics.dart +++ b/lib/pages/lyrics/lyrics.dart @@ -14,7 +14,9 @@ import 'package:spotube/pages/lyrics/synced_lyrics.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/utils/platform.dart'; import 'package:spotube/provider/spotify/spotify.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class LyricsPage extends HookConsumerWidget { static const name = "lyrics"; diff --git a/lib/pages/lyrics/mini_lyrics.dart b/lib/pages/lyrics/mini_lyrics.dart index 9fd54ad6..bb879888 100644 --- a/lib/pages/lyrics/mini_lyrics.dart +++ b/lib/pages/lyrics/mini_lyrics.dart @@ -1,9 +1,10 @@ import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; + import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:palette_generator/palette_generator.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/modules/player/player_controls.dart'; import 'package:spotube/modules/player/player_queue.dart'; @@ -14,7 +15,9 @@ import 'package:spotube/pages/lyrics/synced_lyrics.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/utils/platform.dart'; import 'package:window_manager/window_manager.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class MiniLyricsPage extends HookConsumerWidget { static const name = "mini_lyrics"; @@ -265,7 +268,7 @@ class MiniLyricsPage extends HookConsumerWidget { const Duration(milliseconds: 200)); } finally { if (context.mounted) { - GoRouter.of(context).go('/lyrics'); + context.navigateTo(LyricsRoute()); } } }, diff --git a/lib/pages/mobile_login/hooks/login_callback.dart b/lib/pages/mobile_login/hooks/login_callback.dart index 9979f4a5..af08b9f9 100644 --- a/lib/pages/mobile_login/hooks/login_callback.dart +++ b/lib/pages/mobile_login/hooks/login_callback.dart @@ -1,14 +1,15 @@ import 'dart:io'; +import 'package:auto_route/auto_route.dart'; import 'package:desktop_webview_window/desktop_webview_window.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart' hide join; import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; + import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:path/path.dart'; import 'package:path_provider/path_provider.dart'; -import 'package:spotube/pages/mobile_login/mobile_login.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/pages/mobile_login/no_webview_runtime_dialog.dart'; import 'package:spotube/provider/authentication/authentication.dart'; import 'package:spotube/utils/platform.dart'; @@ -20,7 +21,7 @@ Future Function() useLoginCallback(WidgetRef ref) { return useCallback(() async { if (kIsMobile || kIsMacOS) { - context.pushNamed(WebViewLogin.name); + context.pushRoute(const WebViewLoginRoute()); return; } @@ -57,7 +58,7 @@ Future Function() useLoginCallback(WidgetRef ref) { webview.close(); if (context.mounted) { - context.go("/"); + context.navigateTo(const HomeRoute()); } }); } @@ -76,5 +77,5 @@ Future Function() useLoginCallback(WidgetRef ref) { }); } } - }, [authNotifier, theme, context.go, context.pushNamed]); + }, [authNotifier, theme, context.navigateTo]); } diff --git a/lib/pages/mobile_login/mobile_login.dart b/lib/pages/mobile_login/mobile_login.dart index e2191586..4128bfe6 100644 --- a/lib/pages/mobile_login/mobile_login.dart +++ b/lib/pages/mobile_login/mobile_login.dart @@ -1,16 +1,19 @@ import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -import 'package:go_router/go_router.dart'; + import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/components/button/back_button.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/provider/authentication/authentication.dart'; import 'package:spotube/utils/platform.dart'; +import 'package:auto_route/auto_route.dart'; -class WebViewLogin extends HookConsumerWidget { +@RoutePage() +class WebViewLoginPage extends HookConsumerWidget { static const name = "login"; - const WebViewLogin({super.key}); + const WebViewLoginPage({super.key}); @override Widget build(BuildContext context, ref) { @@ -64,7 +67,7 @@ class WebViewLogin extends HookConsumerWidget { await authenticationNotifier.login(cookieHeader); if (context.mounted) { // ignore: use_build_context_synchronously - GoRouter.of(context).go("/"); + context.navigateTo(const HomeRoute()); } } }, diff --git a/lib/pages/playlist/liked_playlist.dart b/lib/pages/playlist/liked_playlist.dart index 95107a8c..54df2c88 100644 --- a/lib/pages/playlist/liked_playlist.dart +++ b/lib/pages/playlist/liked_playlist.dart @@ -5,7 +5,9 @@ import 'package:spotube/components/track_presentation/presentation_props.dart'; import 'package:spotube/components/track_presentation/track_presentation.dart'; import 'package:spotube/pages/playlist/playlist.dart'; import 'package:spotube/provider/spotify/spotify.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class LikedPlaylistPage extends HookConsumerWidget { static const name = PlaylistPage.name; diff --git a/lib/pages/playlist/playlist.dart b/lib/pages/playlist/playlist.dart index b610b1d4..e3992db8 100644 --- a/lib/pages/playlist/playlist.dart +++ b/lib/pages/playlist/playlist.dart @@ -9,13 +9,17 @@ import 'package:spotube/components/track_presentation/use_is_user_playlist.dart' import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/provider/spotify/spotify.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class PlaylistPage extends HookConsumerWidget { static const name = "playlist"; final PlaylistSimple _playlist; + final String id; const PlaylistPage({ super.key, + @PathParam("id") required this.id, required PlaylistSimple playlist, }) : _playlist = playlist; diff --git a/lib/pages/profile/profile.dart b/lib/pages/profile/profile.dart index 004fbd1a..a82c80b5 100644 --- a/lib/pages/profile/profile.dart +++ b/lib/pages/profile/profile.dart @@ -12,7 +12,9 @@ import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:url_launcher/url_launcher_string.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class ProfilePage extends HookConsumerWidget { static const name = "profile"; diff --git a/lib/pages/root/root_app.dart b/lib/pages/root/root_app.dart index 2a1bf088..e5f0917b 100644 --- a/lib/pages/root/root_app.dart +++ b/lib/pages/root/root_app.dart @@ -1,27 +1,24 @@ +import 'package:auto_route/auto_route.dart'; import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/side_bar_tiles.dart'; import 'package:spotube/components/framework/app_pop_scope.dart'; import 'package:spotube/modules/root/bottom_player.dart'; -import 'package:spotube/modules/root/sidebar.dart'; +import 'package:spotube/modules/root/sidebar/sidebar.dart'; import 'package:spotube/modules/root/spotube_navigation_bar.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/hooks/configurators/use_endless_playback.dart'; import 'package:spotube/modules/root/use_downloader_dialogs.dart'; import 'package:spotube/modules/root/use_global_subscriptions.dart'; -import 'package:spotube/pages/home/home.dart'; import 'package:spotube/provider/glance/glance.dart'; import 'package:spotube/utils/platform.dart'; -class RootApp extends HookConsumerWidget { - final Widget child; - const RootApp({ - required this.child, - super.key, - }); +@RoutePage() +class RootAppPage extends HookConsumerWidget { + const RootAppPage({super.key}); @override Widget build(BuildContext context, ref) { @@ -46,19 +43,19 @@ class RootApp extends HookConsumerWidget { }, [backgroundColor, brightness]); final navTileNames = useMemoized(() { - return getSidebarTileList(context.l10n).map((s) => s.name).toList(); + return getSidebarTileList(context.l10n).map((s) => s.route).toList(); }, []); final scaffold = MediaQuery.removeViewInsets( context: context, removeBottom: true, - child: Scaffold( - footers: const [ + child: const Scaffold( + footers: [ BottomPlayer(), SpotubeNavigationBar(), ], floatingFooter: true, - child: Sidebar(child: child), + child: Sidebar(child: AutoRouter()), ), ); @@ -66,18 +63,18 @@ class RootApp extends HookConsumerWidget { return scaffold; } - final topRoute = GoRouterState.of(context).topRoute; - final canPop = topRoute != null && !navTileNames.contains(topRoute.name); + final topRoute = context.router.topRoute; + final canPop = navTileNames.any((name) => name.routeName == topRoute.name); return AppPopScope( canPop: canPop, onPopInvoked: (didPop) { if (didPop) return; - if (topRoute?.name == HomePage.name) { + if (topRoute.path == const HomeRoute().fragment) { SystemNavigator.pop(); } else { - context.goNamed(HomePage.name); + context.navigateTo(const HomeRoute()); } }, child: scaffold, diff --git a/lib/pages/search/search.dart b/lib/pages/search/search.dart index 701c3c5c..2a69b057 100644 --- a/lib/pages/search/search.dart +++ b/lib/pages/search/search.dart @@ -20,7 +20,9 @@ import 'package:spotube/pages/search/sections/tracks.dart'; import 'package:spotube/provider/authentication/authentication.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:spotube/services/kv_store/kv_store.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class SearchPage extends HookConsumerWidget { static const name = "search"; diff --git a/lib/pages/settings/about.dart b/lib/pages/settings/about.dart index 79c6692b..0703d4ef 100644 --- a/lib/pages/settings/about.dart +++ b/lib/pages/settings/about.dart @@ -11,15 +11,17 @@ import 'package:spotube/hooks/controllers/use_package_info.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:url_launcher/url_launcher.dart'; +import 'package:auto_route/auto_route.dart'; final _licenseProvider = FutureProvider((ref) async { return await rootBundle.loadString("LICENSE"); }); -class AboutSpotube extends HookConsumerWidget { +@RoutePage() +class AboutSpotubePage extends HookConsumerWidget { static const name = "about"; - const AboutSpotube({super.key}); + const AboutSpotubePage({super.key}); @override Widget build(BuildContext context, ref) { diff --git a/lib/pages/settings/blacklist.dart b/lib/pages/settings/blacklist.dart index b525b1b5..377a6079 100644 --- a/lib/pages/settings/blacklist.dart +++ b/lib/pages/settings/blacklist.dart @@ -11,7 +11,9 @@ import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/components/ui/button_tile.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/blacklist_provider.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class BlackListPage extends HookConsumerWidget { static const name = "blacklist"; diff --git a/lib/pages/settings/logs.dart b/lib/pages/settings/logs.dart index 3a4f7715..4985b57a 100644 --- a/lib/pages/settings/logs.dart +++ b/lib/pages/settings/logs.dart @@ -11,7 +11,9 @@ import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/logs/logs_provider.dart'; import 'package:spotube/services/logger/logger.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class LogsPage extends HookConsumerWidget { static const name = "logs"; diff --git a/lib/pages/settings/sections/about.dart b/lib/pages/settings/sections/about.dart index 7f5d3977..fcdac8a7 100644 --- a/lib/pages/settings/sections/about.dart +++ b/lib/pages/settings/sections/about.dart @@ -1,9 +1,11 @@ +import 'package:auto_route/auto_route.dart'; import 'package:auto_size_text/auto_size_text.dart'; import 'package:flutter/material.dart' show ListTile; -import 'package:go_router/go_router.dart'; + import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart' hide ButtonStyle; import 'package:spotube/collections/env.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/modules/settings/section_card_with_heading.dart'; import 'package:spotube/components/adaptive/adaptive_list_tile.dart'; @@ -88,7 +90,7 @@ class SettingsAboutSection extends HookConsumerWidget { title: Text(context.l10n.about_spotube), trailing: const Icon(SpotubeIcons.angleRight), onTap: () { - GoRouter.of(context).push("/settings/about"); + context.pushRoute(const AboutSpotubeRoute()); }, ) ], diff --git a/lib/pages/settings/sections/accounts.dart b/lib/pages/settings/sections/accounts.dart index 6132776c..95619d30 100644 --- a/lib/pages/settings/sections/accounts.dart +++ b/lib/pages/settings/sections/accounts.dart @@ -1,20 +1,20 @@ +import 'package:auto_route/auto_route.dart'; import 'package:auto_size_text/auto_size_text.dart'; import 'package:flutter/material.dart' show ListTile; -import 'package:go_router/go_router.dart'; + import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/modules/settings/section_card_with_heading.dart'; import 'package:spotube/components/image/universal_image.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/image.dart'; -import 'package:spotube/pages/profile/profile.dart'; import 'package:spotube/pages/mobile_login/hooks/login_callback.dart'; import 'package:spotube/provider/authentication/authentication.dart'; import 'package:spotube/provider/scrobbler/scrobbler.dart'; import 'package:spotube/provider/spotify/spotify.dart'; -import 'package:spotube/utils/service_utils.dart'; class SettingsAccountSection extends HookConsumerWidget { const SettingsAccountSection({super.key}); @@ -22,7 +22,6 @@ class SettingsAccountSection extends HookConsumerWidget { @override Widget build(context, ref) { final theme = Theme.of(context); - final router = GoRouter.of(context); final auth = ref.watch(authenticationProvider); final scrobbler = ref.watch(scrobblerProvider); @@ -50,7 +49,7 @@ class SettingsAccountSection extends HookConsumerWidget { ), ), onTap: () { - ServiceUtils.pushNamed(context, ProfilePage.name); + context.pushRoute(ProfileRoute()); }, ), if (auth.asData?.value == null) @@ -99,7 +98,7 @@ class SettingsAccountSection extends HookConsumerWidget { trailing: Button.destructive( onPressed: () async { ref.read(authenticationProvider.notifier).logout(); - GoRouter.of(context).pop(); + context.maybePop(); }, child: Text(context.l10n.logout), ), @@ -113,7 +112,7 @@ class SettingsAccountSection extends HookConsumerWidget { trailing: Button.secondary( leading: const Icon(SpotubeIcons.lastFm), onPressed: () { - router.push("/lastfm-login"); + context.pushRoute(const LastFMLoginRoute()); }, child: Text(context.l10n.connect), ), diff --git a/lib/pages/settings/sections/developers.dart b/lib/pages/settings/sections/developers.dart index 4d8b8ba1..6afe01c3 100644 --- a/lib/pages/settings/sections/developers.dart +++ b/lib/pages/settings/sections/developers.dart @@ -1,7 +1,9 @@ +import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart' show ListTile; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; + import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/modules/settings/section_card_with_heading.dart'; import 'package:spotube/extensions/context.dart'; @@ -19,7 +21,7 @@ class SettingsDevelopersSection extends HookWidget { title: Text(context.l10n.logs), trailing: const Icon(SpotubeIcons.angleRight), onTap: () { - GoRouter.of(context).push("/settings/logs"); + context.pushRoute(const LogsRoute()); }, ) ], diff --git a/lib/pages/settings/sections/playback.dart b/lib/pages/settings/sections/playback.dart index be3fc15b..9e561655 100644 --- a/lib/pages/settings/sections/playback.dart +++ b/lib/pages/settings/sections/playback.dart @@ -1,12 +1,13 @@ +import 'package:auto_route/auto_route.dart'; import 'package:collection/collection.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart' show ListTile; -import 'package:go_router/go_router.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:piped_client/piped_client.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/models/database/database.dart'; import 'package:spotube/modules/settings/section_card_with_heading.dart'; @@ -267,7 +268,7 @@ class SettingsPlaybackSection extends HookConsumerWidget { title: Text(context.l10n.blacklist), subtitle: Text(context.l10n.blacklist_description), onTap: () { - GoRouter.of(context).push("/settings/blacklist"); + context.pushRoute(const BlackListRoute()); }, trailing: const Icon(SpotubeIcons.angleRight), ), diff --git a/lib/pages/settings/settings.dart b/lib/pages/settings/settings.dart index 54c377eb..53610ae4 100644 --- a/lib/pages/settings/settings.dart +++ b/lib/pages/settings/settings.dart @@ -15,7 +15,9 @@ import 'package:spotube/pages/settings/sections/language_region.dart'; import 'package:spotube/pages/settings/sections/playback.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/utils/platform.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class SettingsPage extends HookConsumerWidget { static const name = "settings"; diff --git a/lib/pages/stats/albums/albums.dart b/lib/pages/stats/albums/albums.dart index eee6694b..807b8049 100644 --- a/lib/pages/stats/albums/albums.dart +++ b/lib/pages/stats/albums/albums.dart @@ -10,7 +10,9 @@ import 'package:spotube/provider/history/top.dart'; import 'package:spotube/provider/history/top/albums.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:very_good_infinite_list/very_good_infinite_list.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class StatsAlbumsPage extends HookConsumerWidget { static const name = "stats_albums"; const StatsAlbumsPage({super.key}); diff --git a/lib/pages/stats/artists/artists.dart b/lib/pages/stats/artists/artists.dart index 3a719725..311faa0c 100644 --- a/lib/pages/stats/artists/artists.dart +++ b/lib/pages/stats/artists/artists.dart @@ -11,7 +11,9 @@ import 'package:spotube/provider/history/top.dart'; import 'package:spotube/provider/history/top/tracks.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:very_good_infinite_list/very_good_infinite_list.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class StatsArtistsPage extends HookConsumerWidget { static const name = "stats_artists"; const StatsArtistsPage({super.key}); diff --git a/lib/pages/stats/fees/fees.dart b/lib/pages/stats/fees/fees.dart index 14f432d6..8a20758d 100644 --- a/lib/pages/stats/fees/fees.dart +++ b/lib/pages/stats/fees/fees.dart @@ -12,7 +12,9 @@ import 'package:spotube/provider/history/top.dart'; import 'package:spotube/provider/history/top/tracks.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:very_good_infinite_list/very_good_infinite_list.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class StatsStreamFeesPage extends HookConsumerWidget { static const name = "stats_stream_fees"; diff --git a/lib/pages/stats/minutes/minutes.dart b/lib/pages/stats/minutes/minutes.dart index 39438b47..df7f5983 100644 --- a/lib/pages/stats/minutes/minutes.dart +++ b/lib/pages/stats/minutes/minutes.dart @@ -10,7 +10,9 @@ import 'package:spotube/provider/history/top.dart'; import 'package:spotube/provider/history/top/tracks.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:very_good_infinite_list/very_good_infinite_list.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class StatsMinutesPage extends HookConsumerWidget { static const name = "stats_minutes"; diff --git a/lib/pages/stats/playlists/playlists.dart b/lib/pages/stats/playlists/playlists.dart index f5d7a285..78c3cd24 100644 --- a/lib/pages/stats/playlists/playlists.dart +++ b/lib/pages/stats/playlists/playlists.dart @@ -10,7 +10,9 @@ import 'package:spotube/provider/history/top.dart'; import 'package:spotube/provider/history/top/playlists.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:very_good_infinite_list/very_good_infinite_list.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class StatsPlaylistsPage extends HookConsumerWidget { static const name = "stats_playlists"; const StatsPlaylistsPage({super.key}); diff --git a/lib/pages/stats/stats.dart b/lib/pages/stats/stats.dart index e543900c..4f0cf95b 100644 --- a/lib/pages/stats/stats.dart +++ b/lib/pages/stats/stats.dart @@ -4,7 +4,9 @@ import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/modules/stats/summary/summary.dart'; import 'package:spotube/modules/stats/top/top.dart'; import 'package:spotube/utils/platform.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class StatsPage extends HookConsumerWidget { static const name = "stats"; diff --git a/lib/pages/stats/streams/streams.dart b/lib/pages/stats/streams/streams.dart index 2c2e0c9b..05e53d7c 100644 --- a/lib/pages/stats/streams/streams.dart +++ b/lib/pages/stats/streams/streams.dart @@ -10,7 +10,9 @@ import 'package:spotube/provider/history/top.dart'; import 'package:spotube/provider/history/top/tracks.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:very_good_infinite_list/very_good_infinite_list.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class StatsStreamsPage extends HookConsumerWidget { static const name = "stats_streams"; diff --git a/lib/pages/track/track.dart b/lib/pages/track/track.dart index 54563bfe..765969be 100644 --- a/lib/pages/track/track.dart +++ b/lib/pages/track/track.dart @@ -1,10 +1,10 @@ import 'dart:ui'; -import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotube/collections/fake.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/heart_button/heart_button.dart'; import 'package:spotube/components/image/universal_image.dart'; @@ -20,14 +20,16 @@ import 'package:spotube/provider/spotify/spotify.dart'; import 'package:spotube/services/audio_player/audio_player.dart'; import 'package:spotube/extensions/constrains.dart'; +import 'package:auto_route/auto_route.dart'; +@RoutePage() class TrackPage extends HookConsumerWidget { static const name = "track"; final String trackId; const TrackPage({ super.key, - required this.trackId, + @PathParam("id") required this.trackId, }); @override @@ -138,9 +140,11 @@ class TrackPage extends HookConsumerWidget { Flexible( child: LinkText( track.album!.name!, - '/album/${track.album!.id}', + AlbumRoute( + id: track.album!.id!, + album: track.album!, + ), push: true, - extra: track.album, ), ), ], diff --git a/lib/utils/service_utils.dart b/lib/utils/service_utils.dart index c89866b4..b55af9e9 100644 --- a/lib/utils/service_utils.dart +++ b/lib/utils/service_utils.dart @@ -1,8 +1,9 @@ import 'dart:typed_data'; +import 'package:auto_route/auto_route.dart'; import 'package:dio/dio.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; -import 'package:go_router/go_router.dart'; + import 'package:html/dom.dart' hide Text; import 'package:shadcn_flutter/shadcn_flutter.dart' hide Element; import 'package:spotify/spotify.dart'; @@ -276,70 +277,6 @@ abstract class ServiceUtils { return subtitle; } - static void navigate(BuildContext context, String location, {Object? extra}) { - if (GoRouterState.of(context).matchedLocation == location) return; - GoRouter.of(context).go(location, extra: extra); - } - - static void navigateNamed( - BuildContext context, - String name, { - Object? extra, - Map? pathParameters, - Map? queryParameters, - }) { - if (GoRouterState.of(context).matchedLocation == name) return; - GoRouter.of(context).goNamed( - name, - pathParameters: pathParameters ?? const {}, - queryParameters: queryParameters ?? const {}, - extra: extra, - ); - } - - static void push(BuildContext context, String location, {Object? extra}) { - final router = GoRouter.of(context); - final routerState = GoRouterState.of(context); - final routerStack = router.routerDelegate.currentConfiguration.matches - .map((e) => e.matchedLocation); - - if (routerState.matchedLocation == location || - routerStack.contains(location)) { - return; - } - router.push(location, extra: extra); - } - - static void pushNamed( - BuildContext context, - String name, { - Object? extra, - Map pathParameters = const {}, - Map queryParameters = const {}, - }) { - final router = GoRouter.of(context); - final routerState = GoRouterState.of(context); - final routerStack = router.routerDelegate.currentConfiguration.matches - .map((e) => e.matchedLocation); - - final nameLocation = routerState.namedLocation( - name, - pathParameters: pathParameters, - queryParameters: queryParameters, - ); - - if (routerState.matchedLocation == nameLocation || - routerStack.contains(nameLocation)) { - return; - } - router.pushNamed( - name, - pathParameters: pathParameters, - queryParameters: queryParameters, - extra: extra, - ); - } - static DateTime parseSpotifyAlbumDate(AlbumSimple? album) { if (album == null || album.releaseDate == null) { return DateTime.parse("1975-01-01"); diff --git a/pubspec.lock b/pubspec.lock index 1e9d9265..8c1bb00d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -142,6 +142,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.1.21" + auto_route: + dependency: "direct main" + description: + name: auto_route + sha256: "1d1bd908a1fec327719326d5d0791edd37f16caff6493c01003689fb03315ad7" + url: "https://pub.dev" + source: hosted + version: "9.3.0+1" + auto_route_generator: + dependency: "direct dev" + description: + name: auto_route_generator + sha256: c9086eb07271e51b44071ad5cff34e889f3156710b964a308c2ab590769e79e6 + url: "https://pub.dev" + source: hosted + version: "9.0.0" auto_size_text: dependency: "direct main" description: @@ -1073,14 +1089,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.2" - go_router: - dependency: "direct main" - description: - name: go_router - sha256: "2fd11229f59e23e967b0775df8d5948a519cd7e1e8b6e849729e010587b46539" - url: "https://pub.dev" - source: hosted - version: "14.6.2" google_fonts: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index ed0d7ce5..8b3c3e7b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -19,6 +19,7 @@ dependencies: audio_service: ^0.18.13 audio_service_mpris: ^0.2.0 audio_session: ^0.1.19 + auto_route: ^9.3.0+1 auto_size_text: ^3.0.0 bonsoir: ^5.1.10 cached_network_image: ^3.3.1 @@ -70,7 +71,6 @@ dependencies: freezed_annotation: ^2.4.1 fuzzywuzzy: ^1.1.6 gap: ^3.0.1 - go_router: ^14.2.7 google_fonts: ^6.2.1 hive: ^2.2.3 hive_flutter: ^1.1.0 @@ -161,6 +161,7 @@ dev_dependencies: xml: ^6.5.0 io: ^1.0.4 drift_dev: ^2.21.0 + auto_route_generator: ^9.0.0 dependency_overrides: bonsoir_android: From 4b2d259add240505dae601289eb5a0c3b3ecbcac Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 31 Jan 2025 22:10:40 +0600 Subject: [PATCH 092/112] chore: use navigateTo instead of pushRoute --- lib/collections/routes.dart | 4 +- lib/collections/side_bar_tiles.dart | 18 +- .../fallbacks/anonymous_fallback.dart | 2 +- lib/components/links/artist_link.dart | 2 +- lib/components/links/link_text.dart | 2 +- lib/components/track_tile/track_options.dart | 4 +- lib/components/track_tile/track_tile.dart | 4 +- lib/hooks/configurators/use_deep_linking.dart | 17 +- lib/modules/album/album_card.dart | 2 +- lib/modules/artist/artist_card.dart | 2 +- lib/modules/connect/connect_device.dart | 8 +- lib/modules/home/sections/feed.dart | 2 +- .../home/sections/friends/friend_item.dart | 8 +- .../home/sections/genres/genre_card.dart | 2 +- .../genres/genre_card_playlist_card.dart | 2 +- lib/modules/home/sections/genres/genres.dart | 2 +- .../local_folder/local_folder_item.dart | 2 +- .../library/user_downloads/download_item.dart | 2 +- lib/modules/player/player.dart | 6 +- lib/modules/player/player_overlay.dart | 7 +- lib/modules/player/player_track_details.dart | 4 +- lib/modules/playlist/playlist_card.dart | 2 +- lib/modules/root/sidebar/sidebar.dart | 4 +- lib/modules/root/sidebar/sidebar_footer.dart | 4 +- lib/modules/root/spotube_navigation_bar.dart | 13 +- lib/modules/stats/common/album_item.dart | 4 +- lib/modules/stats/common/artist_item.dart | 2 +- lib/modules/stats/common/playlist_item.dart | 2 +- lib/modules/stats/common/track_item.dart | 4 +- lib/modules/stats/summary/summary.dart | 12 +- lib/pages/connect/connect.dart | 2 +- lib/pages/connect/control/control.dart | 4 +- lib/pages/home/genres/genres.dart | 2 +- lib/pages/home/home.dart | 2 +- lib/pages/library/library.dart | 69 ++-- .../playlist_generate/playlist_generate.dart | 2 +- lib/pages/library/user_playlists.dart | 2 +- .../mobile_login/hooks/login_callback.dart | 2 +- lib/pages/root/root_app.dart | 30 +- lib/pages/search/search.dart | 298 +++++++++--------- lib/pages/settings/sections/about.dart | 2 +- lib/pages/settings/sections/accounts.dart | 4 +- lib/pages/settings/sections/developers.dart | 2 +- lib/pages/settings/sections/playback.dart | 2 +- lib/pages/stats/stats.dart | 39 ++- 45 files changed, 307 insertions(+), 304 deletions(-) diff --git a/lib/collections/routes.dart b/lib/collections/routes.dart index 367e6eb8..10b2dc0d 100644 --- a/lib/collections/routes.dart +++ b/lib/collections/routes.dart @@ -37,7 +37,7 @@ class AppRouter extends RootStackRouter { initial: true, children: [ AutoRoute( - path: "browse", + path: "home", page: HomeRoute.page, initial: true, ), @@ -70,7 +70,7 @@ class AppRouter extends RootStackRouter { page: UserArtistsRoute.page, ), AutoRoute( - path: "album", + path: "albums", page: UserAlbumsRoute.page, ), AutoRoute( diff --git a/lib/collections/side_bar_tiles.dart b/lib/collections/side_bar_tiles.dart index c74d18c7..44c8b308 100644 --- a/lib/collections/side_bar_tiles.dart +++ b/lib/collections/side_bar_tiles.dart @@ -8,6 +8,7 @@ class SideBarTiles { final IconData icon; final String title; final String id; + final String pathPrefix; final PageRouteInfo route; SideBarTiles({ @@ -15,30 +16,35 @@ class SideBarTiles { required this.title, required this.id, required this.route, + required this.pathPrefix, }); } List getSidebarTileList(AppLocalizations l10n) => [ SideBarTiles( - id: "browse", + id: "home", + pathPrefix: "/home", route: const HomeRoute(), icon: SpotubeIcons.home, title: l10n.browse, ), SideBarTiles( id: "search", + pathPrefix: "/search", route: const SearchRoute(), icon: SpotubeIcons.search, title: l10n.search, ), SideBarTiles( id: "lyrics", + pathPrefix: "/lyrics", route: LyricsRoute(), icon: SpotubeIcons.music, title: l10n.lyrics, ), SideBarTiles( id: "stats", + pathPrefix: "/stats", route: const StatsRoute(), icon: SpotubeIcons.chart, title: l10n.stats, @@ -48,24 +54,28 @@ List getSidebarTileList(AppLocalizations l10n) => [ List getSidebarLibraryTileList(AppLocalizations l10n) => [ SideBarTiles( id: "playlists", + pathPrefix: "/library/playlists", title: l10n.playlists, route: const UserPlaylistsRoute(), icon: SpotubeIcons.playlist, ), SideBarTiles( id: "artists", + pathPrefix: "/library/artists", title: l10n.artists, route: const UserArtistsRoute(), icon: SpotubeIcons.artist, ), SideBarTiles( id: "albums", + pathPrefix: "/library/albums", title: l10n.albums, route: const UserAlbumsRoute(), icon: SpotubeIcons.album, ), SideBarTiles( id: "local_library", + pathPrefix: "/library/local", title: l10n.local_library, route: const UserLocalLibraryRoute(), icon: SpotubeIcons.device, @@ -74,25 +84,29 @@ List getSidebarLibraryTileList(AppLocalizations l10n) => [ List getNavbarTileList(AppLocalizations l10n) => [ SideBarTiles( - id: "browse", + id: "home", + pathPrefix: "/home", route: const HomeRoute(), icon: SpotubeIcons.home, title: l10n.browse, ), SideBarTiles( id: "search", + pathPrefix: "/search", route: const SearchRoute(), icon: SpotubeIcons.search, title: l10n.search, ), SideBarTiles( id: "library", + pathPrefix: "/library", route: const UserPlaylistsRoute(), icon: SpotubeIcons.library, title: l10n.library, ), SideBarTiles( id: "stats", + pathPrefix: "/stats", route: const StatsRoute(), icon: SpotubeIcons.chart, title: l10n.stats, diff --git a/lib/components/fallbacks/anonymous_fallback.dart b/lib/components/fallbacks/anonymous_fallback.dart index 714a0df5..293df932 100644 --- a/lib/components/fallbacks/anonymous_fallback.dart +++ b/lib/components/fallbacks/anonymous_fallback.dart @@ -40,7 +40,7 @@ class AnonymousFallback extends ConsumerWidget { Text(context.l10n.not_logged_in), Button.primary( child: Text(context.l10n.login_with_spotify), - onPressed: () => context.pushRoute(const SettingsRoute()), + onPressed: () => context.navigateTo(const SettingsRoute()), ) ], ), diff --git a/lib/components/links/artist_link.dart b/lib/components/links/artist_link.dart index cdd7f659..9467cb38 100644 --- a/lib/components/links/artist_link.dart +++ b/lib/components/links/artist_link.dart @@ -50,7 +50,7 @@ class ArtistLink extends StatelessWidget { onRouteChange?.call("/artist/${artist.value.id}"); } else { context - .pushRoute(ArtistRoute(artistId: artist.value.id!)); + .navigateTo(ArtistRoute(artistId: artist.value.id!)); } }, overflow: TextOverflow.ellipsis, diff --git a/lib/components/links/link_text.dart b/lib/components/links/link_text.dart index f21aa032..c64ae93d 100644 --- a/lib/components/links/link_text.dart +++ b/lib/components/links/link_text.dart @@ -28,7 +28,7 @@ class LinkText extends StatelessWidget { text, onTap: () { if (push) { - context.pushRoute(route); + context.navigateTo(route); } else { context.navigateTo(route); } diff --git a/lib/components/track_tile/track_options.dart b/lib/components/track_tile/track_options.dart index 66cee95f..b1105c7b 100644 --- a/lib/components/track_tile/track_options.dart +++ b/lib/components/track_tile/track_options.dart @@ -210,7 +210,7 @@ class TrackOptions extends HookConsumerWidget { onSelected: (value) async { switch (value) { case TrackOptionValue.album: - await context.pushRoute( + await context.navigateTo( AlbumRoute(id: track.album!.id!, album: track.album!), ); break; @@ -345,7 +345,7 @@ class TrackOptions extends HookConsumerWidget { alignment: Alignment.centerLeft, child: ArtistLink( artists: track.artists!, - onOverflowArtistClick: () => context.pushRoute( + onOverflowArtistClick: () => context.navigateTo( TrackRoute(trackId: track.id!), ), ), diff --git a/lib/components/track_tile/track_tile.dart b/lib/components/track_tile/track_tile.dart index 71aad728..9bb300f4 100644 --- a/lib/components/track_tile/track_tile.dart +++ b/lib/components/track_tile/track_tile.dart @@ -234,7 +234,7 @@ class TrackTile extends HookConsumerWidget { ), onPressed: () { context - .pushRoute(TrackRoute(trackId: track.id!)); + .navigateTo(TrackRoute(trackId: track.id!)); }, child: Text( track.name!, @@ -284,7 +284,7 @@ class TrackTile extends HookConsumerWidget { child: ArtistLink( artists: track.artists ?? [], onOverflowArtistClick: () { - context.pushRoute( + context.navigateTo( TrackRoute(trackId: track.id!), ); }, diff --git a/lib/hooks/configurators/use_deep_linking.dart b/lib/hooks/configurators/use_deep_linking.dart index 045fe016..67000d49 100644 --- a/lib/hooks/configurators/use_deep_linking.dart +++ b/lib/hooks/configurators/use_deep_linking.dart @@ -28,19 +28,20 @@ void useDeepLinking(WidgetRef ref, AppRouter router) { switch (url.pathSegments.first) { case "album": final album = await spotify.albums.get(url.pathSegments.last); - router.push( + router.navigate( AlbumRoute(id: album.id!, album: album), ); break; case "artist": - router.push(ArtistRoute(artistId: url.pathSegments.last)); + router.navigate(ArtistRoute(artistId: url.pathSegments.last)); break; case "playlist": final playlist = await spotify.playlists.get(url.pathSegments.last); - router.push(PlaylistRoute(id: playlist.id!, playlist: playlist)); + router + .navigate(PlaylistRoute(id: playlist.id!, playlist: playlist)); break; case "track": - router.push(TrackRoute(trackId: url.pathSegments.last)); + router.navigate(TrackRoute(trackId: url.pathSegments.last)); break; default: break; @@ -65,19 +66,19 @@ void useDeepLinking(WidgetRef ref, AppRouter router) { switch (startSegment) { case "spotify:album": final album = await spotify.albums.get(endSegment); - await router.push( + await router.navigate( AlbumRoute(id: album.id!, album: album), ); break; case "spotify:artist": - await router.push(ArtistRoute(artistId: endSegment)); + await router.navigate(ArtistRoute(artistId: endSegment)); break; case "spotify:track": - await router.push(TrackRoute(trackId: endSegment)); + await router.navigate(TrackRoute(trackId: endSegment)); break; case "spotify:playlist": final playlist = await spotify.playlists.get(endSegment); - await router.push( + await router.navigate( PlaylistRoute(id: playlist.id!, playlist: playlist), ); break; diff --git a/lib/modules/album/album_card.dart b/lib/modules/album/album_card.dart index a35bd53d..84106594 100644 --- a/lib/modules/album/album_card.dart +++ b/lib/modules/album/album_card.dart @@ -69,7 +69,7 @@ class AlbumCard extends HookConsumerWidget { "${album.albumType?.formatted} • ${album.artists?.asString() ?? ""}"; void onTap() { - context.pushRoute(AlbumRoute(id: album.id!, album: album)); + context.navigateTo(AlbumRoute(id: album.id!, album: album)); } void onPlaybuttonPressed() async { diff --git a/lib/modules/artist/artist_card.dart b/lib/modules/artist/artist_card.dart index 28ae6315..e53070ef 100644 --- a/lib/modules/artist/artist_card.dart +++ b/lib/modules/artist/artist_card.dart @@ -36,7 +36,7 @@ class ArtistCard extends HookConsumerWidget { width: 180, child: Button.card( onPressed: () { - context.pushRoute(ArtistRoute(artistId: artist.id!)); + context.navigateTo(ArtistRoute(artistId: artist.id!)); }, child: Column( children: [ diff --git a/lib/modules/connect/connect_device.dart b/lib/modules/connect/connect_device.dart index df2539a2..2c8d612b 100644 --- a/lib/modules/connect/connect_device.dart +++ b/lib/modules/connect/connect_device.dart @@ -26,7 +26,7 @@ class ConnectDeviceButton extends HookConsumerWidget { return IconButton.ghost( icon: const Icon(SpotubeIcons.speaker), onPressed: () { - context.pushRoute(const ConnectRoute()); + context.navigateTo(const ConnectRoute()); }, ); } @@ -35,7 +35,7 @@ class ConnectDeviceButton extends HookConsumerWidget { width: double.infinity, child: Button.primary( onPressed: () { - context.pushRoute(const ConnectRoute()); + context.navigateTo(const ConnectRoute()); }, trailing: const Icon(SpotubeIcons.speaker), child: Text( @@ -50,7 +50,7 @@ class ConnectDeviceButton extends HookConsumerWidget { children: [ SecondaryBadge( onPressed: () { - context.pushRoute(const ConnectRoute()); + context.navigateTo(const ConnectRoute()); }, style: const ButtonStyle.secondary(size: ButtonSize(.8)), leading: connectClients.asData?.value.resolvedService != null @@ -70,7 +70,7 @@ class ConnectDeviceButton extends HookConsumerWidget { IconButton.primary( icon: const Icon(SpotubeIcons.speaker), onPressed: () { - context.pushRoute(const ConnectRoute()); + context.navigateTo(const ConnectRoute()); }, ) ], diff --git a/lib/modules/home/sections/feed.dart b/lib/modules/home/sections/feed.dart index e423b08c..d3e363cc 100644 --- a/lib/modules/home/sections/feed.dart +++ b/lib/modules/home/sections/feed.dart @@ -40,7 +40,7 @@ class HomePageFeedSection extends HookConsumerWidget { titleTrailing: Button.text( child: Text(context.l10n.browse_all), onPressed: () { - context.pushRoute(HomeFeedSectionRoute(sectionUri: section.uri)); + context.navigateTo(HomeFeedSectionRoute(sectionUri: section.uri)); }, ), ); diff --git a/lib/modules/home/sections/friends/friend_item.dart b/lib/modules/home/sections/friends/friend_item.dart index 216cc607..8e91ab66 100644 --- a/lib/modules/home/sections/friends/friend_item.dart +++ b/lib/modules/home/sections/friends/friend_item.dart @@ -50,7 +50,7 @@ class FriendItem extends HookConsumerWidget { recognizer: TapGestureRecognizer() ..onTap = () { context - .pushRoute(TrackRoute(trackId: friend.track.id)); + .navigateTo(TrackRoute(trackId: friend.track.id)); }, ), const TextSpan(text: " • "), @@ -64,7 +64,7 @@ class FriendItem extends HookConsumerWidget { text: " ${friend.track.artist.name}", recognizer: TapGestureRecognizer() ..onTap = () { - context.pushRoute( + context.navigateTo( ArtistRoute(artistId: friend.track.artist.id), ); }, @@ -74,7 +74,7 @@ class FriendItem extends HookConsumerWidget { text: friend.track.context.name, recognizer: TapGestureRecognizer() ..onTap = () async { - context.router.pushNamed( + context.router.navigateNamed( "/${friend.track.context.path}", // extra: // !friend.track.context.path.startsWith("album") @@ -98,7 +98,7 @@ class FriendItem extends HookConsumerWidget { final album = await spotify.albums.get(friend.track.album.id); if (context.mounted) { - context.pushRoute( + context.navigateTo( AlbumRoute(id: album.id!, album: album), ); } diff --git a/lib/modules/home/sections/genres/genre_card.dart b/lib/modules/home/sections/genres/genre_card.dart index 8371e553..8133f0db 100644 --- a/lib/modules/home/sections/genres/genre_card.dart +++ b/lib/modules/home/sections/genres/genre_card.dart @@ -76,7 +76,7 @@ class GenreSectionCard extends HookConsumerWidget { ).h3(), Button.link( onPressed: () { - context.router.push( + context.navigateTo( GenrePlaylistsRoute( id: category.id!, category: category, diff --git a/lib/modules/home/sections/genres/genre_card_playlist_card.dart b/lib/modules/home/sections/genres/genre_card_playlist_card.dart index e5770efa..1e1b3b76 100644 --- a/lib/modules/home/sections/genres/genre_card_playlist_card.dart +++ b/lib/modules/home/sections/genres/genre_card_playlist_card.dart @@ -47,7 +47,7 @@ class GenreSectionCardPlaylistCard extends HookConsumerWidget { }, ), onPressed: () { - context.pushRoute( + context.navigateTo( PlaylistRoute(id: playlist.id!, playlist: playlist), ); }, diff --git a/lib/modules/home/sections/genres/genres.dart b/lib/modules/home/sections/genres/genres.dart index 507985c2..dd5512c8 100644 --- a/lib/modules/home/sections/genres/genres.dart +++ b/lib/modules/home/sections/genres/genres.dart @@ -48,7 +48,7 @@ class HomeGenresSection extends HookConsumerWidget { ), Button.link( onPressed: () { - context.pushRoute(const GenreRoute()); + context.navigateTo(const GenreRoute()); }, child: Text( context.l10n.browse_all, diff --git a/lib/modules/library/local_folder/local_folder_item.dart b/lib/modules/library/local_folder/local_folder_item.dart index 15355d8f..78f1aa14 100644 --- a/lib/modules/library/local_folder/local_folder_item.dart +++ b/lib/modules/library/local_folder/local_folder_item.dart @@ -59,7 +59,7 @@ class LocalFolderItem extends HookConsumerWidget { return Button( onPressed: () { - context.pushRoute( + context.navigateTo( LocalLibraryRoute( location: folder, isCache: isCacheFolder, diff --git a/lib/modules/library/user_downloads/download_item.dart b/lib/modules/library/user_downloads/download_item.dart index 11c86810..2c0a96a5 100644 --- a/lib/modules/library/user_downloads/download_item.dart +++ b/lib/modules/library/user_downloads/download_item.dart @@ -67,7 +67,7 @@ class DownloadItem extends HookConsumerWidget { artists: track.artists ?? [], mainAxisAlignment: WrapAlignment.start, onOverflowArtistClick: () { - context.pushRoute(TrackRoute(trackId: track.id!)); + context.navigateTo(TrackRoute(trackId: track.id!)); }, ), trailing: isQueryingSourceInfo diff --git a/lib/modules/player/player.dart b/lib/modules/player/player.dart index 2f43cbee..4335e298 100644 --- a/lib/modules/player/player.dart +++ b/lib/modules/player/player.dart @@ -93,7 +93,7 @@ class PlayerView extends HookConsumerWidget { }, [panelController.isAttached && panelController.isPanelOpen]); return AppPopScope( - canPop: context.watchRouter.canPop(), + canPop: false, onPopInvoked: (didPop) async { await panelController.close(); }, @@ -209,9 +209,9 @@ class PlayerView extends HookConsumerWidget { .copyWith(fontWeight: FontWeight.bold), onRouteChange: (route) { panelController.close(); - context.router.pushNamed(route); + context.router.navigateNamed(route); }, - onOverflowArtistClick: () => context.pushRoute( + onOverflowArtistClick: () => context.navigateTo( TrackRoute(trackId: currentTrack!.id!), ), ), diff --git a/lib/modules/player/player_overlay.dart b/lib/modules/player/player_overlay.dart index a37ac5bc..3c3ff373 100644 --- a/lib/modules/player/player_overlay.dart +++ b/lib/modules/player/player_overlay.dart @@ -1,4 +1,3 @@ -import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:sliding_up_panel/sliding_up_panel.dart'; @@ -8,6 +7,10 @@ import 'package:spotube/modules/root/spotube_navigation_bar.dart'; import 'package:spotube/modules/player/player.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; +final playerOverlayControllerProvider = StateProvider((ref) { + return PanelController(); +}); + class PlayerOverlay extends HookConsumerWidget { final String albumArt; @@ -23,7 +26,7 @@ class PlayerOverlay extends HookConsumerWidget { final screenSize = MediaQuery.sizeOf(context); - final panelController = useMemoized(() => PanelController(), []); + final panelController = ref.watch(playerOverlayControllerProvider); return SlidingUpPanel( maxHeight: screenSize.height, diff --git a/lib/modules/player/player_track_details.dart b/lib/modules/player/player_track_details.dart index 345a19db..2e38bf37 100644 --- a/lib/modules/player/player_track_details.dart +++ b/lib/modules/player/player_track_details.dart @@ -81,10 +81,10 @@ class PlayerTrackDetails extends HookConsumerWidget { ArtistLink( artists: playback.activeTrack?.artists ?? [], onRouteChange: (route) { - context.router.pushNamed(route); + context.router.navigateNamed(route); }, onOverflowArtistClick: () => - context.pushRoute(TrackRoute(trackId: track!.id!)), + context.navigateTo(TrackRoute(trackId: track!.id!)), ) ], ), diff --git a/lib/modules/playlist/playlist_card.dart b/lib/modules/playlist/playlist_card.dart index 1bbcf56f..8f0b5097 100644 --- a/lib/modules/playlist/playlist_card.dart +++ b/lib/modules/playlist/playlist_card.dart @@ -73,7 +73,7 @@ class PlaylistCard extends HookConsumerWidget { } void onTap() { - context.pushRoute(PlaylistRoute(id: playlist.id!, playlist: playlist)); + context.navigateTo(PlaylistRoute(id: playlist.id!, playlist: playlist)); } void onPlaybuttonPressed() async { diff --git a/lib/modules/root/sidebar/sidebar.dart b/lib/modules/root/sidebar/sidebar.dart index 2bfb8687..1149bd00 100644 --- a/lib/modules/root/sidebar/sidebar.dart +++ b/lib/modules/root/sidebar/sidebar.dart @@ -52,12 +52,12 @@ class Sidebar extends HookConsumerWidget { final router = context.watchRouter; final selectedIndex = tileList.indexWhere( - (e) => router.topRoute.name == e.route.routeName, + (e) => router.currentPath.startsWith(e.pathPrefix), ); if (layoutMode == LayoutMode.compact || (mediaQuery.smAndDown && layoutMode == LayoutMode.adaptive)) { - return Scaffold(child: child); + return child; } final navigationButtons = [ diff --git a/lib/modules/root/sidebar/sidebar_footer.dart b/lib/modules/root/sidebar/sidebar_footer.dart index 73916f50..fb3edddd 100644 --- a/lib/modules/root/sidebar/sidebar_footer.dart +++ b/lib/modules/root/sidebar/sidebar_footer.dart @@ -97,7 +97,7 @@ class SidebarFooter extends HookConsumerWidget implements NavigationBarItem { Flexible( child: GestureDetector( onTap: () { - context.pushRoute(const ProfileRoute()); + context.navigateTo(const ProfileRoute()); }, child: Row( children: [ @@ -125,7 +125,7 @@ class SidebarFooter extends HookConsumerWidget implements NavigationBarItem { variance: ButtonVariance.ghost, icon: const Icon(SpotubeIcons.settings), onPressed: () { - context.pushRoute(const SettingsRoute()); + context.navigateTo(const SettingsRoute()); }, ), ], diff --git a/lib/modules/root/spotube_navigation_bar.dart b/lib/modules/root/spotube_navigation_bar.dart index cd717833..9dc02378 100644 --- a/lib/modules/root/spotube_navigation_bar.dart +++ b/lib/modules/root/spotube_navigation_bar.dart @@ -6,7 +6,6 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; -import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/side_bar_tiles.dart'; import 'package:spotube/extensions/constrains.dart'; @@ -35,23 +34,13 @@ class SpotubeNavigationBar extends HookConsumerWidget { [context.l10n], ); - final libraryTiles = useMemoized( - () => getSidebarLibraryTileList(context.l10n) - .map((e) => e.route.routeName) - .toList(), - [context.l10n], - ); - final panelHeight = ref.watch(navigationPanelHeight); final router = context.watchRouter; final selectedIndex = max( 0, navbarTileList.indexWhere( - (e) => - router.topRoute.name == e.route.routeName || - (libraryTiles.contains(router.topRoute.name) && - e.route.routeName == LibraryRoute.name), + (e) => router.currentPath.startsWith(e.pathPrefix), ), ); diff --git a/lib/modules/stats/common/album_item.dart b/lib/modules/stats/common/album_item.dart index 3105eb17..cd0a6caf 100644 --- a/lib/modules/stats/common/album_item.dart +++ b/lib/modules/stats/common/album_item.dart @@ -37,14 +37,14 @@ class StatsAlbumItem extends StatelessWidget { artists: album.artists ?? [], mainAxisAlignment: WrapAlignment.start, onOverflowArtistClick: () => - context.pushRoute(AlbumRoute(id: album.id!, album: album)), + context.navigateTo(AlbumRoute(id: album.id!, album: album)), ), ), ], ), trailing: info, onPressed: () { - context.pushRoute(AlbumRoute(id: album.id!, album: album)); + context.navigateTo(AlbumRoute(id: album.id!, album: album)); }, ); } diff --git a/lib/modules/stats/common/artist_item.dart b/lib/modules/stats/common/artist_item.dart index 13e19777..5eff9a9d 100644 --- a/lib/modules/stats/common/artist_item.dart +++ b/lib/modules/stats/common/artist_item.dart @@ -30,7 +30,7 @@ class StatsArtistItem extends StatelessWidget { ), trailing: info, onPressed: () { - context.pushRoute(ArtistRoute(artistId: artist.id!)); + context.navigateTo(ArtistRoute(artistId: artist.id!)); }, ); } diff --git a/lib/modules/stats/common/playlist_item.dart b/lib/modules/stats/common/playlist_item.dart index 744fef04..58610af1 100644 --- a/lib/modules/stats/common/playlist_item.dart +++ b/lib/modules/stats/common/playlist_item.dart @@ -35,7 +35,7 @@ class StatsPlaylistItem extends StatelessWidget { ), trailing: info, onPressed: () { - context.pushRoute(PlaylistRoute(id: playlist.id!, playlist: playlist)); + context.navigateTo(PlaylistRoute(id: playlist.id!, playlist: playlist)); }, ); } diff --git a/lib/modules/stats/common/track_item.dart b/lib/modules/stats/common/track_item.dart index 640c2b0b..ae2e22c6 100644 --- a/lib/modules/stats/common/track_item.dart +++ b/lib/modules/stats/common/track_item.dart @@ -35,12 +35,12 @@ class StatsTrackItem extends StatelessWidget { artists: track.artists!, mainAxisAlignment: WrapAlignment.start, onOverflowArtistClick: () { - context.pushRoute(TrackRoute(trackId: track.id!)); + context.navigateTo(TrackRoute(trackId: track.id!)); }, ), trailing: info, onPressed: () { - context.pushRoute(TrackRoute(trackId: track.id!)); + context.navigateTo(TrackRoute(trackId: track.id!)); }, ); } diff --git a/lib/modules/stats/summary/summary.dart b/lib/modules/stats/summary/summary.dart index 6966da97..352d9ed3 100644 --- a/lib/modules/stats/summary/summary.dart +++ b/lib/modules/stats/summary/summary.dart @@ -45,7 +45,7 @@ class StatsPageSummarySection extends HookConsumerWidget { description: context.l10n.summary_listened_to_music, color: Colors.indigo, onTap: () { - context.pushRoute(const StatsMinutesRoute()); + context.navigateTo(const StatsMinutesRoute()); }, ), SummaryCard( @@ -54,7 +54,7 @@ class StatsPageSummarySection extends HookConsumerWidget { description: context.l10n.summary_streamed_overall, color: Colors.blue, onTap: () { - context.pushRoute(const StatsStreamsRoute()); + context.navigateTo(const StatsStreamsRoute()); }, ), SummaryCard.unformatted( @@ -63,7 +63,7 @@ class StatsPageSummarySection extends HookConsumerWidget { description: context.l10n.summary_owed_to_artists, color: Colors.green, onTap: () { - context.pushRoute(const StatsStreamsRoute()); + context.navigateTo(const StatsStreamsRoute()); }, ), SummaryCard( @@ -72,7 +72,7 @@ class StatsPageSummarySection extends HookConsumerWidget { description: context.l10n.summary_music_reached_you, color: Colors.yellow, onTap: () { - context.pushRoute(const StatsArtistsRoute()); + context.navigateTo(const StatsArtistsRoute()); }, ), SummaryCard( @@ -81,7 +81,7 @@ class StatsPageSummarySection extends HookConsumerWidget { description: context.l10n.summary_got_your_love, color: Colors.pink, onTap: () { - context.pushRoute(const StatsAlbumsRoute()); + context.navigateTo(const StatsAlbumsRoute()); }, ), SummaryCard( @@ -90,7 +90,7 @@ class StatsPageSummarySection extends HookConsumerWidget { description: context.l10n.summary_were_on_repeat, color: Colors.teal, onTap: () { - context.pushRoute(const StatsPlaylistsRoute()); + context.navigateTo(const StatsPlaylistsRoute()); }, ), ]), diff --git a/lib/pages/connect/connect.dart b/lib/pages/connect/connect.dart index 20b6d0da..d394ba16 100644 --- a/lib/pages/connect/connect.dart +++ b/lib/pages/connect/connect.dart @@ -72,7 +72,7 @@ class ConnectPage extends HookConsumerWidget { : null, onPressed: () { if (selected) { - context.pushRoute(const ConnectControlRoute()); + context.navigateTo(const ConnectControlRoute()); } else { connectClientsNotifier.resolveService(device); } diff --git a/lib/pages/connect/control/control.dart b/lib/pages/connect/control/control.dart index 504d670c..d0b423a6 100644 --- a/lib/pages/connect/control/control.dart +++ b/lib/pages/connect/control/control.dart @@ -115,7 +115,7 @@ class ConnectControlPage extends HookConsumerWidget { style: typography.h4, onTap: () { if (playlist.activeTrack == null) return; - context.pushRoute( + context.navigateTo( TrackRoute( trackId: playlist.activeTrack!.id!), ); @@ -127,7 +127,7 @@ class ConnectControlPage extends HookConsumerWidget { artists: playlist.activeTrack?.artists ?? [], textStyle: typography.normal, mainAxisAlignment: WrapAlignment.start, - onOverflowArtistClick: () => context.pushRoute( + onOverflowArtistClick: () => context.navigateTo( TrackRoute(trackId: playlist.activeTrack!.id!), ), ), diff --git a/lib/pages/home/genres/genres.dart b/lib/pages/home/genres/genres.dart index 1bdb3782..eaddeae6 100644 --- a/lib/pages/home/genres/genres.dart +++ b/lib/pages/home/genres/genres.dart @@ -51,7 +51,7 @@ class GenrePage extends HookConsumerWidget { final gradient = gradients[Random().nextInt(gradients.length)]; return CardImage( onPressed: () { - context.pushRoute( + context.navigateTo( GenrePlaylistsRoute( id: category.id!, category: category, diff --git a/lib/pages/home/home.dart b/lib/pages/home/home.dart index 9bcba29e..cd3ed273 100644 --- a/lib/pages/home/home.dart +++ b/lib/pages/home/home.dart @@ -54,7 +54,7 @@ class HomePage extends HookConsumerWidget { IconButton.ghost( icon: const Icon(SpotubeIcons.settings, size: 20), onPressed: () { - context.pushRoute(const SettingsRoute()); + context.navigateTo(const SettingsRoute()); }, ), const Gap(10), diff --git a/lib/pages/library/library.dart b/lib/pages/library/library.dart index 91353aed..be1d04ce 100644 --- a/lib/pages/library/library.dart +++ b/lib/pages/library/library.dart @@ -24,6 +24,7 @@ class LibraryPage extends HookConsumerWidget { ...getSidebarLibraryTileList(context.l10n), SideBarTiles( id: "downloads", + pathPrefix: "library/downloads", title: context.l10n.downloads, route: const UserDownloadsRoute(), icon: SpotubeIcons.download, @@ -32,42 +33,48 @@ class LibraryPage extends HookConsumerWidget { [context.l10n], ); final index = sidebarLibraryTileList.indexWhere( - (e) => router.topRoute.name == e.route.routeName, + (e) => router.currentPath.startsWith(e.pathPrefix), ); - return SafeArea( - bottom: false, - child: LayoutBuilder(builder: (context, constraints) { - return Scaffold( - headers: [ - if (constraints.smAndDown) - TitleBar( - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: TabList( - index: index, - children: [ - for (final tile in sidebarLibraryTileList) - TabButton( - child: Badge( - isLabelVisible: - tile.id == 'downloads' && downloadingCount > 0, - label: Text(downloadingCount.toString()), - child: Text(tile.title), + return PopScope( + canPop: false, + onPopInvokedWithResult: (didPop, result) { + context.navigateTo(const HomeRoute()); + }, + child: SafeArea( + bottom: false, + child: LayoutBuilder(builder: (context, constraints) { + return Scaffold( + headers: [ + if (constraints.smAndDown) + TitleBar( + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: TabList( + index: index, + children: [ + for (final tile in sidebarLibraryTileList) + TabButton( + child: Badge( + isLabelVisible: tile.id == 'downloads' && + downloadingCount > 0, + label: Text(downloadingCount.toString()), + child: Text(tile.title), + ), + onPressed: () { + context.navigateTo(tile.route); + }, ), - onPressed: () { - context.navigateTo(tile.route); - }, - ), - ], + ], + ), ), ), - ), - const Gap(10), - ], - child: const AutoRouter(), - ); - }), + const Gap(10), + ], + child: const AutoRouter(), + ); + }), + ), ); } } diff --git a/lib/pages/library/playlist_generate/playlist_generate.dart b/lib/pages/library/playlist_generate/playlist_generate.dart index 29bfb360..1bc96a29 100644 --- a/lib/pages/library/playlist_generate/playlist_generate.dart +++ b/lib/pages/library/playlist_generate/playlist_generate.dart @@ -663,7 +663,7 @@ class PlaylistGeneratorPage extends HookConsumerWidget { min: min.value, target: target.value, ); - context.pushRoute( + context.navigateTo( PlaylistGenerateResultRoute( state: routeState, ), diff --git a/lib/pages/library/user_playlists.dart b/lib/pages/library/user_playlists.dart index 76a01e18..6ac3bac0 100644 --- a/lib/pages/library/user_playlists.dart +++ b/lib/pages/library/user_playlists.dart @@ -114,7 +114,7 @@ class UserPlaylistsPage extends HookConsumerWidget { leading: const Icon(SpotubeIcons.magic), child: Text(context.l10n.generate), onPressed: () { - context.pushRoute(const PlaylistGeneratorRoute()); + context.navigateTo(const PlaylistGeneratorRoute()); }, ), const Gap(10), diff --git a/lib/pages/mobile_login/hooks/login_callback.dart b/lib/pages/mobile_login/hooks/login_callback.dart index af08b9f9..986b7f4a 100644 --- a/lib/pages/mobile_login/hooks/login_callback.dart +++ b/lib/pages/mobile_login/hooks/login_callback.dart @@ -21,7 +21,7 @@ Future Function() useLoginCallback(WidgetRef ref) { return useCallback(() async { if (kIsMobile || kIsMacOS) { - context.pushRoute(const WebViewLoginRoute()); + context.navigateTo(const WebViewLoginRoute()); return; } diff --git a/lib/pages/root/root_app.dart b/lib/pages/root/root_app.dart index e5f0917b..43e8fdcb 100644 --- a/lib/pages/root/root_app.dart +++ b/lib/pages/root/root_app.dart @@ -3,18 +3,13 @@ import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; -import 'package:spotube/collections/routes.gr.dart'; -import 'package:spotube/collections/side_bar_tiles.dart'; -import 'package:spotube/components/framework/app_pop_scope.dart'; import 'package:spotube/modules/root/bottom_player.dart'; import 'package:spotube/modules/root/sidebar/sidebar.dart'; import 'package:spotube/modules/root/spotube_navigation_bar.dart'; -import 'package:spotube/extensions/context.dart'; import 'package:spotube/hooks/configurators/use_endless_playback.dart'; import 'package:spotube/modules/root/use_downloader_dialogs.dart'; import 'package:spotube/modules/root/use_global_subscriptions.dart'; import 'package:spotube/provider/glance/glance.dart'; -import 'package:spotube/utils/platform.dart'; @RoutePage() class RootAppPage extends HookConsumerWidget { @@ -42,10 +37,6 @@ class RootAppPage extends HookConsumerWidget { return null; }, [backgroundColor, brightness]); - final navTileNames = useMemoized(() { - return getSidebarTileList(context.l10n).map((s) => s.route).toList(); - }, []); - final scaffold = MediaQuery.removeViewInsets( context: context, removeBottom: true, @@ -59,25 +50,6 @@ class RootAppPage extends HookConsumerWidget { ), ); - if (!kIsAndroid) { - return scaffold; - } - - final topRoute = context.router.topRoute; - final canPop = navTileNames.any((name) => name.routeName == topRoute.name); - - return AppPopScope( - canPop: canPop, - onPopInvoked: (didPop) { - if (didPop) return; - - if (topRoute.path == const HomeRoute().fragment) { - SystemNavigator.pop(); - } else { - context.navigateTo(const HomeRoute()); - } - }, - child: scaffold, - ); + return scaffold; } } diff --git a/lib/pages/search/search.dart b/lib/pages/search/search.dart index 2a69b057..d82b3153 100644 --- a/lib/pages/search/search.dart +++ b/lib/pages/search/search.dart @@ -6,6 +6,7 @@ import 'package:spotify/spotify.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:fuzzywuzzy/fuzzywuzzy.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/inter_scrollbar/inter_scrollbar.dart'; @@ -68,165 +69,174 @@ class SearchPage extends HookConsumerWidget { ); } - return SafeArea( - bottom: false, - child: Scaffold( - headers: [ - if (kTitlebarVisible) - const TitleBar(automaticallyImplyLeading: true, height: 30) - ], - child: auth.asData?.value == null - ? const AnonymousFallback() - : Column( - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - child: Padding( - padding: const EdgeInsets.all(20), - child: ListenableBuilder( - listenable: controller, - builder: (context, _) { - final suggestions = controller.text.isEmpty - ? KVStoreService.recentSearches - : KVStoreService.recentSearches - .where( - (s) => - weightedRatio( - s.toLowerCase(), - controller.text.toLowerCase(), - ) > - 50, - ) - .toList(); + return PopScope( + canPop: false, + onPopInvokedWithResult: (didPop, result) { + context.navigateTo(const HomeRoute()); + }, + child: SafeArea( + bottom: false, + child: Scaffold( + headers: [ + if (kTitlebarVisible) + const TitleBar(automaticallyImplyLeading: true, height: 30) + ], + child: auth.asData?.value == null + ? const AnonymousFallback() + : Column( + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.all(20), + child: ListenableBuilder( + listenable: controller, + builder: (context, _) { + final suggestions = controller.text.isEmpty + ? KVStoreService.recentSearches + : KVStoreService.recentSearches + .where( + (s) => + weightedRatio( + s.toLowerCase(), + controller.text.toLowerCase(), + ) > + 50, + ) + .toList(); - return KeyboardListener( - focusNode: focusNode, - autofocus: true, - onKeyEvent: (value) { - final isEnter = value.logicalKey == - LogicalKeyboardKey.enter; - - if (isEnter) { - onSubmitted(controller.text); - focusNode.unfocus(); - } - }, - child: AutoComplete( + return KeyboardListener( + focusNode: focusNode, autofocus: true, - controller: controller, - suggestions: suggestions, - leading: const Icon(SpotubeIcons.search), - textInputAction: TextInputAction.search, - placeholder: Text(context.l10n.search), - trailing: AnimatedCrossFade( - duration: - const Duration(milliseconds: 300), - crossFadeState: controller.text.isNotEmpty - ? CrossFadeState.showFirst - : CrossFadeState.showSecond, - firstChild: IconButton.ghost( - size: ButtonSize.small, - icon: const Icon(SpotubeIcons.close), - onPressed: () { - controller.clear(); - }, - ), - secondChild: - const SizedBox.square(dimension: 28), - ), - onAcceptSuggestion: (index) { - controller.text = - KVStoreService.recentSearches[index]; - ref - .read(searchTermStateProvider - .notifier) - .state = - KVStoreService.recentSearches[index]; + onKeyEvent: (value) { + final isEnter = value.logicalKey == + LogicalKeyboardKey.enter; + + if (isEnter) { + onSubmitted(controller.text); + focusNode.unfocus(); + } }, - onChanged: (value) {}, - onSubmitted: onSubmitted, - ), - ); - }), - ), - ), - ], - ), - Expanded( - child: AnimatedSwitcher( - duration: const Duration(milliseconds: 300), - child: switch ((searchTerm.isEmpty, isFetching)) { - (true, false) => Column( - children: [ - SizedBox( - height: mediaQuery.height * 0.2, - ), - Undraw( - illustration: UndrawIllustration.explore, - color: theme.colorScheme.primary, - height: 200 * theme.scaling, - ), - const SizedBox(height: 20), - Text(context.l10n.search_to_get_results).large(), - ], + child: AutoComplete( + autofocus: true, + controller: controller, + suggestions: suggestions, + leading: const Icon(SpotubeIcons.search), + textInputAction: TextInputAction.search, + placeholder: Text(context.l10n.search), + trailing: AnimatedCrossFade( + duration: + const Duration(milliseconds: 300), + crossFadeState: + controller.text.isNotEmpty + ? CrossFadeState.showFirst + : CrossFadeState.showSecond, + firstChild: IconButton.ghost( + size: ButtonSize.small, + icon: const Icon(SpotubeIcons.close), + onPressed: () { + controller.clear(); + }, + ), + secondChild: const SizedBox.square( + dimension: 28), + ), + onAcceptSuggestion: (index) { + controller.text = KVStoreService + .recentSearches[index]; + ref + .read(searchTermStateProvider + .notifier) + .state = + KVStoreService + .recentSearches[index]; + }, + onChanged: (value) {}, + onSubmitted: onSubmitted, + ), + ); + }), ), - (false, true) => Container( - constraints: BoxConstraints( - maxWidth: mediaQuery.lgAndUp - ? mediaQuery.width * 0.5 - : mediaQuery.width, - ), - padding: const EdgeInsets.symmetric( - horizontal: 20, - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, + ), + ], + ), + Expanded( + child: AnimatedSwitcher( + duration: const Duration(milliseconds: 300), + child: switch ((searchTerm.isEmpty, isFetching)) { + (true, false) => Column( children: [ - Text( - context.l10n.crunching_results, - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.w900, - color: theme.colorScheme.foreground - .withOpacity(0.7), - ), + SizedBox( + height: mediaQuery.height * 0.2, + ), + Undraw( + illustration: UndrawIllustration.explore, + color: theme.colorScheme.primary, + height: 200 * theme.scaling, ), const SizedBox(height: 20), - const LinearProgressIndicator(), + Text(context.l10n.search_to_get_results) + .large(), ], ), - ), - _ => InterScrollbar( - controller: scrollController, - child: SingleChildScrollView( + (false, true) => Container( + constraints: BoxConstraints( + maxWidth: mediaQuery.lgAndUp + ? mediaQuery.width * 0.5 + : mediaQuery.width, + ), + padding: const EdgeInsets.symmetric( + horizontal: 20, + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + context.l10n.crunching_results, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.w900, + color: theme.colorScheme.foreground + .withOpacity(0.7), + ), + ), + const SizedBox(height: 20), + const LinearProgressIndicator(), + ], + ), + ), + _ => InterScrollbar( controller: scrollController, - child: const Padding( - padding: EdgeInsets.symmetric(vertical: 8), - child: SafeArea( - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - SearchTracksSection(), - SearchPlaylistsSection(), - Gap(20), - SearchArtistsSection(), - Gap(20), - SearchAlbumsSection(), - ], + child: SingleChildScrollView( + controller: scrollController, + child: const Padding( + padding: EdgeInsets.symmetric(vertical: 8), + child: SafeArea( + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + SearchTracksSection(), + SearchPlaylistsSection(), + Gap(20), + SearchArtistsSection(), + Gap(20), + SearchAlbumsSection(), + ], + ), ), ), ), ), - ), - }, + }, + ), ), - ), - ], - ), + ], + ), + ), ), ); } diff --git a/lib/pages/settings/sections/about.dart b/lib/pages/settings/sections/about.dart index fcdac8a7..82c98e90 100644 --- a/lib/pages/settings/sections/about.dart +++ b/lib/pages/settings/sections/about.dart @@ -90,7 +90,7 @@ class SettingsAboutSection extends HookConsumerWidget { title: Text(context.l10n.about_spotube), trailing: const Icon(SpotubeIcons.angleRight), onTap: () { - context.pushRoute(const AboutSpotubeRoute()); + context.navigateTo(const AboutSpotubeRoute()); }, ) ], diff --git a/lib/pages/settings/sections/accounts.dart b/lib/pages/settings/sections/accounts.dart index 95619d30..5e40b9ec 100644 --- a/lib/pages/settings/sections/accounts.dart +++ b/lib/pages/settings/sections/accounts.dart @@ -49,7 +49,7 @@ class SettingsAccountSection extends HookConsumerWidget { ), ), onTap: () { - context.pushRoute(ProfileRoute()); + context.navigateTo(ProfileRoute()); }, ), if (auth.asData?.value == null) @@ -112,7 +112,7 @@ class SettingsAccountSection extends HookConsumerWidget { trailing: Button.secondary( leading: const Icon(SpotubeIcons.lastFm), onPressed: () { - context.pushRoute(const LastFMLoginRoute()); + context.navigateTo(const LastFMLoginRoute()); }, child: Text(context.l10n.connect), ), diff --git a/lib/pages/settings/sections/developers.dart b/lib/pages/settings/sections/developers.dart index 6afe01c3..0862e023 100644 --- a/lib/pages/settings/sections/developers.dart +++ b/lib/pages/settings/sections/developers.dart @@ -21,7 +21,7 @@ class SettingsDevelopersSection extends HookWidget { title: Text(context.l10n.logs), trailing: const Icon(SpotubeIcons.angleRight), onTap: () { - context.pushRoute(const LogsRoute()); + context.navigateTo(const LogsRoute()); }, ) ], diff --git a/lib/pages/settings/sections/playback.dart b/lib/pages/settings/sections/playback.dart index 9e561655..537156d0 100644 --- a/lib/pages/settings/sections/playback.dart +++ b/lib/pages/settings/sections/playback.dart @@ -268,7 +268,7 @@ class SettingsPlaybackSection extends HookConsumerWidget { title: Text(context.l10n.blacklist), subtitle: Text(context.l10n.blacklist_description), onTap: () { - context.pushRoute(const BlackListRoute()); + context.navigateTo(const BlackListRoute()); }, trailing: const Icon(SpotubeIcons.angleRight), ), diff --git a/lib/pages/stats/stats.dart b/lib/pages/stats/stats.dart index 4f0cf95b..1a2a86a1 100644 --- a/lib/pages/stats/stats.dart +++ b/lib/pages/stats/stats.dart @@ -1,5 +1,6 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:spotube/collections/routes.gr.dart'; import 'package:spotube/components/titlebar/titlebar.dart'; import 'package:spotube/modules/stats/summary/summary.dart'; import 'package:spotube/modules/stats/top/top.dart'; @@ -14,23 +15,29 @@ class StatsPage extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - return SafeArea( - bottom: false, - child: Scaffold( - headers: [ - if (kTitlebarVisible) const TitleBar(), - ], - child: CustomScrollView( - slivers: [ - if (kIsMacOS) const SliverGap(20), - const StatsPageSummarySection(), - const StatsPageTopSection(), - const SliverToBoxAdapter( - child: SafeArea( - child: SizedBox(), - ), - ) + return PopScope( + canPop: false, + onPopInvokedWithResult: (didPop, result) { + context.navigateTo(const HomeRoute()); + }, + child: SafeArea( + bottom: false, + child: Scaffold( + headers: [ + if (kTitlebarVisible) const TitleBar(), ], + child: CustomScrollView( + slivers: [ + if (kIsMacOS) const SliverGap(20), + const StatsPageSummarySection(), + const StatsPageTopSection(), + const SliverToBoxAdapter( + child: SafeArea( + child: SizedBox(), + ), + ) + ], + ), ), ), ); From 6ddf6b9cce01bd14e7b8122b2e9e08f07615bdfd Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 31 Jan 2025 22:37:10 +0600 Subject: [PATCH 093/112] fix: remove automaticallyImplyLeading from root tabs --- lib/pages/library/library.dart | 1 + lib/pages/library/user_albums.dart | 1 + lib/pages/library/user_artists.dart | 1 + lib/pages/library/user_playlists.dart | 1 + lib/pages/search/search.dart | 2 +- lib/pages/stats/stats.dart | 3 ++- 6 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/pages/library/library.dart b/lib/pages/library/library.dart index be1d04ce..359cc609 100644 --- a/lib/pages/library/library.dart +++ b/lib/pages/library/library.dart @@ -48,6 +48,7 @@ class LibraryPage extends HookConsumerWidget { headers: [ if (constraints.smAndDown) TitleBar( + automaticallyImplyLeading: false, child: SingleChildScrollView( scrollDirection: Axis.horizontal, child: TabList( diff --git a/lib/pages/library/user_albums.dart b/lib/pages/library/user_albums.dart index e11c6c8b..99cee135 100644 --- a/lib/pages/library/user_albums.dart +++ b/lib/pages/library/user_albums.dart @@ -65,6 +65,7 @@ class UserAlbumsPage extends HookConsumerWidget { controller: controller, slivers: [ SliverAppBar( + automaticallyImplyLeading: false, backgroundColor: Theme.of(context).colorScheme.background, floating: true, flexibleSpace: Padding( diff --git a/lib/pages/library/user_artists.dart b/lib/pages/library/user_artists.dart index f55f4587..c8c1dda8 100644 --- a/lib/pages/library/user_artists.dart +++ b/lib/pages/library/user_artists.dart @@ -72,6 +72,7 @@ class UserArtistsPage extends HookConsumerWidget { controller: controller, slivers: [ SliverAppBar( + automaticallyImplyLeading: false, backgroundColor: Theme.of(context).colorScheme.background, floating: true, flexibleSpace: SizedBox( diff --git a/lib/pages/library/user_playlists.dart b/lib/pages/library/user_playlists.dart index 6ac3bac0..6b92f8ea 100644 --- a/lib/pages/library/user_playlists.dart +++ b/lib/pages/library/user_playlists.dart @@ -91,6 +91,7 @@ class UserPlaylistsPage extends HookConsumerWidget { controller: controller, slivers: [ SliverAppBar( + automaticallyImplyLeading: false, floating: true, backgroundColor: context.theme.colorScheme.background, flexibleSpace: Container( diff --git a/lib/pages/search/search.dart b/lib/pages/search/search.dart index d82b3153..1555c062 100644 --- a/lib/pages/search/search.dart +++ b/lib/pages/search/search.dart @@ -79,7 +79,7 @@ class SearchPage extends HookConsumerWidget { child: Scaffold( headers: [ if (kTitlebarVisible) - const TitleBar(automaticallyImplyLeading: true, height: 30) + const TitleBar(automaticallyImplyLeading: false, height: 30) ], child: auth.asData?.value == null ? const AnonymousFallback() diff --git a/lib/pages/stats/stats.dart b/lib/pages/stats/stats.dart index 1a2a86a1..da7c64f3 100644 --- a/lib/pages/stats/stats.dart +++ b/lib/pages/stats/stats.dart @@ -24,7 +24,8 @@ class StatsPage extends HookConsumerWidget { bottom: false, child: Scaffold( headers: [ - if (kTitlebarVisible) const TitleBar(), + if (kTitlebarVisible) + const TitleBar(automaticallyImplyLeading: false), ], child: CustomScrollView( slivers: [ From d4504722d82374f4c21f59372af122d703b106fd Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 31 Jan 2025 23:07:37 +0600 Subject: [PATCH 094/112] fix(android): back button and safe area issues --- lib/components/titlebar/titlebar.dart | 13 +- lib/pages/connect/connect.dart | 114 +-- lib/pages/connect/control/control.dart | 1 - lib/pages/home/feed/feed_section.dart | 123 +-- lib/pages/home/genres/genre_playlists.dart | 165 ++-- lib/pages/home/genres/genres.dart | 1 - lib/pages/lastfm_login/lastfm_login.dart | 183 ++-- .../playlist_generate/playlist_generate.dart | 824 +++++++++--------- .../playlist_generate_result.dart | 403 ++++----- lib/pages/mobile_login/mobile_login.dart | 89 +- lib/pages/profile/profile.dart | 1 - lib/pages/settings/about.dart | 301 +++---- lib/pages/settings/blacklist.dart | 88 +- lib/pages/settings/settings.dart | 1 - lib/pages/stats/albums/albums.dart | 52 +- lib/pages/stats/artists/artists.dart | 52 +- lib/pages/stats/fees/fees.dart | 148 ++-- lib/pages/stats/minutes/minutes.dart | 58 +- lib/pages/stats/playlists/playlists.dart | 57 +- lib/pages/stats/streams/streams.dart | 58 +- lib/pages/track/track.dart | 343 ++++---- 21 files changed, 1559 insertions(+), 1516 deletions(-) diff --git a/lib/components/titlebar/titlebar.dart b/lib/components/titlebar/titlebar.dart index 5b86f6ad..778f0b09 100644 --- a/lib/components/titlebar/titlebar.dart +++ b/lib/components/titlebar/titlebar.dart @@ -1,3 +1,4 @@ +import 'package:auto_route/auto_route.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; @@ -73,6 +74,10 @@ class TitleBar extends HookConsumerWidget implements PreferredSizeWidget { final hasFullscreen = MediaQuery.sizeOf(context).width == constraints.maxWidth; + final canPop = leading.isEmpty && + automaticallyImplyLeading && + (Navigator.canPop(context) || context.watchRouter.canPop()); + return GestureDetector( onHorizontalDragStart: (_) => onDrag(ref), onVerticalDragStart: (_) => onDrag(ref), @@ -94,13 +99,7 @@ class TitleBar extends HookConsumerWidget implements PreferredSizeWidget { } }, child: AppBar( - leading: leading.isEmpty && - automaticallyImplyLeading && - Navigator.canPop(context) - ? [ - const BackButton(), - ] - : leading, + leading: canPop ? [const BackButton()] : leading, trailing: [ ...trailing, Align( diff --git a/lib/pages/connect/connect.dart b/lib/pages/connect/connect.dart index d394ba16..bb8bbfae 100644 --- a/lib/pages/connect/connect.dart +++ b/lib/pages/connect/connect.dart @@ -23,65 +23,65 @@ class ConnectPage extends HookConsumerWidget { final connectClientsNotifier = ref.read(connectClientsProvider.notifier); final discoveredDevices = connectClients.asData?.value.services; - return Scaffold( - headers: [ - TitleBar( - automaticallyImplyLeading: true, - title: Text(context.l10n.devices), - ) - ], - child: Padding( - padding: const EdgeInsets.all(10.0), - child: CustomScrollView( - slivers: [ - SliverPadding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - sliver: SliverToBoxAdapter( - child: Text( - context.l10n.remote, - style: typography.bold, + return SafeArea( + bottom: false, + child: Scaffold( + headers: [ + TitleBar(title: Text(context.l10n.devices)), + ], + child: Padding( + padding: const EdgeInsets.all(10.0), + child: CustomScrollView( + slivers: [ + SliverPadding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + sliver: SliverToBoxAdapter( + child: Text( + context.l10n.remote, + style: typography.bold, + ), ), ), - ), - const SliverGap(10), - SliverList.separated( - itemCount: discoveredDevices?.length ?? 0, - separatorBuilder: (context, index) => const Gap(10), - itemBuilder: (context, index) { - final device = discoveredDevices![index]; - final selected = - connectClients.asData?.value.resolvedService?.name == - device.name; - return ButtonTile( - selected: selected, - leading: const Icon(SpotubeIcons.monitor), - title: Text(device.name), - subtitle: selected - ? Text( - "${connectClients.asData?.value.resolvedService?.host}" - ":${connectClients.asData?.value.resolvedService?.port}", - ) - : null, - trailing: selected - ? IconButton.outline( - icon: const Icon(SpotubeIcons.power), - size: ButtonSize.small, - onPressed: () => - connectClientsNotifier.clearResolvedService(), - ) - : null, - onPressed: () { - if (selected) { - context.navigateTo(const ConnectControlRoute()); - } else { - connectClientsNotifier.resolveService(device); - } - }, - ); - }, - ), - const ConnectPageLocalDevices(), - ], + const SliverGap(10), + SliverList.separated( + itemCount: discoveredDevices?.length ?? 0, + separatorBuilder: (context, index) => const Gap(10), + itemBuilder: (context, index) { + final device = discoveredDevices![index]; + final selected = + connectClients.asData?.value.resolvedService?.name == + device.name; + return ButtonTile( + selected: selected, + leading: const Icon(SpotubeIcons.monitor), + title: Text(device.name), + subtitle: selected + ? Text( + "${connectClients.asData?.value.resolvedService?.host}" + ":${connectClients.asData?.value.resolvedService?.port}", + ) + : null, + trailing: selected + ? IconButton.outline( + icon: const Icon(SpotubeIcons.power), + size: ButtonSize.small, + onPressed: () => + connectClientsNotifier.clearResolvedService(), + ) + : null, + onPressed: () { + if (selected) { + context.navigateTo(const ConnectControlRoute()); + } else { + connectClientsNotifier.resolveService(device); + } + }, + ); + }, + ), + const ConnectPageLocalDevices(), + ], + ), ), ), ); diff --git a/lib/pages/connect/control/control.dart b/lib/pages/connect/control/control.dart index d0b423a6..2511809c 100644 --- a/lib/pages/connect/control/control.dart +++ b/lib/pages/connect/control/control.dart @@ -75,7 +75,6 @@ class ConnectControlPage extends HookConsumerWidget { headers: [ TitleBar( title: Text(resolvedService!.name), - automaticallyImplyLeading: true, ) ], child: LayoutBuilder(builder: (context, constrains) { diff --git a/lib/pages/home/feed/feed_section.dart b/lib/pages/home/feed/feed_section.dart index eff70808..2b38d0ed 100644 --- a/lib/pages/home/feed/feed_section.dart +++ b/lib/pages/home/feed/feed_section.dart @@ -28,68 +28,71 @@ class HomeFeedSectionPage extends HookConsumerWidget { final controller = useScrollController(); final isArtist = section.items.every((item) => item.artist != null); - return Skeletonizer( - enabled: homeFeedSection.isLoading, - child: Scaffold( - headers: [ - TitleBar( - title: Text(section.title ?? ""), - automaticallyImplyLeading: true, - ) - ], - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: CustomScrollView( - controller: controller, - slivers: [ - if (isArtist) - SliverGrid.builder( - gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( - maxCrossAxisExtent: 200, - mainAxisExtent: 250, - crossAxisSpacing: 8, - mainAxisSpacing: 8, + return SafeArea( + bottom: false, + child: Skeletonizer( + enabled: homeFeedSection.isLoading, + child: Scaffold( + headers: [ + TitleBar( + title: Text(section.title ?? ""), + ) + ], + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: CustomScrollView( + controller: controller, + slivers: [ + if (isArtist) + SliverGrid.builder( + gridDelegate: + const SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: 200, + mainAxisExtent: 250, + crossAxisSpacing: 8, + mainAxisSpacing: 8, + ), + itemCount: section.items.length, + itemBuilder: (context, index) { + final item = section.items[index]; + return ArtistCard(item.artist!.asArtist); + }, + ) + else + PlaybuttonView( + controller: controller, + itemCount: section.items.length, + hasMore: false, + isLoading: false, + onRequestMore: () => {}, + listItemBuilder: (context, index) { + final item = section.items[index]; + if (item.album != null) { + return AlbumCard.tile(item.album!.asAlbum); + } + if (item.playlist != null) { + return PlaylistCard.tile(item.playlist!.asPlaylist); + } + return const SizedBox.shrink(); + }, + gridItemBuilder: (context, index) { + final item = section.items[index]; + if (item.album != null) { + return AlbumCard(item.album!.asAlbum); + } + if (item.playlist != null) { + return PlaylistCard(item.playlist!.asPlaylist); + } + return const SizedBox.shrink(); + }, + ), + const SliverToBoxAdapter( + child: SafeArea( + child: SizedBox(), ), - itemCount: section.items.length, - itemBuilder: (context, index) { - final item = section.items[index]; - return ArtistCard(item.artist!.asArtist); - }, - ) - else - PlaybuttonView( - controller: controller, - itemCount: section.items.length, - hasMore: false, - isLoading: false, - onRequestMore: () => {}, - listItemBuilder: (context, index) { - final item = section.items[index]; - if (item.album != null) { - return AlbumCard.tile(item.album!.asAlbum); - } - if (item.playlist != null) { - return PlaylistCard.tile(item.playlist!.asPlaylist); - } - return const SizedBox.shrink(); - }, - gridItemBuilder: (context, index) { - final item = section.items[index]; - if (item.album != null) { - return AlbumCard(item.album!.asAlbum); - } - if (item.playlist != null) { - return PlaylistCard(item.playlist!.asPlaylist); - } - return const SizedBox.shrink(); - }, ), - const SliverToBoxAdapter( - child: SafeArea( - child: SizedBox(), - ), - ), - ], + ], + ), ), ), ), diff --git a/lib/pages/home/genres/genre_playlists.dart b/lib/pages/home/genres/genre_playlists.dart index a3e38309..ea421cb4 100644 --- a/lib/pages/home/genres/genre_playlists.dart +++ b/lib/pages/home/genres/genre_playlists.dart @@ -45,93 +45,98 @@ class GenrePlaylistsPage extends HookConsumerWidget { automaticSystemUiAdjustment: false, ); - return Scaffold( - headers: [ - if (kIsDesktop) - const TitleBar( - leading: [ - BackButton(), - ], - backgroundColor: Colors.transparent, - surfaceOpacity: 0, - surfaceBlur: 0, - ) - ], - floatingHeader: true, - child: DecoratedBox( - decoration: BoxDecoration( - image: DecorationImage( - image: UniversalImage.imageProvider(category.icons!.first.url!), - alignment: Alignment.topCenter, - fit: BoxFit.cover, - repeat: ImageRepeat.noRepeat, - matchTextDirection: true, + return SafeArea( + child: Scaffold( + headers: [ + if (kIsDesktop) + const TitleBar( + leading: [ + BackButton(), + ], + backgroundColor: Colors.transparent, + surfaceOpacity: 0, + surfaceBlur: 0, + ) + ], + floatingHeader: true, + child: DecoratedBox( + decoration: BoxDecoration( + image: DecorationImage( + image: UniversalImage.imageProvider(category.icons!.first.url!), + alignment: Alignment.topCenter, + fit: BoxFit.cover, + repeat: ImageRepeat.noRepeat, + matchTextDirection: true, + ), ), - ), - child: SurfaceCard( - borderRadius: BorderRadius.zero, - padding: EdgeInsets.zero, - child: CustomScrollView( - controller: scrollController, - slivers: [ - SliverAppBar( - automaticallyImplyLeading: false, - leading: kIsMobile ? const BackButton() : null, - expandedHeight: mediaQuery.mdAndDown ? 200 : 150, - title: const Text(""), - backgroundColor: Colors.transparent, - flexibleSpace: FlexibleSpaceBar( - centerTitle: kIsDesktop, - title: Text( - category.name!, - style: context.theme.typography.h3.copyWith( - color: Colors.white, - letterSpacing: 3, - shadows: [ - Shadow( - offset: const Offset(-1.5, -1.5), - color: Colors.black.withAlpha(138), + child: SurfaceCard( + borderRadius: BorderRadius.zero, + padding: EdgeInsets.zero, + child: CustomScrollView( + controller: scrollController, + slivers: [ + SliverSafeArea( + bottom: false, + sliver: SliverAppBar( + automaticallyImplyLeading: false, + leading: kIsMobile ? const BackButton() : null, + expandedHeight: mediaQuery.mdAndDown ? 200 : 150, + title: const Text(""), + backgroundColor: Colors.transparent, + flexibleSpace: FlexibleSpaceBar( + centerTitle: kIsDesktop, + title: Text( + category.name!, + style: context.theme.typography.h3.copyWith( + color: Colors.white, + letterSpacing: 3, + shadows: [ + Shadow( + offset: const Offset(-1.5, -1.5), + color: Colors.black.withAlpha(138), + ), + Shadow( + offset: const Offset(1.5, -1.5), + color: Colors.black.withAlpha(138), + ), + Shadow( + offset: const Offset(1.5, 1.5), + color: Colors.black.withAlpha(138), + ), + Shadow( + offset: const Offset(-1.5, 1.5), + color: Colors.black.withAlpha(138), + ), + ], ), - Shadow( - offset: const Offset(1.5, -1.5), - color: Colors.black.withAlpha(138), - ), - Shadow( - offset: const Offset(1.5, 1.5), - color: Colors.black.withAlpha(138), - ), - Shadow( - offset: const Offset(-1.5, 1.5), - color: Colors.black.withAlpha(138), - ), - ], + ), + collapseMode: CollapseMode.parallax, ), ), - collapseMode: CollapseMode.parallax, ), - ), - const SliverGap(20), - SliverSafeArea( - top: false, - sliver: SliverPadding( - padding: EdgeInsets.symmetric( - horizontal: mediaQuery.mdAndDown ? 12 : 24, - ), - sliver: PlaybuttonView( - controller: scrollController, - itemCount: playlists.asData?.value.items.length ?? 0, - isLoading: playlists.isLoading, - hasMore: playlists.asData?.value.hasMore == true, - onRequestMore: playlistsNotifier.fetchMore, - listItemBuilder: (context, index) => - PlaylistCard.tile(playlists.asData!.value.items[index]), - gridItemBuilder: (context, index) => - PlaylistCard(playlists.asData!.value.items[index]), + const SliverGap(20), + SliverSafeArea( + top: false, + sliver: SliverPadding( + padding: EdgeInsets.symmetric( + horizontal: mediaQuery.mdAndDown ? 12 : 24, + ), + sliver: PlaybuttonView( + controller: scrollController, + itemCount: playlists.asData?.value.items.length ?? 0, + isLoading: playlists.isLoading, + hasMore: playlists.asData?.value.hasMore == true, + onRequestMore: playlistsNotifier.fetchMore, + listItemBuilder: (context, index) => PlaylistCard.tile( + playlists.asData!.value.items[index]), + gridItemBuilder: (context, index) => + PlaylistCard(playlists.asData!.value.items[index]), + ), ), ), - ), - const SliverGap(20), - ], + const SliverGap(20), + ], + ), ), ), ), diff --git a/lib/pages/home/genres/genres.dart b/lib/pages/home/genres/genres.dart index eaddeae6..38d110db 100644 --- a/lib/pages/home/genres/genres.dart +++ b/lib/pages/home/genres/genres.dart @@ -32,7 +32,6 @@ class GenrePage extends HookConsumerWidget { headers: [ TitleBar( title: Text(context.l10n.explore_genres), - automaticallyImplyLeading: true, ) ], child: GridView.builder( diff --git a/lib/pages/lastfm_login/lastfm_login.dart b/lib/pages/lastfm_login/lastfm_login.dart index 6b741f4d..41042a1b 100644 --- a/lib/pages/lastfm_login/lastfm_login.dart +++ b/lib/pages/lastfm_login/lastfm_login.dart @@ -31,6 +31,7 @@ class LastFMLoginPage extends HookConsumerWidget { return Scaffold( headers: const [ SafeArea( + bottom: false, child: TitleBar( leading: [BackButton()], ), @@ -39,102 +40,104 @@ class LastFMLoginPage extends HookConsumerWidget { child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Container( - constraints: const BoxConstraints(maxWidth: 400), - alignment: Alignment.center, - padding: const EdgeInsets.all(16), - child: Card( - padding: const EdgeInsets.all(16.0), - child: Form( - onSubmit: (context, values) async { - try { - isLoading.value = true; - await scrobblerNotifier.login( - values[usernameKey].trim(), - values[passwordKey], - ); - if (context.mounted) { - context.back(); - } - } catch (e) { - if (context.mounted) { - showPromptDialog( - context: context, - title: context.l10n.error("Authentication failed"), - message: e.toString(), - cancelText: null, + Flexible( + child: Container( + constraints: const BoxConstraints(maxWidth: 400), + alignment: Alignment.center, + padding: const EdgeInsets.all(16), + child: Card( + padding: const EdgeInsets.all(16.0), + child: Form( + onSubmit: (context, values) async { + try { + isLoading.value = true; + await scrobblerNotifier.login( + values[usernameKey].trim(), + values[passwordKey], ); + if (context.mounted) { + context.back(); + } + } catch (e) { + if (context.mounted) { + showPromptDialog( + context: context, + title: context.l10n.error("Authentication failed"), + message: e.toString(), + cancelText: null, + ); + } + } finally { + isLoading.value = false; } - } finally { - isLoading.value = false; - } - }, - child: Column( - mainAxisSize: MainAxisSize.min, - spacing: 10, - children: [ - Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(30), - color: const Color.fromARGB(255, 186, 0, 0), + }, + child: Column( + mainAxisSize: MainAxisSize.min, + spacing: 10, + children: [ + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(30), + color: const Color.fromARGB(255, 186, 0, 0), + ), + padding: const EdgeInsets.all(12), + child: const Icon( + SpotubeIcons.lastFm, + color: Colors.white, + size: 60, + ), ), - padding: const EdgeInsets.all(12), - child: const Icon( - SpotubeIcons.lastFm, - color: Colors.white, - size: 60, - ), - ), - const Text("last.fm").h3(), - Text(context.l10n.login_with_your_lastfm), - AutofillGroup( - child: Column( - spacing: 10, - children: [ - FormField( - label: Text(context.l10n.username), - key: usernameKey, - validator: const NotEmptyValidator(), - child: TextField( - autofillHints: const [ - AutofillHints.username, - AutofillHints.email, - ], - placeholder: Text(context.l10n.username), - ), - ), - FormField( - key: passwordKey, - validator: const NotEmptyValidator(), - label: Text(context.l10n.password), - child: TextField( - autofillHints: const [ - AutofillHints.password, - ], - obscureText: !passwordVisible.value, - placeholder: Text(context.l10n.password), - trailing: IconButton.ghost( - icon: Icon( - passwordVisible.value - ? SpotubeIcons.eye - : SpotubeIcons.noEye, - ), - onPressed: () => passwordVisible.value = - !passwordVisible.value, + const Text("last.fm").h3(), + Text(context.l10n.login_with_your_lastfm), + AutofillGroup( + child: Column( + spacing: 10, + children: [ + FormField( + label: Text(context.l10n.username), + key: usernameKey, + validator: const NotEmptyValidator(), + child: TextField( + autofillHints: const [ + AutofillHints.username, + AutofillHints.email, + ], + placeholder: Text(context.l10n.username), ), ), - ), - ], + FormField( + key: passwordKey, + validator: const NotEmptyValidator(), + label: Text(context.l10n.password), + child: TextField( + autofillHints: const [ + AutofillHints.password, + ], + obscureText: !passwordVisible.value, + placeholder: Text(context.l10n.password), + trailing: IconButton.ghost( + icon: Icon( + passwordVisible.value + ? SpotubeIcons.eye + : SpotubeIcons.noEye, + ), + onPressed: () => passwordVisible.value = + !passwordVisible.value, + ), + ), + ), + ], + ), ), - ), - FormErrorBuilder(builder: (context, errors, child) { - return Button.primary( - onPressed: () => context.submitForm(), - enabled: errors.isEmpty && !isLoading.value, - child: Text(context.l10n.login), - ); - }), - ], + FormErrorBuilder(builder: (context, errors, child) { + return Button.primary( + onPressed: () => context.submitForm(), + enabled: errors.isEmpty && !isLoading.value, + child: Text(context.l10n.login), + ); + }), + ], + ), ), ), ), diff --git a/lib/pages/library/playlist_generate/playlist_generate.dart b/lib/pages/library/playlist_generate/playlist_generate.dart index 1bc96a29..573d502c 100644 --- a/lib/pages/library/playlist_generate/playlist_generate.dart +++ b/lib/pages/library/playlist_generate/playlist_generate.dart @@ -256,426 +256,430 @@ class PlaylistGeneratorPage extends HookConsumerWidget { final controller = useScrollController(); - return Scaffold( - headers: [ - TitleBar( - leading: const [BackButton()], - title: Text(context.l10n.generate), - ) - ], - child: Scrollbar( - controller: controller, - child: Center( - child: ConstrainedBox( - constraints: BoxConstraints(maxWidth: Breakpoints.lg), - child: SafeArea( - child: LayoutBuilder(builder: (context, constrains) { - return ScrollConfiguration( - behavior: ScrollConfiguration.of(context) - .copyWith(scrollbars: false), - child: ListView( - controller: controller, - padding: const EdgeInsets.all(16), - children: [ - ValueListenableBuilder( - valueListenable: limit, - builder: (context, value, child) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - context.l10n.number_of_tracks_generate, - style: typography.semiBold, - ), - Row( - spacing: 5, - children: [ - Container( - width: 40, - height: 40, - alignment: Alignment.center, - decoration: BoxDecoration( - color: theme.colorScheme.primary - .withAlpha(25), - shape: BoxShape.circle, - ), - child: Text( - value.round().toString(), - style: typography.large.copyWith( - color: theme.colorScheme.primary, + return SafeArea( + bottom: false, + child: Scaffold( + headers: [ + TitleBar( + leading: const [BackButton()], + title: Text(context.l10n.generate), + ) + ], + child: Scrollbar( + controller: controller, + child: Center( + child: ConstrainedBox( + constraints: BoxConstraints(maxWidth: Breakpoints.lg), + child: SafeArea( + child: LayoutBuilder(builder: (context, constrains) { + return ScrollConfiguration( + behavior: ScrollConfiguration.of(context) + .copyWith(scrollbars: false), + child: ListView( + controller: controller, + padding: const EdgeInsets.all(16), + children: [ + ValueListenableBuilder( + valueListenable: limit, + builder: (context, value, child) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + context.l10n.number_of_tracks_generate, + style: typography.semiBold, + ), + Row( + spacing: 5, + children: [ + Container( + width: 40, + height: 40, + alignment: Alignment.center, + decoration: BoxDecoration( + color: theme.colorScheme.primary + .withAlpha(25), + shape: BoxShape.circle, + ), + child: Text( + value.round().toString(), + style: typography.large.copyWith( + color: theme.colorScheme.primary, + ), ), ), - ), - Expanded( - child: Slider( - value: - SliderValue.single(value.toDouble()), - min: 10, - max: 100, - divisions: 9, - onChanged: (value) { - limit.value = value.value.round(); - }, - ), - ) - ], - ) + Expanded( + child: Slider( + value: SliderValue.single( + value.toDouble()), + min: 10, + max: 100, + divisions: 9, + onChanged: (value) { + limit.value = value.value.round(); + }, + ), + ) + ], + ) + ], + ); + }, + ), + const SizedBox(height: 16), + if (constrains.mdAndUp) + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: countrySelector, + ), + const SizedBox(width: 16), + Expanded( + child: genreSelector, + ), ], - ); - }, - ), - const SizedBox(height: 16), - if (constrains.mdAndUp) - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: countrySelector, - ), - const SizedBox(width: 16), - Expanded( - child: genreSelector, - ), - ], - ) - else ...[ - countrySelector, + ) + else ...[ + countrySelector, + const SizedBox(height: 16), + genreSelector, + ], const SizedBox(height: 16), - genreSelector, - ], - const SizedBox(height: 16), - if (constrains.mdAndUp) - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: artistAutoComplete, - ), - const SizedBox(width: 16), - Expanded( - child: tracksAutocomplete, - ), - ], - ) - else ...[ - artistAutoComplete, + if (constrains.mdAndUp) + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: artistAutoComplete, + ), + const SizedBox(width: 16), + Expanded( + child: tracksAutocomplete, + ), + ], + ) + else ...[ + artistAutoComplete, + const SizedBox(height: 16), + tracksAutocomplete, + ], const SizedBox(height: 16), - tracksAutocomplete, - ], - const SizedBox(height: 16), - RecommendationAttributeDials( - title: Text(context.l10n.acousticness), - values: ( - target: target.value.acousticness?.toDouble() ?? 0, - min: min.value.acousticness?.toDouble() ?? 0, - max: max.value.acousticness?.toDouble() ?? 0, - ), - onChanged: (value) { - target.value = target.value.copyWith( - acousticness: value.target, - ); - min.value = min.value.copyWith( - acousticness: value.min, - ); - max.value = max.value.copyWith( - acousticness: value.max, - ); - }, - ), - RecommendationAttributeDials( - title: Text(context.l10n.danceability), - values: ( - target: target.value.danceability?.toDouble() ?? 0, - min: min.value.danceability?.toDouble() ?? 0, - max: max.value.danceability?.toDouble() ?? 0, - ), - onChanged: (value) { - target.value = target.value.copyWith( - danceability: value.target, - ); - min.value = min.value.copyWith( - danceability: value.min, - ); - max.value = max.value.copyWith( - danceability: value.max, - ); - }, - ), - RecommendationAttributeDials( - title: Text(context.l10n.energy), - values: ( - target: target.value.energy?.toDouble() ?? 0, - min: min.value.energy?.toDouble() ?? 0, - max: max.value.energy?.toDouble() ?? 0, - ), - onChanged: (value) { - target.value = target.value.copyWith( - energy: value.target, - ); - min.value = min.value.copyWith( - energy: value.min, - ); - max.value = max.value.copyWith( - energy: value.max, - ); - }, - ), - RecommendationAttributeDials( - title: Text(context.l10n.instrumentalness), - values: ( - target: - target.value.instrumentalness?.toDouble() ?? 0, - min: min.value.instrumentalness?.toDouble() ?? 0, - max: max.value.instrumentalness?.toDouble() ?? 0, - ), - onChanged: (value) { - target.value = target.value.copyWith( - instrumentalness: value.target, - ); - min.value = min.value.copyWith( - instrumentalness: value.min, - ); - max.value = max.value.copyWith( - instrumentalness: value.max, - ); - }, - ), - RecommendationAttributeDials( - title: Text(context.l10n.liveness), - values: ( - target: target.value.liveness?.toDouble() ?? 0, - min: min.value.liveness?.toDouble() ?? 0, - max: max.value.liveness?.toDouble() ?? 0, - ), - onChanged: (value) { - target.value = target.value.copyWith( - liveness: value.target, - ); - min.value = min.value.copyWith( - liveness: value.min, - ); - max.value = max.value.copyWith( - liveness: value.max, - ); - }, - ), - RecommendationAttributeDials( - title: Text(context.l10n.loudness), - values: ( - target: target.value.loudness?.toDouble() ?? 0, - min: min.value.loudness?.toDouble() ?? 0, - max: max.value.loudness?.toDouble() ?? 0, - ), - onChanged: (value) { - target.value = target.value.copyWith( - loudness: value.target, - ); - min.value = min.value.copyWith( - loudness: value.min, - ); - max.value = max.value.copyWith( - loudness: value.max, - ); - }, - ), - RecommendationAttributeDials( - title: Text(context.l10n.speechiness), - values: ( - target: target.value.speechiness?.toDouble() ?? 0, - min: min.value.speechiness?.toDouble() ?? 0, - max: max.value.speechiness?.toDouble() ?? 0, - ), - onChanged: (value) { - target.value = target.value.copyWith( - speechiness: value.target, - ); - min.value = min.value.copyWith( - speechiness: value.min, - ); - max.value = max.value.copyWith( - speechiness: value.max, - ); - }, - ), - RecommendationAttributeDials( - title: Text(context.l10n.valence), - values: ( - target: target.value.valence?.toDouble() ?? 0, - min: min.value.valence?.toDouble() ?? 0, - max: max.value.valence?.toDouble() ?? 0, - ), - onChanged: (value) { - target.value = target.value.copyWith( - valence: value.target, - ); - min.value = min.value.copyWith( - valence: value.min, - ); - max.value = max.value.copyWith( - valence: value.max, - ); - }, - ), - RecommendationAttributeDials( - title: Text(context.l10n.popularity), - base: 100, - values: ( - target: target.value.popularity?.toDouble() ?? 0, - min: min.value.popularity?.toDouble() ?? 0, - max: max.value.popularity?.toDouble() ?? 0, - ), - onChanged: (value) { - target.value = target.value.copyWith( - popularity: value.target, - ); - min.value = min.value.copyWith( - popularity: value.min, - ); - max.value = max.value.copyWith( - popularity: value.max, - ); - }, - ), - RecommendationAttributeDials( - title: Text(context.l10n.key), - base: 11, - values: ( - target: target.value.key?.toDouble() ?? 0, - min: min.value.key?.toDouble() ?? 0, - max: max.value.key?.toDouble() ?? 0, - ), - onChanged: (value) { - target.value = target.value.copyWith( - key: value.target, - ); - min.value = min.value.copyWith( - key: value.min, - ); - max.value = max.value.copyWith( - key: value.max, - ); - }, - ), - RecommendationAttributeFields( - title: Text(context.l10n.duration), - values: ( - max: (max.value.durationMs ?? 0) / 1000, - target: (target.value.durationMs ?? 0) / 1000, - min: (min.value.durationMs ?? 0) / 1000, - ), - onChanged: (value) { - target.value = target.value.copyWith( - durationMs: (value.target * 1000).toInt(), - ); - min.value = min.value.copyWith( - durationMs: (value.min * 1000).toInt(), - ); - max.value = max.value.copyWith( - durationMs: (value.max * 1000).toInt(), - ); - }, - presets: { - context.l10n.short: (min: 50, target: 90, max: 120), - context.l10n.medium: ( - min: 120, - target: 180, - max: 200 + RecommendationAttributeDials( + title: Text(context.l10n.acousticness), + values: ( + target: target.value.acousticness?.toDouble() ?? 0, + min: min.value.acousticness?.toDouble() ?? 0, + max: max.value.acousticness?.toDouble() ?? 0, ), - context.l10n.long: (min: 480, target: 560, max: 640) - }, - ), - RecommendationAttributeFields( - title: Text(context.l10n.tempo), - values: ( - max: max.value.tempo?.toDouble() ?? 0, - target: target.value.tempo?.toDouble() ?? 0, - min: min.value.tempo?.toDouble() ?? 0, + onChanged: (value) { + target.value = target.value.copyWith( + acousticness: value.target, + ); + min.value = min.value.copyWith( + acousticness: value.min, + ); + max.value = max.value.copyWith( + acousticness: value.max, + ); + }, ), - onChanged: (value) { - target.value = target.value.copyWith( - tempo: value.target, - ); - min.value = min.value.copyWith( - tempo: value.min, - ); - max.value = max.value.copyWith( - tempo: value.max, - ); - }, - ), - RecommendationAttributeFields( - title: Text(context.l10n.mode), - values: ( - max: max.value.mode?.toDouble() ?? 0, - target: target.value.mode?.toDouble() ?? 0, - min: min.value.mode?.toDouble() ?? 0, + RecommendationAttributeDials( + title: Text(context.l10n.danceability), + values: ( + target: target.value.danceability?.toDouble() ?? 0, + min: min.value.danceability?.toDouble() ?? 0, + max: max.value.danceability?.toDouble() ?? 0, + ), + onChanged: (value) { + target.value = target.value.copyWith( + danceability: value.target, + ); + min.value = min.value.copyWith( + danceability: value.min, + ); + max.value = max.value.copyWith( + danceability: value.max, + ); + }, ), - onChanged: (value) { - target.value = target.value.copyWith( - mode: value.target, - ); - min.value = min.value.copyWith( - mode: value.min, - ); - max.value = max.value.copyWith( - mode: value.max, - ); - }, - ), - RecommendationAttributeFields( - title: Text(context.l10n.time_signature), - values: ( - max: max.value.timeSignature?.toDouble() ?? 0, - target: target.value.timeSignature?.toDouble() ?? 0, - min: min.value.timeSignature?.toDouble() ?? 0, + RecommendationAttributeDials( + title: Text(context.l10n.energy), + values: ( + target: target.value.energy?.toDouble() ?? 0, + min: min.value.energy?.toDouble() ?? 0, + max: max.value.energy?.toDouble() ?? 0, + ), + onChanged: (value) { + target.value = target.value.copyWith( + energy: value.target, + ); + min.value = min.value.copyWith( + energy: value.min, + ); + max.value = max.value.copyWith( + energy: value.max, + ); + }, ), - onChanged: (value) { - target.value = target.value.copyWith( - timeSignature: value.target, - ); - min.value = min.value.copyWith( - timeSignature: value.min, - ); - max.value = max.value.copyWith( - timeSignature: value.max, - ); - }, - ), - const Gap(20), - Center( - child: Button.primary( - leading: const Icon(SpotubeIcons.magic), - onPressed: artists.value.isEmpty && - tracks.value.isEmpty && - genres.value.isEmpty - ? null - : () { - final routeState = - GeneratePlaylistProviderInput( - seedArtists: artists.value - .map((a) => a.id!) - .toList(), - seedTracks: - tracks.value.map((t) => t.id!).toList(), - seedGenres: genres.value, - limit: limit.value, - max: max.value, - min: min.value, - target: target.value, - ); - context.navigateTo( - PlaylistGenerateResultRoute( - state: routeState, - ), - ); - }, - child: Text(context.l10n.generate), + RecommendationAttributeDials( + title: Text(context.l10n.instrumentalness), + values: ( + target: + target.value.instrumentalness?.toDouble() ?? 0, + min: min.value.instrumentalness?.toDouble() ?? 0, + max: max.value.instrumentalness?.toDouble() ?? 0, + ), + onChanged: (value) { + target.value = target.value.copyWith( + instrumentalness: value.target, + ); + min.value = min.value.copyWith( + instrumentalness: value.min, + ); + max.value = max.value.copyWith( + instrumentalness: value.max, + ); + }, ), - ), - ], - ), - ); - }), + RecommendationAttributeDials( + title: Text(context.l10n.liveness), + values: ( + target: target.value.liveness?.toDouble() ?? 0, + min: min.value.liveness?.toDouble() ?? 0, + max: max.value.liveness?.toDouble() ?? 0, + ), + onChanged: (value) { + target.value = target.value.copyWith( + liveness: value.target, + ); + min.value = min.value.copyWith( + liveness: value.min, + ); + max.value = max.value.copyWith( + liveness: value.max, + ); + }, + ), + RecommendationAttributeDials( + title: Text(context.l10n.loudness), + values: ( + target: target.value.loudness?.toDouble() ?? 0, + min: min.value.loudness?.toDouble() ?? 0, + max: max.value.loudness?.toDouble() ?? 0, + ), + onChanged: (value) { + target.value = target.value.copyWith( + loudness: value.target, + ); + min.value = min.value.copyWith( + loudness: value.min, + ); + max.value = max.value.copyWith( + loudness: value.max, + ); + }, + ), + RecommendationAttributeDials( + title: Text(context.l10n.speechiness), + values: ( + target: target.value.speechiness?.toDouble() ?? 0, + min: min.value.speechiness?.toDouble() ?? 0, + max: max.value.speechiness?.toDouble() ?? 0, + ), + onChanged: (value) { + target.value = target.value.copyWith( + speechiness: value.target, + ); + min.value = min.value.copyWith( + speechiness: value.min, + ); + max.value = max.value.copyWith( + speechiness: value.max, + ); + }, + ), + RecommendationAttributeDials( + title: Text(context.l10n.valence), + values: ( + target: target.value.valence?.toDouble() ?? 0, + min: min.value.valence?.toDouble() ?? 0, + max: max.value.valence?.toDouble() ?? 0, + ), + onChanged: (value) { + target.value = target.value.copyWith( + valence: value.target, + ); + min.value = min.value.copyWith( + valence: value.min, + ); + max.value = max.value.copyWith( + valence: value.max, + ); + }, + ), + RecommendationAttributeDials( + title: Text(context.l10n.popularity), + base: 100, + values: ( + target: target.value.popularity?.toDouble() ?? 0, + min: min.value.popularity?.toDouble() ?? 0, + max: max.value.popularity?.toDouble() ?? 0, + ), + onChanged: (value) { + target.value = target.value.copyWith( + popularity: value.target, + ); + min.value = min.value.copyWith( + popularity: value.min, + ); + max.value = max.value.copyWith( + popularity: value.max, + ); + }, + ), + RecommendationAttributeDials( + title: Text(context.l10n.key), + base: 11, + values: ( + target: target.value.key?.toDouble() ?? 0, + min: min.value.key?.toDouble() ?? 0, + max: max.value.key?.toDouble() ?? 0, + ), + onChanged: (value) { + target.value = target.value.copyWith( + key: value.target, + ); + min.value = min.value.copyWith( + key: value.min, + ); + max.value = max.value.copyWith( + key: value.max, + ); + }, + ), + RecommendationAttributeFields( + title: Text(context.l10n.duration), + values: ( + max: (max.value.durationMs ?? 0) / 1000, + target: (target.value.durationMs ?? 0) / 1000, + min: (min.value.durationMs ?? 0) / 1000, + ), + onChanged: (value) { + target.value = target.value.copyWith( + durationMs: (value.target * 1000).toInt(), + ); + min.value = min.value.copyWith( + durationMs: (value.min * 1000).toInt(), + ); + max.value = max.value.copyWith( + durationMs: (value.max * 1000).toInt(), + ); + }, + presets: { + context.l10n.short: (min: 50, target: 90, max: 120), + context.l10n.medium: ( + min: 120, + target: 180, + max: 200 + ), + context.l10n.long: (min: 480, target: 560, max: 640) + }, + ), + RecommendationAttributeFields( + title: Text(context.l10n.tempo), + values: ( + max: max.value.tempo?.toDouble() ?? 0, + target: target.value.tempo?.toDouble() ?? 0, + min: min.value.tempo?.toDouble() ?? 0, + ), + onChanged: (value) { + target.value = target.value.copyWith( + tempo: value.target, + ); + min.value = min.value.copyWith( + tempo: value.min, + ); + max.value = max.value.copyWith( + tempo: value.max, + ); + }, + ), + RecommendationAttributeFields( + title: Text(context.l10n.mode), + values: ( + max: max.value.mode?.toDouble() ?? 0, + target: target.value.mode?.toDouble() ?? 0, + min: min.value.mode?.toDouble() ?? 0, + ), + onChanged: (value) { + target.value = target.value.copyWith( + mode: value.target, + ); + min.value = min.value.copyWith( + mode: value.min, + ); + max.value = max.value.copyWith( + mode: value.max, + ); + }, + ), + RecommendationAttributeFields( + title: Text(context.l10n.time_signature), + values: ( + max: max.value.timeSignature?.toDouble() ?? 0, + target: target.value.timeSignature?.toDouble() ?? 0, + min: min.value.timeSignature?.toDouble() ?? 0, + ), + onChanged: (value) { + target.value = target.value.copyWith( + timeSignature: value.target, + ); + min.value = min.value.copyWith( + timeSignature: value.min, + ); + max.value = max.value.copyWith( + timeSignature: value.max, + ); + }, + ), + const Gap(20), + Center( + child: Button.primary( + leading: const Icon(SpotubeIcons.magic), + onPressed: artists.value.isEmpty && + tracks.value.isEmpty && + genres.value.isEmpty + ? null + : () { + final routeState = + GeneratePlaylistProviderInput( + seedArtists: artists.value + .map((a) => a.id!) + .toList(), + seedTracks: tracks.value + .map((t) => t.id!) + .toList(), + seedGenres: genres.value, + limit: limit.value, + max: max.value, + min: min.value, + target: target.value, + ); + context.navigateTo( + PlaylistGenerateResultRoute( + state: routeState, + ), + ); + }, + child: Text(context.l10n.generate), + ), + ), + ], + ), + ); + }), + ), ), ), ), diff --git a/lib/pages/library/playlist_generate/playlist_generate_result.dart b/lib/pages/library/playlist_generate/playlist_generate_result.dart index 4c350366..9e6f2987 100644 --- a/lib/pages/library/playlist_generate/playlist_generate_result.dart +++ b/lib/pages/library/playlist_generate/playlist_generate_result.dart @@ -48,218 +48,225 @@ class PlaylistGenerateResultPage extends HookConsumerWidget { final isAllTrackSelected = selectedTracks.value.length == (generatedPlaylist.asData?.value.length ?? 0); - return Scaffold( - headers: const [ - TitleBar(leading: [BackButton()]) - ], - child: generatedPlaylist.isLoading - ? Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const CircularProgressIndicator(), - Text(context.l10n.generating_playlist), - ], - ), - ) - : Padding( - padding: const EdgeInsets.all(8.0), - child: ListView( - children: [ - GridView( - gridDelegate: - const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, - crossAxisSpacing: 8, - mainAxisSpacing: 8, - mainAxisExtent: 32, - ), - shrinkWrap: true, - children: [ - Button.primary( - leading: const Icon(SpotubeIcons.play), - onPressed: selectedTracks.value.isEmpty - ? null - : () async { - await playlistNotifier.load( - generatedPlaylist.asData!.value - .where( - (e) => selectedTracks.value - .contains(e.id!), - ) - .toList(), - autoPlay: true, - ); - }, - child: Text(context.l10n.play), + return SafeArea( + bottom: false, + child: Scaffold( + headers: const [ + TitleBar(leading: [BackButton()]) + ], + child: generatedPlaylist.isLoading + ? Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const CircularProgressIndicator(), + Text(context.l10n.generating_playlist), + ], + ), + ) + : Padding( + padding: const EdgeInsets.all(8.0), + child: ListView( + children: [ + GridView( + gridDelegate: + const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + crossAxisSpacing: 8, + mainAxisSpacing: 8, + mainAxisExtent: 32, ), - Button.primary( - leading: const Icon(SpotubeIcons.queueAdd), - onPressed: selectedTracks.value.isEmpty - ? null - : () async { - await playlistNotifier.addTracks( - generatedPlaylist.asData!.value.where( - (e) => selectedTracks.value.contains(e.id!), - ), - ); - if (context.mounted) { - showToast( - context: context, - location: ToastLocation.topRight, - builder: (context, overlay) { - return SurfaceCard( - child: Text( - context.l10n.add_count_to_queue( - selectedTracks.value.length, - ), - ), - ); - }, - ); - } - }, - child: Text(context.l10n.add_to_queue), - ), - Button.primary( - leading: const Icon(SpotubeIcons.addFilled), - onPressed: selectedTracks.value.isEmpty - ? null - : () async { - final playlist = await showDialog( - context: context, - builder: (context) => PlaylistCreateDialog( - trackIds: selectedTracks.value, - ), - ); - - if (playlist != null && context.mounted) { - context.navigateTo( - PlaylistRoute( - id: playlist.id!, - playlist: playlist, - ), - ); - } - }, - child: Text(context.l10n.create_a_playlist), - ), - Button.primary( - leading: const Icon(SpotubeIcons.playlistAdd), - onPressed: selectedTracks.value.isEmpty - ? null - : () async { - final hasAdded = await showDialog( - context: context, - builder: (context) => PlaylistAddTrackDialog( - openFromPlaylist: null, - tracks: selectedTracks.value - .map( - (e) => generatedPlaylist.asData!.value - .firstWhere( - (element) => element.id == e, - ), + shrinkWrap: true, + children: [ + Button.primary( + leading: const Icon(SpotubeIcons.play), + onPressed: selectedTracks.value.isEmpty + ? null + : () async { + await playlistNotifier.load( + generatedPlaylist.asData!.value + .where( + (e) => selectedTracks.value + .contains(e.id!), ) .toList(), - ), - ); - - if (context.mounted && hasAdded == true) { - showToast( - context: context, - location: ToastLocation.topRight, - builder: (context, overlay) { - return SurfaceCard( - child: Text( - context.l10n.add_count_to_playlist( - selectedTracks.value.length, - ), - ), - ); - }, + autoPlay: true, ); - } - }, - child: Text(context.l10n.add_to_playlist), - ) - ], - ), - const SizedBox(height: 16), - if (generatedPlaylist.asData?.value != null) - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - context.l10n.selected_count_tracks( - selectedTracks.value.length, - ), + }, + child: Text(context.l10n.play), ), - Button.secondary( - onPressed: () { - if (isAllTrackSelected) { - selectedTracks.value = []; - } else { - selectedTracks.value = generatedPlaylist - .asData?.value - .map((e) => e.id!) - .toList() ?? - []; - } - }, - leading: const Icon(SpotubeIcons.selectionCheck), - child: Text( - isAllTrackSelected - ? context.l10n.deselect_all - : context.l10n.select_all, - ), + Button.primary( + leading: const Icon(SpotubeIcons.queueAdd), + onPressed: selectedTracks.value.isEmpty + ? null + : () async { + await playlistNotifier.addTracks( + generatedPlaylist.asData!.value.where( + (e) => + selectedTracks.value.contains(e.id!), + ), + ); + if (context.mounted) { + showToast( + context: context, + location: ToastLocation.topRight, + builder: (context, overlay) { + return SurfaceCard( + child: Text( + context.l10n.add_count_to_queue( + selectedTracks.value.length, + ), + ), + ); + }, + ); + } + }, + child: Text(context.l10n.add_to_queue), ), + Button.primary( + leading: const Icon(SpotubeIcons.addFilled), + onPressed: selectedTracks.value.isEmpty + ? null + : () async { + final playlist = await showDialog( + context: context, + builder: (context) => PlaylistCreateDialog( + trackIds: selectedTracks.value, + ), + ); + + if (playlist != null && context.mounted) { + context.navigateTo( + PlaylistRoute( + id: playlist.id!, + playlist: playlist, + ), + ); + } + }, + child: Text(context.l10n.create_a_playlist), + ), + Button.primary( + leading: const Icon(SpotubeIcons.playlistAdd), + onPressed: selectedTracks.value.isEmpty + ? null + : () async { + final hasAdded = await showDialog( + context: context, + builder: (context) => + PlaylistAddTrackDialog( + openFromPlaylist: null, + tracks: selectedTracks.value + .map( + (e) => generatedPlaylist + .asData!.value + .firstWhere( + (element) => element.id == e, + ), + ) + .toList(), + ), + ); + + if (context.mounted && hasAdded == true) { + showToast( + context: context, + location: ToastLocation.topRight, + builder: (context, overlay) { + return SurfaceCard( + child: Text( + context.l10n.add_count_to_playlist( + selectedTracks.value.length, + ), + ), + ); + }, + ); + } + }, + child: Text(context.l10n.add_to_playlist), + ) ], ), - const SizedBox(height: 8), - SafeArea( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - for (final track - in generatedPlaylist.asData?.value ?? []) - Row( - spacing: 5, - children: [ - Checkbox( - state: selectedTracks.value.contains(track.id) - ? CheckboxState.checked - : CheckboxState.unchecked, - onChanged: (value) { - if (value == CheckboxState.checked) { - selectedTracks.value.add(track.id!); - } else { - selectedTracks.value.remove(track.id); - } - selectedTracks.value = - selectedTracks.value.toList(); - }, - ), - Expanded( - child: GestureDetector( - onTap: () { - selectedTracks.value.contains(track.id) - ? selectedTracks.value.remove(track.id) - : selectedTracks.value.add(track.id!); + const SizedBox(height: 16), + if (generatedPlaylist.asData?.value != null) + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + context.l10n.selected_count_tracks( + selectedTracks.value.length, + ), + ), + Button.secondary( + onPressed: () { + if (isAllTrackSelected) { + selectedTracks.value = []; + } else { + selectedTracks.value = generatedPlaylist + .asData?.value + .map((e) => e.id!) + .toList() ?? + []; + } + }, + leading: const Icon(SpotubeIcons.selectionCheck), + child: Text( + isAllTrackSelected + ? context.l10n.deselect_all + : context.l10n.select_all, + ), + ), + ], + ), + const SizedBox(height: 8), + SafeArea( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + for (final track + in generatedPlaylist.asData?.value ?? []) + Row( + spacing: 5, + children: [ + Checkbox( + state: selectedTracks.value.contains(track.id) + ? CheckboxState.checked + : CheckboxState.unchecked, + onChanged: (value) { + if (value == CheckboxState.checked) { + selectedTracks.value.add(track.id!); + } else { + selectedTracks.value.remove(track.id); + } selectedTracks.value = selectedTracks.value.toList(); }, - child: SimpleTrackTile(track: track), ), - ), - ], - ) - ], + Expanded( + child: GestureDetector( + onTap: () { + selectedTracks.value.contains(track.id) + ? selectedTracks.value + .remove(track.id) + : selectedTracks.value.add(track.id!); + selectedTracks.value = + selectedTracks.value.toList(); + }, + child: SimpleTrackTile(track: track), + ), + ), + ], + ) + ], + ), ), - ), - ], + ], + ), ), - ), + ), ); } } diff --git a/lib/pages/mobile_login/mobile_login.dart b/lib/pages/mobile_login/mobile_login.dart index 4128bfe6..eb50316f 100644 --- a/lib/pages/mobile_login/mobile_login.dart +++ b/lib/pages/mobile_login/mobile_login.dart @@ -27,50 +27,53 @@ class WebViewLoginPage extends HookConsumerWidget { ); } - return Scaffold( - headers: const [ - TitleBar( - leading: [BackButton(color: Colors.white)], - backgroundColor: Colors.transparent, - ), - ], - floatingHeader: true, - child: InAppWebView( - initialSettings: InAppWebViewSettings( - userAgent: - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 safari/537.36", - ), - initialUrlRequest: URLRequest( - url: WebUri("https://accounts.spotify.com/"), - ), - onPermissionRequest: (controller, permissionRequest) async { - return PermissionResponse( - resources: permissionRequest.resources, - action: PermissionResponseAction.GRANT, - ); - }, - onLoadStop: (controller, action) async { - if (action == null) return; - String url = action.toString(); - if (url.endsWith("/")) { - url = url.substring(0, url.length - 1); - } - - final exp = RegExp(r"https:\/\/accounts.spotify.com\/.+\/status"); - - if (exp.hasMatch(url)) { - final cookies = - await CookieManager.instance().getCookies(url: action); - final cookieHeader = - "sp_dc=${cookies.firstWhere((element) => element.name == "sp_dc").value}"; - - await authenticationNotifier.login(cookieHeader); - if (context.mounted) { - // ignore: use_build_context_synchronously - context.navigateTo(const HomeRoute()); + return SafeArea( + bottom: false, + child: Scaffold( + headers: const [ + TitleBar( + leading: [BackButton(color: Colors.white)], + backgroundColor: Colors.transparent, + ), + ], + floatingHeader: true, + child: InAppWebView( + initialSettings: InAppWebViewSettings( + userAgent: + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 safari/537.36", + ), + initialUrlRequest: URLRequest( + url: WebUri("https://accounts.spotify.com/"), + ), + onPermissionRequest: (controller, permissionRequest) async { + return PermissionResponse( + resources: permissionRequest.resources, + action: PermissionResponseAction.GRANT, + ); + }, + onLoadStop: (controller, action) async { + if (action == null) return; + String url = action.toString(); + if (url.endsWith("/")) { + url = url.substring(0, url.length - 1); } - } - }, + + final exp = RegExp(r"https:\/\/accounts.spotify.com\/.+\/status"); + + if (exp.hasMatch(url)) { + final cookies = + await CookieManager.instance().getCookies(url: action); + final cookieHeader = + "sp_dc=${cookies.firstWhere((element) => element.name == "sp_dc").value}"; + + await authenticationNotifier.login(cookieHeader); + if (context.mounted) { + // ignore: use_build_context_synchronously + context.navigateTo(const HomeRoute()); + } + } + }, + ), ), ); } diff --git a/lib/pages/profile/profile.dart b/lib/pages/profile/profile.dart index a82c80b5..b6c4a2cd 100644 --- a/lib/pages/profile/profile.dart +++ b/lib/pages/profile/profile.dart @@ -44,7 +44,6 @@ class ProfilePage extends HookConsumerWidget { headers: [ TitleBar( title: Text(context.l10n.profile), - automaticallyImplyLeading: true, ) ], child: Skeletonizer( diff --git a/lib/pages/settings/about.dart b/lib/pages/settings/about.dart index 0703d4ef..1837bbec 100644 --- a/lib/pages/settings/about.dart +++ b/lib/pages/settings/about.dart @@ -31,163 +31,166 @@ class AboutSpotubePage extends HookConsumerWidget { const colon = TableCell(child: Text(":")); - return Scaffold( - headers: [ - TitleBar( - leading: const [BackButton()], - title: Text(context.l10n.about_spotube), - ) - ], - child: SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: Column( - children: [ - Assets.spotubeLogoPng.image( - height: 200, - width: 200, - ), - Center( - child: Column( - children: [ - Text(context.l10n.spotube_description).semiBold().large(), - const SizedBox(height: 20), - Table( - columnWidths: const { - 0: FixedTableSize(95), - 1: FixedTableSize(10), - 2: IntrinsicTableSize(), - }, - defaultRowHeight: const FixedTableSize(40), - rows: [ - TableRow( - cells: [ - TableCell(child: Text(context.l10n.founder)), - colon, - TableCell( - child: Hyperlink( - context.l10n.kingkor_roy_tirtho, - "https://github.com/KRTirtho", + return SafeArea( + bottom: false, + child: Scaffold( + headers: [ + TitleBar( + leading: const [BackButton()], + title: Text(context.l10n.about_spotube), + ) + ], + child: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Column( + children: [ + Assets.spotubeLogoPng.image( + height: 200, + width: 200, + ), + Center( + child: Column( + children: [ + Text(context.l10n.spotube_description).semiBold().large(), + const SizedBox(height: 20), + Table( + columnWidths: const { + 0: FixedTableSize(95), + 1: FixedTableSize(10), + 2: IntrinsicTableSize(), + }, + defaultRowHeight: const FixedTableSize(40), + rows: [ + TableRow( + cells: [ + TableCell(child: Text(context.l10n.founder)), + colon, + TableCell( + child: Hyperlink( + context.l10n.kingkor_roy_tirtho, + "https://github.com/KRTirtho", + ), + ) + ], + ), + TableRow( + cells: [ + TableCell(child: Text(context.l10n.version)), + colon, + TableCell(child: Text("v${packageInfo.version}")) + ], + ), + TableRow( + cells: [ + TableCell(child: Text(context.l10n.channel)), + colon, + TableCell(child: Text(Env.releaseChannel.name)) + ], + ), + TableRow( + cells: [ + TableCell(child: Text(context.l10n.build_number)), + colon, + TableCell( + child: Text(packageInfo.buildNumber + .replaceAll(".", " ")), + ) + ], + ), + TableRow( + cells: [ + TableCell(child: Text(context.l10n.repository)), + colon, + const TableCell( + child: Hyperlink( + "github.com/KRTirtho/spotube", + "https://github.com/KRTirtho/spotube", + ), ), - ) - ], - ), - TableRow( - cells: [ - TableCell(child: Text(context.l10n.version)), - colon, - TableCell(child: Text("v${packageInfo.version}")) - ], - ), - TableRow( - cells: [ - TableCell(child: Text(context.l10n.channel)), - colon, - TableCell(child: Text(Env.releaseChannel.name)) - ], - ), - TableRow( - cells: [ - TableCell(child: Text(context.l10n.build_number)), - colon, - TableCell( - child: Text( - packageInfo.buildNumber.replaceAll(".", " ")), - ) - ], - ), - TableRow( - cells: [ - TableCell(child: Text(context.l10n.repository)), - colon, - const TableCell( - child: Hyperlink( - "github.com/KRTirtho/spotube", - "https://github.com/KRTirtho/spotube", + ], + ), + TableRow( + cells: [ + TableCell(child: Text(context.l10n.license)), + colon, + const TableCell( + child: Hyperlink( + "BSD-4-Clause", + "https://raw.githubusercontent.com/KRTirtho/spotube/master/LICENSE", + ), ), - ), - ], - ), - TableRow( - cells: [ - TableCell(child: Text(context.l10n.license)), - colon, - const TableCell( - child: Hyperlink( - "BSD-4-Clause", - "https://raw.githubusercontent.com/KRTirtho/spotube/master/LICENSE", + ], + ), + TableRow( + cells: [ + TableCell(child: Text(context.l10n.bug_issues)), + colon, + const TableCell( + child: Hyperlink( + "github.com/KRTirtho/spotube/issues", + "https://github.com/KRTirtho/spotube/issues", + ), ), - ), - ], - ), - TableRow( - cells: [ - TableCell(child: Text(context.l10n.bug_issues)), - colon, - const TableCell( - child: Hyperlink( - "github.com/KRTirtho/spotube/issues", - "https://github.com/KRTirtho/spotube/issues", - ), - ), - ], - ), - ], + ], + ), + ], + ), + ], + ), + ), + const SizedBox(height: 20), + MouseRegion( + cursor: SystemMouseCursors.click, + child: GestureDetector( + onTap: () => launchUrl( + Uri.parse("https://discord.gg/uJ94vxB6vg"), + mode: LaunchMode.externalApplication, + ), + child: const UniversalImage( + path: + "https://discord.com/api/guilds/1012234096237350943/widget.png?style=banner2", ), - ], - ), - ), - const SizedBox(height: 20), - MouseRegion( - cursor: SystemMouseCursors.click, - child: GestureDetector( - onTap: () => launchUrl( - Uri.parse("https://discord.gg/uJ94vxB6vg"), - mode: LaunchMode.externalApplication, - ), - child: const UniversalImage( - path: - "https://discord.com/api/guilds/1012234096237350943/widget.png?style=banner2", ), ), - ), - const SizedBox(height: 20), - Text( - context.l10n.made_with, - textAlign: TextAlign.center, - style: theme.typography.small, - ), - Text( - context.l10n.copyright(DateTime.now().year), - textAlign: TextAlign.center, - style: theme.typography.small, - ), - const SizedBox(height: 20), - ConstrainedBox( - constraints: const BoxConstraints(maxWidth: 750), - child: SafeArea( - child: license.when( - data: (data) { - return Text( - data, - style: theme.typography.small, - ); - }, - loading: () { - return const Center( - child: CircularProgressIndicator(), - ); - }, - error: (e, s) { - return Text( - e.toString(), - style: theme.typography.small, - ); - }, + const SizedBox(height: 20), + Text( + context.l10n.made_with, + textAlign: TextAlign.center, + style: theme.typography.small, + ), + Text( + context.l10n.copyright(DateTime.now().year), + textAlign: TextAlign.center, + style: theme.typography.small, + ), + const SizedBox(height: 20), + ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 750), + child: SafeArea( + child: license.when( + data: (data) { + return Text( + data, + style: theme.typography.small, + ); + }, + loading: () { + return const Center( + child: CircularProgressIndicator(), + ); + }, + error: (e, s) { + return Text( + e.toString(), + style: theme.typography.small, + ); + }, + ), ), ), - ), - ], + ], + ), ), ), ), diff --git a/lib/pages/settings/blacklist.dart b/lib/pages/settings/blacklist.dart index 377a6079..8ac2c1b9 100644 --- a/lib/pages/settings/blacklist.dart +++ b/lib/pages/settings/blacklist.dart @@ -47,50 +47,52 @@ class BlackListPage extends HookConsumerWidget { [blacklist, searchText.value], ); - return Scaffold( - headers: [ - TitleBar( - title: Text(context.l10n.blacklist), - leading: const [BackButton()], - ) - ], - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: TextField( - onChanged: (value) => searchText.value = value, - placeholder: Text(context.l10n.search), - leading: const Icon(SpotubeIcons.search), - ), - ), - InterScrollbar( - controller: controller, - child: ListView.builder( - controller: controller, - shrinkWrap: true, - itemCount: filteredBlacklist.length, - itemBuilder: (context, index) { - final item = filteredBlacklist.elementAt(index); - return ButtonTile( - style: ButtonVariance.ghost, - leading: Text("${index + 1}."), - title: Text("${item.name} (${item.elementType.name})"), - subtitle: Text(item.elementId), - trailing: IconButton.ghost( - icon: Icon(SpotubeIcons.trash, color: Colors.red[400]), - onPressed: () { - ref - .read(blacklistProvider.notifier) - .remove(filteredBlacklist.elementAt(index).elementId); - }, - ), - ); - }, - ), - ), + return SafeArea( + bottom: false, + child: Scaffold( + headers: [ + TitleBar( + title: Text(context.l10n.blacklist), + leading: const [BackButton()], + ) ], + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: TextField( + onChanged: (value) => searchText.value = value, + placeholder: Text(context.l10n.search), + leading: const Icon(SpotubeIcons.search), + ), + ), + InterScrollbar( + controller: controller, + child: ListView.builder( + controller: controller, + shrinkWrap: true, + itemCount: filteredBlacklist.length, + itemBuilder: (context, index) { + final item = filteredBlacklist.elementAt(index); + return ButtonTile( + style: ButtonVariance.ghost, + leading: Text("${index + 1}."), + title: Text("${item.name} (${item.elementType.name})"), + subtitle: Text(item.elementId), + trailing: IconButton.ghost( + icon: Icon(SpotubeIcons.trash, color: Colors.red[400]), + onPressed: () { + ref.read(blacklistProvider.notifier).remove( + filteredBlacklist.elementAt(index).elementId); + }, + ), + ); + }, + ), + ), + ], + ), ), ); } diff --git a/lib/pages/settings/settings.dart b/lib/pages/settings/settings.dart index 53610ae4..0948bdeb 100644 --- a/lib/pages/settings/settings.dart +++ b/lib/pages/settings/settings.dart @@ -34,7 +34,6 @@ class SettingsPage extends HookConsumerWidget { headers: [ TitleBar( title: Text(context.l10n.settings), - automaticallyImplyLeading: true, ) ], child: Scrollbar( diff --git a/lib/pages/stats/albums/albums.dart b/lib/pages/stats/albums/albums.dart index 807b8049..834837af 100644 --- a/lib/pages/stats/albums/albums.dart +++ b/lib/pages/stats/albums/albums.dart @@ -26,31 +26,33 @@ class StatsAlbumsPage extends HookConsumerWidget { final albumsData = topAlbums.asData?.value.items ?? []; - return Scaffold( - headers: [ - TitleBar( - automaticallyImplyLeading: true, - title: Text(context.l10n.albums), - ) - ], - child: Skeletonizer( - enabled: topAlbums.isLoading && !topAlbums.isLoadingNextPage, - child: InfiniteList( - onFetchData: () async { - await topAlbumsNotifier.fetchMore(); - }, - hasError: topAlbums.hasError, - isLoading: topAlbums.isLoading && !topAlbums.isLoadingNextPage, - hasReachedMax: topAlbums.asData?.value.hasMore ?? true, - itemCount: albumsData.length, - itemBuilder: (context, index) { - final album = albumsData[index]; - return StatsAlbumItem( - album: album.album, - info: Text(context.l10n - .count_plays(compactNumberFormatter.format(album.count))), - ); - }, + return SafeArea( + bottom: false, + child: Scaffold( + headers: [ + TitleBar( + title: Text(context.l10n.albums), + ) + ], + child: Skeletonizer( + enabled: topAlbums.isLoading && !topAlbums.isLoadingNextPage, + child: InfiniteList( + onFetchData: () async { + await topAlbumsNotifier.fetchMore(); + }, + hasError: topAlbums.hasError, + isLoading: topAlbums.isLoading && !topAlbums.isLoadingNextPage, + hasReachedMax: topAlbums.asData?.value.hasMore ?? true, + itemCount: albumsData.length, + itemBuilder: (context, index) { + final album = albumsData[index]; + return StatsAlbumItem( + album: album.album, + info: Text(context.l10n + .count_plays(compactNumberFormatter.format(album.count))), + ); + }, + ), ), ), ); diff --git a/lib/pages/stats/artists/artists.dart b/lib/pages/stats/artists/artists.dart index 311faa0c..f3d2f0dd 100644 --- a/lib/pages/stats/artists/artists.dart +++ b/lib/pages/stats/artists/artists.dart @@ -29,31 +29,33 @@ class StatsArtistsPage extends HookConsumerWidget { final artistsData = useMemoized( () => topTracks.asData?.value.artists ?? [], [topTracks.asData?.value]); - return Scaffold( - headers: [ - TitleBar( - automaticallyImplyLeading: true, - title: Text(context.l10n.artists), - ) - ], - child: Skeletonizer( - enabled: topTracks.isLoading && !topTracks.isLoadingNextPage, - child: InfiniteList( - onFetchData: () async { - await topTracksNotifier.fetchMore(); - }, - hasError: topTracks.hasError, - isLoading: topTracks.isLoading && !topTracks.isLoadingNextPage, - hasReachedMax: topTracks.asData?.value.hasMore ?? true, - itemCount: artistsData.length, - itemBuilder: (context, index) { - final artist = artistsData[index]; - return StatsArtistItem( - artist: artist.artist, - info: Text(context.l10n - .count_plays(compactNumberFormatter.format(artist.count))), - ); - }, + return SafeArea( + bottom: false, + child: Scaffold( + headers: [ + TitleBar( + title: Text(context.l10n.artists), + ) + ], + child: Skeletonizer( + enabled: topTracks.isLoading && !topTracks.isLoadingNextPage, + child: InfiniteList( + onFetchData: () async { + await topTracksNotifier.fetchMore(); + }, + hasError: topTracks.hasError, + isLoading: topTracks.isLoading && !topTracks.isLoadingNextPage, + hasReachedMax: topTracks.asData?.value.hasMore ?? true, + itemCount: artistsData.length, + itemBuilder: (context, index) { + final artist = artistsData[index]; + return StatsArtistItem( + artist: artist.artist, + info: Text(context.l10n + .count_plays(compactNumberFormatter.format(artist.count))), + ); + }, + ), ), ), ); diff --git a/lib/pages/stats/fees/fees.dart b/lib/pages/stats/fees/fees.dart index 8a20758d..6df911ce 100644 --- a/lib/pages/stats/fees/fees.dart +++ b/lib/pages/stats/fees/fees.dart @@ -50,79 +50,83 @@ class StatsStreamFeesPage extends HookConsumerWidget { HistoryDuration.allTime: context.l10n.all_time, }; - return Scaffold( - headers: [ - TitleBar( - automaticallyImplyLeading: true, - title: Text(context.l10n.streaming_fees_hypothetical), - ) - ], - child: CustomScrollView( - slivers: [ - SliverCrossAxisConstrained( - maxCrossAxisExtent: 600, - alignment: -1, - child: SliverPadding( - padding: const EdgeInsets.all(16.0), - sliver: SliverToBoxAdapter( - child: Text( - context.l10n.spotify_hipotetical_calculation, - ).small().muted(), - ), - ), - ), - SliverToBoxAdapter( - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - context.l10n.total_money(usdFormatter.format(total)), - ).semiBold().large(), - Select( - value: duration.value, - onChanged: (value) { - if (value == null) return; - duration.value = value; - }, - itemBuilder: (context, value) => Text(translations[value]!), - constraints: const BoxConstraints(maxWidth: 150), - popupWidthConstraint: PopoverConstraint.anchorMaxSize, - children: [ - for (final entry in translations.entries) - SelectItemButton( - value: entry.key, - child: Text(entry.value), - ), - ], - ), - ], - ), - ), - ), - SliverSafeArea( - sliver: Skeletonizer.sliver( - enabled: topTracks.isLoading && !topTracks.isLoadingNextPage, - child: SliverInfiniteList( - onFetchData: () async { - await topTracksNotifier.fetchMore(); - }, - hasError: topTracks.hasError, - isLoading: topTracks.isLoading && !topTracks.isLoadingNextPage, - hasReachedMax: topTracks.asData?.value.hasMore ?? true, - itemCount: artistsData.length, - itemBuilder: (context, index) { - final artist = artistsData[index]; - return StatsArtistItem( - artist: artist.artist, - info: Text(usdFormatter.format(artist.count * 0.005)), - ); - }, - ), - ), - ), + return SafeArea( + bottom: false, + child: Scaffold( + headers: [ + TitleBar( + title: Text(context.l10n.streaming_fees_hypothetical), + ) ], + child: CustomScrollView( + slivers: [ + SliverCrossAxisConstrained( + maxCrossAxisExtent: 600, + alignment: -1, + child: SliverPadding( + padding: const EdgeInsets.all(16.0), + sliver: SliverToBoxAdapter( + child: Text( + context.l10n.spotify_hipotetical_calculation, + ).small().muted(), + ), + ), + ), + SliverToBoxAdapter( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + context.l10n.total_money(usdFormatter.format(total)), + ).semiBold().large(), + Select( + value: duration.value, + onChanged: (value) { + if (value == null) return; + duration.value = value; + }, + itemBuilder: (context, value) => + Text(translations[value]!), + constraints: const BoxConstraints(maxWidth: 150), + popupWidthConstraint: PopoverConstraint.anchorMaxSize, + children: [ + for (final entry in translations.entries) + SelectItemButton( + value: entry.key, + child: Text(entry.value), + ), + ], + ), + ], + ), + ), + ), + SliverSafeArea( + sliver: Skeletonizer.sliver( + enabled: topTracks.isLoading && !topTracks.isLoadingNextPage, + child: SliverInfiniteList( + onFetchData: () async { + await topTracksNotifier.fetchMore(); + }, + hasError: topTracks.hasError, + isLoading: + topTracks.isLoading && !topTracks.isLoadingNextPage, + hasReachedMax: topTracks.asData?.value.hasMore ?? true, + itemCount: artistsData.length, + itemBuilder: (context, index) { + final artist = artistsData[index]; + return StatsArtistItem( + artist: artist.artist, + info: Text(usdFormatter.format(artist.count * 0.005)), + ); + }, + ), + ), + ), + ], + ), ), ); } diff --git a/lib/pages/stats/minutes/minutes.dart b/lib/pages/stats/minutes/minutes.dart index df7f5983..2ee4c8d7 100644 --- a/lib/pages/stats/minutes/minutes.dart +++ b/lib/pages/stats/minutes/minutes.dart @@ -28,34 +28,36 @@ class StatsMinutesPage extends HookConsumerWidget { final tracksData = topTracks.asData?.value.items ?? []; - return Scaffold( - headers: [ - TitleBar( - title: Text(context.l10n.minutes_listened), - automaticallyImplyLeading: true, - ) - ], - child: Skeletonizer( - enabled: topTracks.isLoading && !topTracks.isLoadingNextPage, - child: InfiniteList( - separatorBuilder: (context, index) => const Gap(8), - onFetchData: () async { - await topTracksNotifier.fetchMore(); - }, - hasError: topTracks.hasError, - isLoading: topTracks.isLoading && !topTracks.isLoadingNextPage, - hasReachedMax: topTracks.asData?.value.hasMore ?? true, - itemCount: tracksData.length, - itemBuilder: (context, index) { - final track = tracksData[index]; - return StatsTrackItem( - track: track.track, - info: Text( - context.l10n.count_mins(compactNumberFormatter - .format(track.count * track.track.duration!.inMinutes)), - ), - ); - }, + return SafeArea( + bottom: false, + child: Scaffold( + headers: [ + TitleBar( + title: Text(context.l10n.minutes_listened), + ) + ], + child: Skeletonizer( + enabled: topTracks.isLoading && !topTracks.isLoadingNextPage, + child: InfiniteList( + separatorBuilder: (context, index) => const Gap(8), + onFetchData: () async { + await topTracksNotifier.fetchMore(); + }, + hasError: topTracks.hasError, + isLoading: topTracks.isLoading && !topTracks.isLoadingNextPage, + hasReachedMax: topTracks.asData?.value.hasMore ?? true, + itemCount: tracksData.length, + itemBuilder: (context, index) { + final track = tracksData[index]; + return StatsTrackItem( + track: track.track, + info: Text( + context.l10n.count_mins(compactNumberFormatter + .format(track.count * track.track.duration!.inMinutes)), + ), + ); + }, + ), ), ), ); diff --git a/lib/pages/stats/playlists/playlists.dart b/lib/pages/stats/playlists/playlists.dart index 78c3cd24..03ea5126 100644 --- a/lib/pages/stats/playlists/playlists.dart +++ b/lib/pages/stats/playlists/playlists.dart @@ -27,33 +27,36 @@ class StatsPlaylistsPage extends HookConsumerWidget { final playlistsData = topPlaylists.asData?.value.items ?? []; - return Scaffold( - headers: [ - TitleBar( - automaticallyImplyLeading: true, - title: Text(context.l10n.playlists), - ) - ], - child: Skeletonizer( - enabled: topPlaylists.isLoading && !topPlaylists.isLoadingNextPage, - child: InfiniteList( - onFetchData: () async { - await topPlaylistsNotifier.fetchMore(); - }, - hasError: topPlaylists.hasError, - isLoading: topPlaylists.isLoading && !topPlaylists.isLoadingNextPage, - hasReachedMax: topPlaylists.asData?.value.hasMore ?? true, - itemCount: playlistsData.length, - itemBuilder: (context, index) { - final playlist = playlistsData[index]; - return StatsPlaylistItem( - playlist: playlist.playlist, - info: Text( - context.l10n - .count_plays(compactNumberFormatter.format(playlist.count)), - ), - ); - }, + return SafeArea( + bottom: false, + child: Scaffold( + headers: [ + TitleBar( + title: Text(context.l10n.playlists), + ) + ], + child: Skeletonizer( + enabled: topPlaylists.isLoading && !topPlaylists.isLoadingNextPage, + child: InfiniteList( + onFetchData: () async { + await topPlaylistsNotifier.fetchMore(); + }, + hasError: topPlaylists.hasError, + isLoading: + topPlaylists.isLoading && !topPlaylists.isLoadingNextPage, + hasReachedMax: topPlaylists.asData?.value.hasMore ?? true, + itemCount: playlistsData.length, + itemBuilder: (context, index) { + final playlist = playlistsData[index]; + return StatsPlaylistItem( + playlist: playlist.playlist, + info: Text( + context.l10n.count_plays( + compactNumberFormatter.format(playlist.count)), + ), + ); + }, + ), ), ), ); diff --git a/lib/pages/stats/streams/streams.dart b/lib/pages/stats/streams/streams.dart index 05e53d7c..0d919a44 100644 --- a/lib/pages/stats/streams/streams.dart +++ b/lib/pages/stats/streams/streams.dart @@ -28,34 +28,36 @@ class StatsStreamsPage extends HookConsumerWidget { final tracksData = topTracks.asData?.value.items ?? []; - return Scaffold( - headers: [ - TitleBar( - title: Text(context.l10n.streamed_songs), - automaticallyImplyLeading: true, - ) - ], - child: Skeletonizer( - enabled: topTracks.isLoading && !topTracks.isLoadingNextPage, - child: InfiniteList( - separatorBuilder: (context, index) => const Gap(8), - onFetchData: () async { - await topTracksNotifier.fetchMore(); - }, - hasError: topTracks.hasError, - isLoading: topTracks.isLoading && !topTracks.isLoadingNextPage, - hasReachedMax: topTracks.asData?.value.hasMore ?? true, - itemCount: tracksData.length, - itemBuilder: (context, index) { - final track = tracksData[index]; - return StatsTrackItem( - track: track.track, - info: Text( - context.l10n - .count_plays(compactNumberFormatter.format(track.count)), - ), - ); - }, + return SafeArea( + bottom: false, + child: Scaffold( + headers: [ + TitleBar( + title: Text(context.l10n.streamed_songs), + ) + ], + child: Skeletonizer( + enabled: topTracks.isLoading && !topTracks.isLoadingNextPage, + child: InfiniteList( + separatorBuilder: (context, index) => const Gap(8), + onFetchData: () async { + await topTracksNotifier.fetchMore(); + }, + hasError: topTracks.hasError, + isLoading: topTracks.isLoading && !topTracks.isLoadingNextPage, + hasReachedMax: topTracks.asData?.value.hasMore ?? true, + itemCount: tracksData.length, + itemBuilder: (context, index) { + final track = tracksData[index]; + return StatsTrackItem( + track: track.track, + info: Text( + context.l10n + .count_plays(compactNumberFormatter.format(track.count)), + ), + ); + }, + ), ), ), ); diff --git a/lib/pages/track/track.dart b/lib/pages/track/track.dart index 765969be..0f8dae5d 100644 --- a/lib/pages/track/track.dart +++ b/lib/pages/track/track.dart @@ -54,197 +54,200 @@ class TrackPage extends HookConsumerWidget { } } - return Scaffold( - headers: const [ - TitleBar( - automaticallyImplyLeading: true, - backgroundColor: Colors.transparent, - surfaceBlur: 0, - ) - ], - floatingHeader: true, - child: Stack( - children: [ - Positioned.fill( - child: Container( - decoration: BoxDecoration( - image: DecorationImage( - image: UniversalImage.imageProvider( - track.album!.images.asUrlString( - placeholder: ImagePlaceholder.albumArt, + return SafeArea( + bottom: false, + child: Scaffold( + headers: const [ + TitleBar( + backgroundColor: Colors.transparent, + surfaceBlur: 0, + ) + ], + floatingHeader: true, + child: Stack( + children: [ + Positioned.fill( + child: Container( + decoration: BoxDecoration( + image: DecorationImage( + image: UniversalImage.imageProvider( + track.album!.images.asUrlString( + placeholder: ImagePlaceholder.albumArt, + ), ), + fit: BoxFit.cover, + colorFilter: ColorFilter.mode( + colorScheme.background.withOpacity(0.5), + BlendMode.srcOver, + ), + alignment: Alignment.topCenter, ), - fit: BoxFit.cover, - colorFilter: ColorFilter.mode( - colorScheme.background.withOpacity(0.5), - BlendMode.srcOver, - ), - alignment: Alignment.topCenter, ), ), ), - ), - Positioned.fill( - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10), - child: Skeletonizer( - enabled: trackQuery.isLoading, - child: Container( - alignment: Alignment.topCenter, - decoration: BoxDecoration( - gradient: LinearGradient( - colors: [ - colorScheme.background, - Colors.transparent, - ], - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - stops: const [0.2, 1], + Positioned.fill( + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10), + child: Skeletonizer( + enabled: trackQuery.isLoading, + child: Container( + alignment: Alignment.topCenter, + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + colorScheme.background, + Colors.transparent, + ], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + stops: const [0.2, 1], + ), ), - ), - child: SafeArea( - child: Wrap( - spacing: 20, - runSpacing: 20, - alignment: WrapAlignment.center, - crossAxisAlignment: WrapCrossAlignment.center, - runAlignment: WrapAlignment.center, - children: [ - ClipRRect( - borderRadius: BorderRadius.circular(10), - child: UniversalImage( - path: track.album!.images.asUrlString( - placeholder: ImagePlaceholder.albumArt, + child: SafeArea( + child: Wrap( + spacing: 20, + runSpacing: 20, + alignment: WrapAlignment.center, + crossAxisAlignment: WrapCrossAlignment.center, + runAlignment: WrapAlignment.center, + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(10), + child: UniversalImage( + path: track.album!.images.asUrlString( + placeholder: ImagePlaceholder.albumArt, + ), + height: 200, + width: 200, ), - height: 200, - width: 200, ), - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: Column( - crossAxisAlignment: mediaQuery.smAndDown - ? CrossAxisAlignment.center - : CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Text( - track.name!, - ).large().semiBold(), - const Gap(10), - Row( - mainAxisSize: MainAxisSize.min, - children: [ - const Icon(SpotubeIcons.album), - const Gap(5), - Flexible( - child: LinkText( - track.album!.name!, - AlbumRoute( - id: track.album!.id!, - album: track.album!, - ), - push: true, - ), - ), - ], - ), - const Gap(10), - Row( - mainAxisSize: MainAxisSize.min, - children: [ - const Icon(SpotubeIcons.artist), - const Gap(5), - Flexible( - child: ArtistLink( - artists: track.artists!, - hideOverflowArtist: false, - ), - ), - ], - ), - const Gap(10), - ConstrainedBox( - constraints: - const BoxConstraints(maxWidth: 350), - child: Row( - mainAxisSize: mediaQuery.smAndDown - ? MainAxisSize.max - : MainAxisSize.min, + Padding( + padding: + const EdgeInsets.symmetric(horizontal: 16.0), + child: Column( + crossAxisAlignment: mediaQuery.smAndDown + ? CrossAxisAlignment.center + : CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + track.name!, + ).large().semiBold(), + const Gap(10), + Row( + mainAxisSize: MainAxisSize.min, children: [ + const Icon(SpotubeIcons.album), const Gap(5), - if (!isActive && - !playlist.tracks - .containsBy(track, (t) => t.id)) - Button.outline( - leading: - const Icon(SpotubeIcons.queueAdd), - child: Text(context.l10n.queue), - onPressed: () { - playlistNotifier.addTrack(track); - }, - ), - const Gap(5), - if (!isActive && - !playlist.tracks - .containsBy(track, (t) => t.id)) - Tooltip( - tooltip: TooltipContainer( - child: Text(context.l10n.play_next), + Flexible( + child: LinkText( + track.album!.name!, + AlbumRoute( + id: track.album!.id!, + album: track.album!, ), - child: IconButton.outline( - icon: const Icon( - SpotubeIcons.lightning), - onPressed: () { - playlistNotifier - .addTracksAtFirst([track]); - }, - ), - ), - const Gap(5), - Tooltip( - tooltip: TooltipContainer( - child: Text( - isActive - ? context.l10n.pause_playback - : context.l10n.play, - ), - ), - child: IconButton.primary( - shape: ButtonShape.circle, - icon: Icon( - isActive - ? SpotubeIcons.pause - : SpotubeIcons.play, - ), - onPressed: onPlay, + push: true, ), ), - const Gap(5), - if (mediaQuery.smAndDown) - const Spacer() - else - const Gap(20), - TrackHeartButton(track: track), - TrackOptions( - track: track, - userPlaylist: false, - ), - const Gap(5), ], ), - ), - ], + const Gap(10), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(SpotubeIcons.artist), + const Gap(5), + Flexible( + child: ArtistLink( + artists: track.artists!, + hideOverflowArtist: false, + ), + ), + ], + ), + const Gap(10), + ConstrainedBox( + constraints: + const BoxConstraints(maxWidth: 350), + child: Row( + mainAxisSize: mediaQuery.smAndDown + ? MainAxisSize.max + : MainAxisSize.min, + children: [ + const Gap(5), + if (!isActive && + !playlist.tracks + .containsBy(track, (t) => t.id)) + Button.outline( + leading: + const Icon(SpotubeIcons.queueAdd), + child: Text(context.l10n.queue), + onPressed: () { + playlistNotifier.addTrack(track); + }, + ), + const Gap(5), + if (!isActive && + !playlist.tracks + .containsBy(track, (t) => t.id)) + Tooltip( + tooltip: TooltipContainer( + child: Text(context.l10n.play_next), + ), + child: IconButton.outline( + icon: const Icon( + SpotubeIcons.lightning), + onPressed: () { + playlistNotifier + .addTracksAtFirst([track]); + }, + ), + ), + const Gap(5), + Tooltip( + tooltip: TooltipContainer( + child: Text( + isActive + ? context.l10n.pause_playback + : context.l10n.play, + ), + ), + child: IconButton.primary( + shape: ButtonShape.circle, + icon: Icon( + isActive + ? SpotubeIcons.pause + : SpotubeIcons.play, + ), + onPressed: onPlay, + ), + ), + const Gap(5), + if (mediaQuery.smAndDown) + const Spacer() + else + const Gap(20), + TrackHeartButton(track: track), + TrackOptions( + track: track, + userPlaylist: false, + ), + const Gap(5), + ], + ), + ), + ], + ), ), - ), - ], + ], + ), ), ), ), ), ), - ), - ], + ], + ), ), ); } From b1780e0cf8226a38d8f4c33e3b2bd35d08e019a3 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 1 Feb 2025 19:14:50 +0600 Subject: [PATCH 095/112] fix: duplicates in recent section --- .github/ISSUE_TEMPLATE/bug_report.yml | 12 +++-- lib/pages/settings/about.dart | 4 +- lib/provider/history/recent.dart | 69 ++++++++++++--------------- 3 files changed, 41 insertions(+), 44 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index a9c57836..d4872798 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -9,7 +9,8 @@ body: attributes: label: Is there an existing issue for this? (Please read the description) description: | - PLEASE! Make sure to check if this issue is a duplicate. + 🚨 PLEASE! Make sure to check if this issue is a duplicate. 🚨 + Don't waste our time, we are working hard to make Spotube better for you. Try with multiple similar keywords, and check the closed issues too. @@ -50,7 +51,7 @@ body: value: |

Logs - + ``` ``` @@ -60,7 +61,7 @@ body: - type: input attributes: label: Operating System - description: The OS in which you used Spotube to face the issue. + description: The OS in which you used Spotube to face the issue. Use comma to separate multiple OS. placeholder: Android, Linux, macOS or Windows? Make sure to include the version too. validations: required: true @@ -96,7 +97,10 @@ body: - type: checkboxes attributes: label: Self grab - description: If you are a developer and want to work on this issue yourself, you can check this box and wait for maintainer response. Any contributions are welcome! + description: | + If you are a developer and want to work on this issue yourself, you can check this box and wait for maintainer response. Any contributions are welcome! + + This project is maintained by one person. So PRs are always welcome. This is the best way to get your issue fixed faster. options: - label: I'm ready to work on this issue! required: false diff --git a/lib/pages/settings/about.dart b/lib/pages/settings/about.dart index 1837bbec..1552c7e5 100644 --- a/lib/pages/settings/about.dart +++ b/lib/pages/settings/about.dart @@ -128,8 +128,8 @@ class AboutSpotubePage extends HookConsumerWidget { colon, const TableCell( child: Hyperlink( - "github.com/KRTirtho/spotube/issues", - "https://github.com/KRTirtho/spotube/issues", + "Discord", + "https://discord.gg/uJ94vxB6vg", ), ), ], diff --git a/lib/provider/history/recent.dart b/lib/provider/history/recent.dart index ef393a17..1ee2a5d6 100644 --- a/lib/provider/history/recent.dart +++ b/lib/provider/history/recent.dart @@ -1,6 +1,7 @@ -import 'package:collection/collection.dart'; -import 'package:drift/drift.dart'; +import 'dart:convert'; + import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/models/database/database.dart'; import 'package:spotube/provider/database/database.dart'; @@ -9,48 +10,40 @@ class RecentlyPlayedItemNotifier extends AsyncNotifier> { build() async { final database = ref.watch(databaseProvider); - final uniqueItemIds = await (database.selectOnly( - database.historyTable, - distinct: true, - ) - ..addColumns([database.historyTable.itemId, database.historyTable.id]) - ..where( - database.historyTable.type.isInValues([ - HistoryEntryType.playlist, - HistoryEntryType.album, - ]), - ) - ..limit(10) - ..orderBy([ - OrderingTerm( - expression: database.historyTable.createdAt, - mode: OrderingMode.desc, - ), - ])) - .map( - (row) => row.read(database.historyTable.id), - ) - .get() - .then((value) => value.whereNotNull().toList()); - - final query = database.select(database.historyTable) - ..where( - (tbl) => tbl.id.isIn(uniqueItemIds), + final query = database.customSelect( + """ + WITH RankedHistory AS ( + SELECT *, ROW_NUMBER() OVER (PARTITION BY item_id ORDER BY created_at DESC) AS rn + FROM history_table + WHERE type in ('playlist', 'album') ) - ..orderBy([ - (tbl) => OrderingTerm( - expression: tbl.createdAt, - mode: OrderingMode.desc, - ), - ]); + SELECT * + FROM RankedHistory + WHERE rn = 1 + ORDER BY created_at DESC + LIMIT 10 + """, + readsFrom: {database.historyTable}, + ).map((rows) async { + return await rows.map((row) { + final type = row.read('type'); + return HistoryTableData( + id: row.read('id'), + itemId: row.read('item_id'), + type: HistoryEntryType.values.firstWhere((e) => e.name == type), + createdAt: row.read('created_at'), + data: jsonDecode(row.read('data')) as Map, + ); + }); + }); - final subscription = query.watch().listen((event) { - state = AsyncData(event); + final subscription = query.watch().listen((event) async { + state = AsyncData(await Future.wait(event)); }); ref.onDispose(() => subscription.cancel()); - final items = await query.get(); + final items = await Future.wait(await query.get()); return items; } From 043eaba81f1e27d468d0ab2d83c17e243060b9a0 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 3 Feb 2025 20:53:48 +0600 Subject: [PATCH 096/112] fix: youtube source taking too long to buffer --- lib/modules/player/player_controls.dart | 1 + lib/pages/settings/about.dart | 2 +- .../sourced_track/sources/youtube.dart | 44 +++++++------------ 3 files changed, 17 insertions(+), 30 deletions(-) diff --git a/lib/modules/player/player_controls.dart b/lib/modules/player/player_controls.dart index 964ff54f..4d5d6deb 100644 --- a/lib/modules/player/player_controls.dart +++ b/lib/modules/player/player_controls.dart @@ -93,6 +93,7 @@ class PlayerControls extends HookConsumerWidget { child: SizedBox( width: mediaQuery.xlAndUp ? 600 : 500, child: Slider( + hintValue: SliderValue.single(bufferProgress), value: SliderValue.single(progress.value.toDouble()), onChanged: isFetchingActiveTrack diff --git a/lib/pages/settings/about.dart b/lib/pages/settings/about.dart index 1552c7e5..92143d96 100644 --- a/lib/pages/settings/about.dart +++ b/lib/pages/settings/about.dart @@ -128,7 +128,7 @@ class AboutSpotubePage extends HookConsumerWidget { colon, const TableCell( child: Hyperlink( - "Discord", + "Discord#chat", "https://discord.gg/uJ94vxB6vg", ), ), diff --git a/lib/services/sourced_track/sources/youtube.dart b/lib/services/sourced_track/sources/youtube.dart index fa13a25d..0b5e1b2a 100644 --- a/lib/services/sourced_track/sources/youtube.dart +++ b/lib/services/sourced_track/sources/youtube.dart @@ -1,7 +1,6 @@ import 'package:collection/collection.dart'; import 'package:drift/drift.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:http/http.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/models/database/database.dart'; import 'package:spotube/provider/database/database.dart'; @@ -44,6 +43,18 @@ class YoutubeSourcedTrack extends SourcedTrack { required super.ref, }); + static Future _getStreamManifest(String id) async { + return youtubeClient.videos.streamsClient.getManifest( + id, + requireWatchPage: false, + ytClients: [ + YoutubeApiClient.android, + YoutubeApiClient.mweb, + YoutubeApiClient.safari, + ], + ); + } + static Future fetchFromTrack({ required Track track, required Ref ref, @@ -82,17 +93,7 @@ class YoutubeSourcedTrack extends SourcedTrack { ); } final item = await youtubeClient.videos.get(cachedSource.sourceId); - final manifest = await youtubeClient.videos.streamsClient.getManifest( - cachedSource.sourceId, - requireWatchPage: false, - ytClients: [ - YoutubeApiClient.mediaConnect, - YoutubeApiClient.ios, - YoutubeApiClient.android, - YoutubeApiClient.mweb, - YoutubeApiClient.tv, - ], - ); + final manifest = await _getStreamManifest(cachedSource.sourceId); return YoutubeSourcedTrack( ref: ref, siblings: [], @@ -144,17 +145,7 @@ class YoutubeSourcedTrack extends SourcedTrack { ) async { SourceMap? sourceMap; if (index == 0) { - final manifest = await youtubeClient.videos.streamsClient.getManifest( - item.id, - requireWatchPage: false, - ytClients: [ - YoutubeApiClient.mediaConnect, - YoutubeApiClient.ios, - YoutubeApiClient.android, - YoutubeApiClient.mweb, - YoutubeApiClient.tv, - ], - ); + final manifest = await _getStreamManifest(item.id); sourceMap = toSourceMap(manifest); } @@ -294,12 +285,7 @@ class YoutubeSourcedTrack extends SourcedTrack { final newSiblings = siblings.where((s) => s.id != sibling.id).toList() ..insert(0, sourceInfo); - final manifest = await youtubeClient.videos.streamsClient - .getManifest(newSourceInfo.id) - .timeout( - const Duration(seconds: 5), - onTimeout: () => throw ClientException("Timeout"), - ); + final manifest = await _getStreamManifest(newSourceInfo.id); final database = ref.read(databaseProvider); From 698fb6ba2793eb1332dfa00f3f94e7c78646681b Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 5 Feb 2025 00:36:23 +0600 Subject: [PATCH 097/112] fix: youtube tracks keeps skipping despite being matched correctly --- lib/pages/settings/sections/playback.dart | 2 +- .../audio_player/audio_player_streams.dart | 12 ++-- lib/provider/server/routes/playback.dart | 58 ++++++++++++++----- lib/provider/server/sourced_track.dart | 13 +++++ lib/services/logger/logger.dart | 2 +- .../sourced_track/sources/youtube.dart | 24 +++++++- 6 files changed, 90 insertions(+), 21 deletions(-) diff --git a/lib/pages/settings/sections/playback.dart b/lib/pages/settings/sections/playback.dart index 537156d0..363e228c 100644 --- a/lib/pages/settings/sections/playback.dart +++ b/lib/pages/settings/sections/playback.dart @@ -197,7 +197,7 @@ class SettingsPlaybackSection extends HookConsumerWidget { ), AnimatedCrossFade( duration: const Duration(milliseconds: 300), - crossFadeState: preferences.audioSource != AudioSource.youtube + crossFadeState: preferences.audioSource == AudioSource.youtube ? CrossFadeState.showFirst : CrossFadeState.showSecond, firstChild: const SizedBox.shrink(), diff --git a/lib/provider/audio_player/audio_player_streams.dart b/lib/provider/audio_player/audio_player_streams.dart index 880f643f..54c6d7cd 100644 --- a/lib/provider/audio_player/audio_player_streams.dart +++ b/lib/provider/audio_player/audio_player_streams.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:math'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotube/models/local_track.dart'; @@ -103,16 +104,19 @@ class AudioPlayerStreamListeners { StreamSubscription subscribeToPosition() { String lastTrack = ""; // used to prevent multiple calls to the same track return audioPlayer.positionStream.listen((event) async { + final percentProgress = + (event.inSeconds / max(audioPlayer.duration.inSeconds, 1)) * 100; try { - if (event < const Duration(seconds: 3) || + if (percentProgress < 80 || audioPlayerState.playlist.index == -1 || audioPlayerState.playlist.index == audioPlayerState.tracks.length - 1) { return; } - final nextTrack = SpotubeMedia.fromMedia(audioPlayerState - .playlist.medias - .elementAt(audioPlayerState.playlist.index + 1)); + final nextTrack = SpotubeMedia.fromMedia( + audioPlayerState.playlist.medias + .elementAt(audioPlayerState.playlist.index + 1), + ); if (lastTrack == nextTrack.track.id || nextTrack.track is LocalTrack) { return; diff --git a/lib/provider/server/routes/playback.dart b/lib/provider/server/routes/playback.dart index 289da0e3..3a480248 100644 --- a/lib/provider/server/routes/playback.dart +++ b/lib/provider/server/routes/playback.dart @@ -1,4 +1,5 @@ import 'dart:io'; +import 'dart:math'; import 'package:dio/dio.dart' hide Response; import 'package:dio/dio.dart' as dio_lib; @@ -10,6 +11,7 @@ import 'package:shelf/shelf.dart'; import 'package:spotube/extensions/artist_simple.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/extensions/track.dart'; +import 'package:spotube/models/database/database.dart'; import 'package:spotube/models/parser/range_headers.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/provider/audio_player/state.dart'; @@ -22,6 +24,20 @@ import 'package:spotube/services/logger/logger.dart'; import 'package:spotube/services/sourced_track/enums.dart'; import 'package:spotube/services/sourced_track/sourced_track.dart'; import 'package:spotube/utils/service_utils.dart'; +import 'package:youtube_explode_dart/youtube_explode_dart.dart'; + +const _deviceClients = { + YoutubeApiClient.android, + YoutubeApiClient.ios, + YoutubeApiClient.mweb, + YoutubeApiClient.safari, +}; + +String? get _randomUserAgent => _deviceClients + .elementAt( + Random().nextInt(_deviceClients.length), + ) + .payload["context"]["client"]["userAgent"]; class ServerPlaybackRoutes { final Ref ref; @@ -47,9 +63,8 @@ class ServerPlaybackRoutes { var options = Options( headers: { ...headers, - "User-Agent": - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36", - "Cache-Control": "max-age=0", + "user-agent": _randomUserAgent, + "Cache-Control": "max-age=3600", "Connection": "keep-alive", "host": Uri.parse(track.url).host, }, @@ -100,18 +115,35 @@ class ServerPlaybackRoutes { ); } - final res = - await dio.get(track.url, options: options).catchError( - (e, stack) async { - final sourcedTrack = await ref - .read(sourcedTrackProvider(SpotubeMedia(track)).notifier) - .switchToAlternativeSources(); + final res = await dio + .get( + track.url, + options: options.copyWith(headers: { + ...?options.headers, + "user-agent": _randomUserAgent, + }), + ) + .catchError((e, stack) async { + AppLogger.reportError(e, stack); + final sourcedTrack = userPreferences.audioSource == AudioSource.youtube && + e is DioException + ? await ref + .read(sourcedTrackProvider(SpotubeMedia(track)).notifier) + .refreshStreamingUrl() + : await ref + .read(sourcedTrackProvider(SpotubeMedia(track)).notifier) + .switchToAlternativeSources(); - ref.read(activeSourcedTrackProvider.notifier).update(sourcedTrack); + ref.read(activeSourcedTrackProvider.notifier).update(sourcedTrack); - return await dio.get(sourcedTrack!.url, options: options); - }, - ); + return await dio.get( + sourcedTrack!.url, + options: options.copyWith(headers: { + ...?options.headers, + "user-agent": _randomUserAgent, + }), + ); + }); final bytes = res.data; diff --git a/lib/provider/server/sourced_track.dart b/lib/provider/server/sourced_track.dart index 58531523..2081ac0a 100644 --- a/lib/provider/server/sourced_track.dart +++ b/lib/provider/server/sourced_track.dart @@ -29,6 +29,19 @@ class SourcedTrackNotifier return sourcedTrack; } + Future refreshStreamingUrl() async { + if (arg == null) { + return null; + } + + return await update((prev) async { + return await SourcedTrack.fetchFromTrack( + track: state.value!, + ref: ref, + ); + }); + } + Future switchToAlternativeSources() async { if (arg == null) { return null; diff --git a/lib/services/logger/logger.dart b/lib/services/logger/logger.dart index d1595930..1f15bf92 100644 --- a/lib/services/logger/logger.dart +++ b/lib/services/logger/logger.dart @@ -38,7 +38,7 @@ class AppLogger { if (!kDebugMode) return; logging.hierarchicalLoggingEnabled = true; logging.Logger('YoutubeExplode.StreamsClient') - ..level = logging.Level.ALL + ..level = logging.Level.SEVERE ..onRecord.listen( (record) { log.log( diff --git a/lib/services/sourced_track/sources/youtube.dart b/lib/services/sourced_track/sources/youtube.dart index 0b5e1b2a..f54b1772 100644 --- a/lib/services/sourced_track/sources/youtube.dart +++ b/lib/services/sourced_track/sources/youtube.dart @@ -50,7 +50,6 @@ class YoutubeSourcedTrack extends SourcedTrack { ytClients: [ YoutubeApiClient.android, YoutubeApiClient.mweb, - YoutubeApiClient.safari, ], ); } @@ -59,6 +58,23 @@ class YoutubeSourcedTrack extends SourcedTrack { required Track track, required Ref ref, }) async { + // Indicates the track is requesting a stream refresh + if (track is YoutubeSourcedTrack) { + final manifest = await _getStreamManifest(track.sourceInfo.id); + + final sourcedTrack = YoutubeSourcedTrack( + ref: ref, + siblings: track.siblings, + source: toSourceMap(manifest), + sourceInfo: track.sourceInfo, + track: track, + ); + + AppLogger.log.i("Refreshing ${track.name}: ${sourcedTrack.url}"); + + return sourcedTrack; + } + final database = ref.read(databaseProvider); final cachedSource = await (database.select(database.sourceMatchTable) ..where((s) => s.trackId.equals(track.id!)) @@ -94,7 +110,7 @@ class YoutubeSourcedTrack extends SourcedTrack { } final item = await youtubeClient.videos.get(cachedSource.sourceId); final manifest = await _getStreamManifest(cachedSource.sourceId); - return YoutubeSourcedTrack( + final sourcedTrack = YoutubeSourcedTrack( ref: ref, siblings: [], source: toSourceMap(manifest), @@ -110,6 +126,10 @@ class YoutubeSourcedTrack extends SourcedTrack { ), track: track, ); + + AppLogger.log.i("${track.name}: ${sourcedTrack.url}"); + + return sourcedTrack; } static SourceMap toSourceMap(StreamManifest manifest) { From 1e6d709e04eb81381fc5c4090f2bec6e55e10b96 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Tue, 11 Feb 2025 21:36:07 +0600 Subject: [PATCH 098/112] feat: implement yt-dlp for desktop and NewPipeExtractor for Android (#2316) * feat: add youtube engine abstraction and yt-dlp integration * chore: add yt-dlp as optional dependency * feat: implement custom path support for youtube engines * chore: check for custom path in setting engine select dropdown * chore: update yt_dlp_dart * chore: setting video url instead of video id in fetchSiblings * feat: implement NewPipe engine * chore: update local path to git url for flutter_new_pipe_extractor package * chore: fix android build isn't working * chore: fix routes not working when initially signing in * refactor: drop fallback support to different sources --- .github/workflows/pr-lint.yml | 2 +- Makefile | 9 +- android/app/build.gradle | 3 + android/app/proguard-rules.pro | 13 + aur-struct/.SRCINFO | 1 + aur-struct/PKGBUILD | 2 +- drift_schemas/app_db/drift_schema_v4.json | 1 + lib/collections/routes.dart | 28 +- lib/collections/spotube_icons.dart | 1 + .../use_check_yt_dlp_installed.dart | 40 + lib/l10n/app_en.arb | 9 +- lib/main.dart | 17 +- lib/models/database/database.dart | 11 +- lib/models/database/database.g.dart | 77 + lib/models/database/database.steps.dart | 293 +- lib/models/database/tables/preferences.dart | 22 + lib/modules/player/sibling_tracks_sheet.dart | 12 +- .../youtube_engine_not_installed_dialog.dart | 121 + lib/pages/root/root_app.dart | 3 + lib/pages/settings/sections/playback.dart | 77 +- .../local_tracks/local_tracks_provider.dart | 3 +- lib/provider/server/routes/playback.dart | 12 +- lib/provider/server/sourced_track.dart | 12 - lib/provider/spotify/category/playlists.dart | 2 +- .../user_preferences_provider.dart | 4 + .../youtube_engine/youtube_engine.dart | 22 + lib/services/kv_store/kv_store.dart | 28 + lib/services/sourced_track/sourced_track.dart | 113 +- .../sourced_track/sources/invidious.dart | 16 + lib/services/sourced_track/sources/piped.dart | 20 +- .../sourced_track/sources/youtube.dart | 57 +- .../youtube_engine/newpipe_engine.dart | 109 + .../youtube_engine/youtube_engine.dart | 14 + .../youtube_explode_engine.dart | 47 + .../youtube_engine/yt_dlp_engine.dart | 149 + linux/packaging/deb/make_config.yaml | 3 + pubspec.lock | 26 +- pubspec.yaml | 8 + test/drift/app_db/generated/schema.dart | 5 +- test/drift/app_db/generated/schema_v4.dart | 3433 +++++++++++++++++ untranslated_messages.json | 234 +- windows/packaging/exe/inno_setup.iss | 4 +- 42 files changed, 4819 insertions(+), 244 deletions(-) create mode 100644 drift_schemas/app_db/drift_schema_v4.json create mode 100644 lib/hooks/configurators/use_check_yt_dlp_installed.dart create mode 100644 lib/modules/settings/youtube_engine_not_installed_dialog.dart create mode 100644 lib/provider/youtube_engine/youtube_engine.dart create mode 100644 lib/services/youtube_engine/newpipe_engine.dart create mode 100644 lib/services/youtube_engine/youtube_engine.dart create mode 100644 lib/services/youtube_engine/youtube_explode_engine.dart create mode 100644 lib/services/youtube_engine/yt_dlp_engine.dart create mode 100644 test/drift/app_db/generated/schema_v4.dart diff --git a/.github/workflows/pr-lint.yml b/.github/workflows/pr-lint.yml index b5afbc9e..454d0c78 100644 --- a/.github/workflows/pr-lint.yml +++ b/.github/workflows/pr-lint.yml @@ -4,7 +4,7 @@ on: pull_request: env: - FLUTTER_VERSION: 3.27.0 + FLUTTER_VERSION: 3.27.3 jobs: lint: diff --git a/Makefile b/Makefile index 25ac3a6d..48626312 100644 --- a/Makefile +++ b/Makefile @@ -45,4 +45,11 @@ gensums: sh -c scripts/gensums.sh migrate: - dart run drift_dev make-migrations \ No newline at end of file + dart run drift_dev make-migrations + +dmg: + flutter build macos &&\ + if [ -f dist/Spotube-macos-universal.dmg ];\ + then rm dist/Spotube-macos-universal.dmg;\ + fi &&\ + appdmg appdmg.json dist/Spotube-macos-universal.dmg \ No newline at end of file diff --git a/android/app/build.gradle b/android/app/build.gradle index 74f6efea..5051f5a3 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -38,6 +38,7 @@ android { ndkVersion = "27.0.12077973" compileOptions { + coreLibraryDesugaringEnabled true sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } @@ -120,6 +121,8 @@ flutter { def glanceVersion = "1.1.1" dependencies { + coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.4' + implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1' // other deps so just ignore implementation 'com.android.support:multidex:2.0.1' diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro index ee867c13..700901e8 100644 --- a/android/app/proguard-rules.pro +++ b/android/app/proguard-rules.pro @@ -6,3 +6,16 @@ -keepclassmembers class ** { @kotlinx.serialization.* ; } + +## We don't need beans +-dontwarn java.beans.BeanDescriptor +-dontwarn java.beans.BeanInfo +-dontwarn java.beans.IntrospectionException +-dontwarn java.beans.Introspector +-dontwarn java.beans.PropertyDescriptor + +## Rules for NewPipeExtractor +-keep class org.schabi.newpipe.extractor.timeago.patterns.** { *; } +-keep class org.mozilla.javascript.** { *; } +-keep class org.mozilla.classfile.ClassFileWriter +-dontwarn org.mozilla.javascript.tools.** \ No newline at end of file diff --git a/aur-struct/.SRCINFO b/aur-struct/.SRCINFO index 4c07a045..89878245 100644 --- a/aur-struct/.SRCINFO +++ b/aur-struct/.SRCINFO @@ -12,6 +12,7 @@ depends = jsoncpp depends = libnotify depends = xdg-user-dirs depends = webkit2gtk-4.1 +optdepends = yt-dlp-git source = https://github.com/KRTirtho/spotube/releases/download/v3.7.1/spotube-linux-3.7.1-x86_64.tar.xz md5sums = 475b1ae9b08f27743a4d4749391ae3db diff --git a/aur-struct/PKGBUILD b/aur-struct/PKGBUILD index d7e1052b..735f992e 100644 --- a/aur-struct/PKGBUILD +++ b/aur-struct/PKGBUILD @@ -11,7 +11,7 @@ groups=() depends=('mpv' 'libappindicator-gtk3' 'libsecret' 'jsoncpp' 'libnotify' 'xdg-user-dirs' 'webkit2gtk-4.1') makedepends=() checkdepends=() -optdepends=() +optdepends=('yt-dlp-git') provides=() conflicts=() replaces=() diff --git a/drift_schemas/app_db/drift_schema_v4.json b/drift_schemas/app_db/drift_schema_v4.json new file mode 100644 index 00000000..fc50a6f8 --- /dev/null +++ b/drift_schemas/app_db/drift_schema_v4.json @@ -0,0 +1 @@ +{"_meta":{"description":"This file contains a serialized version of schema entities for drift.","version":"1.2.0"},"options":{"store_date_time_values_as_text":false},"entities":[{"id":0,"references":[],"type":"table","data":{"name":"authentication_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"cookie","getter_name":"cookie","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"EncryptedTextConverter()","dart_type_name":"DecryptedText"}},{"name":"access_token","getter_name":"accessToken","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"EncryptedTextConverter()","dart_type_name":"DecryptedText"}},{"name":"expiration","getter_name":"expiration","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":1,"references":[],"type":"table","data":{"name":"blacklist_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"element_type","getter_name":"elementType","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(BlacklistedType.values)","dart_type_name":"BlacklistedType"}},{"name":"element_id","getter_name":"elementId","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":2,"references":[],"type":"table","data":{"name":"preferences_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"audio_quality","getter_name":"audioQuality","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(SourceQualities.high.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(SourceQualities.values)","dart_type_name":"SourceQualities"}},{"name":"album_color_sync","getter_name":"albumColorSync","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"album_color_sync\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"album_color_sync\" IN (0, 1))"},"default_dart":"const Constant(true)","default_client_dart":null,"dsl_features":[]},{"name":"amoled_dark_theme","getter_name":"amoledDarkTheme","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"amoled_dark_theme\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"amoled_dark_theme\" IN (0, 1))"},"default_dart":"const Constant(false)","default_client_dart":null,"dsl_features":[]},{"name":"check_update","getter_name":"checkUpdate","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"check_update\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"check_update\" IN (0, 1))"},"default_dart":"const Constant(true)","default_client_dart":null,"dsl_features":[]},{"name":"normalize_audio","getter_name":"normalizeAudio","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"normalize_audio\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"normalize_audio\" IN (0, 1))"},"default_dart":"const Constant(false)","default_client_dart":null,"dsl_features":[]},{"name":"show_system_tray_icon","getter_name":"showSystemTrayIcon","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"show_system_tray_icon\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"show_system_tray_icon\" IN (0, 1))"},"default_dart":"const Constant(false)","default_client_dart":null,"dsl_features":[]},{"name":"system_title_bar","getter_name":"systemTitleBar","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"system_title_bar\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"system_title_bar\" IN (0, 1))"},"default_dart":"const Constant(false)","default_client_dart":null,"dsl_features":[]},{"name":"skip_non_music","getter_name":"skipNonMusic","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"skip_non_music\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"skip_non_music\" IN (0, 1))"},"default_dart":"const Constant(false)","default_client_dart":null,"dsl_features":[]},{"name":"close_behavior","getter_name":"closeBehavior","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(CloseBehavior.close.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(CloseBehavior.values)","dart_type_name":"CloseBehavior"}},{"name":"accent_color_scheme","getter_name":"accentColorScheme","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const Constant(\"Blue:0xFF2196F3\")","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const SpotubeColorConverter()","dart_type_name":"SpotubeColor"}},{"name":"layout_mode","getter_name":"layoutMode","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(LayoutMode.adaptive.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(LayoutMode.values)","dart_type_name":"LayoutMode"}},{"name":"locale","getter_name":"locale","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const Constant('{\"languageCode\":\"system\",\"countryCode\":\"system\"}')","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const LocaleConverter()","dart_type_name":"Locale"}},{"name":"market","getter_name":"market","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(Market.US.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(Market.values)","dart_type_name":"Market"}},{"name":"search_mode","getter_name":"searchMode","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(SearchMode.youtube.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(SearchMode.values)","dart_type_name":"SearchMode"}},{"name":"download_location","getter_name":"downloadLocation","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const Constant(\"\")","default_client_dart":null,"dsl_features":[]},{"name":"local_library_location","getter_name":"localLibraryLocation","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const Constant(\"\")","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const StringListConverter()","dart_type_name":"List"}},{"name":"piped_instance","getter_name":"pipedInstance","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const Constant(\"https://pipedapi.kavin.rocks\")","default_client_dart":null,"dsl_features":[]},{"name":"invidious_instance","getter_name":"invidiousInstance","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"const Constant(\"https://inv.nadeko.net\")","default_client_dart":null,"dsl_features":[]},{"name":"theme_mode","getter_name":"themeMode","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(ThemeMode.system.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(ThemeMode.values)","dart_type_name":"ThemeMode"}},{"name":"audio_source","getter_name":"audioSource","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(AudioSource.youtube.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(AudioSource.values)","dart_type_name":"AudioSource"}},{"name":"youtube_client_engine","getter_name":"youtubeClientEngine","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(YoutubeClientEngine.youtubeExplode.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(YoutubeClientEngine.values)","dart_type_name":"YoutubeClientEngine"}},{"name":"stream_music_codec","getter_name":"streamMusicCodec","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(SourceCodecs.weba.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(SourceCodecs.values)","dart_type_name":"SourceCodecs"}},{"name":"download_music_codec","getter_name":"downloadMusicCodec","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(SourceCodecs.m4a.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(SourceCodecs.values)","dart_type_name":"SourceCodecs"}},{"name":"discord_presence","getter_name":"discordPresence","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"discord_presence\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"discord_presence\" IN (0, 1))"},"default_dart":"const Constant(true)","default_client_dart":null,"dsl_features":[]},{"name":"endless_playback","getter_name":"endlessPlayback","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"endless_playback\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"endless_playback\" IN (0, 1))"},"default_dart":"const Constant(true)","default_client_dart":null,"dsl_features":[]},{"name":"enable_connect","getter_name":"enableConnect","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"enable_connect\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"enable_connect\" IN (0, 1))"},"default_dart":"const Constant(false)","default_client_dart":null,"dsl_features":[]},{"name":"cache_music","getter_name":"cacheMusic","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"cache_music\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"cache_music\" IN (0, 1))"},"default_dart":"const Constant(true)","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":3,"references":[],"type":"table","data":{"name":"scrobbler_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"currentDateAndTime","default_client_dart":null,"dsl_features":[]},{"name":"username","getter_name":"username","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"password_hash","getter_name":"passwordHash","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"EncryptedTextConverter()","dart_type_name":"DecryptedText"}}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":4,"references":[],"type":"table","data":{"name":"skip_segment_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"start","getter_name":"start","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"end","getter_name":"end","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"track_id","getter_name":"trackId","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"currentDateAndTime","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":5,"references":[],"type":"table","data":{"name":"source_match_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"track_id","getter_name":"trackId","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"source_id","getter_name":"sourceId","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"source_type","getter_name":"sourceType","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":"Constant(SourceType.youtube.name)","default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(SourceType.values)","dart_type_name":"SourceType"}},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"currentDateAndTime","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":6,"references":[],"type":"table","data":{"name":"audio_player_state_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"playing","getter_name":"playing","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"playing\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"playing\" IN (0, 1))"},"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"loop_mode","getter_name":"loopMode","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(PlaylistMode.values)","dart_type_name":"PlaylistMode"}},{"name":"shuffled","getter_name":"shuffled","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"shuffled\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"shuffled\" IN (0, 1))"},"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"collections","getter_name":"collections","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const StringListConverter()","dart_type_name":"List"}}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":7,"references":[6],"type":"table","data":{"name":"playlist_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"audio_player_state_id","getter_name":"audioPlayerStateId","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES audio_player_state_table (id)","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES audio_player_state_table (id)"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"index","getter_name":"index","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":8,"references":[7],"type":"table","data":{"name":"playlist_media_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"playlist_id","getter_name":"playlistId","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"REFERENCES playlist_table (id)","dialectAwareDefaultConstraints":{"sqlite":"REFERENCES playlist_table (id)"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"uri","getter_name":"uri","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"extras","getter_name":"extras","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const MapTypeConverter()","dart_type_name":"Map"}},{"name":"http_headers","getter_name":"httpHeaders","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const MapTypeConverter()","dart_type_name":"Map"}}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":9,"references":[],"type":"table","data":{"name":"history_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"currentDateAndTime","default_client_dart":null,"dsl_features":[]},{"name":"type","getter_name":"type","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const EnumNameConverter(HistoryEntryType.values)","dart_type_name":"HistoryEntryType"}},{"name":"item_id","getter_name":"itemId","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"data","getter_name":"data","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const MapTypeConverter()","dart_type_name":"Map"}}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":10,"references":[],"type":"table","data":{"name":"lyrics_table","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"track_id","getter_name":"trackId","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"data","getter_name":"data","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"SubtitleTypeConverter()","dart_type_name":"SubtitleSimple"}}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":11,"references":[1],"type":"index","data":{"on":1,"name":"unique_blacklist","sql":null,"unique":true,"columns":["element_type","element_id"]}},{"id":12,"references":[5],"type":"index","data":{"on":5,"name":"uniq_track_match","sql":null,"unique":true,"columns":["track_id","source_id","source_type"]}}]} \ No newline at end of file diff --git a/lib/collections/routes.dart b/lib/collections/routes.dart index 10b2dc0d..d2c19c52 100644 --- a/lib/collections/routes.dart +++ b/lib/collections/routes.dart @@ -14,21 +14,6 @@ class AppRouter extends RootStackRouter { AppRouter(this.ref) : super(navigatorKey: rootNavigatorKey); - @override - List get guards => [ - AutoRouteGuardCallback( - (resolver, router) async { - final auth = await ref.read(authenticationProvider.future); - - if (auth == null && !KVStoreService.doneGettingStarted) { - resolver.redirect(const GettingStartedRoute()); - } else { - resolver.next(true); - } - }, - ), - ]; - @override List get routes => [ AutoRoute( @@ -40,6 +25,19 @@ class AppRouter extends RootStackRouter { path: "home", page: HomeRoute.page, initial: true, + guards: [ + AutoRouteGuardCallback( + (resolver, router) async { + final auth = await ref.read(authenticationProvider.future); + + if (auth == null && !KVStoreService.doneGettingStarted) { + resolver.redirect(const GettingStartedRoute()); + } else { + resolver.next(true); + } + }, + ), + ], ), AutoRoute( path: "home/genres", diff --git a/lib/collections/spotube_icons.dart b/lib/collections/spotube_icons.dart index b5fbe5e8..bd9d037c 100644 --- a/lib/collections/spotube_icons.dart +++ b/lib/collections/spotube_icons.dart @@ -134,4 +134,5 @@ abstract class SpotubeIcons { static const grid = FeatherIcons.grid; static const list = FeatherIcons.list; static const device = FeatherIcons.smartphone; + static const engine = FeatherIcons.server; } diff --git a/lib/hooks/configurators/use_check_yt_dlp_installed.dart b/lib/hooks/configurators/use_check_yt_dlp_installed.dart new file mode 100644 index 00000000..1d948258 --- /dev/null +++ b/lib/hooks/configurators/use_check_yt_dlp_installed.dart @@ -0,0 +1,40 @@ +import 'dart:io'; + +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:spotube/models/database/database.dart'; +import 'package:spotube/modules/settings/youtube_engine_not_installed_dialog.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; +import 'package:spotube/services/kv_store/kv_store.dart'; +import 'package:spotube/services/youtube_engine/yt_dlp_engine.dart'; + +void useCheckYtDlpInstalled(WidgetRef ref) { + final context = useContext(); + + useEffect(() { + WidgetsBinding.instance.addPostFrameCallback((_) async { + final youtubeEngine = ref.read( + userPreferencesProvider.select( + (value) => value.youtubeClientEngine, + ), + ); + + final customPath = + KVStoreService.getYoutubeEnginePath(YoutubeClientEngine.ytDlp); + + if (youtubeEngine == YoutubeClientEngine.ytDlp && + !await YtDlpEngine.isInstalled() && + (customPath == null || !await File(customPath).exists()) && + context.mounted) { + await showDialog( + context: context, + builder: (context) => + YouTubeEngineNotInstalledDialog(engine: youtubeEngine), + ); + } + }); + + return null; + }, []); +} diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index ae7abb01..98dd5d5f 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -415,5 +415,12 @@ "no_tracks_listened_yet": "Looks like you haven't listened to anything yet", "not_following_artists": "You're not following any artists", "no_favorite_albums_yet": "Looks like you haven't added any albums to your favorites yet", - "no_logs_found": "No logs found" + "no_logs_found": "No logs found", + "youtube_engine": "YouTube Engine", + "youtube_engine_not_installed_title": "{engine} is not installed", + "youtube_engine_not_installed_message": "{engine} is not installed in your system.", + "youtube_engine_set_path": "Make sure it's available in the PATH variable or\nset the absolute path to the {engine} executable below", + "youtube_engine_unix_issue_message": "In macOS/Linux/unix like OS's, setting path on .zshrc/.bashrc/.bash_profile etc. won't work.\nYou need to set the path in the shell configuration file", + "download": "Download", + "file_not_found": "File not found" } \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 016c0fea..6f3cbfbf 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -50,6 +50,8 @@ import 'package:flutter_displaymode/flutter_displaymode.dart'; import 'package:timezone/data/latest.dart' as tz; import 'package:window_manager/window_manager.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:yt_dlp_dart/yt_dlp_dart.dart'; +import 'package:flutter_new_pipe_extractor/flutter_new_pipe_extractor.dart'; Future main(List rawArgs) async { if (rawArgs.contains("web_view_title_bar")) { @@ -77,17 +79,23 @@ Future main(List rawArgs) async { // force High Refresh Rate on some Android devices (like One Plus) if (kIsAndroid) { await FlutterDisplayMode.setHighRefreshRate(); - } - - if (kIsDesktop) { - await windowManager.setPreventClose(true); + await NewPipeExtractor.init(); } if (!kIsWeb) { MetadataGod.initialize(); } + await KVStoreService.initialize(); + if (kIsDesktop) { + await windowManager.setPreventClose(true); + await YtDlp.instance + .setBinaryLocation( + KVStoreService.getYoutubeEnginePath(YoutubeClientEngine.ytDlp) ?? + "yt-dlp${kIsWindows ? '.exe' : ''}", + ) + .catchError((e, stack) => null); await FlutterDiscordRPC.initialize(Env.discordAppId); } @@ -95,7 +103,6 @@ Future main(List rawArgs) async { await SMTCWindows.initialize(); } - await KVStoreService.initialize(); await EncryptedKvStoreService.initialize(); final database = AppDatabase(); diff --git a/lib/models/database/database.dart b/lib/models/database/database.dart index f76d25bc..199e7147 100644 --- a/lib/models/database/database.dart +++ b/lib/models/database/database.dart @@ -18,6 +18,9 @@ import 'package:spotube/services/sourced_track/enums.dart'; import 'package:flutter/widgets.dart' hide Table, Key, View; import 'package:spotube/modules/settings/color_scheme_picker_dialog.dart'; import 'package:drift/native.dart'; +import 'package:spotube/services/youtube_engine/newpipe_engine.dart'; +import 'package:spotube/services/youtube_engine/youtube_explode_engine.dart'; +import 'package:spotube/services/youtube_engine/yt_dlp_engine.dart'; import 'package:sqlite3/sqlite3.dart'; import 'package:sqlite3_flutter_libs/sqlite3_flutter_libs.dart'; @@ -59,7 +62,7 @@ class AppDatabase extends _$AppDatabase { AppDatabase() : super(_openConnection()); @override - int get schemaVersion => 3; + int get schemaVersion => 4; @override MigrationStrategy get migration { @@ -78,6 +81,12 @@ class AppDatabase extends _$AppDatabase { schema.preferencesTable.cacheMusic, ); }, + from3To4: (m, schema) async { + await m.addColumn( + schema.preferencesTable, + schema.preferencesTable.youtubeClientEngine, + ); + }, ), ); } diff --git a/lib/models/database/database.g.dart b/lib/models/database/database.g.dart index 951b2ed5..cd004d69 100644 --- a/lib/models/database/database.g.dart +++ b/lib/models/database/database.g.dart @@ -760,6 +760,17 @@ class $PreferencesTableTable extends PreferencesTable defaultValue: Constant(AudioSource.youtube.name)) .withConverter( $PreferencesTableTable.$converteraudioSource); + static const VerificationMeta _youtubeClientEngineMeta = + const VerificationMeta('youtubeClientEngine'); + @override + late final GeneratedColumnWithTypeConverter + youtubeClientEngine = GeneratedColumn( + 'youtube_client_engine', aliasedName, false, + type: DriftSqlType.string, + requiredDuringInsert: false, + defaultValue: Constant(YoutubeClientEngine.youtubeExplode.name)) + .withConverter( + $PreferencesTableTable.$converteryoutubeClientEngine); static const VerificationMeta _streamMusicCodecMeta = const VerificationMeta('streamMusicCodec'); @override @@ -845,6 +856,7 @@ class $PreferencesTableTable extends PreferencesTable invidiousInstance, themeMode, audioSource, + youtubeClientEngine, streamMusicCodec, downloadMusicCodec, discordPresence, @@ -937,6 +949,8 @@ class $PreferencesTableTable extends PreferencesTable } context.handle(_themeModeMeta, const VerificationResult.success()); context.handle(_audioSourceMeta, const VerificationResult.success()); + context.handle( + _youtubeClientEngineMeta, const VerificationResult.success()); context.handle(_streamMusicCodecMeta, const VerificationResult.success()); context.handle(_downloadMusicCodecMeta, const VerificationResult.success()); if (data.containsKey('discord_presence')) { @@ -1025,6 +1039,9 @@ class $PreferencesTableTable extends PreferencesTable audioSource: $PreferencesTableTable.$converteraudioSource.fromSql( attachedDatabase.typeMapping.read( DriftSqlType.string, data['${effectivePrefix}audio_source'])!), + youtubeClientEngine: $PreferencesTableTable.$converteryoutubeClientEngine + .fromSql(attachedDatabase.typeMapping.read(DriftSqlType.string, + data['${effectivePrefix}youtube_client_engine'])!), streamMusicCodec: $PreferencesTableTable.$converterstreamMusicCodec .fromSql(attachedDatabase.typeMapping.read(DriftSqlType.string, data['${effectivePrefix}stream_music_codec'])!), @@ -1069,6 +1086,9 @@ class $PreferencesTableTable extends PreferencesTable const EnumNameConverter(ThemeMode.values); static JsonTypeConverter2 $converteraudioSource = const EnumNameConverter(AudioSource.values); + static JsonTypeConverter2 + $converteryoutubeClientEngine = + const EnumNameConverter(YoutubeClientEngine.values); static JsonTypeConverter2 $converterstreamMusicCodec = const EnumNameConverter(SourceCodecs.values); @@ -1100,6 +1120,7 @@ class PreferencesTableData extends DataClass final String invidiousInstance; final ThemeMode themeMode; final AudioSource audioSource; + final YoutubeClientEngine youtubeClientEngine; final SourceCodecs streamMusicCodec; final SourceCodecs downloadMusicCodec; final bool discordPresence; @@ -1128,6 +1149,7 @@ class PreferencesTableData extends DataClass required this.invidiousInstance, required this.themeMode, required this.audioSource, + required this.youtubeClientEngine, required this.streamMusicCodec, required this.downloadMusicCodec, required this.discordPresence, @@ -1190,6 +1212,11 @@ class PreferencesTableData extends DataClass map['audio_source'] = Variable( $PreferencesTableTable.$converteraudioSource.toSql(audioSource)); } + { + map['youtube_client_engine'] = Variable($PreferencesTableTable + .$converteryoutubeClientEngine + .toSql(youtubeClientEngine)); + } { map['stream_music_codec'] = Variable($PreferencesTableTable .$converterstreamMusicCodec @@ -1230,6 +1257,7 @@ class PreferencesTableData extends DataClass invidiousInstance: Value(invidiousInstance), themeMode: Value(themeMode), audioSource: Value(audioSource), + youtubeClientEngine: Value(youtubeClientEngine), streamMusicCodec: Value(streamMusicCodec), downloadMusicCodec: Value(downloadMusicCodec), discordPresence: Value(discordPresence), @@ -1273,6 +1301,8 @@ class PreferencesTableData extends DataClass .fromJson(serializer.fromJson(json['themeMode'])), audioSource: $PreferencesTableTable.$converteraudioSource .fromJson(serializer.fromJson(json['audioSource'])), + youtubeClientEngine: $PreferencesTableTable.$converteryoutubeClientEngine + .fromJson(serializer.fromJson(json['youtubeClientEngine'])), streamMusicCodec: $PreferencesTableTable.$converterstreamMusicCodec .fromJson(serializer.fromJson(json['streamMusicCodec'])), downloadMusicCodec: $PreferencesTableTable.$converterdownloadMusicCodec @@ -1316,6 +1346,9 @@ class PreferencesTableData extends DataClass $PreferencesTableTable.$converterthemeMode.toJson(themeMode)), 'audioSource': serializer.toJson( $PreferencesTableTable.$converteraudioSource.toJson(audioSource)), + 'youtubeClientEngine': serializer.toJson($PreferencesTableTable + .$converteryoutubeClientEngine + .toJson(youtubeClientEngine)), 'streamMusicCodec': serializer.toJson($PreferencesTableTable .$converterstreamMusicCodec .toJson(streamMusicCodec)), @@ -1351,6 +1384,7 @@ class PreferencesTableData extends DataClass String? invidiousInstance, ThemeMode? themeMode, AudioSource? audioSource, + YoutubeClientEngine? youtubeClientEngine, SourceCodecs? streamMusicCodec, SourceCodecs? downloadMusicCodec, bool? discordPresence, @@ -1379,6 +1413,7 @@ class PreferencesTableData extends DataClass invidiousInstance: invidiousInstance ?? this.invidiousInstance, themeMode: themeMode ?? this.themeMode, audioSource: audioSource ?? this.audioSource, + youtubeClientEngine: youtubeClientEngine ?? this.youtubeClientEngine, streamMusicCodec: streamMusicCodec ?? this.streamMusicCodec, downloadMusicCodec: downloadMusicCodec ?? this.downloadMusicCodec, discordPresence: discordPresence ?? this.discordPresence, @@ -1439,6 +1474,9 @@ class PreferencesTableData extends DataClass themeMode: data.themeMode.present ? data.themeMode.value : this.themeMode, audioSource: data.audioSource.present ? data.audioSource.value : this.audioSource, + youtubeClientEngine: data.youtubeClientEngine.present + ? data.youtubeClientEngine.value + : this.youtubeClientEngine, streamMusicCodec: data.streamMusicCodec.present ? data.streamMusicCodec.value : this.streamMusicCodec, @@ -1483,6 +1521,7 @@ class PreferencesTableData extends DataClass ..write('invidiousInstance: $invidiousInstance, ') ..write('themeMode: $themeMode, ') ..write('audioSource: $audioSource, ') + ..write('youtubeClientEngine: $youtubeClientEngine, ') ..write('streamMusicCodec: $streamMusicCodec, ') ..write('downloadMusicCodec: $downloadMusicCodec, ') ..write('discordPresence: $discordPresence, ') @@ -1516,6 +1555,7 @@ class PreferencesTableData extends DataClass invidiousInstance, themeMode, audioSource, + youtubeClientEngine, streamMusicCodec, downloadMusicCodec, discordPresence, @@ -1548,6 +1588,7 @@ class PreferencesTableData extends DataClass other.invidiousInstance == this.invidiousInstance && other.themeMode == this.themeMode && other.audioSource == this.audioSource && + other.youtubeClientEngine == this.youtubeClientEngine && other.streamMusicCodec == this.streamMusicCodec && other.downloadMusicCodec == this.downloadMusicCodec && other.discordPresence == this.discordPresence && @@ -1578,6 +1619,7 @@ class PreferencesTableCompanion extends UpdateCompanion { final Value invidiousInstance; final Value themeMode; final Value audioSource; + final Value youtubeClientEngine; final Value streamMusicCodec; final Value downloadMusicCodec; final Value discordPresence; @@ -1606,6 +1648,7 @@ class PreferencesTableCompanion extends UpdateCompanion { this.invidiousInstance = const Value.absent(), this.themeMode = const Value.absent(), this.audioSource = const Value.absent(), + this.youtubeClientEngine = const Value.absent(), this.streamMusicCodec = const Value.absent(), this.downloadMusicCodec = const Value.absent(), this.discordPresence = const Value.absent(), @@ -1635,6 +1678,7 @@ class PreferencesTableCompanion extends UpdateCompanion { this.invidiousInstance = const Value.absent(), this.themeMode = const Value.absent(), this.audioSource = const Value.absent(), + this.youtubeClientEngine = const Value.absent(), this.streamMusicCodec = const Value.absent(), this.downloadMusicCodec = const Value.absent(), this.discordPresence = const Value.absent(), @@ -1664,6 +1708,7 @@ class PreferencesTableCompanion extends UpdateCompanion { Expression? invidiousInstance, Expression? themeMode, Expression? audioSource, + Expression? youtubeClientEngine, Expression? streamMusicCodec, Expression? downloadMusicCodec, Expression? discordPresence, @@ -1695,6 +1740,8 @@ class PreferencesTableCompanion extends UpdateCompanion { if (invidiousInstance != null) 'invidious_instance': invidiousInstance, if (themeMode != null) 'theme_mode': themeMode, if (audioSource != null) 'audio_source': audioSource, + if (youtubeClientEngine != null) + 'youtube_client_engine': youtubeClientEngine, if (streamMusicCodec != null) 'stream_music_codec': streamMusicCodec, if (downloadMusicCodec != null) 'download_music_codec': downloadMusicCodec, @@ -1727,6 +1774,7 @@ class PreferencesTableCompanion extends UpdateCompanion { Value? invidiousInstance, Value? themeMode, Value? audioSource, + Value? youtubeClientEngine, Value? streamMusicCodec, Value? downloadMusicCodec, Value? discordPresence, @@ -1755,6 +1803,7 @@ class PreferencesTableCompanion extends UpdateCompanion { invidiousInstance: invidiousInstance ?? this.invidiousInstance, themeMode: themeMode ?? this.themeMode, audioSource: audioSource ?? this.audioSource, + youtubeClientEngine: youtubeClientEngine ?? this.youtubeClientEngine, streamMusicCodec: streamMusicCodec ?? this.streamMusicCodec, downloadMusicCodec: downloadMusicCodec ?? this.downloadMusicCodec, discordPresence: discordPresence ?? this.discordPresence, @@ -1845,6 +1894,11 @@ class PreferencesTableCompanion extends UpdateCompanion { .$converteraudioSource .toSql(audioSource.value)); } + if (youtubeClientEngine.present) { + map['youtube_client_engine'] = Variable($PreferencesTableTable + .$converteryoutubeClientEngine + .toSql(youtubeClientEngine.value)); + } if (streamMusicCodec.present) { map['stream_music_codec'] = Variable($PreferencesTableTable .$converterstreamMusicCodec @@ -1894,6 +1948,7 @@ class PreferencesTableCompanion extends UpdateCompanion { ..write('invidiousInstance: $invidiousInstance, ') ..write('themeMode: $themeMode, ') ..write('audioSource: $audioSource, ') + ..write('youtubeClientEngine: $youtubeClientEngine, ') ..write('streamMusicCodec: $streamMusicCodec, ') ..write('downloadMusicCodec: $downloadMusicCodec, ') ..write('discordPresence: $discordPresence, ') @@ -4565,6 +4620,7 @@ typedef $$PreferencesTableTableCreateCompanionBuilder Value invidiousInstance, Value themeMode, Value audioSource, + Value youtubeClientEngine, Value streamMusicCodec, Value downloadMusicCodec, Value discordPresence, @@ -4595,6 +4651,7 @@ typedef $$PreferencesTableTableUpdateCompanionBuilder Value invidiousInstance, Value themeMode, Value audioSource, + Value youtubeClientEngine, Value streamMusicCodec, Value downloadMusicCodec, Value discordPresence, @@ -4702,6 +4759,12 @@ class $$PreferencesTableTableFilterComposer column: $table.audioSource, builder: (column) => ColumnWithTypeConverterFilters(column)); + ColumnWithTypeConverterFilters + get youtubeClientEngine => $composableBuilder( + column: $table.youtubeClientEngine, + builder: (column) => ColumnWithTypeConverterFilters(column)); + ColumnWithTypeConverterFilters get streamMusicCodec => $composableBuilder( column: $table.streamMusicCodec, @@ -4812,6 +4875,10 @@ class $$PreferencesTableTableOrderingComposer ColumnOrderings get audioSource => $composableBuilder( column: $table.audioSource, builder: (column) => ColumnOrderings(column)); + ColumnOrderings get youtubeClientEngine => $composableBuilder( + column: $table.youtubeClientEngine, + builder: (column) => ColumnOrderings(column)); + ColumnOrderings get streamMusicCodec => $composableBuilder( column: $table.streamMusicCodec, builder: (column) => ColumnOrderings(column)); @@ -4915,6 +4982,10 @@ class $$PreferencesTableTableAnnotationComposer $composableBuilder( column: $table.audioSource, builder: (column) => column); + GeneratedColumnWithTypeConverter + get youtubeClientEngine => $composableBuilder( + column: $table.youtubeClientEngine, builder: (column) => column); + GeneratedColumnWithTypeConverter get streamMusicCodec => $composableBuilder( column: $table.streamMusicCodec, builder: (column) => column); @@ -4985,6 +5056,8 @@ class $$PreferencesTableTableTableManager extends RootTableManager< Value invidiousInstance = const Value.absent(), Value themeMode = const Value.absent(), Value audioSource = const Value.absent(), + Value youtubeClientEngine = + const Value.absent(), Value streamMusicCodec = const Value.absent(), Value downloadMusicCodec = const Value.absent(), Value discordPresence = const Value.absent(), @@ -5014,6 +5087,7 @@ class $$PreferencesTableTableTableManager extends RootTableManager< invidiousInstance: invidiousInstance, themeMode: themeMode, audioSource: audioSource, + youtubeClientEngine: youtubeClientEngine, streamMusicCodec: streamMusicCodec, downloadMusicCodec: downloadMusicCodec, discordPresence: discordPresence, @@ -5043,6 +5117,8 @@ class $$PreferencesTableTableTableManager extends RootTableManager< Value invidiousInstance = const Value.absent(), Value themeMode = const Value.absent(), Value audioSource = const Value.absent(), + Value youtubeClientEngine = + const Value.absent(), Value streamMusicCodec = const Value.absent(), Value downloadMusicCodec = const Value.absent(), Value discordPresence = const Value.absent(), @@ -5072,6 +5148,7 @@ class $$PreferencesTableTableTableManager extends RootTableManager< invidiousInstance: invidiousInstance, themeMode: themeMode, audioSource: audioSource, + youtubeClientEngine: youtubeClientEngine, streamMusicCodec: streamMusicCodec, downloadMusicCodec: downloadMusicCodec, discordPresence: discordPresence, diff --git a/lib/models/database/database.steps.dart b/lib/models/database/database.steps.dart index 25bf6ad9..8e0f8e3f 100644 --- a/lib/models/database/database.steps.dart +++ b/lib/models/database/database.steps.dart @@ -1,11 +1,11 @@ // dart format width=80 import 'package:drift/internal/versioned_schema.dart' as i0; import 'package:drift/drift.dart' as i1; -import 'package:drift/drift.dart'; // ignore_for_file: type=lint,unused_import +import 'package:drift/drift.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/models/database/database.dart'; -import 'package:spotube/services/sourced_track/enums.dart'; +import 'package:spotube/services/sourced_track/enums.dart'; // ignore_for_file: type=lint,unused_import // GENERATED BY drift_dev, DO NOT MODIFY. final class Schema2 extends i0.VersionedSchema { @@ -907,9 +907,291 @@ i1.GeneratedColumn _column_53(String aliasedName) => defaultConstraints: i1.GeneratedColumn.constraintIsAlways( 'CHECK ("cache_music" IN (0, 1))'), defaultValue: const Constant(true)); + +final class Schema4 extends i0.VersionedSchema { + Schema4({required super.database}) : super(version: 4); + @override + late final List entities = [ + authenticationTable, + blacklistTable, + preferencesTable, + scrobblerTable, + skipSegmentTable, + sourceMatchTable, + audioPlayerStateTable, + playlistTable, + playlistMediaTable, + historyTable, + lyricsTable, + uniqueBlacklist, + uniqTrackMatch, + ]; + late final Shape0 authenticationTable = Shape0( + source: i0.VersionedTable( + entityName: 'authentication_table', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [ + _column_0, + _column_1, + _column_2, + _column_3, + ], + attachedDatabase: database, + ), + alias: null); + late final Shape1 blacklistTable = Shape1( + source: i0.VersionedTable( + entityName: 'blacklist_table', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [ + _column_0, + _column_4, + _column_5, + _column_6, + ], + attachedDatabase: database, + ), + alias: null); + late final Shape12 preferencesTable = Shape12( + source: i0.VersionedTable( + entityName: 'preferences_table', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [ + _column_0, + _column_7, + _column_8, + _column_9, + _column_10, + _column_11, + _column_12, + _column_13, + _column_14, + _column_15, + _column_16, + _column_17, + _column_18, + _column_19, + _column_20, + _column_21, + _column_22, + _column_23, + _column_24, + _column_25, + _column_26, + _column_54, + _column_27, + _column_28, + _column_29, + _column_30, + _column_31, + _column_53, + ], + attachedDatabase: database, + ), + alias: null); + late final Shape3 scrobblerTable = Shape3( + source: i0.VersionedTable( + entityName: 'scrobbler_table', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [ + _column_0, + _column_32, + _column_33, + _column_34, + ], + attachedDatabase: database, + ), + alias: null); + late final Shape4 skipSegmentTable = Shape4( + source: i0.VersionedTable( + entityName: 'skip_segment_table', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [ + _column_0, + _column_35, + _column_36, + _column_37, + _column_32, + ], + attachedDatabase: database, + ), + alias: null); + late final Shape5 sourceMatchTable = Shape5( + source: i0.VersionedTable( + entityName: 'source_match_table', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [ + _column_0, + _column_37, + _column_38, + _column_39, + _column_32, + ], + attachedDatabase: database, + ), + alias: null); + late final Shape6 audioPlayerStateTable = Shape6( + source: i0.VersionedTable( + entityName: 'audio_player_state_table', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [ + _column_0, + _column_40, + _column_41, + _column_42, + _column_43, + ], + attachedDatabase: database, + ), + alias: null); + late final Shape7 playlistTable = Shape7( + source: i0.VersionedTable( + entityName: 'playlist_table', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [ + _column_0, + _column_44, + _column_45, + ], + attachedDatabase: database, + ), + alias: null); + late final Shape8 playlistMediaTable = Shape8( + source: i0.VersionedTable( + entityName: 'playlist_media_table', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [ + _column_0, + _column_46, + _column_47, + _column_48, + _column_49, + ], + attachedDatabase: database, + ), + alias: null); + late final Shape9 historyTable = Shape9( + source: i0.VersionedTable( + entityName: 'history_table', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [ + _column_0, + _column_32, + _column_50, + _column_51, + _column_52, + ], + attachedDatabase: database, + ), + alias: null); + late final Shape10 lyricsTable = Shape10( + source: i0.VersionedTable( + entityName: 'lyrics_table', + withoutRowId: false, + isStrict: false, + tableConstraints: [], + columns: [ + _column_0, + _column_37, + _column_52, + ], + attachedDatabase: database, + ), + alias: null); + final i1.Index uniqueBlacklist = i1.Index('unique_blacklist', + 'CREATE UNIQUE INDEX unique_blacklist ON blacklist_table (element_type, element_id)'); + final i1.Index uniqTrackMatch = i1.Index('uniq_track_match', + 'CREATE UNIQUE INDEX uniq_track_match ON source_match_table (track_id, source_id, source_type)'); +} + +class Shape12 extends i0.VersionedTable { + Shape12({required super.source, required super.alias}) : super.aliased(); + i1.GeneratedColumn get id => + columnsByName['id']! as i1.GeneratedColumn; + i1.GeneratedColumn get audioQuality => + columnsByName['audio_quality']! as i1.GeneratedColumn; + i1.GeneratedColumn get albumColorSync => + columnsByName['album_color_sync']! as i1.GeneratedColumn; + i1.GeneratedColumn get amoledDarkTheme => + columnsByName['amoled_dark_theme']! as i1.GeneratedColumn; + i1.GeneratedColumn get checkUpdate => + columnsByName['check_update']! as i1.GeneratedColumn; + i1.GeneratedColumn get normalizeAudio => + columnsByName['normalize_audio']! as i1.GeneratedColumn; + i1.GeneratedColumn get showSystemTrayIcon => + columnsByName['show_system_tray_icon']! as i1.GeneratedColumn; + i1.GeneratedColumn get systemTitleBar => + columnsByName['system_title_bar']! as i1.GeneratedColumn; + i1.GeneratedColumn get skipNonMusic => + columnsByName['skip_non_music']! as i1.GeneratedColumn; + i1.GeneratedColumn get closeBehavior => + columnsByName['close_behavior']! as i1.GeneratedColumn; + i1.GeneratedColumn get accentColorScheme => + columnsByName['accent_color_scheme']! as i1.GeneratedColumn; + i1.GeneratedColumn get layoutMode => + columnsByName['layout_mode']! as i1.GeneratedColumn; + i1.GeneratedColumn get locale => + columnsByName['locale']! as i1.GeneratedColumn; + i1.GeneratedColumn get market => + columnsByName['market']! as i1.GeneratedColumn; + i1.GeneratedColumn get searchMode => + columnsByName['search_mode']! as i1.GeneratedColumn; + i1.GeneratedColumn get downloadLocation => + columnsByName['download_location']! as i1.GeneratedColumn; + i1.GeneratedColumn get localLibraryLocation => + columnsByName['local_library_location']! as i1.GeneratedColumn; + i1.GeneratedColumn get pipedInstance => + columnsByName['piped_instance']! as i1.GeneratedColumn; + i1.GeneratedColumn get invidiousInstance => + columnsByName['invidious_instance']! as i1.GeneratedColumn; + i1.GeneratedColumn get themeMode => + columnsByName['theme_mode']! as i1.GeneratedColumn; + i1.GeneratedColumn get audioSource => + columnsByName['audio_source']! as i1.GeneratedColumn; + i1.GeneratedColumn get youtubeClientEngine => + columnsByName['youtube_client_engine']! as i1.GeneratedColumn; + i1.GeneratedColumn get streamMusicCodec => + columnsByName['stream_music_codec']! as i1.GeneratedColumn; + i1.GeneratedColumn get downloadMusicCodec => + columnsByName['download_music_codec']! as i1.GeneratedColumn; + i1.GeneratedColumn get discordPresence => + columnsByName['discord_presence']! as i1.GeneratedColumn; + i1.GeneratedColumn get endlessPlayback => + columnsByName['endless_playback']! as i1.GeneratedColumn; + i1.GeneratedColumn get enableConnect => + columnsByName['enable_connect']! as i1.GeneratedColumn; + i1.GeneratedColumn get cacheMusic => + columnsByName['cache_music']! as i1.GeneratedColumn; +} + +i1.GeneratedColumn _column_54(String aliasedName) => + i1.GeneratedColumn('youtube_client_engine', aliasedName, false, + type: i1.DriftSqlType.string, + defaultValue: Constant(YoutubeClientEngine.youtubeExplode.name)); i0.MigrationStepWithVersion migrationSteps({ required Future Function(i1.Migrator m, Schema2 schema) from1To2, required Future Function(i1.Migrator m, Schema3 schema) from2To3, + required Future Function(i1.Migrator m, Schema4 schema) from3To4, }) { return (currentVersion, database) async { switch (currentVersion) { @@ -923,6 +1205,11 @@ i0.MigrationStepWithVersion migrationSteps({ final migrator = i1.Migrator(database, schema); await from2To3(migrator, schema); return 3; + case 3: + final schema = Schema4(database: database); + final migrator = i1.Migrator(database, schema); + await from3To4(migrator, schema); + return 4; default: throw ArgumentError.value('Unknown migration from $currentVersion'); } @@ -932,9 +1219,11 @@ i0.MigrationStepWithVersion migrationSteps({ i1.OnUpgrade stepByStep({ required Future Function(i1.Migrator m, Schema2 schema) from1To2, required Future Function(i1.Migrator m, Schema3 schema) from2To3, + required Future Function(i1.Migrator m, Schema4 schema) from3To4, }) => i0.VersionedSchema.stepByStepHelper( step: migrationSteps( from1To2: from1To2, from2To3: from2To3, + from3To4: from3To4, )); diff --git a/lib/models/database/tables/preferences.dart b/lib/models/database/tables/preferences.dart index c3904c84..492ac1f9 100644 --- a/lib/models/database/tables/preferences.dart +++ b/lib/models/database/tables/preferences.dart @@ -20,6 +20,25 @@ enum AudioSource { String get label => name[0].toUpperCase() + name.substring(1); } +enum YoutubeClientEngine { + ytDlp("yt-dlp"), + youtubeExplode("YouTubeExplode"), + newPipe("NewPipe"); + + final String label; + + const YoutubeClientEngine(this.label); + + bool isAvailableForPlatform() { + return switch (this) { + YoutubeClientEngine.youtubeExplode => + YouTubeExplodeEngine.isAvailableForPlatform, + YoutubeClientEngine.ytDlp => YtDlpEngine.isAvailableForPlatform, + YoutubeClientEngine.newPipe => NewPipeEngine.isAvailableForPlatform, + }; + } +} + enum MusicCodec { m4a._("M4a (Best for downloaded music)"), weba._("WebA (Best for streamed music)\nDoesn't support audio metadata"); @@ -84,6 +103,8 @@ class PreferencesTable extends Table { textEnum().withDefault(Constant(ThemeMode.system.name))(); TextColumn get audioSource => textEnum().withDefault(Constant(AudioSource.youtube.name))(); + TextColumn get youtubeClientEngine => textEnum() + .withDefault(Constant(YoutubeClientEngine.youtubeExplode.name))(); TextColumn get streamMusicCodec => textEnum().withDefault(Constant(SourceCodecs.weba.name))(); TextColumn get downloadMusicCodec => @@ -120,6 +141,7 @@ class PreferencesTable extends Table { invidiousInstance: "https://inv.nadeko.net", themeMode: ThemeMode.system, audioSource: AudioSource.youtube, + youtubeClientEngine: YoutubeClientEngine.youtubeExplode, streamMusicCodec: SourceCodecs.m4a, downloadMusicCodec: SourceCodecs.m4a, discordPresence: true, diff --git a/lib/modules/player/sibling_tracks_sheet.dart b/lib/modules/player/sibling_tracks_sheet.dart index 6f9763b6..ccc1bfcd 100644 --- a/lib/modules/player/sibling_tracks_sheet.dart +++ b/lib/modules/player/sibling_tracks_sheet.dart @@ -19,6 +19,7 @@ import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/provider/audio_player/querying_track_info.dart'; import 'package:spotube/provider/server/active_sourced_track.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; +import 'package:spotube/provider/youtube_engine/youtube_engine.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'; @@ -68,6 +69,7 @@ class SiblingTracksSheet extends HookConsumerWidget { final playlist = ref.watch(audioPlayerProvider); final isFetchingActiveTrack = ref.watch(queryingTrackInfoProvider); final preferences = ref.watch(userPreferencesProvider); + final youtubeEngine = ref.watch(youtubeEngineProvider); final isSearching = useState(false); final searchMode = useState(preferences.searchMode); @@ -115,14 +117,14 @@ class SiblingTracksSheet extends HookConsumerWidget { activeSourceInfo, ); } else { - final resultsYt = await youtubeClient.search.search(searchTerm.trim()); + final resultsYt = await youtubeEngine.searchVideos(searchTerm.trim()); final searchResults = await Future.wait( resultsYt .map(YoutubeVideoInfo.fromVideo) .mapIndexed((i, video) async { final siblingType = - await YoutubeSourcedTrack.toSiblingType(i, video); + await YoutubeSourcedTrack.toSiblingType(i, video, ref); return siblingType.info; }), ); @@ -139,6 +141,7 @@ class SiblingTracksSheet extends HookConsumerWidget { searchMode.value, activeTrack, preferences.audioSource, + youtubeEngine, ]); final siblings = useMemoized( @@ -151,12 +154,15 @@ class SiblingTracksSheet extends HookConsumerWidget { [activeTrack, isFetchingActiveTrack], ); + final previousActiveTrack = usePrevious(activeTrack); useEffect(() { + /// Populate sibling when active track changes + if (previousActiveTrack?.id == activeTrack?.id) return; if (activeTrack is SourcedTrack && activeTrack.siblings.isEmpty) { activeTrackNotifier.populateSibling(); } return null; - }, [activeTrack]); + }, [activeTrack, previousActiveTrack]); final itemBuilder = useCallback( (SourceInfo sourceInfo) { diff --git a/lib/modules/settings/youtube_engine_not_installed_dialog.dart b/lib/modules/settings/youtube_engine_not_installed_dialog.dart new file mode 100644 index 00000000..bc18bc66 --- /dev/null +++ b/lib/modules/settings/youtube_engine_not_installed_dialog.dart @@ -0,0 +1,121 @@ +import 'dart:io'; + +import 'package:flutter_form_builder/flutter_form_builder.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; +import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/form/text_form_field.dart'; +import 'package:spotube/extensions/context.dart'; +import 'package:spotube/models/database/database.dart'; +import 'package:spotube/services/kv_store/kv_store.dart'; +import 'package:spotube/utils/platform.dart'; +import 'package:url_launcher/url_launcher.dart'; +import 'package:yt_dlp_dart/yt_dlp_dart.dart'; + +const engineDownloadUrls = { + YoutubeClientEngine.ytDlp: + "https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#installation", +}; + +class YouTubeEngineNotInstalledDialog extends HookConsumerWidget { + final YoutubeClientEngine engine; + const YouTubeEngineNotInstalledDialog({ + super.key, + required this.engine, + }); + + @override + Widget build(BuildContext context, ref) { + final controller = useTextEditingController(); + final formKey = useMemoized(() => GlobalKey(), []); + + return AlertDialog( + title: Row( + spacing: 8, + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(SpotubeIcons.error, color: Colors.red), + Text( + context.l10n.youtube_engine_not_installed_title(engine.label), + style: const TextStyle(color: Colors.red), + ), + ], + ), + content: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 400), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 8, + children: [ + Text( + context.l10n.youtube_engine_not_installed_message(engine.label), + ), + if (engineDownloadUrls[engine] != null) + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text("${context.l10n.download}:"), + Button.link( + child: Text(engineDownloadUrls[engine]!.split("?").first), + onPressed: () async { + launchUrl(Uri.parse(engineDownloadUrls[engine]!)); + }, + ), + ], + ), + Text(context.l10n.youtube_engine_set_path(engine.label)), + const Gap(8), + FormBuilder( + key: formKey, + child: TextFormBuilderField( + name: "path", + controller: controller, + placeholder: Text(switch (context.theme.platform) { + TargetPlatform.macOS => "e.g. /opt/homebrew/bin/yt-dlp", + TargetPlatform.windows => + r"e.g. C:\Program Files\yt-dlp\yt-dlp.exe", + _ => "e.g. /home/user/.local/bin/yt-dlp", + }), + ), + ), + if (kIsMacOS || kIsLinux) + Text(context.l10n.youtube_engine_unix_issue_message), + ], + ), + ), + actions: [ + Button.text( + onPressed: () { + if (!context.mounted) return; + Navigator.of(context).pop(false); + }, + child: Text(context.l10n.cancel), + ), + Button.secondary( + onPressed: () async { + if (controller.text.isNotEmpty) { + if (!await File(controller.text).exists() && context.mounted) { + formKey.currentState?.fields["path"] + ?.invalidate(context.l10n.file_not_found); + return; + } + await KVStoreService.setYoutubeEnginePath( + engine, + controller.text, + ); + if (engine == YoutubeClientEngine.ytDlp) { + await YtDlp.instance.setBinaryLocation(controller.text); + } + } + if (!context.mounted) return; + Navigator.of(context).pop(true); + }, + child: Text(context.l10n.save), + ), + ], + ); + } +} diff --git a/lib/pages/root/root_app.dart b/lib/pages/root/root_app.dart index 43e8fdcb..e2b64b1e 100644 --- a/lib/pages/root/root_app.dart +++ b/lib/pages/root/root_app.dart @@ -3,6 +3,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shadcn_flutter/shadcn_flutter.dart'; +import 'package:spotube/hooks/configurators/use_check_yt_dlp_installed.dart'; import 'package:spotube/modules/root/bottom_player.dart'; import 'package:spotube/modules/root/sidebar/sidebar.dart'; import 'package:spotube/modules/root/spotube_navigation_bar.dart'; @@ -21,9 +22,11 @@ class RootAppPage extends HookConsumerWidget { final brightness = Theme.of(context).brightness; ref.listen(glanceProvider, (_, __) {}); + useGlobalSubscriptions(ref); useDownloaderDialogs(ref); useEndlessPlayback(ref); + useCheckYtDlpInstalled(ref); useEffect(() { SystemChrome.setSystemUIOverlayStyle( diff --git a/lib/pages/settings/sections/playback.dart b/lib/pages/settings/sections/playback.dart index 363e228c..8cbf7054 100644 --- a/lib/pages/settings/sections/playback.dart +++ b/lib/pages/settings/sections/playback.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:auto_route/auto_route.dart'; import 'package:collection/collection.dart'; import 'package:flutter/gestures.dart'; @@ -13,11 +15,14 @@ import 'package:spotube/models/database/database.dart'; import 'package:spotube/modules/settings/section_card_with_heading.dart'; import 'package:spotube/components/adaptive/adaptive_select_tile.dart'; import 'package:spotube/extensions/context.dart'; +import 'package:spotube/modules/settings/youtube_engine_not_installed_dialog.dart'; import 'package:spotube/provider/audio_player/sources/invidious_instances_provider.dart'; import 'package:spotube/provider/audio_player/sources/piped_instances_provider.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; +import 'package:spotube/services/kv_store/kv_store.dart'; import 'package:spotube/services/sourced_track/enums.dart'; +import 'package:spotube/services/youtube_engine/yt_dlp_engine.dart'; import 'package:spotube/utils/platform.dart'; class SettingsPlaybackSection extends HookConsumerWidget { @@ -195,28 +200,56 @@ class SettingsPlaybackSection extends HookConsumerWidget { }, ), ), - AnimatedCrossFade( - duration: const Duration(milliseconds: 300), - crossFadeState: preferences.audioSource == AudioSource.youtube - ? CrossFadeState.showFirst - : CrossFadeState.showSecond, - firstChild: const SizedBox.shrink(), - secondChild: AdaptiveSelectTile( - secondary: const Icon(SpotubeIcons.search), - title: Text(context.l10n.search_mode), - value: preferences.searchMode, - options: SearchMode.values - .map((e) => SelectItemButton( - value: e, - child: Text(e.label), - )) - .toList(), - onChanged: (value) { - if (value == null) return; - preferencesNotifier.setSearchMode(value); - }, - ), - ), + switch (preferences.audioSource) { + AudioSource.youtube => AdaptiveSelectTile( + secondary: const Icon(SpotubeIcons.engine), + title: Text(context.l10n.youtube_engine), + value: preferences.youtubeClientEngine, + options: YoutubeClientEngine.values + .where((e) => e.isAvailableForPlatform()) + .map((e) => SelectItemButton( + value: e, + child: Text(e.label), + )) + .toList(), + onChanged: (value) async { + if (value == null) return; + if (value == YoutubeClientEngine.ytDlp) { + final customPath = KVStoreService.getYoutubeEnginePath(value); + if (!await YtDlpEngine.isInstalled() && + (customPath == null || + !await File(customPath).exists()) && + context.mounted) { + final hasInstalled = await showDialog( + context: context, + builder: (context) => + YouTubeEngineNotInstalledDialog(engine: value), + ); + if (hasInstalled != true) return; + } + } + preferencesNotifier.setYoutubeClientEngine(value); + }, + ), + AudioSource.piped || + AudioSource.invidious => + AdaptiveSelectTile( + secondary: const Icon(SpotubeIcons.search), + title: Text(context.l10n.search_mode), + value: preferences.searchMode, + options: SearchMode.values + .map((e) => SelectItemButton( + value: e, + child: Text(e.label), + )) + .toList(), + onChanged: (value) { + if (value == null) return; + preferencesNotifier.setSearchMode(value); + }, + ), + _ => const SizedBox.shrink(), + }, AnimatedCrossFade( duration: const Duration(milliseconds: 300), crossFadeState: preferences.searchMode == SearchMode.youtube && diff --git a/lib/provider/local_tracks/local_tracks_provider.dart b/lib/provider/local_tracks/local_tracks_provider.dart index 3245ff2d..db8c3401 100644 --- a/lib/provider/local_tracks/local_tracks_provider.dart +++ b/lib/provider/local_tracks/local_tracks_provider.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'dart:io'; -import 'package:collection/collection.dart'; import 'package:spotube/services/logger/logger.dart'; import 'package:flutter/foundation.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; @@ -110,7 +109,7 @@ final localTracksProvider = return null; } }), - ).then((value) => value.whereNotNull().toList()); + ).then((value) => value.nonNulls.toList()); final tracksFromMetadata = filesWithMetadata .map( diff --git a/lib/provider/server/routes/playback.dart b/lib/provider/server/routes/playback.dart index 3a480248..9ee00896 100644 --- a/lib/provider/server/routes/playback.dart +++ b/lib/provider/server/routes/playback.dart @@ -11,7 +11,6 @@ import 'package:shelf/shelf.dart'; import 'package:spotube/extensions/artist_simple.dart'; import 'package:spotube/extensions/image.dart'; import 'package:spotube/extensions/track.dart'; -import 'package:spotube/models/database/database.dart'; import 'package:spotube/models/parser/range_headers.dart'; import 'package:spotube/provider/audio_player/audio_player.dart'; import 'package:spotube/provider/audio_player/state.dart'; @@ -125,14 +124,9 @@ class ServerPlaybackRoutes { ) .catchError((e, stack) async { AppLogger.reportError(e, stack); - final sourcedTrack = userPreferences.audioSource == AudioSource.youtube && - e is DioException - ? await ref - .read(sourcedTrackProvider(SpotubeMedia(track)).notifier) - .refreshStreamingUrl() - : await ref - .read(sourcedTrackProvider(SpotubeMedia(track)).notifier) - .switchToAlternativeSources(); + final sourcedTrack = await ref + .read(sourcedTrackProvider(SpotubeMedia(track)).notifier) + .refreshStreamingUrl(); ref.read(activeSourcedTrackProvider.notifier).update(sourcedTrack); diff --git a/lib/provider/server/sourced_track.dart b/lib/provider/server/sourced_track.dart index 2081ac0a..f733f9d6 100644 --- a/lib/provider/server/sourced_track.dart +++ b/lib/provider/server/sourced_track.dart @@ -41,18 +41,6 @@ class SourcedTrackNotifier ); }); } - - Future switchToAlternativeSources() async { - if (arg == null) { - return null; - } - return await update((prev) async { - return await SourcedTrack.fetchFromTrackAltSource( - track: arg!.track, - ref: ref, - ); - }); - } } final sourcedTrackProvider = AsyncNotifierProviderFamily PlaylistsFeatured.fromJson(json), ).getPage(limit, offset); - final items = playlists.items?.whereNotNull().toList() ?? []; + final items = playlists.items?.nonNulls.toList() ?? []; return ( items: items, diff --git a/lib/provider/user_preferences/user_preferences_provider.dart b/lib/provider/user_preferences/user_preferences_provider.dart index eeb712e1..75234241 100644 --- a/lib/provider/user_preferences/user_preferences_provider.dart +++ b/lib/provider/user_preferences/user_preferences_provider.dart @@ -207,6 +207,10 @@ class UserPreferencesNotifier extends Notifier { setData(PreferencesTableCompanion(audioSource: Value(type))); } + void setYoutubeClientEngine(YoutubeClientEngine engine) { + setData(PreferencesTableCompanion(youtubeClientEngine: Value(engine))); + } + void setSystemTitleBar(bool isSystemTitleBar) { setData( PreferencesTableCompanion( diff --git a/lib/provider/youtube_engine/youtube_engine.dart b/lib/provider/youtube_engine/youtube_engine.dart new file mode 100644 index 00000000..0aa37db5 --- /dev/null +++ b/lib/provider/youtube_engine/youtube_engine.dart @@ -0,0 +1,22 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:spotube/models/database/database.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; +import 'package:spotube/services/youtube_engine/newpipe_engine.dart'; +import 'package:spotube/services/youtube_engine/youtube_explode_engine.dart'; +import 'package:spotube/services/youtube_engine/yt_dlp_engine.dart'; + +final youtubeEngineProvider = Provider((ref) { + final engineMode = ref.watch( + userPreferencesProvider.select((value) => value.youtubeClientEngine), + ); + + if (engineMode == YoutubeClientEngine.newPipe && + NewPipeEngine.isAvailableForPlatform) { + return NewPipeEngine(); + } else if (engineMode == YoutubeClientEngine.ytDlp && + YtDlpEngine.isAvailableForPlatform) { + return YtDlpEngine(); + } else { + return YouTubeExplodeEngine(); + } +}); diff --git a/lib/services/kv_store/kv_store.dart b/lib/services/kv_store/kv_store.dart index efe83abf..e334322e 100644 --- a/lib/services/kv_store/kv_store.dart +++ b/lib/services/kv_store/kv_store.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'package:encrypt/encrypt.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'package:spotube/models/database/database.dart'; import 'package:spotube/services/wm_tools/wm_tools.dart'; import 'package:uuid/uuid.dart'; @@ -87,4 +88,31 @@ abstract class KVStoreService { sharedPreferences.getBool('hasMigratedToDrift') ?? false; static Future setHasMigratedToDrift(bool value) async => await sharedPreferences.setBool('hasMigratedToDrift', value); + + static Map? get _youtubeEnginePaths { + final jsonRaw = sharedPreferences.getString('ytDlpPath'); + + if (jsonRaw == null) { + return null; + } + + return jsonDecode(jsonRaw); + } + + static String? getYoutubeEnginePath(YoutubeClientEngine engine) { + return _youtubeEnginePaths?[engine.name]; + } + + static Future setYoutubeEnginePath( + YoutubeClientEngine engine, + String path, + ) async { + await sharedPreferences.setString( + 'ytDlpPath', + jsonEncode({ + ...?_youtubeEnginePaths, + engine.name: path, + }), + ); + } } diff --git a/lib/services/sourced_track/sourced_track.dart b/lib/services/sourced_track/sourced_track.dart index 38f01498..272295e4 100644 --- a/lib/services/sourced_track/sourced_track.dart +++ b/lib/services/sourced_track/sourced_track.dart @@ -1,15 +1,9 @@ -import 'dart:io'; - -import 'package:http/http.dart'; -import 'package:collection/collection.dart'; -import 'package:dio/dio.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/models/database/database.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/services/sourced_track/enums.dart'; -import 'package:spotube/services/sourced_track/exceptions.dart'; import 'package:spotube/services/sourced_track/models/source_info.dart'; import 'package:spotube/services/sourced_track/models/source_map.dart'; import 'package:spotube/services/sourced_track/sources/invidious.dart'; @@ -17,7 +11,6 @@ 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:youtube_explode_dart/youtube_explode_dart.dart'; abstract class SourcedTrack extends Track { final SourceMap source; @@ -97,11 +90,8 @@ abstract class SourcedTrack extends Track { } static String getSearchTerm(Track track) { - final artists = (track.artists ?? []) - .map((ar) => ar.name) - .toList() - .whereNotNull() - .toList(); + final artists = + (track.artists ?? []).map((ar) => ar.name).toList().nonNulls.toList(); final title = ServiceUtils.getTitle( track.name!, @@ -112,100 +102,21 @@ abstract class SourcedTrack extends Track { return "$title - ${artists.join(", ")}"; } - static fetchFromTrackAltSource({ - required Track track, - required Ref ref, - }) async { - final preferences = ref.read(userPreferencesProvider); - try { - return switch (preferences.audioSource) { - AudioSource.piped || - AudioSource.invidious || - AudioSource.jiosaavn => - await YoutubeSourcedTrack.fetchFromTrack(track: track, ref: ref), - AudioSource.youtube => - await JioSaavnSourcedTrack.fetchFromTrack(track: track, ref: ref), - }; - } on TrackNotFoundError catch (_) { - return switch (preferences.audioSource) { - AudioSource.piped || - AudioSource.youtube || - AudioSource.invidious => - await JioSaavnSourcedTrack.fetchFromTrack( - track: track, - ref: ref, - weakMatch: true, - ), - AudioSource.jiosaavn => - await YoutubeSourcedTrack.fetchFromTrack(track: track, ref: ref), - }; - } on HttpClientClosedException catch (_) { - return await PipedSourcedTrack.fetchFromTrack(track: track, ref: ref); - } on VideoUnplayableException catch (_) { - return await InvidiousSourcedTrack.fetchFromTrack(track: track, ref: ref); - } catch (e) { - if (e is DioException || e is ClientException || e is SocketException) { - return await JioSaavnSourcedTrack.fetchFromTrack( - track: track, - ref: ref, - weakMatch: preferences.audioSource == AudioSource.jiosaavn, - ); - } - rethrow; - } - } - static Future fetchFromTrack({ required Track track, required Ref ref, }) async { final preferences = ref.read(userPreferencesProvider); - try { - return switch (preferences.audioSource) { - AudioSource.piped => - await PipedSourcedTrack.fetchFromTrack(track: track, ref: ref), - AudioSource.youtube => - await YoutubeSourcedTrack.fetchFromTrack(track: track, ref: ref), - AudioSource.jiosaavn => - await JioSaavnSourcedTrack.fetchFromTrack(track: track, ref: ref), - AudioSource.invidious => - await InvidiousSourcedTrack.fetchFromTrack(track: track, ref: ref), - }; - } on TrackNotFoundError catch (_) { - return switch (preferences.audioSource) { - AudioSource.piped || - AudioSource.youtube || - AudioSource.invidious => - await JioSaavnSourcedTrack.fetchFromTrack( - track: track, - ref: ref, - weakMatch: true, - ), - AudioSource.jiosaavn => - await YoutubeSourcedTrack.fetchFromTrack(track: track, ref: ref), - }; - } on HttpClientClosedException catch (_) { - return await PipedSourcedTrack.fetchFromTrack(track: track, ref: ref); - } on VideoUnplayableException catch (_) { - return await PipedSourcedTrack.fetchFromTrack(track: track, ref: ref); - } catch (e) { - if (e is DioException || e is ClientException || e is SocketException) { - return switch (preferences.audioSource) { - AudioSource.piped || - AudioSource.invidious => - await YoutubeSourcedTrack.fetchFromTrack( - track: track, - ref: ref, - ), - _ => await JioSaavnSourcedTrack.fetchFromTrack( - track: track, - ref: ref, - weakMatch: preferences.audioSource == AudioSource.jiosaavn, - ) - }; - } - rethrow; - } + return switch (preferences.audioSource) { + AudioSource.youtube => + await YoutubeSourcedTrack.fetchFromTrack(track: track, ref: ref), + AudioSource.piped => + await PipedSourcedTrack.fetchFromTrack(track: track, ref: ref), + AudioSource.invidious => + await InvidiousSourcedTrack.fetchFromTrack(track: track, ref: ref), + AudioSource.jiosaavn => + await JioSaavnSourcedTrack.fetchFromTrack(track: track, ref: ref), + }; } static Future> fetchSiblings({ diff --git a/lib/services/sourced_track/sources/invidious.dart b/lib/services/sourced_track/sources/invidious.dart index 2ec5068e..4a32ad41 100644 --- a/lib/services/sourced_track/sources/invidious.dart +++ b/lib/services/sourced_track/sources/invidious.dart @@ -50,6 +50,22 @@ class InvidiousSourcedTrack extends SourcedTrack { required Track track, required Ref ref, }) async { + // Indicates a stream url refresh + if (track is InvidiousSourcedTrack) { + final manifest = await ref + .read(invidiousProvider) + .videos + .get(track.sourceInfo.id, local: true); + + return InvidiousSourcedTrack( + ref: ref, + siblings: track.siblings, + source: toSourceMap(manifest), + sourceInfo: track.sourceInfo, + track: track, + ); + } + final database = ref.read(databaseProvider); final cachedSource = await (database.select(database.sourceMatchTable) ..where((s) => s.trackId.equals(track.id!)) diff --git a/lib/services/sourced_track/sources/piped.dart b/lib/services/sourced_track/sources/piped.dart index d24f110f..1728753a 100644 --- a/lib/services/sourced_track/sources/piped.dart +++ b/lib/services/sourced_track/sources/piped.dart @@ -50,6 +50,19 @@ class PipedSourcedTrack extends SourcedTrack { required Track track, required Ref ref, }) async { + // Means it wants a refresh of the stream + if (track is PipedSourcedTrack) { + final manifest = + await ref.read(pipedProvider).streams(track.sourceInfo.id); + return PipedSourcedTrack( + ref: ref, + siblings: track.siblings, + sourceInfo: track.sourceInfo, + source: toSourceMap(manifest), + track: track, + ); + } + final database = ref.read(databaseProvider); final cachedSource = await (database.select(database.sourceMatchTable) ..where((s) => s.trackId.equals(track.id!)) @@ -183,11 +196,8 @@ class PipedSourcedTrack extends SourcedTrack { : preference.searchMode == SearchMode.youtubeMusic; if (isYouTubeMusic) { - final artists = (track.artists ?? []) - .map((ar) => ar.name) - .toList() - .whereNotNull() - .toList(); + final artists = + (track.artists ?? []).map((ar) => ar.name).toList().nonNulls.toList(); return await Future.wait( searchResults diff --git a/lib/services/sourced_track/sources/youtube.dart b/lib/services/sourced_track/sources/youtube.dart index f54b1772..c4881051 100644 --- a/lib/services/sourced_track/sources/youtube.dart +++ b/lib/services/sourced_track/sources/youtube.dart @@ -4,6 +4,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/models/database/database.dart'; import 'package:spotube/provider/database/database.dart'; +import 'package:spotube/provider/youtube_engine/youtube_engine.dart'; import 'package:spotube/services/logger/logger.dart'; import 'package:spotube/services/song_link/song_link.dart'; import 'package:spotube/services/sourced_track/enums.dart'; @@ -15,7 +16,6 @@ import 'package:spotube/services/sourced_track/sourced_track.dart'; import 'package:spotube/utils/service_utils.dart'; import 'package:youtube_explode_dart/youtube_explode_dart.dart'; -final youtubeClient = YoutubeExplode(); final officialMusicRegex = RegExp( r"official\s(video|audio|music\svideo|lyric\svideo|visualizer)", caseSensitive: false, @@ -43,24 +43,15 @@ class YoutubeSourcedTrack extends SourcedTrack { required super.ref, }); - static Future _getStreamManifest(String id) async { - return youtubeClient.videos.streamsClient.getManifest( - id, - requireWatchPage: false, - ytClients: [ - YoutubeApiClient.android, - YoutubeApiClient.mweb, - ], - ); - } - static Future fetchFromTrack({ required Track track, required Ref ref, }) async { // Indicates the track is requesting a stream refresh if (track is YoutubeSourcedTrack) { - final manifest = await _getStreamManifest(track.sourceInfo.id); + final manifest = await ref + .read(youtubeEngineProvider) + .getStreamManifest(track.sourceInfo.id); final sourcedTrack = YoutubeSourcedTrack( ref: ref, @@ -108,8 +99,10 @@ class YoutubeSourcedTrack extends SourcedTrack { track: track, ); } - final item = await youtubeClient.videos.get(cachedSource.sourceId); - final manifest = await _getStreamManifest(cachedSource.sourceId); + final (item, manifest) = await ref + .read(youtubeEngineProvider) + .getVideoWithStreamInfo(cachedSource.sourceId); + final sourcedTrack = YoutubeSourcedTrack( ref: ref, siblings: [], @@ -162,10 +155,13 @@ class YoutubeSourcedTrack extends SourcedTrack { static Future toSiblingType( int index, YoutubeVideoInfo item, + dynamic ref, ) async { + assert(ref is WidgetRef || ref is Ref, "Invalid ref type"); SourceMap? sourceMap; if (index == 0) { - final manifest = await _getStreamManifest(item.id); + final manifest = + await ref.read(youtubeEngineProvider).getStreamManifest(item.id); sourceMap = toSourceMap(manifest); } @@ -188,11 +184,8 @@ class YoutubeSourcedTrack extends SourcedTrack { static List rankResults( List results, Track track) { - final artists = (track.artists ?? []) - .map((ar) => ar.name) - .toList() - .whereNotNull() - .toList(); + final artists = + (track.artists ?? []).map((ar) => ar.name).toList().nonNulls.toList(); return results .sorted((a, b) => b.views.compareTo(a.views)) @@ -259,8 +252,11 @@ class YoutubeSourcedTrack extends SourcedTrack { await toSiblingType( 0, YoutubeVideoInfo.fromVideo( - await youtubeClient.videos.get(ytLink!.url!), + await ref.read(youtubeEngineProvider).getVideo( + Uri.parse(ytLink!.url!).queryParameters["v"]!, + ), ), + ref, ) ]; } on VideoUnplayableException catch (e, stack) { @@ -271,15 +267,13 @@ class YoutubeSourcedTrack extends SourcedTrack { final query = SourcedTrack.getSearchTerm(track); - final searchResults = await youtubeClient.search.search( - "$query - Topic", - filter: TypeFilters.video, - ); + final searchResults = + await ref.read(youtubeEngineProvider).searchVideos(query); if (ServiceUtils.onlyContainsEnglish(query)) { return await Future.wait(searchResults .map(YoutubeVideoInfo.fromVideo) - .mapIndexed(toSiblingType)); + .mapIndexed((index, info) => toSiblingType(index, info, ref))); } final rankedSiblings = rankResults( @@ -287,7 +281,10 @@ class YoutubeSourcedTrack extends SourcedTrack { track, ); - return await Future.wait(rankedSiblings.mapIndexed(toSiblingType)); + return await Future.wait( + rankedSiblings + .mapIndexed((index, info) => toSiblingType(index, info, ref)), + ); } @override @@ -305,7 +302,9 @@ class YoutubeSourcedTrack extends SourcedTrack { final newSiblings = siblings.where((s) => s.id != sibling.id).toList() ..insert(0, sourceInfo); - final manifest = await _getStreamManifest(newSourceInfo.id); + final manifest = await ref + .read(youtubeEngineProvider) + .getStreamManifest(newSourceInfo.id); final database = ref.read(databaseProvider); diff --git a/lib/services/youtube_engine/newpipe_engine.dart b/lib/services/youtube_engine/newpipe_engine.dart new file mode 100644 index 00000000..f58fc333 --- /dev/null +++ b/lib/services/youtube_engine/newpipe_engine.dart @@ -0,0 +1,109 @@ +import 'package:flutter_new_pipe_extractor/flutter_new_pipe_extractor.dart' + hide Engagement; +import 'package:spotube/services/youtube_engine/youtube_engine.dart'; +import 'package:spotube/utils/platform.dart'; +import 'package:youtube_explode_dart/youtube_explode_dart.dart'; +import 'package:http_parser/http_parser.dart'; + +class NewPipeEngine implements YouTubeEngine { + static bool get isAvailableForPlatform => kIsAndroid; + + AudioOnlyStreamInfo _parseAudioStream(AudioStream stream, String videoId) { + return AudioOnlyStreamInfo( + VideoId(videoId), + stream.itag, + Uri.parse(stream.content), + StreamContainer.parse(stream.mediaFormat!.mimeType.split("/").last), + FileSize.unknown, + Bitrate(stream.bitrate), + stream.codec, + stream.quality, + [], + MediaType.parse(stream.mediaFormat!.mimeType), + null, + ); + } + + Video _parseVideo(VideoInfo info) { + return Video( + VideoId(info.id), + info.name, + info.uploaderName, + ChannelId(info.uploaderUrl), + info.uploadDate.offsetDateTime, + info.uploadDate.offsetDateTime.toString(), + info.uploadDate.offsetDateTime, + info.description.content ?? "", + Duration(seconds: info.duration), + ThumbnailSet(info.id), + info.tags, + Engagement( + info.viewCount, + info.likeCount, + info.dislikeCount, + ), + !info.streamType.name.toLowerCase().contains("live"), + ); + } + + Video _parseVideoResult(VideoSearchResultItem info) { + final id = Uri.parse(info.url).queryParameters["v"]!; + return Video( + VideoId(id), + info.name, + info.uploaderName, + ChannelId(info.uploaderUrl), + info.uploadDate?.offsetDateTime, + info.uploadDate?.offsetDateTime.toString(), + info.uploadDate?.offsetDateTime, + info.shortDescription ?? "", + Duration(seconds: info.duration), + ThumbnailSet(id), + [], + Engagement(info.viewCount, null, null), + !info.streamType.name.toLowerCase().contains("live"), + ); + } + + @override + Future getStreamManifest(String videoId) async { + final video = await NewPipeExtractor.getVideoInfo(videoId); + + final streams = + video.audioStreams.map((stream) => _parseAudioStream(stream, videoId)); + + return StreamManifest(streams); + } + + @override + Future

© Copyright Spotube 2024

diff --git a/aur-struct/.SRCINFO b/aur-struct/.SRCINFO index 89878245..772594f6 100644 --- a/aur-struct/.SRCINFO +++ b/aur-struct/.SRCINFO @@ -1,8 +1,8 @@ pkgbase = spotube-bin pkgdesc = Open source Spotify client that doesn't require Premium nor uses Electron! Available for both desktop & mobile! -pkgver = 3.7.1 -pkgrel = 2 -url = https://github.com/KRTirtho/spotube/ +pkgver = 4.0.0 +pkgrel = 1 +url = https://spotube.krtirtho.dev arch = x86_64 license = BSD-4-Clause depends = mpv diff --git a/aur-struct/PKGBUILD b/aur-struct/PKGBUILD index 735f992e..cf6c0134 100644 --- a/aur-struct/PKGBUILD +++ b/aur-struct/PKGBUILD @@ -5,7 +5,7 @@ pkgrel=%{{PKGREL}}% epoch= pkgdesc="Open source Spotify client that doesn't require Premium nor uses Electron! Available for both desktop & mobile!" arch=(x86_64) -url="https://github.com/KRTirtho/spotube/" +url="https://spotube.krtirtho.dev" license=('BSD-4-Clause') groups=() depends=('mpv' 'libappindicator-gtk3' 'libsecret' 'jsoncpp' 'libnotify' 'xdg-user-dirs' 'webkit2gtk-4.1') diff --git a/choco-struct/spotube.nuspec b/choco-struct/spotube.nuspec index 1cef4354..1ebcd3c7 100644 --- a/choco-struct/spotube.nuspec +++ b/choco-struct/spotube.nuspec @@ -1,5 +1,6 @@ - + @@ -12,34 +13,39 @@ spotube (Install) Kingkor Roy Tirtho - https://github.com/KRTirtho/spotube/ - https://rawcdn.githack.com/KRTirtho/spotube/7edb0bb834eb18c05551e30a891720a6abf53dbe/assets/spotube-logo.png + https://spotube.krtirtho.dev + + https://rawcdn.githack.com/KRTirtho/spotube/7edb0bb834eb18c05551e30a891720a6abf53dbe/assets/spotube-logo.png 2022 Spotube https://github.com/KRTirtho/spotube/blob/master/LICENSE true https://github.com/KRTirtho/spotube - https://github.com/KRTirtho/spotube#readme + https://spotube.krtirtho.dev https://github.com/KRTirtho/spotube/issues/new spotube music audio spotify youtube flutter - 🎧 Open source Spotify client that doesn't require Premium nor uses Electron! Available for both desktop & mobile! + 🎧 Open source Spotify client that doesn't require Premium nor uses Electron! Available + for both desktop & mobile! - Spotube is a Flutter based lightweight spotify client. It utilizes the power - of Spotify & Youtube's public API & creates a hazardless, performant & resource - friendly User Experience + Spotube is a Flutter based lightweight spotify client. It utilizes the power + of Spotify & Youtube's public API & creates a hazardless, performant & resource + friendly User Experience - # Features - - Open source/libre software - - Anonymous/guest login - - Cross platform support - - No telemetry, diagnostics or user data collection - - Lightweight & resource-friendly - - Native performance (Thanks to Flutter+Skia) - - Playback control is done locally instead of on the server - - Small size & less data usage - - No Spotify or YouTube ads since it uses all public & free APIs (It is still recommended to support the creators by watching/liking/subscribing to the artists' YouTube channels or liking their tracks on Spotify. Purchasing Spotify Premium is usually the best way to support their valuable creations.) - - Time synced lyrics - - Downloadable tracks + # Features + - Open source/libre software + - Anonymous/guest login + - Cross platform support + - No telemetry, diagnostics or user data collection + - Lightweight & resource-friendly + - Native performance (Thanks to Flutter+Skia) + - Playback control is done locally instead of on the server + - Small size & less data usage + - No Spotify or YouTube ads since it uses all public & free APIs (It is still recommended + to support the creators by watching/liking/subscribing to the artists' YouTube channels or + liking their tracks on Spotify. Purchasing Spotify Premium is usually the best way to support + their valuable creations.) + - Time synced lyrics + - Downloadable tracks https://github.com/KRTirtho/spotube/releases/tag/v%{{SPOTUBE_VERSION}}% diff --git a/choco-struct/tools/LICENSE.txt b/choco-struct/tools/LICENSE.txt index 6d460a42..1a285107 100644 --- a/choco-struct/tools/LICENSE.txt +++ b/choco-struct/tools/LICENSE.txt @@ -2,7 +2,7 @@ BSD 4-Clause License -Copyright (c) 2022 Kingkor Roy Tirtho. All rights reserved. +Copyright (c) 2025 Kingkor Roy Tirtho. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/lib/l10n/app_ar.arb b/lib/l10n/app_ar.arb index 8cb52b38..f4cbde9b 100644 --- a/lib/l10n/app_ar.arb +++ b/lib/l10n/app_ar.arb @@ -401,5 +401,30 @@ "export_cache_files": "تصدير الملفات المخزنة مؤقتًا", "found_n_files": "تم العثور على {count} ملف", "export_cache_confirmation": "هل تريد تصدير هذه الملفات إلى", - "exported_n_out_of_m_files": "تم تصدير {filesExported} من أصل {files} ملفات" + "exported_n_out_of_m_files": "تم تصدير {filesExported} من أصل {files} ملفات", + "playlist": "قائمة التشغيل", + "no_loop": "بدون تكرار", + "generate": "إنشاء", + "undo": "تراجع", + "download_all": "تنزيل الكل", + "add_all_to_playlist": "إضافة الكل إلى قائمة التشغيل", + "add_all_to_queue": "إضافة الكل إلى القائمة", + "play_all_next": "تشغيل الكل بعد ذلك", + "pause": "إيقاف مؤقت", + "view_all": "عرض الكل", + "no_tracks_added_yet": "يبدو أنك لم تضف أي مسارات بعد", + "no_tracks": "يبدو أنه لا يوجد أي مسارات هنا", + "no_tracks_listened_yet": "يبدو أنك لم تستمع إلى أي شيء بعد", + "not_following_artists": "أنت لا تتابع أي فنانين", + "no_favorite_albums_yet": "يبدو أنك لم تضف أي ألبومات إلى المفضلة بعد", + "no_logs_found": "لم يتم العثور على سجلات", + "youtube_engine": "محرك يوتيوب", + "youtube_engine_not_installed_title": "{engine} غير مثبت", + "youtube_engine_not_installed_message": "{engine} غير مثبت في نظامك.", + "youtube_engine_set_path": "تأكد من أنه متاح في متغير PATH أو\nحدد المسار الكامل للملف القابل للتنفيذ {engine} أدناه", + "youtube_engine_unix_issue_message": "في أنظمة macOS/Linux/Unix مثل الأنظمة، لن يعمل تعيين المسار في .zshrc/.bashrc/.bash_profile وما إلى ذلك.\nيجب تعيين المسار في ملف تكوين الصدفة", + "download": "تنزيل", + "file_not_found": "الملف غير موجود", + "custom": "مخصص", + "add_custom_url": "إضافة URL مخصص" } \ No newline at end of file diff --git a/lib/l10n/app_bn.arb b/lib/l10n/app_bn.arb index ff49aafd..cc2971ce 100644 --- a/lib/l10n/app_bn.arb +++ b/lib/l10n/app_bn.arb @@ -401,5 +401,30 @@ "export_cache_files": "ক্যাশে ফাইল রপ্তানি", "found_n_files": "{count} টি ফাইল পাওয়া গেছে", "export_cache_confirmation": "আপনি কি এই ফাইলগুলি রপ্তানি করতে চান", - "exported_n_out_of_m_files": "{filesExported} টি ফাইল রপ্তানি করা হয়েছে {files} এর মধ্যে" + "exported_n_out_of_m_files": "{filesExported} টি ফাইল রপ্তানি করা হয়েছে {files} এর মধ্যে", + "playlist": "প্লেলিস্ট", + "no_loop": "কোনো লুপ নেই", + "generate": "উৎপন্ন করুন", + "undo": "পূর্বাবস্থায় ফিরুন", + "download_all": "সব ডাউনলোড করুন", + "add_all_to_playlist": "সব প্লেলিস্টে যোগ করুন", + "add_all_to_queue": "সব কিউতে যোগ করুন", + "play_all_next": "সব পরবর্তী খেলুন", + "pause": "বিরতি", + "view_all": "সব দেখুন", + "no_tracks_added_yet": "এখনও কোনো ট্র্যাক যোগ করা হয়নি মনে হচ্ছে", + "no_tracks": "এখানে কোনো ট্র্যাক নেই মনে হচ্ছে", + "no_tracks_listened_yet": "এখনও কিছু শোনা হয়নি মনে হচ্ছে", + "not_following_artists": "আপনি কোনো শিল্পীকে অনুসরণ করছেন না", + "no_favorite_albums_yet": "এখনও কোনো অ্যালবাম প্রিয় তালিকায় যোগ করা হয়নি মনে হচ্ছে", + "no_logs_found": "কোনো লগ পাওয়া যায়নি", + "youtube_engine": "ইউটিউব ইঞ্জিন", + "youtube_engine_not_installed_title": "{engine} ইনস্টল করা নেই", + "youtube_engine_not_installed_message": "{engine} আপনার সিস্টেমে ইনস্টল করা নেই।", + "youtube_engine_set_path": "এটি PATH ভেরিয়েবলে উপলব্ধ কিনা নিশ্চিত করুন অথবা\nনীচে {engine} এক্সিকিউটেবল এর পূর্ণপথ সেট করুন", + "youtube_engine_unix_issue_message": "macOS/Linux/Unix-এর মতো অপারেটিং সিস্টেমে, .zshrc/.bashrc/.bash_profile ইত্যাদিতে পাথ সেট করা কাজ করবে না।\nআপনাকে শেল কনফিগারেশন ফাইলে পাথ সেট করতে হবে", + "download": "ডাউনলোড", + "file_not_found": "ফাইল পাওয়া যায়নি", + "custom": "কাস্টম", + "add_custom_url": "কাস্টম URL যোগ করুন" } \ No newline at end of file diff --git a/lib/l10n/app_ca.arb b/lib/l10n/app_ca.arb index aee39ffd..7cb007c4 100644 --- a/lib/l10n/app_ca.arb +++ b/lib/l10n/app_ca.arb @@ -401,5 +401,30 @@ "export_cache_files": "Exportar arxius en caché", "found_n_files": "S'han trobat {count} arxius", "export_cache_confirmation": "Voleu exportar aquests arxius a", - "exported_n_out_of_m_files": "S'han exportat {filesExported} de {files} arxius" + "exported_n_out_of_m_files": "S'han exportat {filesExported} de {files} arxius", + "playlist": "Llista de reproducció", + "no_loop": "Sense repetició", + "generate": "Generar", + "undo": "Desfer", + "download_all": "Descarregar tot", + "add_all_to_playlist": "Afegir tot a la llista de reproducció", + "add_all_to_queue": "Afegir tot a la cua", + "play_all_next": "Reproduir tot a continuació", + "pause": "Pausa", + "view_all": "Veure tot", + "no_tracks_added_yet": "Sembla que encara no has afegit cap pista", + "no_tracks": "Sembla que no hi ha pistes aquí", + "no_tracks_listened_yet": "Sembla que no has escoltat res encara", + "not_following_artists": "No estàs seguint cap artista", + "no_favorite_albums_yet": "Sembla que encara no has afegit cap àlbum als teus favorits", + "no_logs_found": "No s'han trobat registres", + "youtube_engine": "Motor de YouTube", + "youtube_engine_not_installed_title": "{engine} no està instal·lat", + "youtube_engine_not_installed_message": "{engine} no està instal·lat al teu sistema.", + "youtube_engine_set_path": "Assegura't que estigui disponible a la variable PATH o\nestableix el camí absolut a l'executable de {engine} a continuació", + "youtube_engine_unix_issue_message": "En macOS/Linux/Unix com a sistemes operatius, establir el camí a .zshrc/.bashrc/.bash_profile etc. no funcionarà.\nHas de configurar el camí al fitxer de configuració de la shell", + "download": "Descarregar", + "file_not_found": "Fitxer no trobat", + "custom": "Personalitzat", + "add_custom_url": "Afegir URL personalitzada" } \ No newline at end of file diff --git a/lib/l10n/app_cs.arb b/lib/l10n/app_cs.arb index a40251c0..a6fdf25c 100644 --- a/lib/l10n/app_cs.arb +++ b/lib/l10n/app_cs.arb @@ -401,5 +401,30 @@ "export_cache_files": "Exportovat soubory z mezipaměti", "found_n_files": "Nalezeno {count} souborů", "export_cache_confirmation": "Chcete exportovat tyto soubory do", - "exported_n_out_of_m_files": "Exportováno {filesExported} z {files} souborů" + "exported_n_out_of_m_files": "Exportováno {filesExported} z {files} souborů", + "playlist": "Seznam skladeb", + "no_loop": "Žádné opakování", + "generate": "Generovat", + "undo": "Zpět", + "download_all": "Stáhnout vše", + "add_all_to_playlist": "Přidat vše do seznamu skladeb", + "add_all_to_queue": "Přidat vše do fronty", + "play_all_next": "Přehrát vše následně", + "pause": "Pauza", + "view_all": "Zobrazit vše", + "no_tracks_added_yet": "Zdá se, že jste ještě nepřidali žádné skladby", + "no_tracks": "Zdá se, že zde nejsou žádné skladby", + "no_tracks_listened_yet": "Zdá se, že jste ještě nic neposlouchali", + "not_following_artists": "Nezajímáte se o žádné umělce", + "no_favorite_albums_yet": "Zdá se, že jste ještě nepřidali žádné alba mezi oblíbené", + "no_logs_found": "Žádné záznamy nenalezeny", + "youtube_engine": "YouTube Engine", + "youtube_engine_not_installed_title": "{engine} není nainstalován", + "youtube_engine_not_installed_message": "{engine} není nainstalován ve vašem systému.", + "youtube_engine_set_path": "Ujistěte se, že je k dispozici v proměnné PATH nebo\nnastavte absolutní cestu k {engine} spustitelnému souboru níže", + "youtube_engine_unix_issue_message": "V macOS/Linux/Unixových systémech nebude fungovat nastavení cesty v .zshrc/.bashrc/.bash_profile atd.\nMusíte nastavit cestu v konfiguračním souboru shellu", + "download": "Stáhnout", + "file_not_found": "Soubor nenalezen", + "custom": "Vlastní", + "add_custom_url": "Přidat vlastní URL" } \ No newline at end of file diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 76ec2218..af2b26ad 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -401,5 +401,30 @@ "export_cache_files": "Cachedateien exportieren", "found_n_files": "{count} Dateien gefunden", "export_cache_confirmation": "Möchten Sie diese Dateien exportieren nach", - "exported_n_out_of_m_files": "{filesExported} von {files} Dateien exportiert" + "exported_n_out_of_m_files": "{filesExported} von {files} Dateien exportiert", + "playlist": "Playlist", + "no_loop": "Kein Loop", + "generate": "Generieren", + "undo": "Rückgängig", + "download_all": "Alle herunterladen", + "add_all_to_playlist": "Alle zur Playlist hinzufügen", + "add_all_to_queue": "Alle zur Warteschlange hinzufügen", + "play_all_next": "Alle als Nächstes abspielen", + "pause": "Pause", + "view_all": "Alle ansehen", + "no_tracks_added_yet": "Sie haben noch keine Titel hinzugefügt.", + "no_tracks": "Es sieht so aus, als ob hier keine Titel sind.", + "no_tracks_listened_yet": "Es scheint, dass Sie noch nichts gehört haben.", + "not_following_artists": "Sie folgen noch keinem Künstler.", + "no_favorite_albums_yet": "Es sieht so aus, als ob Sie noch keine Alben zu Ihren Favoriten hinzugefügt haben.", + "no_logs_found": "Keine Protokolle gefunden", + "youtube_engine": "YouTube-Engine", + "youtube_engine_not_installed_title": "{engine} ist nicht installiert", + "youtube_engine_not_installed_message": "{engine} ist nicht auf Ihrem System installiert.", + "youtube_engine_set_path": "Stellen Sie sicher, dass es im PATH verfügbar ist oder\nsetzen Sie den absoluten Pfad zur {engine} ausführbaren Datei unten.", + "youtube_engine_unix_issue_message": "In macOS/Linux/unixähnlichen Betriebssystemen funktioniert das Setzen des Pfads in .zshrc/.bashrc/.bash_profile usw. nicht.\nSie müssen den Pfad in der Shell-Konfigurationsdatei festlegen.", + "download": "Herunterladen", + "file_not_found": "Datei nicht gefunden", + "custom": "Benutzerdefiniert", + "add_custom_url": "Benutzerdefinierte URL hinzufügen" } \ No newline at end of file diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 9fc7e560..565c786a 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -401,5 +401,30 @@ "export_cache_files": "Exportar archivos en caché", "found_n_files": "Se encontraron {count} archivos", "export_cache_confirmation": "¿Desea exportar estos archivos a", - "exported_n_out_of_m_files": "Se exportaron {filesExported} de {files} archivos" + "exported_n_out_of_m_files": "Se exportaron {filesExported} de {files} archivos", + "playlist": "Lista de reproducción", + "no_loop": "Sin bucle", + "generate": "Generar", + "undo": "Deshacer", + "download_all": "Descargar todo", + "add_all_to_playlist": "Agregar todo a la lista de reproducción", + "add_all_to_queue": "Agregar todo a la cola", + "play_all_next": "Reproducir todo a continuación", + "pause": "Pausa", + "view_all": "Ver todo", + "no_tracks_added_yet": "Parece que aún no has agregado ninguna canción.", + "no_tracks": "Parece que no hay canciones aquí.", + "no_tracks_listened_yet": "Parece que no has escuchado nada todavía.", + "not_following_artists": "No sigues a ningún artista.", + "no_favorite_albums_yet": "Parece que aún no has agregado ningún álbum a tus favoritos.", + "no_logs_found": "No se encontraron registros", + "youtube_engine": "Motor de YouTube", + "youtube_engine_not_installed_title": "{engine} no está instalado", + "youtube_engine_not_installed_message": "{engine} no está instalado en tu sistema.", + "youtube_engine_set_path": "Asegúrate de que esté disponible en la variable PATH o\nestablece la ruta absoluta del ejecutable de {engine} a continuación.", + "youtube_engine_unix_issue_message": "En macOS/Linux/sistemas operativos similares a Unix, establecer la ruta en .zshrc/.bashrc/.bash_profile etc. no funcionará.\nNecesitas establecer la ruta en el archivo de configuración del shell.", + "download": "Descargar", + "file_not_found": "Archivo no encontrado", + "custom": "Personalizado", + "add_custom_url": "Agregar URL personalizada" } \ No newline at end of file diff --git a/lib/l10n/app_eu.arb b/lib/l10n/app_eu.arb index 98596725..70a581a7 100644 --- a/lib/l10n/app_eu.arb +++ b/lib/l10n/app_eu.arb @@ -401,5 +401,30 @@ "export_cache_files": "Esportatu cache fitxategiak", "found_n_files": "{count} fitxategi aurkitu dira", "export_cache_confirmation": "Fitxategi hauek esportatu nahi al dituzu", - "exported_n_out_of_m_files": "{filesExported} fitxategi esportatu dira {files} -tik" + "exported_n_out_of_m_files": "{filesExported} fitxategi esportatu dira {files} -tik", + "playlist": "Playlist", + "no_loop": "Ez dago loop-ik", + "generate": "Sortu", + "undo": "Desegondu", + "download_all": "Guztia deskargatu", + "add_all_to_playlist": "Guztia playlist-era gehitu", + "add_all_to_queue": "Guztia zerrendara gehitu", + "play_all_next": "Guztia hurrengoan jolastu", + "pause": "Pausatu", + "view_all": "Ikusi guztia", + "no_tracks_added_yet": "Dirudienez, oraindik ez duzu abestirik gehitu.", + "no_tracks": "Ez dirudi hemen abestirik dagoenik.", + "no_tracks_listened_yet": "Dirudienez, oraindik ez duzu ezer entzun.", + "not_following_artists": "Ez zaude artisten atzetik.", + "no_favorite_albums_yet": "Dirudienez, oraindik ez duzu albumik gehitu zure gogokoen artean.", + "no_logs_found": "Ez dira log-ak aurkitu", + "youtube_engine": "YouTube Motorra", + "youtube_engine_not_installed_title": "{engine} ez dago instalatuta", + "youtube_engine_not_installed_message": "{engine} ez dago zure sisteman instalatuta.", + "youtube_engine_set_path": "Ziurtatu PATH aldagaiaren barruan dagoela edo\nezarri {engine} exekutagarriaren helbide absolutua behean.", + "youtube_engine_unix_issue_message": "macOS/Linux/Unix bezalako sistemetan, .zshrc/.bashrc/.bash_profile bezalako fitxategietan bidearen ezarpenak ez dira funtzionatuko.\nBidearen ezarpena shell konfigurazio fitxategian egin behar duzu.", + "download": "Deskargatu", + "file_not_found": "Fitxategia ez da aurkitu", + "custom": "Pertsonalizatua", + "add_custom_url": "Gehitu URL pertsonalizatua" } \ No newline at end of file diff --git a/lib/l10n/app_fa.arb b/lib/l10n/app_fa.arb index 4d11dd81..d3918e55 100644 --- a/lib/l10n/app_fa.arb +++ b/lib/l10n/app_fa.arb @@ -401,5 +401,30 @@ "export_cache_files": "صادر کردن فایل‌های حافظه موقت", "found_n_files": "{count} فایل یافت شد", "export_cache_confirmation": "آیا می‌خواهید این فایل‌ها را صادر کنید به", - "exported_n_out_of_m_files": "{filesExported} از {files} فایل صادر شد" + "exported_n_out_of_m_files": "{filesExported} از {files} فایل صادر شد", + "playlist": "لیست پخش", + "no_loop": "بدون حلقه", + "generate": "ایجاد", + "undo": "بازگشت", + "download_all": "دانلود همه", + "add_all_to_playlist": "افزودن همه به لیست پخش", + "add_all_to_queue": "افزودن همه به صف", + "play_all_next": "پخش همه بعدی", + "pause": "مکث", + "view_all": "مشاهده همه", + "no_tracks_added_yet": "به نظر می‌رسد هنوز هیچ آهنگی اضافه نکرده‌اید.", + "no_tracks": "به نظر می‌رسد هیچ آهنگی در اینجا وجود ندارد.", + "no_tracks_listened_yet": "به نظر می‌رسد هنوز چیزی نشنیده‌اید.", + "not_following_artists": "شما هیچ هنرمندی را دنبال نمی‌کنید.", + "no_favorite_albums_yet": "به نظر می‌رسد هنوز هیچ آلبومی را به علاقه‌مندی‌هایتان اضافه نکرده‌اید.", + "no_logs_found": "هیچ لاگی پیدا نشد", + "youtube_engine": "موتور YouTube", + "youtube_engine_not_installed_title": "{engine} نصب نشده است", + "youtube_engine_not_installed_message": "{engine} در سیستم شما نصب نشده است.", + "youtube_engine_set_path": "اطمینان حاصل کنید که در متغیر PATH موجود است یا\nآدرس مطلق فایل اجرایی {engine} را در زیر تنظیم کنید.", + "youtube_engine_unix_issue_message": "در macOS/Linux/سیستم‌عامل‌های مشابه Unix، تنظیم مسیر در .zshrc/.bashrc/.bash_profile و غیره کار نمی‌کند.\nباید مسیر را در فایل پیکربندی شل تنظیم کنید.", + "download": "دانلود", + "file_not_found": "فایل پیدا نشد", + "custom": "شخصی‌سازی شده", + "add_custom_url": "اضافه کردن URL سفارشی" } \ No newline at end of file diff --git a/lib/l10n/app_fi.arb b/lib/l10n/app_fi.arb index f6794043..797c36f7 100644 --- a/lib/l10n/app_fi.arb +++ b/lib/l10n/app_fi.arb @@ -401,5 +401,30 @@ "export_cache_files": "Vie välimuistitiedostot", "found_n_files": "Löydettiin {count} tiedostoa", "export_cache_confirmation": "Haluatko viedä nämä tiedostot", - "exported_n_out_of_m_files": "Vietiin {filesExported}/{files} tiedostoa" + "exported_n_out_of_m_files": "Vietiin {filesExported}/{files} tiedostoa", + "playlist": "Soittolista", + "no_loop": "Ei silmukkaa", + "generate": "Luo", + "undo": "Peruuta", + "download_all": "Lataa kaikki", + "add_all_to_playlist": "Lisää kaikki soittolistalle", + "add_all_to_queue": "Lisää kaikki jonoon", + "play_all_next": "Toista kaikki seuraavaksi", + "pause": "Pysäytä", + "view_all": "Näytä kaikki", + "no_tracks_added_yet": "Näyttää siltä, että et ole lisännyt vielä mitään kappaleita.", + "no_tracks": "Näyttää siltä, että täällä ei ole kappaleita.", + "no_tracks_listened_yet": "Näyttää siltä, että et ole kuunnellut mitään vielä.", + "not_following_artists": "Et seuraa yhtään artistia.", + "no_favorite_albums_yet": "Näyttää siltä, että et ole lisännyt yhtään albumia suosikkeihisi.", + "no_logs_found": "Ei lokitietoja löydetty", + "youtube_engine": "YouTube-moottori", + "youtube_engine_not_installed_title": "{engine} ei ole asennettu", + "youtube_engine_not_installed_message": "{engine} ei ole asennettu järjestelmääsi.", + "youtube_engine_set_path": "Varmista, että se on saatavilla PATH-muuttujassa tai\nasetetaan {engine} suoritettavan tiedoston absoluuttinen polku alla.", + "youtube_engine_unix_issue_message": "macOS/Linux/unix-tyyppisissä käyttöjärjestelmissä polun asettaminen .zshrc/.bashrc/.bash_profile jne. ei toimi.\nSinun täytyy asettaa polku shellin asetustiedostoon.", + "download": "Lataa", + "file_not_found": "Tiedostoa ei löydy", + "custom": "Mukautettu", + "add_custom_url": "Lisää mukautettu URL" } \ No newline at end of file diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 9062ada7..636cffec 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -401,5 +401,30 @@ "export_cache_files": "Exporter les fichiers en cache", "found_n_files": "{count} fichiers trouvés", "export_cache_confirmation": "Voulez-vous exporter ces fichiers vers", - "exported_n_out_of_m_files": "{filesExported} fichiers exportés sur {files}" + "exported_n_out_of_m_files": "{filesExported} fichiers exportés sur {files}", + "playlist": "Playlist", + "no_loop": "Pas de boucle", + "generate": "Générer", + "undo": "Annuler", + "download_all": "Télécharger tout", + "add_all_to_playlist": "Ajouter tout à la playlist", + "add_all_to_queue": "Ajouter tout à la file d'attente", + "play_all_next": "Lire tout suivant", + "pause": "Pause", + "view_all": "Voir tout", + "no_tracks_added_yet": "Il semble que vous n'avez encore ajouté aucun morceau.", + "no_tracks": "Il semble qu'il n'y ait pas de morceaux ici.", + "no_tracks_listened_yet": "Il semble que vous n'avez encore rien écouté.", + "not_following_artists": "Vous ne suivez aucun artiste.", + "no_favorite_albums_yet": "Il semble que vous n'ayez encore ajouté aucun album à vos favoris.", + "no_logs_found": "Aucun log trouvé", + "youtube_engine": "Moteur YouTube", + "youtube_engine_not_installed_title": "{engine} n'est pas installé", + "youtube_engine_not_installed_message": "{engine} n'est pas installé sur votre système.", + "youtube_engine_set_path": "Assurez-vous qu'il est disponible dans la variable PATH ou\nfixez le chemin absolu du fichier exécutable {engine} ci-dessous.", + "youtube_engine_unix_issue_message": "Dans macOS/Linux/les systèmes d'exploitation similaires à Unix, définir le chemin dans .zshrc/.bashrc/.bash_profile etc. ne fonctionnera pas.\nVous devez définir le chemin dans le fichier de configuration du shell.", + "download": "Télécharger", + "file_not_found": "Fichier non trouvé", + "custom": "Personnalisé", + "add_custom_url": "Ajouter une URL personnalisée" } \ No newline at end of file diff --git a/lib/l10n/app_hi.arb b/lib/l10n/app_hi.arb index 7a1eae4e..fc59d31a 100644 --- a/lib/l10n/app_hi.arb +++ b/lib/l10n/app_hi.arb @@ -401,5 +401,30 @@ "export_cache_files": "कैश फ़ाइलें निर्यात करें", "found_n_files": "{count} फ़ाइलें मिलीं", "export_cache_confirmation": "क्या आप इन फ़ाइलों को निर्यात करना चाहते हैं", - "exported_n_out_of_m_files": "{filesExported} फ़ाइलें निर्यात की गईं {files} में से" + "exported_n_out_of_m_files": "{filesExported} फ़ाइलें निर्यात की गईं {files} में से", + "playlist": "प्लेलिस्ट", + "no_loop": "कोई लूप नहीं", + "generate": "उत्पन्न करें", + "undo": "पूर्ववत करें", + "download_all": "सभी डाउनलोड करें", + "add_all_to_playlist": "सभी को प्लेलिस्ट में जोड़ें", + "add_all_to_queue": "सभी को कतार में जोड़ें", + "play_all_next": "सभी को अगले खेलने के लिए", + "pause": "रोकें", + "view_all": "सभी देखें", + "no_tracks_added_yet": "लगता है आपने अभी तक कोई ट्रैक नहीं जोड़ा है।", + "no_tracks": "लगता है यहाँ कोई ट्रैक नहीं है।", + "no_tracks_listened_yet": "लगता है आपने अभी तक कुछ नहीं सुना है।", + "not_following_artists": "आप किसी भी कलाकार को फॉलो नहीं कर रहे हैं।", + "no_favorite_albums_yet": "लगता है आपने अभी तक कोई एल्बम अपनी पसंदीदा सूची में नहीं जोड़ा है।", + "no_logs_found": "कोई लॉग नहीं मिला", + "youtube_engine": "YouTube इंजन", + "youtube_engine_not_installed_title": "{engine} स्थापित नहीं है", + "youtube_engine_not_installed_message": "{engine} आपके सिस्टम में स्थापित नहीं है।", + "youtube_engine_set_path": "यह सुनिश्चित करें कि यह PATH वेरिएबल में उपलब्ध हो या\nनीचे {engine} निष्पादन योग्य फ़ाइल का पूर्ण पथ सेट करें।", + "youtube_engine_unix_issue_message": "macOS/Linux/यूनिक्स जैसे OS में, .zshrc/.bashrc/.bash_profile आदि में पथ सेट करना काम नहीं करेगा।\nआपको पथ को शेल कॉन्फ़िगरेशन फ़ाइल में सेट करना होगा।", + "download": "डाउनलोड करें", + "file_not_found": "फाइल नहीं मिली", + "custom": "कस्टम", + "add_custom_url": "कस्टम URL जोड़ें" } \ No newline at end of file diff --git a/lib/l10n/app_id.arb b/lib/l10n/app_id.arb index 5e041dc0..91bc9aef 100644 --- a/lib/l10n/app_id.arb +++ b/lib/l10n/app_id.arb @@ -401,5 +401,30 @@ "export_cache_files": "Export Cached Files", "found_n_files": "Found {count} files", "export_cache_confirmation": "Do you want to export these files to", - "exported_n_out_of_m_files": "Exported {filesExported} out of {files} files" + "exported_n_out_of_m_files": "Exported {filesExported} out of {files} files", + "playlist": "Playlist", + "no_loop": "No loop", + "generate": "Generate", + "undo": "Undo", + "download_all": "Download all", + "add_all_to_playlist": "Add all to playlist", + "add_all_to_queue": "Add all to queue", + "play_all_next": "Play all next", + "pause": "Pause", + "view_all": "View all", + "no_tracks_added_yet": "Looks like you haven't added any tracks yet", + "no_tracks": "Looks like there are no tracks here", + "no_tracks_listened_yet": "Looks like you haven't listened to anything yet", + "not_following_artists": "You're not following any artists", + "no_favorite_albums_yet": "Looks like you haven't added any albums to your favorites yet", + "no_logs_found": "No logs found", + "youtube_engine": "YouTube Engine", + "youtube_engine_not_installed_title": "{engine} is not installed", + "youtube_engine_not_installed_message": "{engine} is not installed in your system.", + "youtube_engine_set_path": "Make sure it's available in the PATH variable or\nset the absolute path to the {engine} executable below", + "youtube_engine_unix_issue_message": "In macOS/Linux/unix like OS's, setting path on .zshrc/.bashrc/.bash_profile etc. won't work.\nYou need to set the path in the shell configuration file", + "download": "Download", + "file_not_found": "File not found", + "custom": "Custom", + "add_custom_url": "Add custom URL" } \ No newline at end of file diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index c4954dd1..f598d363 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -402,5 +402,30 @@ "export_cache_files": "Esporta file nella cache", "found_n_files": "Trovati {count} file", "export_cache_confirmation": "Vuoi esportare questi file su", - "exported_n_out_of_m_files": "Esportati {filesExported} su {files} file" + "exported_n_out_of_m_files": "Esportati {filesExported} su {files} file", + "playlist": "Playlist", + "no_loop": "Nessun ciclo", + "generate": "Genera", + "undo": "Annulla", + "download_all": "Scarica tutto", + "add_all_to_playlist": "Aggiungi tutto alla playlist", + "add_all_to_queue": "Aggiungi tutto alla coda", + "play_all_next": "Riproduci tutto dopo", + "pause": "Pausa", + "view_all": "Vedi tutto", + "no_tracks_added_yet": "Sembra che non hai ancora aggiunto nessun brano", + "no_tracks": "Sembra che non ci siano brani qui", + "no_tracks_listened_yet": "Sembra che non hai ascoltato nulla ancora", + "not_following_artists": "Non stai seguendo alcun artista", + "no_favorite_albums_yet": "Sembra che non hai ancora aggiunto album ai tuoi preferiti", + "no_logs_found": "Nessun registro trovato", + "youtube_engine": "Motore YouTube", + "youtube_engine_not_installed_title": "{engine} non è installato", + "youtube_engine_not_installed_message": "{engine} non è installato nel tuo sistema.", + "youtube_engine_set_path": "Assicurati che sia disponibile nella variabile PATH o\nimposta il percorso assoluto all'eseguibile {engine} qui sotto", + "youtube_engine_unix_issue_message": "In macOS/Linux/os simili a unix, impostare il percorso su .zshrc/.bashrc/.bash_profile ecc. non funzionerà.\nDevi impostare il percorso nel file di configurazione della shell", + "download": "Scarica", + "file_not_found": "File non trovato", + "custom": "Personalizzato", + "add_custom_url": "Aggiungi URL personalizzato" } \ No newline at end of file diff --git a/lib/l10n/app_ja.arb b/lib/l10n/app_ja.arb index 4f299025..b885fa59 100644 --- a/lib/l10n/app_ja.arb +++ b/lib/l10n/app_ja.arb @@ -401,5 +401,30 @@ "export_cache_files": "キャッシュされたファイルをエクスポート", "found_n_files": "{count}ファイルが見つかりました", "export_cache_confirmation": "これらのファイルをエクスポートしますか", - "exported_n_out_of_m_files": "{filesExported} / {files}ファイルがエクスポートされました" + "exported_n_out_of_m_files": "{filesExported} / {files}ファイルがエクスポートされました", + "playlist": "プレイリスト", + "no_loop": "ループなし", + "generate": "生成", + "undo": "元に戻す", + "download_all": "すべてをダウンロード", + "add_all_to_playlist": "すべてをプレイリストに追加", + "add_all_to_queue": "すべてをキューに追加", + "play_all_next": "次にすべてを再生", + "pause": "一時停止", + "view_all": "すべてを見る", + "no_tracks_added_yet": "まだ曲を追加していないようです", + "no_tracks": "ここには曲がないようです", + "no_tracks_listened_yet": "まだ何も聞いていないようです", + "not_following_artists": "アーティストをフォローしていません", + "no_favorite_albums_yet": "まだお気に入りのアルバムを追加していないようです", + "no_logs_found": "ログが見つかりませんでした", + "youtube_engine": "YouTubeエンジン", + "youtube_engine_not_installed_title": "{engine}はインストールされていません", + "youtube_engine_not_installed_message": "{engine}はシステムにインストールされていません。", + "youtube_engine_set_path": "PATH変数に設定されていることを確認するか\n{engine}実行ファイルの絶対パスを下記に設定してください", + "youtube_engine_unix_issue_message": "macOS/Linux/Unix系OSでは、.zshrc/.bashrc/.bash_profileなどでパスを設定しても動作しません。\nシェルの設定ファイルにパスを設定する必要があります", + "download": "ダウンロード", + "file_not_found": "ファイルが見つかりません", + "custom": "カスタム", + "add_custom_url": "カスタムURLを追加" } \ No newline at end of file diff --git a/lib/l10n/app_ka.arb b/lib/l10n/app_ka.arb index 3bcd0748..8bc9cf36 100644 --- a/lib/l10n/app_ka.arb +++ b/lib/l10n/app_ka.arb @@ -401,5 +401,30 @@ "export_cache_files": "ქეშირებული ფაილების ექსპორტი", "found_n_files": "ნაპოვნია {count} ფაილი", "export_cache_confirmation": "გსურთ ამ ფაილების ექსპორტი", - "exported_n_out_of_m_files": "{filesExported} ფაილი {files}-დან ექსპორტირებულია" + "exported_n_out_of_m_files": "{filesExported} ფაილი {files}-დან ექსპორტირებულია", + "playlist": "პლეისთი", + "no_loop": "არ არის ციკლი", + "generate": "გააგენერირეთ", + "undo": "დაბრუნება", + "download_all": "ყველას ჩამოტვირთვა", + "add_all_to_playlist": "ყველა დაამატეთ პლეისთში", + "add_all_to_queue": "ყველა დაამატეთ რიგში", + "play_all_next": "ყველა შემდეგ ითამაშე", + "pause": "შეჩერება", + "view_all": "ყველა ნახვა", + "no_tracks_added_yet": "გაჩნდება რომ ჯერ არ გაქვთ დამატებული ტრეკები", + "no_tracks": "გავლებული არ ჩანს არ არსებობს ტრეკები", + "no_tracks_listened_yet": "გქონდეთ გრძნობა, რომ ჯერ არაფერი უსმენია", + "not_following_artists": "არ მიჰყვებით რომელიმე არტისტს", + "no_favorite_albums_yet": "გაჩნდება რომ ჯერ არ გაქვთ დამატებული ალბომები თქვენს ფავორიტებში", + "no_logs_found": "ჩაწერები ვერ მოიძებნა", + "youtube_engine": "YouTube ძრავა", + "youtube_engine_not_installed_title": "{engine} არ არის ინსტალირებული", + "youtube_engine_not_installed_message": "{engine} არ არის ინსტალირებული თქვენს სისტემაში.", + "youtube_engine_set_path": "დარწმუნდით, რომ ის ხელმისაწვდომია PATH ცვლადში ან\nდაუყავით {engine} პროგრამის ფაილის სრული გზა", + "youtube_engine_unix_issue_message": "macOS/Linux/Unix მსგავსი ოპერაციული სისტემებში, .zshrc/.bashrc/.bash_profile-ით პათის დაყენება ვერ იმუშავებს.\nთქვენ უნდა დააყენოთ პათი შელ ფაილში", + "download": "ჩამოტვირთვა", + "file_not_found": "ფაილი ვერ მოიძებნა", + "custom": "პერსონალიზირებული", + "add_custom_url": "დამატება პერსონალური URL" } \ No newline at end of file diff --git a/lib/l10n/app_ko.arb b/lib/l10n/app_ko.arb index 7e368081..6c8031b5 100644 --- a/lib/l10n/app_ko.arb +++ b/lib/l10n/app_ko.arb @@ -402,5 +402,30 @@ "export_cache_files": "캐시된 파일 내보내기", "found_n_files": "{count}개의 파일을 찾았습니다", "export_cache_confirmation": "이 파일들을 내보내시겠습니까", - "exported_n_out_of_m_files": "{files}개 중 {filesExported}개 파일을 내보냈습니다" + "exported_n_out_of_m_files": "{files}개 중 {filesExported}개 파일을 내보냈습니다", + "playlist": "재생 목록", + "no_loop": "반복 없음", + "generate": "생성", + "undo": "실행 취소", + "download_all": "모두 다운로드", + "add_all_to_playlist": "모두 재생 목록에 추가", + "add_all_to_queue": "모두 큐에 추가", + "play_all_next": "모두 다음에 재생", + "pause": "일시 정지", + "view_all": "모두 보기", + "no_tracks_added_yet": "아직 트랙을 추가하지 않은 것 같습니다", + "no_tracks": "여기에 트랙이 없는 것 같습니다", + "no_tracks_listened_yet": "아직 아무 것도 듣지 않은 것 같습니다", + "not_following_artists": "아티스트를 팔로우하지 않고 있습니다", + "no_favorite_albums_yet": "아직 즐겨찾기 앨범을 추가하지 않은 것 같습니다", + "no_logs_found": "로그를 찾을 수 없습니다", + "youtube_engine": "YouTube 엔진", + "youtube_engine_not_installed_title": "{engine}가 설치되지 않았습니다", + "youtube_engine_not_installed_message": "{engine}가 시스템에 설치되지 않았습니다.", + "youtube_engine_set_path": "PATH 변수에서 사용할 수 있는지 확인하거나\n아래에 {engine} 실행 파일의 절대 경로를 설정하세요", + "youtube_engine_unix_issue_message": "macOS/Linux/unix와 같은 운영 체제에서는 .zshrc/.bashrc/.bash_profile 등에 경로 설정이 작동하지 않습니다.\n셸 구성 파일에 경로를 설정해야 합니다", + "download": "다운로드", + "file_not_found": "파일을 찾을 수 없습니다", + "custom": "사용자 정의", + "add_custom_url": "사용자 정의 URL 추가" } \ No newline at end of file diff --git a/lib/l10n/app_ne.arb b/lib/l10n/app_ne.arb index 77eea7d0..beddc3ad 100644 --- a/lib/l10n/app_ne.arb +++ b/lib/l10n/app_ne.arb @@ -401,5 +401,30 @@ "export_cache_files": "क्यास फाइलहरू निर्यात गर्नुहोस्", "found_n_files": "{count} फाइलहरू फेला परे", "export_cache_confirmation": "यी फाइलहरू निर्यात गर्न चाहनुहुन्छ", - "exported_n_out_of_m_files": "{filesExported} मध्ये {files} फाइलहरू निर्यात गरियो" + "exported_n_out_of_m_files": "{filesExported} मध्ये {files} फाइलहरू निर्यात गरियो", + "playlist": "प्लेलिस्ट", + "no_loop": "कोई लूप नहीं", + "generate": "जनरेट", + "undo": "पूर्ववत", + "download_all": "सभी डाउनलोड करें", + "add_all_to_playlist": "सभी को प्लेलिस्ट में जोड़ें", + "add_all_to_queue": "सभी को कतार में जोड़ें", + "play_all_next": "सभी को अगला प्ले करें", + "pause": "विराम", + "view_all": "सभी देखें", + "no_tracks_added_yet": "लगता है आपने अभी तक कोई ट्रैक नहीं जोड़ा है", + "no_tracks": "यहाँ कोई ट्रैक नहीं दिख रहे हैं", + "no_tracks_listened_yet": "आपने अभी तक कुछ नहीं सुना है ऐसा लगता है", + "not_following_artists": "आप किसी कलाकार को फॉलो नहीं कर रहे हैं", + "no_favorite_albums_yet": "लगता है आपने अभी तक कोई एल्बम पसंदीदा में नहीं जोड़ा है", + "no_logs_found": "कोई लॉग नहीं मिला", + "youtube_engine": "YouTube इंजन", + "youtube_engine_not_installed_title": "{engine} इंस्टॉल नहीं है", + "youtube_engine_not_installed_message": "{engine} आपके सिस्टम में इंस्टॉल नहीं है।", + "youtube_engine_set_path": "सुनिश्चित करें कि यह PATH वेरिएबल में उपलब्ध है या\nनीचे {engine} एक्जीक्यूटेबल का पूर्ण पथ सेट करें", + "youtube_engine_unix_issue_message": "macOS/Linux/unix जैसे ऑपरेटिंग सिस्टम में, .zshrc/.bashrc/.bash_profile आदि में पथ सेट करना काम नहीं करेगा।\nआपको शेल कॉन्फ़िगरेशन फ़ाइल में पथ सेट करना होगा", + "download": "डाउनलोड", + "file_not_found": "फ़ाइल नहीं मिली", + "custom": "कस्टम", + "add_custom_url": "कस्टम URL जोड़ें" } \ No newline at end of file diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index 50b5e3bd..2127b382 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -402,5 +402,30 @@ "export_cache_files": "Gecacheerde bestanden exporteren", "found_n_files": "{count} bestanden gevonden", "export_cache_confirmation": "Wilt u deze bestanden exporteren naar", - "exported_n_out_of_m_files": "{filesExported} van de {files} bestanden geëxporteerd" + "exported_n_out_of_m_files": "{filesExported} van de {files} bestanden geëxporteerd", + "playlist": "Afspeellijst", + "no_loop": "Geen herhaling", + "generate": "Genereren", + "undo": "Ongedaan maken", + "download_all": "Alles downloaden", + "add_all_to_playlist": "Voeg alles toe aan afspeellijst", + "add_all_to_queue": "Voeg alles toe aan wachtrij", + "play_all_next": "Speel alles volgende", + "pause": "Pauzeren", + "view_all": "Bekijk alles", + "no_tracks_added_yet": "Het lijkt erop dat je nog geen nummers hebt toegevoegd", + "no_tracks": "Het lijkt erop dat er hier geen nummers zijn", + "no_tracks_listened_yet": "Het lijkt erop dat je nog niets hebt beluisterd", + "not_following_artists": "Je volgt geen artiesten", + "no_favorite_albums_yet": "Het lijkt erop dat je nog geen albums aan je favorieten hebt toegevoegd", + "no_logs_found": "Geen logbestanden gevonden", + "youtube_engine": "YouTube Engine", + "youtube_engine_not_installed_title": "{engine} is niet geïnstalleerd", + "youtube_engine_not_installed_message": "{engine} is niet geïnstalleerd op je systeem.", + "youtube_engine_set_path": "Zorg ervoor dat het beschikbaar is in de PATH-variabele of\nstel het absolute pad naar de {engine} uitvoerbare bestanden in", + "youtube_engine_unix_issue_message": "Op macOS/Linux/unix-achtige besturingssystemen werkt het instellen van paden in .zshrc/.bashrc/.bash_profile enz. niet.\nJe moet het pad instellen in het shell-configuratiebestand", + "download": "Downloaden", + "file_not_found": "Bestand niet gevonden", + "custom": "Aangepast", + "add_custom_url": "Voeg aangepaste URL toe" } \ No newline at end of file diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index 11ab51ce..ade74c90 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -401,5 +401,30 @@ "export_cache_files": "Eksportuj pliki z pamięci podręcznej", "found_n_files": "Znaleziono {count} plików", "export_cache_confirmation": "Czy chcesz wyeksportować te pliki do", - "exported_n_out_of_m_files": "Wyeksportowano {filesExported} z {files} plików" + "exported_n_out_of_m_files": "Wyeksportowano {filesExported} z {files} plików", + "playlist": "Playlista", + "no_loop": "Brak pętli", + "generate": "Generuj", + "undo": "Cofnij", + "download_all": "Pobierz wszystko", + "add_all_to_playlist": "Dodaj wszystko do playlisty", + "add_all_to_queue": "Dodaj wszystko do kolejki", + "play_all_next": "Odtwórz wszystko następnie", + "pause": "Pauza", + "view_all": "Zobacz wszystko", + "no_tracks_added_yet": "Wygląda na to, że jeszcze nie dodałeś żadnych utworów", + "no_tracks": "Wygląda na to, że tutaj nie ma żadnych utworów", + "no_tracks_listened_yet": "Wygląda na to, że jeszcze nic nie słuchałeś", + "not_following_artists": "Nie obserwujesz żadnych artystów", + "no_favorite_albums_yet": "Wygląda na to, że jeszcze nie dodałeś żadnych albumów do ulubionych", + "no_logs_found": "Nie znaleziono żadnych logów", + "youtube_engine": "Silnik YouTube", + "youtube_engine_not_installed_title": "{engine} nie jest zainstalowany", + "youtube_engine_not_installed_message": "{engine} nie jest zainstalowany w systemie.", + "youtube_engine_set_path": "Upewnij się, że jest dostępny w zmiennej PATH lub\nustaw absolutną ścieżkę do pliku wykonywalnego {engine} poniżej", + "youtube_engine_unix_issue_message": "W systemach macOS/Linux/unix, ustawianie ścieżki w .zshrc/.bashrc/.bash_profile itp. nie będzie działać.\nMusisz ustawić ścieżkę w pliku konfiguracyjnym powłoki", + "download": "Pobierz", + "file_not_found": "Plik nie znaleziony", + "custom": "Niestandardowy", + "add_custom_url": "Dodaj niestandardowy URL" } \ No newline at end of file diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 72841eab..6b1098a9 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -401,5 +401,30 @@ "export_cache_files": "Exportar Arquivos em Cache", "found_n_files": "Encontrados {count} arquivos", "export_cache_confirmation": "Deseja exportar estes arquivos para", - "exported_n_out_of_m_files": "Exportados {filesExported} de {files} arquivos" + "exported_n_out_of_m_files": "Exportados {filesExported} de {files} arquivos", + "playlist": "Playlist", + "no_loop": "Sem loop", + "generate": "Gerar", + "undo": "Desfazer", + "download_all": "Baixar tudo", + "add_all_to_playlist": "Adicionar tudo à playlist", + "add_all_to_queue": "Adicionar tudo à fila", + "play_all_next": "Reproduzir tudo a seguir", + "pause": "Pausar", + "view_all": "Ver tudo", + "no_tracks_added_yet": "Parece que você ainda não adicionou nenhuma faixa", + "no_tracks": "Parece que não há faixas aqui", + "no_tracks_listened_yet": "Parece que você ainda não ouviu nada", + "not_following_artists": "Você não está seguindo nenhum artista", + "no_favorite_albums_yet": "Parece que você ainda não adicionou nenhum álbum aos favoritos", + "no_logs_found": "Nenhum log encontrado", + "youtube_engine": "Motor YouTube", + "youtube_engine_not_installed_title": "{engine} não está instalado", + "youtube_engine_not_installed_message": "{engine} não está instalado no seu sistema.", + "youtube_engine_set_path": "Certifique-se de que está disponível na variável PATH ou\ndefina o caminho absoluto para o executável {engine} abaixo", + "youtube_engine_unix_issue_message": "Em sistemas macOS/Linux/unix, definir o caminho no .zshrc/.bashrc/.bash_profile etc. não funcionará.\nVocê precisa definir o caminho no arquivo de configuração do shell", + "download": "Baixar", + "file_not_found": "Arquivo não encontrado", + "custom": "Personalizado", + "add_custom_url": "Adicionar URL personalizada" } \ No newline at end of file diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index 6be53ba9..461e8da8 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -401,5 +401,30 @@ "export_cache_files": "Экспортировать кэшированные файлы", "found_n_files": "Найдено {count} файлов", "export_cache_confirmation": "Вы хотите экспортировать эти файлы в", - "exported_n_out_of_m_files": "Экспортировано {filesExported} из {files} файлов" + "exported_n_out_of_m_files": "Экспортировано {filesExported} из {files} файлов", + "playlist": "Плейлист", + "no_loop": "Без повтора", + "generate": "Генерировать", + "undo": "Отменить", + "download_all": "Скачать все", + "add_all_to_playlist": "Добавить все в плейлист", + "add_all_to_queue": "Добавить все в очередь", + "play_all_next": "Воспроизвести все следующее", + "pause": "Пауза", + "view_all": "Просмотреть все", + "no_tracks_added_yet": "Похоже, вы ещё не добавили ни одного трека", + "no_tracks": "Похоже, здесь нет треков", + "no_tracks_listened_yet": "Похоже, вы ещё ничего не слушали", + "not_following_artists": "Вы не подписаны на художников", + "no_favorite_albums_yet": "Похоже, вы ещё не добавили ни одного альбома в избранное", + "no_logs_found": "Логи не найдены", + "youtube_engine": "YouTube Движок", + "youtube_engine_not_installed_title": "{engine} не установлен", + "youtube_engine_not_installed_message": "{engine} не установлен в вашей системе.", + "youtube_engine_set_path": "Убедитесь, что он доступен в переменной PATH или\nустановите абсолютный путь к исполнимому файлу {engine} ниже", + "youtube_engine_unix_issue_message": "В macOS/Linux/Unix-подобных ОС, установка пути в .zshrc/.bashrc/.bash_profile и т.д. не будет работать.\nВы должны установить путь в файле конфигурации оболочки", + "download": "Скачать", + "file_not_found": "Файл не найден", + "custom": "Пользовательский", + "add_custom_url": "Добавить пользовательский URL" } \ No newline at end of file diff --git a/lib/l10n/app_th.arb b/lib/l10n/app_th.arb index 1b72f1a3..8e9a0318 100644 --- a/lib/l10n/app_th.arb +++ b/lib/l10n/app_th.arb @@ -402,5 +402,30 @@ "export_cache_files": "ส่งออกไฟล์แคช", "found_n_files": "พบ {count} ไฟล์", "export_cache_confirmation": "คุณต้องการส่งออกไฟล์เหล่านี้ไปยัง", - "exported_n_out_of_m_files": "ส่งออก {filesExported} จาก {files} ไฟล์" + "exported_n_out_of_m_files": "ส่งออก {filesExported} จาก {files} ไฟล์", + "playlist": "เพลย์ลิสต์", + "no_loop": "ไม่มีการวนซ้ำ", + "generate": "สร้าง", + "undo": "ย้อนกลับ", + "download_all": "ดาวน์โหลดทั้งหมด", + "add_all_to_playlist": "เพิ่มทั้งหมดในเพลย์ลิสต์", + "add_all_to_queue": "เพิ่มทั้งหมดในคิว", + "play_all_next": "เล่นทั้งหมดถัดไป", + "pause": "หยุดชั่วคราว", + "view_all": "ดูทั้งหมด", + "no_tracks_added_yet": "ดูเหมือนคุณยังไม่ได้เพิ่มเพลงใด ๆ", + "no_tracks": "ดูเหมือนจะไม่มีเพลงที่นี่", + "no_tracks_listened_yet": "ดูเหมือนคุณยังไม่ได้ฟังอะไรเลย", + "not_following_artists": "คุณไม่ได้ติดตามศิลปินใด ๆ", + "no_favorite_albums_yet": "ดูเหมือนคุณยังไม่ได้เพิ่มอัลบัมใด ๆ ในรายการโปรด", + "no_logs_found": "ไม่พบบันทึก", + "youtube_engine": "เครื่องมือ YouTube", + "youtube_engine_not_installed_title": "{engine} ยังไม่ได้ติดตั้ง", + "youtube_engine_not_installed_message": "{engine} ยังไม่ได้ติดตั้งในระบบของคุณ", + "youtube_engine_set_path": "ตรวจสอบให้แน่ใจว่ามันมีอยู่ในตัวแปร PATH หรือ\nตั้งค่าพาธที่แท้จริงของไฟล์ที่สามารถทำงานได้ {engine} ด้านล่าง", + "youtube_engine_unix_issue_message": "ใน macOS/Linux/Unix อย่าง OS การตั้งค่าพาธใน .zshrc/.bashrc/.bash_profile เป็นต้น จะไม่ทำงาน\nคุณต้องตั้งค่าพาธในไฟล์การกำหนดค่า shell", + "download": "ดาวน์โหลด", + "file_not_found": "ไม่พบไฟล์", + "custom": "กำหนดเอง", + "add_custom_url": "เพิ่ม URL แบบกำหนดเอง" } \ No newline at end of file diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb index 7f2bf5fb..1e659cc5 100644 --- a/lib/l10n/app_tr.arb +++ b/lib/l10n/app_tr.arb @@ -401,5 +401,30 @@ "export_cache_files": "Önbelleğe Alınmış Dosyaları Dışa Aktar", "found_n_files": "{count} dosya bulundu", "export_cache_confirmation": "Bu dosyaları dışa aktarmak istiyor musunuz", - "exported_n_out_of_m_files": "{filesExported} / {files} dosya dışa aktarıldı" + "exported_n_out_of_m_files": "{filesExported} / {files} dosya dışa aktarıldı", + "playlist": "Çalma Listesi", + "no_loop": "Dönüş Yok", + "generate": "Oluştur", + "undo": "Geri Al", + "download_all": "Tümünü İndir", + "add_all_to_playlist": "Hepsini çalma listesine ekle", + "add_all_to_queue": "Hepsini kuyruğa ekle", + "play_all_next": "Hepsini bir sonraki çal", + "pause": "Duraklat", + "view_all": "Tümünü Gör", + "no_tracks_added_yet": "Henüz hiçbir şarkı eklemediniz gibi görünüyor", + "no_tracks": "Burada hiç şarkı yok gibi görünüyor", + "no_tracks_listened_yet": "Henüz hiçbir şey dinlemediniz gibi görünüyor", + "not_following_artists": "Hiçbir sanatçıyı takip etmiyorsunuz", + "no_favorite_albums_yet": "Henüz favorilerinize herhangi bir albüm eklemediniz gibi görünüyor", + "no_logs_found": "Log bulunamadı", + "youtube_engine": "YouTube Motoru", + "youtube_engine_not_installed_title": "{engine} Yüklü değil", + "youtube_engine_not_installed_message": "{engine} sisteminizde yüklü değil.", + "youtube_engine_set_path": "PATH değişkeninde kullanılabilir olduğundan emin olun veya\n{engine} çalıştırılabilir dosyasının mutlak yolunu aşağıda ayarlayın", + "youtube_engine_unix_issue_message": "macOS/Linux/Unix benzeri işletim sistemlerinde, .zshrc/.bashrc/.bash_profile gibi dosyalarda yol ayarlamak işe yaramaz.\nYolunuzu kabuk yapılandırma dosyasına ayarlamanız gerekir", + "download": "İndir", + "file_not_found": "Dosya bulunamadı", + "custom": "Özel", + "add_custom_url": "Özel URL ekle" } \ No newline at end of file diff --git a/lib/l10n/app_uk.arb b/lib/l10n/app_uk.arb index 245c87e1..bc731240 100644 --- a/lib/l10n/app_uk.arb +++ b/lib/l10n/app_uk.arb @@ -401,5 +401,30 @@ "export_cache_files": "Експортувати кешовані файли", "found_n_files": "Знайдено {count} файлів", "export_cache_confirmation": "Ви хочете експортувати ці файли до", - "exported_n_out_of_m_files": "Експортовано {filesExported} з {files} файлів" + "exported_n_out_of_m_files": "Експортовано {filesExported} з {files} файлів", + "playlist": "Плейлист", + "no_loop": "Без повтору", + "generate": "Генерувати", + "undo": "Скасувати", + "download_all": "Завантажити все", + "add_all_to_playlist": "Додати все до плейлиста", + "add_all_to_queue": "Додати все в чергу", + "play_all_next": "Відтворити все наступне", + "pause": "Пауза", + "view_all": "Переглянути все", + "no_tracks_added_yet": "Здається, ви ще не додали жодної пісні", + "no_tracks": "Здається, тут немає пісень", + "no_tracks_listened_yet": "Здається, ви ще нічого не слухали", + "not_following_artists": "Ви не підписані на жодного артиста", + "no_favorite_albums_yet": "Здається, ви ще не додали жодного альбому в улюблені", + "no_logs_found": "Жодних журналів не знайдено", + "youtube_engine": "YouTube Двигун", + "youtube_engine_not_installed_title": "{engine} не встановлено", + "youtube_engine_not_installed_message": "{engine} не встановлено на вашій системі.", + "youtube_engine_set_path": "Переконайтесь, що він доступний у змінній PATH або\nвстановіть абсолютний шлях до виконуваного файлу {engine} нижче", + "youtube_engine_unix_issue_message": "У macOS/Linux/Unix-подібних ОС, встановлення шляху в .zshrc/.bashrc/.bash_profile тощо не працює.\nВам потрібно налаштувати шлях у файлі конфігурації оболонки", + "download": "Завантажити", + "file_not_found": "Файл не знайдено", + "custom": "Користувацький", + "add_custom_url": "Додати користувацький URL" } \ No newline at end of file diff --git a/lib/l10n/app_vi.arb b/lib/l10n/app_vi.arb index 37f7f709..75f8e3f7 100644 --- a/lib/l10n/app_vi.arb +++ b/lib/l10n/app_vi.arb @@ -401,5 +401,30 @@ "export_cache_files": "Xuất các tệp được lưu trong bộ nhớ đệm", "found_n_files": "Tìm thấy {count} tệp", "export_cache_confirmation": "Bạn có muốn xuất các tệp này đến", - "exported_n_out_of_m_files": "Đã xuất {filesExported} trên {files} tệp" + "exported_n_out_of_m_files": "Đã xuất {filesExported} trên {files} tệp", + "playlist": "Danh sách phát", + "no_loop": "Không lặp lại", + "generate": "Tạo", + "undo": "Hoàn tác", + "download_all": "Tải xuống tất cả", + "add_all_to_playlist": "Thêm tất cả vào danh sách phát", + "add_all_to_queue": "Thêm tất cả vào danh sách chờ", + "play_all_next": "Chơi tất cả tiếp theo", + "pause": "Tạm dừng", + "view_all": "Xem tất cả", + "no_tracks_added_yet": "Có vẻ bạn chưa thêm bất kỳ bài hát nào", + "no_tracks": "Có vẻ không có bài hát nào ở đây", + "no_tracks_listened_yet": "Có vẻ bạn chưa nghe gì cả", + "not_following_artists": "Bạn không đang theo dõi bất kỳ nghệ sĩ nào", + "no_favorite_albums_yet": "Có vẻ bạn chưa thêm album nào vào danh sách yêu thích", + "no_logs_found": "Không tìm thấy nhật ký", + "youtube_engine": "Công cụ YouTube", + "youtube_engine_not_installed_title": "{engine} chưa được cài đặt", + "youtube_engine_not_installed_message": "{engine} chưa được cài đặt trong hệ thống của bạn.", + "youtube_engine_set_path": "Đảm bảo nó có sẵn trong biến PATH hoặc\nđặt đường dẫn tuyệt đối đến tệp thực thi {engine} dưới đây", + "youtube_engine_unix_issue_message": "Trên macOS/Linux/Unix, việc thiết lập đường dẫn trong .zshrc/.bashrc/.bash_profile v.v. sẽ không hoạt động.\nBạn cần thiết lập đường dẫn trong tệp cấu hình shell", + "download": "Tải xuống", + "file_not_found": "Không tìm thấy tệp", + "custom": "Tùy chỉnh", + "add_custom_url": "Thêm URL tùy chỉnh" } \ No newline at end of file diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index dc2920ed..03ebae12 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -401,5 +401,30 @@ "export_cache_files": "导出缓存文件", "found_n_files": "找到 {count} 个文件", "export_cache_confirmation": "您要导出这些文件到", - "exported_n_out_of_m_files": "导出了 {filesExported} / {files} 个文件" + "exported_n_out_of_m_files": "导出了 {filesExported} / {files} 个文件", + "playlist": "播放列表", + "no_loop": "无循环", + "generate": "生成", + "undo": "撤销", + "download_all": "下载全部", + "add_all_to_playlist": "将全部添加到播放列表", + "add_all_to_queue": "将全部添加到队列", + "play_all_next": "播放全部下一首", + "pause": "暂停", + "view_all": "查看所有", + "no_tracks_added_yet": "看起来你还没有添加任何曲目", + "no_tracks": "看起来这里没有任何曲目", + "no_tracks_listened_yet": "看起来你还没有听任何东西", + "not_following_artists": "你没有关注任何艺术家", + "no_favorite_albums_yet": "看起来你还没有将任何专辑添加到收藏夹", + "no_logs_found": "未找到日志", + "youtube_engine": "YouTube 引擎", + "youtube_engine_not_installed_title": "{engine} 未安装", + "youtube_engine_not_installed_message": "{engine} 未在您的系统中安装。", + "youtube_engine_set_path": "确保它可用在 PATH 变量中,或\n设置 {engine} 可执行文件的绝对路径", + "youtube_engine_unix_issue_message": "在 macOS/Linux/Unix 类操作系统中,在 .zshrc/.bashrc/.bash_profile 等文件中设置路径无效。\n您需要在 shell 配置文件中设置路径", + "download": "下载", + "file_not_found": "文件未找到", + "custom": "自定义", + "add_custom_url": "添加自定义 URL" } \ No newline at end of file diff --git a/lib/pages/settings/about.dart b/lib/pages/settings/about.dart index 92143d96..27775f3c 100644 --- a/lib/pages/settings/about.dart +++ b/lib/pages/settings/about.dart @@ -98,6 +98,18 @@ class AboutSpotubePage extends HookConsumerWidget { ) ], ), + const TableRow( + cells: [ + TableCell(child: Text("Website")), + colon, + TableCell( + child: Hyperlink( + "spotube.krtirtho.dev", + "https://spotube.krtirtho.dev", + ), + ), + ], + ), TableRow( cells: [ TableCell(child: Text(context.l10n.repository)), diff --git a/pubspec.lock b/pubspec.lock index 11ecb18e..f44f3288 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1138,30 +1138,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.0" - hive: - dependency: "direct main" - description: - name: hive - sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941" - url: "https://pub.dev" - source: hosted - version: "2.2.3" - hive_flutter: - dependency: "direct main" - description: - name: hive_flutter - sha256: dca1da446b1d808a51689fb5d0c6c9510c0a2ba01e22805d492c73b68e33eecc - url: "https://pub.dev" - source: hosted - version: "1.1.0" - hive_generator: - dependency: "direct dev" - description: - name: hive_generator - sha256: "06cb8f58ace74de61f63500564931f9505368f45f98958bd7a6c35ba24159db4" - url: "https://pub.dev" - source: hosted - version: "2.0.1" home_widget: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index d508a2c5..0a487cee 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -3,14 +3,14 @@ description: Open source Spotify client that doesn't require Premium nor uses El publish_to: "none" -version: 3.9.0+38 +version: 4.0.0+39 homepage: https://spotube.krtirtho.dev repository: https://github.com/KRTirtho/spotube environment: sdk: ">=3.0.0 <4.0.0" - flutter: ">=3.10.0" + flutter: ">=3.29.0" dependencies: app_links: ^6.3.2 @@ -71,8 +71,6 @@ dependencies: fuzzywuzzy: ^1.1.6 gap: ^3.0.1 google_fonts: ^6.2.1 - hive: ^2.2.3 - hive_flutter: ^1.1.0 home_widget: ^0.7.0 hooks_riverpod: ^2.5.1 html: ^0.15.1 @@ -154,7 +152,6 @@ dev_dependencies: sdk: flutter integration_test: sdk: flutter - hive_generator: ^2.0.0 json_serializable: ^6.6.2 freezed: ^2.5.2 process_run: ^0.14.2 diff --git a/untranslated_messages.json b/untranslated_messages.json index 44adb37f..9e26dfee 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -1,729 +1 @@ -{ - "ar": [ - "playlist", - "no_loop", - "generate", - "undo", - "download_all", - "add_all_to_playlist", - "add_all_to_queue", - "play_all_next", - "pause", - "view_all", - "no_tracks_added_yet", - "no_tracks", - "no_tracks_listened_yet", - "not_following_artists", - "no_favorite_albums_yet", - "no_logs_found", - "youtube_engine", - "youtube_engine_not_installed_title", - "youtube_engine_not_installed_message", - "youtube_engine_set_path", - "youtube_engine_unix_issue_message", - "download", - "file_not_found", - "custom", - "add_custom_url" - ], - - "bn": [ - "playlist", - "no_loop", - "generate", - "undo", - "download_all", - "add_all_to_playlist", - "add_all_to_queue", - "play_all_next", - "pause", - "view_all", - "no_tracks_added_yet", - "no_tracks", - "no_tracks_listened_yet", - "not_following_artists", - "no_favorite_albums_yet", - "no_logs_found", - "youtube_engine", - "youtube_engine_not_installed_title", - "youtube_engine_not_installed_message", - "youtube_engine_set_path", - "youtube_engine_unix_issue_message", - "download", - "file_not_found", - "custom", - "add_custom_url" - ], - - "ca": [ - "playlist", - "no_loop", - "generate", - "undo", - "download_all", - "add_all_to_playlist", - "add_all_to_queue", - "play_all_next", - "pause", - "view_all", - "no_tracks_added_yet", - "no_tracks", - "no_tracks_listened_yet", - "not_following_artists", - "no_favorite_albums_yet", - "no_logs_found", - "youtube_engine", - "youtube_engine_not_installed_title", - "youtube_engine_not_installed_message", - "youtube_engine_set_path", - "youtube_engine_unix_issue_message", - "download", - "file_not_found", - "custom", - "add_custom_url" - ], - - "cs": [ - "playlist", - "no_loop", - "generate", - "undo", - "download_all", - "add_all_to_playlist", - "add_all_to_queue", - "play_all_next", - "pause", - "view_all", - "no_tracks_added_yet", - "no_tracks", - "no_tracks_listened_yet", - "not_following_artists", - "no_favorite_albums_yet", - "no_logs_found", - "youtube_engine", - "youtube_engine_not_installed_title", - "youtube_engine_not_installed_message", - "youtube_engine_set_path", - "youtube_engine_unix_issue_message", - "download", - "file_not_found", - "custom", - "add_custom_url" - ], - - "de": [ - "playlist", - "no_loop", - "generate", - "undo", - "download_all", - "add_all_to_playlist", - "add_all_to_queue", - "play_all_next", - "pause", - "view_all", - "no_tracks_added_yet", - "no_tracks", - "no_tracks_listened_yet", - "not_following_artists", - "no_favorite_albums_yet", - "no_logs_found", - "youtube_engine", - "youtube_engine_not_installed_title", - "youtube_engine_not_installed_message", - "youtube_engine_set_path", - "youtube_engine_unix_issue_message", - "download", - "file_not_found", - "custom", - "add_custom_url" - ], - - "es": [ - "playlist", - "no_loop", - "generate", - "undo", - "download_all", - "add_all_to_playlist", - "add_all_to_queue", - "play_all_next", - "pause", - "view_all", - "no_tracks_added_yet", - "no_tracks", - "no_tracks_listened_yet", - "not_following_artists", - "no_favorite_albums_yet", - "no_logs_found", - "youtube_engine", - "youtube_engine_not_installed_title", - "youtube_engine_not_installed_message", - "youtube_engine_set_path", - "youtube_engine_unix_issue_message", - "download", - "file_not_found", - "custom", - "add_custom_url" - ], - - "eu": [ - "playlist", - "no_loop", - "generate", - "undo", - "download_all", - "add_all_to_playlist", - "add_all_to_queue", - "play_all_next", - "pause", - "view_all", - "no_tracks_added_yet", - "no_tracks", - "no_tracks_listened_yet", - "not_following_artists", - "no_favorite_albums_yet", - "no_logs_found", - "youtube_engine", - "youtube_engine_not_installed_title", - "youtube_engine_not_installed_message", - "youtube_engine_set_path", - "youtube_engine_unix_issue_message", - "download", - "file_not_found", - "custom", - "add_custom_url" - ], - - "fa": [ - "playlist", - "no_loop", - "generate", - "undo", - "download_all", - "add_all_to_playlist", - "add_all_to_queue", - "play_all_next", - "pause", - "view_all", - "no_tracks_added_yet", - "no_tracks", - "no_tracks_listened_yet", - "not_following_artists", - "no_favorite_albums_yet", - "no_logs_found", - "youtube_engine", - "youtube_engine_not_installed_title", - "youtube_engine_not_installed_message", - "youtube_engine_set_path", - "youtube_engine_unix_issue_message", - "download", - "file_not_found", - "custom", - "add_custom_url" - ], - - "fi": [ - "playlist", - "no_loop", - "generate", - "undo", - "download_all", - "add_all_to_playlist", - "add_all_to_queue", - "play_all_next", - "pause", - "view_all", - "no_tracks_added_yet", - "no_tracks", - "no_tracks_listened_yet", - "not_following_artists", - "no_favorite_albums_yet", - "no_logs_found", - "youtube_engine", - "youtube_engine_not_installed_title", - "youtube_engine_not_installed_message", - "youtube_engine_set_path", - "youtube_engine_unix_issue_message", - "download", - "file_not_found", - "custom", - "add_custom_url" - ], - - "fr": [ - "playlist", - "no_loop", - "generate", - "undo", - "download_all", - "add_all_to_playlist", - "add_all_to_queue", - "play_all_next", - "pause", - "view_all", - "no_tracks_added_yet", - "no_tracks", - "no_tracks_listened_yet", - "not_following_artists", - "no_favorite_albums_yet", - "no_logs_found", - "youtube_engine", - "youtube_engine_not_installed_title", - "youtube_engine_not_installed_message", - "youtube_engine_set_path", - "youtube_engine_unix_issue_message", - "download", - "file_not_found", - "custom", - "add_custom_url" - ], - - "hi": [ - "playlist", - "no_loop", - "generate", - "undo", - "download_all", - "add_all_to_playlist", - "add_all_to_queue", - "play_all_next", - "pause", - "view_all", - "no_tracks_added_yet", - "no_tracks", - "no_tracks_listened_yet", - "not_following_artists", - "no_favorite_albums_yet", - "no_logs_found", - "youtube_engine", - "youtube_engine_not_installed_title", - "youtube_engine_not_installed_message", - "youtube_engine_set_path", - "youtube_engine_unix_issue_message", - "download", - "file_not_found", - "custom", - "add_custom_url" - ], - - "id": [ - "playlist", - "no_loop", - "generate", - "undo", - "download_all", - "add_all_to_playlist", - "add_all_to_queue", - "play_all_next", - "pause", - "view_all", - "no_tracks_added_yet", - "no_tracks", - "no_tracks_listened_yet", - "not_following_artists", - "no_favorite_albums_yet", - "no_logs_found", - "youtube_engine", - "youtube_engine_not_installed_title", - "youtube_engine_not_installed_message", - "youtube_engine_set_path", - "youtube_engine_unix_issue_message", - "download", - "file_not_found", - "custom", - "add_custom_url" - ], - - "it": [ - "playlist", - "no_loop", - "generate", - "undo", - "download_all", - "add_all_to_playlist", - "add_all_to_queue", - "play_all_next", - "pause", - "view_all", - "no_tracks_added_yet", - "no_tracks", - "no_tracks_listened_yet", - "not_following_artists", - "no_favorite_albums_yet", - "no_logs_found", - "youtube_engine", - "youtube_engine_not_installed_title", - "youtube_engine_not_installed_message", - "youtube_engine_set_path", - "youtube_engine_unix_issue_message", - "download", - "file_not_found", - "custom", - "add_custom_url" - ], - - "ja": [ - "playlist", - "no_loop", - "generate", - "undo", - "download_all", - "add_all_to_playlist", - "add_all_to_queue", - "play_all_next", - "pause", - "view_all", - "no_tracks_added_yet", - "no_tracks", - "no_tracks_listened_yet", - "not_following_artists", - "no_favorite_albums_yet", - "no_logs_found", - "youtube_engine", - "youtube_engine_not_installed_title", - "youtube_engine_not_installed_message", - "youtube_engine_set_path", - "youtube_engine_unix_issue_message", - "download", - "file_not_found", - "custom", - "add_custom_url" - ], - - "ka": [ - "playlist", - "no_loop", - "generate", - "undo", - "download_all", - "add_all_to_playlist", - "add_all_to_queue", - "play_all_next", - "pause", - "view_all", - "no_tracks_added_yet", - "no_tracks", - "no_tracks_listened_yet", - "not_following_artists", - "no_favorite_albums_yet", - "no_logs_found", - "youtube_engine", - "youtube_engine_not_installed_title", - "youtube_engine_not_installed_message", - "youtube_engine_set_path", - "youtube_engine_unix_issue_message", - "download", - "file_not_found", - "custom", - "add_custom_url" - ], - - "ko": [ - "playlist", - "no_loop", - "generate", - "undo", - "download_all", - "add_all_to_playlist", - "add_all_to_queue", - "play_all_next", - "pause", - "view_all", - "no_tracks_added_yet", - "no_tracks", - "no_tracks_listened_yet", - "not_following_artists", - "no_favorite_albums_yet", - "no_logs_found", - "youtube_engine", - "youtube_engine_not_installed_title", - "youtube_engine_not_installed_message", - "youtube_engine_set_path", - "youtube_engine_unix_issue_message", - "download", - "file_not_found", - "custom", - "add_custom_url" - ], - - "ne": [ - "playlist", - "no_loop", - "generate", - "undo", - "download_all", - "add_all_to_playlist", - "add_all_to_queue", - "play_all_next", - "pause", - "view_all", - "no_tracks_added_yet", - "no_tracks", - "no_tracks_listened_yet", - "not_following_artists", - "no_favorite_albums_yet", - "no_logs_found", - "youtube_engine", - "youtube_engine_not_installed_title", - "youtube_engine_not_installed_message", - "youtube_engine_set_path", - "youtube_engine_unix_issue_message", - "download", - "file_not_found", - "custom", - "add_custom_url" - ], - - "nl": [ - "playlist", - "no_loop", - "generate", - "undo", - "download_all", - "add_all_to_playlist", - "add_all_to_queue", - "play_all_next", - "pause", - "view_all", - "no_tracks_added_yet", - "no_tracks", - "no_tracks_listened_yet", - "not_following_artists", - "no_favorite_albums_yet", - "no_logs_found", - "youtube_engine", - "youtube_engine_not_installed_title", - "youtube_engine_not_installed_message", - "youtube_engine_set_path", - "youtube_engine_unix_issue_message", - "download", - "file_not_found", - "custom", - "add_custom_url" - ], - - "pl": [ - "playlist", - "no_loop", - "generate", - "undo", - "download_all", - "add_all_to_playlist", - "add_all_to_queue", - "play_all_next", - "pause", - "view_all", - "no_tracks_added_yet", - "no_tracks", - "no_tracks_listened_yet", - "not_following_artists", - "no_favorite_albums_yet", - "no_logs_found", - "youtube_engine", - "youtube_engine_not_installed_title", - "youtube_engine_not_installed_message", - "youtube_engine_set_path", - "youtube_engine_unix_issue_message", - "download", - "file_not_found", - "custom", - "add_custom_url" - ], - - "pt": [ - "playlist", - "no_loop", - "generate", - "undo", - "download_all", - "add_all_to_playlist", - "add_all_to_queue", - "play_all_next", - "pause", - "view_all", - "no_tracks_added_yet", - "no_tracks", - "no_tracks_listened_yet", - "not_following_artists", - "no_favorite_albums_yet", - "no_logs_found", - "youtube_engine", - "youtube_engine_not_installed_title", - "youtube_engine_not_installed_message", - "youtube_engine_set_path", - "youtube_engine_unix_issue_message", - "download", - "file_not_found", - "custom", - "add_custom_url" - ], - - "ru": [ - "playlist", - "no_loop", - "generate", - "undo", - "download_all", - "add_all_to_playlist", - "add_all_to_queue", - "play_all_next", - "pause", - "view_all", - "no_tracks_added_yet", - "no_tracks", - "no_tracks_listened_yet", - "not_following_artists", - "no_favorite_albums_yet", - "no_logs_found", - "youtube_engine", - "youtube_engine_not_installed_title", - "youtube_engine_not_installed_message", - "youtube_engine_set_path", - "youtube_engine_unix_issue_message", - "download", - "file_not_found", - "custom", - "add_custom_url" - ], - - "th": [ - "playlist", - "no_loop", - "generate", - "undo", - "download_all", - "add_all_to_playlist", - "add_all_to_queue", - "play_all_next", - "pause", - "view_all", - "no_tracks_added_yet", - "no_tracks", - "no_tracks_listened_yet", - "not_following_artists", - "no_favorite_albums_yet", - "no_logs_found", - "youtube_engine", - "youtube_engine_not_installed_title", - "youtube_engine_not_installed_message", - "youtube_engine_set_path", - "youtube_engine_unix_issue_message", - "download", - "file_not_found", - "custom", - "add_custom_url" - ], - - "tr": [ - "playlist", - "no_loop", - "generate", - "undo", - "download_all", - "add_all_to_playlist", - "add_all_to_queue", - "play_all_next", - "pause", - "view_all", - "no_tracks_added_yet", - "no_tracks", - "no_tracks_listened_yet", - "not_following_artists", - "no_favorite_albums_yet", - "no_logs_found", - "youtube_engine", - "youtube_engine_not_installed_title", - "youtube_engine_not_installed_message", - "youtube_engine_set_path", - "youtube_engine_unix_issue_message", - "download", - "file_not_found", - "custom", - "add_custom_url" - ], - - "uk": [ - "playlist", - "no_loop", - "generate", - "undo", - "download_all", - "add_all_to_playlist", - "add_all_to_queue", - "play_all_next", - "pause", - "view_all", - "no_tracks_added_yet", - "no_tracks", - "no_tracks_listened_yet", - "not_following_artists", - "no_favorite_albums_yet", - "no_logs_found", - "youtube_engine", - "youtube_engine_not_installed_title", - "youtube_engine_not_installed_message", - "youtube_engine_set_path", - "youtube_engine_unix_issue_message", - "download", - "file_not_found", - "custom", - "add_custom_url" - ], - - "vi": [ - "playlist", - "no_loop", - "generate", - "undo", - "download_all", - "add_all_to_playlist", - "add_all_to_queue", - "play_all_next", - "pause", - "view_all", - "no_tracks_added_yet", - "no_tracks", - "no_tracks_listened_yet", - "not_following_artists", - "no_favorite_albums_yet", - "no_logs_found", - "youtube_engine", - "youtube_engine_not_installed_title", - "youtube_engine_not_installed_message", - "youtube_engine_set_path", - "youtube_engine_unix_issue_message", - "download", - "file_not_found", - "custom", - "add_custom_url" - ], - - "zh": [ - "playlist", - "no_loop", - "generate", - "undo", - "download_all", - "add_all_to_playlist", - "add_all_to_queue", - "play_all_next", - "pause", - "view_all", - "no_tracks_added_yet", - "no_tracks", - "no_tracks_listened_yet", - "not_following_artists", - "no_favorite_albums_yet", - "no_logs_found", - "youtube_engine", - "youtube_engine_not_installed_title", - "youtube_engine_not_installed_message", - "youtube_engine_set_path", - "youtube_engine_unix_issue_message", - "download", - "file_not_found", - "custom", - "add_custom_url" - ] -} +{} \ No newline at end of file diff --git a/windows/packaging/exe/inno_setup.iss b/windows/packaging/exe/inno_setup.iss index b6694aaf..976da962 100644 --- a/windows/packaging/exe/inno_setup.iss +++ b/windows/packaging/exe/inno_setup.iss @@ -24,6 +24,7 @@ WizardSmallImageFile="..\\..\\assets\\spotube-logo.bmp" PrivilegesRequired={{PRIVILEGES_REQUIRED}} ArchitecturesAllowed=x64compatible ArchitecturesInstallIn64BitMode=x64compatible +UninstallDisplayIcon={app}\{{EXECUTABLE_NAME}} [Languages] {% for locale in LOCALES %}