#Mobile app

1 messages · Page 3 of 1

abstract trench
#

Yeah I will think on how to make it right. Probably cast is as string, and then map to enum with fallback to NULL.

abstract trench
#

Did that.

scarlet valley
#

2026.03.23.1721 working fine with 2.8.0.b22

mellow widget
#

Ah ok! I hadn't found this. I'm away from home at the moment, but will check this out when I get back.

abstract trench
#

Sorry guys, how do I play Genre? It says no playable items....

abstract trench
#

Also @fast grove do we have Firebase console, so I could setup Crashlytics?

#

Or do we prefer any other logging solution?

abstract trench
fast grove
abstract trench
abstract trench
scarlet valley
#

2026.03.27.1440 working flawlessly with 2.8.0rc3

desert needle
#

I'll test it when I get home this evening

fast grove
#

We should maybe start with setting up Testflight. We have a Apple Development agreement etc. for the OHF. All we need to do is figure out how to set it up.

fast grove
#

Lijkt veel op wat jij laatst had gedaan

desert needle
desert needle
#

The build works well for me after the song and dance number of setting up dev mode on my iPhone etc.
No point trying to build a signed app without testflight so that is the next step, also saw oauth is not supported on ios
This we also need to fix before testflight I reckon.
I am also no expert here, would just like to help to push this forward.

shrewd crown
#

For the TestFlight build

#

I highly recommend using one version number like 1.2.0

#

But for fixing things distinguish by the build number. If one version like 1.2.0 is approved the next builds are automatically approved so no further reviews by the App Store Team…

shrewd crown
desert needle
#

We should decide then if we want to always ensure that the android and iOS builds have the same version number or we make the decision that we keep the versioning separate across OSes

abstract trench
#

On unrelated topic - I see that although my app player isn't in UI, it's still visible in "transfer queue" list...
Also my Sendspin respeaker players show "universal_player" as type - is it okay?

shrewd crown
desert needle
abstract trench
desert needle
abstract trench
#

There are virtually no advantages to carry cognitive load of handling same version between platforms 🙂

shrewd crown
shrewd crown
abstract trench
#

Issues are still reported on one on another platform. They're bound to that platform, then after investigation - if the trouble is common - both build numbers are added to ticket.

#

And the fix to the issue should contain iOS and Android fix versions. It's easier to tackle, just build both, and record corresponding version.

#

Because each platform can release on their own pace, so single fix (even in common code) can be delayed for iOS, while already released on Android, because of some induced platform-specific changes.

shrewd crown
abstract trench
shrewd crown
abstract trench
# shrewd crown Not if you asked Claude 😉

Nope. I do use Claude, but it's not simple refactoring - it's user-facing functionality, that relies on 3rdparty API (Github), so it can give troubles even if we don't break anything. In these cases I prefer KISS principle instead of relying on AI knowing my codebase better than me.

shrewd crown
#

For testing and bug fixing would be great to have more information

abstract trench
mellow widget
mellow widget
#

@abstract trench what are you thinking for the Github APKs going forward? Is there an advantage to them being debuggable? I was just playing around at adding a command line arg for building selfSignedRelease in release mode, but we could also just change it so that isDebuggable is false always for it.

#

It does feel like once proper release mode APKs are getting distributed it might feel a bit lax to just be using a non "official" key for signing. I'm not sure how Home Assistant's Android signing is usually handled and who manages keys.

abstract trench
mellow widget
#

But for now, do you want to keep the APKs on Github debuggable? I just meant that it would be good to have a simple way to build a non-debuggable ("release mode" for Compose) APK for checking performance during development, but that could just be selfSignedRelease if there's no reason to keep that build variant as debuggable.

#

If we do want to keep the Github APKs debuggable we can just add a new build variant or a command line property to get release mode APKs

abstract trench
mellow widget
#

Yup makes sense

abstract trench
#

I don't want to make another keystore... 🙂 It will get messy

mellow widget
#

I can add a build variant that uses the same signing config. That's probably simplest.

#

And yeah. No more keystores haha.

mellow widget
#

@abstract trench I've noticed there's a "pop-in" for the gradient color when switching from the compact to expanded player. It looks like some recomposition happens that causes the animation to run again. I was going to refactor the player pager a bit anyway to try and make the different modes a bit more distinct in the code (it's hard to follow at the moment), so I'll look at that as well. Just a heads up that I'm playing around in that area (HomeScreen and PlayerPager mainly).

abstract trench
abstract trench
#

I see problem with podcasts right now. When I try to seek, every time the progress returned to me starts from 0. Stream seems to be correct, but progress bar always jumps to 0 and starts from there, wherever I tap on it. Found it on mobile app, confirmed on web. Music seems to be working good.

#

Same problem with audiobooks.

thorny trail
#

I believe that is a known issue but I can't find the thread on GH at the moment

abstract trench
#

@mellow widget I noticed today that whole home screen gets recomposed twice a second. Mitigated it.

mellow widget
#

@abstract trench ah great! Yeah I'd seen that we were getting regular recompositions in the player, but I'd thought that was just to playback state updating and hadn't investigated up the hierarchy. It looks like it was something to do with the view model "actions" from your PR? I haven't really dug into those at all.

#

I like Compose a lot, but the "magic" that its compiler adds to make recompositions happen makes it very, very easy to have things redrawing on a tick by accident.

#

This app is going to be especially sensitive to that given all the "live" state like playback, speakers getting updated etc.

abstract trench
abstract trench
#

Oh damn. I was today years old when I discovered that MA doesn't return track duration for non-library tracks. Or is it bug?

abstract trench
#

There's 0.0

mortal wadi
#

Should be returned AFAIK. What music provider is that track from.?

abstract trench
#

I feel like Tidal is more and more doomed.

fast grove
#

I ran into this myself - sometimes we have track durations of 00:00

#

I think this is some core bug somewhere

#

Did the tracks come from a MA playlist in this case ?

abstract trench
fast grove
wet hound
#

Been a while since I’ve been over here, how’s iOS development coming along?

abstract trench
mortal wadi
wet hound
abstract trench
wet hound
abstract trench
unkempt socket
abstract trench
abstract trench
#

Hey guys @mortal wadi @fast grove will we be able to use Localise for mobile app?

mortal wadi
abstract trench
#

Checking now

abstract trench
brave sentinel
opaque cradle
#

Audiobooks and local MA playlist image metadata isn't loading

#

I will be able to jump back on this next month

opaque cradle
#

I will report when they happen again

shrewd crown
opaque cradle
#

play/pause is also buggy from lock screen

abstract trench
mellow widget
#

Is there an easy way to run ./gradlew detektAll and have it fail only if it can't fix things? From skimming docs it seems like you can do this at a config level, but obviously we'd still want that task to fail on CI if any problems are detected. I'd have thought there would be an arg or somthing.

#

I've generally used ktlint without autofixing in the past, so haven't really played around with detekt before

#

Right now it always has to be run twice if there are problems getting autofixed to get a green run

abstract trench
#

With Detekt, I run it, then after failure I click "run with stacktrace" and it succeeds.

abstract trench
#

Does anyone but me experience progress bar seek bug? I try to seek - the track is switching to required time, but visual progress goes back to 0 and starts from there. It was like this for podcasts/audiobooks a while ago - Marcel fixed it reportedly - now I see the same with regular tracks.

mellow widget
mellow widget
mellow widget
#

@brave sentinel how up to date is https://github.com/music-assistant/mobile-app/blob/dev/ios_build_instructions.md? I'd like to be setup for at least running iOS locally. I noticed that the instructions expect the WebRTC framework to be in the repo (which isn't) so thought I'd pause just in case I end up going down a rabbit hole for nothing here.

GitHub

The (official) Music Assistant Mobile app is a cross-platform client application designed for Android, iOS, and Java runtime environments. Developed using Kotlin Multiplatform (KMP) and Compose Mul...

brave sentinel
opaque cradle
#

Hi @abstract trench @mortal wadi , I don't see a channel for Core questions, but since I am developing for a mobile app, here it goes:

API question on cache-invalidation strategy, want to confirm I'm reading this right before I commit to an approach.

Designing the library cache for users with thousands of tracks where re-fetching everything on cold start is painful. Read through dev + models and here's what I think the surface looks like:

  • music_sync_completed fires when sync tasks drain, but the event carries no payload (no counts, no per-provider breakdown)
  • No modified_since / updated_after filter on <type>/library_items
  • DB has timestamp_modified with an auto-update trigger, but MediaItem only exposes date_added over the wire
  • media_item_added / media_item_updated / media_item_deleted emit the full item as payload
  • No library/changes_since / version-cursor endpoint

Is the intended pattern: bulk-load once, then keep the cache live off the per-item media_item_* events, with a full invalidate-and-reload as the fallback for reconnects / missed-event windows? Or is there a delta facility I missed?

If that's the pattern, three small asks that would make it robust against dropped events — happy to PR any of them if the direction's welcome:

  1. expose timestamp_modified on MediaItem (column + trigger already exist, just hydrate the field)
  2. add a modified_since filter to <type>/library_items — pairs with #1 for bounded reconciliation
  3. include {added, updated, removed} counts per provider on the music_sync_completed payload, so clients can skip reconciliation when a sync run was a no-op

Want to check intent before writing anything that conflicts with something already on the roadmap.

abstract trench
mortal wadi
abstract trench
#

Damn, we need somehow shorten down the iOS build time. It takes ages. 🙂

lean jewel
#

Does the default picture from missing album art in the app come from the server or it is local to the app?

lean jewel
#

Is it similar to like SVG drawing?

#

Seems like it. Wonder if there is a converter to convert that

lean jewel
#

Are these genre icons sent from music assistant?

abstract trench
lean jewel
#

are you using sendspin + ma api calls for data or just sendspin?

abstract trench
lean jewel
abstract trench
lean jewel
#

Isn't that the premise of sendspin, a global cache synced between players?

abstract trench
lean jewel
#

what is the legal limit for a cache?

#

I feel like you would be less on the hook connecting to direct linked radio stations than streaming stuff yourself to multiple devices

#

As the fault would lay on the station for not obtaining the appropriate licenses

#

Now your friend comes over connects to your sendspin and walks outside of your property area that could be illegal in some places 😄 That responsibility lies on you to tackle them before they cross the boundary.

lean jewel
#

Seems when caching is concerned it only seems illegal if you turn it into a permanent copy to play multiple times, says you can make a single copy of a legal broadcast to listen to at a later time but you can't keep it no longer than reasonably necessary to listen to it at a more convenient time.

Says the cache can be as long as you need to prevent network dropouts. As long as the cache is an automated, essential part of the streaming process and lasts only for the duration of that playback, it does not infringe copyright. Whether your device buffers 5 seconds (standard radio stream) or 30 minutes of audio to prevent network dropouts, it remains entirely legal because the system deletes the older cached blocks as new ones arrive.

Hopefully other places have sane rules like that as well.

abstract trench
#

@fast grove @grand jewel guys what's current policy about cache? I suppose we're actually are pretty far with mobile app now, it's pretty useable - apart from hiccups because of cache. Well, WebRTC too, bit I have thoughts about it.

lean jewel
#

through the sendspin protocol

#

I feel like that would be a lot of data to spam to multiple players. Almost killed the lvgl player sending the progress bar duration time updates 😄

#

Let alone a wild amount audio spectrum points

abstract trench
#

No, I don't plan it. Go3ss WLED is doing it.
I would debounce it.

fast grove
# opaque cradle Hi <@299947094674767872> <@639082567898890248> , I don't see a channel for Core ...

Just create a new thread here in devs support is easiest. We can potentially expose timestamp_modified for library/db items but that is at item level. I think you more need something like like a etag or timestamp of last modification for the library itself. But I also wonder why you need to cache in the first place ? Because the whole library is fully paged and in general something like 100 items of a list would return in less than 25ms.

abstract trench
#

It's strange that I send buffer_capacity = 10_000_000 (it's microseconds, right?), but getting back 30 seconds buffer.

