diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
index fe63bb677dc7c018519fa0fb0fecb445e5256c67..f8467b458e43862c587a34f34c06af8fbbf30d0f 100644
--- a/.idea/kotlinc.xml
+++ b/.idea/kotlinc.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project version="4">
   <component name="KotlinJpsPluginSettings">
-    <option name="version" value="1.9.23" />
+    <option name="version" value="1.9.10" />
   </component>
 </project>
\ No newline at end of file
diff --git a/app/src/main/java/net/novagamestudios/kaffeekasse/App.kt b/app/src/main/java/net/novagamestudios/kaffeekasse/App.kt
index 996f2fa36017a60a000129d7cc4ee80a5a0db430..2bfe4619527be652f9e818c959a269ebcc0ce8d9 100644
--- a/app/src/main/java/net/novagamestudios/kaffeekasse/App.kt
+++ b/app/src/main/java/net/novagamestudios/kaffeekasse/App.kt
@@ -19,22 +19,24 @@ import kotlinx.coroutines.plus
 import net.novagamestudios.common_utils.Logger
 import net.novagamestudios.common_utils.compose.application
 import net.novagamestudios.common_utils.compose.state.loadInitialBlocking
-import net.novagamestudios.common_utils.debug
+import net.novagamestudios.common_utils.error
 import net.novagamestudios.common_utils.info
 import net.novagamestudios.common_utils.toastShort
-import net.novagamestudios.kaffeekasse.api.portal.PortalClient
+import net.novagamestudios.common_utils.warn
 import net.novagamestudios.kaffeekasse.api.hiwi_tracker.HiwiTrackerAPI
 import net.novagamestudios.kaffeekasse.api.hiwi_tracker.HiwiTrackerScraper
 import net.novagamestudios.kaffeekasse.api.kaffeekasse.KaffeekasseAPI
 import net.novagamestudios.kaffeekasse.api.kaffeekasse.KaffeekasseScraper
-import net.novagamestudios.kaffeekasse.repositories.UpdateController
+import net.novagamestudios.kaffeekasse.api.portal.PortalClient
 import net.novagamestudios.kaffeekasse.gitlab.GitLab
-import net.novagamestudios.kaffeekasse.repositories.releases.GitLabReleases
+import net.novagamestudios.kaffeekasse.repositories.Credentials
+import net.novagamestudios.kaffeekasse.repositories.SettingsRepository
+import net.novagamestudios.kaffeekasse.repositories.UpdateController
 import net.novagamestudios.kaffeekasse.repositories.i11.HiwiTrackerRepository
 import net.novagamestudios.kaffeekasse.repositories.i11.KaffeekasseRepository
-import net.novagamestudios.kaffeekasse.repositories.Credentials
 import net.novagamestudios.kaffeekasse.repositories.i11.PortalRepository
 import net.novagamestudios.kaffeekasse.repositories.newSettingsStore
