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 <noreply@anthropic.com>
This commit is contained in:
ClericalErrorandClaude Opus 5.5 committed 2026-10-14 21:24:56 -07:00
1 parent 1845f03c41
commit 45bc0eefe0
159 files changed
+1136 -542

No files matched your search

+2 -2
View File
@@ -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
+3 -3
View File
@@ -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(...);
}
@@ -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
}
+2 -2
View File
@@ -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">
<activity
@@ -51,7 +51,7 @@
<!-- Album art for Android Auto, which only loads content:// artwork. Read-only. -->
<provider
android:name=".auto.CarArtProvider"
android:authorities="com.stemroller.mobile.carart"
android:authorities="com.stemify.mobile.carart"
android:exported="true"
tools:ignore="ExportedContentProvider" />
@@ -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
@@ -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
@@ -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<out String>?) = 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
@@ -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) {
@@ -1,4 +1,4 @@
package com.stemroller.mobile.auto
package com.stemify.mobile.auto
import java.text.Normalizer
@@ -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
@@ -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
@@ -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
@@ -1,4 +1,4 @@
package com.stemroller.mobile.core
package com.stemify.mobile.core
import android.content.Context
import android.net.ConnectivityManager
@@ -1,4 +1,4 @@
package com.stemroller.mobile.core
package com.stemify.mobile.core
import android.content.Context
import android.content.SharedPreferences
@@ -1,4 +1,4 @@
package com.stemroller.mobile.engine
package com.stemify.mobile.engine
import kotlin.math.PI
import kotlin.math.abs
@@ -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
@@ -1,4 +1,4 @@
package com.stemroller.mobile.engine
package com.stemify.mobile.engine
import android.media.AudioAttributes
import android.media.AudioDeviceInfo
@@ -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
@@ -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
@@ -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<String>) -> Map<String, StemSetting>?)
@@ -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) {
@@ -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<MediaSession.MediaItemsWithStartPosition> {
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. */
@@ -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
}
}
@@ -1,4 +1,4 @@
package com.stemroller.mobile.plex
package com.stemify.mobile.plex
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@@ -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
@@ -1,4 +1,4 @@
package com.stemroller.mobile.stems
package com.stemify.mobile.stems
import kotlinx.serialization.Serializable
import java.text.Normalizer
@@ -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
@@ -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
@@ -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)
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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<ImageVector, androidx.compose.ui.graphics.Color> = when (d.kind) {
@@ -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
@@ -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)
@@ -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
@@ -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
@@ -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 }) }) },
@@ -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
@@ -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. */
+1 -1
View File
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">StemRoller</string>
<string name="app_name">Stemify</string>
</resources>
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.StemRoller" parent="android:Theme.Material.NoActionBar">
<style name="Theme.Stemify" parent="android:Theme.Material.NoActionBar">
<item name="android:windowBackground">@android:color/black</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
@@ -1,9 +1,9 @@
package com.stemroller.mobile
package com.stemify.mobile
import com.stemroller.mobile.auto.CarIds
import com.stemroller.mobile.auto.CarTree
import com.stemroller.mobile.playback.MixPresets
import com.stemroller.mobile.playback.StemSetting
import com.stemify.mobile.auto.CarIds
import com.stemify.mobile.auto.CarTree
import com.stemify.mobile.playback.MixPresets
import com.stemify.mobile.playback.StemSetting
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNull
@@ -1,18 +1,18 @@
package com.stemroller.mobile
package com.stemify.mobile
import com.stemroller.mobile.engine.EQ_BANDS
import com.stemroller.mobile.engine.EqChannel
import com.stemroller.mobile.engine.EqFilter
import com.stemroller.mobile.engine.FilterType
import com.stemroller.mobile.eq.ApoConfig
import com.stemroller.mobile.eq.EqProfile
import com.stemroller.mobile.engine.EqMath
import com.stemroller.mobile.engine.EqParams
import com.stemroller.mobile.engine.Equalizer
import com.stemroller.mobile.engine.FloatRing
import com.stemroller.mobile.engine.Limiter
import com.stemroller.mobile.engine.stemTaper
import com.stemroller.mobile.engine.stemUntaper
import com.stemify.mobile.engine.EQ_BANDS
import com.stemify.mobile.engine.EqChannel
import com.stemify.mobile.engine.EqFilter
import com.stemify.mobile.engine.FilterType
import com.stemify.mobile.eq.ApoConfig
import com.stemify.mobile.eq.EqProfile
import com.stemify.mobile.engine.EqMath
import com.stemify.mobile.engine.EqParams
import com.stemify.mobile.engine.Equalizer
import com.stemify.mobile.engine.FloatRing
import com.stemify.mobile.engine.Limiter
import com.stemify.mobile.engine.stemTaper
import com.stemify.mobile.engine.stemUntaper
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test
@@ -143,7 +143,7 @@ class DspTest {
@Test fun oldEqSettingsStillLoad() {
val old = """{"enabled":true,"automatic":false,"manualId":"abc","profiles":[{"id":"abc","name":"XM5",
"gains":[1,2,3,0,0,0,0,0,-1,-2],"devices":[{"type":8,"name":"WH-1000XM5"}]}]}"""
val s = com.stemroller.mobile.core.AppJson.decodeFromString(com.stemroller.mobile.eq.EqState.serializer(), old)
val s = com.stemify.mobile.core.AppJson.decodeFromString(com.stemify.mobile.eq.EqState.serializer(), old)
val p = s.profiles.single()
assertEquals("XM5", p.name)
assertEquals(0, p.filters.size)
@@ -1,6 +1,6 @@
package com.stemroller.mobile
package com.stemify.mobile
import com.stemroller.mobile.cache.MediaCache
import com.stemify.mobile.cache.MediaCache
import okhttp3.OkHttpClient
import org.junit.After
import org.junit.Assert.assertArrayEquals
@@ -1,10 +1,10 @@
package com.stemroller.mobile
package com.stemify.mobile
import com.stemroller.mobile.core.AppJson
import com.stemroller.mobile.stems.StemEntry
import com.stemroller.mobile.stems.StemFile
import com.stemroller.mobile.stems.StemIndex
import com.stemroller.mobile.stems.StemIndexFile
import com.stemify.mobile.core.AppJson
import com.stemify.mobile.stems.StemEntry
import com.stemify.mobile.stems.StemFile
import com.stemify.mobile.stems.StemIndex
import com.stemify.mobile.stems.StemIndexFile
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Assume.assumeTrue