mellow widget
#

@abstract trench just been familiarizing myself with the foreground service setup after reading https://github.com/music-assistant/mobile-app/issues/379#issuecomment-4446562260. Is there a reason not to just start a foreground service (and notification) on app launch? From skimming the code, I think we'd need to switch the wifi lock on and off while the service is running to not drain extra battery when there's no playback, but that's doable.

#

Just interested if it's a "by design" thing or a "not done it yet" thing!

abstract trench
# mellow widget <@299947094674767872> just been familiarizing myself with the foreground service...

I don't want to hold service all the time. State management (e.g. when disconnected, unauthorized, reconnecting etc.) and notification management, when, say, there's no players with content to play, or there's no local player etc. - it will be awful .. Not to mention battery drain - system won't be able to kill the app, while foreground service is active, no matter if WiFi lock is acquired or not.

mellow widget
#

Gotcha! So right now, from looking at the service code, it runs while anything is playing and then stops when everything is stopped (or I'm guessing when the app doesn't know anything is running because of a disconnect).

#

That all makes sense, as I said I was just interested in if that was by design. "It keeps things simple" is a good answer!

abstract trench
#

Yeah, it's still a bit complicated with Android Auto and new Google Assistant integration - but I try to hold it on KISS grounds. 🙂

abstract trench
#

@mellow widget heads up - I prepare huge refactoring. Too much things are done "for MVP" in data layer, need proper factories, client data objects layer, and many other things to change for better DI and less hassle on UI layer.

mellow widget
abstract trench
#

Opening PR

mellow widget
#

Is AppMediaItem going to be sealed with data subclasses? That's be a wee gift.

mellow widget
#

Hero. It's an annoying refactor.

abstract trench
#

like "non-nullable text is null" on composing.

#

We don't use !! anywhere, so it shouldn't happen.

#

Stacktrace is useless.

mellow widget
#

Yeah every time I've tried it I've run into something like that. It's a surprisingly subtle shift. It's the sort of thing that you'd hope agent could help with, but it seems like a class of problem that tech has trouble with.

#

Probably needs to be done a single property at a time 😒

abstract trench
#

BTW I'm fixing scroll state too, don't bother 🙂

#

Unless you're actually on it already 🙂

mellow widget
#

I've got a solution but wasn't finished yet

abstract trench
#

I bet your solution will be more elegant. 🙂

mellow widget
#

haha nah I'm sure you had it

#

We just need to use rememberSaveableStateHolderNavEntryDecorator to decorate back stack entries, but it also looks like that doesn't fix all screens.

abstract trench
#

Well, see... I was just saving lazy states in VMs

mellow widget
#

Nah we shouldn't need that

abstract trench
#

Yes, decorator should do it automagically

mellow widget
#

I think some screens don't work with it because the scroll state "owner" ends up being a Column that's wrapping a lazy grid (ItemDetailsScreen for example). Hopefully just need to move everything into the lazy component as item bits.

#

