diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
index c224ad5..131e44d 100644
--- a/.idea/kotlinc.xml
+++ b/.idea/kotlinc.xml
@@ -1,6 +1,6 @@
 
 
   
-    
+    
   
 
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index a4f09e2..1a1bf72 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,4 +1,3 @@
-
 
   
   
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 4dd8821..354b030 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -3,6 +3,9 @@ plugins {
     alias(libs.plugins.kotlin.android)
     alias(libs.plugins.kotlin.compose)
     alias(libs.plugins.kotlin.serialization)
+    alias(libs.plugins.ksp)
+    alias(libs.plugins.hilt)
+    alias(libs.plugins.protobuf)
 }
 
 android {
@@ -41,7 +44,6 @@ android {
 }
 
 dependencies {
-
     implementation(libs.androidx.core.ktx)
     implementation(libs.androidx.appcompat)
     implementation(libs.material)
@@ -56,6 +58,10 @@ dependencies {
     implementation(libs.knbt)
     implementation(libs.reorderable)
     implementation(libs.androidx.navigation.compose)
+    implementation(libs.hilt.android)
+    implementation(libs.androidx.hilt.navigation.compose)
+    implementation(libs.androidx.datastore)
+    implementation(libs.protobuf.javalite)
     testImplementation(libs.junit)
     androidTestImplementation(libs.androidx.junit)
     androidTestImplementation(libs.androidx.espresso.core)
@@ -63,4 +69,20 @@ dependencies {
     androidTestImplementation(libs.androidx.ui.test.junit4)
     debugImplementation(libs.androidx.ui.tooling)
     debugImplementation(libs.androidx.ui.test.manifest)
+    ksp(libs.hilt.compiler)
+}
+
+protobuf {
+    protoc {
+        artifact = "com.google.protobuf:protoc:4.30.2"
+    }
+    generateProtoTasks {
+        all().forEach { task ->
+            task.builtins {
+                create("java") {
+                    option("lite")
+                }
+            }
+        }
+    }
 }
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 25b3816..a211ec4 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -8,6 +8,7 @@
     
 
     
+        android:theme="@style/Theme.PojavBackup">
         
         
+        
             
                 
@@ -34,17 +39,6 @@
                 
             
         
-
-        
-            
-                
-            
-        
     
 
 
\ No newline at end of file
diff --git a/app/src/main/java/eu/m724/pojavbackup/MyCloudProvider.kt b/app/src/main/java/eu/m724/pojavbackup/MyCloudProvider.kt
deleted file mode 100644
index 6c89956..0000000
--- a/app/src/main/java/eu/m724/pojavbackup/MyCloudProvider.kt
+++ /dev/null
@@ -1,138 +0,0 @@
-package eu.m724.pojavbackup
-
-import android.R
-import android.database.Cursor
-import android.database.MatrixCursor
-import android.os.CancellationSignal
-import android.os.ParcelFileDescriptor
-import android.provider.DocumentsContract
-import android.provider.DocumentsContract.Root
-import android.provider.DocumentsProvider
-import android.util.Log
-import java.io.FileNotFoundException
-
-
-class MyCloudProvider : DocumentsProvider() {
-    val TAG: String = "MinimalDocsProvider"
-
-    // Define the authority (must match AndroidManifest.xml)
-    // Use your app's package name + ".documents" or similar unique identifier
-    val AUTHORITY: String = "com.example.myapp.minimalprovider"
-
-    // Define a unique ID for our single root
-    val ROOT_ID: String = "minimal_root"
-
-    // Define the document ID for the root directory itself
-    val ROOT_DOC_ID: String = "minimal_root_directory"
-
-    private val DEFAULT_ROOT_PROJECTION: Array = arrayOf(
-        DocumentsContract.Root.COLUMN_ROOT_ID,
-        DocumentsContract.Root.COLUMN_MIME_TYPES,
-        DocumentsContract.Root.COLUMN_FLAGS,
-        DocumentsContract.Root.COLUMN_ICON,
-        DocumentsContract.Root.COLUMN_TITLE,
-        DocumentsContract.Root.COLUMN_SUMMARY,
-        DocumentsContract.Root.COLUMN_DOCUMENT_ID,
-        DocumentsContract.Root.COLUMN_AVAILABLE_BYTES
-    )
-    private val DEFAULT_DOCUMENT_PROJECTION: Array = arrayOf(
-        DocumentsContract.Document.COLUMN_DOCUMENT_ID,
-        DocumentsContract.Document.COLUMN_MIME_TYPE,
-        DocumentsContract.Document.COLUMN_DISPLAY_NAME,
-        DocumentsContract.Document.COLUMN_LAST_MODIFIED,
-        DocumentsContract.Document.COLUMN_FLAGS,
-        DocumentsContract.Document.COLUMN_SIZE
-    )
-
-    override fun onCreate(): Boolean {
-        return true
-    }
-
-    override fun queryRoots(projection: Array?): Cursor {
-        Log.d(TAG, "queryRoots called")
-
-        // Use the default projection if none is provided
-        val resolvedProjection: Array = projection ?: DEFAULT_ROOT_PROJECTION
-
-
-        // Create a MatrixCursor to hold the root information
-        val cursor = MatrixCursor(resolvedProjection)
-
-
-        // Add a single row for our minimal root
-        val row = cursor.newRow()
-        row.add(Root.COLUMN_ROOT_ID, ROOT_ID)
-        row.add(Root.COLUMN_TITLE, "My Minimal Provider") // The name shown in the file manager
-        row.add(Root.COLUMN_DOCUMENT_ID, ROOT_DOC_ID) // ID of the root directory document
-
-
-        // --- IMPORTANT: Add an icon! ---
-        // Replace R.mipmap.ic_launcher with your actual app icon or a dedicated icon
-        // If you don't have one, the entry might not show up correctly.
-        row.add(Root.COLUMN_ICON, R.mipmap.sym_def_app_icon)
-
-
-        // --- Set Flags ---
-        // FLAG_SUPPORTS_CREATE: If you plan to allow creating files/folders later
-        // FLAG_LOCAL_ONLY: If the data is only on the device
-        // FLAG_SUPPORTS_SEARCH: If you plan to implement search
-        // For minimal display, LOCAL_ONLY is often sufficient.
-        row.add(Root.COLUMN_FLAGS, Root.FLAG_LOCAL_ONLY /* | Root.FLAG_SUPPORTS_CREATE */)
-
-
-        // You could add other columns here if they are in the projection
-        // row.add(Root.COLUMN_SUMMARY, "A basic example provider");
-        // row.add(Root.COLUMN_AVAILABLE_BYTES, null); // Or calculate if known
-        return cursor
-    }
-
-    override fun queryDocument(documentId: String?, projection: Array?): Cursor {
-        println("queryDocument called for ID: $documentId")
-
-        throw FileNotFoundException("Document not found: $documentId")
-    }
-
-    override fun queryChildDocuments(
-        parentDocumentId: String?,
-        projection: Array?,
-        sortOrder: String?
-    ): Cursor {
-        println("queryChildDocuments called for parent ID: $parentDocumentId")
-
-        val resolvedProjection: Array = projection
-            ?: DEFAULT_DOCUMENT_PROJECTION
-        val cursor = MatrixCursor(resolvedProjection)
-
-
-        // Check if the request is for the children of our root directory
-        if (ROOT_DOC_ID.equals(parentDocumentId)) {
-            // --- THIS IS WHERE YOU WOULD ADD ACTUAL FILES/FOLDERS ---
-            // For this minimal example, we return an empty cursor, meaning the root directory is empty.
-
-            // Example of adding a dummy file (if you wanted to test further):
-            /*
-            MatrixCursor.RowBuilder row = cursor.newRow();
-            row.add(Document.COLUMN_DOCUMENT_ID, "dummy_file_1");
-            row.add(Document.COLUMN_DISPLAY_NAME, "hello.txt");
-            row.add(Document.COLUMN_MIME_TYPE, "text/plain");
-            row.add(Document.COLUMN_FLAGS, Document.FLAG_SUPPORTS_WRITE | Document.FLAG_SUPPORTS_DELETE);
-            row.add(Document.COLUMN_SIZE, 1234);
-            row.add(Document.COLUMN_LAST_MODIFIED, System.currentTimeMillis());
-            */
-        } else {
-            // We only know the root, so any other parent ID is invalid
-            println("queryChildDocuments requested for unknown parent ID: $parentDocumentId")
-            throw FileNotFoundException("Parent document not found: $parentDocumentId")
-        }
-
-        return cursor
-    }
-
-    override fun openDocument(
-        documentId: String?,
-        mode: String?,
-        signal: CancellationSignal?
-    ): ParcelFileDescriptor {
-        throw FileNotFoundException("Cannot open document in minimal provider: $documentId");
-    }
-}
\ No newline at end of file
diff --git a/app/src/main/java/eu/m724/pojavbackup/PojavBackupApplication.kt b/app/src/main/java/eu/m724/pojavbackup/PojavBackupApplication.kt
new file mode 100644
index 0000000..96650c3
--- /dev/null
+++ b/app/src/main/java/eu/m724/pojavbackup/PojavBackupApplication.kt
@@ -0,0 +1,9 @@
+package eu.m724.pojavbackup
+
+import android.app.Application
+import dagger.hilt.android.HiltAndroidApp
+
+@HiltAndroidApp
+class PojavBackupApplication : Application() {
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/eu/m724/pojavbackup/core/DataLoader.kt b/app/src/main/java/eu/m724/pojavbackup/core/DataLoader.kt
deleted file mode 100644
index 1322d45..0000000
--- a/app/src/main/java/eu/m724/pojavbackup/core/DataLoader.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-package eu.m724.pojavbackup.core
-
-import android.content.ContentResolver
-import androidx.documentfile.provider.DocumentFile
-
-class DataLoader(
-    private val contentResolver: ContentResolver,
-    private val dataDirectory: DocumentFile
-) {
-
-    fun listWorlds(): List {
-        return WorldDetector(contentResolver, getSavesDirectory())
-            .listWorlds()
-    }
-
-    fun listWorlds(consumer: (World) -> Unit) {
-        WorldDetector(contentResolver, getSavesDirectory())
-            .listWorlds(consumer)
-    }
-
-    fun getWorld(id: String): World? {
-        return WorldDetector(contentResolver, getSavesDirectory())
-            .getWorld(id)
-    }
-
-    fun getSavesDirectory(): DocumentFile {
-        return dataDirectory.findFile(".minecraft")!!.findFile("saves")!!
-    }
-}
\ No newline at end of file
diff --git a/app/src/main/java/eu/m724/pojavbackup/core/WorldDetector.kt b/app/src/main/java/eu/m724/pojavbackup/core/WorldDetector.kt
index 03ced12..3857c82 100644
--- a/app/src/main/java/eu/m724/pojavbackup/core/WorldDetector.kt
+++ b/app/src/main/java/eu/m724/pojavbackup/core/WorldDetector.kt
@@ -4,10 +4,11 @@ import android.content.ContentResolver
 import android.graphics.BitmapFactory
 import android.util.Log
 import androidx.documentfile.provider.DocumentFile
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flow
 import net.benwoodworth.knbt.Nbt
 import net.benwoodworth.knbt.NbtCompound
 import net.benwoodworth.knbt.NbtCompression
-import net.benwoodworth.knbt.NbtTag
 import net.benwoodworth.knbt.NbtVariant
 import net.benwoodworth.knbt.decodeFromStream
 import net.benwoodworth.knbt.nbtCompound
@@ -27,19 +28,14 @@ class WorldDetector(
         compression = NbtCompression.Gzip
     }
 
-    // TODO not at once
-    /**
-     * List worlds in the savesDirectory
-     *
-     * @return The worlds
-     */
-    fun listWorlds(): List {
-        return savesDirectory.listFiles().mapNotNull {
-            try {
-                getWorldFromDirectory(it)
-            } catch (e: InvalidWorldException) {
-                Log.i(TAG, "${it.name} is invalid: ${e.message}")
-                null
+    fun listWorlds(): Flow {
+        return flow {
+            savesDirectory.listFiles().mapNotNull {
+                try {
+                    emit(getWorldFromDirectory(it))
+                } catch (e: InvalidWorldException) {
+                    Log.i(TAG, "${it.name} is invalid: ${e.message}")
+                }
             }
         }
     }
diff --git a/app/src/main/java/eu/m724/pojavbackup/core/WorldRepository.kt b/app/src/main/java/eu/m724/pojavbackup/core/WorldRepository.kt
new file mode 100644
index 0000000..3b22f26
--- /dev/null
+++ b/app/src/main/java/eu/m724/pojavbackup/core/WorldRepository.kt
@@ -0,0 +1,58 @@
+package eu.m724.pojavbackup.core
+
+import android.content.Context
+import androidx.documentfile.provider.DocumentFile
+import dagger.hilt.android.qualifiers.ApplicationContext
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.toList
+import kotlinx.coroutines.sync.Mutex
+import kotlinx.coroutines.sync.withLock
+import kotlinx.coroutines.withContext
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class WorldRepository @Inject constructor(
+    @ApplicationContext private val appContext: Context
+) {
+    private lateinit var savesDirectory: DocumentFile
+    private lateinit var worldDetector: WorldDetector
+
+    private var worldsCache: List? = null
+    private val cacheMutex = Mutex() // To ensure thread-safe access to cache
+
+    fun setSavesDirectory(documentFile: DocumentFile) {
+        this.savesDirectory = documentFile
+        this.worldDetector = WorldDetector(appContext.contentResolver, savesDirectory)
+    }
+
+    suspend fun listWorlds(): List {
+        cacheMutex.withLock {
+            if (worldsCache != null) {
+                return worldsCache!! // Return copy or immutable list if needed
+            }
+        }
+
+        // If cache is empty, fetch data on IO dispatcher
+        val freshData = withContext(Dispatchers.IO) {
+            worldDetector.listWorlds().toList() // TODO
+        }
+
+        // Store in cache (thread-safe)
+        cacheMutex.withLock {
+            worldsCache = freshData
+        }
+
+        return freshData
+    }
+
+    suspend fun getWorld(id: String): World? {
+        return listWorlds().firstOrNull { it.id == id }
+    }
+
+    suspend fun clearCache() {
+        cacheMutex.withLock {
+            worldsCache = null
+        }
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/eu/m724/pojavbackup/core/datastore/DataStoreModule.kt b/app/src/main/java/eu/m724/pojavbackup/core/datastore/DataStoreModule.kt
new file mode 100644
index 0000000..96bc440
--- /dev/null
+++ b/app/src/main/java/eu/m724/pojavbackup/core/datastore/DataStoreModule.kt
@@ -0,0 +1,42 @@
+package eu.m724.pojavbackup.core.datastore
+
+import android.content.Context
+import androidx.datastore.core.DataStore
+import androidx.datastore.core.DataStoreFactory
+import androidx.datastore.dataStoreFile
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.android.qualifiers.ApplicationContext
+import dagger.hilt.components.SingletonComponent
+import eu.m724.pojavbackup.proto.Settings
+import javax.inject.Singleton
+
+private const val USER_PREFERENCES_FILE_NAME = "user_prefs.pb"
+
+@Module
+@InstallIn(SingletonComponent::class) // Provides dependencies for the entire app
+object DataStoreModule {
+    @Provides
+    @Singleton // Ensure only one instance is created
+    fun provideUserPreferencesDataStore(
+        @ApplicationContext applicationContext: Context,
+        // Optional: You can inject CoroutineScope/Dispatcher if you want to customize it
+        // userPreferencesSerializer: UserPreferencesSerializer // Inject serializer if it's a class with dependencies
+    ): DataStore {
+        return DataStoreFactory.create(
+            serializer = SettingsSerializer, // Use your serializer instance/object
+            produceFile = { applicationContext.dataStoreFile(USER_PREFERENCES_FILE_NAME) },
+            // Optional: Add corruption handler
+            // corruptionHandler = ReplaceFileCorruptionHandler { ex -> /* Handle corruption */ UserPreferences.getDefaultInstance() },
+            // Optional: Specify a custom scope, though the default (SupervisorJob + Dispatchers.IO) is usually fine
+            // scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
+        )
+    }
+
+    // If your Serializer was a class and had dependencies, you'd provide it too:
+    // @Provides
+    // fun provideUserPreferencesSerializer(): UserPreferencesSerializer {
+    //     return UserPreferencesSerializer(/* dependencies */)
+    // }
+}
\ No newline at end of file
diff --git a/app/src/main/java/eu/m724/pojavbackup/core/datastore/SettingsRepository.kt b/app/src/main/java/eu/m724/pojavbackup/core/datastore/SettingsRepository.kt
new file mode 100644
index 0000000..7cbb3b7
--- /dev/null
+++ b/app/src/main/java/eu/m724/pojavbackup/core/datastore/SettingsRepository.kt
@@ -0,0 +1,31 @@
+package eu.m724.pojavbackup.core.datastore
+
+import androidx.datastore.core.DataStore
+import eu.m724.pojavbackup.proto.Settings
+import eu.m724.pojavbackup.proto.WorldOrder
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.first
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class SettingsRepository @Inject constructor(
+    private val dataStore: DataStore
+) {
+    fun getSettingsFlow(): Flow {
+        return dataStore.data
+    }
+
+    suspend fun getSettings(): Settings {
+        return dataStore.data.first()
+    }
+
+    suspend fun updateWorldOrder(worldOrder: WorldOrder) {
+        dataStore.updateData {
+            it.toBuilder()
+                .clearWorldOrder()
+                .setWorldOrder(worldOrder)
+                .build()
+        }
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/eu/m724/pojavbackup/core/datastore/SettingsSerializer.kt b/app/src/main/java/eu/m724/pojavbackup/core/datastore/SettingsSerializer.kt
new file mode 100644
index 0000000..8e66034
--- /dev/null
+++ b/app/src/main/java/eu/m724/pojavbackup/core/datastore/SettingsSerializer.kt
@@ -0,0 +1,24 @@
+package eu.m724.pojavbackup.core.datastore
+
+import androidx.datastore.core.CorruptionException
+import androidx.datastore.core.Serializer
+import com.google.protobuf.InvalidProtocolBufferException
+import eu.m724.pojavbackup.proto.Settings
+import java.io.InputStream
+import java.io.OutputStream
+
+object SettingsSerializer : Serializer {
+    override val defaultValue: Settings = Settings.getDefaultInstance()
+
+    override suspend fun readFrom(input: InputStream): Settings {
+        try {
+            return Settings.parseFrom(input)
+        } catch (exception: InvalidProtocolBufferException) {
+            throw CorruptionException("Cannot read proto.", exception)
+        }
+    }
+
+    override suspend fun writeTo(t: Settings, output: OutputStream) {
+        t.writeTo(output)
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/eu/m724/pojavbackup/home/HomeActivity.kt b/app/src/main/java/eu/m724/pojavbackup/home/HomeActivity.kt
index be3f3c2..ad33fa6 100644
--- a/app/src/main/java/eu/m724/pojavbackup/home/HomeActivity.kt
+++ b/app/src/main/java/eu/m724/pojavbackup/home/HomeActivity.kt
@@ -1,21 +1,24 @@
 package eu.m724.pojavbackup.home
 
+import android.content.Intent
 import android.os.Bundle
 import androidx.activity.ComponentActivity
 import androidx.activity.compose.setContent
 import androidx.activity.enableEdgeToEdge
-import androidx.compose.animation.core.Spring
-import androidx.compose.animation.core.spring
+import androidx.activity.result.ActivityResult
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.activity.viewModels
 import androidx.compose.animation.fadeIn
 import androidx.compose.animation.fadeOut
 import androidx.compose.animation.slideInHorizontally
 import androidx.compose.animation.slideOutHorizontally
 import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.ColumnScope
 import androidx.compose.foundation.layout.RowScope
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.CircularProgressIndicator
 import androidx.compose.material3.Icon
 import androidx.compose.material3.NavigationBar
 import androidx.compose.material3.NavigationBarItem
@@ -26,76 +29,126 @@ import androidx.compose.runtime.getValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.res.painterResource
+import androidx.core.net.toUri
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import androidx.navigation.NavController
 import androidx.navigation.NavDestination.Companion.hierarchy
 import androidx.navigation.compose.NavHost
 import androidx.navigation.compose.composable
 import androidx.navigation.compose.currentBackStackEntryAsState
 import androidx.navigation.compose.rememberNavController
+import dagger.hilt.android.AndroidEntryPoint
 import eu.m724.pojavbackup.R
-import eu.m724.pojavbackup.home.screen.Screen
+import eu.m724.pojavbackup.home.screen.HomeScreen
 import eu.m724.pojavbackup.home.screen.dashboard.DashboardScreen
 import eu.m724.pojavbackup.home.screen.history.HistoryScreen
+import eu.m724.pojavbackup.settings.SettingsActivity
+import eu.m724.pojavbackup.setup.SetupActivity
 import eu.m724.pojavbackup.ui.theme.PojavBackupTheme
 
+@AndroidEntryPoint
 class HomeActivity : ComponentActivity() {
+    private val viewModel: HomeViewModel by viewModels()
+
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
 
+        viewModel.load(
+            onSetupNeeded = {
+                registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
+                    if (result.resultCode == 0) {
+                        // TODO success
+                    } else {
+                        // TODO failure
+                    }
+                }.launch(Intent(applicationContext, SetupActivity::class.java))
+            }
+        )
+
         enableEdgeToEdge()
         setContent {
-            val navController = rememberNavController()
-
             PojavBackupTheme {
-                Scaffold(
-                    modifier = Modifier.fillMaxSize(),
-                    bottomBar = {
-                        NavigationBar {
-                            ScreenNavigationBarItem(
-                                navController = navController,
-                                label = "Dashboard",
-                                route = Screen.Dashboard,
-                                iconResourceId = R.drawable.baseline_home_24
-                            )
-                            ScreenNavigationBarItem(
-                                navController = navController,
-                                label = "History",
-                                route = Screen.History,
-                                iconResourceId = R.drawable.baseline_history_24
-                            )
-                        }
-                    }
-                ) { innerPadding ->
-                    NavHost(
-                        navController = navController,
-                        startDestination = Screen.Dashboard,
-                        modifier = Modifier.padding(innerPadding),
-                        enterTransition = {
-                            fadeIn() + slideInHorizontally(initialOffsetX = { it / 10 })
-                        },
-                        exitTransition = {
-                            fadeOut() + slideOutHorizontally(targetOffsetX = { -it / 10 })
-                        }
+                val uiState by viewModel.uiState.collectAsStateWithLifecycle()
+
+                if (uiState.loading) {
+                    Column(
+                        modifier = Modifier.fillMaxSize(),
+                        verticalArrangement = Arrangement.Center,
+                        horizontalAlignment = Alignment.CenterHorizontally
                     ) {
-                        composable {
-                            DashboardScreen(navController)
-                        }
-                        composable {
-                            HistoryScreen()
-                        }
-                        // Add more destinations similarly.
+                        CircularProgressIndicator()
                     }
+                } else {
+                    HomeScaffold(
+                        onSettingsOpen = { onSettingsOpen(it) }
+                    )
                 }
             }
         }
     }
+
+    fun onSettingsOpen(page: String) {
+        startActivity(Intent(applicationContext, SettingsActivity::class.java).putExtra("settingsPage", page))
+    }
+}
+
+@Composable
+fun HomeScaffold(
+    onSettingsOpen: (String) -> Unit
+) {
+    val navController = rememberNavController()
+
+    Scaffold(
+        modifier = Modifier.fillMaxSize(),
+        bottomBar = {
+            NavigationBar {
+                ScreenNavigationBarItem(
+                    navController = navController,
+                    label = "Dashboard",
+                    route = HomeScreen.Dashboard,
+                    iconResourceId = R.drawable.baseline_home_24
+                )
+                ScreenNavigationBarItem(
+                    navController = navController,
+                    label = "History",
+                    route = HomeScreen.History,
+                    iconResourceId = R.drawable.baseline_history_24
+                )
+            }
+        }
+    ) { innerPadding ->
+        NavHost(
+            navController = navController,
+            startDestination = HomeScreen.Dashboard,
+            modifier = Modifier.padding(innerPadding),
+            enterTransition = {
+                fadeIn() + slideInHorizontally(initialOffsetX = { it / 10 })
+            },
+            exitTransition = {
+                fadeOut() + slideOutHorizontally(targetOffsetX = { -it / 10 })
+            }
+        ) {
+            composable {
+                DashboardScreen(
+                    navController = navController,
+                    onWorldsIncludedClick = {
+                        onSettingsOpen("content")
+                    }
+                )
+            }
+            composable {
+                HistoryScreen()
+            }
+            // Add more destinations similarly.
+        }
+    }
 }
 
 @Composable
 fun RowScope.ScreenNavigationBarItem(
     navController: NavController,
     label: String,
-    route: Screen,
+    route: HomeScreen,
     iconResourceId: Int
 ) {
     val selected = isSelected(navController, route)
@@ -122,7 +175,7 @@ fun RowScope.ScreenNavigationBarItem(
 @Composable
 fun isSelected(
     navController: NavController,
-    route: Screen
+    route: HomeScreen
 ): Boolean {
     val navBackStackEntry by navController.currentBackStackEntryAsState()
     val currentDestination = navBackStackEntry?.destination
diff --git a/app/src/main/java/eu/m724/pojavbackup/home/HomeUiState.kt b/app/src/main/java/eu/m724/pojavbackup/home/HomeUiState.kt
new file mode 100644
index 0000000..aba434d
--- /dev/null
+++ b/app/src/main/java/eu/m724/pojavbackup/home/HomeUiState.kt
@@ -0,0 +1,5 @@
+package eu.m724.pojavbackup.home
+
+data class HomeUiState(
+    val loading: Boolean = true
+)
\ No newline at end of file
diff --git a/app/src/main/java/eu/m724/pojavbackup/home/HomeViewModel.kt b/app/src/main/java/eu/m724/pojavbackup/home/HomeViewModel.kt
index f405120..769ce2d 100644
--- a/app/src/main/java/eu/m724/pojavbackup/home/HomeViewModel.kt
+++ b/app/src/main/java/eu/m724/pojavbackup/home/HomeViewModel.kt
@@ -1,4 +1,87 @@
 package eu.m724.pojavbackup.home
 
-class HomeViewModel {
+import android.content.Context
+import android.net.Uri
+import android.util.Log
+import androidx.core.net.toUri
+import androidx.documentfile.provider.DocumentFile
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import dagger.hilt.android.lifecycle.HiltViewModel
+import dagger.hilt.android.qualifiers.ApplicationContext
+import eu.m724.pojavbackup.core.WorldRepository
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.update
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import javax.inject.Inject
+
+@HiltViewModel
+class HomeViewModel @Inject constructor(
+    @ApplicationContext private val appContext: Context,
+    private val worldRepository: WorldRepository
+) : ViewModel() {
+    private val TAG = javaClass.name
+
+    private val _uiState = MutableStateFlow(HomeUiState())
+    val uiState: StateFlow = _uiState.asStateFlow()
+
+    fun load(
+        onSetupNeeded: () -> Unit
+    ) {
+        // TODO this should be dynamic (selected) or a list (debug/normal version)
+        val uri = "content://net.kdt.pojavlaunch.scoped.gamefolder.debug/tree/%2Fstorage%2Femulated%2F0%2FAndroid%2Fdata%2Fnet.kdt.pojavlaunch.debug%2Ffiles".toUri()
+
+        viewModelScope.launch {
+            withContext(Dispatchers.IO) {
+                val hasPermission = checkForStoragePermission(uri)
+
+                if (hasPermission) {
+                    // some paths were checked earlier
+                    val documentFile = DocumentFile.fromTreeUri(appContext, uri)!!
+                        .findFile(".minecraft")!!
+                        .findFile("saves")
+
+                    if (documentFile != null) {
+                        worldRepository.setSavesDirectory(documentFile)
+                        worldRepository.listWorlds()
+                    } else {
+                        // TODO handle if "saves" doesn't exist
+                    }
+
+                    _uiState.update { it.copy(loading = false) }
+                } else {
+                    // TODO there could be that only one or two permissions are missing
+                    onSetupNeeded()
+                }
+            }
+        }
+    }
+
+    private fun checkForStoragePermission(uri: Uri): Boolean {
+        Log.i(TAG, "Checking for storage permission...")
+
+        // TODO Is this the right way? This isn't in https://developer.android.com/training/data-storage/shared/documents-files
+        val directory = DocumentFile.fromTreeUri(appContext, uri)
+
+        if (directory == null || !directory.isDirectory) {
+            Log.i(TAG, "No permission or not a directory")
+            return false
+        }
+
+        val dotMinecraftExists = directory.findFile(".minecraft") != null
+        val controlMapExists = directory.findFile("controlmap") != null
+
+        if (!dotMinecraftExists || !controlMapExists) {
+            Log.i(TAG, "Selected directory is missing .minecraft or controlmap")
+            return false
+        }
+
+        Log.i(TAG, "Yes we have permission")
+
+        return true
+    }
 }
\ No newline at end of file
diff --git a/app/src/main/java/eu/m724/pojavbackup/home/screen/Screen.kt b/app/src/main/java/eu/m724/pojavbackup/home/screen/HomeScreen.kt
similarity index 79%
rename from app/src/main/java/eu/m724/pojavbackup/home/screen/Screen.kt
rename to app/src/main/java/eu/m724/pojavbackup/home/screen/HomeScreen.kt
index f72a61e..b8492a8 100644
--- a/app/src/main/java/eu/m724/pojavbackup/home/screen/Screen.kt
+++ b/app/src/main/java/eu/m724/pojavbackup/home/screen/HomeScreen.kt
@@ -1,6 +1,5 @@
 package eu.m724.pojavbackup.home.screen
 
-import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.ColumnScope
 import androidx.compose.foundation.layout.fillMaxSize
@@ -11,9 +10,9 @@ import androidx.compose.ui.Modifier
 import androidx.compose.ui.unit.dp
 import kotlinx.serialization.Serializable
 
-@Serializable sealed interface Screen {
-    @Serializable data object Dashboard : Screen
-    @Serializable data object History : Screen
+@Serializable sealed interface HomeScreen {
+    @Serializable data object Dashboard : HomeScreen
+    @Serializable data object History : HomeScreen
 }
 
 @Composable
diff --git a/app/src/main/java/eu/m724/pojavbackup/home/screen/dashboard/DashboardScreen.kt b/app/src/main/java/eu/m724/pojavbackup/home/screen/dashboard/DashboardScreen.kt
index a91934b..8bea8fd 100644
--- a/app/src/main/java/eu/m724/pojavbackup/home/screen/dashboard/DashboardScreen.kt
+++ b/app/src/main/java/eu/m724/pojavbackup/home/screen/dashboard/DashboardScreen.kt
@@ -9,42 +9,43 @@ import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.size
 import androidx.compose.foundation.layout.width
-import androidx.compose.foundation.lazy.LazyRow
-import androidx.compose.material3.Card
-import androidx.compose.material3.CardDefaults
 import androidx.compose.material3.ElevatedCard
 import androidx.compose.material3.Icon
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Text
-import androidx.compose.material3.TextFieldDefaults
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.res.painterResource
 import androidx.compose.ui.text.font.FontWeight
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
+import androidx.hilt.navigation.compose.hiltViewModel
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import androidx.navigation.NavController
 import eu.m724.pojavbackup.R
-import eu.m724.pojavbackup.home.screen.Screen
+import eu.m724.pojavbackup.home.screen.HomeScreen
 import eu.m724.pojavbackup.home.screen.ScreenColumn
 
 @OptIn(ExperimentalLayoutApi::class)
 @Composable
 fun DashboardScreen(
-    navController: NavController
+    navController: NavController,
+    onWorldsIncludedClick: () -> Unit,
 ) {
+    val viewModel: DashboardScreenViewModel = hiltViewModel()
+    val settings by viewModel.settings.collectAsStateWithLifecycle()
+
     ScreenColumn {
         FlowRow(
             maxItemsInEachRow = 3
         ) {
             DashboardCard(
                 title = "Worlds included",
-                value = "1",
+                value = settings.worldOrder.separatorIndex,
                 iconResourceId = R.drawable.baseline_mosque_24,
-                onClick = {
-
-                }
+                onClick = onWorldsIncludedClick
             )
 
             DashboardCard(
@@ -58,7 +59,7 @@ fun DashboardScreen(
                 value = "1d ago",
                 iconResourceId = R.drawable.baseline_access_time_filled_24,
                 onClick = {
-                    navController.navigate(Screen.History)
+                    navController.navigate(HomeScreen.History)
                 }
             )
         }
diff --git a/app/src/main/java/eu/m724/pojavbackup/home/screen/dashboard/DashboardScreenViewModel.kt b/app/src/main/java/eu/m724/pojavbackup/home/screen/dashboard/DashboardScreenViewModel.kt
new file mode 100644
index 0000000..095afc8
--- /dev/null
+++ b/app/src/main/java/eu/m724/pojavbackup/home/screen/dashboard/DashboardScreenViewModel.kt
@@ -0,0 +1,29 @@
+package eu.m724.pojavbackup.home.screen.dashboard
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import dagger.hilt.android.lifecycle.HiltViewModel
+import eu.m724.pojavbackup.core.datastore.SettingsRepository
+import eu.m724.pojavbackup.proto.Settings
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.update
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+@HiltViewModel
+class DashboardScreenViewModel @Inject constructor(
+    private val settingsRepository: SettingsRepository
+) : ViewModel() {
+    private val _settings = MutableStateFlow(Settings.getDefaultInstance())
+    val settings: StateFlow = _settings.asStateFlow()
+
+    init {
+        viewModelScope.launch {
+            settingsRepository.getSettingsFlow().collect { newSettings ->
+                _settings.update { newSettings }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/eu/m724/pojavbackup/settings/SettingsActivity.kt b/app/src/main/java/eu/m724/pojavbackup/settings/SettingsActivity.kt
new file mode 100644
index 0000000..5c7383e
--- /dev/null
+++ b/app/src/main/java/eu/m724/pojavbackup/settings/SettingsActivity.kt
@@ -0,0 +1,153 @@
+package eu.m724.pojavbackup.settings
+
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.activity.enableEdgeToEdge
+import androidx.compose.animation.fadeIn
+import androidx.compose.animation.fadeOut
+import androidx.compose.animation.slideInHorizontally
+import androidx.compose.animation.slideOutHorizontally
+import androidx.compose.foundation.layout.RowScope
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Icon
+import androidx.compose.material3.NavigationBar
+import androidx.compose.material3.NavigationBarItem
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.painterResource
+import androidx.navigation.NavController
+import androidx.navigation.NavDestination.Companion.hierarchy
+import androidx.navigation.compose.NavHost
+import androidx.navigation.compose.composable
+import androidx.navigation.compose.currentBackStackEntryAsState
+import androidx.navigation.compose.rememberNavController
+import dagger.hilt.android.AndroidEntryPoint
+import eu.m724.pojavbackup.R
+import eu.m724.pojavbackup.settings.screen.SettingsScreen
+import eu.m724.pojavbackup.settings.screen.content.ContentScreen
+import eu.m724.pojavbackup.settings.screen.options.OptionsScreen
+import eu.m724.pojavbackup.ui.theme.PojavBackupTheme
+
+@AndroidEntryPoint
+class SettingsActivity : ComponentActivity() {
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+
+        val startPage = when (intent.getStringExtra("settingsPage")) {
+            "options" -> SettingsScreen.Options
+            "content" -> SettingsScreen.Content
+            else -> SettingsScreen.Options
+        }
+
+        enableEdgeToEdge()
+        setContent {
+            val navController = rememberNavController()
+
+            PojavBackupTheme {
+                Scaffold(
+                    modifier = Modifier.fillMaxSize(),
+                    bottomBar = {
+                        NavigationBar {
+                            ScreenNavigationBarItem(
+                                navController = navController,
+                                label = "Options",
+                                route = SettingsScreen.Options,
+                                iconResourceId = R.drawable.baseline_settings_24
+                            )
+                            ScreenNavigationBarItem(
+                                navController = navController,
+                                label = "Content",
+                                route = SettingsScreen.Content,
+                                iconResourceId = R.drawable.baseline_folder_copy_24
+                            )
+                        }
+                    }
+                ) { innerPadding ->
+                    NavHost(
+                        navController = navController,
+                        startDestination = startPage,
+                        modifier = Modifier.padding(innerPadding),
+                        enterTransition = {
+                            fadeIn() + slideInHorizontally(initialOffsetX = { it / 10 })
+                        },
+                        exitTransition = {
+                            fadeOut() + slideOutHorizontally(targetOffsetX = { -it / 10 })
+                        }
+                    ) {
+                        composable {
+                            OptionsScreen(navController)
+                        }
+                        composable {
+                            ContentScreen(navController)
+                        }
+                        // Add more destinations similarly.
+                    }
+                }
+            }
+        }
+    }
+}
+
+// TODO those functions are reused in Home
+@Composable
+fun RowScope.ScreenNavigationBarItem(
+    navController: NavController,
+    label: String,
+    route: SettingsScreen,
+    iconResourceId: Int
+) {
+    val selected = isSelected(navController, route)
+
+    NavigationBarItem(
+        selected = selected,
+        onClick = {
+            if (!selected) {
+                navController.navigate(route)
+            }
+        },
+        icon = {
+            Icon(
+                painter = painterResource(iconResourceId),
+                contentDescription = label
+            )
+        },
+        label = {
+            Text(label)
+        }
+    )
+}
+
+@Composable
+fun isSelected(
+    navController: NavController,
+    route: SettingsScreen
+): Boolean {
+    val navBackStackEntry by navController.currentBackStackEntryAsState()
+    val currentDestination = navBackStackEntry?.destination
+
+    // Check if the current destination's hierarchy contains a destination
+    // whose route definition matches the target 'route' object.
+
+    // For @Serializable object routes, Navigation Compose typically uses a stable
+    // route string derived from the object's definition. We compare against that.
+    return currentDestination?.hierarchy?.any { destination ->
+        // Check if the destination in the hierarchy corresponds to the
+        // target 'route' object passed into this function.
+        // For @Serializable objects/classes used as routes, comparing
+        // the destination's 'route' property is the standard way.
+        destination.route == navController.graph.findNode(route)?.route
+        // Explanation:
+        // 1. `navController.graph.findNode(route)`: Finds the NavDestination node
+        //    within the navigation graph that corresponds to your @Serializable 'route' object.
+        //    (Requires NavController knows about this route, typically added via `composable(typeMap = ...)`)
+        // 2. `?.route`: Gets the unique route string pattern associated with that node.
+        // 3. `destination.route`: Gets the route string pattern of the current destination being checked in the hierarchy.
+        // 4. `==`: Compares if they are the same route.
+
+    } == true // If currentDestination is null, it's not selected, return false.
+}
\ No newline at end of file
diff --git a/app/src/main/java/eu/m724/pojavbackup/settings/screen/SettingsScreen.kt b/app/src/main/java/eu/m724/pojavbackup/settings/screen/SettingsScreen.kt
new file mode 100644
index 0000000..41ef73f
--- /dev/null
+++ b/app/src/main/java/eu/m724/pojavbackup/settings/screen/SettingsScreen.kt
@@ -0,0 +1,28 @@
+package eu.m724.pojavbackup.settings.screen
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.ColumnScope
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import kotlinx.serialization.Serializable
+
+@Serializable sealed interface SettingsScreen {
+    @Serializable data object Options : SettingsScreen
+    @Serializable data object Content : SettingsScreen
+}
+
+@Composable
+fun ScreenColumn(
+    modifier: Modifier = Modifier,
+    content: @Composable (ColumnScope.() -> Unit)
+) {
+    Column(
+        modifier = modifier.fillMaxSize().padding(top = 50.dp),
+        horizontalAlignment = Alignment.CenterHorizontally,
+        content = content
+    )
+}
\ No newline at end of file
diff --git a/app/src/main/java/eu/m724/pojavbackup/settings/screen/content/ContentScreen.kt b/app/src/main/java/eu/m724/pojavbackup/settings/screen/content/ContentScreen.kt
new file mode 100644
index 0000000..a1c751d
--- /dev/null
+++ b/app/src/main/java/eu/m724/pojavbackup/settings/screen/content/ContentScreen.kt
@@ -0,0 +1,203 @@
+package eu.m724.pojavbackup.settings.screen.content
+
+import android.graphics.Bitmap
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.items
+import androidx.compose.material3.Card
+import androidx.compose.material3.CardDefaults
+import androidx.compose.material3.CardElevation
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.asImageBitmap
+import androidx.compose.ui.graphics.painter.BitmapPainter
+import androidx.compose.ui.graphics.painter.Painter
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import androidx.hilt.navigation.compose.hiltViewModel
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import androidx.navigation.NavController
+import eu.m724.pojavbackup.R
+import eu.m724.pojavbackup.home.screen.ScreenColumn
+import org.burnoutcrew.reorderable.ReorderableItem
+import org.burnoutcrew.reorderable.detectReorderAfterLongPress
+import org.burnoutcrew.reorderable.rememberReorderableLazyListState
+import org.burnoutcrew.reorderable.reorderable
+import java.time.ZonedDateTime
+import java.time.format.DateTimeFormatter
+import java.time.format.FormatStyle
+
+
+@Composable
+fun ContentScreen(
+    navController: NavController,
+) {
+    val viewModel: ContentScreenViewModel = hiltViewModel()
+
+    val worlds by viewModel.worlds.collectAsStateWithLifecycle()
+
+    LaunchedEffect(Unit) {
+        viewModel.listWorlds()
+    }
+
+    ScreenColumn {
+        val state = rememberReorderableLazyListState(onMove = { from, to ->
+            viewModel.moveWorld(from.index, to.index)
+        })
+
+        LazyColumn(
+            modifier = Modifier
+                .reorderable(state)
+                .detectReorderAfterLongPress(state),
+            state = state.listState,
+            horizontalAlignment = Alignment.CenterHorizontally
+        ) {
+            items(
+                items = worlds,
+                key = { it.id }
+            ) { world ->
+                ReorderableItem(state, key = world.id) { isDragging ->
+                    if (!world.id.isEmpty()) {
+                        WorldInfoCard(
+                            bitmap = world.icon,
+                            id = world.id,
+                            displayName = world.displayName,
+                            lastPlayed = world.lastPlayed,
+                            elevation = if (isDragging) CardDefaults.elevatedCardElevation() else CardDefaults.cardElevation()
+                        )
+                    } else {
+                        Text(
+                            text = "↑ Worlds above this line will be backed up ↑",
+                            modifier = Modifier.fillMaxWidth().padding(vertical = 5.dp),
+                            textAlign = TextAlign.Center
+                        )
+                    }
+                }
+            }
+        }
+    }
+}
+
+/**
+ * A Composable Card that displays a square icon (Bitmap or default drawable) on the left
+ * and text information (ID, Display Name, formatted Timestamp) on the right.
+ *
+ * @param modifier Optional Modifier for the Card.
+ * @param bitmap The Bitmap for the icon to display. If null, uses a pack.png-like default icon.
+ * @param iconSize The size for the square icon (width and height).
+ * @param id The ID text to display.
+ * @param displayName The display name text.
+ * @param lastPlayed The ZonedDateTime timestamp to display, formatted by locale.
+ * @param elevation The elevation of the card.
+ * @param internalPadding Padding inside the card, around the content.
+ * @param spacingBetweenIconAndText Space between the icon and the text column.
+ */
+@Composable
+fun WorldInfoCard(
+    modifier: Modifier = Modifier,
+    bitmap: Bitmap?,
+    iconSize: Dp = 64.dp, // Control icon size here
+    id: String,
+    displayName: String,
+    lastPlayed: ZonedDateTime,
+    elevation: CardElevation = CardDefaults.cardElevation(defaultElevation = 4.dp),
+    internalPadding: Dp = 16.dp,
+    spacingBetweenIconAndText: Dp = 16.dp
+) {
+    // Formatter for the timestamp - remember caches the formatter across recompositions
+    val formatter = remember {
+        DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT) // Adjust FormatStyle as needed (SHORT, MEDIUM, LONG, FULL)
+    }
+    val formattedTimestamp = remember(lastPlayed, formatter) { // Only reformat when timestamp or formatter changes
+        lastPlayed.format(formatter)
+    }
+
+    Card(
+        modifier = modifier
+            .padding(horizontal = 8.dp, vertical = 4.dp)
+            .width(300.dp),
+        elevation = elevation
+    ) {
+        Row(
+            modifier = Modifier
+                .padding(internalPadding)
+                .fillMaxWidth(),
+            verticalAlignment = Alignment.CenterVertically
+        ) {
+            // --- Icon ---
+            // Determine the correct painter based on whether bitmap is null
+            val painter: Painter = if (bitmap != null) {
+                // Remember the BitmapPainter based on the bitmap input
+                remember(bitmap) { BitmapPainter(bitmap.asImageBitmap()) }
+            } else {
+                // Use painterResource for the default drawable
+                painterResource(id = R.drawable.default_world_icon)
+            }
+
+            Image(
+                painter = painter, // Use the determined painter
+                contentDescription = "world icon", // Hardcoded content description
+                modifier = Modifier
+                    .size(iconSize)
+                    .align(Alignment.CenterVertically)
+                    .clip(CardDefaults.shape), // TODO match corner radius
+                contentScale = ContentScale.Crop // Crop is usually best for fixed aspect ratio
+            )
+
+            Spacer(modifier = Modifier.width(spacingBetweenIconAndText))
+
+            // --- Text Column ---
+            Column(
+                modifier = Modifier.weight(1f),
+                verticalArrangement = Arrangement.spacedBy(4.dp)
+            ) {
+                Text(
+                    text = displayName,
+                    style = MaterialTheme.typography.titleLarge
+                )
+                Spacer(
+                    modifier = Modifier.width(5.dp)
+                )
+                Text(
+                    text = "Last played $formattedTimestamp", // Use formatted timestamp
+                    style = MaterialTheme.typography.bodySmall,
+                    color = MaterialTheme.colorScheme.onSurfaceVariant
+                )
+            }
+        }
+    }
+}
+
+@Preview(showBackground = true, name = "Card with Default Icon")
+@Composable
+fun WorldInfoCardPreviewDefaultIcon() {
+    MaterialTheme {
+        Column(modifier = Modifier.padding(16.dp)) {
+            WorldInfoCard(
+                bitmap = null, // Test the default icon case
+                id = "world-001",
+                displayName = "Earth",
+                lastPlayed = ZonedDateTime.now().minusDays(1)
+            )
+        }
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/eu/m724/pojavbackup/settings/screen/content/ContentScreenViewModel.kt b/app/src/main/java/eu/m724/pojavbackup/settings/screen/content/ContentScreenViewModel.kt
new file mode 100644
index 0000000..f3cb096
--- /dev/null
+++ b/app/src/main/java/eu/m724/pojavbackup/settings/screen/content/ContentScreenViewModel.kt
@@ -0,0 +1,90 @@
+package eu.m724.pojavbackup.settings.screen.content
+
+import android.content.Context
+import android.util.Log
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import dagger.hilt.android.lifecycle.HiltViewModel
+import dagger.hilt.android.qualifiers.ApplicationContext
+import eu.m724.pojavbackup.core.World
+import eu.m724.pojavbackup.core.WorldRepository
+import eu.m724.pojavbackup.core.datastore.SettingsRepository
+import eu.m724.pojavbackup.proto.WorldOrder
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.update
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import java.time.Instant
+import java.time.ZoneOffset
+import javax.inject.Inject
+
+@HiltViewModel
+class ContentScreenViewModel @Inject constructor(
+    @ApplicationContext private val appContext: Context,
+    private val worldRepository: WorldRepository,
+    private val settingsRepository: SettingsRepository
+) : ViewModel() {
+    private val _worlds = MutableStateFlow>(emptyList())
+    val worlds: StateFlow> = _worlds.asStateFlow()
+
+    fun listWorlds() {
+        viewModelScope.launch {
+            withContext(Dispatchers.IO) {
+                // TODO load order
+                val worldOrder = settingsRepository.getSettings().worldOrder
+                val worlds = worldOrder.worldIdsList.map {
+                    // TODO mark deleted worlds better
+                    worldRepository.getWorld(it) ?: World(it, "Deleted world", Instant.EPOCH.atZone(ZoneOffset.UTC), null)
+                }.toMutableList()
+                worlds.add(worldOrder.separatorIndex, World.SEPARATOR)
+
+                _worlds.update { worlds }
+            }
+        }
+    }
+
+    fun listExtras() {
+        viewModelScope.launch {
+            withContext(Dispatchers.IO) {
+                // TODO load order
+                val worldOrder = settingsRepository.getSettings().worldOrder
+                val worlds = worldOrder.worldIdsList.map {
+                    // TODO mark deleted worlds better
+                    worldRepository.getWorld(it) ?: World(it, "Deleted world", Instant.EPOCH.atZone(ZoneOffset.UTC), null)
+                }.toMutableList()
+                worlds.add(worldOrder.separatorIndex, World.SEPARATOR)
+
+                _worlds.update { worlds }
+            }
+        }
+    }
+
+    fun moveWorld(fromIndex: Int, toIndex: Int) {
+        // Similar to mutableStateOf, create a NEW list
+        val currentList = _worlds.value.toMutableList()
+        // Check bounds for safety
+        if (fromIndex in currentList.indices && toIndex >= 0 && toIndex <= currentList.size) {
+            val item = currentList.removeAt(fromIndex)
+            currentList.add(toIndex, item)
+            _worlds.value = currentList // Assign the new list to the flow
+
+            updateWorldOrder()
+        } else {
+            Log.e("Reorder", "Invalid indices: from $fromIndex, to $toIndex, size ${currentList.size}")
+        }
+    }
+
+    private fun updateWorldOrder() {
+        viewModelScope.launch {
+            settingsRepository.updateWorldOrder(
+                WorldOrder.newBuilder()
+                    .addAllWorldIds(_worlds.value.filter { it != World.SEPARATOR }.map { it.id })
+                    .setSeparatorIndex(_worlds.value.indexOf(World.SEPARATOR))
+                    .build()
+            )
+        }
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/eu/m724/pojavbackup/settings/screen/options/OptionsScreen.kt b/app/src/main/java/eu/m724/pojavbackup/settings/screen/options/OptionsScreen.kt
new file mode 100644
index 0000000..f81da2c
--- /dev/null
+++ b/app/src/main/java/eu/m724/pojavbackup/settings/screen/options/OptionsScreen.kt
@@ -0,0 +1,24 @@
+package eu.m724.pojavbackup.settings.screen.options
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.navigation.NavController
+
+@Composable
+fun OptionsScreen(
+    navController: NavController,
+) {
+    Column(
+        modifier = Modifier.fillMaxSize(),
+        verticalArrangement = Arrangement.Center,
+        horizontalAlignment = Alignment.CenterHorizontally
+    ) {
+        Text("This is the options screen")
+        Text("It's empty for now")
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/eu/m724/pojavbackup/setup/SetupActivity.kt b/app/src/main/java/eu/m724/pojavbackup/setup/SetupActivity.kt
index 3eac915..2f42e6e 100644
--- a/app/src/main/java/eu/m724/pojavbackup/setup/SetupActivity.kt
+++ b/app/src/main/java/eu/m724/pojavbackup/setup/SetupActivity.kt
@@ -1,8 +1,6 @@
 package eu.m724.pojavbackup.setup
 
-import android.R.attr.end
 import android.content.Intent
-import android.graphics.Bitmap
 import android.os.Bundle
 import android.widget.Toast
 import androidx.activity.ComponentActivity
@@ -10,62 +8,32 @@ import androidx.activity.compose.setContent
 import androidx.activity.enableEdgeToEdge
 import androidx.activity.result.contract.ActivityResultContracts
 import androidx.activity.viewModels
-import androidx.compose.foundation.Image
-import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Row
-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.size
 import androidx.compose.foundation.layout.width
-import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.foundation.lazy.items
 import androidx.compose.material3.Button
 import androidx.compose.material3.Card
 import androidx.compose.material3.CardDefaults
-import androidx.compose.material3.CardElevation
-import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Scaffold
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.clip
-import androidx.compose.ui.graphics.asImageBitmap
-import androidx.compose.ui.graphics.painter.BitmapPainter
-import androidx.compose.ui.graphics.painter.Painter
-import androidx.compose.ui.layout.ContentScale
-import androidx.compose.ui.res.painterResource
 import androidx.compose.ui.text.font.FontWeight
 import androidx.compose.ui.text.style.TextAlign
-import androidx.compose.ui.tooling.preview.Preview
-import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
 import eu.m724.pojavbackup.ui.theme.PojavBackupTheme
 import androidx.core.net.toUri
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
-import androidx.lifecycle.viewmodel.compose.viewModel
-import androidx.navigation.compose.NavHost
-import eu.m724.pojavbackup.R
+import dagger.hilt.android.AndroidEntryPoint
 import eu.m724.pojavbackup.home.HomeActivity
-import kotlinx.coroutines.flow.update
-import org.burnoutcrew.reorderable.ReorderableItem
-import org.burnoutcrew.reorderable.detectReorder
-import org.burnoutcrew.reorderable.detectReorderAfterLongPress
-import org.burnoutcrew.reorderable.rememberReorderableLazyListState
-import org.burnoutcrew.reorderable.reorderable
-import java.time.ZonedDateTime
-import java.time.format.DateTimeFormatter
-import java.time.format.FormatStyle
-import kotlin.jvm.javaClass
 
-class MainActivity : ComponentActivity() {
+@AndroidEntryPoint
+class SetupActivity : ComponentActivity() {
     private val viewModel: SetupViewModel by viewModels()
 
     private val openDocumentTree = registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) {
@@ -126,8 +94,6 @@ fun SetupScreen(
 ) {
     val uiState by viewModel.uiState.collectAsStateWithLifecycle()
 
-    val worldsState by viewModel.worlds.collectAsStateWithLifecycle()
-
     Column(
         modifier = modifier.fillMaxSize(),
         horizontalAlignment = Alignment.CenterHorizontally
@@ -177,145 +143,5 @@ fun SetupScreen(
                 }
             }
         }
-
-        // TODO this is for testing world loading only
-        /*val state = rememberReorderableLazyListState(onMove = { from, to ->
-            viewModel.moveWorld(from.index, to.index)
-        })
-
-        LazyColumn(
-            state = state.listState,
-            modifier = Modifier
-                .reorderable(state)
-                .detectReorderAfterLongPress(state)
-        ) {
-            items(
-                items = worldsState,
-                key = { it.id }
-            ) { world ->
-                ReorderableItem(state, key = world.id) { isDragging ->
-                    if (!world.id.isEmpty()) {
-                        WorldInfoCard(
-                            bitmap = world.icon,
-                            id = world.id,
-                            displayName = world.displayName,
-                            lastPlayed = world.lastPlayed,
-                            elevation = if (isDragging) CardDefaults.elevatedCardElevation() else CardDefaults.cardElevation()
-                        )
-                    } else {
-                        Text(
-                            text = "↑ Worlds above this line will be backed up ↑",
-                            modifier = Modifier.fillMaxWidth().padding(vertical = 5.dp),
-                            textAlign = TextAlign.Center
-                        )
-                    }
-                }
-            }
-        }*/
-    }
-}
-
-/**
- * A Composable Card that displays a square icon (Bitmap or default drawable) on the left
- * and text information (ID, Display Name, formatted Timestamp) on the right.
- *
- * @param modifier Optional Modifier for the Card.
- * @param bitmap The Bitmap for the icon to display. If null, uses a pack.png-like default icon.
- * @param iconSize The size for the square icon (width and height).
- * @param id The ID text to display.
- * @param displayName The display name text.
- * @param lastPlayed The ZonedDateTime timestamp to display, formatted by locale.
- * @param elevation The elevation of the card.
- * @param internalPadding Padding inside the card, around the content.
- * @param spacingBetweenIconAndText Space between the icon and the text column.
- */
-@Composable
-fun WorldInfoCard(
-    modifier: Modifier = Modifier,
-    bitmap: Bitmap?,
-    iconSize: Dp = 64.dp, // Control icon size here
-    id: String,
-    displayName: String,
-    lastPlayed: ZonedDateTime,
-    elevation: CardElevation = CardDefaults.cardElevation(defaultElevation = 4.dp),
-    internalPadding: Dp = 16.dp,
-    spacingBetweenIconAndText: Dp = 16.dp
-) {
-    // Formatter for the timestamp - remember caches the formatter across recompositions
-    val formatter = remember {
-        DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM) // Adjust FormatStyle as needed (SHORT, MEDIUM, LONG, FULL)
-    }
-    val formattedTimestamp = remember(lastPlayed, formatter) { // Only reformat when timestamp or formatter changes
-        lastPlayed.format(formatter)
-    }
-
-    Card(
-        modifier = modifier
-            .fillMaxWidth()
-            .padding(horizontal = 8.dp, vertical = 4.dp),
-        elevation = elevation
-    ) {
-        Row(
-            modifier = Modifier
-                .padding(internalPadding)
-                .fillMaxWidth(),
-            verticalAlignment = Alignment.CenterVertically
-        ) {
-            // --- Icon ---
-            // Determine the correct painter based on whether bitmap is null
-            val painter: Painter = if (bitmap != null) {
-                // Remember the BitmapPainter based on the bitmap input
-                remember(bitmap) { BitmapPainter(bitmap.asImageBitmap()) }
-            } else {
-                // Use painterResource for the default drawable
-                painterResource(id = R.drawable.default_world_icon)
-            }
-
-            Image(
-                painter = painter, // Use the determined painter
-                contentDescription = "world icon", // Hardcoded content description
-                modifier = Modifier
-                    .size(iconSize)
-                    .align(Alignment.CenterVertically)
-                    .clip(CardDefaults.shape), // TODO match corner radius
-                contentScale = ContentScale.Crop // Crop is usually best for fixed aspect ratio
-            )
-
-            Spacer(modifier = Modifier.width(spacingBetweenIconAndText))
-
-            // --- Text Column ---
-            Column(
-                modifier = Modifier.weight(1f),
-                verticalArrangement = Arrangement.spacedBy(4.dp)
-            ) {
-                Text(
-                    text = displayName,
-                    style = MaterialTheme.typography.titleLarge
-                )
-                Spacer(
-                    modifier = Modifier.width(5.dp)
-                )
-                Text(
-                    text = "Last played $formattedTimestamp", // Use formatted timestamp
-                    style = MaterialTheme.typography.bodySmall,
-                    color = MaterialTheme.colorScheme.onSurfaceVariant
-                )
-            }
-        }
-    }
-}
-
-@Preview(showBackground = true, name = "Card with Default Icon")
-@Composable
-fun WorldInfoCardPreviewDefaultIcon() {
-    MaterialTheme {
-        Column(modifier = Modifier.padding(16.dp)) {
-            WorldInfoCard(
-                bitmap = null, // Test the default icon case
-                id = "world-001",
-                displayName = "Earth",
-                lastPlayed = ZonedDateTime.now().minusDays(1)
-            )
-        }
     }
 }
\ No newline at end of file
diff --git a/app/src/main/java/eu/m724/pojavbackup/setup/SetupViewModel.kt b/app/src/main/java/eu/m724/pojavbackup/setup/SetupViewModel.kt
index 16621f4..d5d54fc 100644
--- a/app/src/main/java/eu/m724/pojavbackup/setup/SetupViewModel.kt
+++ b/app/src/main/java/eu/m724/pojavbackup/setup/SetupViewModel.kt
@@ -1,26 +1,17 @@
 package eu.m724.pojavbackup.setup
 
-import android.content.ContentResolver
 import android.content.Context
 import android.content.Intent
 import android.content.pm.PackageManager
 import android.content.pm.PackageManager.NameNotFoundException
 import android.net.Uri
 import android.util.Log
-import androidx.compose.runtime.mutableStateListOf
-import androidx.compose.runtime.snapshots.SnapshotStateList
 import androidx.documentfile.provider.DocumentFile
 import androidx.lifecycle.ViewModel
-import androidx.lifecycle.viewModelScope
-import eu.m724.pojavbackup.core.World
-import eu.m724.pojavbackup.core.WorldDetector
-import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.asStateFlow
 import kotlinx.coroutines.flow.update
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
 
 class SetupViewModel : ViewModel() {
     private val TAG: String = javaClass.name
@@ -33,9 +24,6 @@ class SetupViewModel : ViewModel() {
     private val _uiState = MutableStateFlow(SetupUiState())
     val uiState: StateFlow = _uiState.asStateFlow()
 
-    private val _worlds = MutableStateFlow>(emptyList())
-    val worlds: StateFlow> = _worlds.asStateFlow()
-
     // TODO we could make the check call separate and not pass context here
     fun onOpenDocumentTree(context: Context, uri: Uri?, result: (Boolean) -> Unit) {
         if (uri != null) {
@@ -79,45 +67,9 @@ class SetupViewModel : ViewModel() {
 
         Log.i(TAG, "Yes we have permission")
 
-        // TODO remove
-        listWorlds(context, directory)
-
         return true
     }
 
-    // TODO World functions certainly don't belong here. This is for testing.
-    private fun listWorlds(context: Context, documentFile: DocumentFile) {
-        viewModelScope.launch {
-            withContext(Dispatchers.IO) {
-                Log.i(TAG, "listing worlds")
-
-                val worldDetector = WorldDetector(
-                    contentResolver = context.contentResolver,
-                    savesDirectory = documentFile.findFile(".minecraft")!!.findFile("saves")!!
-                )
-
-                worldDetector.listWorlds { world ->
-                    _worlds.update { it + world }
-                }
-
-                _worlds.update { it + World.SEPARATOR }
-            }
-        }
-    }
-
-    fun moveWorld(fromIndex: Int, toIndex: Int) {
-        // Similar to mutableStateOf, create a NEW list
-        val currentList = _worlds.value.toMutableList()
-        // Check bounds for safety
-        if (fromIndex in currentList.indices && toIndex >= 0 && toIndex <= currentList.size) {
-            val item = currentList.removeAt(fromIndex)
-            currentList.add(toIndex, item)
-            _worlds.value = currentList // Assign the new list to the flow
-        } else {
-            Log.e("Reorder", "Invalid indices: from $fromIndex, to $toIndex, size ${currentList.size}")
-        }
-    }
-
     fun detectInstalledLauncherPackage(packageManager: PackageManager): List {
         return POJAV_PACKAGES.filter {
             try {
diff --git a/app/src/main/java/eu/m724/pojavbackup/ui/theme/Color.kt b/app/src/main/java/eu/m724/pojavbackup/ui/theme/Color.kt
deleted file mode 100644
index 39b5346..0000000
--- a/app/src/main/java/eu/m724/pojavbackup/ui/theme/Color.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-package eu.m724.pojavbackup.ui.theme
-
-import androidx.compose.ui.graphics.Color
-
-val Purple80 = Color(0xFFD0BCFF)
-val PurpleGrey80 = Color(0xFFCCC2DC)
-val Pink80 = Color(0xFFEFB8C8)
-
-val Purple40 = Color(0xFF6650a4)
-val PurpleGrey40 = Color(0xFF625b71)
-val Pink40 = Color(0xFF7D5260)
\ No newline at end of file
diff --git a/app/src/main/java/eu/m724/pojavbackup/ui/theme/Theme.kt b/app/src/main/java/eu/m724/pojavbackup/ui/theme/Theme.kt
index 668f590..0e03768 100644
--- a/app/src/main/java/eu/m724/pojavbackup/ui/theme/Theme.kt
+++ b/app/src/main/java/eu/m724/pojavbackup/ui/theme/Theme.kt
@@ -1,6 +1,5 @@
 package eu.m724.pojavbackup.ui.theme
 
-import android.app.Activity
 import android.os.Build
 import androidx.compose.foundation.isSystemInDarkTheme
 import androidx.compose.material3.MaterialTheme
@@ -11,48 +10,23 @@ import androidx.compose.material3.lightColorScheme
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.platform.LocalContext
 
-private val DarkColorScheme = darkColorScheme(
-    primary = Purple80,
-    secondary = PurpleGrey80,
-    tertiary = Pink80
-)
-
-private val LightColorScheme = lightColorScheme(
-    primary = Purple40,
-    secondary = PurpleGrey40,
-    tertiary = Pink40
-
-    /* Other default colors to override
-    background = Color(0xFFFFFBFE),
-    surface = Color(0xFFFFFBFE),
-    onPrimary = Color.White,
-    onSecondary = Color.White,
-    onTertiary = Color.White,
-    onBackground = Color(0xFF1C1B1F),
-    onSurface = Color(0xFF1C1B1F),
-    */
-)
-
 @Composable
 fun PojavBackupTheme(
-    darkTheme: Boolean = isSystemInDarkTheme(),
-    // Dynamic color is available on Android 12+
-    dynamicColor: Boolean = true,
     content: @Composable () -> Unit
 ) {
-    val colorScheme = when {
-        dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
-            val context = LocalContext.current
-            if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
-        }
+    val dynamicColor = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
+    val darkTheme = isSystemInDarkTheme()
 
-        darkTheme -> DarkColorScheme
-        else -> LightColorScheme
+    val colorScheme = when {
+        dynamicColor && darkTheme -> dynamicDarkColorScheme(LocalContext.current)
+        dynamicColor && !darkTheme -> dynamicLightColorScheme(LocalContext.current)
+
+        darkTheme -> darkColorScheme()
+        else -> lightColorScheme()
     }
 
     MaterialTheme(
         colorScheme = colorScheme,
-        typography = Typography,
         content = content
     )
 }
\ No newline at end of file
diff --git a/app/src/main/java/eu/m724/pojavbackup/ui/theme/Type.kt b/app/src/main/java/eu/m724/pojavbackup/ui/theme/Type.kt
deleted file mode 100644
index a0fd7db..0000000
--- a/app/src/main/java/eu/m724/pojavbackup/ui/theme/Type.kt
+++ /dev/null
@@ -1,34 +0,0 @@
-package eu.m724.pojavbackup.ui.theme
-
-import androidx.compose.material3.Typography
-import androidx.compose.ui.text.TextStyle
-import androidx.compose.ui.text.font.FontFamily
-import androidx.compose.ui.text.font.FontWeight
-import androidx.compose.ui.unit.sp
-
-// Set of Material typography styles to start with
-val Typography = Typography(
-    bodyLarge = TextStyle(
-        fontFamily = FontFamily.Default,
-        fontWeight = FontWeight.Normal,
-        fontSize = 16.sp,
-        lineHeight = 24.sp,
-        letterSpacing = 0.5.sp
-    )
-    /* Other default text styles to override
-    titleLarge = TextStyle(
-        fontFamily = FontFamily.Default,
-        fontWeight = FontWeight.Normal,
-        fontSize = 22.sp,
-        lineHeight = 28.sp,
-        letterSpacing = 0.sp
-    ),
-    labelSmall = TextStyle(
-        fontFamily = FontFamily.Default,
-        fontWeight = FontWeight.Medium,
-        fontSize = 11.sp,
-        lineHeight = 16.sp,
-        letterSpacing = 0.5.sp
-    )
-    */
-)
\ No newline at end of file
diff --git a/app/src/main/proto/settings.proto b/app/src/main/proto/settings.proto
new file mode 100644
index 0000000..8381791
--- /dev/null
+++ b/app/src/main/proto/settings.proto
@@ -0,0 +1,14 @@
+syntax = "proto3";
+
+option java_package = "eu.m724.pojavbackup.proto";
+option java_multiple_files = true;
+
+message WorldOrder {
+  repeated string worldIds = 1;
+  int32 separatorIndex = 2;
+}
+
+message Settings {
+  WorldOrder worldOrder = 1;
+  repeated string extraPaths = 2;
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/baseline_folder_copy_24.xml b/app/src/main/res/drawable/baseline_folder_copy_24.xml
new file mode 100644
index 0000000..a7c1f0a
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_folder_copy_24.xml
@@ -0,0 +1,7 @@
+
+      
+    
+      
+    
+    
+
diff --git a/app/src/main/res/drawable/baseline_settings_24.xml b/app/src/main/res/drawable/baseline_settings_24.xml
new file mode 100644
index 0000000..6593f3a
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_settings_24.xml
@@ -0,0 +1,5 @@
+
+      
+    
+    
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index f6986a1..478a0ae 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,5 +1,6 @@
 
     PojavBackup
-    MainActivity
+    SetupActivity
     HomeActivity
+    SettingsActivity
 
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
index 5ba8ae0..c6a2f03 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -4,4 +4,7 @@ plugins {
     alias(libs.plugins.kotlin.android) apply false
     alias(libs.plugins.kotlin.compose) apply false
     alias(libs.plugins.kotlin.serialization) apply false
+    alias(libs.plugins.ksp) apply false
+    alias(libs.plugins.hilt) apply false
+    alias(libs.plugins.protobuf) apply false
 }
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 7c8d803..6b5ee18 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,6 +1,6 @@
 [versions]
 agp = "8.9.1"
-kotlin = "2.0.21"
+kotlin = "2.1.20"
 coreKtx = "1.16.0"
 junit = "4.13.2"
 junitVersion = "1.2.1"
@@ -14,6 +14,12 @@ lifecycleViewmodelCompose = "2.8.7"
 knbt = "0.11.8"
 reorderable = "0.9.6"
 navigation = "2.8.9"
+hilt = "2.56.1"
+ksp = "2.1.20-2.0.0"
+hiltNavigationCompose = "1.2.0"
+datastore = "1.1.4"
+protobufJavalite = "4.30.2"
+protobuf = "0.9.5"
 
 [libraries]
 androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
@@ -36,10 +42,17 @@ androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "l
 knbt = { group = "net.benwoodworth.knbt", name = "knbt", version.ref = "knbt" }
 reorderable = { group = "org.burnoutcrew.composereorderable", name = "reorderable", version.ref = "reorderable" }
 androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigation" }
+hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" }
+hilt-compiler = { group = "com.google.dagger", name = "hilt-compiler", version.ref = "hilt" }
+androidx-hilt-navigation-compose = { group = "androidx.hilt", name = "hilt-navigation-compose", version.ref = "hiltNavigationCompose"}
+androidx-datastore = { group = "androidx.datastore", name = "datastore", version.ref = "datastore" }
+protobuf-javalite = { group = "com.google.protobuf", name = "protobuf-javalite", version.ref = "protobufJavalite"}
 
 [plugins]
 android-application = { id = "com.android.application", version.ref = "agp" }
 kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
 kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
 kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin"}
-
+ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
+hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt"}
+protobuf = { id = "com.google.protobuf", version.ref = "protobuf" }