From 45bc0eefe0c6a2715d81f858446e8f09d1f3a757 Mon Sep 17 00:00:00 2001 From: ClericalError Date: Wed, 14 Oct 2026 21:24:56 -0700 Subject: [PATCH] Rename everything to Stemify, and add a README - Python package stemroller/ -> stemify/, Android package com.stemroller.mobile -> com.stemify.mobile, app names, QML module, icons, desktop entries, MPRIS and Plex product names - Done-markers are now .stemify.json; stemd renames the old ones once at startup so songs separated before the rename aren't separated again - A top-level README covering the server, the Android and Android Auto app, the EQ, Stem Now and the desktop apps Co-Authored-By: Claude Opus 5.5 --- .dockerignore | 4 +- README.md | 562 ++++++++++++++++++ android/README.md | 10 +- android/app/build.gradle.kts | 4 +- android/app/proguard-rules.pro | 6 +- .../mobile/DebugCapture.kt | 10 +- android/app/src/main/AndroidManifest.xml | 4 +- .../com/{stemroller => stemify}/mobile/App.kt | 22 +- .../mobile/MainActivity.kt | 8 +- .../mobile/auto/CarArtProvider.kt | 6 +- .../mobile/auto/CarLibrary.kt | 14 +- .../mobile/auto/CarTree.kt | 2 +- .../mobile/auto/HomeReach.kt | 8 +- .../mobile/cache/Downloads.kt | 22 +- .../mobile/cache/MediaCache.kt | 4 +- .../mobile/core/Net.kt | 2 +- .../mobile/core/Settings.kt | 2 +- .../mobile/engine/Dsp.kt | 2 +- .../mobile/engine/StemDecoder.kt | 4 +- .../mobile/engine/StemEngine.kt | 2 +- .../mobile/eq/ApoConfig.kt | 12 +- .../mobile/eq/EqController.kt | 14 +- .../mobile/playback/MixPresets.kt | 2 +- .../mobile/playback/PlaybackManager.kt | 38 +- .../mobile/playback/PlaybackService.kt | 34 +- .../mobile/plex/PlexClient.kt | 14 +- .../mobile/plex/PlexModels.kt | 2 +- .../mobile/stems/StemCoverage.kt | 10 +- .../mobile/stems/StemIndex.kt | 2 +- .../mobile/stems/StemServer.kt | 16 +- .../{stemroller => stemify}/mobile/ui/Root.kt | 82 +-- .../mobile/ui/components/Chrome.kt | 20 +- .../mobile/ui/components/Controls.kt | 12 +- .../mobile/ui/components/Overlays.kt | 12 +- .../mobile/ui/nav/Navigation.kt | 8 +- .../mobile/ui/screens/Common.kt | 52 +- .../mobile/ui/screens/EqFilterScreens.kt | 50 +- .../mobile/ui/screens/EqScreen.kt | 50 +- .../mobile/ui/screens/LibraryScreens.kt | 62 +- .../mobile/ui/screens/NowPlaying.kt | 60 +- .../mobile/ui/screens/PlaylistScreens.kt | 66 +- .../mobile/ui/screens/ProgressVolumeBar.kt | 22 +- .../mobile/ui/screens/SettingsScreens.kt | 50 +- .../mobile/ui/theme/Icons.kt | 2 +- .../mobile/ui/theme/Theme.kt | 8 +- android/app/src/main/res/values/strings.xml | 2 +- android/app/src/main/res/values/themes.xml | 2 +- .../mobile/CarTreeTest.kt | 10 +- .../{stemroller => stemify}/mobile/DspTest.kt | 30 +- .../mobile/MediaCacheTest.kt | 4 +- .../mobile/StemIndexTest.kt | 12 +- android/settings.gradle.kts | 2 +- pyproject.toml | 10 +- scripts/install-desktop.sh | 36 +- server/README.md | 19 +- server/stemd.Dockerfile | 8 +- server/stemd.py | 39 +- server/stemserve.py | 8 +- {stemroller => stemify}/__init__.py | 0 {stemroller => stemify}/__main__.py | 0 {stemroller => stemify}/app.py | 12 +- .../assets/fonts/Inter-Bold.ttf | Bin .../assets/fonts/Inter-LICENSE.txt | 0 .../assets/fonts/Inter-Medium.ttf | Bin .../assets/fonts/Inter-Regular.ttf | Bin .../assets/fonts/Inter-SemiBold.ttf | Bin .../assets/stemify.svg | 0 {stemroller => stemify}/audio_engine.py | 0 {stemroller => stemify}/catalog.py | 0 {stemroller => stemify}/controller.py | 2 +- {stemroller => stemify}/gpu_monitor.py | 0 {stemroller => stemify}/jobs_model.py | 0 {stemroller => stemify}/library_core.py | 2 +- {stemroller => stemify}/player/README.md | 10 +- {stemroller => stemify}/player/__init__.py | 0 {stemroller => stemify}/player/__main__.py | 0 {stemroller => stemify}/player/app.py | 12 +- .../player/assets/fonts/Carlito-Bold.ttf | Bin .../player/assets/fonts/Carlito-OFL.txt | 0 .../player/assets/fonts/Carlito-Regular.ttf | Bin .../player/assets/fonts/Selawik-Bold.ttf | Bin .../player/assets/fonts/Selawik-LICENSE.txt | 0 .../player/assets/fonts/Selawik-Regular.ttf | Bin .../player/assets/fonts/Selawik-Semibold.ttf | Bin .../player/assets/stemify-player.svg | 0 {stemroller => stemify}/player/config.py | 6 +- {stemroller => stemify}/player/engine.py | 0 {stemroller => stemify}/player/icons.py | 0 {stemroller => stemify}/player/library.py | 0 {stemroller => stemify}/player/mpris.py | 8 +- {stemroller => stemify}/player/player.py | 0 {stemroller => stemify}/player/plex.py | 2 +- .../player/qml/StemPlayer/Backstage.qml | 0 .../player/qml/StemPlayer/CaptionButton.qml | 0 .../player/qml/StemPlayer/FormulaBar.qml | 0 .../player/qml/StemPlayer/Ico.qml | 0 .../player/qml/StemPlayer/Main.qml | 0 .../player/qml/StemPlayer/MessageBar.qml | 0 .../player/qml/StemPlayer/OfficeButton.qml | 0 .../player/qml/StemPlayer/RButton.qml | 0 .../player/qml/StemPlayer/RGroup.qml | 0 .../player/qml/StemPlayer/ResizeEdge.qml | 0 .../player/qml/StemPlayer/Ribbon.qml | 0 .../player/qml/StemPlayer/Sheet.qml | 8 +- .../player/qml/StemPlayer/SheetTabs.qml | 0 .../player/qml/StemPlayer/StatusBar.qml | 0 .../player/qml/StemPlayer/StemChart.qml | 0 .../player/qml/StemPlayer/T.qml | 0 .../player/qml/StemPlayer/TaskPane.qml | 2 +- .../player/qml/StemPlayer/Tip.qml | 0 .../player/qml/StemPlayer/TitleBar.qml | 0 .../player/qml/StemPlayer/X.qml | 0 .../player/qml/StemPlayer/XCheck.qml | 0 .../player/qml/StemPlayer/XField.qml | 0 .../player/qml/StemPlayer/XMenu.qml | 0 .../player/qml/StemPlayer/XScrollBar.qml | 0 .../player/qml/StemPlayer/qmldir | 0 {stemroller => stemify}/player/sheets.py | 0 {stemroller => stemify}/player/stems.py | 0 {stemroller => stemify}/providers.py | 0 .../qml/Stemify}/AeroButton.qml | 0 .../qml/Stemify}/AeroComboBox.qml | 0 .../qml/Stemify}/AeroSlider.qml | 0 .../qml/Stemify}/AeroSwitch.qml | 0 .../qml/Stemify}/CaptionButton.qml | 0 .../qml/Stemify}/Card.qml | 0 .../qml/Stemify}/DashedFrame.qml | 0 .../qml/Stemify}/DropZone.qml | 0 .../qml/Stemify}/Elevation.qml | 0 .../qml/Stemify}/FrameOverlay.qml | 0 .../qml/Stemify}/GlassPanel.qml | 0 .../qml/Stemify}/Glow.qml | 0 .../qml/Stemify}/Icon.qml | 0 .../qml/Stemify}/IconButton.qml | 0 .../qml/Stemify}/LevelMeter.qml | 0 .../qml/Stemify}/Main.qml | 4 +- .../qml/Stemify}/QueueItem.qml | 0 .../qml/Stemify}/ResizeEdge.qml | 0 .../qml/Stemify}/SettingsDialog.qml | 0 .../qml/Stemify}/Sidebar.qml | 0 .../qml/Stemify}/StatusChip.qml | 0 .../qml/Stemify}/StemLane.qml | 0 .../qml/Stemify}/StripedProgress.qml | 0 .../qml/Stemify}/Theme.qml | 0 .../qml/Stemify}/Tip.qml | 0 .../qml/Stemify}/TitleBar.qml | 2 +- .../qml/Stemify}/Toast.qml | 0 .../qml/Stemify}/TrackView.qml | 0 .../qml/Stemify}/Transport.qml | 0 .../qml/Stemify}/Txt.qml | 0 .../StemRoller => stemify/qml/Stemify}/qmldir | 2 +- {stemroller => stemify}/settings.py | 2 +- {stemroller => stemify}/worker/__init__.py | 0 {stemroller => stemify}/worker/__main__.py | 10 +- {stemroller => stemify}/worker/audio_io.py | 0 {stemroller => stemify}/worker/backends.py | 0 {stemroller => stemify}/worker/cli.py | 8 +- {stemroller => stemify}/worker_client.py | 4 +- uv.lock | 2 +- 159 files changed, 1136 insertions(+), 542 deletions(-) create mode 100644 README.md rename android/app/src/debug/java/com/{stemroller => stemify}/mobile/DebugCapture.kt (89%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/App.kt (90%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/MainActivity.kt (96%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/auto/CarArtProvider.kt (97%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/auto/CarLibrary.kt (97%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/auto/CarTree.kt (99%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/auto/HomeReach.kt (94%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/cache/Downloads.kt (95%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/cache/MediaCache.kt (99%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/core/Net.kt (98%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/core/Settings.kt (99%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/engine/Dsp.kt (99%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/engine/StemDecoder.kt (99%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/engine/StemEngine.kt (99%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/eq/ApoConfig.kt (95%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/eq/EqController.kt (97%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/playback/MixPresets.kt (98%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/playback/PlaybackManager.kt (96%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/playback/PlaybackService.kt (96%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/plex/PlexClient.kt (97%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/plex/PlexModels.kt (99%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/stems/StemCoverage.kt (95%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/stems/StemIndex.kt (98%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/stems/StemServer.kt (96%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/ui/Root.kt (85%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/ui/components/Chrome.kt (97%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/ui/components/Controls.kt (98%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/ui/components/Overlays.kt (97%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/ui/nav/Navigation.kt (98%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/ui/screens/Common.kt (93%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/ui/screens/EqFilterScreens.kt (94%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/ui/screens/EqScreen.kt (86%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/ui/screens/LibraryScreens.kt (94%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/ui/screens/NowPlaying.kt (94%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/ui/screens/PlaylistScreens.kt (90%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/ui/screens/ProgressVolumeBar.kt (95%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/ui/screens/SettingsScreens.kt (94%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/ui/theme/Icons.kt (99%) rename android/app/src/main/java/com/{stemroller => stemify}/mobile/ui/theme/Theme.kt (97%) rename android/app/src/test/java/com/{stemroller => stemify}/mobile/CarTreeTest.kt (94%) rename android/app/src/test/java/com/{stemroller => stemify}/mobile/DspTest.kt (91%) rename android/app/src/test/java/com/{stemroller => stemify}/mobile/MediaCacheTest.kt (98%) rename android/app/src/test/java/com/{stemroller => stemify}/mobile/StemIndexTest.kt (91%) rename {stemroller => stemify}/__init__.py (100%) rename {stemroller => stemify}/__main__.py (100%) rename {stemroller => stemify}/app.py (97%) rename {stemroller => stemify}/assets/fonts/Inter-Bold.ttf (100%) rename {stemroller => stemify}/assets/fonts/Inter-LICENSE.txt (100%) rename {stemroller => stemify}/assets/fonts/Inter-Medium.ttf (100%) rename {stemroller => stemify}/assets/fonts/Inter-Regular.ttf (100%) rename {stemroller => stemify}/assets/fonts/Inter-SemiBold.ttf (100%) rename stemroller/assets/stemroller.svg => stemify/assets/stemify.svg (100%) rename {stemroller => stemify}/audio_engine.py (100%) rename {stemroller => stemify}/catalog.py (100%) rename {stemroller => stemify}/controller.py (99%) rename {stemroller => stemify}/gpu_monitor.py (100%) rename {stemroller => stemify}/jobs_model.py (100%) rename {stemroller => stemify}/library_core.py (99%) rename {stemroller => stemify}/player/README.md (91%) rename {stemroller => stemify}/player/__init__.py (100%) rename {stemroller => stemify}/player/__main__.py (100%) rename {stemroller => stemify}/player/app.py (93%) rename {stemroller => stemify}/player/assets/fonts/Carlito-Bold.ttf (100%) rename {stemroller => stemify}/player/assets/fonts/Carlito-OFL.txt (100%) rename {stemroller => stemify}/player/assets/fonts/Carlito-Regular.ttf (100%) rename {stemroller => stemify}/player/assets/fonts/Selawik-Bold.ttf (100%) rename {stemroller => stemify}/player/assets/fonts/Selawik-LICENSE.txt (100%) rename {stemroller => stemify}/player/assets/fonts/Selawik-Regular.ttf (100%) rename {stemroller => stemify}/player/assets/fonts/Selawik-Semibold.ttf (100%) rename stemroller/player/assets/stemroller-player.svg => stemify/player/assets/stemify-player.svg (100%) rename {stemroller => stemify}/player/config.py (87%) rename {stemroller => stemify}/player/engine.py (100%) rename {stemroller => stemify}/player/icons.py (100%) rename {stemroller => stemify}/player/library.py (100%) rename {stemroller => stemify}/player/mpris.py (95%) rename {stemroller => stemify}/player/player.py (100%) rename {stemroller => stemify}/player/plex.py (99%) rename {stemroller => stemify}/player/qml/StemPlayer/Backstage.qml (100%) rename {stemroller => stemify}/player/qml/StemPlayer/CaptionButton.qml (100%) rename {stemroller => stemify}/player/qml/StemPlayer/FormulaBar.qml (100%) rename {stemroller => stemify}/player/qml/StemPlayer/Ico.qml (100%) rename {stemroller => stemify}/player/qml/StemPlayer/Main.qml (100%) rename {stemroller => stemify}/player/qml/StemPlayer/MessageBar.qml (100%) rename {stemroller => stemify}/player/qml/StemPlayer/OfficeButton.qml (100%) rename {stemroller => stemify}/player/qml/StemPlayer/RButton.qml (100%) rename {stemroller => stemify}/player/qml/StemPlayer/RGroup.qml (100%) rename {stemroller => stemify}/player/qml/StemPlayer/ResizeEdge.qml (100%) rename {stemroller => stemify}/player/qml/StemPlayer/Ribbon.qml (100%) rename {stemroller => stemify}/player/qml/StemPlayer/Sheet.qml (97%) rename {stemroller => stemify}/player/qml/StemPlayer/SheetTabs.qml (100%) rename {stemroller => stemify}/player/qml/StemPlayer/StatusBar.qml (100%) rename {stemroller => stemify}/player/qml/StemPlayer/StemChart.qml (100%) rename {stemroller => stemify}/player/qml/StemPlayer/T.qml (100%) rename {stemroller => stemify}/player/qml/StemPlayer/TaskPane.qml (98%) rename {stemroller => stemify}/player/qml/StemPlayer/Tip.qml (100%) rename {stemroller => stemify}/player/qml/StemPlayer/TitleBar.qml (100%) rename {stemroller => stemify}/player/qml/StemPlayer/X.qml (100%) rename {stemroller => stemify}/player/qml/StemPlayer/XCheck.qml (100%) rename {stemroller => stemify}/player/qml/StemPlayer/XField.qml (100%) rename {stemroller => stemify}/player/qml/StemPlayer/XMenu.qml (100%) rename {stemroller => stemify}/player/qml/StemPlayer/XScrollBar.qml (100%) rename {stemroller => stemify}/player/qml/StemPlayer/qmldir (100%) rename {stemroller => stemify}/player/sheets.py (100%) rename {stemroller => stemify}/player/stems.py (100%) rename {stemroller => stemify}/providers.py (100%) rename {stemroller/qml/StemRoller => stemify/qml/Stemify}/AeroButton.qml (100%) rename {stemroller/qml/StemRoller => stemify/qml/Stemify}/AeroComboBox.qml (100%) rename {stemroller/qml/StemRoller => stemify/qml/Stemify}/AeroSlider.qml (100%) rename {stemroller/qml/StemRoller => stemify/qml/Stemify}/AeroSwitch.qml (100%) rename {stemroller/qml/StemRoller => stemify/qml/Stemify}/CaptionButton.qml (100%) rename {stemroller/qml/StemRoller => stemify/qml/Stemify}/Card.qml (100%) rename {stemroller/qml/StemRoller => stemify/qml/Stemify}/DashedFrame.qml (100%) rename {stemroller/qml/StemRoller => stemify/qml/Stemify}/DropZone.qml (100%) rename {stemroller/qml/StemRoller => stemify/qml/Stemify}/Elevation.qml (100%) rename {stemroller/qml/StemRoller => stemify/qml/Stemify}/FrameOverlay.qml (100%) rename {stemroller/qml/StemRoller => stemify/qml/Stemify}/GlassPanel.qml (100%) rename {stemroller/qml/StemRoller => stemify/qml/Stemify}/Glow.qml (100%) rename {stemroller/qml/StemRoller => stemify/qml/Stemify}/Icon.qml (100%) rename {stemroller/qml/StemRoller => stemify/qml/Stemify}/IconButton.qml (100%) rename {stemroller/qml/StemRoller => stemify/qml/Stemify}/LevelMeter.qml (100%) rename {stemroller/qml/StemRoller => stemify/qml/Stemify}/Main.qml (99%) rename {stemroller/qml/StemRoller => stemify/qml/Stemify}/QueueItem.qml (100%) rename {stemroller/qml/StemRoller => stemify/qml/Stemify}/ResizeEdge.qml (100%) rename {stemroller/qml/StemRoller => stemify/qml/Stemify}/SettingsDialog.qml (100%) rename {stemroller/qml/StemRoller => stemify/qml/Stemify}/Sidebar.qml (100%) rename {stemroller/qml/StemRoller => stemify/qml/Stemify}/StatusChip.qml (100%) rename {stemroller/qml/StemRoller => stemify/qml/Stemify}/StemLane.qml (100%) rename {stemroller/qml/StemRoller => stemify/qml/Stemify}/StripedProgress.qml (100%) rename {stemroller/qml/StemRoller => stemify/qml/Stemify}/Theme.qml (100%) rename {stemroller/qml/StemRoller => stemify/qml/Stemify}/Tip.qml (100%) rename {stemroller/qml/StemRoller => stemify/qml/Stemify}/TitleBar.qml (99%) rename {stemroller/qml/StemRoller => stemify/qml/Stemify}/Toast.qml (100%) rename {stemroller/qml/StemRoller => stemify/qml/Stemify}/TrackView.qml (100%) rename {stemroller/qml/StemRoller => stemify/qml/Stemify}/Transport.qml (100%) rename {stemroller/qml/StemRoller => stemify/qml/Stemify}/Txt.qml (100%) rename {stemroller/qml/StemRoller => stemify/qml/Stemify}/qmldir (97%) rename {stemroller => stemify}/settings.py (96%) rename {stemroller => stemify}/worker/__init__.py (100%) rename {stemroller => stemify}/worker/__main__.py (96%) rename {stemroller => stemify}/worker/audio_io.py (100%) rename {stemroller => stemify}/worker/backends.py (100%) rename {stemroller => stemify}/worker/cli.py (92%) rename {stemroller => stemify}/worker_client.py (95%) diff --git a/.dockerignore b/.dockerignore index f4a18b9..bd35756 100644 --- a/.dockerignore +++ b/.dockerignore @@ -2,5 +2,5 @@ * !server/stemd.py !server/stemd-requirements.txt -!stemroller/*.py -!stemroller/worker/*.py +!stemify/*.py +!stemify/worker/*.py diff --git a/README.md b/README.md new file mode 100644 index 0000000..9e55105 --- /dev/null +++ b/README.md @@ -0,0 +1,562 @@ +# Stemify + +**Your whole music library, taken apart and put back together however you like.** + +Ever wanted to hear "Carry On Wayward Son" without the vocals so you can belt it out yourself? Or +mute the drums on a song to figure out what the bass player is actually doing back there? Stemify +splits every song in your library into its separate parts (vocals, drums, bass, guitar, piano and +"other"), keeps them organised next to your music, and gives you players that let you mix them +live, on your phone, in your car, and on your desktop. + +It's a home-grown, slightly over-engineered love letter to karaoke, music nerdery and the joy of +pressing the "mute vocals" button at exactly the wrong moment. + +--- + +## Contents + +- [The big picture](#the-big-picture) +- [What you get](#what-you-get) +- [Setting it up](#setting-it-up) + - [1. The server: stemd and stemserve](#1-the-server-stemd-and-stemserve) + - [2. The Android app](#2-the-android-app) + - [3. The desktop apps (optional)](#3-the-desktop-apps-optional) +- [Using the Android app](#using-the-android-app) +- [Stem Now: skipping the line](#stem-now-skipping-the-line) +- [The Equalizer](#the-equalizer) +- [Android Auto](#android-auto) +- [The desktop apps](#the-desktop-apps) +- [Separation models](#separation-models) +- [How the pieces find each other](#how-the-pieces-find-each-other) +- [stemserve API](#stemserve-api) +- [Building and testing](#building-and-testing) +- [Repo tour](#repo-tour) +- [Troubleshooting and FAQ](#troubleshooting-and-faq) +- [Credits](#credits) +- [License](#license) + +--- + +## The big picture + +There are three moving parts, and they all agree on one simple idea: **the stems folder mirrors +the music folder.** If your song lives at `Kansas/Leftoverture/01 Carry On.flac`, its stems live at +`Stems/Kansas/Leftoverture/01 Carry On/`. That's it. That's the whole trick. + +``` + ┌──────────────────────────── your server (unraid, in our case) ───────────────────────────┐ + │ │ + │ Music/ ──read──▶ stemd (GPU) ──writes──▶ Stems/ ──read──▶ stemserve (:8765) ─────┼──▶ phone, car, desktop + │ ▲ ▲ │ │ + │ │ └──────── "Stem Now" requests ◀──────────────┘ │ + │ Plex Media Server (:32400) ──────────────────────────────────────────────────────────────┼──▶ library, artwork, playlists + └───────────────────────────────────────────────────────────────────────────────────────────┘ +``` + +- **stemd** sits on the server and chews through your library on the GPU, one song at a time, + forever. New album? It notices within half an hour and gets to work. +- **stemserve** hands the finished stems to your devices over HTTP, with seeking, waveforms and + optional Opus transcodes so your phone storage doesn't cry. +- **Plex** stays in charge of what it's good at: your library, metadata, artwork and playlists. +- **The apps** (Android, Android Auto, and two desktop apps) play everything, and quietly fall back + to the original file for any song that hasn't been separated yet. Nothing is ever unplayable. + +--- + +## What you get + +**On your phone (Android)** +- A Plex music player with per-stem faders, mute and solo, and one-tap mixes: Full, Karaoke, + A Cappella, No Drums, Rhythm, No Guitar, No Bass. +- A Plexamp-style waveform seek bar that doubles as a volume control (drag sideways to seek, up and + down for volume). The waveform is scaled to each song, so you can actually see the quiet verse + and the big chorus. +- Live level meters for every stem, updated every frame and in sync with what you hear. +- A 10-band graphic EQ **plus** Equalizer APO-style parametric filters, with per-device profiles + that switch automatically when you plug in headphones or connect to Bluetooth. +- Paste in an AutoEQ correction for your headphones and you're done. +- Downloads for offline listening, stems and all. +- Gapless playback, a proper queue, playlists (create, reorder, rename), search, and "On This + Day" album birthdays on the home screen. +- "Stem Now": jump any song, album, artist or playlist to the front of the separation queue. +- An iOS-flavoured look in Black, Dark or White, at whatever refresh rate your panel can manage. + +**In your car (Android Auto)** +- A browse tree built for a rotary knob and no touchscreen, with voice search, a Vocals on/off + button and a Mix button right next to play/pause. + +**On your desktop (Linux)** +- **Stemify (the separator)**: drag a song onto the window, get stems out the other side, preview them in sync, + export them. Material layout meets Windows 7 Aero glass, running at 240 Hz because why not. +- **Stemify Player**: your Plex library and its stems, with full mixing... dressed up as + Microsoft Excel 2016. Yes, really. Your boss will think you're working on the quarterly numbers. + +**On the server** +- **stemd** separates everything automatically with BS-RoFormer SW (6 stems) on an NVIDIA GPU, + politely, at low priority, sharing the card with Plex transcodes. +- **stemserve** is one Python file using only the standard library. ffmpeg is optional. + +--- + +## Setting it up + +The recommended order is server first, then phone, then (if you like) desktop. The examples below +use unraid paths and the addresses from the original setup (`192.168.86.2`). Swap in your own. + +### 1. The server: stemd and stemserve + +You need Docker, and for stemd an NVIDIA GPU (on unraid, install the **Nvidia-Driver** plugin from +the Apps tab). A CPU-only build exists for testing, but separating a whole library on a CPU is a +good way to celebrate several birthdays while you wait. + +**Folders first** (owned by `99:100`, unraid's nobody:users): + +```sh +mkdir -p /mnt/user/appdata/stemserve/cache \ + /mnt/user/appdata/stemd/models \ + /mnt/user/appdata/stemd/state/queue +chown -R 99:100 /mnt/user/appdata/stemserve /mnt/user/appdata/stemd +``` + +**stemd** builds from the repo root because it borrows the `stemify` package. Copy the repo (or +at least `stemify/`, `server/` and `.dockerignore`) to `/mnt/user/appdata/stemd/src`, then: + +```sh +docker build -f /mnt/user/appdata/stemd/src/server/stemd.Dockerfile -t stemd /mnt/user/appdata/stemd/src +docker run -d --name stemd --restart unless-stopped --stop-timeout 60 \ + --runtime=nvidia -e NVIDIA_VISIBLE_DEVICES=all -e NVIDIA_DRIVER_CAPABILITIES=compute,utility \ + -v "/mnt/user/Music/Actual music/Flacs":/music:ro \ + -v /mnt/user/Music/Stems:/stems \ + -v /mnt/user/appdata/stemd/models:/models \ + -v /mnt/user/appdata/stemd/state:/state \ + stemd +docker logs -f stemd +``` + +The first song downloads the model (about 700 MB). After that the log reads like a very calm +sports commentary: how many tracks are left, which one it's on, and how many times faster than +realtime it went. + +**stemserve** is tiny. Copy the `server/` folder to `/mnt/user/appdata/stemserve` and either use +the included compose file: + +```sh +cd /mnt/user/appdata/stemserve && docker compose up -d --build +``` + +or run it by hand: + +```sh +docker build -t stemserve /mnt/user/appdata/stemserve +docker run -d --name stemserve --restart unless-stopped -p 8765:8765 \ + -v /mnt/user/Music/Stems:/stems:ro \ + -v /mnt/user/appdata/stemserve/cache:/cache \ + -v /mnt/user/appdata/stemd/state/queue:/queue \ + stemserve +``` + +Check it from any machine on your network: + +```sh +curl http://192.168.86.2:8765/api/info +``` + +If you see a happy little JSON blob with a track count, you're in business. + +
+Server settings (environment variables) + +**stemd** + +| Variable | Default | What it does | +|---|---|---| +| `MUSIC_DIR` | `/music` | Your music library (read-only is fine) | +| `STEMS_DIR` | `/stems` | Where stems go | +| `STATE_DIR` | `/state` | The failed-track list lives here | +| `QUEUE_DIR` | `STATE_DIR/queue` | Where "Stem Now" requests arrive | +| `MODELS_DIR` | `/models` | Model weights, downloaded on first use | +| `MODEL` | `roformer_bs_sw` | Any model id from [the table below](#separation-models) | +| `DEVICE` | `cuda` | `cuda`, `cuda:N` or `cpu` | +| `RESCAN_MIN` | `30` | Minutes between library scans once it's caught up | +| `FP16` | `1` | Half precision on the GPU (`0` for full fp32) | +| `OVERLAP`, `SEGMENT`, `SHIFTS` | `0.25`, `0`, `0` | Separation quality knobs, same as the desktop app | + +`docker build --build-arg TORCH_INDEX=cpu ...` makes a small GPU-less image for testing. + +**stemserve** + +| Variable | Default | What it does | +|---|---|---| +| `STEMS_DIR` | `/stems` | The stems folder | +| `CACHE_DIR` | `/cache` | Opus transcodes and waveforms (safe to delete any time) | +| `QUEUE_DIR` | `/queue` | stemd's "Stem Now" folder, shared with it | +| `PORT` | `8765` | Listen port | +| `TOKEN` | empty | If set, every request needs `X-Stem-Token` or `?token=` | +| `INDEX_TTL` | `30` | Seconds between rescans of the stems folder | + +
+ +**Updating later:** copy the new files over, rebuild the image, `docker rm -f` the container, and +run it again. Your stems, models and settings live in the mounted folders, so nothing is lost. +Update stemd before stemserve: if you separated songs before the project was called Stemify, +stemd renames their old done-markers on its first start so nothing gets separated twice. + +### 2. The Android app + +Built for (and lovingly tested on) a OnePlus 15, but any recent Android phone should be happy. + +1. Grab `Stemify.apk` from the Releases page, or [build it yourself](#building-and-testing), + then sideload it: + ```sh + adb install -r Stemify.apk + ``` +2. Open it and go to **Library → Connect** (or Settings → Plex). Enter the 4-character code at + [plex.tv/link](https://plex.tv/link) and pick your music library. +3. Visit **Settings → Stem Server** and point it at your stemserve. It should say "Online" with a + song count. (The default address is `http://192.168.86.2:8765`, which is almost certainly not + yours.) + +The app checks stemserve for freshly separated songs every minute, so your library slowly "lights +up" as stemd works through it. + +### 3. The desktop apps (optional) + +Linux, Python 3.12 and [uv](https://docs.astral.sh/uv/). The default setup uses PyTorch for ROCm +(AMD GPUs, developed on an RX 9070 XT). NVIDIA and CPU work too if you point the torch index +elsewhere in `pyproject.toml`. + +```sh +uv sync +uv run stemify # the drag-and-drop separator +uv run stemify-player # the Excel-shaped music player +./scripts/install-desktop.sh # adds both to your app grid ("--uninstall" removes them) +``` + +--- + +## Using the Android app + +**Tabs:** Library, Playlists, Search, Downloads and Settings. + +**Stems are the norm, so the exceptions are what's marked.** Songs without stems yet say +**NO STEMS**, and albums and artists say **NO STEMS** or something like **7/10 STEMS** until +they're done. Those songs still play, just from the original file. + +**Hold anything** (a song, album, artist or playlist) for: + +- **Add to Front of Queue** / **Add to End of Queue** +- **Download** (or **Remove Download**) +- **Add to Playlist** (playlists can even go into other playlists) +- **Stem Now**, while any of it lacks stems + +**The Now Playing screen** has the waveform seek bar, the mixer (faders, mute, solo, mix presets, +meters, master volume) and the queue. Your mix can carry over from song to song or reset each +time, your choice. + +**Downloads** are proper offline copies: every stem fully fetched (or the original file for songs +without stems). Sort by download order, artist or release date. + +**Stem Quality** decides how stems travel from the server: lossless FLAC, or Opus at a bitrate of +your choosing, which takes roughly an eighth of the space and is transcoded and cached on the +server. + +**Streaming** needs your home network (Plex and stemserve are plain HTTP on the LAN). Anything +you've downloaded or already streamed plays anywhere. + +--- + +## Stem Now: skipping the line + +stemd works through your library on its own, but a big library takes days. If you're desperate to +karaoke your way through an album tonight, hold it and choose **Stem Now**. + +Here's what happens: + +1. The app sends the songs that still lack stems to stemserve. +2. stemserve drops a little request file into stemd's queue folder. +3. stemd finishes the song it's on, then does yours next, ahead of everything else. If it was + idle, it starts within about 5 seconds. +4. About a minute after each song finishes, the app notices and plays it with stems from then on. + +Requests are handled oldest first and survive restarts. stemd matches the paths Plex reports to +files in its own music folder by their artist/album/file tail, so it doesn't matter that Plex and +stemd see the library under different mount points. Songs that failed before (corrupt files, or +anything over 40 minutes) are skipped; delete `state/failed.json` to give them all another shot. + +--- + +## The Equalizer + +Find it in **Settings → Equalizer**. It's two equalizers wearing one trench coat. + +**The graphic EQ** has ten octave bands from 31 Hz to 16 kHz, a response curve, and a pile of +presets borrowed in spirit from iOS (Bass Booster, Late Night, Vocal Booster and friends). + +**Parametric Filters** are modelled on [Equalizer APO](https://sourceforge.net/projects/equalizerapo/): + +| Type | What it's for | +|---|---| +| Peak | Boost or cut around one frequency | +| Low Shelf / High Shelf | Tilt everything below or above a frequency | +| Low Pass / High Pass | Roll off the top or bottom, at 6, 12, 24, 36 or 48 dB per octave | +| Band Pass | Keep only a band | +| Notch | Surgically remove one frequency (hello, 60 Hz hum) | +| All Pass | Shift phase without changing level, for the true connoisseur | + +Every filter has frequency, gain and Q, can apply to **both channels, or just left or right**, +and can be switched off on its own to compare. Drag a filter's handle on its curve (sideways for +frequency, up and down for gain), use the sliders, or tap any value to type it in. + +**Headphone corrections in two taps:** copy a `ParametricEQ.txt` from +[AutoEQ](https://github.com/jaakkopasanen/AutoEq) for your headphones, then on the Filters page +choose **••• → Paste APO Config**. You can also **Copy as APO Config** to take your settings to a +PC. + +**Profiles** link to output devices: the phone speaker, wired headphones, each Bluetooth headset, +USB DACs. Plug something in and its profile switches on automatically, or pick one by hand. + +**Preamp and anti-clipping:** each profile has its own manual preamp, and the anti-clipping switch +adds just enough extra cut that a full-scale signal at the curve's loudest point still peaks at +0 dBFS. A limiter on the master bus catches anything else, so cranking the bass won't make things +crackle. + +--- + +## Android Auto + +Designed for a 2016 Mazda MX-5 with the Mazda Connect retrofit: an 800×480 screen with touch +disabled, driven entirely by the commander knob and the steering wheel buttons. If it works there, +it'll work in your car. + +- **Four tabs:** Playlists, Albums, Artists, Downloads (Downloads comes first when you're away + from home). +- **Shallow and short:** every song list starts with **Shuffle all**, and anything longer than 40 + items splits into A to Z folders, so you never have to twiddle the knob through 400 songs at a + red light. +- **Now playing:** next to the transport controls you get **Vocals** on/off (instant karaoke), + **Mix** (cycles through the presets), shuffle and repeat. The current mix shows on the artist + line, e.g. "Black Sabbath · Karaoke". +- **Voice:** hold the talk button and say "play Paranoid on Stemify". Playlists, artists, + albums and songs all work. +- **Offline:** away from home, the app quickly notices the server is unreachable and lists only + songs that will actually play (downloaded or fully cached). + +**Setting up the car (once):** Android Auto hides sideloaded apps until you allow them. On the +phone, search Settings for "Android Auto", tap **Version** ten times, then in the ⋮ menu go to +**Developer settings** and tick **Unknown sources**. Stemify then shows up in Auto's app +launcher. + +**Testing without a car:** Google's Desktop Head Unit can impersonate the Miata. On the phone, +start the head unit server from Auto's developer settings, then: + +```sh +adb forward tcp:5277 tcp:5277 +~/Android/Sdk/extras/google/auto/desktop-head-unit -c ~/Android/Sdk/extras/google/auto/config/rotary.ini +``` + +--- + +## The desktop apps + +### Stemify (the separator) + +Drop files onto the window. Each becomes a queue item, separation starts right away with your +last-used model and device, and when it's done you get a lane per stem with a waveform, solo, mute, +gain and export. Export everything, one stem, or your current mix, as WAV, FLAC or MP3. + +Other niceties: + +- Separation runs in its own worker process, so the UI never stutters, even mid-separation. +- Works on AMD (ROCm), NVIDIA and CPU, and shows free VRAM. +- Results are cached, so flipping back to an old song is instant (with a size limit you can set). +- A dev frame-time overlay, for anyone who wants proof of the 240 fps claims. + +### Stemify Player (the spreadsheet) + +The desktop sibling of the phone app, disguised as Microsoft Excel 2016. Some highlights from the +translation guide: + +| In Excel | In Stemify Player | +|---|---| +| Sheets (Songs, Artists, Albums, Playlists, Stems, Queue) | Your library | +| "Tell me what you want to do" | Search | +| Zoom slider | Master volume | +| Cell Styles | Mix presets (Karaoke is filed under "Bad", A Cappella under "Good") | +| AutoSum | AutoShuffle | +| Undo / Redo | Previous / next song | +| Format task pane | Now playing, with the stems as a column chart you can drag | +| `#GETTING_DATA` | A playlist loading from Plex | + +It reports plays to Plex, supports media keys and desktop media controls (MPRIS), and remembers +your queue, position and mix between launches. The full tour is in +[`stemify/player/README.md`](stemify/player/README.md). + +--- + +## Separation models + +| Model id | Name | Stems | Notes | +|---|---|---|---| +| `htdemucs` | HT Demucs | 4 | Fast | +| `htdemucs_ft` | HT Demucs FT | 4 | Fine-tuned, about 4x slower | +| `htdemucs_6s` | HT Demucs 6-stem | 6 | Adds guitar and piano | +| `roformer_bs_vocals` | BS-RoFormer Vocals | 2 | Vocals / instrumental (Viperx 1297) | +| `roformer_mel_kim_ft` | Mel-RoFormer Vocals FT | 2 | Cleanest vocals (Kim FT by unwa) | +| `roformer_bs_sw` | BS-RoFormer SW 6-stem | 6 | stemd's default (by jarredou) | + +The 4-stem models give vocals, drums, bass and other. The 6-stem ones add guitar and piano. + +--- + +## How the pieces find each other + +The stems folder mirrors the music folder, with one folder per song: + +``` +Music/Kansas/Leftoverture/01 Carry On Wayward Son.flac +Stems/Kansas/Leftoverture/01 Carry On Wayward Son/ + .stemify.json ← the "this one's done" marker + 01 Carry On Wayward Son - vocals.flac + 01 Carry On Wayward Son - drums.flac + 01 Carry On Wayward Son - bass.flac + ... +``` + +- Stems are written as 24-bit FLAC into a hidden `.partial` folder first, and the marker goes in + last, so a separation interrupted by a reboot is simply redone next time. No half-baked songs. +- When a folder holds the same song in several formats, the best one wins (FLAC/WAV, then M4A, + Opus/Ogg, MP3, WMA). +- Plex reports file paths as *its* container sees them, so the apps match them to stems by suffix, + checking durations along the way, and learn the path prefix from the first confident match. A + song called "Intro.flac" on one album will never steal another album's intro. + +--- + +## stemserve API + +| Request | Returns | +|---|---| +| `GET /api/info` | Track count, whether ffmpeg is available, whether Stem Now is set up | +| `GET /api/index` | Every finished song (with ETag, so unchanged indexes cost one tiny 304) | +| `GET /api/peaks?key=K&n=256` | Per-stem loudness envelopes for waveforms, 0 to 1000 | +| `POST /api/prepare?key=K&fmt=opus&br=256` | Starts Opus transcodes in the background | +| `POST /api/stem` with `{"paths": [...]}` | Stem Now: stemd separates these Plex files next | +| `GET /file/K/.flac[?fmt=opus&br=256]` | The stem itself, with HTTP range support for seeking | + +`K` is the song's folder under the stems root, e.g. `Kansas/Leftoverture/01 Carry On Wayward Son`. +Want to run it outside Docker? It's one file: + +```sh +STEMS_DIR=/path/to/Stems CACHE_DIR=~/.cache/stemserve python3 server/stemserve.py +``` + +--- + +## Building and testing + +**Android** needs JDK 21 and the Android SDK (`android/local.properties` points at it): + +```sh +cd android +JAVA_HOME=/path/to/jdk-21 ./gradlew assembleRelease # app/build/outputs/apk/release/ +JAVA_HOME=/path/to/jdk-21 ./gradlew testDebugUnitTest # stem matching, EQ and filter maths, limiter, cache, car tree +``` + +The cache and index tests stream real stems from a stemserve on `localhost:8765` and skip +themselves when there isn't one. Debug builds include a hook for screenshots and back-gesture +testing (`app/src/debug`); release builds don't. + +**Desktop** apps can be checked without opening a window: + +```sh +QT_QPA_PLATFORM=offscreen uv run stemify-player --no-mpris --screenshot /tmp/p.png@5 --quit-after 6 +``` + +--- + +## Repo tour + +``` +android/ the Android and Android Auto app (Kotlin, Jetpack Compose, Media3) + app/src/main/java/com/stemify/mobile/ + plex/ Plex library, search, playlists, artwork, play reporting + stems/ stemserve client, path matching, which albums have stems + cache/ sparse block cache for streaming, and downloads + engine/ decoders, the sample-locked mixer, EQ, limiter, meters + eq/ EQ profiles, device switching, APO config import/export + playback/ queue, audio focus, mix presets, the Media3 session + auto/ Android Auto browse tree, voice search, offline mode + ui/ every screen, hand-built iOS-style components +server/ + stemd.py the GPU separation daemon + stemserve.py the stem file server (standard library only) + *.Dockerfile, docker-compose.yml +stemify/ the desktop separator (PySide6 + QML) and shared separation code + worker/ separation backends (Demucs, RoFormer) in a separate process + player/ Stemify Player, the Excel-shaped one + library_core.py the folder layout rules shared with stemd +scripts/install-desktop.sh +specs.txt the original design doc for the desktop separator +``` + +--- + +## Troubleshooting and FAQ + +**A song says NO STEMS and I'm impatient.** +Hold it and choose **Stem Now**. It'll be next in line. + +**Stem Now says "stemserve needs updating" or "queue folder isn't mounted".** +stemserve is older than the app, or it's missing the `/queue` mount. See +[the server setup](#1-the-server-stemd-and-stemserve). The queue folder needs to be owned by +`99:100` *before* the container first starts, or Docker creates it as root and nobody can write +to it. + +**stemd says it's separating on the CPU.** +The container can't see the GPU. Make sure it's running with `--runtime=nvidia` and the NVIDIA +environment variables shown above. + +**stemd keeps saying "out of GPU memory".** +Something else (Plex transcoding, a game server, your ambitions) is hogging VRAM. stemd shrugs and +retries that song on the next pass. Nothing is marked failed. + +**The Stem Server page says Offline.** +Check the address in Settings → Stem Server, check `curl http://:8765/api/info` from +another machine, and if you set a `TOKEN` on the server, set the same one in the app. + +**The app doesn't show up in Android Auto.** +Sideloaded apps need **Unknown sources** turned on in Auto's developer settings. See +[setting up the car](#android-auto). + +**Some songs are marked failed in `state/failed.json`.** +Usually corrupt files, or "songs" over 40 minutes (those are almost always DJ mixes or radio rips). +Failed tracks retry automatically when the file changes; delete the file to retry everything. + +**Why is the desktop player an Excel spreadsheet?** +We don't talk about it. + +--- + +## Credits + +Standing on the shoulders of some very clever people: + +- [Demucs](https://github.com/adefossez/demucs) by Alexandre Défossez +- BS-RoFormer and Mel-RoFormer models, including the SW 6-stem model by jarredou, Viperx's 1297, + and Kim's vocal model fine-tuned by unwa, via + [python-audio-separator](https://github.com/nomadkaraoke/python-audio-separator) +- [PyTorch](https://pytorch.org/), [PySide6 / Qt](https://www.qt.io/qt-for-python), + [Jetpack Compose](https://developer.android.com/compose) and + [Media3](https://developer.android.com/media/media3) +- [Equalizer APO](https://sourceforge.net/projects/equalizerapo/) and + [AutoEQ](https://github.com/jaakkopasanen/AutoEq), whose formats the EQ speaks +- The Inter, Selawik and Carlito fonts (licences included alongside them) +- [Plex](https://www.plex.tv/), for keeping the library tidy so we didn't have to + +Stemify isn't affiliated with Plex, Google, Microsoft or Mazda. It just likes them. + +--- + +## License + +[GPL-3.0](LICENSE). Take it apart and put it back together however you like, just like the songs. diff --git a/android/README.md b/android/README.md index 30cb5e5..0473d6c 100644 --- a/android/README.md +++ b/android/README.md @@ -1,4 +1,4 @@ -# StemRoller for Android +# Stemify for Android A Plex music player for the OnePlus 15 that plays the stems stemd separates on your unraid server: per-stem faders, mute/solo, karaoke-style presets, a master volume drawn @@ -8,10 +8,10 @@ iOS look in Black, Dark or White (flat colours, no gradients). ## Install -`../StemRoller.apk` is a release build signed with the debug key, ready to sideload: +`../Stemify.apk` is a release build signed with the debug key, ready to sideload: ```sh -adb install -r ../StemRoller.apk +adb install -r ../Stemify.apk ``` ## First run @@ -87,7 +87,7 @@ that's what is shaped for the knob (`auto/`, `playback/PlaybackService.kt`): shows on the artist line ("Black Sabbath · Karaoke"), since a button press gets no other feedback. Songs without stems just get shuffle and repeat, and say "No stems" in the lists. The same buttons appear on the phone's lock-screen controls. -- **Voice:** hold the wheel's talk button: "play Paranoid on StemRoller" (a playlist, +- **Voice:** hold the wheel's talk button: "play Paranoid on Stemify" (a playlist, artist, album or song; artists shuffle). There's no keyboard while driving, so Auto's search button is voice too. - **Offline:** in the car the phone is on mobile data and Plex/stemserve are LAN-only. The @@ -103,7 +103,7 @@ Auto hides sideloaded apps until you allow them: 1. Phone Settings → search "Android Auto" → scroll to the bottom and tap **Version** ten times → OK. 2. ⋮ menu → **Developer settings** → tick **Unknown sources**. -3. Plug into the Miata. StemRoller is in Auto's app launcher (the grid of icons). +3. Plug into the Miata. Stemify is in Auto's app launcher (the grid of icons). Download what you want for the drive while on home Wi-Fi. diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index d9a530a..8929f27 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -8,11 +8,11 @@ plugins { } android { - namespace = "com.stemroller.mobile" + namespace = "com.stemify.mobile" compileSdk = 36 defaultConfig { - applicationId = "com.stemroller.mobile" + applicationId = "com.stemify.mobile" minSdk = 33 targetSdk = 36 versionCode = 1 diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro index 7c714e8..0d5acdc 100644 --- a/android/app/proguard-rules.pro +++ b/android/app/proguard-rules.pro @@ -1,10 +1,10 @@ # kotlinx.serialization keeps its generated serializers via its own consumer rules. -keepattributes *Annotation*, InnerClasses -dontnote kotlinx.serialization.** --keep,includedescriptorclasses class com.stemroller.mobile.**$$serializer { *; } --keepclassmembers class com.stemroller.mobile.** { +-keep,includedescriptorclasses class com.stemify.mobile.**$$serializer { *; } +-keepclassmembers class com.stemify.mobile.** { *** Companion; } --keepclasseswithmembers class com.stemroller.mobile.** { +-keepclasseswithmembers class com.stemify.mobile.** { kotlinx.serialization.KSerializer serializer(...); } diff --git a/android/app/src/debug/java/com/stemroller/mobile/DebugCapture.kt b/android/app/src/debug/java/com/stemify/mobile/DebugCapture.kt similarity index 89% rename from android/app/src/debug/java/com/stemroller/mobile/DebugCapture.kt rename to android/app/src/debug/java/com/stemify/mobile/DebugCapture.kt index 71a09f0..63dbcdc 100644 --- a/android/app/src/debug/java/com/stemroller/mobile/DebugCapture.kt +++ b/android/app/src/debug/java/com/stemify/mobile/DebugCapture.kt @@ -1,4 +1,4 @@ -package com.stemroller.mobile +package com.stemify.mobile import android.app.Activity import android.app.Application @@ -17,10 +17,10 @@ import java.io.File import java.lang.ref.WeakReference /** - * `adb shell am broadcast -a com.stemroller.mobile.CAPTURE -p com.stemroller.mobile` + * `adb shell am broadcast -a com.stemify.mobile.CAPTURE -p com.stemify.mobile` * writes files/capture.png: the current activity drawn in software. * - * `... -a com.stemroller.mobile.BACK --es phase start|progress|commit|cancel --ef p 0.4` + * `... -a com.stemify.mobile.BACK --es phase start|progress|commit|cancel --ef p 0.4` * feeds the predictive back callbacks the way a system swipe would. */ class DebugCapture : ContentProvider() { @@ -45,7 +45,7 @@ class DebugCapture : ContentProvider() { v.draw(Canvas(bmp)) File(a.filesDir, "capture.png").outputStream().use { bmp.compress(Bitmap.CompressFormat.PNG, 100, it) } } - }, IntentFilter("com.stemroller.mobile.CAPTURE"), Context.RECEIVER_EXPORTED) + }, IntentFilter("com.stemify.mobile.CAPTURE"), Context.RECEIVER_EXPORTED) app.registerReceiver(object : BroadcastReceiver() { override fun onReceive(c: Context, i: Intent) { val a = current.get() as? ComponentActivity ?: return @@ -59,7 +59,7 @@ class DebugCapture : ContentProvider() { "cancel" -> d.dispatchOnBackCancelled() } } - }, IntentFilter("com.stemroller.mobile.BACK"), Context.RECEIVER_EXPORTED) + }, IntentFilter("com.stemify.mobile.BACK"), Context.RECEIVER_EXPORTED) return true } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 0a98b57..2a83e12 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -19,7 +19,7 @@ android:label="@string/app_name" android:networkSecurityConfig="@xml/network_security_config" android:supportsRtl="true" - android:theme="@style/Theme.StemRoller" + android:theme="@style/Theme.Stemify" tools:targetApi="36"> diff --git a/android/app/src/main/java/com/stemroller/mobile/App.kt b/android/app/src/main/java/com/stemify/mobile/App.kt similarity index 90% rename from android/app/src/main/java/com/stemroller/mobile/App.kt rename to android/app/src/main/java/com/stemify/mobile/App.kt index a73a093..a291898 100644 --- a/android/app/src/main/java/com/stemroller/mobile/App.kt +++ b/android/app/src/main/java/com/stemify/mobile/App.kt @@ -1,4 +1,4 @@ -package com.stemroller.mobile +package com.stemify.mobile import android.app.Application import android.content.pm.ApplicationInfo @@ -11,16 +11,16 @@ import coil3.memory.MemoryCache import coil3.network.okhttp.OkHttpNetworkFetcherFactory import coil3.request.allowHardware import coil3.request.crossfade -import com.stemroller.mobile.auto.HomeReach -import com.stemroller.mobile.cache.Downloads -import com.stemroller.mobile.cache.MediaCache -import com.stemroller.mobile.core.Connectivity -import com.stemroller.mobile.core.Settings -import com.stemroller.mobile.eq.EqController -import com.stemroller.mobile.playback.PlaybackManager -import com.stemroller.mobile.plex.PlexClient -import com.stemroller.mobile.stems.StemCoverage -import com.stemroller.mobile.stems.StemServer +import com.stemify.mobile.auto.HomeReach +import com.stemify.mobile.cache.Downloads +import com.stemify.mobile.cache.MediaCache +import com.stemify.mobile.core.Connectivity +import com.stemify.mobile.core.Settings +import com.stemify.mobile.eq.EqController +import com.stemify.mobile.playback.PlaybackManager +import com.stemify.mobile.plex.PlexClient +import com.stemify.mobile.stems.StemCoverage +import com.stemify.mobile.stems.StemServer import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob diff --git a/android/app/src/main/java/com/stemroller/mobile/MainActivity.kt b/android/app/src/main/java/com/stemify/mobile/MainActivity.kt similarity index 96% rename from android/app/src/main/java/com/stemroller/mobile/MainActivity.kt rename to android/app/src/main/java/com/stemify/mobile/MainActivity.kt index 8c4f579..6c1378a 100644 --- a/android/app/src/main/java/com/stemroller/mobile/MainActivity.kt +++ b/android/app/src/main/java/com/stemify/mobile/MainActivity.kt @@ -1,4 +1,4 @@ -package com.stemroller.mobile +package com.stemify.mobile import android.Manifest import android.content.ComponentName @@ -19,9 +19,9 @@ import androidx.lifecycle.repeatOnLifecycle import androidx.media3.session.MediaController import androidx.media3.session.SessionToken import com.google.common.util.concurrent.ListenableFuture -import com.stemroller.mobile.core.ThemeMode -import com.stemroller.mobile.playback.PlaybackService -import com.stemroller.mobile.ui.StemApp +import com.stemify.mobile.core.ThemeMode +import com.stemify.mobile.playback.PlaybackService +import com.stemify.mobile.ui.StemApp import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch diff --git a/android/app/src/main/java/com/stemroller/mobile/auto/CarArtProvider.kt b/android/app/src/main/java/com/stemify/mobile/auto/CarArtProvider.kt similarity index 97% rename from android/app/src/main/java/com/stemroller/mobile/auto/CarArtProvider.kt rename to android/app/src/main/java/com/stemify/mobile/auto/CarArtProvider.kt index 1de0d9c..a08551a 100644 --- a/android/app/src/main/java/com/stemroller/mobile/auto/CarArtProvider.kt +++ b/android/app/src/main/java/com/stemify/mobile/auto/CarArtProvider.kt @@ -1,4 +1,4 @@ -package com.stemroller.mobile.auto +package com.stemify.mobile.auto import android.content.ContentProvider import android.content.ContentValues @@ -10,7 +10,7 @@ import android.graphics.Typeface import android.net.Uri import android.os.ParcelFileDescriptor import coil3.SingletonImageLoader -import com.stemroller.mobile.App +import com.stemify.mobile.App import okhttp3.Request import java.io.File import java.io.FileNotFoundException @@ -102,7 +102,7 @@ class CarArtProvider : ContentProvider() { override fun update(uri: Uri, v: ContentValues?, s: String?, a: Array?) = 0 companion object { - const val AUTHORITY = "com.stemroller.mobile.carart" + const val AUTHORITY = "com.stemify.mobile.carart" private const val THUMB = "thumb" private const val LETTER = "letter" private const val LETTER_PX = 256 diff --git a/android/app/src/main/java/com/stemroller/mobile/auto/CarLibrary.kt b/android/app/src/main/java/com/stemify/mobile/auto/CarLibrary.kt similarity index 97% rename from android/app/src/main/java/com/stemroller/mobile/auto/CarLibrary.kt rename to android/app/src/main/java/com/stemify/mobile/auto/CarLibrary.kt index 6221a53..c285623 100644 --- a/android/app/src/main/java/com/stemroller/mobile/auto/CarLibrary.kt +++ b/android/app/src/main/java/com/stemify/mobile/auto/CarLibrary.kt @@ -1,4 +1,4 @@ -package com.stemroller.mobile.auto +package com.stemify.mobile.auto import android.net.Uri import android.os.Bundle @@ -7,11 +7,11 @@ import androidx.media3.common.MediaItem import androidx.media3.common.MediaMetadata import androidx.media3.common.util.UnstableApi import androidx.media3.session.MediaConstants -import com.stemroller.mobile.Graph -import com.stemroller.mobile.plex.Album -import com.stemroller.mobile.plex.Artist -import com.stemroller.mobile.plex.Playlist -import com.stemroller.mobile.plex.Track +import com.stemify.mobile.Graph +import com.stemify.mobile.plex.Album +import com.stemify.mobile.plex.Artist +import com.stemify.mobile.plex.Playlist +import com.stemify.mobile.plex.Track import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @@ -166,7 +166,7 @@ class CarLibrary(private val g: Graph) { } /** - * "Hey Google, play … on StemRoller". Prefers a playlist, then an artist (shuffled), then an + * "Hey Google, play … on Stemify". Prefers a playlist, then an artist (shuffled), then an * album whose name matches; otherwise plays the song hits. Away from home it searches downloads. */ suspend fun resolveSearch(query: String): Resolved? = withContext(Dispatchers.IO) { diff --git a/android/app/src/main/java/com/stemroller/mobile/auto/CarTree.kt b/android/app/src/main/java/com/stemify/mobile/auto/CarTree.kt similarity index 99% rename from android/app/src/main/java/com/stemroller/mobile/auto/CarTree.kt rename to android/app/src/main/java/com/stemify/mobile/auto/CarTree.kt index 7ec30a0..bd63b5b 100644 --- a/android/app/src/main/java/com/stemroller/mobile/auto/CarTree.kt +++ b/android/app/src/main/java/com/stemify/mobile/auto/CarTree.kt @@ -1,4 +1,4 @@ -package com.stemroller.mobile.auto +package com.stemify.mobile.auto import java.text.Normalizer diff --git a/android/app/src/main/java/com/stemroller/mobile/auto/HomeReach.kt b/android/app/src/main/java/com/stemify/mobile/auto/HomeReach.kt similarity index 94% rename from android/app/src/main/java/com/stemroller/mobile/auto/HomeReach.kt rename to android/app/src/main/java/com/stemify/mobile/auto/HomeReach.kt index 8febada..3b7a72d 100644 --- a/android/app/src/main/java/com/stemroller/mobile/auto/HomeReach.kt +++ b/android/app/src/main/java/com/stemify/mobile/auto/HomeReach.kt @@ -1,8 +1,8 @@ -package com.stemroller.mobile.auto +package com.stemify.mobile.auto -import com.stemroller.mobile.core.Connectivity -import com.stemroller.mobile.core.Settings -import com.stemroller.mobile.core.await +import com.stemify.mobile.core.Connectivity +import com.stemify.mobile.core.Settings +import com.stemify.mobile.core.await import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.async import kotlinx.coroutines.coroutineScope diff --git a/android/app/src/main/java/com/stemroller/mobile/cache/Downloads.kt b/android/app/src/main/java/com/stemify/mobile/cache/Downloads.kt similarity index 95% rename from android/app/src/main/java/com/stemroller/mobile/cache/Downloads.kt rename to android/app/src/main/java/com/stemify/mobile/cache/Downloads.kt index 6ce64f2..b76c0e3 100644 --- a/android/app/src/main/java/com/stemroller/mobile/cache/Downloads.kt +++ b/android/app/src/main/java/com/stemify/mobile/cache/Downloads.kt @@ -1,4 +1,4 @@ -package com.stemroller.mobile.cache +package com.stemify.mobile.cache import android.app.Notification import android.app.NotificationChannel @@ -11,16 +11,16 @@ import android.content.pm.ServiceInfo import android.os.IBinder import coil3.SingletonImageLoader import coil3.request.ImageRequest -import com.stemroller.mobile.App -import com.stemroller.mobile.MainActivity -import com.stemroller.mobile.R -import com.stemroller.mobile.core.AppJson -import com.stemroller.mobile.core.Connectivity -import com.stemroller.mobile.core.Settings -import com.stemroller.mobile.playback.PlaybackManager -import com.stemroller.mobile.plex.PlexClient -import com.stemroller.mobile.plex.Track -import com.stemroller.mobile.stems.StemServer +import com.stemify.mobile.App +import com.stemify.mobile.MainActivity +import com.stemify.mobile.R +import com.stemify.mobile.core.AppJson +import com.stemify.mobile.core.Connectivity +import com.stemify.mobile.core.Settings +import com.stemify.mobile.playback.PlaybackManager +import com.stemify.mobile.plex.PlexClient +import com.stemify.mobile.plex.Track +import com.stemify.mobile.stems.StemServer import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job diff --git a/android/app/src/main/java/com/stemroller/mobile/cache/MediaCache.kt b/android/app/src/main/java/com/stemify/mobile/cache/MediaCache.kt similarity index 99% rename from android/app/src/main/java/com/stemroller/mobile/cache/MediaCache.kt rename to android/app/src/main/java/com/stemify/mobile/cache/MediaCache.kt index 98a94f1..00b76c7 100644 --- a/android/app/src/main/java/com/stemroller/mobile/cache/MediaCache.kt +++ b/android/app/src/main/java/com/stemify/mobile/cache/MediaCache.kt @@ -1,6 +1,6 @@ -package com.stemroller.mobile.cache +package com.stemify.mobile.cache -import com.stemroller.mobile.core.AppJson +import com.stemify.mobile.core.AppJson import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow diff --git a/android/app/src/main/java/com/stemroller/mobile/core/Net.kt b/android/app/src/main/java/com/stemify/mobile/core/Net.kt similarity index 98% rename from android/app/src/main/java/com/stemroller/mobile/core/Net.kt rename to android/app/src/main/java/com/stemify/mobile/core/Net.kt index d92e006..86e0afe 100644 --- a/android/app/src/main/java/com/stemroller/mobile/core/Net.kt +++ b/android/app/src/main/java/com/stemify/mobile/core/Net.kt @@ -1,4 +1,4 @@ -package com.stemroller.mobile.core +package com.stemify.mobile.core import android.content.Context import android.net.ConnectivityManager diff --git a/android/app/src/main/java/com/stemroller/mobile/core/Settings.kt b/android/app/src/main/java/com/stemify/mobile/core/Settings.kt similarity index 99% rename from android/app/src/main/java/com/stemroller/mobile/core/Settings.kt rename to android/app/src/main/java/com/stemify/mobile/core/Settings.kt index bf0db38..a5a4b7d 100644 --- a/android/app/src/main/java/com/stemroller/mobile/core/Settings.kt +++ b/android/app/src/main/java/com/stemify/mobile/core/Settings.kt @@ -1,4 +1,4 @@ -package com.stemroller.mobile.core +package com.stemify.mobile.core import android.content.Context import android.content.SharedPreferences diff --git a/android/app/src/main/java/com/stemroller/mobile/engine/Dsp.kt b/android/app/src/main/java/com/stemify/mobile/engine/Dsp.kt similarity index 99% rename from android/app/src/main/java/com/stemroller/mobile/engine/Dsp.kt rename to android/app/src/main/java/com/stemify/mobile/engine/Dsp.kt index 6cb6ea4..acb2e87 100644 --- a/android/app/src/main/java/com/stemroller/mobile/engine/Dsp.kt +++ b/android/app/src/main/java/com/stemify/mobile/engine/Dsp.kt @@ -1,4 +1,4 @@ -package com.stemroller.mobile.engine +package com.stemify.mobile.engine import kotlin.math.PI import kotlin.math.abs diff --git a/android/app/src/main/java/com/stemroller/mobile/engine/StemDecoder.kt b/android/app/src/main/java/com/stemify/mobile/engine/StemDecoder.kt similarity index 99% rename from android/app/src/main/java/com/stemroller/mobile/engine/StemDecoder.kt rename to android/app/src/main/java/com/stemify/mobile/engine/StemDecoder.kt index 04347e4..aaf4000 100644 --- a/android/app/src/main/java/com/stemroller/mobile/engine/StemDecoder.kt +++ b/android/app/src/main/java/com/stemify/mobile/engine/StemDecoder.kt @@ -1,4 +1,4 @@ -package com.stemroller.mobile.engine +package com.stemify.mobile.engine import android.media.AudioFormat import android.media.MediaCodec @@ -6,7 +6,7 @@ import android.media.MediaDataSource import android.media.MediaExtractor import android.media.MediaFormat import android.util.Log -import com.stemroller.mobile.cache.MediaCache +import com.stemify.mobile.cache.MediaCache import java.io.IOException import java.nio.ByteOrder import java.util.concurrent.CountDownLatch diff --git a/android/app/src/main/java/com/stemroller/mobile/engine/StemEngine.kt b/android/app/src/main/java/com/stemify/mobile/engine/StemEngine.kt similarity index 99% rename from android/app/src/main/java/com/stemroller/mobile/engine/StemEngine.kt rename to android/app/src/main/java/com/stemify/mobile/engine/StemEngine.kt index 1aa372c..29a1ed6 100644 --- a/android/app/src/main/java/com/stemroller/mobile/engine/StemEngine.kt +++ b/android/app/src/main/java/com/stemify/mobile/engine/StemEngine.kt @@ -1,4 +1,4 @@ -package com.stemroller.mobile.engine +package com.stemify.mobile.engine import android.media.AudioAttributes import android.media.AudioDeviceInfo diff --git a/android/app/src/main/java/com/stemroller/mobile/eq/ApoConfig.kt b/android/app/src/main/java/com/stemify/mobile/eq/ApoConfig.kt similarity index 95% rename from android/app/src/main/java/com/stemroller/mobile/eq/ApoConfig.kt rename to android/app/src/main/java/com/stemify/mobile/eq/ApoConfig.kt index ac64d22..01868c6 100644 --- a/android/app/src/main/java/com/stemroller/mobile/eq/ApoConfig.kt +++ b/android/app/src/main/java/com/stemify/mobile/eq/ApoConfig.kt @@ -1,9 +1,9 @@ -package com.stemroller.mobile.eq +package com.stemify.mobile.eq -import com.stemroller.mobile.engine.EQ_Q -import com.stemroller.mobile.engine.EqChannel -import com.stemroller.mobile.engine.EqFilter -import com.stemroller.mobile.engine.FilterType +import com.stemify.mobile.engine.EQ_Q +import com.stemify.mobile.engine.EqChannel +import com.stemify.mobile.engine.EqFilter +import com.stemify.mobile.engine.FilterType import java.util.Locale import kotlin.math.pow import kotlin.math.sqrt @@ -107,7 +107,7 @@ object ApoConfig { /** The profile as an Equalizer APO config: preamp, graphic bands as peaks, then the filters. */ fun format(p: EqProfile): String = buildString { fun n(v: Float) = String.format(Locale.ROOT, "%.2f", v).trimEnd('0').trimEnd('.') - appendLine("# ${p.name}, from StemRoller") + appendLine("# ${p.name}, from Stemify") appendLine("Preamp: ${n(p.preamp)} dB") var channel = EqChannel.Both var k = 1 diff --git a/android/app/src/main/java/com/stemroller/mobile/eq/EqController.kt b/android/app/src/main/java/com/stemify/mobile/eq/EqController.kt similarity index 97% rename from android/app/src/main/java/com/stemroller/mobile/eq/EqController.kt rename to android/app/src/main/java/com/stemify/mobile/eq/EqController.kt index bed24fa..ad7612c 100644 --- a/android/app/src/main/java/com/stemroller/mobile/eq/EqController.kt +++ b/android/app/src/main/java/com/stemify/mobile/eq/EqController.kt @@ -1,4 +1,4 @@ -package com.stemroller.mobile.eq +package com.stemify.mobile.eq import android.content.Context import android.media.AudioAttributes @@ -7,12 +7,12 @@ import android.media.AudioDeviceInfo import android.media.AudioManager import android.os.Handler import android.os.Looper -import com.stemroller.mobile.core.AppJson -import com.stemroller.mobile.engine.EQ_BANDS -import com.stemroller.mobile.engine.EQ_MAX_DB -import com.stemroller.mobile.engine.EqFilter -import com.stemroller.mobile.engine.EqMath -import com.stemroller.mobile.engine.EqParams +import com.stemify.mobile.core.AppJson +import com.stemify.mobile.engine.EQ_BANDS +import com.stemify.mobile.engine.EQ_MAX_DB +import com.stemify.mobile.engine.EqFilter +import com.stemify.mobile.engine.EqMath +import com.stemify.mobile.engine.EqParams import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow diff --git a/android/app/src/main/java/com/stemroller/mobile/playback/MixPresets.kt b/android/app/src/main/java/com/stemify/mobile/playback/MixPresets.kt similarity index 98% rename from android/app/src/main/java/com/stemroller/mobile/playback/MixPresets.kt rename to android/app/src/main/java/com/stemify/mobile/playback/MixPresets.kt index 55ac7d5..d12242b 100644 --- a/android/app/src/main/java/com/stemroller/mobile/playback/MixPresets.kt +++ b/android/app/src/main/java/com/stemify/mobile/playback/MixPresets.kt @@ -1,4 +1,4 @@ -package com.stemroller.mobile.playback +package com.stemify.mobile.playback /** A one-tap stem mix. [build] returns null when the track lacks the stems it needs. */ class MixPreset(val label: String, val build: (List) -> Map?) diff --git a/android/app/src/main/java/com/stemroller/mobile/playback/PlaybackManager.kt b/android/app/src/main/java/com/stemify/mobile/playback/PlaybackManager.kt similarity index 96% rename from android/app/src/main/java/com/stemroller/mobile/playback/PlaybackManager.kt rename to android/app/src/main/java/com/stemify/mobile/playback/PlaybackManager.kt index 0b6cab0..6e76e85 100644 --- a/android/app/src/main/java/com/stemroller/mobile/playback/PlaybackManager.kt +++ b/android/app/src/main/java/com/stemify/mobile/playback/PlaybackManager.kt @@ -1,4 +1,4 @@ -package com.stemroller.mobile.playback +package com.stemify.mobile.playback import android.content.BroadcastReceiver import android.content.Context @@ -12,22 +12,22 @@ import android.net.wifi.WifiManager import android.os.Handler import android.os.Looper import android.os.PowerManager -import com.stemroller.mobile.cache.MediaCache -import com.stemroller.mobile.core.AppJson -import com.stemroller.mobile.core.Settings -import com.stemroller.mobile.core.StemQuality -import com.stemroller.mobile.engine.EqParams -import com.stemroller.mobile.engine.ResourceDataSource -import com.stemroller.mobile.engine.StemDecoder -import com.stemroller.mobile.engine.StemEngine -import com.stemroller.mobile.engine.TrackSession -import com.stemroller.mobile.engine.masterTaper -import com.stemroller.mobile.engine.stemTaper -import com.stemroller.mobile.eq.EqController -import com.stemroller.mobile.plex.PlexClient -import com.stemroller.mobile.plex.Track -import com.stemroller.mobile.stems.StemEntry -import com.stemroller.mobile.stems.StemServer +import com.stemify.mobile.cache.MediaCache +import com.stemify.mobile.core.AppJson +import com.stemify.mobile.core.Settings +import com.stemify.mobile.core.StemQuality +import com.stemify.mobile.engine.EqParams +import com.stemify.mobile.engine.ResourceDataSource +import com.stemify.mobile.engine.StemDecoder +import com.stemify.mobile.engine.StemEngine +import com.stemify.mobile.engine.TrackSession +import com.stemify.mobile.engine.masterTaper +import com.stemify.mobile.engine.stemTaper +import com.stemify.mobile.eq.EqController +import com.stemify.mobile.plex.PlexClient +import com.stemify.mobile.plex.Track +import com.stemify.mobile.stems.StemEntry +import com.stemify.mobile.stems.StemServer import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -697,10 +697,10 @@ class PlaybackManager( } private val noisyRegistered = AtomicBoolean(false) private val wakeLock = context.getSystemService(PowerManager::class.java) - .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "StemRoller:playback").apply { setReferenceCounted(false) } + .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Stemify:playback").apply { setReferenceCounted(false) } @Suppress("DEPRECATION") private val wifiLock = context.applicationContext.getSystemService(WifiManager::class.java) - .createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "StemRoller:stream").apply { setReferenceCounted(false) } + .createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "Stemify:stream").apply { setReferenceCounted(false) } private fun holdLocks(on: Boolean) { if (on) { diff --git a/android/app/src/main/java/com/stemroller/mobile/playback/PlaybackService.kt b/android/app/src/main/java/com/stemify/mobile/playback/PlaybackService.kt similarity index 96% rename from android/app/src/main/java/com/stemroller/mobile/playback/PlaybackService.kt rename to android/app/src/main/java/com/stemify/mobile/playback/PlaybackService.kt index 71b7e6a..610d500 100644 --- a/android/app/src/main/java/com/stemroller/mobile/playback/PlaybackService.kt +++ b/android/app/src/main/java/com/stemify/mobile/playback/PlaybackService.kt @@ -1,4 +1,4 @@ -package com.stemroller.mobile.playback +package com.stemify.mobile.playback import android.app.PendingIntent import android.content.Intent @@ -25,15 +25,15 @@ import androidx.media3.session.SessionResult import com.google.common.collect.ImmutableList import com.google.common.util.concurrent.Futures import com.google.common.util.concurrent.ListenableFuture -import com.stemroller.mobile.App -import com.stemroller.mobile.MainActivity -import com.stemroller.mobile.R -import com.stemroller.mobile.auto.CarArtProvider -import com.stemroller.mobile.auto.CarIds -import com.stemroller.mobile.auto.CarLibrary -import com.stemroller.mobile.auto.Resolved -import com.stemroller.mobile.plex.NotSignedInException -import com.stemroller.mobile.plex.Track +import com.stemify.mobile.App +import com.stemify.mobile.MainActivity +import com.stemify.mobile.R +import com.stemify.mobile.auto.CarArtProvider +import com.stemify.mobile.auto.CarIds +import com.stemify.mobile.auto.CarLibrary +import com.stemify.mobile.auto.Resolved +import com.stemify.mobile.plex.NotSignedInException +import com.stemify.mobile.plex.Track import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.flow.drop @@ -399,7 +399,7 @@ class PlaybackService : MediaLibraryService() { // Auto says how many tabs it can show (4 on the Miata's screen). params?.extras?.getInt(MediaConstants.EXTRAS_KEY_ROOT_CHILDREN_LIMIT, 0)?.takeIf { it > 0 }?.let { rootLimit = it } val root = MediaItem.Builder().setMediaId(CarIds.ROOT).setMediaMetadata( - MediaMetadata.Builder().setTitle("StemRoller").setIsBrowsable(true).setIsPlayable(false) + MediaMetadata.Builder().setTitle("Stemify").setIsBrowsable(true).setIsPlayable(false) .setMediaType(MediaMetadata.MEDIA_TYPE_FOLDER_MIXED).build(), ).build() val extras = Bundle().apply { @@ -477,14 +477,14 @@ class PlaybackService : MediaLibraryService() { override fun onPlaybackResumption(mediaSession: MediaSession, controller: MediaSession.ControllerInfo): ListenableFuture { val q = pm.queue.value if (q.isEmpty()) return Futures.immediateFailedFuture(UnsupportedOperationException("no saved queue")) - val items = q.map { MediaItem.Builder().setMediaId("${it.uid}:${it.track.ratingKey}").setUri("stemroller://resume").setTag(ResumeTag).build() } + val items = q.map { MediaItem.Builder().setMediaId("${it.uid}:${it.track.ratingKey}").setUri("stemify://resume").setTag(ResumeTag).build() } return Futures.immediateFuture(MediaSession.MediaItemsWithStartPosition(items, pm.index.value.coerceIn(0, q.lastIndex), pm.positionMs())) } } private fun tagged(t: Track, shuffle: Boolean) = MediaItem.Builder() .setMediaId("track:${t.ratingKey}") - .setUri("stemroller://track/${t.ratingKey}") + .setUri("stemify://track/${t.ratingKey}") .setTag(PlayTag(t, shuffle)) .setMediaMetadata(MediaMetadata.Builder().setTitle(t.title).setArtist(t.artist).setArtworkUri(CarArtProvider.uri(t.thumb)).build()) .build() @@ -506,10 +506,10 @@ class PlaybackService : MediaLibraryService() { companion object { private const val TAG = "StemCar" - private const val ACTION_VOCALS = "stemroller.VOCALS" - private const val ACTION_MIX = "stemroller.MIX" - private const val ACTION_SHUFFLE = "stemroller.SHUFFLE" - private const val ACTION_REPEAT = "stemroller.REPEAT" + private const val ACTION_VOCALS = "stemify.VOCALS" + private const val ACTION_MIX = "stemify.MIX" + private const val ACTION_SHUFFLE = "stemify.SHUFFLE" + private const val ACTION_REPEAT = "stemify.REPEAT" private val ACTIONS = listOf(ACTION_VOCALS, ACTION_MIX, ACTION_SHUFFLE, ACTION_REPEAT) /** Tells Auto to show its (voice) search button. */ diff --git a/android/app/src/main/java/com/stemroller/mobile/plex/PlexClient.kt b/android/app/src/main/java/com/stemify/mobile/plex/PlexClient.kt similarity index 97% rename from android/app/src/main/java/com/stemroller/mobile/plex/PlexClient.kt rename to android/app/src/main/java/com/stemify/mobile/plex/PlexClient.kt index 43b263b..93bea53 100644 --- a/android/app/src/main/java/com/stemroller/mobile/plex/PlexClient.kt +++ b/android/app/src/main/java/com/stemify/mobile/plex/PlexClient.kt @@ -1,12 +1,12 @@ -package com.stemroller.mobile.plex +package com.stemify.mobile.plex import android.net.Uri import android.os.Build -import com.stemroller.mobile.core.AppJson -import com.stemroller.mobile.core.HttpException -import com.stemroller.mobile.core.Settings -import com.stemroller.mobile.core.await -import com.stemroller.mobile.core.awaitBody +import com.stemify.mobile.core.AppJson +import com.stemify.mobile.core.HttpException +import com.stemify.mobile.core.Settings +import com.stemify.mobile.core.await +import com.stemify.mobile.core.awaitBody import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import okhttp3.HttpUrl @@ -247,7 +247,7 @@ class PlexClient(private val http: OkHttpClient, private val settings: Settings) }.getOrDefault(false) companion object { - const val PRODUCT = "StemRoller" + const val PRODUCT = "Stemify" private const val PAGE = 1000 } } diff --git a/android/app/src/main/java/com/stemroller/mobile/plex/PlexModels.kt b/android/app/src/main/java/com/stemify/mobile/plex/PlexModels.kt similarity index 99% rename from android/app/src/main/java/com/stemroller/mobile/plex/PlexModels.kt rename to android/app/src/main/java/com/stemify/mobile/plex/PlexModels.kt index 9c85978..61c29c1 100644 --- a/android/app/src/main/java/com/stemroller/mobile/plex/PlexModels.kt +++ b/android/app/src/main/java/com/stemify/mobile/plex/PlexModels.kt @@ -1,4 +1,4 @@ -package com.stemroller.mobile.plex +package com.stemify.mobile.plex import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable diff --git a/android/app/src/main/java/com/stemroller/mobile/stems/StemCoverage.kt b/android/app/src/main/java/com/stemify/mobile/stems/StemCoverage.kt similarity index 95% rename from android/app/src/main/java/com/stemroller/mobile/stems/StemCoverage.kt rename to android/app/src/main/java/com/stemify/mobile/stems/StemCoverage.kt index 7c30cf2..29bd8e5 100644 --- a/android/app/src/main/java/com/stemroller/mobile/stems/StemCoverage.kt +++ b/android/app/src/main/java/com/stemify/mobile/stems/StemCoverage.kt @@ -1,9 +1,9 @@ -package com.stemroller.mobile.stems +package com.stemify.mobile.stems -import com.stemroller.mobile.core.AppJson -import com.stemroller.mobile.core.Settings -import com.stemroller.mobile.plex.PlexClient -import com.stemroller.mobile.plex.Track +import com.stemify.mobile.core.AppJson +import com.stemify.mobile.core.Settings +import com.stemify.mobile.plex.PlexClient +import com.stemify.mobile.plex.Track import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow diff --git a/android/app/src/main/java/com/stemroller/mobile/stems/StemIndex.kt b/android/app/src/main/java/com/stemify/mobile/stems/StemIndex.kt similarity index 98% rename from android/app/src/main/java/com/stemroller/mobile/stems/StemIndex.kt rename to android/app/src/main/java/com/stemify/mobile/stems/StemIndex.kt index 6c13aea..9bdb3ad 100644 --- a/android/app/src/main/java/com/stemroller/mobile/stems/StemIndex.kt +++ b/android/app/src/main/java/com/stemify/mobile/stems/StemIndex.kt @@ -1,4 +1,4 @@ -package com.stemroller.mobile.stems +package com.stemify.mobile.stems import kotlinx.serialization.Serializable import java.text.Normalizer diff --git a/android/app/src/main/java/com/stemroller/mobile/stems/StemServer.kt b/android/app/src/main/java/com/stemify/mobile/stems/StemServer.kt similarity index 96% rename from android/app/src/main/java/com/stemroller/mobile/stems/StemServer.kt rename to android/app/src/main/java/com/stemify/mobile/stems/StemServer.kt index 62c6569..b186da5 100644 --- a/android/app/src/main/java/com/stemroller/mobile/stems/StemServer.kt +++ b/android/app/src/main/java/com/stemify/mobile/stems/StemServer.kt @@ -1,13 +1,13 @@ -package com.stemroller.mobile.stems +package com.stemify.mobile.stems import android.net.Uri -import com.stemroller.mobile.core.AppJson -import com.stemroller.mobile.core.HttpException -import com.stemroller.mobile.core.Settings -import com.stemroller.mobile.core.StemQuality -import com.stemroller.mobile.core.await -import com.stemroller.mobile.core.awaitBody -import com.stemroller.mobile.plex.Track +import com.stemify.mobile.core.AppJson +import com.stemify.mobile.core.HttpException +import com.stemify.mobile.core.Settings +import com.stemify.mobile.core.StemQuality +import com.stemify.mobile.core.await +import com.stemify.mobile.core.awaitBody +import com.stemify.mobile.plex.Track import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay diff --git a/android/app/src/main/java/com/stemroller/mobile/ui/Root.kt b/android/app/src/main/java/com/stemify/mobile/ui/Root.kt similarity index 85% rename from android/app/src/main/java/com/stemroller/mobile/ui/Root.kt rename to android/app/src/main/java/com/stemify/mobile/ui/Root.kt index f2889ef..2501d57 100644 --- a/android/app/src/main/java/com/stemroller/mobile/ui/Root.kt +++ b/android/app/src/main/java/com/stemify/mobile/ui/Root.kt @@ -1,4 +1,4 @@ -package com.stemroller.mobile.ui +package com.stemify.mobile.ui import androidx.activity.compose.PredictiveBackHandler import androidx.compose.animation.core.AnimationSpec @@ -46,46 +46,46 @@ import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.stemroller.mobile.App -import com.stemroller.mobile.ui.components.Hairline -import com.stemroller.mobile.ui.components.LocalBottomInset -import com.stemroller.mobile.ui.components.LocalOverlays -import com.stemroller.mobile.ui.components.OverlayHost -import com.stemroller.mobile.ui.components.Overlays -import com.stemroller.mobile.ui.components.tappable -import com.stemroller.mobile.ui.nav.NavStack -import com.stemroller.mobile.ui.nav.Route -import com.stemroller.mobile.ui.nav.StackHost -import com.stemroller.mobile.ui.screens.AlbumScreen -import com.stemroller.mobile.ui.screens.EqFilterScreen -import com.stemroller.mobile.ui.screens.EqFiltersScreen -import com.stemroller.mobile.ui.screens.AlbumsScreen -import com.stemroller.mobile.ui.screens.AppActions -import com.stemroller.mobile.ui.screens.AppearanceScreen -import com.stemroller.mobile.ui.screens.ArtistScreen -import com.stemroller.mobile.ui.screens.ArtistsScreen -import com.stemroller.mobile.ui.screens.DownloadsScreen -import com.stemroller.mobile.ui.screens.EqScreen -import com.stemroller.mobile.ui.screens.LibraryHome -import com.stemroller.mobile.ui.screens.LocalApp -import com.stemroller.mobile.ui.screens.MiniPlayer -import com.stemroller.mobile.ui.screens.NowPlayingScreen -import com.stemroller.mobile.ui.screens.PlaylistScreen -import com.stemroller.mobile.ui.screens.PlaylistsScreen -import com.stemroller.mobile.ui.screens.PlexAccountScreen -import com.stemroller.mobile.ui.screens.QualityScreen -import com.stemroller.mobile.ui.screens.SearchScreen -import com.stemroller.mobile.ui.screens.SettingsScreen -import com.stemroller.mobile.ui.screens.SongsScreen -import com.stemroller.mobile.ui.screens.StemServerScreen -import com.stemroller.mobile.ui.screens.StorageScreen -import com.stemroller.mobile.ui.screens.Tab -import com.stemroller.mobile.ui.theme.Icon -import com.stemroller.mobile.ui.theme.IosTheme -import com.stemroller.mobile.ui.theme.Ios -import com.stemroller.mobile.ui.theme.Sym -import com.stemroller.mobile.ui.theme.Txt -import com.stemroller.mobile.ui.theme.Type +import com.stemify.mobile.App +import com.stemify.mobile.ui.components.Hairline +import com.stemify.mobile.ui.components.LocalBottomInset +import com.stemify.mobile.ui.components.LocalOverlays +import com.stemify.mobile.ui.components.OverlayHost +import com.stemify.mobile.ui.components.Overlays +import com.stemify.mobile.ui.components.tappable +import com.stemify.mobile.ui.nav.NavStack +import com.stemify.mobile.ui.nav.Route +import com.stemify.mobile.ui.nav.StackHost +import com.stemify.mobile.ui.screens.AlbumScreen +import com.stemify.mobile.ui.screens.EqFilterScreen +import com.stemify.mobile.ui.screens.EqFiltersScreen +import com.stemify.mobile.ui.screens.AlbumsScreen +import com.stemify.mobile.ui.screens.AppActions +import com.stemify.mobile.ui.screens.AppearanceScreen +import com.stemify.mobile.ui.screens.ArtistScreen +import com.stemify.mobile.ui.screens.ArtistsScreen +import com.stemify.mobile.ui.screens.DownloadsScreen +import com.stemify.mobile.ui.screens.EqScreen +import com.stemify.mobile.ui.screens.LibraryHome +import com.stemify.mobile.ui.screens.LocalApp +import com.stemify.mobile.ui.screens.MiniPlayer +import com.stemify.mobile.ui.screens.NowPlayingScreen +import com.stemify.mobile.ui.screens.PlaylistScreen +import com.stemify.mobile.ui.screens.PlaylistsScreen +import com.stemify.mobile.ui.screens.PlexAccountScreen +import com.stemify.mobile.ui.screens.QualityScreen +import com.stemify.mobile.ui.screens.SearchScreen +import com.stemify.mobile.ui.screens.SettingsScreen +import com.stemify.mobile.ui.screens.SongsScreen +import com.stemify.mobile.ui.screens.StemServerScreen +import com.stemify.mobile.ui.screens.StorageScreen +import com.stemify.mobile.ui.screens.Tab +import com.stemify.mobile.ui.theme.Icon +import com.stemify.mobile.ui.theme.IosTheme +import com.stemify.mobile.ui.theme.Ios +import com.stemify.mobile.ui.theme.Sym +import com.stemify.mobile.ui.theme.Txt +import com.stemify.mobile.ui.theme.Type import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job diff --git a/android/app/src/main/java/com/stemroller/mobile/ui/components/Chrome.kt b/android/app/src/main/java/com/stemify/mobile/ui/components/Chrome.kt similarity index 97% rename from android/app/src/main/java/com/stemroller/mobile/ui/components/Chrome.kt rename to android/app/src/main/java/com/stemify/mobile/ui/components/Chrome.kt index 42a0882..27ccda5 100644 --- a/android/app/src/main/java/com/stemroller/mobile/ui/components/Chrome.kt +++ b/android/app/src/main/java/com/stemify/mobile/ui/components/Chrome.kt @@ -1,4 +1,4 @@ -package com.stemroller.mobile.ui.components +package com.stemify.mobile.ui.components import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.tween @@ -58,14 +58,14 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import coil3.compose.AsyncImage -import com.stemroller.mobile.App -import com.stemroller.mobile.ui.nav.LocalEntry -import com.stemroller.mobile.ui.nav.LocalNav -import com.stemroller.mobile.ui.theme.Icon -import com.stemroller.mobile.ui.theme.Ios -import com.stemroller.mobile.ui.theme.Sym -import com.stemroller.mobile.ui.theme.Txt -import com.stemroller.mobile.ui.theme.Type +import com.stemify.mobile.App +import com.stemify.mobile.ui.nav.LocalEntry +import com.stemify.mobile.ui.nav.LocalNav +import com.stemify.mobile.ui.theme.Icon +import com.stemify.mobile.ui.theme.Ios +import com.stemify.mobile.ui.theme.Sym +import com.stemify.mobile.ui.theme.Txt +import com.stemify.mobile.ui.theme.Type import kotlin.math.ceil /** Height of the tab bar plus mini player, so lists can scroll clear of them. */ @@ -385,7 +385,7 @@ fun ErrorRow(message: String, onRetry: () -> Unit) { if (!App.graph.plex.signedIn) { val nav = LocalNav.current EmptyState(Sym.server, "Not Connected", "Sign in to your Plex server to see your music here.", "Connect") { - nav.push(com.stemroller.mobile.ui.nav.Route.PlexAccount) + nav.push(com.stemify.mobile.ui.nav.Route.PlexAccount) } } else { EmptyState(Sym.warning, "Couldn't Load", message, "Try Again", onRetry) diff --git a/android/app/src/main/java/com/stemroller/mobile/ui/components/Controls.kt b/android/app/src/main/java/com/stemify/mobile/ui/components/Controls.kt similarity index 98% rename from android/app/src/main/java/com/stemroller/mobile/ui/components/Controls.kt rename to android/app/src/main/java/com/stemify/mobile/ui/components/Controls.kt index 939a9b9..77385d3 100644 --- a/android/app/src/main/java/com/stemroller/mobile/ui/components/Controls.kt +++ b/android/app/src/main/java/com/stemify/mobile/ui/components/Controls.kt @@ -1,4 +1,4 @@ -package com.stemroller.mobile.ui.components +package com.stemify.mobile.ui.components import androidx.compose.animation.animateColorAsState import androidx.compose.animation.core.LinearEasing @@ -56,11 +56,11 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.dp -import com.stemroller.mobile.ui.theme.Icon -import com.stemroller.mobile.ui.theme.Ios -import com.stemroller.mobile.ui.theme.Sym -import com.stemroller.mobile.ui.theme.Txt -import com.stemroller.mobile.ui.theme.Type +import com.stemify.mobile.ui.theme.Icon +import com.stemify.mobile.ui.theme.Ios +import com.stemify.mobile.ui.theme.Sym +import com.stemify.mobile.ui.theme.Txt +import com.stemify.mobile.ui.theme.Type import kotlin.math.abs import kotlin.math.roundToInt diff --git a/android/app/src/main/java/com/stemroller/mobile/ui/components/Overlays.kt b/android/app/src/main/java/com/stemify/mobile/ui/components/Overlays.kt similarity index 97% rename from android/app/src/main/java/com/stemroller/mobile/ui/components/Overlays.kt rename to android/app/src/main/java/com/stemify/mobile/ui/components/Overlays.kt index 8cadcbc..b8bb1f8 100644 --- a/android/app/src/main/java/com/stemroller/mobile/ui/components/Overlays.kt +++ b/android/app/src/main/java/com/stemify/mobile/ui/components/Overlays.kt @@ -1,4 +1,4 @@ -package com.stemroller.mobile.ui.components +package com.stemify.mobile.ui.components import androidx.activity.compose.PredictiveBackHandler import androidx.compose.animation.core.Animatable @@ -50,11 +50,11 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp -import com.stemroller.mobile.ui.theme.Icon -import com.stemroller.mobile.ui.theme.Ios -import com.stemroller.mobile.ui.theme.Sym -import com.stemroller.mobile.ui.theme.Txt -import com.stemroller.mobile.ui.theme.Type +import com.stemify.mobile.ui.theme.Icon +import com.stemify.mobile.ui.theme.Ios +import com.stemify.mobile.ui.theme.Sym +import com.stemify.mobile.ui.theme.Txt +import com.stemify.mobile.ui.theme.Type import kotlinx.coroutines.CancellationException import kotlinx.coroutines.delay import kotlinx.coroutines.launch diff --git a/android/app/src/main/java/com/stemroller/mobile/ui/nav/Navigation.kt b/android/app/src/main/java/com/stemify/mobile/ui/nav/Navigation.kt similarity index 98% rename from android/app/src/main/java/com/stemroller/mobile/ui/nav/Navigation.kt rename to android/app/src/main/java/com/stemify/mobile/ui/nav/Navigation.kt index 71c67bf..e8b14e9 100644 --- a/android/app/src/main/java/com/stemroller/mobile/ui/nav/Navigation.kt +++ b/android/app/src/main/java/com/stemify/mobile/ui/nav/Navigation.kt @@ -1,4 +1,4 @@ -package com.stemroller.mobile.ui.nav +package com.stemify.mobile.ui.nav import androidx.activity.BackEventCompat import androidx.activity.compose.PredictiveBackHandler @@ -29,9 +29,9 @@ import androidx.compose.ui.draw.clipToBounds import androidx.compose.ui.draw.drawWithContent import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.graphicsLayer -import com.stemroller.mobile.plex.Album -import com.stemroller.mobile.plex.Artist -import com.stemroller.mobile.plex.Playlist +import com.stemify.mobile.plex.Album +import com.stemify.mobile.plex.Artist +import com.stemify.mobile.plex.Playlist import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers diff --git a/android/app/src/main/java/com/stemroller/mobile/ui/screens/Common.kt b/android/app/src/main/java/com/stemify/mobile/ui/screens/Common.kt similarity index 93% rename from android/app/src/main/java/com/stemroller/mobile/ui/screens/Common.kt rename to android/app/src/main/java/com/stemify/mobile/ui/screens/Common.kt index 881d954..96718ef 100644 --- a/android/app/src/main/java/com/stemroller/mobile/ui/screens/Common.kt +++ b/android/app/src/main/java/com/stemify/mobile/ui/screens/Common.kt @@ -1,4 +1,4 @@ -package com.stemroller.mobile.ui.screens +package com.stemify.mobile.ui.screens import androidx.compose.foundation.background import androidx.compose.foundation.interaction.MutableInteractionSource @@ -27,31 +27,31 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp -import com.stemroller.mobile.App -import com.stemroller.mobile.stems.Coverage -import com.stemroller.mobile.plex.Album -import com.stemroller.mobile.plex.Artist -import com.stemroller.mobile.plex.Playlist -import com.stemroller.mobile.plex.Track -import com.stemroller.mobile.ui.components.Artwork -import com.stemroller.mobile.ui.components.Chevron -import com.stemroller.mobile.ui.components.DownloadedMark -import com.stemroller.mobile.ui.components.Hairline -import com.stemroller.mobile.ui.components.IconButton -import com.stemroller.mobile.ui.components.LocalOverlays -import com.stemroller.mobile.ui.components.MARGIN -import com.stemroller.mobile.ui.components.Overlays -import com.stemroller.mobile.ui.components.PillButton -import com.stemroller.mobile.ui.components.PlayingBars -import com.stemroller.mobile.ui.components.ProgressRing -import com.stemroller.mobile.ui.components.SheetAction -import com.stemroller.mobile.ui.components.Tag -import com.stemroller.mobile.ui.components.tappable -import com.stemroller.mobile.ui.nav.Route -import com.stemroller.mobile.ui.theme.Ios -import com.stemroller.mobile.ui.theme.Sym -import com.stemroller.mobile.ui.theme.Txt -import com.stemroller.mobile.ui.theme.Type +import com.stemify.mobile.App +import com.stemify.mobile.stems.Coverage +import com.stemify.mobile.plex.Album +import com.stemify.mobile.plex.Artist +import com.stemify.mobile.plex.Playlist +import com.stemify.mobile.plex.Track +import com.stemify.mobile.ui.components.Artwork +import com.stemify.mobile.ui.components.Chevron +import com.stemify.mobile.ui.components.DownloadedMark +import com.stemify.mobile.ui.components.Hairline +import com.stemify.mobile.ui.components.IconButton +import com.stemify.mobile.ui.components.LocalOverlays +import com.stemify.mobile.ui.components.MARGIN +import com.stemify.mobile.ui.components.Overlays +import com.stemify.mobile.ui.components.PillButton +import com.stemify.mobile.ui.components.PlayingBars +import com.stemify.mobile.ui.components.ProgressRing +import com.stemify.mobile.ui.components.SheetAction +import com.stemify.mobile.ui.components.Tag +import com.stemify.mobile.ui.components.tappable +import com.stemify.mobile.ui.nav.Route +import com.stemify.mobile.ui.theme.Ios +import com.stemify.mobile.ui.theme.Sym +import com.stemify.mobile.ui.theme.Txt +import com.stemify.mobile.ui.theme.Type import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch diff --git a/android/app/src/main/java/com/stemroller/mobile/ui/screens/EqFilterScreens.kt b/android/app/src/main/java/com/stemify/mobile/ui/screens/EqFilterScreens.kt similarity index 94% rename from android/app/src/main/java/com/stemroller/mobile/ui/screens/EqFilterScreens.kt rename to android/app/src/main/java/com/stemify/mobile/ui/screens/EqFilterScreens.kt index e109d5f..83db8b9 100644 --- a/android/app/src/main/java/com/stemroller/mobile/ui/screens/EqFilterScreens.kt +++ b/android/app/src/main/java/com/stemify/mobile/ui/screens/EqFilterScreens.kt @@ -1,4 +1,4 @@ -package com.stemroller.mobile.ui.screens +package com.stemify.mobile.ui.screens import android.content.ClipData import android.content.ClipboardManager @@ -35,30 +35,30 @@ import androidx.compose.ui.text.rememberTextMeasurer import androidx.compose.ui.text.drawText import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp -import com.stemroller.mobile.App -import com.stemroller.mobile.engine.EQ_BANDS -import com.stemroller.mobile.engine.EQ_SLOPES -import com.stemroller.mobile.engine.EqChannel -import com.stemroller.mobile.engine.EqFilter -import com.stemroller.mobile.engine.EqMath -import com.stemroller.mobile.engine.FilterType -import com.stemroller.mobile.eq.ApoConfig -import com.stemroller.mobile.eq.EqController -import com.stemroller.mobile.ui.components.Cell -import com.stemroller.mobile.ui.components.IconButton -import com.stemroller.mobile.ui.components.IosSlider -import com.stemroller.mobile.ui.components.IosSwitch -import com.stemroller.mobile.ui.components.LocalOverlays -import com.stemroller.mobile.ui.components.Page -import com.stemroller.mobile.ui.components.SegmentedControl -import com.stemroller.mobile.ui.components.SheetAction -import com.stemroller.mobile.ui.components.section -import com.stemroller.mobile.ui.nav.LocalNav -import com.stemroller.mobile.ui.nav.Route -import com.stemroller.mobile.ui.theme.Ios -import com.stemroller.mobile.ui.theme.Sym -import com.stemroller.mobile.ui.theme.Txt -import com.stemroller.mobile.ui.theme.Type +import com.stemify.mobile.App +import com.stemify.mobile.engine.EQ_BANDS +import com.stemify.mobile.engine.EQ_SLOPES +import com.stemify.mobile.engine.EqChannel +import com.stemify.mobile.engine.EqFilter +import com.stemify.mobile.engine.EqMath +import com.stemify.mobile.engine.FilterType +import com.stemify.mobile.eq.ApoConfig +import com.stemify.mobile.eq.EqController +import com.stemify.mobile.ui.components.Cell +import com.stemify.mobile.ui.components.IconButton +import com.stemify.mobile.ui.components.IosSlider +import com.stemify.mobile.ui.components.IosSwitch +import com.stemify.mobile.ui.components.LocalOverlays +import com.stemify.mobile.ui.components.Page +import com.stemify.mobile.ui.components.SegmentedControl +import com.stemify.mobile.ui.components.SheetAction +import com.stemify.mobile.ui.components.section +import com.stemify.mobile.ui.nav.LocalNav +import com.stemify.mobile.ui.nav.Route +import com.stemify.mobile.ui.theme.Ios +import com.stemify.mobile.ui.theme.Sym +import com.stemify.mobile.ui.theme.Txt +import com.stemify.mobile.ui.theme.Type import java.util.Locale import kotlin.math.abs import kotlin.math.ln diff --git a/android/app/src/main/java/com/stemroller/mobile/ui/screens/EqScreen.kt b/android/app/src/main/java/com/stemify/mobile/ui/screens/EqScreen.kt similarity index 86% rename from android/app/src/main/java/com/stemroller/mobile/ui/screens/EqScreen.kt rename to android/app/src/main/java/com/stemify/mobile/ui/screens/EqScreen.kt index c6cf804..e19ab0e 100644 --- a/android/app/src/main/java/com/stemroller/mobile/ui/screens/EqScreen.kt +++ b/android/app/src/main/java/com/stemify/mobile/ui/screens/EqScreen.kt @@ -1,4 +1,4 @@ -package com.stemroller.mobile.ui.screens +package com.stemify.mobile.ui.screens import androidx.compose.foundation.Canvas import androidx.compose.foundation.layout.Arrangement @@ -24,30 +24,30 @@ import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp -import com.stemroller.mobile.App -import com.stemroller.mobile.engine.EQ_BANDS -import com.stemroller.mobile.engine.EQ_LABELS -import com.stemroller.mobile.engine.EQ_MAX_DB -import com.stemroller.mobile.engine.EqMath -import com.stemroller.mobile.eq.DeviceKind -import com.stemroller.mobile.eq.EQ_PRESETS -import com.stemroller.mobile.eq.EqProfile -import com.stemroller.mobile.eq.OutputDevice -import com.stemroller.mobile.ui.components.Cell -import com.stemroller.mobile.ui.components.IosSwitch -import com.stemroller.mobile.ui.components.LocalOverlays -import com.stemroller.mobile.ui.components.Page -import com.stemroller.mobile.ui.components.SegmentedControl -import com.stemroller.mobile.ui.components.SettingsIcon -import com.stemroller.mobile.ui.components.SheetAction -import com.stemroller.mobile.ui.components.VerticalBandSlider -import com.stemroller.mobile.ui.components.section -import com.stemroller.mobile.ui.nav.LocalNav -import com.stemroller.mobile.ui.nav.Route -import com.stemroller.mobile.ui.theme.Ios -import com.stemroller.mobile.ui.theme.Sym -import com.stemroller.mobile.ui.theme.Txt -import com.stemroller.mobile.ui.theme.Type +import com.stemify.mobile.App +import com.stemify.mobile.engine.EQ_BANDS +import com.stemify.mobile.engine.EQ_LABELS +import com.stemify.mobile.engine.EQ_MAX_DB +import com.stemify.mobile.engine.EqMath +import com.stemify.mobile.eq.DeviceKind +import com.stemify.mobile.eq.EQ_PRESETS +import com.stemify.mobile.eq.EqProfile +import com.stemify.mobile.eq.OutputDevice +import com.stemify.mobile.ui.components.Cell +import com.stemify.mobile.ui.components.IosSwitch +import com.stemify.mobile.ui.components.LocalOverlays +import com.stemify.mobile.ui.components.Page +import com.stemify.mobile.ui.components.SegmentedControl +import com.stemify.mobile.ui.components.SettingsIcon +import com.stemify.mobile.ui.components.SheetAction +import com.stemify.mobile.ui.components.VerticalBandSlider +import com.stemify.mobile.ui.components.section +import com.stemify.mobile.ui.nav.LocalNav +import com.stemify.mobile.ui.nav.Route +import com.stemify.mobile.ui.theme.Ios +import com.stemify.mobile.ui.theme.Sym +import com.stemify.mobile.ui.theme.Txt +import com.stemify.mobile.ui.theme.Type import kotlin.math.abs fun deviceIcon(d: OutputDevice): Pair = when (d.kind) { diff --git a/android/app/src/main/java/com/stemroller/mobile/ui/screens/LibraryScreens.kt b/android/app/src/main/java/com/stemify/mobile/ui/screens/LibraryScreens.kt similarity index 94% rename from android/app/src/main/java/com/stemroller/mobile/ui/screens/LibraryScreens.kt rename to android/app/src/main/java/com/stemify/mobile/ui/screens/LibraryScreens.kt index 91fbdb9..a754012 100644 --- a/android/app/src/main/java/com/stemroller/mobile/ui/screens/LibraryScreens.kt +++ b/android/app/src/main/java/com/stemify/mobile/ui/screens/LibraryScreens.kt @@ -1,7 +1,7 @@ -package com.stemroller.mobile.ui.screens +package com.stemify.mobile.ui.screens import androidx.compose.foundation.background -import com.stemroller.mobile.ui.components.ProgressRing +import com.stemify.mobile.ui.components.ProgressRing import androidx.compose.ui.draw.clip import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.layout.size @@ -44,35 +44,35 @@ import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp -import com.stemroller.mobile.App -import com.stemroller.mobile.plex.Album -import com.stemroller.mobile.plex.Artist -import com.stemroller.mobile.plex.Track -import com.stemroller.mobile.cache.DownloadRecord -import com.stemroller.mobile.ui.components.Artwork -import com.stemroller.mobile.ui.components.Chevron -import com.stemroller.mobile.ui.components.EmptyState -import com.stemroller.mobile.ui.components.ErrorRow -import com.stemroller.mobile.ui.components.Hairline -import com.stemroller.mobile.ui.components.IconButton -import com.stemroller.mobile.ui.components.LoadingRow -import com.stemroller.mobile.ui.components.LocalOverlays -import com.stemroller.mobile.ui.components.MARGIN -import com.stemroller.mobile.ui.components.Page -import com.stemroller.mobile.ui.components.SectionTitle -import com.stemroller.mobile.ui.components.SheetAction -import com.stemroller.mobile.ui.components.TextButton -import com.stemroller.mobile.ui.components.tappable -import com.stemroller.mobile.ui.nav.Load -import com.stemroller.mobile.ui.nav.LocalNav -import com.stemroller.mobile.ui.nav.Route -import com.stemroller.mobile.ui.nav.rememberInEntry -import com.stemroller.mobile.ui.nav.rememberLoader -import com.stemroller.mobile.ui.theme.Icon -import com.stemroller.mobile.ui.theme.Ios -import com.stemroller.mobile.ui.theme.Sym -import com.stemroller.mobile.ui.theme.Txt -import com.stemroller.mobile.ui.theme.Type +import com.stemify.mobile.App +import com.stemify.mobile.plex.Album +import com.stemify.mobile.plex.Artist +import com.stemify.mobile.plex.Track +import com.stemify.mobile.cache.DownloadRecord +import com.stemify.mobile.ui.components.Artwork +import com.stemify.mobile.ui.components.Chevron +import com.stemify.mobile.ui.components.EmptyState +import com.stemify.mobile.ui.components.ErrorRow +import com.stemify.mobile.ui.components.Hairline +import com.stemify.mobile.ui.components.IconButton +import com.stemify.mobile.ui.components.LoadingRow +import com.stemify.mobile.ui.components.LocalOverlays +import com.stemify.mobile.ui.components.MARGIN +import com.stemify.mobile.ui.components.Page +import com.stemify.mobile.ui.components.SectionTitle +import com.stemify.mobile.ui.components.SheetAction +import com.stemify.mobile.ui.components.TextButton +import com.stemify.mobile.ui.components.tappable +import com.stemify.mobile.ui.nav.Load +import com.stemify.mobile.ui.nav.LocalNav +import com.stemify.mobile.ui.nav.Route +import com.stemify.mobile.ui.nav.rememberInEntry +import com.stemify.mobile.ui.nav.rememberLoader +import com.stemify.mobile.ui.theme.Icon +import com.stemify.mobile.ui.theme.Ios +import com.stemify.mobile.ui.theme.Sym +import com.stemify.mobile.ui.theme.Txt +import com.stemify.mobile.ui.theme.Type import kotlinx.coroutines.flow.distinctUntilChanged import java.time.LocalDate import java.time.format.DateTimeFormatter diff --git a/android/app/src/main/java/com/stemroller/mobile/ui/screens/NowPlaying.kt b/android/app/src/main/java/com/stemify/mobile/ui/screens/NowPlaying.kt similarity index 94% rename from android/app/src/main/java/com/stemroller/mobile/ui/screens/NowPlaying.kt rename to android/app/src/main/java/com/stemify/mobile/ui/screens/NowPlaying.kt index 58e04e6..9140dc8 100644 --- a/android/app/src/main/java/com/stemroller/mobile/ui/screens/NowPlaying.kt +++ b/android/app/src/main/java/com/stemify/mobile/ui/screens/NowPlaying.kt @@ -1,4 +1,4 @@ -package com.stemroller.mobile.ui.screens +package com.stemify.mobile.ui.screens import android.graphics.Bitmap import androidx.compose.animation.AnimatedContent @@ -66,33 +66,33 @@ import coil3.request.ImageRequest import coil3.request.SuccessResult import coil3.request.allowHardware import coil3.toBitmap -import com.stemroller.mobile.App -import com.stemroller.mobile.engine.MeterHistory -import com.stemroller.mobile.ui.nav.Route -import com.stemroller.mobile.core.StemQuality -import com.stemroller.mobile.playback.MixPresets -import com.stemroller.mobile.playback.QueueItem -import com.stemroller.mobile.playback.RepeatMode -import com.stemroller.mobile.playback.SourceKind -import com.stemroller.mobile.playback.StemSetting -import com.stemroller.mobile.playback.Stems -import com.stemroller.mobile.ui.components.Artwork -import com.stemroller.mobile.ui.components.Chip -import com.stemroller.mobile.ui.components.Hairline -import com.stemroller.mobile.ui.components.IconButton -import com.stemroller.mobile.ui.components.IosSlider -import com.stemroller.mobile.ui.components.LocalOverlays -import com.stemroller.mobile.ui.components.SheetAction -import com.stemroller.mobile.ui.components.Spinner -import com.stemroller.mobile.ui.components.TextButton -import com.stemroller.mobile.ui.components.pressFade -import com.stemroller.mobile.ui.components.tappable -import com.stemroller.mobile.ui.theme.Icon -import com.stemroller.mobile.ui.theme.Ios -import com.stemroller.mobile.ui.theme.LocalPalette -import com.stemroller.mobile.ui.theme.Sym -import com.stemroller.mobile.ui.theme.Txt -import com.stemroller.mobile.ui.theme.Type +import com.stemify.mobile.App +import com.stemify.mobile.engine.MeterHistory +import com.stemify.mobile.ui.nav.Route +import com.stemify.mobile.core.StemQuality +import com.stemify.mobile.playback.MixPresets +import com.stemify.mobile.playback.QueueItem +import com.stemify.mobile.playback.RepeatMode +import com.stemify.mobile.playback.SourceKind +import com.stemify.mobile.playback.StemSetting +import com.stemify.mobile.playback.Stems +import com.stemify.mobile.ui.components.Artwork +import com.stemify.mobile.ui.components.Chip +import com.stemify.mobile.ui.components.Hairline +import com.stemify.mobile.ui.components.IconButton +import com.stemify.mobile.ui.components.IosSlider +import com.stemify.mobile.ui.components.LocalOverlays +import com.stemify.mobile.ui.components.SheetAction +import com.stemify.mobile.ui.components.Spinner +import com.stemify.mobile.ui.components.TextButton +import com.stemify.mobile.ui.components.pressFade +import com.stemify.mobile.ui.components.tappable +import com.stemify.mobile.ui.theme.Icon +import com.stemify.mobile.ui.theme.Ios +import com.stemify.mobile.ui.theme.LocalPalette +import com.stemify.mobile.ui.theme.Sym +import com.stemify.mobile.ui.theme.Txt +import com.stemify.mobile.ui.theme.Type import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import kotlin.math.exp @@ -200,7 +200,7 @@ fun NowPlayingScreen(onClose: () -> Unit, dragModifier: Modifier) { Column(Modifier.weight(1f)) { Txt(track.title, Type.title3) Txt(track.artist, Type.title3, color = c.label2, weight = FontWeight.Normal, modifier = Modifier.tappable { - track.artistKey?.let { k -> app.showInLibrary(com.stemroller.mobile.ui.nav.Route.ArtistPage(com.stemroller.mobile.plex.Artist(k, track.artist, track.artist))) } + track.artistKey?.let { k -> app.showInLibrary(com.stemify.mobile.ui.nav.Route.ArtistPage(com.stemify.mobile.plex.Artist(k, track.artist, track.artist))) } }) } Box(Modifier.size(32.dp).clip(CircleShape).background(c.fill).pressFade { menu.show(track) }, contentAlignment = Alignment.Center) { @@ -356,7 +356,7 @@ private fun StemFader(name: String, s: StemSetting, level: Float, enabled: Boole Box(Modifier.size(10.dp).clip(CircleShape).background(if (s.muted) c.label3 else color)) Spacer(Modifier.width(8.dp)) Txt(Stems.label(name), Type.headline, Modifier.weight(1f), color = if (s.muted) c.label2 else c.label) - val pct = (com.stemroller.mobile.engine.stemTaper(s.level) * 100).toInt() + val pct = (com.stemify.mobile.engine.stemTaper(s.level) * 100).toInt() Txt("$pct%", Type.footnote.copy(fontFeatureSettings = "tnum"), color = c.label2, modifier = Modifier.padding(end = 10.dp)) if (enabled) { ToggleBox("M", s.muted, c.red, onMute) diff --git a/android/app/src/main/java/com/stemroller/mobile/ui/screens/PlaylistScreens.kt b/android/app/src/main/java/com/stemify/mobile/ui/screens/PlaylistScreens.kt similarity index 90% rename from android/app/src/main/java/com/stemroller/mobile/ui/screens/PlaylistScreens.kt rename to android/app/src/main/java/com/stemify/mobile/ui/screens/PlaylistScreens.kt index d2623d8..603e5fc 100644 --- a/android/app/src/main/java/com/stemroller/mobile/ui/screens/PlaylistScreens.kt +++ b/android/app/src/main/java/com/stemify/mobile/ui/screens/PlaylistScreens.kt @@ -1,4 +1,4 @@ -package com.stemroller.mobile.ui.screens +package com.stemify.mobile.ui.screens import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background @@ -35,37 +35,37 @@ import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.zIndex -import com.stemroller.mobile.App -import com.stemroller.mobile.plex.Playlist -import com.stemroller.mobile.plex.SearchResults -import com.stemroller.mobile.plex.Track -import com.stemroller.mobile.ui.components.Artwork -import com.stemroller.mobile.ui.components.Chevron -import com.stemroller.mobile.ui.components.EmptyState -import com.stemroller.mobile.ui.components.ErrorRow -import com.stemroller.mobile.ui.components.Hairline -import com.stemroller.mobile.ui.components.IconButton -import com.stemroller.mobile.ui.components.LoadingRow -import com.stemroller.mobile.ui.components.LocalOverlays -import com.stemroller.mobile.ui.components.MARGIN -import com.stemroller.mobile.ui.components.Page -import com.stemroller.mobile.ui.components.SearchField -import com.stemroller.mobile.ui.components.SectionTitle -import com.stemroller.mobile.ui.components.SheetAction -import com.stemroller.mobile.ui.components.Spinner -import com.stemroller.mobile.ui.components.Tag -import com.stemroller.mobile.ui.components.TextButton -import com.stemroller.mobile.ui.components.tappable -import com.stemroller.mobile.ui.nav.Load -import com.stemroller.mobile.ui.nav.LocalNav -import com.stemroller.mobile.ui.nav.Route -import com.stemroller.mobile.ui.nav.rememberInEntry -import com.stemroller.mobile.ui.nav.rememberLoader -import com.stemroller.mobile.ui.theme.Icon -import com.stemroller.mobile.ui.theme.Ios -import com.stemroller.mobile.ui.theme.Sym -import com.stemroller.mobile.ui.theme.Txt -import com.stemroller.mobile.ui.theme.Type +import com.stemify.mobile.App +import com.stemify.mobile.plex.Playlist +import com.stemify.mobile.plex.SearchResults +import com.stemify.mobile.plex.Track +import com.stemify.mobile.ui.components.Artwork +import com.stemify.mobile.ui.components.Chevron +import com.stemify.mobile.ui.components.EmptyState +import com.stemify.mobile.ui.components.ErrorRow +import com.stemify.mobile.ui.components.Hairline +import com.stemify.mobile.ui.components.IconButton +import com.stemify.mobile.ui.components.LoadingRow +import com.stemify.mobile.ui.components.LocalOverlays +import com.stemify.mobile.ui.components.MARGIN +import com.stemify.mobile.ui.components.Page +import com.stemify.mobile.ui.components.SearchField +import com.stemify.mobile.ui.components.SectionTitle +import com.stemify.mobile.ui.components.SheetAction +import com.stemify.mobile.ui.components.Spinner +import com.stemify.mobile.ui.components.Tag +import com.stemify.mobile.ui.components.TextButton +import com.stemify.mobile.ui.components.tappable +import com.stemify.mobile.ui.nav.Load +import com.stemify.mobile.ui.nav.LocalNav +import com.stemify.mobile.ui.nav.Route +import com.stemify.mobile.ui.nav.rememberInEntry +import com.stemify.mobile.ui.nav.rememberLoader +import com.stemify.mobile.ui.theme.Icon +import com.stemify.mobile.ui.theme.Ios +import com.stemify.mobile.ui.theme.Sym +import com.stemify.mobile.ui.theme.Txt +import com.stemify.mobile.ui.theme.Type import kotlinx.coroutines.delay import kotlinx.coroutines.launch @@ -174,7 +174,7 @@ fun PlaylistScreen(playlist: Playlist) { sim.add(i, t) } } - }.onFailure { overlays.hud("Couldn't save: ${it.message}", com.stemroller.mobile.ui.theme.Sym.warning) } + }.onFailure { overlays.hud("Couldn't save: ${it.message}", com.stemify.mobile.ui.theme.Sym.warning) } tracks.refresh() edit.saving = false edit.editing = false diff --git a/android/app/src/main/java/com/stemroller/mobile/ui/screens/ProgressVolumeBar.kt b/android/app/src/main/java/com/stemify/mobile/ui/screens/ProgressVolumeBar.kt similarity index 95% rename from android/app/src/main/java/com/stemroller/mobile/ui/screens/ProgressVolumeBar.kt rename to android/app/src/main/java/com/stemify/mobile/ui/screens/ProgressVolumeBar.kt index 2e03bd0..afd7aaa 100644 --- a/android/app/src/main/java/com/stemroller/mobile/ui/screens/ProgressVolumeBar.kt +++ b/android/app/src/main/java/com/stemify/mobile/ui/screens/ProgressVolumeBar.kt @@ -1,4 +1,4 @@ -package com.stemroller.mobile.ui.screens +package com.stemify.mobile.ui.screens import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.tween @@ -39,16 +39,16 @@ import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.platform.LocalViewConfiguration import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp -import com.stemroller.mobile.App -import com.stemroller.mobile.engine.masterTaper -import com.stemroller.mobile.engine.stemTaper -import com.stemroller.mobile.playback.StemSetting -import com.stemroller.mobile.playback.Waveform -import com.stemroller.mobile.ui.theme.Icon -import com.stemroller.mobile.ui.theme.Ios -import com.stemroller.mobile.ui.theme.Sym -import com.stemroller.mobile.ui.theme.Txt -import com.stemroller.mobile.ui.theme.Type +import com.stemify.mobile.App +import com.stemify.mobile.engine.masterTaper +import com.stemify.mobile.engine.stemTaper +import com.stemify.mobile.playback.StemSetting +import com.stemify.mobile.playback.Waveform +import com.stemify.mobile.ui.theme.Icon +import com.stemify.mobile.ui.theme.Ios +import com.stemify.mobile.ui.theme.Sym +import com.stemify.mobile.ui.theme.Txt +import com.stemify.mobile.ui.theme.Type import kotlinx.coroutines.delay import kotlin.math.abs import kotlin.math.log10 diff --git a/android/app/src/main/java/com/stemroller/mobile/ui/screens/SettingsScreens.kt b/android/app/src/main/java/com/stemify/mobile/ui/screens/SettingsScreens.kt similarity index 94% rename from android/app/src/main/java/com/stemroller/mobile/ui/screens/SettingsScreens.kt rename to android/app/src/main/java/com/stemify/mobile/ui/screens/SettingsScreens.kt index 692abf6..8302513 100644 --- a/android/app/src/main/java/com/stemroller/mobile/ui/screens/SettingsScreens.kt +++ b/android/app/src/main/java/com/stemify/mobile/ui/screens/SettingsScreens.kt @@ -1,4 +1,4 @@ -package com.stemroller.mobile.ui.screens +package com.stemify.mobile.ui.screens import android.content.Intent import android.net.Uri @@ -40,29 +40,29 @@ import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.stemroller.mobile.App -import com.stemroller.mobile.core.Accent -import com.stemroller.mobile.core.StemQuality -import com.stemroller.mobile.core.ThemeMode -import com.stemroller.mobile.plex.MusicSection -import com.stemroller.mobile.stems.StemServerStatus -import com.stemroller.mobile.ui.components.Cell -import com.stemroller.mobile.ui.components.IosSwitch -import com.stemroller.mobile.ui.components.LocalOverlays -import com.stemroller.mobile.ui.components.Page -import com.stemroller.mobile.ui.components.SegmentedControl -import com.stemroller.mobile.ui.components.SettingsIcon -import com.stemroller.mobile.ui.components.Spinner -import com.stemroller.mobile.ui.components.section -import com.stemroller.mobile.ui.components.tappable -import com.stemroller.mobile.ui.nav.LocalNav -import com.stemroller.mobile.ui.nav.Route -import com.stemroller.mobile.ui.nav.rememberInEntry -import com.stemroller.mobile.ui.theme.Ios -import com.stemroller.mobile.ui.theme.Sym -import com.stemroller.mobile.ui.theme.Txt -import com.stemroller.mobile.ui.theme.Type -import com.stemroller.mobile.ui.theme.palette +import com.stemify.mobile.App +import com.stemify.mobile.core.Accent +import com.stemify.mobile.core.StemQuality +import com.stemify.mobile.core.ThemeMode +import com.stemify.mobile.plex.MusicSection +import com.stemify.mobile.stems.StemServerStatus +import com.stemify.mobile.ui.components.Cell +import com.stemify.mobile.ui.components.IosSwitch +import com.stemify.mobile.ui.components.LocalOverlays +import com.stemify.mobile.ui.components.Page +import com.stemify.mobile.ui.components.SegmentedControl +import com.stemify.mobile.ui.components.SettingsIcon +import com.stemify.mobile.ui.components.Spinner +import com.stemify.mobile.ui.components.section +import com.stemify.mobile.ui.components.tappable +import com.stemify.mobile.ui.nav.LocalNav +import com.stemify.mobile.ui.nav.Route +import com.stemify.mobile.ui.nav.rememberInEntry +import com.stemify.mobile.ui.theme.Ios +import com.stemify.mobile.ui.theme.Sym +import com.stemify.mobile.ui.theme.Txt +import com.stemify.mobile.ui.theme.Type +import com.stemify.mobile.ui.theme.palette import kotlinx.coroutines.delay import kotlinx.coroutines.launch @@ -108,7 +108,7 @@ fun SettingsScreen() { { Cell("Download on Wi-Fi Only", icon = { SettingsIcon(Sym.download, Color(0xFF30B0C7)) }, trailing = { IosSwitch(wifi, { s.downloadsWifiOnly.value = it }) }) }, )) section("display", header = "Display", separatorInset = 60.dp, - footer = "StemRoller 1.1 · stems by stemd on your server" + (mode?.let { " · ${"%.0f".format(it.refreshRate)} Hz" } ?: ""), + footer = "Stemify 1.1 · stems by stemd on your server" + (mode?.let { " · ${"%.0f".format(it.refreshRate)} Hz" } ?: ""), rows = listOf( { Cell("Appearance", icon = { SettingsIcon(Sym.paintbrush, Color(0xFF007AFF)) }, value = theme.label, chevron = true) { nav.push(Route.Appearance) } }, { Cell("High Refresh Rate", icon = { SettingsIcon(Sym.phone, Color(0xFFFF9500)) }, trailing = { IosSwitch(hz, { s.highRefreshRate.value = it }) }) }, diff --git a/android/app/src/main/java/com/stemroller/mobile/ui/theme/Icons.kt b/android/app/src/main/java/com/stemify/mobile/ui/theme/Icons.kt similarity index 99% rename from android/app/src/main/java/com/stemroller/mobile/ui/theme/Icons.kt rename to android/app/src/main/java/com/stemify/mobile/ui/theme/Icons.kt index d3f03e4..9dcd6fe 100644 --- a/android/app/src/main/java/com/stemroller/mobile/ui/theme/Icons.kt +++ b/android/app/src/main/java/com/stemify/mobile/ui/theme/Icons.kt @@ -1,4 +1,4 @@ -package com.stemroller.mobile.ui.theme +package com.stemify.mobile.ui.theme import androidx.compose.foundation.Image import androidx.compose.foundation.layout.size diff --git a/android/app/src/main/java/com/stemroller/mobile/ui/theme/Theme.kt b/android/app/src/main/java/com/stemify/mobile/ui/theme/Theme.kt similarity index 97% rename from android/app/src/main/java/com/stemroller/mobile/ui/theme/Theme.kt rename to android/app/src/main/java/com/stemify/mobile/ui/theme/Theme.kt index 865c24c..57bfbb1 100644 --- a/android/app/src/main/java/com/stemroller/mobile/ui/theme/Theme.kt +++ b/android/app/src/main/java/com/stemify/mobile/ui/theme/Theme.kt @@ -1,4 +1,4 @@ -package com.stemroller.mobile.ui.theme +package com.stemify.mobile.ui.theme import androidx.compose.foundation.text.BasicText import androidx.compose.runtime.Composable @@ -19,9 +19,9 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.TextUnit import androidx.compose.ui.unit.sp -import com.stemroller.mobile.R -import com.stemroller.mobile.core.Accent -import com.stemroller.mobile.core.ThemeMode +import com.stemify.mobile.R +import com.stemify.mobile.core.Accent +import com.stemify.mobile.core.ThemeMode import kotlin.math.exp /** iOS semantic colours, flattened to solid values for each scheme. */ diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index 78b8845..1fbd790 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -1,4 +1,4 @@ - StemRoller + Stemify diff --git a/android/app/src/main/res/values/themes.xml b/android/app/src/main/res/values/themes.xml index f986874..875a4b9 100644 --- a/android/app/src/main/res/values/themes.xml +++ b/android/app/src/main/res/values/themes.xml @@ -1,6 +1,6 @@ -