Honestly Navigation 3 + Compose is kind of strange. So much boilerplate to achieve all the things that just work with a multi Activity or Fragment app. They really need some higher level components wrapping all this (which is basically what I've ended up building).

#

It'll be much nicer for any times you have to do non-standard navigation I suppose!

mellow widget
#

Ooof we also have a wee problem because we have a single view model with a single "state" shared between every item details screen. As well as causing problems for scroll state (every screen is being reloaded when navigating between them), it also looks like there's a bug where sometimes details for a previous screen get loaded into the current one (race condition with the requests probably).

#

I can rework that! I feel like the simplest thing is to probably just have loadItem return the value for that request (as a state or stateflow) and then have that as saveable state for the screen. You could do a ViewModel per screen, but that feels super heavy and you could also keep keyed state in the view model, but you run into cache invalidation problems there.

mellow widget
#

Ah damn actually that won't work really as the data isn't immutable (sorting, favourites etc). We could do a ViewModel per entry in the back stack or change the way the current shared ViewModel works to support having multiple items loaded (which would be great in the long term for things like preloading of albums for artist etc.). I'll pause and wait for you to finish that refactor as I'll want to explore options on top of your changes.

#

I will investigate if I can use automagic navigation 3 ViewModel scoping in the mean time, but I'm not sure it works in KMP

abstract trench
mellow widget
#

The current version I have is broken due to some of the nav libraries dropping support for the iosX64 target which is now removed from Compose Multiplatform. I'm going to wait for you to merge your stuff and then come back to fix it - I'd like to do a little rework on how we manage ViewModels and screens to try and make it clearer how everything is scoped, but I'd rather do that on top instead of dealing with a nasty rebase.

abstract trench
#

Okay.

abstract trench
#

I just found that Metadata on items are returning a heck of images. Like dozens, sometimes more than 100 image data objects. Do we need that much?...

royal smelt
mellow widget
#

@abstract trench quick question on ActionsViewModel there's a series of data classes like PlaylistActions that get passed down to Composables. My assumption is that this is to decouple the Composables from the ViewModel itself, but if that's the reason could it just be a series of interfaces that the ViewModel implements? If there's no reason not to do that, I can follow-up with that change after https://github.com/music-assistant/mobile-app/pull/404.

abstract trench
abstract trench
#

Would be great to add Crashlytics before public beta 🙂

#

Also Lokalize (which we have set up in the app, need to plug in the project, need OHF help).

mellow widget
mellow widget
#

Cool! Yeah, would be great to have.

fast grove
abstract trench
fast grove
abstract trench
river sonnet
#

Hey, just a heads-up: PlayerQueue now has an is_dynamic boolean field. The server sets it whenever radio_source changes and also correctly restores it after a restart. So on the client side you can just use queue.is_dynamic directly — no need to inspect radio_source yourself anymore. This can be used e.g. to disable the Shuffle and Repeat buttons when a dynamic playlist is active. Everything is already merged into dev.

abstract trench
#

Guys, is there a way to setup both local and external HA address in MA?
Asking because connection to HA is better via local IP, but when we try to login via HA (both on proxied connection or WebRTC while remote) - local IP is useless.

royal smelt
abstract trench
#

Guys, are there dynamic colors for any particular media item? Or only those in the queue?

abstract trench
fast grove
#

But we could add an api command to retrieve it for a media item or media image.
That must ofc be used with care. Not wise to call it on a large listing of media items

abstract trench
#

Yeah that was my next question... But actually we will be doing it on device - I'm examining current logic on server to make it similar.

#

We do it now - but colors aren't that great

#

But looks like we can match them to server ones pretty easily

#

PoC is in works.

#

So we won't need that palette at all.

fast grove
#

Can’t you then just better use the server for this instead of duplicating on the client? What is the usecase?

abstract trench
#

But if it's easy to expose from server, it's not worth duplicating the logic of course. These calls will be reasonably fast I think...

#

(depending on the server hardware for sure)

fast grove
# abstract trench To unload the server?

I dont think it will be THAT heavy and it can also be cached. In the end server will have more capacity to do this than a mobile client (although new ones are really powerful nowadays)

#

Added benefit is that you can request it for any image, not only url

abstract trench
fast grove
#

What should the command look like ? request the colors for a MediaItemImage object ?

abstract trench
#

Client does read bitmaps anyways - for displaying. So it's pretty easy to extract dominant color

fast grove
fast grove
#

If you want we can also backport to stable as this is a relative safe addition

abstract trench
#

We're using local now - we'll see if I fixed it for iOS. If yes, then we can wait for next release easily!

#

Thank you for fast reaction!

fast grove
abstract trench
abstract trench
#

Wait, I found this:

const buildHeroEntries = (randomize = false): HeroEntry[] => {
  const playlists = findFolder("playlists made for you", "made for you");
  const mood = findFolder("find your mood", "mood");
  const stations = findFolder("stations for you", "radio stations for you");
  const releases = findFolder("new releases for you");
  // "Artist-focused" stations = artist items inside the stations folder.
  const artistStations = (stations?.items ?? []).filter(
    (i) => i.media_type === MediaType.ARTIST,
  );

  ...

Does that mean that Top Picks for you - is completely frontend feature?

fast grove
abstract trench
fast grove
#

Yes and then we better look for a way to offer this from backend in a structured way instead of this magic guessing on frontend. I missed this tbh, otherwise I would have raised this concern earlier.

mellow widget
#

As far as I can see, there isn't a way to grab multiple media items (bulk fetch) with one command to the server at the moment using either item URIs or item/provider ids. Is that correct?

#

I'm working on shortcuts for mobile and currently need to do a music/item_by_uri for each shortcut. That should be fine as I'd expect the number of shortcuts to be pretty small (less than 10), but just wanted to double-check there isn't a better approach I'm missing.

abstract trench
fast grove
mellow widget
#

Yeah I don't think it's the end of the world for this use case. Long term, it'd be nice to have a version of item_by_uri (and probably get_library_item) that take an array of identifiers and then return an array of items.

mellow widget
#

Just another thing to double-check: there's not currently an event that the server fires when shortcuts are added/removed right?

fast grove
mellow widget
#

Yeah that lines up with my impressions from reading the code: the shortcuts are stored in user preferences (in sidebar.shortcuts) available via auth/me and the frontend uses a repository/store "update local and then send to API". Obviously the consequences of that are that there's more complexity in the client (you need to maintain a local store) and there's no way for other clients to stay consistent without polling. You can demonstrate the latter by adding a shortcut with the web client open in two tabs - the second "instance" will be out of date until a refresh.

#

Again, not the end of the world! It does feel a bit out of whack given how the rest of the API works though.

#

From my perspective, the ideal would be to have shortcuts exposed as a list somewhere for displaying in one place (as they already are in sidebar.shortcuts), but also have an isShortcut property on items and have shortcut edits fire the item updated events (like with favourites).

#

Do you want me to file an issue against the server? It's potentially something I can contribute as I'd rather hold off on implementing add/remove in the mobile app if we're going to be able to avoid needing to store the shortcuts state locally later.

fast grove
mellow widget
#

One thing though: I do think having a property on items would be really useful. You can ideally add/remove shortcuts from anywhere you see an item, so if that data isn't part of the item itself (and only part of specific shortcuts commands/events), you're always going to have to maintain a local representation of shortcuts and watch shortcut specific events from anywhere items are displayed in clients.

#

Of course if a client doesn't implement shortcuts then this probably adds some amount of wasted performance overhead, but I'm assuming that should be able to be pretty minimal.

fast grove
#

For library items this would be super easy to add as it will just mean joining another db table but if we want the shortcuts to be flexible so you can reference ANY media item (so also something that is not in your library) then it will come with a performance penalty as we'll need to resolve this for every item.

So maybe better would be if a client just keeps the list of shortcuts in its global store so it knows this itself ?

shrewd crown
#

Are shortcuts only meant to be linked to an media item or like a small automation which triggers a playback of specific items to a specific player (group)?

fast grove
shrewd crown
# fast grove For now its just a shortcut to a media item but if we do it right we can extend ...

Yep can understand a simple play or pause action would be great so I don’t want to use HA to connect a shortcut with a player as I always listen to a specific playlist at specific rooms so yeah this would be a nice addition for the future. Personally I would only allow to use media items of your collection as I want to have a direct feedback of a shortcut and not waiting like a second or two to see it.

#

BTW: If shortcuts are added to players a player should also can call a shortcut based on a button press for example but that’s not the scope of the app here 😉

mellow widget
# fast grove For library items this would be super easy to add as it will just mean joining a...

I've not read enough of the server code to have context to authoratively comment, but I'd guess the performance hit would still be minimal for non-library items: you'd need to hit the DB to grab the shortcuts, and then add the isShortcuts value to the response by matching the items based on URIs (the ol' "in-memory join" essentially). If that work (decorating items with whether their shortcuts or not based on a list of shortcut URIs) doesn't happen on the server, it has to happen on the client anyway so it would still feel worth the hit to me? Again though, I could likely be talking nonsense as I'm coming from a "here's how the server might already be implemented" rather than than a "here's how it actually is" perspective 🙂. Would be interesting to know why I'm wrong here if I am!

fast grove
# mellow widget I've not read enough of the server code to have context to authoratively comment...

Yes we already do this for the new image_id (for the imageproxy) and the translation support but we should be careful of not adding too much "JIT" processing for every item that crosses the wire but I guess one more is not that bad.
Given the fact that shortcuts are just a handful of items, we can just keep it in memory so it will be cheap to add it.
Leave it with me and I'll come up with something later this week.

mellow widget
#

Amazing thanks! Yeah that's a great point that each feature like this (favourites, shortcuts, images etc) in isolation isn't much of a hit, but it could definitely snowball long term.

abstract trench
#

Hmm feature flags... It starts smelling like my job.

#

🙂

mellow widget
#

Haha! Yes.

#

So I'd imagined that the app could be released independently of the server and that the app should be backwards compatible through fallbacks (optionally fields in parsed responses etc), but I don't have a feel for if that will work long term with Music Assistant. Has there already been any major versioning of the API or things being moved around rather than simply being added?

abstract trench
mellow widget
#

Forks of the server or you just mean the schema changed?

#

Sorry I misread, you mean forking logic based on the API response/version I think. Yeah, the shortcuts stuff I just worked on doesn't require the data to actually be in the API response - very recent example.

abstract trench
#

See, now we have server strings, and DSTM renaming - both are basically breaking changes.

#

Good thing that server is deprecating things instead of removing them - but at some point that will be the case too. 🙂

mellow widget
#

Yeah, but I think it's ok to eventually drop support for older server versions as well.

shrewd crown
mellow widget
#

But yeah, I'd hope we can just maintain an independent release pipeline, but obviously we'd probably end up planning some feature additions around things be added to the server.

mellow widget
#

I'm being optimistic I guess haha

shrewd crown
mellow widget
#

Sorry: "don't think there needs to be a polcy"

shrewd crown
#

I usually update every time after a patch release is available. So 3 major stable releases are a long way if we think every quarter comes a new release

#

Major = .10, .11 etc

mellow widget
#

Is there a normal cadence for server releases?

abstract trench
#

Should disable it probably - it might interrupt playback. But we're not THAT addicted to the music.

shrewd crown
abstract trench
#

More convenient to me.

shrewd crown
shrewd crown
abstract trench
mellow widget
#

So yeah saying the app supports the current and 2 previous stable releases feels right. That basically requires people to upgrade very 9-12 months.

#

Although I imagine in practice we'd actually support more releases (even if it's accidental)

#

I can just add a note about compatility to the README @abstract trench if you agree with the 3 release number? I think that gives us a nice window for users where some things might have to be optional/flagged, but not forever. We'd probably also just want to try and keep compatibility with the current beta, but not need to sync releases with the server.

abstract trench
mellow widget
#

2.7 music assistant release?

#

Or do you mean an upgrade to Sendspin itself?

abstract trench
mellow widget
#

That luckily would be our "oldest" release (2.7, 2.8, 2.9), so we don't need to put a caveat in. Nice.

#

I've added a to-do to write this up in the README

#

So did you also want to change branching strategies for release @abstract trench? It looks like right now we have automation for both iOS and Android and it handles version codes, names, tags and the GitHub release etc. I guess we'd just need to update some of that config for release naming.

#

For open source GitHub branching, I've found doing PRs to main, tagging releases and then branching off the tags for hotfixes (patch version) works nicely.

#

And that would work with your current automations I think

abstract trench
mellow widget
#

Should we rename dev to main?

abstract trench
#

(if we need hotfixes)

mellow widget
#

Yeah I like that way of working because you only need to care about branches for the hotfixes rather than maintaining multiple at once all the time

#

Yeah let's rename to main just so it's clearer for folks coming in that's it's the default/trunk

abstract trench
mellow widget
#

Will change my local now before I forget 😂

abstract trench
#

yup 🙂

#

Done it too

fast grove
#

Why keep backwards compatible up to 3 releases ? That is 9 months.
I would do just do latest stable release -1 (so max 1 older stable release)
And with the schema versions you can even add features that are still in beta.

mellow widget
white breach
#

Will iOS also be moved from teancoms personal account? Or will that be a concern for later? It works for now, but might be good thing to think about (would be nice if app could be migrated to OHF account including the current TestFlight history and users).

brave sentinel
mellow widget
abstract trench
#

There's request for Sleep Timer in the app. Should we do it locally, or will it be implemented on server? Because as far as I'm concerned, having local timers for remote players would be awful idea - so we would implement only for local player.

white breach
abstract trench
white breach
abstract trench
#

Yeah. I closed issue anyways - your reasoning added to my hesitation.

brave sentinel
# abstract trench Yeah. I closed issue anyways - your reasoning added to my hesitation.

I was actually thinking about sleep timers just the other day (well, night, as I was listening to an audiobook in bed. 😄). Anyway: https://github.com/music-assistant/server/pull/4432

GitHub

This is an MVP for #5526 , explicitly with no user-facing changes, just adding the API. Assuming this approach works we can add UI support afterwards (honestly, hoping someone else does that part -...