+import net.novagamestudios.kaffeekasse.repositories.releases.GitLabReleases
 
 
 class App : Application(), CoroutineScope by MainScope() + CoroutineName(App::class.simpleName!!), Logger {
@@ -43,22 +45,23 @@ class App : Application(), CoroutineScope by MainScope() + CoroutineName(App::cl
         super.onCreate()
         instanceOrNull = this
         info { "App instance available" }
-        settingsStore.loadInitialBlocking()
+        try {
+            settingsRepository.loadInitialBlocking()
+        } catch (e: Throwable) {
+            error(e) { "Failed to load initial settings" }
+            toastShort("Failed to load settings: ${e.message}")
+            throw e
+        }
         launch {
             try {
                 releases.fetchNewerReleases()
             } catch (e: Throwable) {
-                debug(e) { "Failed to fetch newer releases" }
+                warn(e) { "Failed to fetch newer releases" }
                 toastShort("Failed to check for updates: ${e.message}")
             }
         }
-//        ScreenRegistry {
-//            modules.forEach { it.applyScreenModule() }
-//        }
     }
 
-
-
     companion object : Logger {
         var instanceOrNull: App? = null
             private set
@@ -80,15 +83,27 @@ class App : Application(), CoroutineScope by MainScope() + CoroutineName(App::cl
         ): T = with(app()) {
             LocalNavigator.currentOrThrow.rememberNavigatorScreenModel { factory() }
         }
+
+        @Composable
+        fun settings(): SettingsRepository = app().settingsRepository
+
+        val developerMode: Boolean @Composable get() = settings().value.developerMode
     }
 
-    val settingsStore = newSettingsStore(this)
+
+    // Settings stuff
+    val settingsRepository = SettingsRepository(
+        app = this,
+        settingsStore = newSettingsStore(this)
+    )
     val credentials by lazy {
         Credentials(
             credentialManager = CredentialManager.create(this),
-            settingsStore = settingsStore
+            settingsStore = settingsRepository
         )
     }
+
+    // Update stuff
     val gitLab = GitLab(
         instanceUrl = "https://git.rwth-aachen.de",
         projectPath = "jonas.broeckmann/kaffeekasse",
@@ -96,6 +111,8 @@ class App : Application(), CoroutineScope by MainScope() + CoroutineName(App::cl
     )
     val releases = GitLabReleases(gitLab)
     val updateController = UpdateController(this)
+
+    // I11 stuff
     private val portalClient = PortalClient(this)
     val kaffeekasseRepository = KaffeekasseRepository(
         coroutineScope = this,
@@ -113,6 +130,7 @@ class App : Application(), CoroutineScope by MainScope() + CoroutineName(App::cl
         hiwiTrackerRepository
     )
 
+    // Active app modules
     val modules = AppModules(
         KaffeekasseModule,
         HiwiTrackerModule
diff --git a/app/src/main/java/net/novagamestudios/kaffeekasse/MainActivity.kt b/app/src/main/java/net/novagamestudios/kaffeekasse/MainActivity.kt
index 798eca549c96192f9e135514e7a5e895d80a65a1..496c2bc48ae75d025dc0223a5abcd8a194d1db9c 100644
--- a/app/src/main/java/net/novagamestudios/kaffeekasse/MainActivity.kt
+++ b/app/src/main/java/net/novagamestudios/kaffeekasse/MainActivity.kt
@@ -3,24 +3,12 @@ package net.novagamestudios.kaffeekasse
 import android.os.Bundle
 import androidx.activity.ComponentActivity
 import androidx.activity.compose.setContent
-import androidx.activity.viewModels
-import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.runtime.CompositionLocalProvider
-import androidx.compose.ui.Modifier
-import androidx.lifecycle.ViewModelStoreOwner
-import androidx.lifecycle.viewmodel.CreationExtras
-import androidx.lifecycle.viewmodel.MutableCreationExtras
-import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner
-import androidx.lifecycle.viewmodel.compose.viewModel
 import net.novagamestudios.common_utils.LocalLogger
 import net.novagamestudios.common_utils.Logger
 import net.novagamestudios.common_utils.error
-import net.novagamestudios.common_utils.info
-import net.novagamestudios.kaffeekasse.repositories.LocalSettingsStore
 import net.novagamestudios.kaffeekasse.ui.App
-import net.novagamestudios.kaffeekasse.ui.AppViewModel
 import net.novagamestudios.kaffeekasse.ui.theme.KaffeekasseTheme
-import kotlin.time.measureTimedValue
 
 class MainActivity : ComponentActivity() {
     override fun onCreate(savedInstanceState: Bundle?) {
@@ -29,8 +17,7 @@ class MainActivity : ComponentActivity() {
         setContent {
             val app = app()
             CompositionLocalProvider(
-                LocalLogger provides app,
-                LocalSettingsStore provides app.settingsStore
+                LocalLogger provides app
             ) {
                 KaffeekasseTheme {
                     App()
diff --git a/app/src/main/java/net/novagamestudios/kaffeekasse/repositories/Settings.kt b/app/src/main/java/net/novagamestudios/kaffeekasse/repositories/Settings.kt
index 8611ae09f30bae6d02326488eaa8293359b8adec..821d6685d1e493cccce722fd3700740b0851b48c 100644
--- a/app/src/main/java/net/novagamestudios/kaffeekasse/repositories/Settings.kt
+++ b/app/src/main/java/net/novagamestudios/kaffeekasse/repositories/Settings.kt
@@ -3,7 +3,6 @@ package net.novagamestudios.kaffeekasse.repositories
 import android.content.Context
 import androidx.compose.foundation.isSystemInDarkTheme
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.staticCompositionLocalOf
 import androidx.datastore.core.MultiProcessDataStoreFactory
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.serialization.ExperimentalSerializationApi
@@ -14,7 +13,6 @@ import kotlinx.serialization.serializer
 import net.novagamestudios.common_utils.JsonToDataStore
 import net.novagamestudios.common_utils.compose.state.DataStoreState
 import net.novagamestudios.common_utils.compose.state.MutableDataStoreState
-import net.novagamestudios.common_utils.compose.state.rememberMockedDataStoreState
 import net.novagamestudios.common_utils.compose.state.stateIn
 import net.novagamestudios.kaffeekasse.model.credentials.DeviceCredentials
 import java.io.File
@@ -23,12 +21,9 @@ import java.io.File
 data class Settings(
     val themeMode: ThemeMode = ThemeMode.Dark,
     val autoLogin: Boolean = false,
-    @Deprecated("Use favoriteItemIds instead", ReplaceWith("favoriteItemIds"))
-    val favoriteItems: List<String> = emptyList(),
-    val favoriteItemIds: List<Int> = favoriteItems.mapNotNull { it.toIntOrNull() },
-    val lastSelectedModule: String? = null,
     val deviceCredentials: DeviceCredentials? = null,
-    val developerMode: Boolean = false
+    val developerMode: Boolean = false,
+    val userSettings: Map<String, UserSettings> = emptyMap()
 ) {
 
     enum class ThemeMode {
@@ -42,24 +37,24 @@ data class Settings(
             ThemeMode.Light -> false
         }
 
-        internal val serializersModule = SerializersModule {
-
-        }
+        internal val serializersModule = SerializersModule { }
+    }
+}
 
+@Serializable
+data class UserSettings(
+    val favoriteItemIds: List<Int> = emptyList(),
+    val lastSelectedModule: String? = null
+) {
+    companion object {
+        val Empty = UserSettings()
     }
 }
 
+
 typealias MutableSettingsStore = MutableDataStoreState<Settings>
 typealias SettingsStore = DataStoreState<Settings>
 
-val LocalSettingsStore = staticCompositionLocalOf<MutableSettingsStore> {
-    throw NoSuchElementException()
-}
-
-private val settingsValidator: Settings.(Settings?) -> Settings = {
-    this
-}
-
 @OptIn(ExperimentalSerializationApi::class)
 fun Context.newSettingsStore(
     coroutineScope: CoroutineScope
@@ -79,8 +74,6 @@ fun Context.newSettingsStore(
     }
 ).stateIn(coroutineScope, settingsValidator)
 
-@Composable
-fun rememberMockedSettingsStore(initial: Settings = Settings()) = rememberMockedDataStoreState(
-    initial = initial,
-    validator = settingsValidator
-)
+private val settingsValidator: Settings.(Settings?) -> Settings = {
+    this
+}
diff --git a/app/src/main/java/net/novagamestudios/kaffeekasse/repositories/SettingsRepository.kt b/app/src/main/java/net/novagamestudios/kaffeekasse/repositories/SettingsRepository.kt
new file mode 100644
index 0000000000000000000000000000000000000000..528a8d6d971e0bfa3b71c28aa611d1924fa56d61
--- /dev/null
+++ b/app/src/main/java/net/novagamestudios/kaffeekasse/repositories/SettingsRepository.kt
@@ -0,0 +1,46 @@
+package net.novagamestudios.kaffeekasse.repositories
+
+import kotlinx.coroutines.flow.StateFlow
+import net.novagamestudios.common_utils.compose.state.MutableDataStoreState
+import net.novagamestudios.kaffeekasse.App
+import net.novagamestudios.kaffeekasse.util.mapState
+
+class SettingsRepository(
+    app: App,
+    settingsStore: MutableSettingsStore
+) : MutableSettingsStore by settingsStore {
+    val userSettings: StateFlow<MutableDataStoreState<UserSettings>?> by lazy {
+        app.portalRepository.currentUser.mapState { user ->
+            if (user == null) return@mapState null
+            val key = user.user ?: return@mapState null
+            UserSettingsStore(key, settingsStore)
+        }
+    }
+}
+
+
+private class UserSettingsStore(
+    private val userKey: String,
+    private val settingsStore: MutableSettingsStore
+) : MutableDataStoreState<UserSettings> {
+    private fun Settings.map() = userSettings.getOrElse(userKey) { UserSettings.Empty }
+    private fun Updater<UserSettings>.wrapped(): Updater<Settings> = { settings ->
+        val new = this(settings.map())
+        if (new == UserSettings.Empty) {
+            settings.copy(userSettings = settings.userSettings - userKey)
+        } else {
+            settings.copy(userSettings = settings.userSettings + (userKey to new))
+        }
+    }
+
+    override val value: UserSettings get() = settingsStore.value.map()
+    override val values: StateFlow<UserSettings> get() = settingsStore.values.mapState { settings -> settings.map() }
+
+    override suspend fun loadInitial() = throw UnsupportedOperationException()
+    override fun provideInitial(value: UserSettings) = throw UnsupportedOperationException()
+
+    override fun tryUpdate(updater: suspend (UserSettings) -> UserSettings) = settingsStore.tryUpdate(updater.wrapped())
+    override suspend fun update(updater: suspend (UserSettings) -> UserSettings) = settingsStore.update(updater.wrapped())
+}
+
+private typealias Updater<T> = suspend (T) -> T
diff --git a/app/src/main/java/net/novagamestudios/kaffeekasse/repositories/i11/KaffeekasseRepository.kt b/app/src/main/java/net/novagamestudios/kaffeekasse/repositories/i11/KaffeekasseRepository.kt
index ee38cc77f1bd64b83f2fd1db5f4f02b7f850523d..1587110a15e26149b55e5a5bc2148c07ec157930 100644
--- a/app/src/main/java/net/novagamestudios/kaffeekasse/repositories/i11/KaffeekasseRepository.kt
+++ b/app/src/main/java/net/novagamestudios/kaffeekasse/repositories/i11/KaffeekasseRepository.kt
@@ -185,11 +185,12 @@ class KaffeekasseRepository(
         requireLoggedInUser()
         requireLoggedInDevice()
         cart.forEach { (item, count) ->
-            api.purchase(
+            val result = api.purchase(
                 itemId = item.id,
                 count = count,
                 targetUserId = targetAccount?.id
-            )
+            ).mapToRichDataState { this }
+            if (result is RichData.Error) throw IllegalStateException(result.messages.joinToString("\n"))
         }
         markBalanceDataDirty()
     }
diff --git a/app/src/main/java/net/novagamestudios/kaffeekasse/ui/App.kt b/app/src/main/java/net/novagamestudios/kaffeekasse/ui/App.kt
index 48a307d23cfce72aa14392b2aae8e85d8bd07b14..2c037a64794f1fae4a04f1362ddc30628e32ca53 100644
--- a/app/src/main/java/net/novagamestudios/kaffeekasse/ui/App.kt
+++ b/app/src/main/java/net/novagamestudios/kaffeekasse/ui/App.kt
@@ -69,7 +69,7 @@ import net.novagamestudios.kaffeekasse.AppModules
 import net.novagamestudios.kaffeekasse.HiwiTrackerModule
 import net.novagamestudios.kaffeekasse.KaffeekasseModule
 import net.novagamestudios.kaffeekasse.model.credentials.isUser
-import net.novagamestudios.kaffeekasse.repositories.MutableSettingsStore
+import net.novagamestudios.kaffeekasse.repositories.SettingsRepository
 import net.novagamestudios.kaffeekasse.repositories.i11.PortalRepository
 import net.novagamestudios.kaffeekasse.ui.hiwi_tracker.HiwiTrackerTopBarActions
 import net.novagamestudios.kaffeekasse.ui.hiwi_tracker.HiwiTrackerTopBarTitle
@@ -80,7 +80,7 @@ import net.novagamestudios.kaffeekasse.util.collectAsStateHere
 
 
 class AppViewModel private constructor(
-    val mutableSettingsStore: MutableSettingsStore,
+    val settingsRepository: SettingsRepository,
     private val portal: PortalRepository,
     private val allModules: AppModules
 ) : ScreenModel, Logger {
@@ -91,14 +91,16 @@ class AppViewModel private constructor(
 
     val modules: AppModules get() {
         return when {
-            mutableSettingsStore.value.developerMode -> allModules
+            settingsRepository.value.developerMode -> allModules
             currentDevice != null -> AppModules(allModules.filter { it == KaffeekasseModule })
             else -> allModules
         }
     }
 
+    val userSettings by settingsRepository.userSettings.collectAsStateHere()
+
     val initialModule get() = modules
-        .find { it.id == mutableSettingsStore.value.lastSelectedModule }
+        .find { it.id == userSettings?.value?.lastSelectedModule }
         ?: modules.first()
 
     fun Tab.moduleOrNull() = modules.singleOrNull { it.navigationTab == this }
@@ -106,7 +108,7 @@ class AppViewModel private constructor(
     companion object {
         @Composable fun vm() = App.globalScreenModel {
             AppViewModel(
-                mutableSettingsStore = settingsStore,
+                settingsRepository = settingsRepository,
                 portal = portalRepository,
                 allModules = modules
             )
@@ -143,7 +145,7 @@ fun App(
             }
             LaunchedEffect(tabNavigator.current) {
                 val module = with(vm) { tabNavigator.current.moduleOrNull() }
-                if (module != null) vm.mutableSettingsStore.tryUpdate {
+                if (module != null) vm.userSettings?.tryUpdate {
                     it.copy(lastSelectedModule = module.id)
                 }
             }
diff --git a/app/src/main/java/net/novagamestudios/kaffeekasse/ui/Login.kt b/app/src/main/java/net/novagamestudios/kaffeekasse/ui/Login.kt
index fa95cf1f92e2b7604913942c21e0e3969d7199cb..d7ff037a80c25fb9488d95b2f49f1706abbb2f81 100644
--- a/app/src/main/java/net/novagamestudios/kaffeekasse/ui/Login.kt
+++ b/app/src/main/java/net/novagamestudios/kaffeekasse/ui/Login.kt
@@ -272,7 +272,7 @@ class LoginViewModel private constructor(
     companion object {
         @Composable fun vm() = net.novagamestudios.kaffeekasse.App.navigatorScreenModel {
             LoginViewModel(
-                mutableSettingsStore = settingsStore,
+                mutableSettingsStore = settingsRepository,
                 credentials = credentials,
                 portal = portalRepository,
                 kaffeekasse = kaffeekasseRepository
diff --git a/app/src/main/java/net/novagamestudios/kaffeekasse/ui/Updates.kt b/app/src/main/java/net/novagamestudios/kaffeekasse/ui/Updates.kt
index 118ee55746a08738bfbd5bbd01f219b2b19b8cf7..62b2bceb0d9abb07ffabfa59770995073f2b0ee4 100644
--- a/app/src/main/java/net/novagamestudios/kaffeekasse/ui/Updates.kt
+++ b/app/src/main/java/net/novagamestudios/kaffeekasse/ui/Updates.kt
@@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.widthIn
 import androidx.compose.foundation.rememberScrollState
 import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.foundation.verticalScroll
@@ -21,7 +22,6 @@ import androidx.compose.material3.Button
 import androidx.compose.material3.HorizontalDivider
 import androidx.compose.material3.Icon
 import androidx.compose.material3.IconButton
-import androidx.compose.material3.ListItem
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.OutlinedButton
 import androidx.compose.material3.Switch
@@ -51,6 +51,7 @@ import net.novagamestudios.common_utils.compose.components.CircularLoadingBox
 import net.novagamestudios.common_utils.compose.components.ColumnCenter
 import net.novagamestudios.common_utils.compose.components.LinearProgressIndicator
 import net.novagamestudios.common_utils.compose.components.RowCenter
+import net.novagamestudios.common_utils.compose.components.TransparentListItem
 import net.novagamestudios.common_utils.compose.state.ReentrantActionState
 import net.novagamestudios.common_utils.compose.state.collectAsStateIn
 import net.novagamestudios.common_utils.toastLong
@@ -60,9 +61,8 @@ import net.novagamestudios.kaffeekasse.model.app.AppRelease
 import net.novagamestudios.kaffeekasse.model.app.AppVersion
 import net.novagamestudios.kaffeekasse.model.date_time.format
 import net.novagamestudios.kaffeekasse.repositories.InstallStatus
-import net.novagamestudios.kaffeekasse.repositories.LocalSettingsStore
-import net.novagamestudios.kaffeekasse.repositories.releases.Releases
 import net.novagamestudios.kaffeekasse.repositories.UpdateController
+import net.novagamestudios.kaffeekasse.repositories.releases.Releases
 import net.novagamestudios.kaffeekasse.util.openInBrowser
 import java.time.format.DateTimeFormatter
 
@@ -292,6 +292,7 @@ private fun AppInfoDialog(
             }
         }
     },
+    modifier = Modifier.widthIn(max = 400.dp),
     icon = { Icon(Icons.Default.Info, null) },
     title = { Text("Kaffeekasse") },
     text = {
@@ -319,12 +320,12 @@ private fun AppInfoDialog(
             Spacer(Modifier.height(16.dp))
             Text("Made with love\nby\nJonas Broeckmann", textAlign = TextAlign.Center)
             Spacer(Modifier.height(16.dp))
-            val settingsStore = LocalSettingsStore.current
-            ListItem(
+            val settings = App.settings()
+            TransparentListItem(
                 headlineContent = { Text("Developer mode") },
                 trailingContent = { Switch(
-                    settingsStore.value.developerMode,
-                    onCheckedChange = { new -> settingsStore.tryUpdate { it.copy(developerMode = new) } }
+                    settings.value.developerMode,
+                    onCheckedChange = { new -> settings.tryUpdate { it.copy(developerMode = new) } }
                 ) }
             )
             Spacer(Modifier.height(16.dp))
diff --git a/app/src/main/java/net/novagamestudios/kaffeekasse/ui/UserSelection.kt b/app/src/main/java/net/novagamestudios/kaffeekasse/ui/UserSelection.kt
index 817ea05f2beda9e03fcb831cae0ee3545d2ab2f5..578d1ea0239c45db5daab4e534afc4919f57c428 100644
--- a/app/src/main/java/net/novagamestudios/kaffeekasse/ui/UserSelection.kt
+++ b/app/src/main/java/net/novagamestudios/kaffeekasse/ui/UserSelection.kt
@@ -1,13 +1,16 @@
 package net.novagamestudios.kaffeekasse.ui
 
+import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
 import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.widthIn
-import androidx.compose.foundation.rememberScrollState
-import androidx.compose.foundation.verticalScroll
+import androidx.compose.foundation.lazy.grid.GridCells
+import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
+import androidx.compose.foundation.lazy.grid.items
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.filled.Close
 import androidx.compose.material.icons.filled.Lock
@@ -140,18 +143,19 @@ fun UserSelection(
                         .fillMaxWidth()
                 ) },
                 dataContent = { users ->
-                    Column(
-                        Modifier
-                            .fillMaxSize()
-                            .verticalScroll(rememberScrollState())
-                            .padding(vertical = 8.dp),
-                        horizontalAlignment = Alignment.CenterHorizontally
+                    LazyVerticalGrid(
+                        columns = GridCells.Adaptive(minSize = 300.dp),
+                        Modifier.fillMaxSize(),
+                        contentPadding = PaddingValues(8.dp),
+                        horizontalArrangement = Arrangement.Center
                     ) {
-                        users.forEach { user ->
+                        items(users) { user ->
                             UserItem(
                                 user = user,
                                 onClick = { vm.selectUser(user) },
-                                Modifier.padding(6.dp)
+                                Modifier
+                                    .padding(6.dp)
+                                    .widthIn(max = 300.dp)
                             )
                         }
                     }
@@ -169,7 +173,7 @@ private fun UserItem(
 ) {
     OutlinedCard(
         onClick = onClick,
-        modifier.widthIn(max = 300.dp)
+        modifier
     ) {
         RowCenter(Modifier.padding(14.dp)) {
             Text("${user.lastName}, ${user.firstName}")
diff --git a/app/src/main/java/net/novagamestudios/kaffeekasse/ui/hiwi_tracker/HiwiTrackerModule.kt b/app/src/main/java/net/novagamestudios/kaffeekasse/ui/hiwi_tracker/HiwiTrackerModule.kt
index 11423cd4153ad4a1ea5c2836f192e080525f70c3..3d88d6e3ed0b44f831bddc7ca4d1e8e63764734f 100644
--- a/app/src/main/java/net/novagamestudios/kaffeekasse/ui/hiwi_tracker/HiwiTrackerModule.kt
+++ b/app/src/main/java/net/novagamestudios/kaffeekasse/ui/hiwi_tracker/HiwiTrackerModule.kt
@@ -200,7 +200,7 @@ class HiwiTrackerModuleViewModel private constructor(
     companion object {
         @Composable fun vm() = App.navigatorScreenModel {
             HiwiTrackerModuleViewModel(
-                mutableSettingsStore = settingsStore,
+                mutableSettingsStore = settingsRepository,
                 hiwiTracker = hiwiTrackerRepository
             )
         }
diff --git a/app/src/main/java/net/novagamestudios/kaffeekasse/ui/kaffeekasse/KaffeekasseModule.kt b/app/src/main/java/net/novagamestudios/kaffeekasse/ui/kaffeekasse/KaffeekasseModule.kt
index 84250d1e8a81d5d0639d693499339f725f1ee958..da56a17e6d32ad1a411ab77e8ab08332cc2a8f45 100644
--- a/app/src/main/java/net/novagamestudios/kaffeekasse/ui/kaffeekasse/KaffeekasseModule.kt
+++ b/app/src/main/java/net/novagamestudios/kaffeekasse/ui/kaffeekasse/KaffeekasseModule.kt
@@ -38,7 +38,11 @@ class KaffeekasseModuleViewModel private constructor(
     private val currentDevice by portal.kaffeekasse.currentDevice.collectAsStateHere()
     private val currentUser by portal.currentUser.collectAsStateHere()
 
-    val accountName get() = if (currentDevice != null) currentUser?.displayName else null
+    val accountName get() = if (currentDevice != null) {
+        currentUser?.displayName ?: "Unknown User"
+    } else {
+        null
+    }
 
     companion object {
         @Composable fun vm() = App.navigatorScreenModel {
diff --git a/app/src/main/java/net/novagamestudios/kaffeekasse/ui/kaffeekasse/Transactions.kt b/app/src/main/java/net/novagamestudios/kaffeekasse/ui/kaffeekasse/Transactions.kt
index fdbb6c46fb777d9a775ad59be1eef13506f1f5c8..cf063c7b61f4ed1c1b11884dae5aec9904b4da02 100644
--- a/app/src/main/java/net/novagamestudios/kaffeekasse/ui/kaffeekasse/Transactions.kt
+++ b/app/src/main/java/net/novagamestudios/kaffeekasse/ui/kaffeekasse/Transactions.kt
@@ -47,7 +47,6 @@ import net.novagamestudios.kaffeekasse.data.category
 import net.novagamestudios.kaffeekasse.data.cleanFullName
 import net.novagamestudios.kaffeekasse.model.kaffeekasse.Transaction
 import net.novagamestudios.kaffeekasse.repositories.i11.KaffeekasseRepository
-import net.novagamestudios.kaffeekasse.repositories.LocalSettingsStore
 import net.novagamestudios.kaffeekasse.ui.kaffeekasse.components.FailureRetryScreen
 import net.novagamestudios.kaffeekasse.ui.kaffeekasse.components.cards.CategoryIcon
 import net.novagamestudios.kaffeekasse.ui.util.PullToRefreshBox
@@ -64,7 +63,7 @@ class TransactionsViewModel private constructor(
     val transactions get() = transactionsState.dataOrNull
     val errors get() = transactionsState.errorOrNull?.messages
     val isLoading get() = transactionsState.isLoading
-    val chartViewModel = TransactionsChartsViewModel(screenModelScope, snapshotFlow { transactions })
+    val chartViewModel by lazy { TransactionsChartsViewModel(screenModelScope, snapshotFlow { transactions }) }
 
     var showCharts by mutableStateOf(false)
 
@@ -215,7 +214,6 @@ private fun TransactionListItem(
     modifier: Modifier = Modifier
 ) = ListItem(
     headlineContent = {
-        val settings by LocalSettingsStore.current
         val style = LocalTextStyle.current
         when (val purpose = transaction.purpose) {
             is Transaction.Purpose.Purchase -> Row(verticalAlignment = Alignment.CenterVertically) {
@@ -232,7 +230,7 @@ private fun TransactionListItem(
                 } else {
                     Text(knownItems.joinToString("/") { it.cleanFullName }, style = style)
                 }
-                if (settings.developerMode) ProvideTextStyle(MaterialTheme.typography.labelSmall) {
+                if (App.developerMode) ProvideTextStyle(MaterialTheme.typography.labelSmall) {
                     if (knownItems.isEmpty()) Text(
                         "Unknown",
                         Modifier.padding(start = 4.dp),
diff --git a/app/src/main/java/net/novagamestudios/kaffeekasse/ui/kaffeekasse/components/CategorizedItems.kt b/app/src/main/java/net/novagamestudios/kaffeekasse/ui/kaffeekasse/components/CategorizedItems.kt
index 79b74d537cd5df425f684c882b20854a15859fbb..9300550eef5f8cc9b49811e214d5f8b6deb92700 100644
--- a/app/src/main/java/net/novagamestudios/kaffeekasse/ui/kaffeekasse/components/CategorizedItems.kt
+++ b/app/src/main/java/net/novagamestudios/kaffeekasse/ui/kaffeekasse/components/CategorizedItems.kt
@@ -9,6 +9,7 @@ import androidx.compose.animation.scaleOut
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.fillMaxHeight
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
@@ -18,12 +19,11 @@ import androidx.compose.ui.Modifier
 import androidx.compose.ui.platform.LocalContext
 import kotlinx.coroutines.launch
 import net.novagamestudios.common_utils.toastShort
+import net.novagamestudios.kaffeekasse.App
 import net.novagamestudios.kaffeekasse.model.kaffeekasse.Cart
 import net.novagamestudios.kaffeekasse.model.kaffeekasse.Item
 import net.novagamestudios.kaffeekasse.model.kaffeekasse.ItemCategory
-import net.novagamestudios.kaffeekasse.model.kaffeekasse.ManualBillDetails
 import net.novagamestudios.kaffeekasse.model.kaffeekasse.MutableCart
-import net.novagamestudios.kaffeekasse.repositories.LocalSettingsStore
 import net.novagamestudios.kaffeekasse.ui.kaffeekasse.components.cards.BasicCardGrid
 import net.novagamestudios.kaffeekasse.ui.kaffeekasse.components.cards.CategoryCard
 import net.novagamestudios.kaffeekasse.ui.kaffeekasse.components.cards.LazyBasicCardGrid
@@ -152,7 +152,7 @@ private fun ItemCard(
     cart: MutableCart
 ) {
     val coroutineScope = rememberCoroutineScope()
-    val settingsStore = LocalSettingsStore.current
+    val userSettings by App.settings().userSettings.collectAsState()
     val context = LocalContext.current
     net.novagamestudios.kaffeekasse.ui.kaffeekasse.components.cards.ItemCard(
         item = item,
@@ -166,7 +166,7 @@ private fun ItemCard(
         onRemove = { cart -= item },
         onLongClick = {
             coroutineScope.launch {
-                settingsStore.update {
+                userSettings?.update {
                     val list = it.favoriteItemIds.toMutableList()
                     val wasFavorite = item.id in list
                     if (wasFavorite) list -= item.id
diff --git a/app/src/main/java/net/novagamestudios/kaffeekasse/ui/kaffeekasse/components/Checkout.kt b/app/src/main/java/net/novagamestudios/kaffeekasse/ui/kaffeekasse/components/Checkout.kt
index d6f5033d1c153f92b350b3e7ca412f883d0bb341..f8eb04fc079f6df7dbbf684a8fb7060b8e296b21 100644
--- a/app/src/main/java/net/novagamestudios/kaffeekasse/ui/kaffeekasse/components/Checkout.kt
+++ b/app/src/main/java/net/novagamestudios/kaffeekasse/ui/kaffeekasse/components/Checkout.kt
@@ -113,7 +113,7 @@ abstract class CheckoutViewModel(
                     true
                 } catch (e: Exception) {
                     warn(e) { "Failed to submit cart" }
-                    errorToast = "Fehler: ${e.message ?: "Unbekannter Fehler"}"
+                    errorToast = "Fehler: ${e.message ?: e::class.simpleName ?: "Unbekannter Fehler"}"
                     false
                 }
             }
@@ -177,6 +177,8 @@ class APICheckoutViewModel(
         selfUserExtended,
         kaffeekasse.basicUserInfoList
     ) { self, userList ->
+        // FIXME wrong way around
+
         val fromWhitelist = self.whitelist.orEmpty()
         val fromBlacklist = self.blacklist?.let { blacklist ->
             val blacklistIds = blacklist.mapTo(mutableSetOf()) { it.id }
diff --git a/app/src/main/java/net/novagamestudios/kaffeekasse/ui/kaffeekasse/components/CustomItems.kt b/app/src/main/java/net/novagamestudios/kaffeekasse/ui/kaffeekasse/components/CustomItems.kt
index 5048dcc67f6c0899b6ec09f9d286faa3ab3fdec1..645d7e5c3c846c3431189b4b8e09aba421ff476f 100644
--- a/app/src/main/java/net/novagamestudios/kaffeekasse/ui/kaffeekasse/components/CustomItems.kt
+++ b/app/src/main/java/net/novagamestudios/kaffeekasse/ui/kaffeekasse/components/CustomItems.kt
@@ -22,10 +22,13 @@ import androidx.compose.ui.unit.dp
 import cafe.adriel.voyager.core.model.ScreenModel
 import cafe.adriel.voyager.core.model.screenModelScope
 import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.collectLatest
 import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.emptyFlow
 import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.flatMapLatest
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
@@ -38,8 +41,8 @@ import net.novagamestudios.kaffeekasse.App
 import net.novagamestudios.kaffeekasse.model.kaffeekasse.Item
 import net.novagamestudios.kaffeekasse.model.kaffeekasse.MutableCart
 import net.novagamestudios.kaffeekasse.model.kaffeekasse.Transaction
+import net.novagamestudios.kaffeekasse.repositories.SettingsRepository
 import net.novagamestudios.kaffeekasse.repositories.i11.KaffeekasseRepository
-import net.novagamestudios.kaffeekasse.repositories.SettingsStore
 import net.novagamestudios.kaffeekasse.ui.theme.disabled
 import net.novagamestudios.kaffeekasse.util.richdata.asRichDataFlow
 import net.novagamestudios.kaffeekasse.util.richdata.collectAsRichStateHere
@@ -50,7 +53,7 @@ import net.novagamestudios.kaffeekasse.util.richdata.stateIn
 import java.time.LocalDateTime
 
 class CustomItemsViewModel private constructor(
-    settingsStore: SettingsStore,
+    settingsRepository: SettingsRepository,
     private val kaffeekasse: KaffeekasseRepository
 ) : ScreenModel, Logger {
 
@@ -64,9 +67,9 @@ class CustomItemsViewModel private constructor(
         .mapRich { items -> items.associateBy { it.originalName } }
         .stateIn(screenModelScope, SharingStarted.Eagerly)
 
-//    val favoriteItems by derivedStateOf { settings.favoriteItems.mapNotNull { item -> allItemsById[item] } }
+    @OptIn(ExperimentalCoroutinesApi::class)
     val favoriteItems = combineRich(
-        settingsStore.values.map { it.favoriteItemIds }.distinctUntilChanged().asRichDataFlow(),
+        settingsRepository.userSettings.flatMapLatest { it?.values ?: emptyFlow() }.map { it.favoriteItemIds }.distinctUntilChanged().asRichDataFlow(),
         allItemsById
     ) { favoriteItems, itemsById ->
         favoriteItems.mapNotNull { itemsById[it] }
@@ -172,7 +175,7 @@ class CustomItemsViewModel private constructor(
 
         @Composable fun vm() = App.navigatorScreenModel {
             CustomItemsViewModel(
-                settingsStore = settingsStore,
+                settingsRepository = settingsRepository,
                 kaffeekasse = kaffeekasseRepository
             )
         }
diff --git a/app/src/main/java/net/novagamestudios/kaffeekasse/ui/kaffeekasse/components/cards/Item.kt b/app/src/main/java/net/novagamestudios/kaffeekasse/ui/kaffeekasse/components/cards/Item.kt
index 4d9cf4a7b041ef70ea7d105b6e4f1478d193bad6..28dbaeecbca62c4e42d5ad9bb48547145443b750 100644
--- a/app/src/main/java/net/novagamestudios/kaffeekasse/ui/kaffeekasse/components/cards/Item.kt
+++ b/app/src/main/java/net/novagamestudios/kaffeekasse/ui/kaffeekasse/components/cards/Item.kt
@@ -56,11 +56,11 @@ import net.novagamestudios.common_utils.compose.components.BoxCenter
 import net.novagamestudios.common_utils.compose.maskedCircleIcon
 import net.novagamestudios.common_utils.info
 import net.novagamestudios.common_utils.warn
+import net.novagamestudios.kaffeekasse.App
 import net.novagamestudios.kaffeekasse.app
 import net.novagamestudios.kaffeekasse.model.kaffeekasse.Item
 import net.novagamestudios.kaffeekasse.model.kaffeekasse.KnownItem
 import net.novagamestudios.kaffeekasse.model.kaffeekasse.Transaction
-import net.novagamestudios.kaffeekasse.repositories.LocalSettingsStore
 import net.novagamestudios.kaffeekasse.util.richdata.collectAsRichState
 
 @Composable
@@ -82,7 +82,6 @@ fun ItemCard(
         ),
     highlighted = highlighted
 ) {
-    val settings by LocalSettingsStore.current
     BoxCenter(
         Modifier
             .weight(1f)
@@ -113,7 +112,7 @@ fun ItemCard(
             onRemove = onRemove
         )
     }
-    if (settings.developerMode) ProvideTextStyle(MaterialTheme.typography.labelSmall) {
+    if (App.developerMode) ProvideTextStyle(MaterialTheme.typography.labelSmall) {
         Row {
             Text("${item.id}")
             Spacer(Modifier.weight(1f))
@@ -144,11 +143,10 @@ private fun ItemInformation(
         )
     }
     Spacer(Modifier.weight(1f))
-    val settings by LocalSettingsStore.current
     val transactionsState = app().kaffeekasseRepository.transactions.collectAsRichState()
     val lastUnitPrice by remember { derivedStateOf { transactionsState.dataOrNull?.findLastUnitPrice(item) } }
     (item.price ?: lastUnitPrice ?: item.estimatedPrice)?.let {
-        val highlighted = it != item.estimatedPrice && settings.developerMode
+        val highlighted = it != item.estimatedPrice && App.developerMode
         Text(
             remember(it) {
                 listOfNotNull(
diff --git a/app/src/main/java/net/novagamestudios/kaffeekasse/ui/theme/Theme.kt b/app/src/main/java/net/novagamestudios/kaffeekasse/ui/theme/Theme.kt
index c8e84fc9bd65d404587440f0992ac1be60e8f848..acdbf9c1e17d0bee0bd501e20f0f1ea18db3aa7b 100644
--- a/app/src/main/java/net/novagamestudios/kaffeekasse/ui/theme/Theme.kt
+++ b/app/src/main/java/net/novagamestudios/kaffeekasse/ui/theme/Theme.kt
@@ -14,7 +14,7 @@ import androidx.compose.ui.graphics.toArgb
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.platform.LocalView
 import androidx.core.view.WindowCompat
-import net.novagamestudios.kaffeekasse.repositories.LocalSettingsStore
+import net.novagamestudios.kaffeekasse.App
 import net.novagamestudios.kaffeekasse.repositories.Settings.Companion.isDarkMode
 
 private val DarkColorScheme = darkColorScheme(
@@ -31,7 +31,7 @@ private val LightColorScheme = lightColorScheme(
 
 @Composable
 fun KaffeekasseTheme(
-    darkTheme: Boolean = LocalSettingsStore.current.value.isDarkMode,
+    darkTheme: Boolean = App.settings().value.isDarkMode,
     // Dynamic color is available on Android 12+
     dynamicColor: Boolean = true,
     content: @Composable () -> Unit
diff --git a/app/src/main/java/net/novagamestudios/kaffeekasse/ui/util/KaffeekassePreview.kt b/app/src/main/java/net/novagamestudios/kaffeekasse/ui/util/KaffeekassePreview.kt
deleted file mode 100644
index f7737c8df4178fe3e940c42e05f90f0cb67f866f..0000000000000000000000000000000000000000
--- a/app/src/main/java/net/novagamestudios/kaffeekasse/ui/util/KaffeekassePreview.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-package net.novagamestudios.kaffeekasse.ui.util
-
-import android.annotation.SuppressLint
-import android.content.res.Configuration
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.CompositionLocalProvider
-import androidx.compose.ui.tooling.preview.Preview
-import net.novagamestudios.kaffeekasse.repositories.LocalSettingsStore
-import net.novagamestudios.kaffeekasse.repositories.Settings
-import net.novagamestudios.kaffeekasse.repositories.rememberMockedSettingsStore
-import net.novagamestudios.kaffeekasse.ui.theme.KaffeekasseTheme
-
-
-
-@Preview(
-    showBackground = false,
-    showSystemUi = true,
-    device = "id:pixel_3a",
-    uiMode = Configuration.UI_MODE_NIGHT_YES or Configuration.UI_MODE_TYPE_NORMAL
-)
-annotation class PreviewDevice
-
-@Preview(
-    showBackground = false,
-    showSystemUi = false,
-    uiMode = Configuration.UI_MODE_NIGHT_YES or Configuration.UI_MODE_TYPE_NORMAL
-)
-annotation class PreviewMinimal
-
-
-@SuppressLint("RememberReturnType")
-@Composable
-fun PreviewTheme(
-    initialSettings: Settings = Settings(),
-    content: @Composable () -> Unit
-) = CompositionLocalProvider(
-    LocalSettingsStore provides rememberMockedSettingsStore(initialSettings)
-) {
-    KaffeekasseTheme(content = content)
-}
-
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 84e0f446984555ebf00037472fd7f2714c3d07b4..1ca878fe428515bda6b02176aa3f37698afce977 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -15,12 +15,12 @@ dependencyResolutionManagement {
     }
     versionCatalogs {
         create("libs") {
-            version("kotlin", "1.9.23")
-            version("compose-compiler", "1.5.12")
+            version("kotlin", "1.9.10")
+            version("compose-compiler", "1.5.3")
             version("compose-bom", "2024.04.01")
             version("material3", "1.3.0-alpha05")
             version("androidx-lifecycle", "2.8.0-beta01")
-            version("ktor", "3.0.0-beta-1")
+            version("ktor", "2.3.8")
             version("vico", "2.0.0-alpha.8")
             version("voyager", "1.1.0-alpha04")
             version("coil", "2.6.0")