An Angular Ionic PWA
NOTE: To test out this app, your Spotify email must be added to the list of authorised users beforehand. Contact me if you would like to try.
preview.mp4
- 'Tinder-swiper' card-based music recommendation, determined by the users' favourite artists and tracks
- 'OAuth PKCE flow' used for Spotify account authorisation
- recommended track music previews played, via AudioContext
- recommended track visualisations, utilising metadata for:
- audio play progress
- interactive cards (+ depth effects on touch/hover) with Hammer.js
- track and artist image, track title and artists
- track feature category labels (i.e. 'high energy'/'low energy', 'hidden gem'/'popular')
- seamless card background colour/track art blending, processed on a Web Worker & OffscreenCanvas combo when supported (falling back to the main thread if necessary)
- reliance on reactive programming via RxJS for asynchronous event handling
- 'IndexedDB' and 'localStorage' are utilised for maintaining some basic data across sessions
- basic error handling on failed networking or authentication
- basic PWA capabilities (i.e. Service Worker)
- logging and dynamic env configuration
- 'ii8n' via ngx-translate
- integrated with (deployed via) Firebase
- supports Chrome (+Edge), Firefox and Safari
- reactive design, suitable for desktop and mobile devices
- 'lint-staged', 'ESLint' and 'Prettier' utilised for linting setup
- codebase complies with strict Typescript and Angular rules
- if the browser supports Web Worker OffscreenCanvas, the calculations to fetch, convert and determine an album art's average colour are processed on a separate thread
- after a new card is loaded (and painted), only fast GPU compositor rendering events will occur on card interaction (avoiding Paint and Layout on interactions such as drag and hover), with CSS transforms and conservative 'will-change' usage
- utilise CSS 'contain' to help to improve rendering time
- multiple network requests are executed in parallel where possible (when they have no sequential dependencies) with 'Promise.All'
- where possible, all networking requests are batched to maintain low rates (i.e. when a track is 'liked' no call is fired until the current batch of liked ids gets flushed - either triggered by timeouts or exiting the page)
- assets are compressed where possible
- utilise preloading/prefetching for essential domains such as 'https://api.spotify.com'
- utilise fetch priority hints
- abort no-longer necessary fetch requests
- always use 'onPush' change detection
- run code outside of Angular's zone if it would trigger unnecessary change detections (i.e. for handling events such as card hovering)
- rely on pure pipes for template transformations
- modules are split and utilise lazy-loading to avoid excessive payloads
- ensure all observables are completed to prevent leaks
- ensure all event listeners are removed to prevent leaks
- for handling all card events, listeners are added on a single wrapper element - relying on bubbled events - rather than listening to each card