abstract trench
#

I mean, good that you started it 🙂

abstract trench
brave sentinel
#

Oh, phew. I was really confused for a second. 😄

abstract trench
#

🙂

#

Sorry

#

We can work with that API from scratch, and it also stops player automatically, so purely UI feature for us.

mellow widget
brave sentinel
abstract trench
#

Continuing conversation on the icons @mellow widget @woven mesa @river sonnet

#

I guess we can use lucide font as well to generate full map

#

Same way we do it for MDI now

#

There is official font

#

So now we would: search MDI, search Lucide, then search in subset of custom icons.

#

For custom icons we will need their names and SVG.

mellow widget
#

Yeah to clarify (based on your last question in the other channel @abstract trench ) I meant that would mean clients could just map to whatever icons they want. Front end changing to Lucide wouldn't matter - we could continue using MDI in the app. Obviously that's not the place we've ended up in though!

#

I think if we need to support two sets, your plan is good @abstract trench 👍

#

But I would be interested to know if instead of introducing another set of identifiers, the front end could just map their new icons to mdi ones and continue to have them as the single set of identifiers that the API serves. That would also mean the front end could show "newer" icons for the existing mdi selections.

woven mesa
#

We could have something like this:

{ "id": "homepod-mini", "source": "custom", "svg": "custom-svgs/homepod-mini.svg", "codepoint": "U+F500", "mdi": "mdi-speaker" },
    { "id": "sonos", "source": "custom", "svg": "custom-svgs/sonos.svg", "codepoint": "U+F501", "mdi": "mdi-speaker" },
    { "id": "mac", "source": "custom", "svg": "custom-svgs/mac.svg", "codepoint": "U+F502", "mdi": "mdi-laptop" },
    { "id": "apple-tv", "source": "custom", "svg": "custom-svgs/apple-tv.svg", "codepoint": "U+F503", "mdi": "mdi-apple" },

    { "id": "speaker", "source": "lucide", "lucide": "speaker", "mdi": "mdi-speaker" },
mellow widget
#

I have to boost, but will catch up on this later 👍

river sonnet
#

As far as I know, aliases are also defined in MDI, right? Do we also need these aliases for Lucide and custom icons?

Something like this to add on every entry ?

"aliases": ["homepod", "apple-homepod-mini"]
fast grove
#

I would love us to also have some (custom?) icons which are area based, such as a kitchen or a livingroom.
The Hue app has this as well and its really nice for recognition of a speaker

mellow widget
mellow widget
#

I guess I'm a bit confused about the general concept of how this should work. My impression was that MA and HA both used the MDI icon set to give users a broad set of choices, but that that obviously meant that clients all had to support the MDI sets (based on string IDs). And now MA is planning to support both Lucide and MDI (maybe eventually removing the latter) with each having its own set of IDs at a server level. Is that correct?

woven mesa
woven mesa
#

I know this situation is kinda annoying for you, I totally get that and we should have thought about it before (sorry about that)

#

But I really think we should get away from mdi and find a proper solution with lucide and custom icons

mellow widget
#

I do agree that it's not ideal to have the IDs of the player icons tied to MDI though. Was there any discussion of trying to define a smaller icon ID set (on the server) not tied to any actual icon set to give clients more flexibility? I do think that would be the ideal setup personally.

woven mesa
abstract trench
mellow widget
#

I guess something I should say out loud that I've probably made too implicit is that I don't think the server should have to know anything about the client. It should just say "this player looks like a speaker" and the clients can decide how that looks.

#

Right now that is sadly all tied to MDI so I guess I'm arguing for a different setup entirely really

abstract trench
abstract trench
#

Would definitely be good to have some MA icon set, distributed for everyone.

mellow widget
abstract trench
#

( == a lot of complaints)

mellow widget
abstract trench
#

Also you would need to map those values to icons manually

#

For MDI, for example, we take font, and rip the names out.

mellow widget
#

It'd let you use more native feelings icons on different platforms and update look and feel over time without having to change the "schema" or format of the player data . It's definitely a trade off though I get it.

#

But yeah maybe that's me trying to redesign everything from the ground up (it is).

fast grove
# mellow widget I guess something I should say out loud that I've probably made too implicit is ...

I agree with this as well to a certain degree. We just just have a curated picker of an icon/devicetype and then each client can translate it to what they support. But... in terms of consistency having the same icons, regardless of client would be even better.

The whole point that drove this was that we want to have recognizable icons for the players. Like an Homepod to describe the speaker type or like a symbol to describe the kitchen.

#

What if.... we only have custom SVG icons ?
And we have an endpoint to fetch the icon data ?
A bit like imageproxy

#

This is btw also where we need to go for the providericons as currently they're embedded in the provider manifest payload but that is becoming painful

abstract trench
#

Yup that would be cool.

mellow widget
#

Yeah I think having the icons work as SVG image assets the server can provide us a nice compromise: clients can't have their own styling (which isn't a huge loss in practice), but get the advantage of not having to worry about mapping icon IDs and most importantly icons can be updated without clients need to make changes.

#

I'd need to remind myself how iOS/Android do with dynamic SVG rendering these days, as I seem to remember that unintuitively being a problem.

mellow widget
#

Ok did some quick research on this and it's in (sadly) still in the state I suspected: no native rendering of SVGs in iOS or Android. It does look like there are libraries for doing SVG rendering for both iOS and Android out there (https://github.com/BigBadaboom/androidsvg and https://github.com/mchoe/SwiftSVG for example) so I'd imagine we could end up using these to back a shared component. Probably makes sense for us to do a quick spike on showing an SVG icon like this before deciding it's our favourite route though.

GitHub

SVG rendering library for Android. Contribute to BigBadaboom/androidsvg development by creating an account on GitHub.

GitHub

A simple, performant, and lightweight SVG parser. Contribute to mchoe/SwiftSVG development by creating an account on GitHub.

#

I guess there's also the potential of having the server provide icons as SVGs or BMPs with the API accepting dimensions for the latter. I don't like that as much, but it might be that that something like that is more practical given Android/iOS lack of (dynamic) SVG support.

abstract trench
fast grove
#

yikes, you would have expected this to be in a better shape in 2026

#

So we're back to the drawing board then

mellow widget
#

I don't think it's completely out of the question to show dynamic SVGs, but yeah it's definitely not as straightforward as any of us would hope.

fast grove
#

Then maybe back to the idea of a preselected set of icon names for which we'll have a mdi and lucide variant but that still leaves us with custom icons, unless we can reproduce those with both

mellow widget
#

Well we can show SVG icons statically: they can be converted to vector assets for Kotlin Multiplatform to use.

abstract trench
#

Yeah and no server-side updates

mellow widget
#

So if we migrated to a small set of custom icons, we could just publish the SVGs for each icon ID that the API will serve and the clients can either use them or convert them (which mobile would do)

#

Obviously less choice for users, but means that icons can be consistent and can be updated over time without too much disruption for clients (they can just update their packaged assets)

fast grove
#

Yeah, I guess that would be the best way forward. We just need to make sure to not change that icon set too often 😅

mellow widget
#

I mean it's definitely pushing more work into visual design, but an upside is being able to have more music centric visuals.

mellow widget
abstract trench
#

Font would be better 🙂 Single file, vector inside. Both MDI and Lucifer have font.

fast grove
#

The Roon icons are great indeed! I was a Roon user before I started MA (maybe because of it)

abstract trench
fast grove
#

Roon is amazing but its such a closed box that I kept running into stupid limitations (especially with its weird api) and that got me into building MA

#

But still, everytime I see it I'm in love with their UI

brave sentinel
mellow widget
white breach
#

Roon ARC was 'meh' at best 😬

mellow widget
#

But anyway, Roon is a good example of using a limited icon set. Is that idea something that we could feasibly adopt? It sounds like @fast grove is onboard, but I'm aware that it's a change in direction for the front end, and requires design work to define the icon set.

#

I'm happy to write up a more formal proposal if that would be helpful

fast grove
#

I'd rather have a limited icon set which is consistent than something that is inconsistent

abstract trench
#

@brave sentinel for reference, this is the prompt that I use in claude.md:

# Persona
From now one act as pessimistic, self-critical code architecture professional with anxiety.
Check yourself on every step.
Ask questions if there's littlest ambiguity.
Don't accept "good enough" solution, make it the best one, robust, complete, optimized, effective and architecturally perfect.
Also make MINIMAL changes to the code upon refactoring, be short and specific.
Be reasonably sarcastic, but no exsaturation or induced sarcasm.
Use SOLID principles where it's reasonable.
Use KISS principle, don't over-complicate solutions. They should be laconic and sharp.
brave sentinel
abstract trench
#

Right, forgot it..

#

🙂

#

I still have sometimes to do something like I just did:

 Stop and roll back what you're doing. I don't think introducing bunch of new booleans and constants will help. The behaviour should be reactive, not stateful. Re-read your system prompt, and act as experienced engineer by SOLID and KISS principles, instead of introducing more ambiguity and potential fail points into the code.
abstract trench
#

From next Android we won't be able to force portrait mode on the phone.

#

App should be able to support any orientation/screen size.

abstract trench
white breach
white breach
#

Lemme grab my android device and see what happens 🙂

abstract trench
#

Okay, everyone merging the PRs into main now:

  1. We squash.
  2. We give readable descriptions.
    Okay? 🙂
#

We can close beta for now @fast grove what do you think? Or should we make it accessible to everyone?

mellow widget
abstract trench
mellow widget
mellow widget
abstract trench
#

Yeah. I thought having options is good.

#

Squashing looks cleaner in main

mellow widget
#

I personally prefer merge commits because they allow for finer grain bisecting. You can always view the PR merges with git log --first-parent? This isn't really a hill I choose to die on though. If we want to squashes, I'm happy to just have it as the only option.

#

While we're at it, it would also be nice to make sure "Require status checks to pass before merging " is enabled for main as in branch rules as well. I can add a PR template to encourage more detail in PR descriptions.

abstract trench
#

The log in What's new is built from PR descriptions, so I just don't want things like "fixed tests" in Play Store. Other things don't bother me 🙂

mellow widget
#

Could we not use --first-parent there? That's what GitHub's generated release notes do as well.

mellow widget
abstract trench
mellow widget
#

I can do an update to the actions and README tomorrow as well along with a PR template. We'll want to stop the debug APK release now that we've got Play Store betas so we're not publishing with two keys (as we discussed a wee while ago).

abstract trench
#

Let's wait on Marcel's decision. If we stick open beta - then yes. I honestly only wanted to see if it works. We can disable it.

white breach
#

Did they actually approve already?😮

#

They; Google

abstract trench
#

Yeah In guess OHF has pretty reliable account

mellow widget
#

Could just be temporary. If it keeps happening we can package it locally.

#

And on that: @woven mesa , we was there any reaction to the discussion about the propsal for creating a limited icon set for all MA clients as a migration away from MDI (as an alternative to using Lucide)?

woven mesa
fast grove
mellow widget
#

Yup! Sorry was on a call. Thanks for jumping in @fast grove.

#

So for the moment should the mobile app just remain the same, and we can adapt to the new limited icon names when the server is able to start providing them?

#

We'd also discussed having SVGs available for each of these icon names that clients could use to keep things consistent. Are you thinking that would be available at the same time @mortal wadi or that it'd be a future thing?

fast grove
mellow widget
#

Dynamically yes, but we can convert SVGs to vector assets and include them statically. So for a limited set it's definitely doable. I'd mentioned that here: #1343766783768789002 message

abstract trench
fast grove
#

Ah ok, makes sense. Let's go with a static set then of icons and extend them later.
I'm assuming that Lucide icons are in fact also just svg's ?

abstract trench
mellow widget
#

@fast grove sorry to spam you, but I reckon this probably got buried by other pings: #1343766783768789002 message

fast grove
mellow widget
#

Nice! Ok so I'd vote we just make it public with a link like we have now (not sure if it's searchable in Play Store, but either way seems fine). We can add the link to the README like we have for TestFlight and stop building the "self signed" release @abstract trench

fast grove
#

And for Apple appstore lets pick a moment this week to set everything up

mellow widget
#

@abstract trench I'll do a wee PR for the Android workflow changes

white breach
abstract trench
#

Ummm, I tried to put fake power control into one of my sendspin players. It "worked", but mobile app stopped receiving any sendspin players in players/all. Only if something changing on the player, it gets received. I removed that power control from player, but still don't receive any of them.
P.S. Guess it was some fluke, restarted MA and issue is gone.

mellow widget
#

I'm going to start having a think about new things that should go in here as well!

fast grove
#

@abstract trench @mellow widget I have been looking into a proposal to consolidate the "audio chain" we talked about before and let my robot create a draft PR on the mobile app repo.

Most important change is that with this proposal you no longer have to collect the chain from various sources and the quality label will be determined server-side.

I can imagine that mobile app is only interested in displaying a portion of the data.

#

First feedback I'm looking for is if this is the datamodel you expected @mellow widget ?

#

BTW: Sorry that the PR arrived before my message here. I am experimenting with CoPilot desktop app and it was a bit more eager than I anticipated.

mellow widget
#

Is that a correct understanding of the general approach here?

fast grove
#

yes, and with my comment that the AI overengineered some stuff so I'm tweaking

mellow widget
#

And then essentially the chain breaks down into input, processing (volume normalization etc) and outputs. The outputs contain the DSP details, the input and outputs get a "fidelity" each and there is also an overall summary of the fidelity.

#

I'd more expected the processing and DSP details to be one chain, but I can see that it works the way it does because "processing" happens before the outputs and then each output can have it's own DSP.

fast grove
#

yeah, there can be 2 types of processing happening;

on the input signal: volume normalization
on the output signal, resampling, dithering, dsp, limiter

mellow widget
#

Would it make sense to have those in a list/array rather than properties on the output? Presumably there is an ordering to them?

#

Also can't DSP be multi stage?

#

My other thought was that the fidelity summary seems superfluous? There are also a bunch of properties like "revision" and "state" that don't seem needed for how I'd think to implement it, but they might be things that other clients would find useful, or I'm missing something.

#

I guess the other important question is around event timing: I'm guessing we get the event every time any of these details change for any queue right? So if I start playing a track I get an event, I skip to the next track I get an event, I play something else I get an event etc.

fast grove
#

OK, final proposal for the models looks like this (python, but you get the point):

#
class AudioQuality(StrEnum):
    UNKNOWN = "unknown"
    LOW = "low"
    STANDARD = "standard"
    LOSSLESS = "lossless"
    HI_RES = "hi_res"


class AudioNormalizationMeasurementSource(StrEnum):
    UNKNOWN = "unknown"
    TRACK = "track"
    ALBUM = "album"
    LIVE = "live"
    FALLBACK = "fallback"


@dataclass(kw_only=True)
class AudioFidelity(DataClassDictMixin):
    """Effective audio fidelity."""

    quality: AudioQuality = AudioQuality.UNKNOWN
    bit_perfect: bool | None = None


@dataclass(kw_only=True)
class AudioInputDetails(DataClassDictMixin):
    """Audio entering Music Assistant."""

    # Provider instance that supplied the stream.
    provider: str = ""

    # Original/provider audio format.
    audio_format: AudioFormat | None = None

    fidelity: AudioFidelity = field(default_factory=AudioFidelity)
#
@dataclass(kw_only=True)
class AudioNormalizationDetails(DataClassDictMixin):
    """Effective volume normalization."""

    mode: VolumeNormalizationMode = VolumeNormalizationMode.UNKNOWN
    measurement_source: AudioNormalizationMeasurementSource = (
        AudioNormalizationMeasurementSource.UNKNOWN
    )
    target_lufs: float | None = None
    measured_lufs: float | None = None
    applied_gain_db: float | None = None


@dataclass(kw_only=True)
class AudioQueueProcessing(DataClassDictMixin):
    """Shared processing before player-specific output processing."""

    # Internal PCM format, including F32 headroom when applicable.
    pcm_format: AudioFormat | None = None

    normalization: AudioNormalizationDetails | None = None
    playback_speed: float = 1.0

    # Effective mode; DISABLED means no crossfade processing.
    crossfade_mode: CrossfadeMode = CrossfadeMode.DISABLED

    # Whether another audio source is mixed into the queue stream.
    overlay_active: bool = False

#
@dataclass(kw_only=True)
class AudioDSPDetails(DataClassDictMixin):
    """Effective player-specific DSP."""

    state: DSPState = DSPState.UNKNOWN
    input_gain: float = 0.0
    filters: list[DSPFilter] = field(default_factory=list)
    output_gain: float = 0.0
    output_limiter: bool = False


@dataclass(kw_only=True)
class AudioOutputDetails(DataClassDictMixin):
    """Audio delivered to one or more equivalent player outputs."""

    player_ids: list[str] = field(default_factory=list)
    dsp: AudioDSPDetails = field(default_factory=AudioDSPDetails)

    # Only set for explicit left/right routing.
    source_channel: AudioChannel | None = None

    # Furthest downstream format known to the server.
    output_format: AudioFormat | None = None

    fidelity: AudioFidelity = field(default_factory=AudioFidelity)


@dataclass(kw_only=True)
class AudioProcessingChain(DataClassDictMixin):
    """Effective audio processing chain for the current queue item."""

    queue_id: str = ""
    queue_item_id: str | None = None

    input: AudioInputDetails | None = None
    queue_processing: AudioQueueProcessing | None = None
    outputs: list[AudioOutputDetails] = field(default_factory=list)
fast grove
fast grove
# mellow widget Also can't DSP be multi stage?

sure but that would make the model even more complex while in real world it doenst matter for the presentation. Most important is at which part of the chain something happens and that is now reflected in the one object

mellow widget
mellow widget
#

As far as I can see, this gives us (and other clients) as much detail as we'd ever need, but also seems like it doesn't make building simple visual representations awkward either.

#

One thing I can't think of a reason for is queue_item_id? I'm probably missing a use case here, but in my mind you'd only ever be fetching (or merging) these by queue ID, and I'm not sure what value being able to link it to a queue item gets us.

fast grove
mellow widget
fast grove
mellow widget
#

So basically to get the AudioProcessingChain, you'd go through the QueueItem so you could get that for the current item from PlayerQueue for example?

fast grove
#

yes it will only be filled for queue.current_item

mellow widget
#

And you also thinking that clients just use the queue_updated event instead of introducing a new one specifically for the audio chain?

#

If it's on current_item, that would make sense anyway

fast grove
#

lets just jeep the queue_updated event for this to keep it KISS

mellow widget
#

Yeah I like that

#

It makes it very easy for existing clients to adapt as they'll probably already be using that command or hooked into the event

fast grove
#

Yes and we'll keep the old data intact until 2.10 stable

mellow widget
#

Yes true

fast grove
#

so clients have some time to migrate

mellow widget
#

And if for some reason you did just want to build a client that showed audio chains, it's not a big ask to fetch the queue and then get to the chain through current_item.

fast grove
#

The only thing I left out of the server models is the color per quality as I think that should be something client decided

abstract trench
#

Glad about the direction you guys are going in. 🙂

fast grove
#

We're all in this together - with proper aligment we can achieve great things

mellow widget
mellow widget
#

@abstract trench I'll start writing up issue(s) later today or tomorrow around using this. I think having a good way to get between the audio chain and DSP settings (and vice versa) is something to add as well.

mellow widget
#

@abstract trench just on all the APK questions: are you not able to download the universal APK from Play Store console like I suggested, or is that not available until after review?

abstract trench
mellow widget
#

Do we have access to keys to do that?

#

Ah sorry just seen you've already made the change

#

Being honest, I don't think we should be distributing with two keys (two valid APKs end up with different certs, more keys to manage etc.) - maybe that's how OHF does things for the Home Assistant companion app as well though?

#

Even if we do use two keys, I really don't think we should use a debug key as one of them. The debug key itself isn't inherently weaker (in terms of security), but it uses default aliases and passwords, is stored in a keystore with a default password and even without them being guessable it's all exposed in our Github Action config.

abstract trench
#

I think interchangeability isn't that matter

#

and we have both debug and release in well_known

#

You want to create another key for GH APKs?

mellow widget
#

Agreed interchangeability is a minor issue! If both are verifiable then it's just adding a bit of complexity to verification, but there's no actual issue with them being different from a security perspective (other than the situation of needing to uninstall to reinstall becoming a valid scenario). I do think the Github APK one should be at least as secure as the Play Store one though: the keystore should use non-default strong passphrases that aren't shown in our action config or logs. I'm not sure how OHF usually manages keys, but ideally it's stored somewhere secure but well documented as well.

#

I'm guessing using the Play Store key to sign the GitHub APK is out for the question? I don't have access, so don't know if it's a Play generated one or one that OHF manages and has uploaded, but I'm assuming it's the former given that that option hasn't come up.

abstract trench
mellow widget
mellow widget
#

Right if we're using a Play Store generated key then I think the only options for getting a signed APK are to download from the Play dev console or build an APK and sign with a different key. It does look like there might be API options for grabbing the Play Store signed universal APK:

Google for Developers

Discover the typical publishing workflow that includes downloading generated APKs before they are released on any track.

abstract trench
mellow widget
#

Ah, need to wait for it to be generated I guess?

abstract trench
mellow widget
#

Does adding it to the GitHub Release manually after the fact cause any problems for things like Obtanium or is it just annoying?

abstract trench
#

But first I want 0.7.0 to be up and running.

abstract trench
#

Talking to Claude 🙂

mellow widget
#

Yeah as much as it's annoying I'd vote to just add it manually after the fact and remove automated build with the debug key. If Claude has a cool way to do it with the API that we've not seen from a search that'd be ace, but I think the manual task is worth it here if not.

#

I guess there might be a way to poll the API until it's ready etc, but would need to explore it more

#

I would generally just do this manually until it pissed me off 😂. Which I guess is basically how all software engineering works really.

abstract trench
#

At least it will try for 15-20 minutes.

mellow widget
#

Thanks so much for giving it a go!

abstract trench
#

Got new(ish) phone today, and the app shows predictive back now... I haven't seen it on my S21 Ultra. Had to upgrade due to lack of security upgrades... 🙁

mellow widget
#

Ah hadn't realized you weren't seeing them!

#

So few apps actually have it. I basically only see it in Settings.

abstract trench
#

Well, then we're cool!

fast grove
#

@mellow widget one more thing we should perhaps add to the audio chain details in the DSP section... the preset

#

So backend keeps track of the selected preset someone selected I mean

mellow widget
#

Ah ok yes! We're showing that in the app right now, but not familiar with how it's retrieved (not able to look at the code right now).

white breach
fast grove
abstract trench
#

What if user selected preset, and then tuned manually?

fast grove
#

or show "custom" as preset

mellow widget
#

@abstract trench think we're good to do another Android release?

abstract trench
#

Wanna merge that items fix

mellow widget
#

Ah nice you found a fix for that

brave sentinel
#

Should we add another tag in gh for PRs, something like 'chore' and any PR with that tag gets omitted from the automated changelog? Thinking of https://github.com/music-assistant/mobile-app/pull/796 but there's been a few where the users couldn't possibly care less. 😅

GitHub

Is there anything about the code changes here that should be highlighted?
Two commits, the first removing all of the now-dead code from the iOS refactoring, and a second that cleans up pre-existing...

abstract trench
abstract trench
brave sentinel
#

Yup, about to open that PR, was testing it locally first.

abstract trench
#

Well, now we know that APK strategy works. 🙂

mellow widget
# abstract trench Well you can call it that.

Oh wow yeah that needs to be much more complex now. I'm going to have a look at writing something up to try and simplify the view a little. Right now we end up with doubled up albums, and it's not clear where exactly things come from. The important thing for the moment is though: you can see everything in the single provider case most folks will have!

abstract trench
mellow widget
#

Wow I think web is actually broken

abstract trench
fast grove
#

@mellow widget latest beta has the changes to the audiochain included - frontend already uses it

mellow widget
fast grove
mellow widget
fast grove
#

/api-docs/schemas#schema-AudioProcessingChain

mellow widget
#

@fast grove @mortal wadi something I've not found docs for and can't quite figure out is when the API chooses to return items with library as the provider and with itemId as the library ID vs when it returns items with their "original" provider and provider item ID.

#

I'm meaning for items that are in the library obviously 😆

#

From observation, it seems like if we grab an individual item (like music/albums/get) it returns the library provider version regardless of the item_id and provider_instance_id_or_domain, but if you fetch a list (of artist albums for example), the provider in returned items (and with it the item ID) are determined by the provider_instance_id_or_domain used in the request.

fast grove
#

if you do music/albums/get
it will always resolve to the full library version if there is one, regardless if you passed it a library id or a provider id

#

but listings (like artist albums) are strict and only listen to what you literally passed. This way you can divide library items from provider specific

#

before we had no way to divide albums in the library from albums existing on a provider

mellow widget
#

Right that makes sense so items always come back as their "library version" for the individual item endpoints/commands (regardless of how they are addressed) but come back with the provider used for the list endpoints/commands. It's "detail" vs "list" views of the data.

#

And is that the case for all media types yeah?

#

Oh, but search always returns items with "library" if they're in the library as well. Again, that makes sense.

fast grove
#

the reasoning is that if you do request the full details, you want to get everything we have and we auto resolve a provider into a library - but when looking at artist albums for example you care about your library albums but you want to use the provider albums for discovering of more

#

when we had that auto mangled together people got confused

fast grove
mellow widget
#

I'd file that under "the right amount of magic"

fast grove
#

I think one of the next things we should tackle on this regard is paging and filtering of lists like playlist tracks

mellow widget
#

Yeah pagination will definitely be helpful for long playlists

fast grove
#

Yes and a stable contract between server and clients on sort and filter options

abstract trench
#

Do we already have localizations on server side in 2.10 beta? Can we start implementing it?

#

Same question about removing main player from group. 🙂

#

And will we make player icons common lib too?

fast grove
fast grove
fast grove
abstract trench
#

@fast grove please take my head and put it into the server code related to those two 🙂

fast grove
#

Another important change is that the providers icons are now no longer embedded in the manifest (as that message got super huge) but you now simply request the icon with a command

fast grove
#

Oh and don't know if @mortal wadi already told you but he's working on the webrtc improvements - its already lightyears faster now

fast grove
abstract trench
#

Oh, another thing: are we 100% positive that server can give up to 30 seconds of stream upfront? I will be re-checking this part on app side, so want to be bold on server side.

woven mesa
#

I'll probably finish the icon lib either next week or the week after @abstract trench 👍

#

Didn't have the time to start it before

fast grove
abstract trench
fast grove
#

We're also working on a simple HTTP endpoint to fetch audio (with a api command to create a virtual player/queue) which could be something in potential for remote listening (and then fetch a very large portion of the queue stream for offline playback) - but let's first see how far you come with using sendspin

abstract trench
abstract trench
fast grove
abstract trench
#

Just verified buffer: started playback, and after several seconds turned off wifi and mobile data. For 25 seconds it was continuing playback, and then I turned data conenction back on - no gaps everything plays smoothly.

#

So the complaints about insufficient buffer are false.

#

Of course, buffer is wiped on playback pause (server sends stream stop command, so we dismantle buffer)

fast grove
brave sentinel
#

That's actually the biggest gap between the non-mobile use-case and the mobile-app use-case, imo. Our phones are constantly interrupting playback for a second or two or three, to announce incoming texts or when I pop an earpod out to talk to my fiance or because GPS is telling me to turn left, etc. My stream to the wiim in my living room isn't interrupted unless I manually hit pause. And it has my home network to use to connect to my home server 10' away. "Fixing" pause/resume on mobile in some way is imo the biggest bang-for-buck thing we could do. I don't have a solution (off the top of my head) just noting it as a real difference in kind.

abstract trench
brave sentinel
abstract trench
#

Well if user uses FLAC - I can't imagine the potato internet that will give troubles on playback start... 🙂

#

Maybe some Edge.

brave sentinel
#

I don't often have problems with resuming (though spoilers, I'm working on a PR to better handle resuming from the lockscreen and immediately-on-foregrounding) but it's often a couple of seconds of wait-wait-wait-ok-now-audio-is-going-again. Which only happens because we've wiped the buffer.

abstract trench
#

ah crap, spec says it's bytes.

#

Not microseconds

#

right?

fast grove
abstract trench
#

But if it's microseconds, I would make that dependent on codec used.

woven mesa
#

Ok so I made the repo, i was curious after our discussion ahah

#

If we agree on the process, i will implement the solution on the fe and be repo

#

Since we didn't decided on the other icons, i put a small list but definitvely open to discussion/enhancement

abstract trench
#

Ok that's something to work with I guess.

#

Right now we have material icons for players. So many users gonna have that. We will need to replace those with equivalents, or drop to default, right?

#

On the fetching: there's three ways.
First, we fetch from repo online by name. Fastest, dirtiest, online updates.
Second - we include all icons from repo into each build. Chunkier, harder to update (build required).
Third: we watch the folder from mobile repo, convert that into font on change, and include font into the app. Harder on build, effective in app, but again - harder to update (build required)

fast grove
abstract trench
#

Still have to decide how to consume it

#

SVGs or font

mellow widget
# woven mesa If we agree on the process, i will implement the solution on the fe and be repo

A couple of questions:

  1. How often do we expect this to change? From the tone of the README, it sounds like it will hopefully be rare and that any changes would likely be additional or just tweaks so not things clients would absolutely need to take up quickly.
  2. Will the front end only allow picking options with the manifest IDs? If so, clients don't strictly have to deal with the mdi or aliases. I'd actually be tempted to not even define them to prevent them hanging around forever and just do a migration as part of the next server update.
#

@abstract trench I'm thinking if the rate of change is low, we can literally just convert the SVGs to vector assets by hand (I volunteer as tribute) and create an id to asset map. This is a small enough set for that. If we have to change/add an icon later, it's a very small amount of work to convert and alter the mappings. Again, that depends on us thinking of this as a low rate of change set: if this repo is accepting a new icon every week it will get very taxing.

woven mesa
#
  1. So i just put a couple icons to just show the process but the goal would be to decide now which icon we want to have there and add new ones if really needed but it'll be rare i think
  2. Yeah the goal, is to remove the prefix and use default like speaker and so on
mellow widget
abstract trench
#

Guys, how do we deal with beta server?
We're getting issues related to beta like several days a week.
With the way MA server is, I can't run both stable and beta simultaneously. For that I would need to have another Docker server, which I don't want. And I use stable, because my family is listening music often.

#

So switching to beta sometimes is okayish - but not having it permanently (which required for development)

mellow widget
# abstract trench Guys, how do we deal with beta server? We're getting issues related to beta like...

Something that's confusing me is that it appears we're getting breaking changes introduced to the API by 2.10 - I'd usually expect an API for a server to maintain backwards compatibility between minor versions, but that doesn't seem to be the case. I see the API also has a schema version that versions separately from the server version, but 2.10's minimum supported version is the same as 2.9's (28).

mellow widget
abstract trench
abstract trench
mellow widget
abstract trench
#

Our app usually is older than server.

mellow widget
#

What is min_supported_schema_version for then? My guess would have been that the server would support clients using that schema version (so it's backwards compatible to that).

#

I guess the question is: what version (for the server) changing indicates that a breaking change could occur in the API? Should we expect that on:

  • server_version
  • schema_version
  • min_supported_schema_version

The current experience seems to be that it's schema_version, but I'd like to confirm that's intended and not just mistakes slipping through.

abstract trench
#

Well MAX version belongs to the app code, it's not server value 🙂

fast grove
#

we bump the schema version if we make breaking changes to non-important api commands or ADD new api commands
we bump the min_supported_schema_version if there is a backwards incompatible change to major api functions. Ofcourse we try to keep that at a minimal - last time was with the introduction of mandatory auth

abstract trench
#

I'm merging related PR

fast grove
#

So what we do on frontend is we have a nightly, beta and stable channel there as well

#

I'm proposing the app should do the same.
stable version (on app store) can only work with MA stable
beta version only compatible with beta version of MA
otherwise you need a lot of "if schema version blah" hacks in your code

#

2.10 has a lot of changes (more than usual) but also a lot of that came more or less from discussion with you guys 😉

  • serverside translations
  • optimized search
  • optimized recomendations
  • new audio pipelines
abstract trench
#

Ah, so we want to check OUR schema against server min, instead of current server schema against our max supported.

#

But we're still getting troubles pretty often with beta

#

More often than it would be comfortable

fast grove
abstract trench
fast grove
#

Or accept some schema version checks in your code if you want one app version to be compatible with multiple schema versions but imo that can get ugly fast

abstract trench
#

We just have beta now. But it's app beta, not correspondence to server beta

fast grove
abstract trench
#

Since we're moving fast with changes, would be nice to have something that we can release quicker than once per 2 weeks... GPlay is awful.

abstract trench
fast grove
#

The betas of MA server are rather stable (as they are first tested on nightly)
And my guess is that people willing to use a beta of the app are also the ones that run MA server beta

abstract trench
#

You guys are introducing new changes every day

#

🙂

fast grove
#

yeah but that is because in this release we are making some foundational changes that were long due

abstract trench
abstract trench
#

All my dev experience talks for it.

fast grove
#

so that is why you need 2 release chnanels

abstract trench
#

Well we do need stable - but we need Play Store listing for this, and I'm asking you guys to check Privacy Policy for a month 😉

#

And iOS TestFlight is still on Teancom's private account.

fast grove
fast grove
mellow widget
#

Ok so just to recap here: we shouldn't expect breaking changes without min_supported_schema_version also incrementing (which is what I'd hoped from the property name). If we do get breaking changes without it incrementing, we should raise an issue with the server rather than trying to work around it in the client.

fast grove
#

Not really
we did make some breaking changes to non critical commands

#

without bumping "min_supported_schema_version"

#

but ofc that is kept to a minimal - we always try to keep it backwards compatibel since we also have to deal with HA

#

so it will more be a behavioral change then

#

search is a good example - it accepts some additional filter parameters now but the old command still works

#

the only one that is breaking is recommendations

#

server side translations are also backwards compatible

#

So the python client (used by HA) has logic where it handles a command per schema version

mellow widget
#

So does schema_version always increment whenever a breaking change is made or just whenever anything changes?

fast grove
#

again, breaking changes are very rare
the schema is bumped when a new feature is added or an existing one modified

#

so a client can check against that schema version to know if a feature is supported

abstract trench
#

I merged some changes and adding more. The behaviour will be: if app schema is < minimal - terminal doalog is shown, app is closed. Otherwise if app schema < server schema - warning dialog shown, app works.

mellow widget
#

@abstract trench right that works nicely for the current scenario. I do think for API consumers, it'd be best to always increment min_support_schema_version for any breaking change (even if the team feels it's "non-critical") though @fast grove. That way, clients can be confident that things will work as long as they speak min_support_schema_version and only need to care about schema_version for if the server supports a newer feature or not.

abstract trench
#

Later we can move user to the app distribution channel (GPlay/GHub) together with closing the app.

mellow widget
#

That's what I'm saying. "for any breaking change".

abstract trench
#

Just wanted to double-stress

fast grove
#

Models / api responses are always backwards compatible to avoid breaking clients btw - they contain logic for that

#

I can still boot a 3 months old HA instance and happily connect it to a nightly MA server

#

The one time where everything was breaking was with the auth support

#

So maybe instead of talking in theory we can zoom in on what you experience in the app ?
Because as far as I'm aware an app created for stable api schema schould connect and work just fine with a MA beta/nightly - it will just miss out on functionality

mellow widget
abstract trench
#

Case is that our deserialization is strict - it's Json, so if there's no field that isn't marked as nullable with default value null - the request will fail.

#

So we need to scrap through the server DTO, and check what is nullable.

fast grove
#

hmmm that is a big difference then between python and javascript
most of our fields are nullable/optional

abstract trench
#

Our schema is still pretty casual actually.

fast grove
#

Do you use the models repo ? Because that is where all the models live
Or the api-docs ofc

abstract trench
fast grove
abstract trench
#

We use api mostly

#

Yes

#

We just make some minimal objects, omitting fields we don't need.

fast grove
#

Ok well, when we do a change to a model its always additions. And if there is a field deprecated, it will still be sent for backwards compat

abstract trench
#

Basically saving on deserialization and memory, and code 🙂

abstract trench
#

(probably)

#

This leads to app crash

#

So this considered breaking change.

fast grove
#

probably it has always been nullable then

#

big change in server is that a large listing now does not send the optional fields anymore to slim down the listing.
we were sending multi megabyte messages to get one page of tracks for example

abstract trench
#

Yeah, I reckon

fast grove
#

Maybe good if we write a good parser that can do a sanity check of the models repo to kotlin and flag issues

abstract trench
#

Still question stands - as a dev, I probably HAVE to keep beta server running.

abstract trench
#

If field is nullable in model, we should treat it and handle null by design. There will be no troubles.

#

Until there's field that was non-null and became null 🙂

fast grove
abstract trench
#

And if there's nullable field that becomes non-null on server, we will be getting errors in calls. No crashes, just errors.

#

But It's not the case as well I guess.

fast grove
#

correct

abstract trench
#

So I just need to sweep on schema to make sure it corresponds to nullability in models.

fast grove
#

how do you handle nullable fields that are omited from the response ?
because that is something we do

abstract trench
#

Other things should be fine.

abstract trench
#

That's fine.

fast grove
#

OK all good then

#

Then its a case of going over the models defined in Kotlin and correct the cases where now is not nullable

#

For example, all metadata fields are optional so they are nullable

abstract trench
#

Doing it already.

#

It was long overdue, now I know the essentials.

mellow widget
# fast grove That is not going to happen sorry - then we will break HA compatibility even wit...

Just catching up and this confused me as it sounds like you're describing min_supported_schema_version as exactly what I'm asking for elsewhere (the server defining the oldest schema it is backwards compatible with). I realize I didn't define what I meant by "breaking changes" though: I'd meant "is not backwards compatible" rather than "happens to break a client". The difference is subtle, but an example like us having an optional parameter as non-null breaking things is the latter, not the former: the actual API contract hasn't been broken.

#

Anyway, looks like @abstract trench has now made sure the app doesn't launch when we end up with a min_supported_schema_version we don't expect, so that should solve any future big changes from breaking the app, and hopefully all of the issues we ran into were just nullable/non-null mismatches rather than actual changes in the API contract (I see @abstract trench's also reviewed and updated those).

fast grove
#

Yes, the only exception to this rule is the changes on recommendations - on the 2.10 path you simply do not get the items anymore when you fetch them (but api still returns items as an empty array) - you actually need to fetch the items for each recommendation row. It's not a breaking change in terms of API/schema but a behavior change we had to make due to the performance issues caused by fetching all these recommendations in one single call.

abstract trench
#

Are fetch methods for recommendations available on 2.9 (schema 31)? Or is it new thing?

fast grove
#

the old command still returns all recommendations that are available (but with items set to an empty array)

#

you have a dedicated command to fetch the recommendation row items you are actually interested in (or what the user has enabled)

#

frontend uses userpreferences to store enabled recomemndation rows, would make sense if mobile app uses the same ?

abstract trench
#

So there should be "if schema > 31".

fast grove
abstract trench
fast grove
abstract trench
fast grove
abstract trench
abstract trench
fast grove
#

recommendations change was done in api schema 39

#

then something else in 40

#

something else in 41

#

40 = for the config flow changes (not relevant to the mobile app)

abstract trench
#

39 then...
How do we track these? Apart from asking?

fast grove
#

41 is for the ai radio plugin

fast grove
#

an automated ping would be the best I guess

#

if a PR has a schema bump, there is a notification (or we simply auto append a label)

#

Let's setup some github actions to keep track of this

abstract trench
abstract trench
#

@mellow widget I think you may lay the foundation of loading home page on schema 39+ with your current PR. Probably worth making some abstract multi-row loader?

mellow widget
abstract trench
mellow widget
#

Yes I definitely think we need that for the artist page so was going to build it out a skeleton/placeholder loading mode for CategoryRow.

#

You've probably noticed me indulging in a bit of microframework building, so you'll this is music to my ears 😂

abstract trench
#

@fast grove recently there were changes to the WebRTC, that also brought breaking changes to the mobile client.
Even if we will have enough enthusiasm to read every server PR in order to check if that brings something breaking to the client - corresponding changes to the mobile should be developed, merged and tested. Meanwhile bold part of our users (using beta) will have bad experience.
Not to brag, just to support the point that server and clients should move together - or we just accept that users using beta will experience troubles pretty often.

fast grove
mortal wadi
#

Yep I talked to @brave sentinel about this. But, looking at my communication, I could have been a bit clearer about this. So that's my bad, sorry. Do you guys need a hand pointing you in the right direction?

abstract trench
mortal wadi
abstract trench
white breach
mortal wadi
#

@abstract trench Do you need me to submit a draft PR to the mobile repo based on my frontend changes?

abstract trench
abstract trench
shrewd crown
abstract trench
mortal wadi
#

We should synchronize changes better, 100%. Like I said above, I should have let you guys know when this hit nightly. But still, if you guys are on holiday or what not and we cut a beta, then there is still a risk of mobile breaking in beta..

#

On the upside. Web RTC has been ROCK solid since we moved to the new lib and chunked responses, so hope you have the same experience on mobile

shrewd crown
# abstract trench That's what I'm talking about: are we intended to discard any issue with beta se...

I understand both sides but where do you see a problem with issues at a GitHub repo?

My proposal would be:

  • mobile app should not be supported by nightly (all issues are closed)
  • Mobile App should work with RC candidates beta may break things, and those issues should be auto-commented that this is a beta version and should get closed or marked as stale as long as release candidate is not available yet
  • The mobile app should reject to work with nightly and should warn the user that he’s using a beta version
#
  • the user should be more chilled when using a OPEN SOURCE MOBILE APP without a big corporate company behind!!!!
abstract trench
abstract trench
#

We already added (yesterday) warning if server schema version is newer than app has.

#

But all things "should" just don't work with open source:)

mortal wadi
#

I think there's another way to look at this. Beta becomes stable eventually, so closing issues on beta is not the solution in my opinion, because, something is not working well. We also have plenty of issues reported on the beta channel, which help us solve issues together with our beta testers before we release anything to stable.

#

That said, once we reach v1.0, it might be an idea to split the mobile app in stable / nonstable and do the same thing we do with MA: At release time, promote nonstable > stable and do a release

fast grove
mortal wadi
#

Ah I missed that.

abstract trench
fast grove
#

what we need is a bot that flags when the schema is changed and reports what was changed - and regular schema changes may only be additionals or behavioral changes. if breaking: bump the minimal schema version

fast grove
#

We also have to account for API stability with HA so it's not only mobile app

abstract trench
fast grove
abstract trench
# fast grove yes but that was; - unavoidable (and also communicated by Marvin) - not related ...

Yeah, I'm talking here about changes like this - not just schema, but any breaking change. We need to have better way to support these.
I work with big team (on my daily job), which has synced BE and FE releases. Basically, if server has it - then app has it too.
I realize that it's too much changes to keep another product in the loop. Mobile app releases could pull server back, which is more than inconvenience - because vast majority of users is using server through web, so it's automatically available to them with release.

#

Just want to come to common denominator here.

fast grove
#

I think somebody implementing something in the backend that hits core/models (so it impacts the api) should also open a draft PR on all affected projects - we already do this for frontend but we often forget to update the python client and mobile app is completely forgotten.

Or at least create a message here with the changes.

thorny trail
#

we could have the AI Code Review process try to make a pass and flag items that it thinks would have an impact on the mobile client?

mellow widget
fast grove
#

If we ever need to a breaking change we bump minimum_supported_schema_version
so far that has only happened a few times and the last time was the auth support
I'm not expecting that we need to do it again (but never say never)

mellow widget
#

Right, so I'm not sure client teams need a notification any time there's any change as it shouldn't be a problem.

#

I'm not familiar with the WebRTC changes, but maybe a good improvement to communicating changes would be for there to be a published changelog (ideally actually before they're out in the wild) of changes to just the API (breaking protocol changes or minimum_supported_schema_version increments) that client developers can follow? MA is a single server/multi client ecosystem as far as I can see, so it'll be a lot of work (and I'd imagine more and more as time goes on) for the server team to individually keep every client updated on coming changes.

fast grove
#

Yeah, that is where we have the changelog for but it is also a lot of work for you guys to treverse it and hunt for things you also like to implement in the app

#

So that is where the idea of a bot comes in:
as soon as the api schema is bumped and/or a command was added/changed, a notification here or somewhere else

mellow widget
#

I think that'd work well

#

But I'd also be happy with a changelog just for the API that can be easily followed. That might be more work I guess!

fast grove
#

Example: today I added a "queue_ended" field on the PlayerQueue object.
it is a signal towards frontend to show a pretty message that the whole queue was consumed (and auto play is not enabled) instead of doing guesswork based on the index.
Not an important change but might be interesting to know about

mellow widget
#

Could the bot post to a dedicated channel, so other clients could follow it as well? I think posting here makes it less visible for others building different clients.

mellow widget
fast grove
mellow widget
#

I think that's a really nice next step - if problems then come up down the line due to some change in the API not being dealt with, we can discuss again.

#

And @abstract trench, I don't think we should discard issues about the beta as they'll (usually) be things we do want to deal with. I don't think we should think about them as "stop everything and fix this" production issues though. We support stable and one previous version, we'd only need to fix issues with the beta in preparation for it being the next stable.

#

Ideally if this idea of the changelog/bot does its job, we'd hopefully be closing these issues as duplicates to things we'd already have written ourselves though I guess!

abstract trench
brave sentinel
#

Just a note that yes, Marvin had pinged me directly that some WebRTC changes were coming soon but, because he's human, didn't follow up with a "BTW, that's happening now, here's the PRs with the actual change". And (as format has mentioned) I don't read all the server changes, so when I updated my dev server a week later I'd completely forgotten about that and was confused. 😅

fast grove
#

Thanks for the discussion folks, this is how we learn and improve!

mellow widget
#

Just a heads-up that Android Studio Quail 3 upgrades the included JVM to 25 which will break development for us 😒

#

We'll need to at least upgrade detekt which looks like it only looks like it supports 25 in its new 2.0.0 alpha. For now, you'll need to install and configure a 21 JDK separately.

abstract trench
mellow widget
#

Have you tried a detektAll?

#

It might just be detekt that's the problem I guess

abstract trench
#

True, detekt fails

mellow widget
#

I was just doing a quick thing in between other work, so didn't have a chance to look updating detekt. For now, I've just got my JAVA_HOME pointing at OpenJDK 21 and then have Android Studio set to use JAVA_HOME.

#

But we'll need to either upgrade detekt, or just update our dev env docs.

mortal wadi
#

@fast grove Let's add a label mobile-app-impact (maybe even a second mobile-app-breaking) to the server repo that we either set manually (or via the checklist) on every PR. That way the mobile folks can easily filter (and even get notifiied) about PRs that have direct impact. As a bonus, let's add in to our CLAUDE.md file that Claude will automatically scan for impact and set this checkbox.

fast grove
mortal wadi
viscid pine
#

Is this limitation where volume control is disabled still the case? Is it possible to allow the volume control if “Hide this player in the user interface” is unchecked? Or perhaps another check that is on by default called “Disable volume control in the user interface”?

I use iPads as touch screen controls for my various sound systems around the house. I would like to be able to use the iPads as the audio source as well, but cannot currently as I am unable to adjust the volume without walking over to each device and manually adjusting.

abstract trench
viscid pine
white breach
viscid pine
white breach
viscid pine
abstract trench
viscid pine
abstract trench